Merge "msm: kgsl: Ensure the GMU does not go to sleep in ISR" into msm-4.9
diff --git a/Documentation/devicetree/bindings/devfreq/bimc-bwmon.txt b/Documentation/devicetree/bindings/devfreq/bimc-bwmon.txt
index c77f84b..29b7334 100644
--- a/Documentation/devicetree/bindings/devfreq/bimc-bwmon.txt
+++ b/Documentation/devicetree/bindings/devfreq/bimc-bwmon.txt
@@ -6,17 +6,25 @@
 
 Required properties:
 - compatible:		Must be "qcom,bimc-bwmon", "qcom,bimc-bwmon2",
-			"qcom,bimc-bwmon3" or "qcom,bimc-bwmon4"
+			"qcom,bimc-bwmon3" or "qcom,bimc-bwmon4" or
+			"qcom,bimc-bwmon5"
 - 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: "base", "global_base"
+			"global_base" should not be specified for
+			"qcom,bimc-bwmon5" compatibles.
 - interrupts:		Lists the threshold IRQ.
 - qcom,mport:		The hardware master port that this device can monitor
 - qcom,target-dev:	The DT device that corresponds to this master port
 - qcom,hw-timer-hz:	Hardware sampling rate in Hz. This field must be
 			specified for "qcom,bimc-bwmon4"
 
+Optional properties:
+- qcom,byte-mid-match:	Byte count MID match value
+- qcom,byte-mid-mask:	Byte count MID mask value
+- qcom,count-unit:	Number of bytes monitor counts in
+
 Example:
 	qcom,cpu-bwmon {
 		compatible = "qcom,bimc-bwmon";
@@ -26,4 +34,7 @@
 		qcom,mport = <0>;
 		qcom,target-dev = <&cpubw>;
 		qcom,hw-timer-hz = <19200000>;
+		qcom,byte-mid-match = <0x1e00>;
+		qcom,byte-mid-mask = <0x1e00>;
+		qcom,count-unit = <0x100000>;
 	};
diff --git a/Documentation/devicetree/bindings/display/msm/sde.txt b/Documentation/devicetree/bindings/display/msm/sde.txt
index a3ef34c..c766df8 100644
--- a/Documentation/devicetree/bindings/display/msm/sde.txt
+++ b/Documentation/devicetree/bindings/display/msm/sde.txt
@@ -274,6 +274,29 @@
 				applied in scenarios where panel interface can
 				be more tolerant to memory latency such as
 				command mode panels.
+- qcom,sde-core-ib-ff:		A string entry indicating the fudge factor for
+				core ib calculation.
+- qcom,sde-core-clk-ff:		A string entry indicating the fudge factor for
+				core clock calculation.
+- qcom,sde-comp-ratio-rt:	A string entry indicating the compression ratio
+				for each supported compressed format on realtime interface.
+				The string is composed of one or more of
+				<fourcc code>/<vendor code>/<modifier>/<compression ratio>
+				separated with spaces.
+- qcom,sde-comp-ratio-nrt:	A string entry indicating the compression ratio
+				for each supported compressed format on non-realtime interface.
+				The string is composed of one or more of
+				<fourcc code>/<vendor code>/<modifier>/<compression ratio>
+				separated with spaces.
+- qcom,sde-undersized-prefill-lines:	A u32 value indicates the size of undersized prefill in lines.
+- qcom,sde-xtra-prefill-lines:	A u32 value indicates the extra prefill in lines.
+- qcom,sde-dest-scale-prefill-lines:	A u32 value indicates the latency of destination scaler in lines.
+- qcom,sde-macrotile-prefill-lines:	A u32 value indicates the latency of macrotile in lines.
+- qcom,sde-yuv-nv12-prefill-lines:	A u32 value indicates the latency of yuv/nv12 in lines.
+- qcom,sde-linear-prefill-lines:	A u32 value indicates the latency of linear in lines.
+- qcom,sde-downscaling-prefill-lines:	A u32 value indicates the latency of downscaling in lines.
+- qcom,sde-max-per-pipe-bw-kbps:	Array of u32 value indicates the max per pipe bandwidth in Kbps.
+- qcom,sde-amortizable-threshold:	This value indicates the min for traffic shaping in lines.
 
 Bus Scaling Subnodes:
 - qcom,sde-reg-bus:		Property to provide Bus scaling for register access for
@@ -462,6 +485,21 @@
     qcom,sde-max-bw-high-kbps = <9000000>;
     qcom,sde-max-bw-low-kbps = <9000000>;
 
+    qcom,sde-core-ib-ff = "1.1";
+    qcom,sde-core-clk-ff = "1.0";
+    qcom,sde-comp-ratio-rt = "NV12/5/1/1.1 AB24/5/1/1.2 XB24/5/1/1.3";
+    qcom,sde-comp-ratio-nrt = "NV12/5/1/1.1 AB24/5/1/1.2 XB24/5/1/1.3";
+    qcom,sde-undersized-prefill-lines = <4>;
+    qcom,sde-xtra-prefill-lines = <5>;
+    qcom,sde-dest-scale-prefill-lines = <6>;
+    qcom,sde-macrotile-prefill-lines = <7>;
+    qcom,sde-yuv-nv12-prefill-lines = <8>;
+    qcom,sde-linear-prefill-lines = <9>;
+    qcom,sde-downscaling-prefill-lines = <10>;
+    qcom,sde-max-per-pipe-bw-kbps = <2400000 2400000 2400000 2400000
+        2400000 2400000 2400000 2400000>;
+    qcom,sde-amortizable-threshold = <11>;
+
     qcom,sde-sspp-vig-blocks {
         qcom,sde-vig-csc-off = <0x320>;
         qcom,sde-vig-qseed-off = <0x200>;
diff --git a/Documentation/devicetree/bindings/extcon/extcon-gpio.txt b/Documentation/devicetree/bindings/extcon/extcon-gpio.txt
new file mode 100644
index 0000000..1b3a1d2
--- /dev/null
+++ b/Documentation/devicetree/bindings/extcon/extcon-gpio.txt
@@ -0,0 +1,32 @@
+GPIO Extcon device
+
+This is a virtual device used to generate USB cable states from the USB ID pin
+connected to a GPIO pin.
+
+Required properties:
+- compatible: Should be "extcon-gpio"
+- extcon-id: The unique id of specific external connector.
+	     Valid range is 0 (EXTCON_NONE) to 63 (EXTCON_NUM).
+	     Refer include/linux/extcon.h for details.
+- gpio: Specify GPIO (see gpio binding)
+- debounce-ms: Debounce time for GPIO IRQ in ms
+- irq-flags: interrupt flags (edge/level). Refer to "include/dt-bindings/interrupt-controller/irq.h"
+- pinctrl-names, pinctrl-0, pinctrl-1,.. pinctrl-n: Refer to "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt"
+  for these optional properties
+
+Example:
+	extcon_storage_cd {
+		compatible = "extcon-gpio";
+		extcon-id = <62>; /* EXTCON_MECHANICAL */
+		gpio = <&tlmm 126 GPIO_ACTIVE_LOW>;
+		debounce-ms = <200>;
+		irq-flags = <IRQ_TYPE_EDGE_BOTH>;
+	}
+
+	&ufshc_card {
+		extcon = <&extcon_storage_cd>;
+	};
+
+	&sd_card {
+		extcon = <&extcon_storage_cd>;
+	};
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cam-cci.txt
index 8e2bdee..c9aaa00 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cam-cci.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cam-cci.txt
@@ -165,6 +165,15 @@
   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.
+- qcom,clock-rates: clock rate in Hz.
+- qcom,clock-cntl-support: Says whether clock control support is present or not
+- 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.
 
 * Qualcomm Technologies, Inc. MSM ACTUATOR
 
@@ -205,6 +214,7 @@
   sensor
   - 0 -> MASTER 0
   - 1 -> MASTER 1
+- qcom,clock-rates: clock rate in Hz.
 
 Optional properties:
 - qcom,cam-vreg-name : should contain names of all regulators needed by this
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt b/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt
new file mode 100644
index 0000000..c560a05
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt
@@ -0,0 +1,219 @@
+* Qualcomm Technologies, Inc. MSM Camera ICP
+
+The MSM camera ICP devices are implemented multiple device nodes.
+The root icp device node has properties defined to hint the driver
+about the number of A5,IPE and BPS nodes available during the
+probe sequence. Each node has multiple properties defined
+for interrupts, clocks and regulators.
+
+=======================
+Required Node Structure
+=======================
+ICP root interface node takes care of the handling account for number
+of A5, IPE and BPS devices present on the hardware.
+
+- compatible
+  Usage: required
+  Value type: <string>
+  Definition: Should be "qcom,cam-icp".
+
+- compat-hw-name
+
+  Usage: required
+  Value type: <string>
+  Definition: Should be "qcom,a5" or "qcom,ipe".
+
+- num-a5
+  Usage: required
+  Value type: <u32>
+  Definition: Number of supported A5 processors.
+
+- num-ipe
+  Usage: required
+  Value type: <u32>
+  Definition: Number of supported IPE HW blocks.
+
+- num-bps
+  Usage: required
+  Value type: <u32>
+  Definition: Number of supported BPS HW blocks.
+
+Example:
+	qcom,cam-icp {
+		compatible = "qcom,cam-icp";
+		compat-hw-name = "qcom,a5", "qcom,ipe0", "qcom,ipe1", "qcom,bps";
+		num-a5 = <1>;
+		num-ipe = <2>;
+		num-bps = <1>;
+		status = "ok";
+	};
+
+=======================
+Required Node Structure
+=======================
+A5/IPE/BPS Node's provides interface for Image Control Processor driver
+about the A5 register map, interrupt map, clocks, regulators
+and name of firmware image.
+
+- cell-index
+  Usage: required
+  Value type: <u32>
+  Definition: Node instance number.
+
+- compatible
+  Usage: required
+  Value type: <string>
+  Definition: Should be "qcom,cam-cdm-intf".
+
+- reg-names
+  Usage: optional
+  Value type: <string>
+  Definition: Name of the register resources.
+
+- reg
+  Usage: optional
+  Value type: <u32>
+  Definition: Register values.
+
+- reg-cam-base
+  Usage: optional
+  Value type: <u32>
+  Definition: Register values.
+
+- interrupt-names
+  Usage: optional
+  Value type: <string>
+  Definition: Name of the interrupt.
+
+- interrupts
+  Usage: optional
+  Value type: <u32>
+  Definition: Interrupt associated with CDM HW.
+
+- regulator-names
+  Usage: required
+  Value type: <string>
+  Definition: Name of the regulator resources for CDM HW.
+
+- camss-supply
+  Usage: required
+  Value type: <phandle>
+  Definition: Regulator reference corresponding to the names listed
+              in "regulator-names".
+
+- clock-names
+  Usage: required
+  Value type: <string>
+  Definition: List of clock names required for CDM HW.
+
+- clocks
+  Usage: required
+  Value type: <phandle>
+  Definition: List of clocks used for CDM HW.
+
+- clock-rates
+  Usage: required
+  Value type: <u32>
+  Definition: List of clocks rates.
+
+- fw_name
+  Usage: optional
+  Value type: <string>
+  Definition: Name of firmware image.
+
+Examples:
+a5: qcom,a5@a10000 {
+	cell-index = <0>;
+	compatible = "qcom,cam_a5";
+	reg = <0xac00000 0x6000>,
+		<0xac10000 0x8000>,
+		<0xac18000 0x3000>;
+	reg-names = "a5_qgic", "a5_sierra", "a5_csr";
+	interrupts = <0 463 0>;
+	interrupt-names = "a5";
+	regulator-names = "camss-vdd";
+	camss-vdd-supply = <&titan_top_gdsc>;
+	clock-names = "gcc_cam_ahb_clk",
+		"gcc_cam_axi_clk",
+		"soc_ahb_clk",
+		"cpas_ahb_clk",
+		"camnoc_axi_clk",
+		"icp_apb_clk",
+		"icp_atb_clk",
+		"icp_clk",
+		"icp_clk_src",
+		"icp_cti_clk",
+		"icp_ts_clk";
+	clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>,
+			<&clock_gcc GCC_CAMERA_AXI_CLK>,
+			<&clock_camcc CAM_CC_SOC_AHB_CLK>,
+			<&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+			<&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
+			<&clock_camcc CAM_CC_ICP_APB_CLK>,
+			<&clock_camcc CAM_CC_ICP_ATB_CLK>,
+			<&clock_camcc CAM_CC_ICP_CLK>,
+			<&clock_camcc CAM_CC_ICP_CLK_SRC>,
+			<&clock_camcc CAM_CC_ICP_CTI_CLK>,
+			<&clock_camcc CAM_CC_ICP_TS_CLK>;
+
+	clock-rates = <0 0 0 80000000 0 0 0 0 600000000 0 0>;
+	fw_name = "CAMERA_ICP.elf";
+};
+
+qcom,ipe0 {
+	cell-index = <0>;
+	compatible = "qcom,cam_ipe";
+	regulator-names = "ipe0-vdd";
+	ipe0-vdd-supply = <&ipe_0_gdsc>;
+	clock-names = "ipe_0_ahb_clk",
+		"ipe_0_areg_clk",
+		"ipe_0_axi_clk",
+		"ipe_0_clk",
+		"ipe_0_clk_src";
+	clocks = <&clock_camcc CAM_CC_IPE_0_AHB_CLK>,
+			<&clock_camcc CAM_CC_IPE_0_AREG_CLK>,
+			<&clock_camcc CAM_CC_IPE_0_AXI_CLK>,
+			<&clock_camcc CAM_CC_IPE_0_CLK>,
+			<&clock_camcc CAM_CC_IPE_0_CLK_SRC>;
+
+	clock-rates = <80000000 400000000 0 0 600000000>;
+};
+
+qcom,ipe1 {
+	cell-index = <1>;
+	compatible = "qcom,cam_ipe";
+	regulator-names = "ipe1-vdd";
+	ipe1-vdd-supply = <&ipe_1_gdsc>;
+	clock-names = "ipe_1_ahb_clk",
+		"ipe_1_areg_clk",
+		"ipe_1_axi_clk",
+		"ipe_1_clk",
+		"ipe_1_clk_src";
+	clocks = <&clock_camcc CAM_CC_IPE_1_AHB_CLK>,
+			<&clock_camcc CAM_CC_IPE_1_AREG_CLK>,
+			<&clock_camcc CAM_CC_IPE_1_AXI_CLK>,
+			<&clock_camcc CAM_CC_IPE_1_CLK>,
+			<&clock_camcc CAM_CC_IPE_1_CLK_SRC>;
+
+		clock-rates = <80000000 400000000 0 0 600000000>;
+};
+
+bps: qcom,bps {
+	cell-index = <0>;
+	compatible = "qcom,cam_bps";
+	regulator-names = "bps-vdd";
+	bps-vdd-supply = <&bps_gdsc>;
+	clock-names = "bps_ahb_clk",
+		"bps_areg_clk",
+		"bps_axi_clk",
+		"bps_clk",
+		"bps_clk_src";
+	clocks = <&clock_camcc CAM_CC_BPS_AHB_CLK>,
+			<&clock_camcc CAM_CC_BPS_AREG_CLK>,
+			<&clock_camcc CAM_CC_BPS_AXI_CLK>,
+			<&clock_camcc CAM_CC_BPS_CLK>,
+			<&clock_camcc CAM_CC_BPS_CLK_SRC>;
+
+	clock-rates = <80000000 400000000 0 0 600000000>;
+};
+
diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt
index 8a37782..f978c58 100644
--- a/Documentation/devicetree/bindings/mmc/mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/mmc.txt
@@ -52,6 +52,7 @@
 - no-sdio: controller is limited to send sdio cmd during initialization
 - no-sd: controller is limited to send sd cmd during initialization
 - no-mmc: controller is limited to send mmc cmd during initialization
+- extcon: phandle to external connector (Refer Documentation/devicetree/bindings/extcon/extcon-gpio.txt for more details).
 
 *NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
 polarity properties, we have to fix the meaning of the "normal" and "inverted"
diff --git a/Documentation/devicetree/bindings/platform/msm/ipa.txt b/Documentation/devicetree/bindings/platform/msm/ipa.txt
index 3a03add..e821feb 100644
--- a/Documentation/devicetree/bindings/platform/msm/ipa.txt
+++ b/Documentation/devicetree/bindings/platform/msm/ipa.txt
@@ -19,10 +19,13 @@
                    "bam-irq" - string to identify the IPA BAM interrupt.
                    "a2-bam-irq" - string to identify the A2 BAM interrupt.
 - qcom,ipa-hw-ver: Specifies the IPA hardware version.
+- qcom,ipa-ram-mmap: An array of unsigned integers representing addresses and
+                     sizes which are used by the driver to access IPA RAM.
 
 Optional:
 
-- qcom,wan-rx-ring-size: size of WAN rx ring, default is 32
+- qcom,wan-rx-ring-size: size of WAN rx ring, default is 192
+- qcom,lan-rx-ring-size: size of LAN rx ring, default is 192
 - qcom,arm-smmu: SMMU is present and ARM SMMU driver is used
 - qcom,msm-smmu: SMMU is present and QSMMU driver is used
 - qcom,smmu-s1-bypass: Boolean context flag to set SMMU to S1 bypass
@@ -59,12 +62,12 @@
 - qcom,bandwidth-vote-for-ipa:	Boolean context flag to indicate whether
 				ipa clock voting is done by bandwidth
 				voting via msm-bus-scale driver or not
+- qcom,use-64-bit-dma-mask:     Boolean context flag to indicate whether
+                                using 64bit dma mask or not
 - qcom,use-dma-zone:            Boolean context flag to indicate whether memory
                                 allocations controlled by IPA driver that do not
 				specify a struct device * should use GFP_DMA to
 				workaround IPA HW limitations
-- qcom,use-gsi:                 Boolean context flag to indicate if the
-                                transport protocol is GSI
 - qcom,use-rg10-limitation-mitigation:	Boolean context flag to activate
 					the mitigation to register group 10
 					AP access limitation
@@ -123,6 +126,9 @@
 
 - qcom,iova-mapping: specifies the start address and size of iova space.
 
+- qcom,additional-mapping: specifies any addtional mapping needed for this
+				context bank. The format is <iova pa size>
+
 IPA SMP2P sub nodes
 
 -compatible: "qcom,smp2pgpio-map-ipa-1-out" - represents the out gpio from
@@ -198,18 +204,24 @@
 
 	ipa_smmu_ap: ipa_smmu_ap {
 		compatible = "qcom,ipa-smmu-ap-cb";
-		iommus = <&anoc2_smmu 0x30>;
-		qcom,iova-mapping = <0x10000000 0x40000000>;
+		iommus = <&apps_smmu 0x720>;
+		qcom,iova-mapping = <0x20000000 0x40000000>;
+		qcom,additional-mapping =
+		/* modem tables in IMEM */
+		<0x146bd000 0x146bd000 0x2000>;
 	};
 
 	ipa_smmu_wlan: ipa_smmu_wlan {
 		compatible = "qcom,ipa-smmu-wlan-cb";
-		iommus = <&anoc2_smmu 0x31>;
+		iommus = <&apps_smmu 0x721>;
+		qcom,additional-mapping =
+		/* ipa-uc ram */
+		<0x1e60000 0x1e60000 0x80000>;
 	};
 
 	ipa_smmu_uc: ipa_smmu_uc {
 		compatible = "qcom,ipa-smmu-uc-cb";
-		iommus = <&anoc2_smmu 0x32>;
+		iommus = <&apps_smmu 0x722>;
 		qcom,iova-mapping = <0x40000000 0x20000000>;
 	};
 };
diff --git a/Documentation/devicetree/bindings/qdsp/msm-ssc-sensors.txt b/Documentation/devicetree/bindings/qdsp/msm-ssc-sensors.txt
new file mode 100644
index 0000000..db7ab75
--- /dev/null
+++ b/Documentation/devicetree/bindings/qdsp/msm-ssc-sensors.txt
@@ -0,0 +1,21 @@
+Qualcomm Technologies, Inc. SSC Driver
+
+msm-ssc-sensors driver implements the mechanism that allows to load SLPI firmware images.
+
+Required properties:
+
+ - compatible:  This must be "qcom,msm-ssc-sensors"
+
+Optional properties:
+
+ - qcom,firmware-name: SLPI firmware name, must be "slpi" or "slpi_v1" or "slpi_v2"
+	Firmware name is not required, if sensors driver is sharing processor for execution.
+
+
+Example:
+ The following for sdm845.
+
+	qcom,msm-ssc-sensors {
+		compatible = "qcom,msm-ssc-sensors";
+		qcom,firmware-name = "slpi";
+	};
diff --git a/Makefile b/Makefile
index f834951..f47cd95 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 4
 PATCHLEVEL = 9
-SUBLEVEL = 27
+SUBLEVEL = 28
 EXTRAVERSION =
 NAME = Roaring Lionus
 
diff --git a/arch/arm/boot/dts/bcm958522er.dts b/arch/arm/boot/dts/bcm958522er.dts
index a21b0fd..417f657 100644
--- a/arch/arm/boot/dts/bcm958522er.dts
+++ b/arch/arm/boot/dts/bcm958522er.dts
@@ -55,6 +55,7 @@
 	gpio-restart {
 		compatible = "gpio-restart";
 		gpios = <&gpioa 15 GPIO_ACTIVE_LOW>;
+		open-source;
 		priority = <200>;
 	};
 };
diff --git a/arch/arm/boot/dts/bcm958525er.dts b/arch/arm/boot/dts/bcm958525er.dts
index be7f2f8..5279b76 100644
--- a/arch/arm/boot/dts/bcm958525er.dts
+++ b/arch/arm/boot/dts/bcm958525er.dts
@@ -55,6 +55,7 @@
 	gpio-restart {
 		compatible = "gpio-restart";
 		gpios = <&gpioa 15 GPIO_ACTIVE_LOW>;
+		open-source;
 		priority = <200>;
 	};
 };
diff --git a/arch/arm/boot/dts/bcm958525xmc.dts b/arch/arm/boot/dts/bcm958525xmc.dts
index 959cde9..872882b 100644
--- a/arch/arm/boot/dts/bcm958525xmc.dts
+++ b/arch/arm/boot/dts/bcm958525xmc.dts
@@ -55,6 +55,7 @@
 	gpio-restart {
 		compatible = "gpio-restart";
 		gpios = <&gpioa 31 GPIO_ACTIVE_LOW>;
+		open-source;
 		priority = <200>;
 	};
 };
diff --git a/arch/arm/boot/dts/bcm958622hr.dts b/arch/arm/boot/dts/bcm958622hr.dts
index ad2aa87..a340e1d 100644
--- a/arch/arm/boot/dts/bcm958622hr.dts
+++ b/arch/arm/boot/dts/bcm958622hr.dts
@@ -55,6 +55,7 @@
 	gpio-restart {
 		compatible = "gpio-restart";
 		gpios = <&gpioa 15 GPIO_ACTIVE_LOW>;
+		open-source;
 		priority = <200>;
 	};
 };
diff --git a/arch/arm/boot/dts/bcm958623hr.dts b/arch/arm/boot/dts/bcm958623hr.dts
index 4ceb8fe..226b652 100644
--- a/arch/arm/boot/dts/bcm958623hr.dts
+++ b/arch/arm/boot/dts/bcm958623hr.dts
@@ -55,6 +55,7 @@
 	gpio-restart {
 		compatible = "gpio-restart";
 		gpios = <&gpioa 15 GPIO_ACTIVE_LOW>;
+		open-source;
 		priority = <200>;
 	};
 };
diff --git a/arch/arm/boot/dts/bcm958625hr.dts b/arch/arm/boot/dts/bcm958625hr.dts
index 4420025..a1658d0 100644
--- a/arch/arm/boot/dts/bcm958625hr.dts
+++ b/arch/arm/boot/dts/bcm958625hr.dts
@@ -55,6 +55,7 @@
 	gpio-restart {
 		compatible = "gpio-restart";
 		gpios = <&gpioa 15 GPIO_ACTIVE_LOW>;
+		open-source;
 		priority = <200>;
 	};
 };
diff --git a/arch/arm/boot/dts/bcm988312hr.dts b/arch/arm/boot/dts/bcm988312hr.dts
index 104afe9..ed05e33 100644
--- a/arch/arm/boot/dts/bcm988312hr.dts
+++ b/arch/arm/boot/dts/bcm988312hr.dts
@@ -55,6 +55,7 @@
 	gpio-restart {
 		compatible = "gpio-restart";
 		gpios = <&gpioa 15 GPIO_ACTIVE_LOW>;
+		open-source;
 		priority = <200>;
 	};
 };
diff --git a/arch/arm/boot/dts/qcom-ipq8064.dtsi b/arch/arm/boot/dts/qcom-ipq8064.dtsi
index 2e37557..76f4e89 100644
--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
@@ -65,13 +65,13 @@
 		cxo_board {
 			compatible = "fixed-clock";
 			#clock-cells = <0>;
-			clock-frequency = <19200000>;
+			clock-frequency = <25000000>;
 		};
 
 		pxo_board {
 			compatible = "fixed-clock";
 			#clock-cells = <0>;
-			clock-frequency = <27000000>;
+			clock-frequency = <25000000>;
 		};
 
 		sleep_clk: sleep_clk {
diff --git a/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts b/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts
index 73c05da..e00539a 100644
--- a/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts
+++ b/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts
@@ -167,7 +167,7 @@
 					reg = <8>;
 					label = "cpu";
 					ethernet = <&gmac>;
-					phy-mode = "rgmii";
+					phy-mode = "rgmii-txid";
 					fixed-link {
 						speed = <1000>;
 						full-duplex;
diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig
index 1921325..fc0d3b0 100644
--- a/arch/arm/configs/sdxpoorwills-perf_defconfig
+++ b/arch/arm/configs/sdxpoorwills-perf_defconfig
@@ -174,6 +174,8 @@
 # CONFIG_NET_VENDOR_INTEL is not set
 CONFIG_KS8851=y
 # CONFIG_NET_VENDOR_MICROCHIP is not set
+CONFIG_ECM_IPA=y
+CONFIG_RNDIS_IPA=y
 # CONFIG_NET_VENDOR_NATSEMI is not set
 # CONFIG_NET_VENDOR_SEEQ is not set
 # CONFIG_NET_VENDOR_SMSC is not set
@@ -255,6 +257,8 @@
 CONFIG_UIO=y
 CONFIG_STAGING=y
 CONFIG_GSI=y
+CONFIG_IPA3=y
+CONFIG_IPA_UT=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
 CONFIG_USB_BAM=y
diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig
index 0a875b1..c62aa16 100644
--- a/arch/arm/configs/sdxpoorwills_defconfig
+++ b/arch/arm/configs/sdxpoorwills_defconfig
@@ -166,6 +166,8 @@
 # CONFIG_NET_VENDOR_INTEL is not set
 CONFIG_KS8851=y
 # CONFIG_NET_VENDOR_MICROCHIP is not set
+CONFIG_ECM_IPA=y
+CONFIG_RNDIS_IPA=y
 # CONFIG_NET_VENDOR_NATSEMI is not set
 # CONFIG_NET_VENDOR_SEEQ is not set
 # CONFIG_NET_VENDOR_SMSC is not set
@@ -248,6 +250,9 @@
 CONFIG_DMADEVICES=y
 CONFIG_UIO=y
 CONFIG_STAGING=y
+CONFIG_GSI=y
+CONFIG_IPA3=y
+CONFIG_IPA_UT=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
 CONFIG_HWSPINLOCK_QCOM=y
diff --git a/arch/arm/mach-omap2/omap-headsmp.S b/arch/arm/mach-omap2/omap-headsmp.S
index fe36ce2..4c6f14c 100644
--- a/arch/arm/mach-omap2/omap-headsmp.S
+++ b/arch/arm/mach-omap2/omap-headsmp.S
@@ -17,6 +17,7 @@
 
 #include <linux/linkage.h>
 #include <linux/init.h>
+#include <asm/assembler.h>
 
 #include "omap44xx.h"
 
@@ -66,7 +67,7 @@
 	cmp	r0, r4
 	bne	wait_2
 	ldr	r12, =API_HYP_ENTRY
-	adr	r0, hyp_boot
+	badr	r0, hyp_boot
 	smc	#0
 hyp_boot:
 	b	omap_secondary_startup
diff --git a/arch/arm64/boot/dts/qcom/pm8998.dtsi b/arch/arm64/boot/dts/qcom/pm8998.dtsi
index b9a6c79..f46b5639 100644
--- a/arch/arm64/boot/dts/qcom/pm8998.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8998.dtsi
@@ -36,6 +36,7 @@
 			interrupt-names = "kpdpwr", "resin",
 					"resin-bark", "kpdpwr-resin-bark";
 			qcom,pon-dbc-delay = <15625>;
+			qcom,kpdpwr-sw-debounce;
 			qcom,system-reset;
 			qcom,store-hard-reset-reason;
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
index e3f7036..072e592 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
@@ -500,4 +500,350 @@
 		cdm-client-names = "vfe";
 		status = "ok";
 	};
+
+	qcom,cam-isp {
+		compatible = "qcom,cam-isp";
+		arch-compat = "ife";
+		status = "ok";
+	};
+
+	qcom,csid0@acb3000 {
+		cell-index = <0>;
+		compatible = "qcom,csid170";
+		reg-names = "csid";
+		reg = <0xacb3000 0x1000>;
+		reg-cam-base = <0xb3000>;
+		interrupt-names = "csid";
+		interrupts = <0 464 0>;
+		regulator-names = "camss", "ife0";
+		camss-supply = <&titan_top_gdsc>;
+		ife0-supply = <&ife_0_gdsc>;
+		clock-names = "camera_ahb",
+			"camera_axi",
+			"soc_ahb_clk",
+			"cpas_ahb_clk",
+			"slow_ahb_clk_src",
+			"ife_csid_clk",
+			"ife_csid_clk_src",
+			"ife_cphy_rx_clk",
+			"cphy_rx_clk_src",
+			"ife_clk",
+			"ife_clk_src",
+			"camnoc_axi_clk",
+			"ife_axi_clk";
+		clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>,
+			<&clock_gcc GCC_CAMERA_AXI_CLK>,
+			<&clock_camcc CAM_CC_SOC_AHB_CLK>,
+			<&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+			<&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>,
+			<&clock_camcc CAM_CC_IFE_0_CSID_CLK>,
+			<&clock_camcc CAM_CC_IFE_0_CSID_CLK_SRC>,
+			<&clock_camcc CAM_CC_IFE_0_CPHY_RX_CLK>,
+			<&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>,
+			<&clock_camcc CAM_CC_IFE_0_CLK>,
+			<&clock_camcc CAM_CC_IFE_0_CLK_SRC>,
+			<&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
+			<&clock_camcc CAM_CC_IFE_0_AXI_CLK>;
+		clock-rates = <0 0 0 0 0 0 384000000 0 0 0 40400000 0 0>;
+		src-clock-name = "ife_csid_clk_src";
+		status = "ok";
+	};
+
+	qcom,vfe0@acaf000 {
+		cell-index = <0>;
+		compatible = "qcom,vfe170";
+		reg-names = "ife";
+		reg = <0xacaf000 0x4000>;
+		reg-cam-base = <0xaf000>;
+		interrupt-names = "ife";
+		interrupts = <0 465 0>;
+		regulator-names = "camss", "ife0";
+		camss-supply = <&titan_top_gdsc>;
+		ife0-supply = <&ife_0_gdsc>;
+		clock-names = "camera_ahb",
+			"camera_axi",
+			"soc_ahb_clk",
+			"cpas_ahb_clk",
+			"slow_ahb_clk_src",
+			"ife_clk",
+			"ife_clk_src",
+			"camnoc_axi_clk",
+			"ife_axi_clk";
+		clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>,
+			<&clock_gcc GCC_CAMERA_AXI_CLK>,
+			<&clock_camcc CAM_CC_SOC_AHB_CLK>,
+			<&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+			<&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>,
+			<&clock_camcc CAM_CC_IFE_0_CLK>,
+			<&clock_camcc CAM_CC_IFE_0_CLK_SRC>,
+			<&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
+			<&clock_camcc CAM_CC_IFE_0_AXI_CLK>;
+		clock-rates = <0 0 0 0 0 0 404000000 0 0>;
+		src-clock-name = "ife_clk_src";
+		clock-names-option =  "ife_dsp_clk";
+		clocks-option = <&clock_camcc CAM_CC_IFE_0_DSP_CLK>;
+		clock-rates-option = <404000000>;
+		status = "ok";
+	};
+
+	qcom,csid1@acba000 {
+		cell-index = <1>;
+		compatible = "qcom,csid170";
+		reg-names = "csid";
+		reg = <0xacba000 0x1000>;
+		reg-cam-base = <0xba000>;
+		interrupt-names = "csid";
+		interrupts = <0 466 0>;
+		regulator-names = "camss", "ife1";
+		camss-supply = <&titan_top_gdsc>;
+		ife1-supply = <&ife_1_gdsc>;
+		clock-names = "camera_ahb",
+			"camera_axi",
+			"soc_ahb_clk",
+			"cpas_ahb_clk",
+			"slow_ahb_clk_src",
+			"ife_csid_clk",
+			"ife_csid_clk_src",
+			"ife_cphy_rx_clk",
+			"cphy_rx_clk_src",
+			"ife_clk",
+			"ife_clk_src",
+			"camnoc_axi_clk",
+			"ife_axi_clk";
+		clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>,
+			<&clock_gcc GCC_CAMERA_AXI_CLK>,
+			<&clock_camcc CAM_CC_SOC_AHB_CLK>,
+			<&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+			<&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>,
+			<&clock_camcc CAM_CC_IFE_1_CSID_CLK>,
+			<&clock_camcc CAM_CC_IFE_1_CSID_CLK_SRC>,
+			<&clock_camcc CAM_CC_IFE_1_CPHY_RX_CLK>,
+			<&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>,
+			<&clock_camcc CAM_CC_IFE_1_CLK>,
+			<&clock_camcc CAM_CC_IFE_1_CLK_SRC>,
+			<&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
+			<&clock_camcc CAM_CC_IFE_1_AXI_CLK>;
+		clock-rates = <0 0 0 0 0 0 384000000 0 0 0 40400000 0 0>;
+		src-clock-name = "ife_csid_clk_src";
+		status = "ok";
+	};
+
+	qcom,vfe1@acb6000 {
+		cell-index = <1>;
+		compatible = "qcom,vfe170";
+		reg-names = "ife";
+		reg = <0xacb6000 0x4000>;
+		reg-cam-base = <0xb6000>;
+		interrupt-names = "ife";
+		interrupts = <0 467 0>;
+		regulator-names = "camss", "ife1";
+		camss-supply = <&titan_top_gdsc>;
+		ife1-supply = <&ife_1_gdsc>;
+		clock-names = "camera_ahb",
+			"camera_axi",
+			"soc_ahb_clk",
+			"cpas_ahb_clk",
+			"slow_ahb_clk_src",
+			"ife_clk",
+			"ife_clk_src",
+			"camnoc_axi_clk",
+			"ife_axi_clk";
+		clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>,
+			<&clock_gcc GCC_CAMERA_AXI_CLK>,
+			<&clock_camcc CAM_CC_SOC_AHB_CLK>,
+			<&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+			<&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>,
+			<&clock_camcc CAM_CC_IFE_1_CLK>,
+			<&clock_camcc CAM_CC_IFE_1_CLK_SRC>,
+			<&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
+			<&clock_camcc CAM_CC_IFE_1_AXI_CLK>;
+		clock-rates = <0 0 0 0 0 0 404000000 0 0>;
+		src-clock-name = "ife_clk_src";
+		clock-names-option =  "ife_dsp_clk";
+		clocks-option = <&clock_camcc CAM_CC_IFE_1_DSP_CLK>;
+		clock-rates-option = <404000000>;
+		status = "ok";
+	};
+
+	qcom,csid-lite@acc8000 {
+		cell-index = <2>;
+		compatible = "qcom,csid-lite170";
+		reg-names = "csid-lite";
+		reg = <0xacc8000 0x1000>;
+		reg-cam-base = <0xc8000>;
+		interrupt-names = "csid-lite";
+		interrupts = <0 468 0>;
+		regulator-names = "camss";
+		camss-supply = <&titan_top_gdsc>;
+		clock-names = "camera_ahb",
+			"camera_axi",
+			"soc_ahb_clk",
+			"cpas_ahb_clk",
+			"slow_ahb_clk_src",
+			"ife_csid_clk",
+			"ife_csid_clk_src",
+			"ife_cphy_rx_clk",
+			"cphy_rx_clk_src",
+			"ife_clk",
+			"ife_clk_src",
+			"camnoc_axi_clk";
+		clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>,
+			<&clock_gcc GCC_CAMERA_AXI_CLK>,
+			<&clock_camcc CAM_CC_SOC_AHB_CLK>,
+			<&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+			<&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>,
+			<&clock_camcc CAM_CC_IFE_LITE_CSID_CLK>,
+			<&clock_camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>,
+			<&clock_camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>,
+			<&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>,
+			<&clock_camcc CAM_CC_IFE_LITE_CLK>,
+			<&clock_camcc CAM_CC_IFE_LITE_CLK_SRC>,
+			<&clock_camcc CAM_CC_CAMNOC_AXI_CLK>;
+		clock-rates = <0 0 0 0 0 0 384000000 0 0 0 40400000 0>;
+		src-clock-name = "ife_csid_clk_src";
+		status = "ok";
+	};
+
+	qcom,vfe-lite@acc4000 {
+		cell-index = <2>;
+		compatible = "qcom,vfe-lite170";
+		reg-names = "ife-lite";
+		reg = <0xacc4000 0x4000>;
+		reg-cam-base = <0xc4000>;
+		interrupt-names = "ife-lite";
+		interrupts = <0 469 0>;
+		regulator-names = "camss";
+		camss-supply = <&titan_top_gdsc>;
+		clock-names = "camera_ahb",
+			"camera_axi",
+			"soc_ahb_clk",
+			"cpas_ahb_clk",
+			"slow_ahb_clk_src",
+			"ife_clk",
+			"ife_clk_src",
+			"camnoc_axi_clk";
+		clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>,
+			<&clock_gcc GCC_CAMERA_AXI_CLK>,
+			<&clock_camcc CAM_CC_SOC_AHB_CLK>,
+			<&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+			<&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>,
+			<&clock_camcc CAM_CC_IFE_LITE_CLK>,
+			<&clock_camcc CAM_CC_IFE_LITE_CLK_SRC>,
+			<&clock_camcc CAM_CC_CAMNOC_AXI_CLK>;
+		qcom,clock-rates = <0 0 0 0 0 0 404000000 0>;
+		src-clock-name = "ife_clk_src";
+		status = "ok";
+	};
+
+	qcom,cam-icp {
+		compatible = "qcom,cam-icp";
+		compat-hw-name = "qcom,a5",
+			"qcom,ipe0",
+			"qcom,ipe1",
+			"qcom,bps";
+		num-a5 = <1>;
+		num-ipe = <2>;
+		num-bps = <1>;
+		status = "ok";
+	};
+
+	qcom,a5@ac00000 {
+		cell-index = <0>;
+		compatible = "qcom,cam_a5";
+		reg = <0xac00000 0x6000>,
+			<0xac10000 0x8000>,
+			<0xac18000 0x3000>;
+		reg-names = "a5_qgic", "a5_sierra", "a5_csr";
+		reg-cam-base = <0x00000 0x10000 0x18000>;
+		interrupts = <0 463 0>;
+		interrupt-names = "a5";
+		regulator-names = "camss-vdd";
+		camss-vdd-supply = <&titan_top_gdsc>;
+		clock-names = "gcc_cam_ahb_clk",
+			"gcc_cam_axi_clk",
+			"soc_ahb_clk",
+			"cpas_ahb_clk",
+			"camnoc_axi_clk",
+			"icp_apb_clk",
+			"icp_atb_clk",
+			"icp_clk",
+			"icp_clk_src",
+			"icp_cti_clk",
+			"icp_ts_clk";
+		clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>,
+				<&clock_gcc GCC_CAMERA_AXI_CLK>,
+				<&clock_camcc CAM_CC_SOC_AHB_CLK>,
+				<&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+				<&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
+				<&clock_camcc CAM_CC_ICP_APB_CLK>,
+				<&clock_camcc CAM_CC_ICP_ATB_CLK>,
+				<&clock_camcc CAM_CC_ICP_CLK>,
+				<&clock_camcc CAM_CC_ICP_CLK_SRC>,
+				<&clock_camcc CAM_CC_ICP_CTI_CLK>,
+				<&clock_camcc CAM_CC_ICP_TS_CLK>;
+
+		clock-rates = <0 0 0 80000000 0 0 0 0 600000000 0 0>;
+		fw_name = "CAMERA_ICP.elf";
+		status = "ok";
+	};
+
+	qcom,ipe0 {
+		cell-index = <0>;
+		compatible = "qcom,cam_ipe";
+		regulator-names = "ipe0-vdd";
+		ipe0-vdd-supply = <&ipe_0_gdsc>;
+		clock-names = "ipe_0_ahb_clk",
+			"ipe_0_areg_clk",
+			"ipe_0_axi_clk",
+			"ipe_0_clk",
+			"ipe_0_clk_src";
+		clocks = <&clock_camcc CAM_CC_IPE_0_AHB_CLK>,
+				<&clock_camcc CAM_CC_IPE_0_AREG_CLK>,
+				<&clock_camcc CAM_CC_IPE_0_AXI_CLK>,
+				<&clock_camcc CAM_CC_IPE_0_CLK>,
+				<&clock_camcc CAM_CC_IPE_0_CLK_SRC>;
+
+		clock-rates = <80000000 400000000 0 0 600000000>;
+		status = "ok";
+	};
+
+	qcom,ipe1 {
+		cell-index = <1>;
+		compatible = "qcom,cam_ipe";
+		regulator-names = "ipe1-vdd";
+		ipe1-vdd-supply = <&ipe_1_gdsc>;
+		clock-names = "ipe_1_ahb_clk",
+			"ipe_1_areg_clk",
+			"ipe_1_axi_clk",
+			"ipe_1_clk",
+			"ipe_1_clk_src";
+		clocks = <&clock_camcc CAM_CC_IPE_1_AHB_CLK>,
+				<&clock_camcc CAM_CC_IPE_1_AREG_CLK>,
+				<&clock_camcc CAM_CC_IPE_1_AXI_CLK>,
+				<&clock_camcc CAM_CC_IPE_1_CLK>,
+				<&clock_camcc CAM_CC_IPE_1_CLK_SRC>;
+
+		clock-rates = <80000000 400000000 0 0 600000000>;
+		status = "ok";
+	};
+
+	qcom,bps {
+		cell-index = <0>;
+		compatible = "qcom,cam_bps";
+		regulator-names = "bps-vdd";
+		bps-vdd-supply = <&bps_gdsc>;
+		clock-names = "bps_ahb_clk",
+			"bps_areg_clk",
+			"bps_axi_clk",
+			"bps_clk",
+			"bps_clk_src";
+		clocks = <&clock_camcc CAM_CC_BPS_AHB_CLK>,
+				<&clock_camcc CAM_CC_BPS_AREG_CLK>,
+				<&clock_camcc CAM_CC_BPS_AXI_CLK>,
+				<&clock_camcc CAM_CC_BPS_CLK>,
+				<&clock_camcc CAM_CC_BPS_CLK_SRC>;
+
+		clock-rates = <80000000 400000000 0 0 600000000>;
+		status = "ok";
+	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
index 106d0c6..7cdc746 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
@@ -122,6 +122,17 @@
 	status = "ok";
 };
 
+&extcon_storage_cd {
+	gpio = <&tlmm 126 GPIO_ACTIVE_LOW>;
+	debounce-ms = <200>;
+	irq-flags = <IRQ_TYPE_EDGE_BOTH>;
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&storage_cd>;
+
+	status = "ok";
+};
+
 &ufsphy_card {
 	compatible = "qcom,ufs-phy-qmp-v3";
 
@@ -164,6 +175,8 @@
 				50000000 100000000 200000000>;
 	qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
 
+	extcon = <&extcon_storage_cd>;
+
 	status = "ok";
 };
 
@@ -481,3 +494,7 @@
 		};
 	};
 };
+
+&wil6210 {
+	status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
index 77edb85..1b3f2a6 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
@@ -64,7 +64,6 @@
 		qcom,initial-pwrlevel = <2>;
 
 		qcom,gpu-quirk-hfi-use-reg;
-		qcom,gpu-quirk-two-pass-use-wfi;
 
 		qcom,idle-timeout = <100000000>; //msecs
 		qcom,no-nap;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
index 3dc45ae..c776624 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
@@ -464,3 +464,7 @@
 		};
 	};
 };
+
+&wil6210 {
+	status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
index 947262fb..59b3396 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
@@ -112,6 +112,19 @@
 			};
 		};
 
+		storage_cd: storage_cd {
+			mux {
+				pins = "gpio126";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio126";
+				bias-pull-up;           /* pull up */
+				drive-strength = <2>;   /* 2 MA */
+			};
+		};
+
 		sdc2_clk_on: sdc2_clk_on {
 			config {
 				pins = "sdc2_clk";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
index 1ac661d..9056569 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
@@ -147,3 +147,7 @@
 &dsi_sharp_4k_dsc_video_display {
 	qcom,dsi-display-active;
 };
+
+&wil6210 {
+	status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 5ae733b..a911d5e 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -1378,6 +1378,12 @@
 		status = "disabled";
 	};
 
+	extcon_storage_cd: extcon_storage_cd {
+		compatible = "extcon-gpio";
+		extcon-id = <62>; /* EXTCON_MECHANICAL */
+		status = "disabled";
+	};
+
 	ufsphy_card: ufsphy_card@1da7000 {
 		reg = <0x1da7000 0xda8>; /* PHY regs */
 		reg-names = "phy_mem";
@@ -1910,6 +1916,12 @@
 		status = "ok";
 	};
 
+	ssc_sensors: qcom,msm-ssc-sensors {
+		compatible = "qcom,msm-ssc-sensors";
+		status = "ok";
+		qcom,firmware-name = "slpi";
+	};
+
 	cpuss_dump {
 		compatible = "qcom,cpuss-dump";
 		qcom,l1_i_cache0 {
@@ -3740,6 +3752,27 @@
 		qcom,affinity = <1>;
 		#thermal-sensor-cells = <0>;
 	};
+
+	wil6210: qcom,wil6210 {
+		compatible = "qcom,wil6210";
+		qcom,pcie-parent = <&pcie0>;
+		qcom,wigig-en = <&tlmm 39 0>;
+		qcom,msm-bus,name = "wil6210";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<45 512 0 0>,
+			<45 512 600000 800000>; /* ~4.6Gbps (MCS12) */
+		qcom,use-ext-supply;
+		vdd-supply= <&pm8998_s7>;
+		vddio-supply= <&pm8998_s5>;
+		qcom,use-ext-clocks;
+		clocks = <&clock_rpmh RPMH_RF_CLK3>,
+			 <&clock_rpmh RPMH_RF_CLK3_A>;
+		clock-names = "rf_clk3_clk", "rf_clk3_pin_clk";
+		qcom,smmu-support;
+		status = "disabled";
+	};
 };
 
 &pcie_0_gdsc {
diff --git a/arch/arm64/boot/dts/renesas/r8a7795.dtsi b/arch/arm64/boot/dts/renesas/r8a7795.dtsi
index 8c15040..9536f20 100644
--- a/arch/arm64/boot/dts/renesas/r8a7795.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a7795.dtsi
@@ -553,6 +553,7 @@
 			phy-mode = "rgmii-id";
 			#address-cells = <1>;
 			#size-cells = <0>;
+			status = "disabled";
 		};
 
 		can0: can@e6c30000 {
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index 86bae12..47e0042 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -78,7 +78,6 @@
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
 CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
 CONFIG_CPU_BOOST=y
 CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
@@ -338,7 +337,6 @@
 CONFIG_V4L_PLATFORM_DRIVERS=y
 CONFIG_SPECTRA_CAMERA=y
 CONFIG_MSM_VIDC_V4L2=y
-CONFIG_MSM_VIDC_VMEM=y
 CONFIG_MSM_VIDC_GOVERNORS=y
 CONFIG_MSM_SDE_ROTATOR=y
 CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
@@ -498,7 +496,6 @@
 CONFIG_DEVFREQ_GOV_MEMLAT=y
 CONFIG_DEVFREQ_SIMPLE_DEV=y
 CONFIG_QCOM_DEVFREQ_DEVBW=y
-CONFIG_EXTCON=y
 CONFIG_EXTCON_USB_GPIO=y
 CONFIG_IIO=y
 CONFIG_QCOM_RRADC=y
@@ -507,6 +504,7 @@
 CONFIG_ARM_GIC_V3_ACL=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
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index 1436a40..261744d 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -84,7 +84,6 @@
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
 CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
 CONFIG_CPU_BOOST=y
 CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
@@ -347,7 +346,6 @@
 CONFIG_V4L_PLATFORM_DRIVERS=y
 CONFIG_SPECTRA_CAMERA=y
 CONFIG_MSM_VIDC_V4L2=y
-CONFIG_MSM_VIDC_VMEM=y
 CONFIG_MSM_VIDC_GOVERNORS=y
 CONFIG_MSM_SDE_ROTATOR=y
 CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
@@ -519,7 +517,6 @@
 CONFIG_DEVFREQ_GOV_MEMLAT=y
 CONFIG_DEVFREQ_SIMPLE_DEV=y
 CONFIG_QCOM_DEVFREQ_DEVBW=y
-CONFIG_EXTCON=y
 CONFIG_EXTCON_USB_GPIO=y
 CONFIG_IIO=y
 CONFIG_QCOM_RRADC=y
@@ -529,6 +526,7 @@
 CONFIG_PHY_XGENE=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
@@ -595,6 +593,7 @@
 CONFIG_CPU_FREQ_SWITCH_PROFILER=y
 CONFIG_LKDTM=y
 CONFIG_MEMTEST=y
+CONFIG_PANIC_ON_DATA_CORRUPTION=y
 CONFIG_ARM64_PTDUMP=y
 CONFIG_PID_IN_CONTEXTIDR=y
 CONFIG_CORESIGHT=y
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 875545d..3845f33 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -72,9 +72,8 @@
 #define pte_young(pte)		(!!(pte_val(pte) & PTE_AF))
 #define pte_special(pte)	(!!(pte_val(pte) & PTE_SPECIAL))
 #define pte_write(pte)		(!!(pte_val(pte) & PTE_WRITE))
-#define pte_exec(pte)		(!(pte_val(pte) & PTE_UXN))
+#define pte_user_exec(pte)	(!(pte_val(pte) & PTE_UXN))
 #define pte_cont(pte)		(!!(pte_val(pte) & PTE_CONT))
-#define pte_ng(pte)		(!!(pte_val(pte) & PTE_NG))
 
 #ifdef CONFIG_ARM64_HW_AFDBM
 #define pte_hw_dirty(pte)	(pte_write(pte) && !(pte_val(pte) & PTE_RDONLY))
@@ -85,8 +84,12 @@
 #define pte_dirty(pte)		(pte_sw_dirty(pte) || pte_hw_dirty(pte))
 
 #define pte_valid(pte)		(!!(pte_val(pte) & PTE_VALID))
-#define pte_valid_global(pte) \
-	((pte_val(pte) & (PTE_VALID | PTE_NG)) == PTE_VALID)
+/*
+ * Execute-only user mappings do not have the PTE_USER bit set. All valid
+ * kernel mappings have the PTE_UXN bit set.
+ */
+#define pte_valid_not_user(pte) \
+	((pte_val(pte) & (PTE_VALID | PTE_USER | PTE_UXN)) == (PTE_VALID | PTE_UXN))
 #define pte_valid_young(pte) \
 	((pte_val(pte) & (PTE_VALID | PTE_AF)) == (PTE_VALID | PTE_AF))
 
@@ -207,7 +210,7 @@
 	 * Only if the new pte is valid and kernel, otherwise TLB maintenance
 	 * or update_mmu_cache() have the necessary barriers.
 	 */
-	if (pte_valid_global(pte)) {
+	if (pte_valid_not_user(pte)) {
 		dsb(ishst);
 		isb();
 	}
@@ -241,7 +244,7 @@
 			pte_val(pte) &= ~PTE_RDONLY;
 		else
 			pte_val(pte) |= PTE_RDONLY;
-		if (pte_ng(pte) && pte_exec(pte) && !pte_special(pte))
+		if (pte_user_exec(pte) && !pte_special(pte))
 			__sync_icache_dcache(pte, addr);
 	}
 
diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c
index b2fc97a..9c4b57a 100644
--- a/arch/arm64/net/bpf_jit_comp.c
+++ b/arch/arm64/net/bpf_jit_comp.c
@@ -779,14 +779,14 @@
 		int ret;
 
 		ret = build_insn(insn, ctx);
-
-		if (ctx->image == NULL)
-			ctx->offset[i] = ctx->idx;
-
 		if (ret > 0) {
 			i++;
+			if (ctx->image == NULL)
+				ctx->offset[i] = ctx->idx;
 			continue;
 		}
+		if (ctx->image == NULL)
+			ctx->offset[i] = ctx->idx;
 		if (ret)
 			return ret;
 	}
diff --git a/arch/mips/kernel/mips-r2-to-r6-emul.c b/arch/mips/kernel/mips-r2-to-r6-emul.c
index bd09853..d8227f2 100644
--- a/arch/mips/kernel/mips-r2-to-r6-emul.c
+++ b/arch/mips/kernel/mips-r2-to-r6-emul.c
@@ -433,8 +433,8 @@
 	rs = regs->regs[MIPSInst_RS(ir)];
 	res = (u64)rt * (u64)rs;
 	rt = res;
-	regs->lo = (s64)rt;
-	regs->hi = (s64)(res >> 32);
+	regs->lo = (s64)(s32)rt;
+	regs->hi = (s64)(s32)(res >> 32);
 
 	MIPS_R2_STATS(muls);
 
@@ -670,9 +670,9 @@
 	res += ((((s64)rt) << 32) | (u32)rs);
 
 	rt = res;
-	regs->lo = (s64)rt;
+	regs->lo = (s64)(s32)rt;
 	rs = res >> 32;
-	regs->hi = (s64)rs;
+	regs->hi = (s64)(s32)rs;
 
 	MIPS_R2_STATS(dsps);
 
@@ -728,9 +728,9 @@
 	res = ((((s64)rt) << 32) | (u32)rs) - res;
 
 	rt = res;
-	regs->lo = (s64)rt;
+	regs->lo = (s64)(s32)rt;
 	rs = res >> 32;
-	regs->hi = (s64)rs;
+	regs->hi = (s64)(s32)rs;
 
 	MIPS_R2_STATS(dsps);
 
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 65fba4c..8f01f21 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -388,8 +388,8 @@
 	  be disabled also.
 
 	  If you have a toolchain which supports mprofile-kernel, then you can
-	  enable this. Otherwise leave it disabled. If you're not sure, say
-	  "N".
+	  disable this. Otherwise leave it enabled. If you're not sure, say
+	  "Y".
 
 config MPROFILE_KERNEL
 	depends on PPC64 && CPU_LITTLE_ENDIAN
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 13f5fad..e7d9eca 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -337,7 +337,7 @@
 #define   LPCR_DPFD_SH		52
 #define   LPCR_DPFD		(ASM_CONST(7) << LPCR_DPFD_SH)
 #define   LPCR_VRMASD_SH	47
-#define   LPCR_VRMASD		(ASM_CONST(1) << LPCR_VRMASD_SH)
+#define   LPCR_VRMASD		(ASM_CONST(0x1f) << LPCR_VRMASD_SH)
 #define   LPCR_VRMA_L		ASM_CONST(0x0008000000000000)
 #define   LPCR_VRMA_LP0		ASM_CONST(0x0001000000000000)
 #define   LPCR_VRMA_LP1		ASM_CONST(0x0000800000000000)
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 1925341..adb52d1 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -15,7 +15,7 @@
 endif
 
 CFLAGS_cputable.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
-CFLAGS_init.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
+CFLAGS_prom_init.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
 CFLAGS_btext.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
 CFLAGS_prom.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
 
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index 44d2d84..483d8c0 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -146,7 +146,7 @@
 opal_tracepoint_return:
 	std	r3,STK_REG(R31)(r1)
 	mr	r4,r3
-	ld	r0,STK_REG(R23)(r1)
+	ld	r3,STK_REG(R23)(r1)
 	bl	__trace_opal_exit
 	ld	r3,STK_REG(R31)(r1)
 	addi	r1,r1,STACKFRAMESIZE
diff --git a/arch/sparc/kernel/head_64.S b/arch/sparc/kernel/head_64.S
index 6aa3da1..9835152 100644
--- a/arch/sparc/kernel/head_64.S
+++ b/arch/sparc/kernel/head_64.S
@@ -935,3 +935,9 @@
 	retl
 	 mov	%o1, %o0
 ENDPROC(__retl_o1)
+
+ENTRY(__retl_o1_asi)
+	wr      %o5, 0x0, %asi
+	retl
+	 mov    %o1, %o0
+ENDPROC(__retl_o1_asi)
diff --git a/arch/sparc/lib/GENbzero.S b/arch/sparc/lib/GENbzero.S
index 8e7a843..2fbf629 100644
--- a/arch/sparc/lib/GENbzero.S
+++ b/arch/sparc/lib/GENbzero.S
@@ -8,7 +8,7 @@
 98:	x,y;			\
 	.section __ex_table,"a";\
 	.align 4;		\
-	.word 98b, __retl_o1;	\
+	.word 98b, __retl_o1_asi;\
 	.text;			\
 	.align 4;
 
diff --git a/arch/sparc/lib/NGbzero.S b/arch/sparc/lib/NGbzero.S
index beab29b..33053bd 100644
--- a/arch/sparc/lib/NGbzero.S
+++ b/arch/sparc/lib/NGbzero.S
@@ -8,7 +8,7 @@
 98:	x,y;			\
 	.section __ex_table,"a";\
 	.align 4;		\
-	.word 98b, __retl_o1;	\
+	.word 98b, __retl_o1_asi;\
 	.text;			\
 	.align 4;
 
diff --git a/arch/x86/events/intel/pt.c b/arch/x86/events/intel/pt.c
index c5047b8..df60b58 100644
--- a/arch/x86/events/intel/pt.c
+++ b/arch/x86/events/intel/pt.c
@@ -106,18 +106,24 @@
 };
 
 PMU_FORMAT_ATTR(cyc,		"config:1"	);
+PMU_FORMAT_ATTR(pwr_evt,	"config:4"	);
+PMU_FORMAT_ATTR(fup_on_ptw,	"config:5"	);
 PMU_FORMAT_ATTR(mtc,		"config:9"	);
 PMU_FORMAT_ATTR(tsc,		"config:10"	);
 PMU_FORMAT_ATTR(noretcomp,	"config:11"	);
+PMU_FORMAT_ATTR(ptw,		"config:12"	);
 PMU_FORMAT_ATTR(mtc_period,	"config:14-17"	);
 PMU_FORMAT_ATTR(cyc_thresh,	"config:19-22"	);
 PMU_FORMAT_ATTR(psb_period,	"config:24-27"	);
 
 static struct attribute *pt_formats_attr[] = {
 	&format_attr_cyc.attr,
+	&format_attr_pwr_evt.attr,
+	&format_attr_fup_on_ptw.attr,
 	&format_attr_mtc.attr,
 	&format_attr_tsc.attr,
 	&format_attr_noretcomp.attr,
+	&format_attr_ptw.attr,
 	&format_attr_mtc_period.attr,
 	&format_attr_cyc_thresh.attr,
 	&format_attr_psb_period.attr,
diff --git a/arch/x86/include/asm/xen/events.h b/arch/x86/include/asm/xen/events.h
index 608a79d..e6911ca 100644
--- a/arch/x86/include/asm/xen/events.h
+++ b/arch/x86/include/asm/xen/events.h
@@ -20,4 +20,15 @@
 /* No need for a barrier -- XCHG is a barrier on x86. */
 #define xchg_xen_ulong(ptr, val) xchg((ptr), (val))
 
+extern int xen_have_vector_callback;
+
+/*
+ * Events delivered via platform PCI interrupts are always
+ * routed to vcpu 0 and hence cannot be rebound.
+ */
+static inline bool xen_support_evtchn_rebind(void)
+{
+	return (!xen_hvm_domain() || xen_have_vector_callback);
+}
+
 #endif /* _ASM_X86_XEN_EVENTS_H */
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index d1e2556..7249f15 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -1876,6 +1876,7 @@
 	.irq_ack		= irq_chip_ack_parent,
 	.irq_eoi		= ioapic_ack_level,
 	.irq_set_affinity	= ioapic_set_affinity,
+	.irq_retrigger		= irq_chip_retrigger_hierarchy,
 	.flags			= IRQCHIP_SKIP_SET_WAKE,
 };
 
@@ -1887,6 +1888,7 @@
 	.irq_ack		= irq_chip_ack_parent,
 	.irq_eoi		= ioapic_ir_ack_level,
 	.irq_set_affinity	= ioapic_set_affinity,
+	.irq_retrigger		= irq_chip_retrigger_hierarchy,
 	.flags			= IRQCHIP_SKIP_SET_WAKE,
 };
 
diff --git a/arch/x86/kernel/kprobes/common.h b/arch/x86/kernel/kprobes/common.h
index c6ee63f..d688826 100644
--- a/arch/x86/kernel/kprobes/common.h
+++ b/arch/x86/kernel/kprobes/common.h
@@ -67,7 +67,7 @@
 #endif
 
 /* Ensure if the instruction can be boostable */
-extern int can_boost(kprobe_opcode_t *instruction);
+extern int can_boost(kprobe_opcode_t *instruction, void *addr);
 /* Recover instruction if given address is probed */
 extern unsigned long recover_probed_instruction(kprobe_opcode_t *buf,
 					 unsigned long addr);
diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c
index d9d8d16..b55d07b 100644
--- a/arch/x86/kernel/kprobes/core.c
+++ b/arch/x86/kernel/kprobes/core.c
@@ -166,12 +166,12 @@
  * Returns non-zero if opcode is boostable.
  * RIP relative instructions are adjusted at copying time in 64 bits mode
  */
-int can_boost(kprobe_opcode_t *opcodes)
+int can_boost(kprobe_opcode_t *opcodes, void *addr)
 {
 	kprobe_opcode_t opcode;
 	kprobe_opcode_t *orig_opcodes = opcodes;
 
-	if (search_exception_tables((unsigned long)opcodes))
+	if (search_exception_tables((unsigned long)addr))
 		return 0;	/* Page fault may occur on this address. */
 
 retry:
@@ -416,7 +416,7 @@
 	 * __copy_instruction can modify the displacement of the instruction,
 	 * but it doesn't affect boostable check.
 	 */
-	if (can_boost(p->ainsn.insn))
+	if (can_boost(p->ainsn.insn, p->addr))
 		p->ainsn.boostable = 0;
 	else
 		p->ainsn.boostable = -1;
diff --git a/arch/x86/kernel/kprobes/opt.c b/arch/x86/kernel/kprobes/opt.c
index 3bb4c5f..4d74f73 100644
--- a/arch/x86/kernel/kprobes/opt.c
+++ b/arch/x86/kernel/kprobes/opt.c
@@ -178,7 +178,7 @@
 
 	while (len < RELATIVEJUMP_SIZE) {
 		ret = __copy_instruction(dest + len, src + len);
-		if (!ret || !can_boost(dest + len))
+		if (!ret || !can_boost(dest + len, src + len))
 			return -EINVAL;
 		len += ret;
 	}
diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c
index 5d400ba..d475179 100644
--- a/arch/x86/kernel/pci-calgary_64.c
+++ b/arch/x86/kernel/pci-calgary_64.c
@@ -296,7 +296,7 @@
 
 	/* were we called with bad_dma_address? */
 	badend = DMA_ERROR_CODE + (EMERGENCY_PAGES * PAGE_SIZE);
-	if (unlikely((dma_addr >= DMA_ERROR_CODE) && (dma_addr < badend))) {
+	if (unlikely(dma_addr < badend)) {
 		WARN(1, KERN_ERR "Calgary: driver tried unmapping bad DMA "
 		       "address 0x%Lx\n", dma_addr);
 		return;
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index afa7bbb..967e459 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -846,12 +846,6 @@
 	if (!best)
 		best = check_cpuid_limit(vcpu, function, index);
 
-	/*
-	 * Perfmon not yet supported for L2 guest.
-	 */
-	if (is_guest_mode(vcpu) && function == 0xa)
-		best = NULL;
-
 	if (best) {
 		*eax = best->eax;
 		*ebx = best->ebx;
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 43b55ef..89b98e0 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -8051,8 +8051,6 @@
 	case EXIT_REASON_TASK_SWITCH:
 		return true;
 	case EXIT_REASON_CPUID:
-		if (kvm_register_read(vcpu, VCPU_REGS_RAX) == 0xa)
-			return false;
 		return true;
 	case EXIT_REASON_HLT:
 		return nested_cpu_has(vmcs12, CPU_BASED_HLT_EXITING);
@@ -8137,6 +8135,9 @@
 		return nested_cpu_has2(vmcs12, SECONDARY_EXEC_XSAVES);
 	case EXIT_REASON_PREEMPTION_TIMER:
 		return false;
+	case EXIT_REASON_PML_FULL:
+		/* We don't expose PML support to L1. */
+		return false;
 	default:
 		return true;
 	}
@@ -10073,6 +10074,18 @@
 
 	}
 
+	if (enable_pml) {
+		/*
+		 * Conceptually we want to copy the PML address and index from
+		 * vmcs01 here, and then back to vmcs01 on nested vmexit. But,
+		 * since we always flush the log on each vmexit, this happens
+		 * to be equivalent to simply resetting the fields in vmcs02.
+		 */
+		ASSERT(vmx->pml_pg);
+		vmcs_write64(PML_ADDRESS, page_to_phys(vmx->pml_pg));
+		vmcs_write16(GUEST_PML_INDEX, PML_ENTITY_NUM - 1);
+	}
+
 	if (nested_cpu_has_ept(vmcs12)) {
 		kvm_mmu_unload(vcpu);
 		nested_ept_init_mmu_context(vcpu);
diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
index a00a6c0..4ea9f29 100644
--- a/arch/x86/pci/xen.c
+++ b/arch/x86/pci/xen.c
@@ -447,7 +447,7 @@
 
 int __init pci_xen_hvm_init(void)
 {
-	if (!xen_feature(XENFEAT_hvm_pirqs))
+	if (!xen_have_vector_callback || !xen_feature(XENFEAT_hvm_pirqs))
 		return 0;
 
 #ifdef CONFIG_ACPI
diff --git a/arch/x86/platform/intel-mid/device_libs/platform_mrfld_wdt.c b/arch/x86/platform/intel-mid/device_libs/platform_mrfld_wdt.c
index 3f1f1c7..10bad1e 100644
--- a/arch/x86/platform/intel-mid/device_libs/platform_mrfld_wdt.c
+++ b/arch/x86/platform/intel-mid/device_libs/platform_mrfld_wdt.c
@@ -19,7 +19,7 @@
 #include <asm/intel_scu_ipc.h>
 #include <asm/io_apic.h>
 
-#define TANGIER_EXT_TIMER0_MSI 15
+#define TANGIER_EXT_TIMER0_MSI 12
 
 static struct platform_device wdt_dev = {
 	.name = "intel_mid_wdt",
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index bdd8556..8f1f7ef 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -137,6 +137,8 @@
 void *xen_initial_gdt;
 
 RESERVE_BRK(shared_info_page_brk, PAGE_SIZE);
+__read_mostly int xen_have_vector_callback;
+EXPORT_SYMBOL_GPL(xen_have_vector_callback);
 
 static int xen_cpu_up_prepare(unsigned int cpu);
 static int xen_cpu_up_online(unsigned int cpu);
@@ -1521,7 +1523,10 @@
 	if (!xen_feature(XENFEAT_auto_translated_physmap))
 		return;
 
-	BUG_ON(!xen_feature(XENFEAT_hvm_callback_vector));
+	if (!xen_feature(XENFEAT_hvm_callback_vector))
+		return;
+
+	xen_have_vector_callback = 1;
 
 	xen_pvh_early_cpu_init(0, false);
 	xen_pvh_set_cr_flags(0);
@@ -1860,7 +1865,9 @@
 		xen_vcpu_setup(cpu);
 	}
 
-	if (xen_pv_domain() || xen_feature(XENFEAT_hvm_safe_pvclock))
+	if (xen_pv_domain() ||
+	    (xen_have_vector_callback &&
+	     xen_feature(XENFEAT_hvm_safe_pvclock)))
 		xen_setup_timer(cpu);
 
 	rc = xen_smp_intr_init(cpu);
@@ -1876,7 +1883,9 @@
 {
 	xen_smp_intr_free(cpu);
 
-	if (xen_pv_domain() || xen_feature(XENFEAT_hvm_safe_pvclock))
+	if (xen_pv_domain() ||
+	    (xen_have_vector_callback &&
+	     xen_feature(XENFEAT_hvm_safe_pvclock)))
 		xen_teardown_timer(cpu);
 
 	return 0;
@@ -1915,8 +1924,8 @@
 
 	xen_panic_handler_init();
 
-	BUG_ON(!xen_feature(XENFEAT_hvm_callback_vector));
-
+	if (xen_feature(XENFEAT_hvm_callback_vector))
+		xen_have_vector_callback = 1;
 	xen_hvm_smp_init();
 	WARN_ON(xen_cpuhp_setup());
 	xen_unplug_emulated_devices();
@@ -1954,7 +1963,7 @@
 		return false;
 	if (!xen_hvm_domain())
 		return false;
-	if (xen_feature(XENFEAT_hvm_pirqs))
+	if (xen_feature(XENFEAT_hvm_pirqs) && xen_have_vector_callback)
 		return false;
 	return true;
 }
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index 311acad..137afbb 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -765,6 +765,8 @@
 
 void __init xen_hvm_smp_init(void)
 {
+	if (!xen_have_vector_callback)
+		return;
 	smp_ops.smp_prepare_cpus = xen_hvm_smp_prepare_cpus;
 	smp_ops.smp_send_reschedule = xen_smp_send_reschedule;
 	smp_ops.cpu_die = xen_cpu_die;
diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
index 33d8f6a..67356d2 100644
--- a/arch/x86/xen/time.c
+++ b/arch/x86/xen/time.c
@@ -432,6 +432,11 @@
 
 void __init xen_hvm_init_time_ops(void)
 {
+	/* vector callback is needed otherwise we cannot receive interrupts
+	 * on cpu > 0 and at this point we don't know how many cpus are
+	 * available */
+	if (!xen_have_vector_callback)
+		return;
 	if (!xen_feature(XENFEAT_hvm_safe_pvclock)) {
 		printk(KERN_INFO "Xen doesn't support pvclock on HVM,"
 				"disable pv timer\n");
diff --git a/block/blk-integrity.c b/block/blk-integrity.c
index d69c5c7..319f2e4 100644
--- a/block/blk-integrity.c
+++ b/block/blk-integrity.c
@@ -417,7 +417,7 @@
 	bi->tuple_size = template->tuple_size;
 	bi->tag_size = template->tag_size;
 
-	blk_integrity_revalidate(disk);
+	disk->queue->backing_dev_info.capabilities |= BDI_CAP_STABLE_WRITES;
 }
 EXPORT_SYMBOL(blk_integrity_register);
 
@@ -430,26 +430,11 @@
  */
 void blk_integrity_unregister(struct gendisk *disk)
 {
-	blk_integrity_revalidate(disk);
+	disk->queue->backing_dev_info.capabilities &= ~BDI_CAP_STABLE_WRITES;
 	memset(&disk->queue->integrity, 0, sizeof(struct blk_integrity));
 }
 EXPORT_SYMBOL(blk_integrity_unregister);
 
-void blk_integrity_revalidate(struct gendisk *disk)
-{
-	struct blk_integrity *bi = &disk->queue->integrity;
-
-	if (!(disk->flags & GENHD_FL_UP))
-		return;
-
-	if (bi->profile)
-		disk->queue->backing_dev_info.capabilities |=
-			BDI_CAP_STABLE_WRITES;
-	else
-		disk->queue->backing_dev_info.capabilities &=
-			~BDI_CAP_STABLE_WRITES;
-}
-
 void blk_integrity_add(struct gendisk *disk)
 {
 	if (kobject_init_and_add(&disk->integrity_kobj, &integrity_ktype,
diff --git a/block/partition-generic.c b/block/partition-generic.c
index 71d9ed9..a2437c0 100644
--- a/block/partition-generic.c
+++ b/block/partition-generic.c
@@ -447,7 +447,6 @@
 
 	if (disk->fops->revalidate_disk)
 		disk->fops->revalidate_disk(disk);
-	blk_integrity_revalidate(disk);
 	check_disk_size_change(disk, bdev);
 	bdev->bd_invalidated = 0;
 	if (!get_capacity(disk) || !(state = check_partition(disk, bdev)))
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 6266a37..5f8abc3 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -208,4 +208,6 @@
 
 source "drivers/fpga/Kconfig"
 
+source "drivers/sensors/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 1419893..413dff9 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -176,3 +176,4 @@
 obj-$(CONFIG_NVMEM)		+= nvmem/
 obj-$(CONFIG_ESOC)              += esoc/
 obj-$(CONFIG_FPGA)		+= fpga/
+obj-$(CONFIG_SENSORS_SSC)		+= sensors/
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index e595013..a017ccd 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -140,7 +140,7 @@
  * Allocates a new struct tpm_chip instance and assigns a free
  * device number for it. Must be paired with put_device(&chip->dev).
  */
-struct tpm_chip *tpm_chip_alloc(struct device *dev,
+struct tpm_chip *tpm_chip_alloc(struct device *pdev,
 				const struct tpm_class_ops *ops)
 {
 	struct tpm_chip *chip;
@@ -159,7 +159,7 @@
 	rc = idr_alloc(&dev_nums_idr, NULL, 0, TPM_NUM_DEVICES, GFP_KERNEL);
 	mutex_unlock(&idr_lock);
 	if (rc < 0) {
-		dev_err(dev, "No available tpm device numbers\n");
+		dev_err(pdev, "No available tpm device numbers\n");
 		kfree(chip);
 		return ERR_PTR(rc);
 	}
@@ -169,7 +169,7 @@
 
 	chip->dev.class = tpm_class;
 	chip->dev.release = tpm_dev_release;
-	chip->dev.parent = dev;
+	chip->dev.parent = pdev;
 	chip->dev.groups = chip->groups;
 
 	if (chip->dev_num == 0)
@@ -181,7 +181,7 @@
 	if (rc)
 		goto out;
 
-	if (!dev)
+	if (!pdev)
 		chip->flags |= TPM_CHIP_FLAG_VIRTUAL;
 
 	cdev_init(&chip->cdev, &tpm_fops);
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 4d183c9..aa4299c 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -518,6 +518,11 @@
 }
 #endif
 
+static inline inline u32 tpm2_rc_value(u32 rc)
+{
+	return (rc & BIT(7)) ? rc & 0xff : rc;
+}
+
 int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
 int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash);
 int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max);
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 7df55d58..17896d6 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -529,7 +529,7 @@
 	tpm_buf_destroy(&buf);
 
 	if (rc > 0) {
-		if ((rc & TPM2_RC_HASH) == TPM2_RC_HASH)
+		if (tpm2_rc_value(rc) == TPM2_RC_HASH)
 			rc = -EINVAL;
 		else
 			rc = -EPERM;
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 925081e..42042c0 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -87,6 +87,8 @@
 obj-$(CONFIG_CLK_UNIPHIER)		+= uniphier/
 obj-$(CONFIG_ARCH_U8500)		+= ux500/
 obj-$(CONFIG_COMMON_CLK_VERSATILE)	+= versatile/
+ifeq ($(CONFIG_COMMON_CLK), y)
 obj-$(CONFIG_X86)			+= x86/
+endif
 obj-$(CONFIG_ARCH_ZX)			+= zte/
 obj-$(CONFIG_ARCH_ZYNQ)			+= zynq/
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 1b545d6..1f0c111 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -1801,6 +1801,15 @@
 		clk_enable_unlock(flags);
 	}
 
+	trace_clk_set_rate(core, core->new_rate);
+
+	/* Enforce vdd requirements for new frequency. */
+	if (core->prepare_count) {
+		rc = clk_vote_rate_vdd(core, core->new_rate);
+		if (rc)
+			goto out;
+	}
+
 	if (core->new_parent && core->new_parent != core->parent) {
 		old_parent = __clk_set_parent_before(core, core->new_parent);
 		trace_clk_set_parent(core, core->new_parent);
@@ -1821,15 +1830,6 @@
 	if (core->flags & CLK_OPS_PARENT_ENABLE)
 		clk_core_prepare_enable(parent);
 
-	trace_clk_set_rate(core, core->new_rate);
-
-	/* Enforce vdd requirements for new frequency. */
-	if (core->prepare_count) {
-		rc = clk_vote_rate_vdd(core, core->new_rate);
-		if (rc)
-			goto out;
-	}
-
 	if (!skip_set_rate && core->ops->set_rate) {
 		rc = core->ops->set_rate(core->hw, core->new_rate,
 						best_parent_rate);
@@ -2329,6 +2329,21 @@
 }
 EXPORT_SYMBOL_GPL(clk_set_flags);
 
+unsigned long clk_list_frequency(struct clk *clk, unsigned int index)
+{
+	int ret = 0;
+
+	if (!clk || !clk->core->ops->list_rate)
+		return -EINVAL;
+
+	clk_prepare_lock();
+	ret = clk->core->ops->list_rate(clk->core->hw, index, ULONG_MAX);
+	clk_prepare_unlock();
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_list_frequency);
+
 /***        debugfs support        ***/
 
 #ifdef CONFIG_DEBUG_FS
diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c
index 29421a1..228f716 100644
--- a/drivers/clk/qcom/gcc-sdm845.c
+++ b/drivers/clk/qcom/gcc-sdm845.c
@@ -1698,6 +1698,19 @@
 	},
 };
 
+static struct clk_branch gcc_gpu_iref_clk = {
+	.halt_reg = 0x8c010,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x8c010,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_gpu_iref_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
 static struct clk_branch gcc_gpu_memnoc_gfx_clk = {
 	.halt_reg = 0x7100c,
 	.halt_check = BRANCH_VOTED,
@@ -3310,6 +3323,7 @@
 	[GCC_GPU_CFG_AHB_CLK] = &gcc_gpu_cfg_ahb_clk.clkr,
 	[GCC_GPU_GPLL0_CLK_SRC] = &gcc_gpu_gpll0_clk_src.clkr,
 	[GCC_GPU_GPLL0_DIV_CLK_SRC] = &gcc_gpu_gpll0_div_clk_src.clkr,
+	[GCC_GPU_IREF_CLK] = &gcc_gpu_iref_clk.clkr,
 	[GCC_GPU_MEMNOC_GFX_CLK] = &gcc_gpu_memnoc_gfx_clk.clkr,
 	[GCC_GPU_SNOC_DVM_GFX_CLK] = &gcc_gpu_snoc_dvm_gfx_clk.clkr,
 	[GCC_MSS_AXIS2_CLK] = &gcc_mss_axis2_clk.clkr,
diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c
index 924f560..dcde70f 100644
--- a/drivers/clk/rockchip/clk-rk3036.c
+++ b/drivers/clk/rockchip/clk-rk3036.c
@@ -127,7 +127,7 @@
 PNAME(mux_pll_src_3plls_p)	= { "apll", "dpll", "gpll" };
 PNAME(mux_timer_p)		= { "xin24m", "pclk_peri_src" };
 
-PNAME(mux_pll_src_apll_dpll_gpll_usb480m_p)	= { "apll", "dpll", "gpll" "usb480m" };
+PNAME(mux_pll_src_apll_dpll_gpll_usb480m_p)	= { "apll", "dpll", "gpll", "usb480m" };
 
 PNAME(mux_mmc_src_p)	= { "apll", "dpll", "gpll", "xin24m" };
 PNAME(mux_i2s_pre_p)	= { "i2s_src", "i2s_frac", "ext_i2s", "xin12m" };
diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c
index 660dc20..2474f14 100644
--- a/drivers/crypto/caam/caamhash.c
+++ b/drivers/crypto/caam/caamhash.c
@@ -154,6 +154,7 @@
 					ctx_len, DMA_FROM_DEVICE);
 	if (dma_mapping_error(jrdev, state->ctx_dma)) {
 		dev_err(jrdev, "unable to map ctx\n");
+		state->ctx_dma = 0;
 		return -ENOMEM;
 	}
 
@@ -214,6 +215,7 @@
 	state->ctx_dma = dma_map_single(jrdev, state->caam_ctx, ctx_len, flag);
 	if (dma_mapping_error(jrdev, state->ctx_dma)) {
 		dev_err(jrdev, "unable to map ctx\n");
+		state->ctx_dma = 0;
 		return -ENOMEM;
 	}
 
@@ -620,8 +622,10 @@
 	struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
 	struct caam_hash_state *state = ahash_request_ctx(req);
 
-	if (state->ctx_dma)
+	if (state->ctx_dma) {
 		dma_unmap_single(dev, state->ctx_dma, ctx->ctx_len, flag);
+		state->ctx_dma = 0;
+	}
 	ahash_unmap(dev, edesc, req, dst_len);
 }
 
@@ -1605,6 +1609,7 @@
 	state->finup = ahash_finup_first;
 	state->final = ahash_final_no_ctx;
 
+	state->ctx_dma = 0;
 	state->current_buf = 0;
 	state->buf_dma = 0;
 	state->buflen_0 = 0;
diff --git a/drivers/devfreq/arm-memlat-mon.c b/drivers/devfreq/arm-memlat-mon.c
index ed83185..5802c21 100644
--- a/drivers/devfreq/arm-memlat-mon.c
+++ b/drivers/devfreq/arm-memlat-mon.c
@@ -47,22 +47,32 @@
 	unsigned long prev_count;
 };
 
-struct memlat_hwmon_data {
+struct cpu_pmu_stats {
 	struct event_data events[NUM_EVENTS];
 	ktime_t prev_ts;
-	bool init_pending;
-	unsigned long cache_miss_event;
-	unsigned long inst_event;
 };
-static DEFINE_PER_CPU(struct memlat_hwmon_data, pm_data);
 
 struct cpu_grp_info {
 	cpumask_t cpus;
+	cpumask_t inited_cpus;
+	unsigned long cache_miss_event;
+	unsigned long inst_event;
+	struct cpu_pmu_stats *cpustats;
 	struct memlat_hwmon hw;
 	struct notifier_block arm_memlat_cpu_notif;
+	struct list_head mon_list;
 };
 
-static unsigned long compute_freq(struct memlat_hwmon_data *hw_data,
+#define to_cpustats(cpu_grp, cpu) \
+	(&cpu_grp->cpustats[cpu - cpumask_first(&cpu_grp->cpus)])
+#define to_devstats(cpu_grp, cpu) \
+	(&cpu_grp->hw.core_stats[cpu - cpumask_first(&cpu_grp->cpus)])
+#define to_cpu_grp(hwmon) container_of(hwmon, struct cpu_grp_info, hw)
+
+static LIST_HEAD(memlat_mon_list);
+static DEFINE_MUTEX(list_lock);
+
+static unsigned long compute_freq(struct cpu_pmu_stats *cpustats,
 						unsigned long cyc_cnt)
 {
 	ktime_t ts;
@@ -70,10 +80,10 @@
 	unsigned long freq = 0;
 
 	ts = ktime_get();
-	diff = ktime_to_us(ktime_sub(ts, hw_data->prev_ts));
+	diff = ktime_to_us(ktime_sub(ts, cpustats->prev_ts));
 	if (!diff)
 		diff = 1;
-	hw_data->prev_ts = ts;
+	cpustats->prev_ts = ts;
 	freq = cyc_cnt;
 	do_div(freq, diff);
 
@@ -99,69 +109,59 @@
 
 static void read_perf_counters(int cpu, struct cpu_grp_info *cpu_grp)
 {
-	int cpu_idx;
-	struct memlat_hwmon_data *hw_data = &per_cpu(pm_data, cpu);
-	struct memlat_hwmon *hw = &cpu_grp->hw;
+	struct cpu_pmu_stats *cpustats = to_cpustats(cpu_grp, cpu);
+	struct dev_stats *devstats = to_devstats(cpu_grp, cpu);
 	unsigned long cyc_cnt;
 
-	if (hw_data->init_pending)
-		return;
-
-	cpu_idx = cpu - cpumask_first(&cpu_grp->cpus);
-
-	hw->core_stats[cpu_idx].inst_count =
-			read_event(&hw_data->events[INST_IDX]);
-
-	hw->core_stats[cpu_idx].mem_count =
-			read_event(&hw_data->events[CM_IDX]);
-
-	cyc_cnt = read_event(&hw_data->events[CYC_IDX]);
-	hw->core_stats[cpu_idx].freq = compute_freq(hw_data, cyc_cnt);
+	devstats->inst_count = read_event(&cpustats->events[INST_IDX]);
+	devstats->mem_count = read_event(&cpustats->events[CM_IDX]);
+	cyc_cnt = read_event(&cpustats->events[CYC_IDX]);
+	devstats->freq = compute_freq(cpustats, cyc_cnt);
 }
 
 static unsigned long get_cnt(struct memlat_hwmon *hw)
 {
 	int cpu;
-	struct cpu_grp_info *cpu_grp = container_of(hw,
-					struct cpu_grp_info, hw);
+	struct cpu_grp_info *cpu_grp = to_cpu_grp(hw);
 
-	for_each_cpu(cpu, &cpu_grp->cpus)
+	for_each_cpu(cpu, &cpu_grp->inited_cpus)
 		read_perf_counters(cpu, cpu_grp);
 
 	return 0;
 }
 
-static void delete_events(struct memlat_hwmon_data *hw_data)
+static void delete_events(struct cpu_pmu_stats *cpustats)
 {
 	int i;
 
 	for (i = 0; i < NUM_EVENTS; i++) {
-		hw_data->events[i].prev_count = 0;
-		perf_event_release_kernel(hw_data->events[i].pevent);
+		cpustats->events[i].prev_count = 0;
+		perf_event_release_kernel(cpustats->events[i].pevent);
 	}
 }
 
 static void stop_hwmon(struct memlat_hwmon *hw)
 {
-	int cpu, idx;
-	struct memlat_hwmon_data *hw_data;
-	struct cpu_grp_info *cpu_grp = container_of(hw,
-					struct cpu_grp_info, hw);
+	int cpu;
+	struct cpu_grp_info *cpu_grp = to_cpu_grp(hw);
+	struct dev_stats *devstats;
 
 	get_online_cpus();
-	for_each_cpu(cpu, &cpu_grp->cpus) {
-		hw_data = &per_cpu(pm_data, cpu);
-		if (hw_data->init_pending)
-			hw_data->init_pending = false;
-		else
-			delete_events(hw_data);
+	for_each_cpu(cpu, &cpu_grp->inited_cpus) {
+		delete_events(to_cpustats(cpu_grp, cpu));
 
 		/* Clear governor data */
-		idx = cpu - cpumask_first(&cpu_grp->cpus);
-		hw->core_stats[idx].inst_count = 0;
-		hw->core_stats[idx].mem_count = 0;
-		hw->core_stats[idx].freq = 0;
+		devstats = to_devstats(cpu_grp, cpu);
+		devstats->inst_count = 0;
+		devstats->mem_count = 0;
+		devstats->freq = 0;
 	}
+	mutex_lock(&list_lock);
+	if (!cpumask_equal(&cpu_grp->cpus, &cpu_grp->inited_cpus))
+		list_del(&cpu_grp->mon_list);
+	mutex_unlock(&list_lock);
+	cpumask_clear(&cpu_grp->inited_cpus);
+
 	put_online_cpus();
 
 	unregister_cpu_notifier(&cpu_grp->arm_memlat_cpu_notif);
@@ -173,7 +173,7 @@
 
 	attr = kzalloc(sizeof(struct perf_event_attr), GFP_KERNEL);
 	if (!attr)
-		return ERR_PTR(-ENOMEM);
+		return attr;
 
 	attr->type = PERF_TYPE_RAW;
 	attr->size = sizeof(struct perf_event_attr);
@@ -183,37 +183,38 @@
 	return attr;
 }
 
-static int set_events(struct memlat_hwmon_data *hw_data, int cpu)
+static int set_events(struct cpu_grp_info *cpu_grp, int cpu)
 {
 	struct perf_event *pevent;
 	struct perf_event_attr *attr;
 	int err;
+	struct cpu_pmu_stats *cpustats = to_cpustats(cpu_grp, cpu);
 
 	/* Allocate an attribute for event initialization */
 	attr = alloc_attr();
-	if (IS_ERR(attr))
-		return PTR_ERR(attr);
+	if (!attr)
+		return -ENOMEM;
 
-	attr->config = hw_data->inst_event;
+	attr->config = cpu_grp->inst_event;
 	pevent = perf_event_create_kernel_counter(attr, cpu, NULL, NULL, NULL);
 	if (IS_ERR(pevent))
 		goto err_out;
-	hw_data->events[INST_IDX].pevent = pevent;
-	perf_event_enable(hw_data->events[INST_IDX].pevent);
+	cpustats->events[INST_IDX].pevent = pevent;
+	perf_event_enable(cpustats->events[INST_IDX].pevent);
 
-	attr->config = hw_data->cache_miss_event;
+	attr->config = cpu_grp->cache_miss_event;
 	pevent = perf_event_create_kernel_counter(attr, cpu, NULL, NULL, NULL);
 	if (IS_ERR(pevent))
 		goto err_out;
-	hw_data->events[CM_IDX].pevent = pevent;
-	perf_event_enable(hw_data->events[CM_IDX].pevent);
+	cpustats->events[CM_IDX].pevent = pevent;
+	perf_event_enable(cpustats->events[CM_IDX].pevent);
 
 	attr->config = CYC_EV;
 	pevent = perf_event_create_kernel_counter(attr, cpu, NULL, NULL, NULL);
 	if (IS_ERR(pevent))
 		goto err_out;
-	hw_data->events[CYC_IDX].pevent = pevent;
-	perf_event_enable(hw_data->events[CYC_IDX].pevent);
+	cpustats->events[CYC_IDX].pevent = pevent;
+	perf_event_enable(cpustats->events[CYC_IDX].pevent);
 
 	kfree(attr);
 	return 0;
@@ -228,15 +229,24 @@
 		unsigned long action, void *hcpu)
 {
 	unsigned long cpu = (unsigned long)hcpu;
-	struct memlat_hwmon_data *hw_data = &per_cpu(pm_data, cpu);
+	struct cpu_grp_info *cpu_grp, *tmp;
 
-	if ((action != CPU_ONLINE) || !hw_data->init_pending)
+	if (action != CPU_ONLINE)
 		return NOTIFY_OK;
 
-	if (set_events(hw_data, cpu))
-		pr_warn("Failed to create perf event for CPU%lu\n", cpu);
-
-	hw_data->init_pending = false;
+	mutex_lock(&list_lock);
+	list_for_each_entry_safe(cpu_grp, tmp, &memlat_mon_list, mon_list) {
+		if (!cpumask_test_cpu(cpu, &cpu_grp->cpus) ||
+		    cpumask_test_cpu(cpu, &cpu_grp->inited_cpus))
+			continue;
+		if (set_events(cpu_grp, cpu))
+			pr_warn("Failed to create perf ev for CPU%lu\n", cpu);
+		else
+			cpumask_set_cpu(cpu, &cpu_grp->inited_cpus);
+		if (cpumask_equal(&cpu_grp->cpus, &cpu_grp->inited_cpus))
+			list_del(&cpu_grp->mon_list);
+	}
+	mutex_unlock(&list_lock);
 
 	return NOTIFY_OK;
 }
@@ -244,29 +254,32 @@
 static int start_hwmon(struct memlat_hwmon *hw)
 {
 	int cpu, ret = 0;
-	struct memlat_hwmon_data *hw_data;
-	struct cpu_grp_info *cpu_grp = container_of(hw,
-					struct cpu_grp_info, hw);
+	struct cpu_grp_info *cpu_grp = to_cpu_grp(hw);
 
 	register_cpu_notifier(&cpu_grp->arm_memlat_cpu_notif);
 
 	get_online_cpus();
 	for_each_cpu(cpu, &cpu_grp->cpus) {
-		hw_data = &per_cpu(pm_data, cpu);
-		ret = set_events(hw_data, cpu);
+		ret = set_events(cpu_grp, cpu);
 		if (ret) {
 			if (!cpu_online(cpu)) {
-				hw_data->init_pending = true;
 				ret = 0;
 			} else {
 				pr_warn("Perf event init failed on CPU%d\n",
 					cpu);
 				break;
 			}
+		} else {
+			cpumask_set_cpu(cpu, &cpu_grp->inited_cpus);
 		}
 	}
+	mutex_lock(&list_lock);
+	if (!cpumask_equal(&cpu_grp->cpus, &cpu_grp->inited_cpus))
+		list_add_tail(&cpu_grp->mon_list, &memlat_mon_list);
+	mutex_unlock(&list_lock);
 
 	put_online_cpus();
+
 	return ret;
 }
 
@@ -328,6 +341,11 @@
 	if (!hw->core_stats)
 		return -ENOMEM;
 
+	cpu_grp->cpustats = devm_kzalloc(dev, hw->num_cores *
+			sizeof(*(cpu_grp->cpustats)), GFP_KERNEL);
+	if (!cpu_grp->cpustats)
+		return -ENOMEM;
+
 	ret = of_property_read_u32(dev->of_node, "qcom,cachemiss-ev",
 			&cachemiss_ev);
 	if (ret) {
@@ -335,6 +353,7 @@
 				L2DM_EV);
 		cachemiss_ev = L2DM_EV;
 	}
+	cpu_grp->cache_miss_event = cachemiss_ev;
 
 	ret = of_property_read_u32(dev->of_node, "qcom,inst-ev", &inst_ev);
 	if (ret) {
@@ -342,12 +361,10 @@
 				INST_EV);
 		inst_ev = INST_EV;
 	}
+	cpu_grp->inst_event = inst_ev;
 
-	for_each_cpu(cpu, &cpu_grp->cpus) {
-		hw->core_stats[cpu - cpumask_first(&cpu_grp->cpus)].id = cpu;
-		(&per_cpu(pm_data, cpu))->cache_miss_event = cachemiss_ev;
-		(&per_cpu(pm_data, cpu))->inst_event = inst_ev;
-	}
+	for_each_cpu(cpu, &cpu_grp->cpus)
+		to_devstats(cpu_grp, cpu)->id = cpu;
 
 	hw->start_hwmon = &start_hwmon;
 	hw->stop_hwmon = &stop_hwmon;
diff --git a/drivers/devfreq/bimc-bwmon.c b/drivers/devfreq/bimc-bwmon.c
index 078e198..ffe60de 100644
--- a/drivers/devfreq/bimc-bwmon.c
+++ b/drivers/devfreq/bimc-bwmon.c
@@ -26,14 +26,20 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/spinlock.h>
+#include <linux/log2.h>
+#include <linux/sizes.h>
 #include "governor_bw_hwmon.h"
 
 #define GLB_INT_STATUS(m)	((m)->global_base + 0x100)
 #define GLB_INT_CLR(m)		((m)->global_base + 0x108)
 #define	GLB_INT_EN(m)		((m)->global_base + 0x10C)
 #define MON_INT_STATUS(m)	((m)->base + 0x100)
+#define MON_INT_STATUS_MASK	0x03
+#define MON2_INT_STATUS_MASK	0xF0
+#define MON2_INT_STATUS_SHIFT	4
 #define MON_INT_CLR(m)		((m)->base + 0x108)
 #define	MON_INT_EN(m)		((m)->base + 0x10C)
+#define MON_INT_ENABLE		0x1
 #define	MON_EN(m)		((m)->base + 0x280)
 #define MON_CLEAR(m)		((m)->base + 0x284)
 #define MON_CNT(m)		((m)->base + 0x288)
@@ -54,9 +60,29 @@
 #define MON2_ZONE_CNT(m)	((m)->base + 0x2D8)
 #define MON2_ZONE_MAX(m, zone)	((m)->base + 0x2E0 + 0x4 * zone)
 
+#define MON3_INT_STATUS(m)	((m)->base + 0x00)
+#define MON3_INT_CLR(m)		((m)->base + 0x08)
+#define MON3_INT_EN(m)		((m)->base + 0x0C)
+#define MON3_INT_STATUS_MASK	0x0F
+#define MON3_EN(m)		((m)->base + 0x10)
+#define MON3_CLEAR(m)		((m)->base + 0x14)
+#define MON3_MASK(m)		((m)->base + 0x18)
+#define MON3_MATCH(m)		((m)->base + 0x1C)
+#define MON3_SW(m)		((m)->base + 0x20)
+#define MON3_THRES_HI(m)	((m)->base + 0x24)
+#define MON3_THRES_MED(m)	((m)->base + 0x28)
+#define MON3_THRES_LO(m)	((m)->base + 0x2C)
+#define MON3_ZONE_ACTIONS(m)	((m)->base + 0x30)
+#define MON3_ZONE_CNT_THRES(m)	((m)->base + 0x34)
+#define MON3_BYTE_CNT(m)	((m)->base + 0x38)
+#define MON3_WIN_TIMER(m)	((m)->base + 0x3C)
+#define MON3_ZONE_CNT(m)	((m)->base + 0x40)
+#define MON3_ZONE_MAX(m, zone)	((m)->base + 0x44 + 0x4 * zone)
+
 enum mon_reg_type {
 	MON1,
 	MON2,
+	MON3,
 };
 
 struct bwmon_spec {
@@ -64,6 +90,8 @@
 	bool overflow;
 	bool throt_adj;
 	bool hw_sampling;
+	bool has_global_base;
+	enum mon_reg_type reg_type;
 };
 
 struct bwmon {
@@ -78,6 +106,10 @@
 	u32 throttle_adj;
 	u32 sample_size_ms;
 	u32 intr_status;
+	u8 count_shift;
+	u32 thres_lim;
+	u32 byte_mask;
+	u32 byte_match;
 };
 
 #define to_bwmon(ptr)		container_of(ptr, struct bwmon, hw)
@@ -85,9 +117,6 @@
 #define ENABLE_MASK BIT(0)
 #define THROTTLE_MASK 0x1F
 #define THROTTLE_SHIFT 16
-#define INT_ENABLE_V1	0x1
-#define INT_STATUS_MASK	0x03
-#define INT_STATUS_MASK_HWS	0xF0
 
 static DEFINE_SPINLOCK(glb_lock);
 
@@ -100,6 +129,9 @@
 	case MON2:
 		writel_relaxed(ENABLE_MASK | m->throttle_adj, MON2_EN(m));
 		break;
+	case MON3:
+		writel_relaxed(ENABLE_MASK | m->throttle_adj, MON3_EN(m));
+		break;
 	}
 }
 
@@ -112,6 +144,9 @@
 	case MON2:
 		writel_relaxed(m->throttle_adj, MON2_EN(m));
 		break;
+	case MON3:
+		writel_relaxed(m->throttle_adj, MON3_EN(m));
+		break;
 	}
 	/*
 	 * mon_disable() and mon_irq_clear(),
@@ -136,6 +171,12 @@
 		else
 			writel_relaxed(MON_CLEAR_BIT, MON2_CLEAR(m));
 		break;
+	case MON3:
+		if (clear_all)
+			writel_relaxed(MON_CLEAR_ALL_BIT, MON3_CLEAR(m));
+		else
+			writel_relaxed(MON_CLEAR_BIT, MON3_CLEAR(m));
+		break;
 	}
 	/*
 	 * The counter clear and IRQ clear bits are not in the same 4KB
@@ -146,7 +187,9 @@
 }
 
 #define	SAMPLE_WIN_LIM	0xFFFFF
-static void mon_set_hw_sampling_window(struct bwmon *m, unsigned int sample_ms)
+static __always_inline
+void mon_set_hw_sampling_window(struct bwmon *m, unsigned int sample_ms,
+				enum mon_reg_type type)
 {
 	u32 rate;
 
@@ -158,7 +201,17 @@
 			pr_warn("Sample window %u larger than hw limit: %u\n",
 					rate, SAMPLE_WIN_LIM);
 		}
-		writel_relaxed(rate, MON2_SW(m));
+		switch (type) {
+		case MON1:
+			WARN(1, "Invalid\n");
+			return;
+		case MON2:
+			writel_relaxed(rate, MON2_SW(m));
+			break;
+		case MON3:
+			writel_relaxed(rate, MON3_SW(m));
+			break;
+		}
 	}
 }
 
@@ -181,15 +234,20 @@
 	case MON1:
 		mon_glb_irq_enable(m);
 		val = readl_relaxed(MON_INT_EN(m));
-		val |= INT_ENABLE_V1;
+		val |= MON_INT_ENABLE;
 		writel_relaxed(val, MON_INT_EN(m));
 		break;
 	case MON2:
 		mon_glb_irq_enable(m);
 		val = readl_relaxed(MON_INT_EN(m));
-		val |= INT_STATUS_MASK_HWS;
+		val |= MON2_INT_STATUS_MASK;
 		writel_relaxed(val, MON_INT_EN(m));
 		break;
+	case MON3:
+		val = readl_relaxed(MON3_INT_EN(m));
+		val |= MON3_INT_STATUS_MASK;
+		writel_relaxed(val, MON3_INT_EN(m));
+		break;
 	}
 	spin_unlock(&glb_lock);
 	/*
@@ -219,15 +277,20 @@
 	case MON1:
 		mon_glb_irq_disable(m);
 		val = readl_relaxed(MON_INT_EN(m));
-		val &= ~INT_ENABLE_V1;
+		val &= ~MON_INT_ENABLE;
 		writel_relaxed(val, MON_INT_EN(m));
 		break;
 	case MON2:
 		mon_glb_irq_disable(m);
 		val = readl_relaxed(MON_INT_EN(m));
-		val &= ~INT_STATUS_MASK_HWS;
+		val &= ~MON2_INT_STATUS_MASK;
 		writel_relaxed(val, MON_INT_EN(m));
 		break;
+	case MON3:
+		val = readl_relaxed(MON3_INT_EN(m));
+		val &= ~MON3_INT_STATUS_MASK;
+		writel_relaxed(val, MON3_INT_EN(m));
+		break;
 	}
 	spin_unlock(&glb_lock);
 	/*
@@ -247,13 +310,19 @@
 		mval = readl_relaxed(MON_INT_STATUS(m));
 		dev_dbg(m->dev, "IRQ status p:%x, g:%x\n", mval,
 				readl_relaxed(GLB_INT_STATUS(m)));
-		mval &= INT_STATUS_MASK;
+		mval &= MON_INT_STATUS_MASK;
 		break;
 	case MON2:
 		mval = readl_relaxed(MON_INT_STATUS(m));
 		dev_dbg(m->dev, "IRQ status p:%x, g:%x\n", mval,
 				readl_relaxed(GLB_INT_STATUS(m)));
-		mval &= INT_STATUS_MASK_HWS;
+		mval &= MON2_INT_STATUS_MASK;
+		mval >>= MON2_INT_STATUS_SHIFT;
+		break;
+	case MON3:
+		mval = readl_relaxed(MON3_INT_STATUS(m));
+		dev_dbg(m->dev, "IRQ status p:%x\n", mval);
+		mval &= MON3_INT_STATUS_MASK;
 		break;
 	}
 
@@ -287,13 +356,16 @@
 {
 	switch (type) {
 	case MON1:
-		writel_relaxed(INT_STATUS_MASK, MON_INT_CLR(m));
+		writel_relaxed(MON_INT_STATUS_MASK, MON_INT_CLR(m));
 		mon_glb_irq_clear(m);
 		break;
 	case MON2:
-		writel_relaxed(INT_STATUS_MASK_HWS, MON_INT_CLR(m));
+		writel_relaxed(MON2_INT_STATUS_MASK, MON_INT_CLR(m));
 		mon_glb_irq_clear(m);
 		break;
+	case MON3:
+		writel_relaxed(MON3_INT_STATUS_MASK, MON3_INT_CLR(m));
+		break;
 	}
 }
 
@@ -350,11 +422,18 @@
 	return zone_counts;
 }
 
-static unsigned int mbps_to_mb(unsigned long mbps, unsigned int ms)
+#define MB_SHIFT	20
+
+static u32 mbps_to_count(unsigned long mbps, unsigned int ms, u8 shift)
 {
 	mbps *= ms;
-	mbps = DIV_ROUND_UP(mbps, MSEC_PER_SEC);
-	return mbps;
+
+	if (shift > MB_SHIFT)
+		mbps >>= shift - MB_SHIFT;
+	else
+		mbps <<= MB_SHIFT - shift;
+
+	return DIV_ROUND_UP(mbps, MSEC_PER_SEC);
 }
 
 /*
@@ -362,43 +441,60 @@
  * Zone 0: byte count < THRES_LO
  * Zone 1: THRES_LO < byte count < THRES_MED
  * Zone 2: THRES_MED < byte count < THRES_HI
- * Zone 3: byte count > THRES_HI
+ * Zone 3: THRES_LIM > byte count > THRES_HI
  */
-#define	THRES_LIM	0x7FFU
-static void set_zone_thres(struct bwmon *m, unsigned int sample_ms)
-{
-	struct bw_hwmon *hw = &(m->hw);
-	u32 hi, med, lo;
+#define	THRES_LIM(shift)	(0xFFFFFFFF >> shift)
 
-	hi = mbps_to_mb(hw->up_wake_mbps, sample_ms);
-	med = mbps_to_mb(hw->down_wake_mbps, sample_ms);
+static __always_inline
+void set_zone_thres(struct bwmon *m, unsigned int sample_ms,
+		    enum mon_reg_type type)
+{
+	struct bw_hwmon *hw = &m->hw;
+	u32 hi, med, lo;
+	u32 zone_cnt_thres = calc_zone_counts(hw);
+
+	hi = mbps_to_count(hw->up_wake_mbps, sample_ms, m->count_shift);
+	med = mbps_to_count(hw->down_wake_mbps, sample_ms, m->count_shift);
 	lo = 0;
 
-	if (unlikely((hi > THRES_LIM) || (med > hi) || (lo > med))) {
+	if (unlikely((hi > m->thres_lim) || (med > hi) || (lo > med))) {
 		pr_warn("Zone thres larger than hw limit: hi:%u med:%u lo:%u\n",
 				hi, med, lo);
-		hi = min(hi, THRES_LIM);
+		hi = min(hi, m->thres_lim);
 		med = min(med, hi - 1);
 		lo = min(lo, med-1);
 	}
 
-	writel_relaxed(hi, MON2_THRES_HI(m));
-	writel_relaxed(med, MON2_THRES_MED(m));
-	writel_relaxed(lo, MON2_THRES_LO(m));
+	switch (type) {
+	case MON1:
+		WARN(1, "Invalid\n");
+		return;
+	case MON2:
+		writel_relaxed(hi, MON2_THRES_HI(m));
+		writel_relaxed(med, MON2_THRES_MED(m));
+		writel_relaxed(lo, MON2_THRES_LO(m));
+		/* Set the zone count thresholds for interrupts */
+		writel_relaxed(zone_cnt_thres, MON2_ZONE_CNT_THRES(m));
+		break;
+	case MON3:
+		writel_relaxed(hi, MON3_THRES_HI(m));
+		writel_relaxed(med, MON3_THRES_MED(m));
+		writel_relaxed(lo, MON3_THRES_LO(m));
+		/* Set the zone count thresholds for interrupts */
+		writel_relaxed(zone_cnt_thres, MON3_ZONE_CNT_THRES(m));
+		break;
+	}
+
 	dev_dbg(m->dev, "Thres: hi:%u med:%u lo:%u\n", hi, med, lo);
+	dev_dbg(m->dev, "Zone Count Thres: %0x\n", zone_cnt_thres);
 }
 
-static void mon_set_zones(struct bwmon *m, unsigned int sample_ms)
+static __always_inline
+void mon_set_zones(struct bwmon *m, unsigned int sample_ms,
+		   enum mon_reg_type type)
 {
-	struct bw_hwmon *hw = &(m->hw);
-	u32 zone_cnt_thres = calc_zone_counts(hw);
-
-	mon_set_hw_sampling_window(m, sample_ms);
-	set_zone_thres(m, sample_ms);
-	/* Set the zone count thresholds for interrupts */
-	writel_relaxed(zone_cnt_thres, MON2_ZONE_CNT_THRES(m));
-
-	dev_dbg(m->dev, "Zone Count Thres: %0x\n", zone_cnt_thres);
+	mon_set_hw_sampling_window(m, sample_ms, type);
+	set_zone_thres(m, sample_ms, type);
 }
 
 static void mon_set_limit(struct bwmon *m, u32 count)
@@ -433,16 +529,28 @@
 	return count;
 }
 
-static unsigned int get_zone(struct bwmon *m)
+static __always_inline
+unsigned int get_zone(struct bwmon *m, enum mon_reg_type type)
 {
 	u32 zone_counts;
 	u32 zone;
 
-	zone = get_bitmask_order((m->intr_status & INT_STATUS_MASK_HWS) >> 4);
+	zone = get_bitmask_order(m->intr_status);
 	if (zone) {
 		zone--;
 	} else {
-		zone_counts = readl_relaxed(MON2_ZONE_CNT(m));
+		switch (type) {
+		case MON1:
+			WARN(1, "Invalid\n");
+			return 0;
+		case MON2:
+			zone_counts = readl_relaxed(MON2_ZONE_CNT(m));
+			break;
+		case MON3:
+			zone_counts = readl_relaxed(MON3_ZONE_CNT(m));
+			break;
+		}
+
 		if (zone_counts) {
 			zone = get_bitmask_order(zone_counts) - 1;
 			zone /= 8;
@@ -453,15 +561,36 @@
 	return zone;
 }
 
-static unsigned long mon_get_zone_stats(struct bwmon *m)
+static __always_inline
+unsigned long get_zone_count(struct bwmon *m, unsigned int zone,
+			     enum mon_reg_type type)
+{
+	unsigned long count;
+
+	switch (type) {
+	case MON1:
+		WARN(1, "Invalid\n");
+		return 0;
+	case MON2:
+		count = readl_relaxed(MON2_ZONE_MAX(m, zone)) + 1;
+		break;
+	case MON3:
+		count = readl_relaxed(MON3_ZONE_MAX(m, zone)) + 1;
+		break;
+	}
+
+	return count;
+}
+
+static __always_inline
+unsigned long mon_get_zone_stats(struct bwmon *m, enum mon_reg_type type)
 {
 	unsigned int zone;
 	unsigned long count = 0;
 
-	zone = get_zone(m);
-
-	count = readl_relaxed(MON2_ZONE_MAX(m, zone)) + 1;
-	count *= SZ_1M;
+	zone = get_zone(m, type);
+	count = get_zone_count(m, zone, type);
+	count <<= m->count_shift;
 
 	dev_dbg(m->dev, "Zone%d Max byte count: %08lx\n", zone, count);
 
@@ -478,7 +607,8 @@
 		count = mon_get_count1(m);
 		break;
 	case MON2:
-		count = mon_get_zone_stats(m);
+	case MON3:
+		count = mon_get_zone_stats(m, type);
 		break;
 	}
 
@@ -523,6 +653,11 @@
 	return __get_bytes_and_clear(hw, MON2);
 }
 
+static unsigned long get_bytes_and_clear3(struct bw_hwmon *hw)
+{
+	return __get_bytes_and_clear(hw, MON3);
+}
+
 static unsigned long set_thres(struct bw_hwmon *hw, unsigned long bytes)
 {
 	unsigned long count;
@@ -545,20 +680,33 @@
 	return count;
 }
 
-static unsigned long set_hw_events(struct bw_hwmon *hw, unsigned int sample_ms)
+static unsigned long
+__set_hw_events(struct bw_hwmon *hw, unsigned int sample_ms,
+		enum mon_reg_type type)
 {
 	struct bwmon *m = to_bwmon(hw);
 
-	mon_disable(m, MON2);
-	mon_clear(m, false, MON2);
-	mon_irq_clear(m, MON2);
+	mon_disable(m, type);
+	mon_clear(m, false, type);
+	mon_irq_clear(m, type);
 
-	mon_set_zones(m, sample_ms);
-	mon_enable(m, MON2);
+	mon_set_zones(m, sample_ms, type);
+	mon_enable(m, type);
 
 	return 0;
 }
 
+static unsigned long set_hw_events(struct bw_hwmon *hw, unsigned int sample_ms)
+{
+	return __set_hw_events(hw, sample_ms, MON2);
+}
+
+static unsigned long
+set_hw_events3(struct bw_hwmon *hw, unsigned int sample_ms)
+{
+	return __set_hw_events(hw, sample_ms, MON3);
+}
+
 static irqreturn_t
 __bwmon_intr_handler(int irq, void *dev, enum mon_reg_type type)
 {
@@ -584,6 +732,11 @@
 	return __bwmon_intr_handler(irq, dev, MON2);
 }
 
+static irqreturn_t bwmon_intr_handler3(int irq, void *dev)
+{
+	return __bwmon_intr_handler(irq, dev, MON3);
+}
+
 static irqreturn_t bwmon_intr_thread(int irq, void *dev)
 {
 	struct bwmon *m = dev;
@@ -592,6 +745,25 @@
 	return IRQ_HANDLED;
 }
 
+static __always_inline
+void mon_set_byte_count_filter(struct bwmon *m, enum mon_reg_type type)
+{
+	if (!m->byte_mask)
+		return;
+
+	switch (type) {
+	case MON1:
+	case MON2:
+		writel_relaxed(m->byte_mask, MON_MASK(m));
+		writel_relaxed(m->byte_match, MON_MATCH(m));
+		break;
+	case MON3:
+		writel_relaxed(m->byte_mask, MON3_MASK(m));
+		writel_relaxed(m->byte_match, MON3_MATCH(m));
+		break;
+	}
+}
+
 static __always_inline int __start_bw_hwmon(struct bw_hwmon *hw,
 		unsigned long mbps, enum mon_reg_type type)
 {
@@ -609,6 +781,10 @@
 		zone_actions = calc_zone_actions();
 		handler = bwmon_intr_handler2;
 		break;
+	case MON3:
+		zone_actions = calc_zone_actions();
+		handler = bwmon_intr_handler3;
+		break;
 	}
 
 	ret = request_threaded_irq(m->irq, handler, bwmon_intr_thread,
@@ -630,12 +806,17 @@
 		mon_set_limit(m, limit);
 		break;
 	case MON2:
-		mon_set_zones(m, hw->df->profile->polling_ms);
+		mon_set_zones(m, hw->df->profile->polling_ms, type);
 		/* Set the zone actions to increment appropriate counters */
 		writel_relaxed(zone_actions, MON2_ZONE_ACTIONS(m));
 		break;
+	case MON3:
+		mon_set_zones(m, hw->df->profile->polling_ms, type);
+		/* Set the zone actions to increment appropriate counters */
+		writel_relaxed(zone_actions, MON3_ZONE_ACTIONS(m));
 	}
 
+	mon_set_byte_count_filter(m, type);
 	mon_irq_clear(m, type);
 	mon_irq_enable(m, type);
 	mon_enable(m, type);
@@ -653,6 +834,11 @@
 	return __start_bw_hwmon(hw, mbps, MON2);
 }
 
+static int start_bw_hwmon3(struct bw_hwmon *hw, unsigned long mbps)
+{
+	return __start_bw_hwmon(hw, mbps, MON3);
+}
+
 static __always_inline
 void __stop_bw_hwmon(struct bw_hwmon *hw, enum mon_reg_type type)
 {
@@ -675,6 +861,11 @@
 	return __stop_bw_hwmon(hw, MON2);
 }
 
+static void stop_bw_hwmon3(struct bw_hwmon *hw)
+{
+	return __stop_bw_hwmon(hw, MON3);
+}
+
 static __always_inline
 int __suspend_bw_hwmon(struct bw_hwmon *hw, enum mon_reg_type type)
 {
@@ -698,7 +889,13 @@
 	return __suspend_bw_hwmon(hw, MON2);
 }
 
-static int __resume_bw_hwmon(struct bw_hwmon *hw, enum mon_reg_type type)
+static int suspend_bw_hwmon3(struct bw_hwmon *hw)
+{
+	return __suspend_bw_hwmon(hw, MON3);
+}
+
+static __always_inline
+int __resume_bw_hwmon(struct bw_hwmon *hw, enum mon_reg_type type)
 {
 	struct bwmon *m = to_bwmon(hw);
 	int ret;
@@ -711,6 +908,9 @@
 	case MON2:
 		handler = bwmon_intr_handler2;
 		break;
+	case MON3:
+		handler = bwmon_intr_handler3;
+		break;
 	}
 
 	mon_clear(m, false, type);
@@ -739,6 +939,11 @@
 	return __resume_bw_hwmon(hw, MON2);
 }
 
+static int resume_bw_hwmon3(struct bw_hwmon *hw)
+{
+	return __resume_bw_hwmon(hw, MON3);
+}
+
 /*************************************************************************/
 
 static const struct bwmon_spec spec[] = {
@@ -746,25 +951,40 @@
 		.wrap_on_thres = true,
 		.overflow = false,
 		.throt_adj = false,
-		.hw_sampling = false
+		.hw_sampling = false,
+		.has_global_base = true,
+		.reg_type = MON1,
 	},
 	[1] = {
 		.wrap_on_thres = false,
 		.overflow = true,
 		.throt_adj = false,
-		.hw_sampling = false
+		.hw_sampling = false,
+		.has_global_base = true,
+		.reg_type = MON1,
 	},
 	[2] = {
 		.wrap_on_thres = false,
 		.overflow = true,
 		.throt_adj = true,
-		.hw_sampling = false
+		.hw_sampling = false,
+		.has_global_base = true,
+		.reg_type = MON1,
 	},
 	[3] = {
 		.wrap_on_thres = false,
 		.overflow = true,
 		.throt_adj = true,
-		.hw_sampling = true
+		.hw_sampling = true,
+		.has_global_base = true,
+		.reg_type = MON2,
+	},
+	[4] = {
+		.wrap_on_thres = false,
+		.overflow = true,
+		.throt_adj = false,
+		.hw_sampling = true,
+		.reg_type = MON3,
 	},
 };
 
@@ -773,6 +993,7 @@
 	{ .compatible = "qcom,bimc-bwmon2", .data = &spec[1] },
 	{ .compatible = "qcom,bimc-bwmon3", .data = &spec[2] },
 	{ .compatible = "qcom,bimc-bwmon4", .data = &spec[3] },
+	{ .compatible = "qcom,bimc-bwmon5", .data = &spec[4] },
 	{}
 };
 
@@ -782,20 +1003,13 @@
 	struct resource *res;
 	struct bwmon *m;
 	int ret;
-	u32 data;
+	u32 data, count_unit;
 
 	m = devm_kzalloc(dev, sizeof(*m), GFP_KERNEL);
 	if (!m)
 		return -ENOMEM;
 	m->dev = dev;
 
-	ret = of_property_read_u32(dev->of_node, "qcom,mport", &data);
-	if (ret) {
-		dev_err(dev, "mport not found!\n");
-		return ret;
-	}
-	m->mport = data;
-
 	m->spec = of_device_get_match_data(dev);
 	if (!m->spec) {
 		dev_err(dev, "Unknown device type!\n");
@@ -813,15 +1027,26 @@
 		return -ENOMEM;
 	}
 
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "global_base");
-	if (!res) {
-		dev_err(dev, "global_base not found!\n");
-		return -EINVAL;
-	}
-	m->global_base = devm_ioremap(dev, res->start, resource_size(res));
-	if (!m->global_base) {
-		dev_err(dev, "Unable map global_base!\n");
-		return -ENOMEM;
+	if (m->spec->has_global_base) {
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						   "global_base");
+		if (!res) {
+			dev_err(dev, "global_base not found!\n");
+			return -EINVAL;
+		}
+		m->global_base = devm_ioremap(dev, res->start,
+					      resource_size(res));
+		if (!m->global_base) {
+			dev_err(dev, "Unable map global_base!\n");
+			return -ENOMEM;
+		}
+
+		ret = of_property_read_u32(dev->of_node, "qcom,mport", &data);
+		if (ret) {
+			dev_err(dev, "mport not found!\n");
+			return ret;
+		}
+		m->mport = data;
 	}
 
 	m->irq = platform_get_irq(pdev, 0);
@@ -841,22 +1066,45 @@
 			dev_err(dev, "HW sampling rate not specified!\n");
 			return ret;
 		}
+	}
 
+	if (of_property_read_u32(dev->of_node, "qcom,count-unit", &count_unit))
+		count_unit = SZ_1M;
+	m->count_shift = order_base_2(count_unit);
+	m->thres_lim = THRES_LIM(m->count_shift);
+
+	switch (m->spec->reg_type) {
+	case MON3:
+		m->hw.start_hwmon = start_bw_hwmon3;
+		m->hw.stop_hwmon = stop_bw_hwmon3;
+		m->hw.suspend_hwmon = suspend_bw_hwmon3;
+		m->hw.resume_hwmon = resume_bw_hwmon3;
+		m->hw.get_bytes_and_clear = get_bytes_and_clear3;
+		m->hw.set_hw_events = set_hw_events3;
+		break;
+	case MON2:
 		m->hw.start_hwmon = start_bw_hwmon2;
 		m->hw.stop_hwmon = stop_bw_hwmon2;
 		m->hw.suspend_hwmon = suspend_bw_hwmon2;
 		m->hw.resume_hwmon = resume_bw_hwmon2;
 		m->hw.get_bytes_and_clear = get_bytes_and_clear2;
 		m->hw.set_hw_events = set_hw_events;
-	} else {
+		break;
+	case MON1:
 		m->hw.start_hwmon = start_bw_hwmon;
 		m->hw.stop_hwmon = stop_bw_hwmon;
 		m->hw.suspend_hwmon = suspend_bw_hwmon;
 		m->hw.resume_hwmon = resume_bw_hwmon;
 		m->hw.get_bytes_and_clear = get_bytes_and_clear;
 		m->hw.set_thres = set_thres;
+		break;
 	}
 
+	of_property_read_u32(dev->of_node, "qcom,byte-mid-match",
+			     &m->byte_match);
+	of_property_read_u32(dev->of_node, "qcom,byte-mid-mask",
+			     &m->byte_mask);
+
 	if (m->spec->throt_adj) {
 		m->hw.set_throttle_adj = mon_set_throttle_adj;
 		m->hw.get_throttle_adj = mon_get_throttle_adj;
diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c
index ebed22f..296ec12 100644
--- a/drivers/extcon/extcon-gpio.c
+++ b/drivers/extcon/extcon-gpio.c
@@ -28,6 +28,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
+#include <linux/of_gpio.h>
 
 struct gpio_extcon_data {
 	struct extcon_dev *edev;
@@ -37,6 +38,7 @@
 
 	struct gpio_desc *id_gpiod;
 	struct gpio_extcon_pdata *pdata;
+	unsigned int *supported_cable;
 };
 
 static void gpio_extcon_work(struct work_struct *work)
@@ -91,15 +93,93 @@
 	return 0;
 }
 
+static int extcon_parse_pinctrl_data(struct device *dev,
+				     struct gpio_extcon_pdata *pdata)
+{
+	struct pinctrl *pctrl;
+	int ret = 0;
+
+	/* Try to obtain pinctrl handle */
+	pctrl = devm_pinctrl_get(dev);
+	if (IS_ERR(pctrl)) {
+		ret = PTR_ERR(pctrl);
+		goto out;
+	}
+	pdata->pctrl = pctrl;
+
+	/* Look-up and keep the state handy to be used later */
+	pdata->pins_default = pinctrl_lookup_state(pdata->pctrl,
+						   "default");
+	if (IS_ERR(pdata->pins_default)) {
+		ret = PTR_ERR(pdata->pins_default);
+		dev_err(dev, "Can't get default pinctrl state, ret %d\n", ret);
+	}
+out:
+	return ret;
+}
+
+/* Parse platform data */
+static
+struct gpio_extcon_pdata *extcon_populate_pdata(struct device *dev)
+{
+	struct gpio_extcon_pdata *pdata = NULL;
+	struct device_node *np = dev->of_node;
+	enum of_gpio_flags flags;
+	u32 val;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		goto out;
+
+	if (of_property_read_u32(np, "extcon-id", &pdata->extcon_id)) {
+		dev_err(dev, "extcon-id property not found\n");
+		goto out;
+	}
+
+	pdata->gpio = of_get_named_gpio_flags(np, "gpio", 0, &flags);
+	if (gpio_is_valid(pdata->gpio)) {
+		if (flags & OF_GPIO_ACTIVE_LOW)
+			pdata->gpio_active_low = true;
+	} else {
+		dev_err(dev, "gpio property not found or invalid\n");
+		goto out;
+	}
+
+	if (of_property_read_u32(np, "irq-flags", &val)) {
+		dev_err(dev, "irq-flags property not found\n");
+		goto out;
+	}
+	pdata->irq_flags = val;
+
+	if (of_property_read_u32(np, "debounce-ms", &val)) {
+		dev_err(dev, "debounce-ms property not found\n");
+		goto out;
+	}
+	pdata->debounce = val;
+
+	if (extcon_parse_pinctrl_data(dev, pdata)) {
+		dev_err(dev, "failed to parse pinctrl data\n");
+		goto out;
+	}
+
+	return pdata;
+out:
+	return NULL;
+}
+
 static int gpio_extcon_probe(struct platform_device *pdev)
 {
 	struct gpio_extcon_pdata *pdata = dev_get_platdata(&pdev->dev);
 	struct gpio_extcon_data *data;
 	int ret;
 
-	if (!pdata)
-		return -EBUSY;
-	if (!pdata->irq_flags || pdata->extcon_id > EXTCON_NONE)
+	if (!pdata) {
+		/* try populating pdata from device tree */
+		pdata = extcon_populate_pdata(&pdev->dev);
+		if (!pdata)
+			return -EBUSY;
+	}
+	if (!pdata->irq_flags || pdata->extcon_id >= EXTCON_NUM)
 		return -EINVAL;
 
 	data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_extcon_data),
@@ -108,13 +188,27 @@
 		return -ENOMEM;
 	data->pdata = pdata;
 
+	ret = pinctrl_select_state(pdata->pctrl, pdata->pins_default);
+	if (ret < 0)
+		dev_err(&pdev->dev, "pinctrl state select failed, ret %d\n",
+			ret);
+
 	/* Initialize the gpio */
 	ret = gpio_extcon_init(&pdev->dev, data);
 	if (ret < 0)
 		return ret;
 
+	data->supported_cable = devm_kzalloc(&pdev->dev,
+					     sizeof(*data->supported_cable) * 2,
+					     GFP_KERNEL);
+	if (!data->supported_cable)
+		return -ENOMEM;
+
+	data->supported_cable[0] = pdata->extcon_id;
+	data->supported_cable[1] = EXTCON_NONE;
 	/* Allocate the memory of extcon devie and register extcon device */
-	data->edev = devm_extcon_dev_allocate(&pdev->dev, &pdata->extcon_id);
+	data->edev = devm_extcon_dev_allocate(&pdev->dev,
+					      data->supported_cable);
 	if (IS_ERR(data->edev)) {
 		dev_err(&pdev->dev, "failed to allocate extcon device\n");
 		return -ENOMEM;
@@ -168,12 +262,18 @@
 
 static SIMPLE_DEV_PM_OPS(gpio_extcon_pm_ops, NULL, gpio_extcon_resume);
 
+static const struct of_device_id extcon_gpio_of_match[] = {
+	{ .compatible = "extcon-gpio"},
+	{},
+};
+
 static struct platform_driver gpio_extcon_driver = {
 	.probe		= gpio_extcon_probe,
 	.remove		= gpio_extcon_remove,
 	.driver		= {
 		.name	= "extcon-gpio",
 		.pm	= &gpio_extcon_pm_ops,
+		.of_match_table = of_match_ptr(extcon_gpio_of_match),
 	},
 };
 
diff --git a/drivers/gpu/drm/msm/sde/sde_core_perf.c b/drivers/gpu/drm/msm/sde/sde_core_perf.c
index db2c515..1015da8 100644
--- a/drivers/gpu/drm/msm/sde/sde_core_perf.c
+++ b/drivers/gpu/drm/msm/sde/sde_core_perf.c
@@ -554,8 +554,8 @@
 
 	perf->max_core_clk_rate = sde_power_clk_get_max_rate(phandle, clk_name);
 	if (!perf->max_core_clk_rate) {
-		SDE_ERROR("invalid max core clk rate\n");
-		goto err;
+		SDE_DEBUG("optional max core clk rate, use default\n");
+		perf->max_core_clk_rate = SDE_PERF_DEFAULT_MAX_CORE_CLK_RATE;
 	}
 
 	return 0;
diff --git a/drivers/gpu/drm/msm/sde/sde_core_perf.h b/drivers/gpu/drm/msm/sde/sde_core_perf.h
index 20e4eb5..c61c9a7 100644
--- a/drivers/gpu/drm/msm/sde/sde_core_perf.h
+++ b/drivers/gpu/drm/msm/sde/sde_core_perf.h
@@ -21,6 +21,10 @@
 #include "sde_hw_catalog.h"
 #include "sde_power_handle.h"
 
+#define	SDE_PERF_DEFAULT_MAX_CORE_CLK_RATE	320000000
+#define	SDE_PERF_DEFAULT_MAX_BUS_AB_QUOTA	2000000000
+#define	SDE_PERF_DEFAULT_MAX_BUS_IB_QUOTA	2000000000
+
 /**
  * struct sde_core_perf_params - definition of performance parameters
  * @max_per_pipe_ib: maximum instantaneous bandwidth request
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 1bd7654..4845c43 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -2382,6 +2382,82 @@
 	return rc;
 }
 
+static int _sde_crtc_excl_rect_overlap_check(struct plane_state pstates[],
+	int cnt, int curr_cnt, struct sde_rect *excl_rect, int z_pos)
+{
+	struct sde_rect dst_rect, intersect;
+	int i, rc = -EINVAL;
+	const struct drm_plane_state *pstate;
+
+	/* start checking from next plane */
+	for (i = curr_cnt; i < cnt; i++) {
+		pstate = pstates[i].drm_pstate;
+		POPULATE_RECT(&dst_rect, pstate->crtc_x, pstate->crtc_y,
+				pstate->crtc_w, pstate->crtc_h, true);
+		sde_kms_rect_intersect(&dst_rect, excl_rect, &intersect);
+
+		if (intersect.w == excl_rect->w && intersect.h == excl_rect->h
+				/* next plane may be on same z-order */
+				&& z_pos != pstates[i].stage) {
+			rc = 0;
+			goto end;
+		}
+	}
+
+	SDE_ERROR("excl rect does not find top overlapping rect\n");
+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)
+{
+	struct sde_crtc_state *cstate = to_sde_crtc_state(state);
+	struct drm_display_mode *mode = &state->adjusted_mode;
+	const struct drm_plane_state *pstate;
+	struct sde_plane_state *sde_pstate;
+	int rc = 0, i;
+
+	/* Check dim layer rect bounds and stage */
+	for (i = 0; i < cstate->num_dim_layers; i++) {
+		if ((CHECK_LAYER_BOUNDS(cstate->dim_layer[i].rect.y,
+			cstate->dim_layer[i].rect.h, mode->vdisplay)) ||
+		    (CHECK_LAYER_BOUNDS(cstate->dim_layer[i].rect.x,
+			cstate->dim_layer[i].rect.w, mode->hdisplay)) ||
+		    (cstate->dim_layer[i].stage >= SDE_STAGE_MAX) ||
+		    (!cstate->dim_layer[i].rect.w) ||
+		    (!cstate->dim_layer[i].rect.h)) {
+			SDE_ERROR("invalid dim_layer:{%d,%d,%d,%d}, stage:%d\n",
+					cstate->dim_layer[i].rect.x,
+					cstate->dim_layer[i].rect.y,
+					cstate->dim_layer[i].rect.w,
+					cstate->dim_layer[i].rect.h,
+					cstate->dim_layer[i].stage);
+			SDE_ERROR("display: %dx%d\n", mode->hdisplay,
+					mode->vdisplay);
+			rc = -E2BIG;
+			goto end;
+		}
+	}
+
+	/* this is traversing on sorted z-order pstates */
+	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 all top z-order */
+			rc = _sde_crtc_excl_rect_overlap_check(pstates, cnt,
+			     i + 1, &sde_pstate->excl_rect, pstates[i].stage);
+			if (rc)
+				goto end;
+		}
+	}
+
+end:
+	return rc;
+}
+
 static int sde_crtc_atomic_check(struct drm_crtc *crtc,
 		struct drm_crtc_state *state)
 {
@@ -2490,31 +2566,13 @@
 		}
 	}
 
-	/* Check dim layer rect bounds and stage */
-	for (i = 0; i < cstate->num_dim_layers; i++) {
-		if ((CHECK_LAYER_BOUNDS(cstate->dim_layer[i].rect.y,
-			cstate->dim_layer[i].rect.h, mode->vdisplay)) ||
-		    (CHECK_LAYER_BOUNDS(cstate->dim_layer[i].rect.x,
-			cstate->dim_layer[i].rect.w, mode->hdisplay)) ||
-		    (cstate->dim_layer[i].stage >= SDE_STAGE_MAX) ||
-		    (!cstate->dim_layer[i].rect.w) ||
-		    (!cstate->dim_layer[i].rect.h)) {
-			SDE_ERROR("invalid dim_layer:{%d,%d,%d,%d}, stage:%d\n",
-					cstate->dim_layer[i].rect.x,
-					cstate->dim_layer[i].rect.y,
-					cstate->dim_layer[i].rect.w,
-					cstate->dim_layer[i].rect.h,
-					cstate->dim_layer[i].stage);
-			SDE_ERROR("display: %dx%d\n", mode->hdisplay,
-					mode->vdisplay);
-			rc = -E2BIG;
-			goto end;
-		}
-	}
-
 	/* assign mixer stages based on sorted zpos property */
 	sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL);
 
+	rc = _sde_crtc_excl_dim_layer_check(state, pstates, cnt);
+	if (rc)
+		goto end;
+
 	if (!sde_is_custom_client()) {
 		int stage_old = pstates[0].stage;
 
@@ -2709,19 +2767,19 @@
 			CRTC_PROP_CORE_CLK);
 	msm_property_install_range(&sde_crtc->property_info,
 			"core_ab", 0x0, 0, U64_MAX,
-			SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA,
+			SDE_PERF_DEFAULT_MAX_BUS_AB_QUOTA,
 			CRTC_PROP_CORE_AB);
 	msm_property_install_range(&sde_crtc->property_info,
 			"core_ib", 0x0, 0, U64_MAX,
-			SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA,
+			SDE_PERF_DEFAULT_MAX_BUS_IB_QUOTA,
 			CRTC_PROP_CORE_IB);
 	msm_property_install_range(&sde_crtc->property_info,
 			"mem_ab", 0x0, 0, U64_MAX,
-			SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA,
+			SDE_PERF_DEFAULT_MAX_BUS_AB_QUOTA,
 			CRTC_PROP_MEM_AB);
 	msm_property_install_range(&sde_crtc->property_info,
 			"mem_ib", 0x0, 0, U64_MAX,
-			SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA,
+			SDE_PERF_DEFAULT_MAX_BUS_IB_QUOTA,
 			CRTC_PROP_MEM_IB);
 	msm_property_install_range(&sde_crtc->property_info,
 			"rot_prefill_bw", 0, 0, U64_MAX,
@@ -2767,13 +2825,40 @@
 	sde_kms_info_add_keyint(info, "has_src_split", catalog->has_src_split);
 	if (catalog->perf.max_bw_low)
 		sde_kms_info_add_keyint(info, "max_bandwidth_low",
-				catalog->perf.max_bw_low);
+				catalog->perf.max_bw_low * 1000LL);
 	if (catalog->perf.max_bw_high)
 		sde_kms_info_add_keyint(info, "max_bandwidth_high",
-				catalog->perf.max_bw_high);
+				catalog->perf.max_bw_high * 1000LL);
 	if (sde_kms->perf.max_core_clk_rate)
 		sde_kms_info_add_keyint(info, "max_mdp_clk",
 				sde_kms->perf.max_core_clk_rate);
+	sde_kms_info_add_keystr(info, "core_ib_ff",
+			catalog->perf.core_ib_ff);
+	sde_kms_info_add_keystr(info, "core_clk_ff",
+			catalog->perf.core_clk_ff);
+	sde_kms_info_add_keystr(info, "comp_ratio_rt",
+			catalog->perf.comp_ratio_rt);
+	sde_kms_info_add_keystr(info, "comp_ratio_nrt",
+			catalog->perf.comp_ratio_nrt);
+	sde_kms_info_add_keyint(info, "dest_scale_prefill_lines",
+			catalog->perf.dest_scale_prefill_lines);
+	sde_kms_info_add_keyint(info, "undersized_prefill_lines",
+			catalog->perf.undersized_prefill_lines);
+	sde_kms_info_add_keyint(info, "macrotile_prefill_lines",
+			catalog->perf.macrotile_prefill_lines);
+	sde_kms_info_add_keyint(info, "yuv_nv12_prefill_lines",
+			catalog->perf.yuv_nv12_prefill_lines);
+	sde_kms_info_add_keyint(info, "linear_prefill_lines",
+			catalog->perf.linear_prefill_lines);
+	sde_kms_info_add_keyint(info, "downscaling_prefill_lines",
+			catalog->perf.downscaling_prefill_lines);
+	sde_kms_info_add_keyint(info, "xtra_prefill_lines",
+			catalog->perf.xtra_prefill_lines);
+	sde_kms_info_add_keyint(info, "amortizable_threshold",
+			catalog->perf.amortizable_threshold);
+	sde_kms_info_add_keyint(info, "min_prefill_lines",
+			catalog->perf.min_prefill_lines);
+
 	msm_property_set_blob(&sde_crtc->property_info, &sde_crtc->blob_info,
 			info->data, info->len, CRTC_PROP_INFO);
 
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index b8ab066..5118a79 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -93,6 +93,27 @@
 
 #define DEFAULT_SBUF_HEADROOM		(20)
 
+/*
+ * Default parameter values
+ */
+#define DEFAULT_MAX_BW_HIGH			7000000
+#define DEFAULT_MAX_BW_LOW			7000000
+#define DEFAULT_UNDERSIZED_PREFILL_LINES	2
+#define DEFAULT_XTRA_PREFILL_LINES		2
+#define DEFAULT_DEST_SCALE_PREFILL_LINES	3
+#define DEFAULT_MACROTILE_PREFILL_LINES		4
+#define DEFAULT_YUV_NV12_PREFILL_LINES		8
+#define DEFAULT_LINEAR_PREFILL_LINES		1
+#define DEFAULT_DOWNSCALING_PREFILL_LINES	1
+#define DEFAULT_CORE_IB_FF			"6.0"
+#define DEFAULT_CORE_CLK_FF			"1.0"
+#define DEFAULT_COMP_RATIO_RT \
+		"NV12/5/1/1.23 AB24/5/1/1.23 XB24/5/1/1.23"
+#define DEFAULT_COMP_RATIO_NRT \
+		"NV12/5/1/1.25 AB24/5/1/1.25 XB24/5/1/1.25"
+#define DEFAULT_MAX_PER_PIPE_BW			2400000
+#define DEFAULT_AMORTIZABLE_THRESHOLD		25
+
 /*************************************************************
  *  DTSI PROPERTY INDEX
  *************************************************************/
@@ -127,6 +148,18 @@
 enum {
 	PERF_MAX_BW_LOW,
 	PERF_MAX_BW_HIGH,
+	PERF_CORE_IB_FF,
+	PERF_CORE_CLK_FF,
+	PERF_COMP_RATIO_RT,
+	PERF_COMP_RATIO_NRT,
+	PERF_UNDERSIZED_PREFILL_LINES,
+	PERF_DEST_SCALE_PREFILL_LINES,
+	PERF_MACROTILE_PREFILL_LINES,
+	PERF_YUV_NV12_PREFILL_LINES,
+	PERF_LINEAR_PREFILL_LINES,
+	PERF_DOWNSCALING_PREFILL_LINES,
+	PERF_XTRA_PREFILL_LINES,
+	PERF_AMORTIZABLE_THRESHOLD,
 	PERF_PROP_MAX,
 };
 
@@ -144,6 +177,7 @@
 	SSPP_RGB_BLOCKS,
 	SSPP_EXCL_RECT,
 	SSPP_SMART_DMA,
+	SSPP_MAX_PER_PIPE_BW,
 	SSPP_PROP_MAX,
 };
 
@@ -320,6 +354,28 @@
 static struct sde_prop_type sde_perf_prop[] = {
 	{PERF_MAX_BW_LOW, "qcom,sde-max-bw-low-kbps", false, PROP_TYPE_U32},
 	{PERF_MAX_BW_HIGH, "qcom,sde-max-bw-high-kbps", false, PROP_TYPE_U32},
+	{PERF_CORE_IB_FF, "qcom,sde-core-ib-ff", false, PROP_TYPE_STRING},
+	{PERF_CORE_CLK_FF, "qcom,sde-core-clk-ff", false, PROP_TYPE_STRING},
+	{PERF_COMP_RATIO_RT, "qcom,sde-comp-ratio-rt", false,
+			PROP_TYPE_STRING},
+	{PERF_COMP_RATIO_NRT, "qcom,sde-comp-ratio-nrt", false,
+			PROP_TYPE_STRING},
+	{PERF_UNDERSIZED_PREFILL_LINES, "qcom,sde-undersizedprefill-lines",
+			false, PROP_TYPE_U32},
+	{PERF_DEST_SCALE_PREFILL_LINES, "qcom,sde-dest-scaleprefill-lines",
+			false, PROP_TYPE_U32},
+	{PERF_MACROTILE_PREFILL_LINES, "qcom,sde-macrotileprefill-lines",
+			false, PROP_TYPE_U32},
+	{PERF_YUV_NV12_PREFILL_LINES, "qcom,sde-yuv-nv12prefill-lines",
+			false, PROP_TYPE_U32},
+	{PERF_LINEAR_PREFILL_LINES, "qcom,sde-linearprefill-lines",
+			false, PROP_TYPE_U32},
+	{PERF_DOWNSCALING_PREFILL_LINES, "qcom,sde-downscalingprefill-lines",
+			false, PROP_TYPE_U32},
+	{PERF_XTRA_PREFILL_LINES, "qcom,sde-xtra-prefill-lines",
+			false, PROP_TYPE_U32},
+	{PERF_AMORTIZABLE_THRESHOLD, "qcom,sde-amortizable-threshold",
+			false, PROP_TYPE_U32},
 };
 
 static struct sde_prop_type sspp_prop[] = {
@@ -339,6 +395,8 @@
 	{SSPP_EXCL_RECT, "qcom,sde-sspp-excl-rect", false, PROP_TYPE_U32_ARRAY},
 	{SSPP_SMART_DMA, "qcom,sde-sspp-smart-dma-priority", false,
 		PROP_TYPE_U32_ARRAY},
+	{SSPP_MAX_PER_PIPE_BW, "qcom,sde-max-per-pipe-bw-kbps", false,
+		PROP_TYPE_U32_ARRAY},
 };
 
 static struct sde_prop_type vig_prop[] = {
@@ -1078,6 +1136,12 @@
 		if (PROP_VALUE_ACCESS(prop_value, SSPP_EXCL_RECT, i) == 1)
 			set_bit(SDE_SSPP_EXCL_RECT, &sspp->features);
 
+		if (prop_exists[SSPP_MAX_PER_PIPE_BW])
+			sblk->max_per_pipe_bw = PROP_VALUE_ACCESS(prop_value,
+					SSPP_MAX_PER_PIPE_BW, i);
+		else
+			sblk->max_per_pipe_bw = DEFAULT_MAX_PER_PIPE_BW;
+
 		for (j = 0; j < sde_cfg->mdp_count; j++) {
 			sde_cfg->mdp[j].clk_ctrls[sspp->clk_ctrl].reg_off =
 				PROP_BITVALUE_ACCESS(prop_value,
@@ -2260,6 +2324,7 @@
 	int rc, len, prop_count[PERF_PROP_MAX];
 	struct sde_prop_value *prop_value = NULL;
 	bool prop_exists[PERF_PROP_MAX];
+	const char *str = NULL;
 
 	if (!cfg) {
 		SDE_ERROR("invalid argument\n");
@@ -2285,9 +2350,72 @@
 		goto freeprop;
 
 	cfg->perf.max_bw_low =
-			PROP_VALUE_ACCESS(prop_value, PERF_MAX_BW_LOW, 0);
+			prop_exists[PERF_MAX_BW_LOW] ?
+			PROP_VALUE_ACCESS(prop_value, PERF_MAX_BW_LOW, 0) :
+			DEFAULT_MAX_BW_LOW;
 	cfg->perf.max_bw_high =
-			PROP_VALUE_ACCESS(prop_value, PERF_MAX_BW_HIGH, 0);
+			prop_exists[PERF_MAX_BW_HIGH] ?
+			PROP_VALUE_ACCESS(prop_value, PERF_MAX_BW_HIGH, 0) :
+			DEFAULT_MAX_BW_HIGH;
+
+	/*
+	 * The following performance parameters (e.g. core_ib_ff) are
+	 * mapped directly as device tree string constants.
+	 */
+	rc = of_property_read_string(np,
+			sde_perf_prop[PERF_CORE_IB_FF].prop_name, &str);
+	cfg->perf.core_ib_ff = rc ? DEFAULT_CORE_IB_FF : str;
+	rc = of_property_read_string(np,
+			sde_perf_prop[PERF_CORE_CLK_FF].prop_name, &str);
+	cfg->perf.core_clk_ff = rc ? DEFAULT_CORE_CLK_FF : str;
+	rc = of_property_read_string(np,
+			sde_perf_prop[PERF_COMP_RATIO_RT].prop_name, &str);
+	cfg->perf.comp_ratio_rt = rc ? DEFAULT_COMP_RATIO_RT : str;
+	rc = of_property_read_string(np,
+			sde_perf_prop[PERF_COMP_RATIO_NRT].prop_name, &str);
+	cfg->perf.comp_ratio_nrt = rc ? DEFAULT_COMP_RATIO_NRT : str;
+	rc = 0;
+
+	cfg->perf.undersized_prefill_lines =
+			prop_exists[PERF_UNDERSIZED_PREFILL_LINES] ?
+			PROP_VALUE_ACCESS(prop_value,
+					PERF_UNDERSIZED_PREFILL_LINES, 0) :
+			DEFAULT_UNDERSIZED_PREFILL_LINES;
+	cfg->perf.xtra_prefill_lines =
+			prop_exists[PERF_XTRA_PREFILL_LINES] ?
+			PROP_VALUE_ACCESS(prop_value,
+					PERF_XTRA_PREFILL_LINES, 0) :
+			DEFAULT_XTRA_PREFILL_LINES;
+	cfg->perf.dest_scale_prefill_lines =
+			prop_exists[PERF_DEST_SCALE_PREFILL_LINES] ?
+			PROP_VALUE_ACCESS(prop_value,
+					PERF_DEST_SCALE_PREFILL_LINES, 0) :
+			DEFAULT_DEST_SCALE_PREFILL_LINES;
+	cfg->perf.macrotile_prefill_lines =
+			prop_exists[PERF_MACROTILE_PREFILL_LINES] ?
+			PROP_VALUE_ACCESS(prop_value,
+					PERF_MACROTILE_PREFILL_LINES, 0) :
+			DEFAULT_MACROTILE_PREFILL_LINES;
+	cfg->perf.yuv_nv12_prefill_lines =
+			prop_exists[PERF_YUV_NV12_PREFILL_LINES] ?
+			PROP_VALUE_ACCESS(prop_value,
+					PERF_YUV_NV12_PREFILL_LINES, 0) :
+			DEFAULT_YUV_NV12_PREFILL_LINES;
+	cfg->perf.linear_prefill_lines =
+			prop_exists[PERF_LINEAR_PREFILL_LINES] ?
+			PROP_VALUE_ACCESS(prop_value,
+					PERF_LINEAR_PREFILL_LINES, 0) :
+			DEFAULT_LINEAR_PREFILL_LINES;
+	cfg->perf.downscaling_prefill_lines =
+			prop_exists[PERF_DOWNSCALING_PREFILL_LINES] ?
+			PROP_VALUE_ACCESS(prop_value,
+					PERF_DOWNSCALING_PREFILL_LINES, 0) :
+			DEFAULT_DOWNSCALING_PREFILL_LINES;
+	cfg->perf.amortizable_threshold =
+			prop_exists[PERF_AMORTIZABLE_THRESHOLD] ?
+			PROP_VALUE_ACCESS(prop_value,
+					PERF_AMORTIZABLE_THRESHOLD, 0) :
+			DEFAULT_AMORTIZABLE_THRESHOLD;
 
 freeprop:
 	kfree(prop_value);
@@ -2400,14 +2528,21 @@
 	case SDE_HW_VER_171:
 	case SDE_HW_VER_172:
 		/* update msm8996 target here */
+		sde_cfg->perf.min_prefill_lines = 21;
 		break;
 	case SDE_HW_VER_300:
 	case SDE_HW_VER_301:
+		/* update msm8998 target here */
+		sde_cfg->has_wb_ubwc = true;
+		sde_cfg->perf.min_prefill_lines = 25;
+		break;
 	case SDE_HW_VER_400:
 		/* update msm8998 and sdm845 target here */
 		sde_cfg->has_wb_ubwc = true;
+		sde_cfg->perf.min_prefill_lines = 24;
 		break;
 	default:
+		sde_cfg->perf.min_prefill_lines = 0xffff;
 		break;
 	}
 
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
index b5f83ad..cfb1b67 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -361,6 +361,7 @@
  * @pcc_blk:
  * @igc_blk:
  * @format_list: Pointer to list of supported formats
+ * @max_per_pipe_bw: maximum allowable bandwidth of this pipe in kBps
  */
 struct sde_sspp_sub_blks {
 	u32 maxlinewidth;
@@ -379,6 +380,7 @@
 	u32 maxhdeciexp; /* max decimation is 2^value */
 	u32 maxvdeciexp; /* max decimation is 2^value */
 	u32 smart_dma_priority;
+	u32 max_per_pipe_bw;
 	struct sde_src_blk src_blk;
 	struct sde_scaler_blk scaler_blk;
 	struct sde_pp_blk csc_blk;
@@ -687,10 +689,36 @@
  * struct sde_perf_cfg - performance control settings
  * @max_bw_low         low threshold of maximum bandwidth (kbps)
  * @max_bw_high        high threshold of maximum bandwidth (kbps)
+ * @core_ib_ff         core instantaneous bandwidth fudge factor
+ * @core_clk_ff        core clock fudge factor
+ * @comp_ratio_rt      string of 0 or more of <fourcc>/<ven>/<mod>/<comp ratio>
+ * @comp_ratio_nrt     string of 0 or more of <fourcc>/<ven>/<mod>/<comp ratio>
+ * @undersized_prefill_lines   undersized prefill in lines
+ * @xtra_prefill_lines         extra prefill latency in lines
+ * @dest_scale_prefill_lines   destination scaler latency in lines
+ * @macrotile_perfill_lines    macrotile latency in lines
+ * @yuv_nv12_prefill_lines     yuv_nv12 latency in lines
+ * @linear_prefill_lines       linear latency in lines
+ * @downscaling_prefill_lines  downscaling latency in lines
+ * @amortizable_theshold minimum y position for traffic shaping prefill
+ * @min_prefill_lines  minimum pipeline latency in lines
  */
 struct sde_perf_cfg {
 	u32 max_bw_low;
 	u32 max_bw_high;
+	const char *core_ib_ff;
+	const char *core_clk_ff;
+	const char *comp_ratio_rt;
+	const char *comp_ratio_nrt;
+	u32 undersized_prefill_lines;
+	u32 xtra_prefill_lines;
+	u32 dest_scale_prefill_lines;
+	u32 macrotile_prefill_lines;
+	u32 yuv_nv12_prefill_lines;
+	u32 linear_prefill_lines;
+	u32 downscaling_prefill_lines;
+	u32 amortizable_threshold;
+	u32 min_prefill_lines;
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h
index d38a6b9..01a5535 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.h
+++ b/drivers/gpu/drm/msm/sde/sde_kms.h
@@ -325,11 +325,11 @@
  * sde_kms_info_add_keyint - add integer value to 'sde_kms_info'
  * @info: Pointer to sde_kms_info structure
  * @key: Pointer to key string
- * @value: Signed 32-bit integer value
+ * @value: Signed 64-bit integer value
  */
 void sde_kms_info_add_keyint(struct sde_kms_info *info,
 		const char *key,
-		int32_t value);
+		int64_t value);
 
 /**
  * sde_kms_info_add_keystr - add string value to 'sde_kms_info'
diff --git a/drivers/gpu/drm/msm/sde/sde_kms_utils.c b/drivers/gpu/drm/msm/sde/sde_kms_utils.c
index 30e12c9..b956be5 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms_utils.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms_utils.c
@@ -24,14 +24,14 @@
 
 void sde_kms_info_add_keyint(struct sde_kms_info *info,
 		const char *key,
-		int32_t value)
+		int64_t value)
 {
 	uint32_t len;
 
 	if (info && key) {
 		len = snprintf(info->data + info->len,
 				SDE_KMS_INFO_MAX_SIZE - info->len,
-				"%s=%d\n",
+				"%s=%lld\n",
 				key,
 				value);
 
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index c408861..cf03a47 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -2886,11 +2886,12 @@
 
 		/*
 		 * Check exclusion rect against src rect.
-		 * Cropping is not required as hardware will consider only the
-		 * intersecting region with the src rect.
+		 * it must intersect with source rect.
 		 */
 		sde_kms_rect_intersect(&src, &pstate->excl_rect, &intersect);
-		if (!intersect.w || !intersect.h || SDE_FORMAT_IS_YUV(fmt)) {
+		if (intersect.w != pstate->excl_rect.w ||
+				intersect.h != pstate->excl_rect.h ||
+				SDE_FORMAT_IS_YUV(fmt)) {
 			SDE_ERROR_PLANE(psde,
 				"invalid excl_rect:{%d,%d,%d,%d} src:{%d,%d,%d,%d}, fmt: %4.4s\n",
 				pstate->excl_rect.x, pstate->excl_rect.y,
@@ -3191,6 +3192,8 @@
 			psde->pipe_sblk->maxhdeciexp);
 	sde_kms_info_add_keyint(info, "max_vertical_deci",
 			psde->pipe_sblk->maxvdeciexp);
+	sde_kms_info_add_keyint(info, "max_per_pipe_bw",
+			psde->pipe_sblk->max_per_pipe_bw * 1000LL);
 	msm_property_set_blob(&psde->property_info, &psde->blob_info,
 			info->data, info->len, PLANE_PROP_INFO);
 
diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c
index 81df309..7fd496f 100644
--- a/drivers/gpu/drm/sti/sti_gdp.c
+++ b/drivers/gpu/drm/sti/sti_gdp.c
@@ -66,7 +66,9 @@
 #define GAM_GDP_ALPHARANGE_255  BIT(5)
 #define GAM_GDP_AGC_FULL_RANGE  0x00808080
 #define GAM_GDP_PPT_IGNORE      (BIT(1) | BIT(0))
-#define GAM_GDP_SIZE_MAX        0x7FF
+
+#define GAM_GDP_SIZE_MAX_WIDTH  3840
+#define GAM_GDP_SIZE_MAX_HEIGHT 2160
 
 #define GDP_NODE_NB_BANK        2
 #define GDP_NODE_PER_FIELD      2
@@ -633,8 +635,8 @@
 	/* src_x are in 16.16 format */
 	src_x = state->src_x >> 16;
 	src_y = state->src_y >> 16;
-	src_w = clamp_val(state->src_w >> 16, 0, GAM_GDP_SIZE_MAX);
-	src_h = clamp_val(state->src_h >> 16, 0, GAM_GDP_SIZE_MAX);
+	src_w = clamp_val(state->src_w >> 16, 0, GAM_GDP_SIZE_MAX_WIDTH);
+	src_h = clamp_val(state->src_h >> 16, 0, GAM_GDP_SIZE_MAX_HEIGHT);
 
 	format = sti_gdp_fourcc2format(fb->pixel_format);
 	if (format == -1) {
@@ -732,8 +734,8 @@
 	/* src_x are in 16.16 format */
 	src_x = state->src_x >> 16;
 	src_y = state->src_y >> 16;
-	src_w = clamp_val(state->src_w >> 16, 0, GAM_GDP_SIZE_MAX);
-	src_h = clamp_val(state->src_h >> 16, 0, GAM_GDP_SIZE_MAX);
+	src_w = clamp_val(state->src_w >> 16, 0, GAM_GDP_SIZE_MAX_WIDTH);
+	src_h = clamp_val(state->src_h >> 16, 0, GAM_GDP_SIZE_MAX_HEIGHT);
 
 	list = sti_gdp_get_free_nodes(gdp);
 	top_field = list->top_field;
diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
index a6ed9d5..750733a 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_vm.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c
@@ -66,8 +66,11 @@
 		if (vmf->flags & FAULT_FLAG_RETRY_NOWAIT)
 			goto out_unlock;
 
+		ttm_bo_reference(bo);
 		up_read(&vma->vm_mm->mmap_sem);
 		(void) fence_wait(bo->moving, true);
+		ttm_bo_unreserve(bo);
+		ttm_bo_unref(&bo);
 		goto out_unlock;
 	}
 
@@ -120,8 +123,10 @@
 
 		if (vmf->flags & FAULT_FLAG_ALLOW_RETRY) {
 			if (!(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) {
+				ttm_bo_reference(bo);
 				up_read(&vma->vm_mm->mmap_sem);
 				(void) ttm_bo_wait_unreserved(bo);
+				ttm_bo_unref(&bo);
 			}
 
 			return VM_FAULT_RETRY;
@@ -166,6 +171,13 @@
 	ret = ttm_bo_vm_fault_idle(bo, vma, vmf);
 	if (unlikely(ret != 0)) {
 		retval = ret;
+
+		if (retval == VM_FAULT_RETRY &&
+		    !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) {
+			/* The BO has already been unreserved. */
+			return retval;
+		}
+
 		goto out_unlock;
 	}
 
diff --git a/drivers/gpu/msm/a6xx_reg.h b/drivers/gpu/msm/a6xx_reg.h
index f78ee05..6db0111 100644
--- a/drivers/gpu/msm/a6xx_reg.h
+++ b/drivers/gpu/msm/a6xx_reg.h
@@ -799,7 +799,7 @@
 #define A6XX_GMU_GPU_NAP_CTRL			0x1F8E4
 #define A6XX_GMU_RPMH_CTRL			0x1F8E8
 #define A6XX_GMU_RPMH_HYST_CTRL			0x1F8E9
-#define A6XX_GMU_RPMH_POWER_STATE		0x1F8EC
+#define A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE    0x1F8EC
 #define A6XX_GMU_BOOT_KMD_LM_HANDSHAKE		0x1F9F0
 
 /* HFI registers*/
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index fbf0e7b..b7cfadd 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1266,9 +1266,12 @@
 		return ret;
 
 	/* Put the GPU in a responsive state */
-	ret = kgsl_pwrctrl_change_state(device, KGSL_STATE_AWARE);
-	if (ret)
-		return ret;
+	if (ADRENO_GPUREV(adreno_dev) < 600) {
+		/* No need for newer generation architectures */
+		ret = kgsl_pwrctrl_change_state(device, KGSL_STATE_AWARE);
+		if (ret)
+			return ret;
+	}
 
 	ret = adreno_iommu_init(adreno_dev);
 	if (ret)
@@ -1278,7 +1281,8 @@
 	adreno_fault_detect_init(adreno_dev);
 
 	/* Power down the device */
-	kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER);
+	if (ADRENO_GPUREV(adreno_dev) < 600)
+		kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER);
 
 	if (gpudev->init != NULL)
 		gpudev->init(adreno_dev);
@@ -1344,6 +1348,9 @@
 {
 	int i;
 
+	if (kgsl_gmu_isenabled(device))
+		return false;
+
 	for (i = 0; i < KGSL_MAX_REGULATORS; i++) {
 		struct kgsl_regulator *regulator =
 			&device->pwrctrl.regulators[i];
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index 9e66ce1..dee2cd1 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -830,6 +830,10 @@
 	struct gmu_device *gmu = &device->gmu;
 
 	/* Configure registers for idle setting. The setting is cumulative */
+
+	kgsl_gmu_regwrite(device,
+		A6XX_GMU_PWR_COL_INTER_FRAME_CTRL,  0x9C40400);
+
 	switch (gmu->idle_level) {
 	case GPU_HW_MIN_VOLT:
 		kgsl_gmu_regrmw(device, A6XX_GMU_RPMH_CTRL, 0,
@@ -1229,7 +1233,8 @@
 	if (ret)
 		dev_err(&gmu->pdev->dev, "OOB set for slumber timed out\n");
 	else {
-		kgsl_gmu_regread(device, A6XX_GMU_RPMH_POWER_STATE, &state);
+		kgsl_gmu_regread(device,
+			A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE, &state);
 		if (state != GPU_HW_SLUMBER) {
 			dev_err(&gmu->pdev->dev,
 					"Failed to prepare for slumber\n");
@@ -2269,7 +2274,7 @@
 	ADRENO_REG_DEFINE(ADRENO_REG_GMU_HFI_SFR_ADDR,
 				A6XX_GMU_HFI_SFR_ADDR),
 	ADRENO_REG_DEFINE(ADRENO_REG_GMU_RPMH_POWER_STATE,
-				A6XX_GMU_RPMH_POWER_STATE),
+				A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE),
 	ADRENO_REG_DEFINE(ADRENO_REG_GMU_GMU2HOST_INTR_CLR,
 				A6XX_GMU_GMU2HOST_INTR_CLR),
 	ADRENO_REG_DEFINE(ADRENO_REG_GMU_GMU2HOST_INTR_INFO,
diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c
index 0c821cd..54659fc 100644
--- a/drivers/gpu/msm/kgsl_gmu.c
+++ b/drivers/gpu/msm/kgsl_gmu.c
@@ -1332,12 +1332,6 @@
 	 * In v2, this function call shall move ahead
 	 * of hfi_start() to save power.
 	 */
-	ret = gpudev->oob_set(adreno_dev, OOB_CPINIT_SET_MASK,
-			OOB_CPINIT_CHECK_MASK, OOB_CPINIT_CLEAR_MASK);
-	gpudev->oob_clear(adreno_dev, OOB_CPINIT_CLEAR_MASK);
-
-	if (ret)
-		goto error_gpu;
 
 	if (device->state == KGSL_STATE_INIT ||
 			device->state == KGSL_STATE_SUSPEND) {
@@ -1379,19 +1373,20 @@
 	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
 	unsigned long t;
 	bool idle = false;
+	unsigned int reg;
 
 	if (!test_bit(GMU_CLK_ON, &gmu->flags))
 		return;
 
-	if (gpudev->hw_isidle) {
-		t = jiffies + msecs_to_jiffies(GMU_IDLE_TIMEOUT);
-		while (!time_after(jiffies, t)) {
-			if (gpudev->hw_isidle(adreno_dev)) {
-				idle = true;
-				break;
-			}
-			cpu_relax();
+	t = jiffies + msecs_to_jiffies(GMU_IDLE_TIMEOUT);
+	while (!time_after(jiffies, t)) {
+		adreno_read_gmureg(ADRENO_DEVICE(device),
+			ADRENO_REG_GMU_RPMH_POWER_STATE, &reg);
+		if (reg == device->gmu.idle_level) {
+			idle = true;
+			break;
 		}
+		cpu_relax();
 	}
 
 	gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_NOTIFY_SLUMBER, 0, 0);
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index b99c1df..81853ee 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -2600,7 +2600,7 @@
 
 		/* Check for pwm4 */
 		reg = superio_inb(sioaddr, IT87_SIO_GPIO4_REG);
-		if (!(reg & BIT(2)))
+		if (reg & BIT(2))
 			sio_data->skip_pwm |= BIT(3);
 
 		/* Check for pwm2, fan2 */
diff --git a/drivers/input/misc/qpnp-power-on.c b/drivers/input/misc/qpnp-power-on.c
index 62e34cc..339f94c 100644
--- a/drivers/input/misc/qpnp-power-on.c
+++ b/drivers/input/misc/qpnp-power-on.c
@@ -2123,6 +2123,9 @@
 		return rc;
 	}
 
+	if (sys_reset)
+		boot_reason = ffs(pon_sts);
+
 	index = ffs(pon_sts) - 1;
 	cold_boot = !qpnp_pon_is_warm_reset();
 	if (index >= ARRAY_SIZE(qpnp_pon_reason) || index < 0) {
@@ -2350,8 +2353,6 @@
 		list_add(&pon->list, &spon_dev_list);
 		spin_unlock_irqrestore(&spon_list_slock, flags);
 		pon->is_spon = true;
-	} else {
-		boot_reason = ffs(pon_sts);
 	}
 
 	/* config whether store the hard reset reason */
diff --git a/drivers/leds/leds-ktd2692.c b/drivers/leds/leds-ktd2692.c
index bf23ba1..45296aa 100644
--- a/drivers/leds/leds-ktd2692.c
+++ b/drivers/leds/leds-ktd2692.c
@@ -270,15 +270,15 @@
 		return -ENXIO;
 
 	led->ctrl_gpio = devm_gpiod_get(dev, "ctrl", GPIOD_ASIS);
-	if (IS_ERR(led->ctrl_gpio)) {
-		ret = PTR_ERR(led->ctrl_gpio);
+	ret = PTR_ERR_OR_ZERO(led->ctrl_gpio);
+	if (ret) {
 		dev_err(dev, "cannot get ctrl-gpios %d\n", ret);
 		return ret;
 	}
 
 	led->aux_gpio = devm_gpiod_get(dev, "aux", GPIOD_ASIS);
-	if (IS_ERR(led->aux_gpio)) {
-		ret = PTR_ERR(led->aux_gpio);
+	ret = PTR_ERR_OR_ZERO(led->aux_gpio);
+	if (ret) {
 		dev_err(dev, "cannot get aux-gpios %d\n", ret);
 		return ret;
 	}
diff --git a/drivers/media/platform/msm/camera/Makefile b/drivers/media/platform/msm/camera/Makefile
index c05c069..2e71d05 100644
--- a/drivers/media/platform/msm/camera/Makefile
+++ b/drivers/media/platform/msm/camera/Makefile
@@ -6,3 +6,5 @@
 obj-$(CONFIG_SPECTRA_CAMERA) += cam_cpas/
 obj-$(CONFIG_SPECTRA_CAMERA) += cam_cdm/
 obj-$(CONFIG_SPECTRA_CAMERA) += cam_isp/
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_module/
+obj-$(CONFIG_SPECTRA_CAMERA) += icp/
diff --git a/drivers/media/platform/msm/camera/cam_core/Makefile b/drivers/media/platform/msm/camera/cam_core/Makefile
index 417de13..60f94d1 100644
--- a/drivers/media/platform/msm/camera/cam_core/Makefile
+++ b/drivers/media/platform/msm/camera/cam_core/Makefile
@@ -1,3 +1,4 @@
 ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sync
 
-obj-$(CONFIG_SPECTRA_CAMERA) += cam_context.o cam_node.o cam_subdev.o
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_context.o cam_context_utils.o cam_node.o cam_subdev.o
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context.c b/drivers/media/platform/msm/camera/cam_core/cam_context.c
index 56b34f5..17b3c7c 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_context.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context.c
@@ -358,4 +358,3 @@
 
 	return 0;
 }
-
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context.h b/drivers/media/platform/msm/camera/cam_core/cam_context.h
index c7329cf..37a5c03 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_context.h
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context.h
@@ -22,6 +22,8 @@
 
 /* max request number */
 #define CAM_CTX_REQ_MAX              20
+#define CAM_CTX_CFG_MAX              20
+#define CAM_CTX_RES_MAX              20
 
 /**
  * enum cam_ctx_state -  context top level states
@@ -43,13 +45,29 @@
  * @status:                Request status
  * @request_id:            Request id
  * @req_priv:              Derived request object
+ * @hw_update_entries:     Hardware update entries
+ * @num_hw_update_entries: Number of hardware update entries
+ * @in_map_entries:        Entries for in fences
+ * @num_in_map_entries:    Number of in map entries
+ * @out_map_entries:       Entries for out fences
+ * @num_out_map_entries:   Number of out map entries
+ * @num_in_acked:          Number of in fence acked
+ * @num_out_acked:         Number of out fence acked
  *
  */
 struct cam_ctx_request {
-	struct list_head   list;
-	uint32_t           status;
-	uint64_t           request_id;
-	void              *req_priv;
+	struct list_head              list;
+	uint32_t                      status;
+	uint64_t                      request_id;
+	void                          *req_priv;
+	struct cam_hw_update_entry    hw_update_entries[CAM_CTX_CFG_MAX];
+	uint32_t                      num_hw_update_entries;
+	struct cam_hw_fence_map_entry in_map_entries[CAM_CTX_CFG_MAX];
+	uint32_t                      num_in_map_entries;
+	struct cam_hw_fence_map_entry out_map_entries[CAM_CTX_CFG_MAX];
+	uint32_t                      num_out_map_entries;
+	uint32_t                      num_in_acked;
+	uint32_t                      num_out_acked;
 };
 
 /**
@@ -132,6 +150,7 @@
  * @state:                 Current state for top level state machine
  * @state_machine:         Top level state machine
  * @ctx_priv:              Private context pointer
+ * @ctxt_to_hw_map:        Context to hardware mapping pointer
  *
  */
 struct cam_context {
@@ -159,6 +178,7 @@
 	struct cam_ctx_ops          *state_machine;
 
 	void                        *ctx_priv;
+	void                        *ctxt_to_hw_map;
 };
 
 /**
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
new file mode 100644
index 0000000..21a61ff
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
@@ -0,0 +1,481 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "CTXT-UTILS %s:%d " fmt, __func__, __LINE__
+
+#include <linux/debugfs.h>
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <media/cam_sync.h>
+#include <media/cam_defs.h>
+
+#include "cam_sync_api.h"
+#include "cam_req_mgr_util.h"
+#include "cam_mem_mgr.h"
+#include "cam_node.h"
+#include "cam_context.h"
+
+int cam_context_buf_done_from_hw(struct cam_context *ctx,
+	void *done_event_data, uint32_t bubble_state)
+{
+	int rc = 0;
+	int i, j;
+	struct cam_ctx_request *req;
+	struct cam_hw_done_event_data *done =
+		(struct cam_hw_done_event_data *)done_event_data;
+
+	if (list_empty(&ctx->active_req_list)) {
+		pr_err("Buf done with no active request\n");
+		rc = -EINVAL;
+		goto end;
+	}
+
+	req = list_first_entry(&ctx->active_req_list,
+		struct cam_ctx_request, list);
+
+	for (i = 0; i < done->num_handles; i++) {
+		for (j = 0; j < req->num_out_map_entries; j++) {
+			if (done->resource_handle[i] ==
+				req->out_map_entries[j].resource_handle)
+				break;
+		}
+
+		if (j == req->num_out_map_entries) {
+			pr_err("Can not find matching lane handle 0x%x\n",
+				done->resource_handle[i]);
+			rc = -EINVAL;
+			continue;
+		}
+
+		cam_sync_signal(req->out_map_entries[j].sync_id,
+			CAM_SYNC_STATE_SIGNALED_SUCCESS);
+		req->num_out_acked++;
+		trace_printk("Sync success req %lld, reset sync id 0x%x\n",
+			req->request_id,
+			req->out_map_entries[j].sync_id);
+
+		req->out_map_entries[j].sync_id = -1;
+	}
+
+	if (req->num_out_acked == req->num_out_map_entries) {
+		list_del_init(&req->list);
+		list_add_tail(&req->list, &ctx->free_req_list);
+	}
+
+end:
+	return rc;
+}
+
+int cam_context_apply_req_to_hw(struct cam_context *ctx,
+	struct cam_req_mgr_apply_request *apply)
+{
+	int rc = 0;
+	struct cam_ctx_request *req;
+	struct cam_hw_config_args cfg;
+
+	if (!ctx->hw_mgr_intf) {
+		pr_err("HW interface is not ready\n");
+		rc = -EFAULT;
+		goto end;
+	}
+
+	if (list_empty(&ctx->pending_req_list)) {
+		pr_err("No available request for Apply id %lld\n",
+			apply->request_id);
+		rc = -EFAULT;
+		goto end;
+	}
+
+	spin_lock(&ctx->lock);
+	req = list_first_entry(&ctx->pending_req_list,
+		struct cam_ctx_request, list);
+	list_del_init(&req->list);
+	spin_unlock(&ctx->lock);
+
+	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;
+	cfg.out_map_entries = req->out_map_entries;
+	cfg.num_out_map_entries = req->num_out_map_entries;
+	cfg.priv = (void *)&req->request_id;
+	list_add_tail(&req->list, &ctx->active_req_list);
+
+	rc = ctx->hw_mgr_intf->hw_config(ctx->hw_mgr_intf->hw_mgr_priv, &cfg);
+	if (rc)
+		list_del_init(&req->list);
+
+end:
+	return rc;
+}
+
+int32_t cam_context_release_dev_to_hw(struct cam_context *ctx,
+	struct cam_release_dev_cmd *cmd)
+{
+	int rc = 0;
+	int i;
+	struct cam_hw_release_args arg;
+	struct cam_ctx_request *req;
+
+	if (!ctx->hw_mgr_intf) {
+		pr_err("HW interface is not ready\n");
+		rc = -EFAULT;
+		goto end;
+	}
+
+	if (ctx->ctxt_to_hw_map) {
+		arg.ctxt_to_hw_map = ctx->ctxt_to_hw_map;
+		ctx->hw_mgr_intf->hw_release(ctx->hw_mgr_intf->hw_mgr_priv,
+			&arg);
+		ctx->ctxt_to_hw_map = NULL;
+	}
+
+	ctx->session_hdl = 0;
+	ctx->dev_hdl = 0;
+	ctx->link_hdl = 0;
+
+	while (!list_empty(&ctx->active_req_list)) {
+		req = list_first_entry(&ctx->active_req_list,
+			struct cam_ctx_request, list);
+		list_del_init(&req->list);
+		pr_warn("signal fence in active list. fence num %d\n",
+			req->num_out_map_entries);
+		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,
+					CAM_SYNC_STATE_SIGNALED_ERROR);
+		}
+		list_add_tail(&req->list, &ctx->free_req_list);
+	}
+
+	/* flush the pending queue */
+	while (!list_empty(&ctx->pending_req_list)) {
+		req = list_first_entry(&ctx->pending_req_list,
+			struct cam_ctx_request, list);
+		list_del_init(&req->list);
+		pr_debug("signal fence in pending list. fence num %d\n",
+			req->num_out_map_entries);
+		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,
+					CAM_SYNC_STATE_SIGNALED_ERROR);
+		list_add_tail(&req->list, &ctx->free_req_list);
+	}
+
+end:
+	return rc;
+}
+
+void cam_context_sync_callback(int32_t sync_obj, int status, void *data)
+{
+	struct cam_context *ctx = data;
+	struct cam_ctx_request *req = NULL;
+	struct cam_req_mgr_apply_request apply;
+
+	spin_lock(&ctx->lock);
+	if (!list_empty(&ctx->pending_req_list))
+		req = list_first_entry(&ctx->pending_req_list,
+			struct cam_ctx_request, list);
+	spin_unlock(&ctx->lock);
+
+	if (!req) {
+		pr_err("No more request obj free\n");
+		return;
+	}
+
+	req->num_in_acked++;
+	if (req->num_in_acked == req->num_in_map_entries) {
+		apply.request_id = req->request_id;
+		trace_printk("async cb for request :%llu",
+			req->request_id);
+		cam_context_apply_req_to_hw(ctx, &apply);
+	}
+}
+
+int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx,
+	struct cam_config_dev_cmd *cmd)
+{
+	int rc = 0;
+	struct cam_ctx_request *req = NULL;
+	struct cam_hw_prepare_update_args cfg;
+	uint64_t packet_addr;
+	struct cam_packet *packet;
+	size_t len = 0;
+	int32_t i = 0;
+
+	if (!ctx->hw_mgr_intf) {
+		pr_err("HW interface is not ready\n");
+		rc = -EFAULT;
+		goto end;
+	}
+
+	spin_lock(&ctx->lock);
+	if (!list_empty(&ctx->free_req_list)) {
+		req = list_first_entry(&ctx->free_req_list,
+			struct cam_ctx_request, list);
+		list_del_init(&req->list);
+	}
+	spin_unlock(&ctx->lock);
+
+	if (!req) {
+		pr_err("No more request obj free\n");
+		rc = -ENOMEM;
+		goto end;
+	}
+
+	memset(req, 0, sizeof(*req));
+	INIT_LIST_HEAD(&req->list);
+
+	/* for config dev, only memory handle is supported */
+	/* map packet from the memhandle */
+	rc = cam_mem_get_cpu_buf((int32_t) cmd->packet_handle,
+		(uint64_t *) &packet_addr,
+		&len);
+	if (rc != 0) {
+		pr_err("Can not get packet address\n");
+		rc = -EINVAL;
+		goto free_req;
+	}
+
+	packet = (struct cam_packet *) (packet_addr + cmd->offset);
+	pr_debug("pack_handle %llx\n", cmd->packet_handle);
+	pr_debug("packet address is 0x%llx\n", packet_addr);
+	pr_debug("packet with length %zu, offset 0x%llx\n",
+		len, cmd->offset);
+	pr_debug("Packet request id 0x%llx\n",
+		packet->header.request_id);
+	pr_debug("Packet size 0x%x\n", packet->header.size);
+	pr_debug("packet op %d\n", packet->header.op_code);
+
+	/* preprocess the configuration */
+	memset(&cfg, 0, sizeof(cfg));
+	cfg.packet = packet;
+	cfg.ctxt_to_hw_map = ctx->ctxt_to_hw_map;
+	cfg.max_hw_update_entries = CAM_CTX_CFG_MAX;
+	cfg.num_hw_update_entries = req->num_hw_update_entries;
+	cfg.hw_update_entries = req->hw_update_entries;
+	cfg.max_out_map_entries = CAM_CTX_CFG_MAX;
+	cfg.out_map_entries = req->out_map_entries;
+	cfg.max_in_map_entries = CAM_CTX_CFG_MAX;
+	cfg.in_map_entries = req->in_map_entries;
+
+	rc = ctx->hw_mgr_intf->hw_prepare_update(
+		ctx->hw_mgr_intf->hw_mgr_priv, &cfg);
+	if (rc != 0) {
+		pr_err("Prepare config packet failed in HW layer\n");
+		rc = -EFAULT;
+		goto free_req;
+	}
+	req->num_hw_update_entries = cfg.num_hw_update_entries;
+	req->num_out_map_entries = cfg.num_out_map_entries;
+	req->num_in_map_entries = cfg.num_in_map_entries;
+	req->request_id = packet->header.request_id;
+	req->status = 1;
+	req->req_priv = cfg.priv;
+
+	if (req->num_in_map_entries > 0) {
+		spin_lock(&ctx->lock);
+		list_add_tail(&req->list, &ctx->pending_req_list);
+		spin_unlock(&ctx->lock);
+		for (i = 0; i < req->num_in_map_entries; i++) {
+			trace_printk("register in fence callback: %d\n",
+				req->in_map_entries[i].sync_id);
+			rc = cam_sync_register_callback(
+					cam_context_sync_callback,
+					(void *)ctx,
+					req->in_map_entries[i].sync_id);
+			pr_debug("register in fence callback: %d ret = %d\n",
+				req->in_map_entries[i].sync_id, rc);
+		}
+		goto end;
+	}
+
+	return rc;
+
+free_req:
+	spin_lock(&ctx->lock);
+	list_add_tail(&req->list, &ctx->free_req_list);
+	spin_unlock(&ctx->lock);
+end:
+	pr_debug("Config dev successful\n");
+	return rc;
+}
+
+int32_t cam_context_acquire_dev_to_hw(struct cam_context *ctx,
+	struct cam_acquire_dev_cmd *cmd)
+{
+	int rc;
+	struct cam_hw_acquire_args param;
+	struct cam_create_dev_hdl req_hdl_param;
+	struct cam_hw_release_args release;
+
+	if (!ctx->hw_mgr_intf) {
+		pr_err("HW interface is not ready\n");
+		rc = -EFAULT;
+		goto end;
+	}
+
+	pr_debug("acquire cmd: session_hdl 0x%x, num_resources %d\n",
+		cmd->session_handle, cmd->num_resources);
+	pr_debug(" handle type %d, res %lld\n", cmd->handle_type,
+		cmd->resource_hdl);
+
+	if (cmd->num_resources > CAM_CTX_RES_MAX) {
+		pr_err("Too much resources in the acquire\n");
+		rc = -ENOMEM;
+		goto end;
+	}
+
+	/* for now we only support user pointer */
+	if (cmd->handle_type != 1)  {
+		pr_err("Only user pointer is supported");
+		rc = -EINVAL;
+		goto end;
+	}
+
+	/* fill in parameters */
+	param.context_data = ctx;
+	param.event_cb = ctx->irq_cb_intf;
+	param.num_acq = cmd->num_resources;
+	param.acquire_info = cmd->resource_hdl;
+
+	pr_debug("ctx %pK: acquire hw resource: hw_intf: 0x%pK, priv 0x%pK",
+		ctx, ctx->hw_mgr_intf, ctx->hw_mgr_intf->hw_mgr_priv);
+	pr_debug("acquire_hw_func 0x%pK\n", ctx->hw_mgr_intf->hw_acquire);
+
+	/* call HW manager to reserve the resource */
+	rc = ctx->hw_mgr_intf->hw_acquire(ctx->hw_mgr_intf->hw_mgr_priv,
+		&param);
+	if (rc != 0) {
+		pr_err("Acquire device failed\n");
+		goto end;
+	}
+
+	ctx->ctxt_to_hw_map = param.ctxt_to_hw_map;
+
+	/* if hw resource acquire successful, acquire dev handle */
+	req_hdl_param.session_hdl = cmd->session_handle;
+	/* bridge is not ready for these flags. so false for now */
+	req_hdl_param.v4l2_sub_dev_flag = 0;
+	req_hdl_param.media_entity_flag = 0;
+	req_hdl_param.priv = ctx;
+
+	pr_debug("get device handle from bridge\n");
+	ctx->dev_hdl = cam_create_device_hdl(&req_hdl_param);
+	if (ctx->dev_hdl <= 0) {
+		rc = -EFAULT;
+		pr_err("Can not create device handle\n");
+		goto free_hw;
+	}
+	cmd->dev_handle = ctx->dev_hdl;
+
+	/* store session information */
+	ctx->session_hdl = cmd->session_handle;
+
+	pr_err("dev_handle = %x\n", cmd->dev_handle);
+	return rc;
+
+free_hw:
+	release.ctxt_to_hw_map = ctx->ctxt_to_hw_map;
+	ctx->hw_mgr_intf->hw_release(ctx->hw_mgr_intf->hw_mgr_priv, &release);
+	ctx->ctxt_to_hw_map = NULL;
+end:
+	return rc;
+}
+
+int32_t cam_context_start_dev_to_hw(struct cam_context *ctx,
+	struct cam_start_stop_dev_cmd *cmd)
+{
+	int rc = 0;
+	struct cam_hw_start_args arg;
+
+	if (!ctx->hw_mgr_intf) {
+		pr_err("HW interface is not ready\n");
+		rc = -EFAULT;
+		goto end;
+	}
+
+	if ((cmd->session_handle != ctx->session_hdl) ||
+		(cmd->dev_handle != ctx->dev_hdl)) {
+		pr_err("Invalid session hdl[%d], dev_handle[%d]\n",
+			cmd->session_handle, cmd->dev_handle);
+		rc = -EPERM;
+		goto end;
+	}
+
+	if (ctx->hw_mgr_intf->hw_start) {
+		rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv,
+				&arg);
+		if (rc) {
+			/* HW failure. user need to clean up the resource */
+			pr_err("Start HW failed\n");
+			goto end;
+		}
+	}
+
+	pr_debug("start device success\n");
+end:
+	return rc;
+}
+
+int32_t cam_context_stop_dev_to_hw(struct cam_context *ctx)
+{
+	int rc = 0;
+	uint32_t i;
+	struct cam_hw_stop_args stop;
+	struct cam_ctx_request *req;
+
+	if (!ctx->hw_mgr_intf) {
+		pr_err("HW interface is not ready\n");
+		rc = -EFAULT;
+		goto end;
+	}
+
+	/* stop hw first */
+	if (ctx->ctxt_to_hw_map) {
+		stop.ctxt_to_hw_map = ctx->ctxt_to_hw_map;
+		if (ctx->hw_mgr_intf->hw_stop)
+			ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv,
+				&stop);
+	}
+
+	/* flush pending and active queue */
+	while (!list_empty(&ctx->pending_req_list)) {
+		req = list_first_entry(&ctx->pending_req_list,
+				struct cam_ctx_request, list);
+		list_del_init(&req->list);
+		pr_debug("signal fence in pending list. fence num %d\n",
+			req->num_out_map_entries);
+		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,
+					CAM_SYNC_STATE_SIGNALED_ERROR);
+		list_add_tail(&req->list, &ctx->free_req_list);
+	}
+
+	while (!list_empty(&ctx->active_req_list)) {
+		req = list_first_entry(&ctx->active_req_list,
+				struct cam_ctx_request, list);
+		list_del_init(&req->list);
+		pr_debug("signal fence in active list. fence num %d\n",
+			req->num_out_map_entries);
+		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,
+					CAM_SYNC_STATE_SIGNALED_ERROR);
+		list_add_tail(&req->list, &ctx->free_req_list);
+	}
+
+end:
+	return rc;
+}
+
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.h b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.h
new file mode 100644
index 0000000..f7982eb
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.h
@@ -0,0 +1,32 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_CONTEXT_UTILS_H_
+#define _CAM_CONTEXT_UTILS_H_
+
+#include <linux/types.h>
+
+int cam_context_buf_done_from_hw(struct cam_context *ctx,
+	void *done_event_data, uint32_t bubble_state);
+int cam_context_apply_req_to_hw(struct cam_context *ctx,
+	struct cam_req_mgr_apply_request *apply);
+int32_t cam_context_release_dev_to_hw(struct cam_context *ctx,
+	struct cam_release_dev_cmd *cmd);
+int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx,
+	struct cam_config_dev_cmd *cmd);
+int32_t cam_context_acquire_dev_to_hw(struct cam_context *ctx,
+	struct cam_acquire_dev_cmd *cmd);
+int32_t cam_context_start_dev_to_hw(struct cam_context *ctx,
+	struct cam_start_stop_dev_cmd *cmd);
+int32_t cam_context_stop_dev_to_hw(struct cam_context *ctx);
+
+#endif /* _CAM_CONTEXT_UTILS_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_core_defs.h b/drivers/media/platform/msm/camera/cam_core/cam_core_defs.h
new file mode 100644
index 0000000..3498836
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_core/cam_core_defs.h
@@ -0,0 +1,44 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _CAM_REQ_MGR_CORE_DEFS_H_
+#define _CAM_REQ_MGR_CORE_DEFS_H_
+
+#define CAM_CORE_TRACE_ENABLE 0
+
+#if (CAM_CORE_TRACE_ENABLE == 1)
+	#define CAM_CORE_DBG(fmt, args...) do { \
+	trace_printk("%d: [cam_core_dbg] "fmt"\n", __LINE__, ##args); \
+	pr_debug("%s:%d "fmt"\n", __func__, __LINE__, ##args); \
+	} while (0)
+
+	#define CAM_CORE_WARN(fmt, args...) do { \
+	trace_printk("%d: [cam_core_warn] "fmt"\n", __LINE__, ##args); \
+	pr_warn("%s:%d "fmt"\n", __func__, __LINE__, ##args); \
+	} while (0)
+
+	#define CAM_CORE_ERR(fmt, args...) do { \
+	trace_printk("%d: [cam_core_err] "fmt"\n", __LINE__, ##args); \
+	pr_err("%s:%d "fmt"\n", __func__, __LINE__, ##args);\
+	} while (0)
+#else
+	#define CAM_CORE_DBG(fmt, args...) pr_debug("%s:%d "fmt"\n", \
+	__func__, __LINE__, ##args)
+
+	#define CAM_CORE_WARN(fmt, args...) pr_warn("%s:%d "fmt"\n", \
+	__func__, __LINE__, ##args)
+
+	#define CAM_CORE_ERR(fmt, args...) pr_err("%s:%d "fmt"\n", \
+	__func__, __LINE__, ##args)
+#endif
+
+#endif /* _CAM_REQ_MGR_CORE_DEFS_H_ */
+
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h b/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h
index db605e7..f72a1d7 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
@@ -36,6 +36,7 @@
  * @offset:                Memory offset
  * @len:                   Size of the configuration
  * @flags:                 Flags for the config entry(eg. DMI)
+ * @addr:                  Address of hardware update entry
  *
  */
 struct cam_hw_update_entry {
@@ -43,6 +44,7 @@
 	uint32_t           offset;
 	uint32_t           len;
 	uint32_t           flags;
+	uint64_t           addr;
 };
 
 /**
@@ -137,6 +139,7 @@
  * @max_in_map_entries:    Maximum input fence mapping supported
  * @in_map_entries:        Actual input fence mapping list (returned)
  * @num_in_map_entries:    Number of acutal input fence mapping (returned)
+ * @priv:                  Private pointer of hw update
  *
  */
 struct cam_hw_prepare_update_args {
@@ -151,6 +154,7 @@
 	uint32_t                        max_in_map_entries;
 	struct cam_hw_fence_map_entry  *in_map_entries;
 	uint32_t                        num_in_map_entries;
+	void                           *priv;
 };
 
 /**
@@ -159,12 +163,18 @@
  * @ctxt_to_hw_map:        HW context from the acquire
  * @num_hw_update_entries: Number of hardware update entries
  * @hw_update_entries:     Hardware update list
+ * @out_map_entries:       Out map info
+ * @num_out_map_entries:   Number of out map entries
+ * @priv:                  Private pointer
  *
  */
 struct cam_hw_config_args {
-	void                        *ctxt_to_hw_map;
-	uint32_t                     num_hw_update_entries;
-	struct cam_hw_update_entry  *hw_update_entries;
+	void                           *ctxt_to_hw_map;
+	uint32_t                        num_hw_update_entries;
+	struct cam_hw_update_entry     *hw_update_entries;
+	struct cam_hw_fence_map_entry  *out_map_entries;
+	uint32_t                        num_out_map_entries;
+	void                           *priv;
 };
 
 /**
@@ -189,6 +199,8 @@
  * @hw_write:              Function pointer for Write hardware registers
  * @hw_cmd:                Function pointer for any customized commands for the
  *                         hardware manager
+ * @download_fw:           Function pointer for firmware downloading
+ * @hw_close:              Function pointer for subdev close
  *
  */
 struct cam_hw_mgr_intf {
@@ -204,6 +216,8 @@
 	int (*hw_read)(void *hw_priv, void *read_args);
 	int (*hw_write)(void *hw_priv, void *write_args);
 	int (*hw_cmd)(void *hw_priv, void *write_args);
+	int (*download_fw)(void *hw_priv, void *fw_download_args);
+	int (*hw_close)(void *hw_priv, void *hw_close_args);
 };
 
 #endif /* _CAM_HW_MGR_INTF_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_node.c b/drivers/media/platform/msm/camera/cam_core/cam_node.c
index ef60822..17f6973 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_node.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_node.c
@@ -21,13 +21,16 @@
 {
 	int rc = -EFAULT;
 
-	if (!query)
+	if (!query) {
+		pr_err("%s: Invalid params\n", __func__);
 		return -EINVAL;
+	}
 
 	if (node->hw_mgr_intf.hw_get_caps) {
 		rc = node->hw_mgr_intf.hw_get_caps(
 			node->hw_mgr_intf.hw_mgr_priv, query);
 	}
+
 	return rc;
 }
 
@@ -47,7 +50,6 @@
 		list_del_init(&ctx->list);
 	}
 	mutex_unlock(&node->list_mutex);
-
 	if (!ctx) {
 		rc = -ENOMEM;
 		goto err;
@@ -254,8 +256,8 @@
 		memset(node, 0, sizeof(*node));
 
 	pr_debug("%s: deinit complete!\n", __func__);
-	return 0;
 
+	return 0;
 }
 
 int cam_node_init(struct cam_node *node, struct cam_hw_mgr_intf *hw_mgr_intf,
@@ -274,7 +276,6 @@
 	strlcpy(node->name, name, sizeof(node->name));
 
 	memcpy(&node->hw_mgr_intf, hw_mgr_intf, sizeof(node->hw_mgr_intf));
-
 	node->crm_node_intf.apply_req = __cam_node_apply_req;
 	node->crm_node_intf.get_dev_info = __cam_node_get_dev_info;
 	node->crm_node_intf.link_setup = __cam_node_link_setup;
@@ -318,15 +319,18 @@
 			rc = -EFAULT;
 			break;
 		}
+
 		rc = __cam_node_handle_query_cap(node, &query);
 		if (rc) {
 			pr_err("%s: querycap is failed(rc = %d)\n",
 				__func__,  rc);
 			break;
 		}
+
 		if (copy_to_user((void __user *)cmd->handle, &query,
 			sizeof(query)))
 			rc = -EFAULT;
+
 		break;
 	}
 	case CAM_ACQUIRE_DEV: {
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_subdev.c b/drivers/media/platform/msm/camera/cam_core/cam_subdev.c
index 429474b..a89981d 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_subdev.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_subdev.c
@@ -148,6 +148,7 @@
 	sd->sd_flags =
 		V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
 	sd->ent_function = dev_type;
+
 	rc = cam_register_subdev(sd);
 	if (rc) {
 		pr_err("%s: cam_register_subdev() failed for dev: %s!\n",
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 c304eed..16bf555 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
@@ -652,7 +652,7 @@
 	ctx->session_hdl = 0;
 	ctx->dev_hdl = 0;
 	ctx->link_hdl = 0;
-	ctx->crm_ctx_intf = NULL;
+	ctx->ctx_crm_intf = NULL;
 	ctx_isp->frame_id = 0;
 
 	/*
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 9c61649..6819fd8 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
@@ -2220,7 +2220,7 @@
 		cam_ife_hw_mgr_do_error_recovery(&recovery_data);
 		break;
 	default:
-		CDBG("%s: None error. Error type (%d)", __func__,
+		CDBG("%s: None error. Error type (%d)\n", __func__,
 			evt_payload->error_type);
 	}
 
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 21494b5..8dbefd8 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
@@ -983,13 +983,10 @@
 		in_rsrc_data->comp_grp_type <= CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5)
 		list_add_tail(&comp_grp->list,
 			&ver2_bus_priv->free_dual_comp_grp);
-	else if (in_rsrc_data->comp_grp_type >= CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0
-		&& in_rsrc_data->comp_grp_type <=
-		CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5)
+	else if (in_rsrc_data->comp_grp_type >= CAM_VFE_BUS_VER2_COMP_GRP_0
+		&& in_rsrc_data->comp_grp_type <= CAM_VFE_BUS_VER2_COMP_GRP_5)
 		list_add_tail(&comp_grp->list, &ver2_bus_priv->free_comp_grp);
 
-	list_add_tail(&comp_grp->list,
-		&ver2_bus_priv->free_comp_grp);
 	in_rsrc_data->unique_id = 0;
 	in_rsrc_data->comp_grp_local_idx = 0;
 	in_rsrc_data->composite_mask = 0;
@@ -997,7 +994,7 @@
 
 	comp_grp->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE;
 
-	return -ENODEV;
+	return 0;
 }
 
 static int cam_vfe_bus_start_comp_grp(struct cam_isp_resource_node *comp_grp)
@@ -1333,11 +1330,26 @@
 static int cam_vfe_bus_release_vfe_out(void *bus_priv,
 	struct cam_isp_resource_node        *vfe_out)
 {
+	uint32_t i;
+	struct cam_vfe_bus_ver2_vfe_out_data  *rsrc_data = vfe_out->res_priv;
+
 	if (vfe_out->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) {
 		pr_err("Error! Invalid resource state:%d\n",
 			vfe_out->res_state);
 	}
 
+	for (i = 0; i < rsrc_data->num_wm; i++)
+		cam_vfe_bus_release_wm(bus_priv, rsrc_data->wm_res[i]);
+	rsrc_data->num_wm = 0;
+
+	if (rsrc_data->comp_grp)
+		cam_vfe_bus_release_comp_grp(bus_priv, rsrc_data->comp_grp);
+	rsrc_data->comp_grp = NULL;
+
+	vfe_out->tasklet_info = NULL;
+	vfe_out->cdm_ops = NULL;
+	rsrc_data->cdm_util_ops = NULL;
+
 	if (vfe_out->res_state == CAM_ISP_RESOURCE_STATE_RESERVED)
 		vfe_out->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE;
 
@@ -1360,7 +1372,7 @@
 	}
 
 	/* Enable IRQ Mask */
-	cam_io_w_mb(0x00001F70, common_data->mem_base + 0x2044);
+	cam_io_w_mb(0x00001FE0, common_data->mem_base + 0x2044);
 	cam_io_w_mb(0x000FFFE7, common_data->mem_base + 0x2048);
 	cam_io_w_mb(0x000000FF, common_data->mem_base + 0x204c);
 
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 019a775..7bc26ec 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
@@ -196,6 +196,7 @@
 	hdl_tbl->hdl[idx].ops = hdl_data->ops;
 	spin_unlock_bh(&hdl_tbl_lock);
 
+	pr_debug("%s: handle = %x\n", __func__, handle);
 	return handle;
 }
 
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/Makefile b/drivers/media/platform/msm/camera/cam_sensor_module/Makefile
new file mode 100644
index 0000000..e515a40
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_utils/
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_cci/
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_io/
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_csiphy/
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_actuator/
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor/
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/Makefile b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/Makefile
new file mode 100644
index 0000000..8670d80
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/Makefile
@@ -0,0 +1,8 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_cci
+
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_actuator_dev.o cam_actuator_core.o cam_actuator_soc.o
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c
new file mode 100644
index 0000000..648617e
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c
@@ -0,0 +1,628 @@
+/* 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/module.h>
+#include <cam_sensor_cmn_header.h>
+#include "cam_actuator_core.h"
+#include <cam_sensor_util.h>
+
+int32_t cam_actuator_slaveInfo_pkt_parser(struct cam_actuator_ctrl_t *a_ctrl,
+	uint32_t *cmd_buf)
+{
+	int32_t rc = 0;
+	struct cam_cmd_i2c_info *i2c_info;
+
+	if (!a_ctrl || !cmd_buf) {
+		pr_err("%s:%d Invalid Args\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	i2c_info = (struct cam_cmd_i2c_info *)cmd_buf;
+	a_ctrl->io_master_info.cci_client->i2c_freq_mode =
+		i2c_info->i2c_freq_mode;
+	a_ctrl->io_master_info.cci_client->sid =
+		i2c_info->slave_addr >> 1;
+	CDBG("%s:%d Slave addr: 0x%x Freq Mode: %d\n", __func__,
+		__LINE__, i2c_info->slave_addr, i2c_info->i2c_freq_mode);
+
+	return rc;
+}
+
+int32_t cam_actuator_apply_settings(struct cam_actuator_ctrl_t *a_ctrl,
+	struct i2c_settings_array *i2c_set)
+{
+	struct i2c_settings_list *i2c_list;
+	int32_t rc = 0;
+	uint32_t i, size;
+
+	if (a_ctrl == NULL || i2c_set == NULL) {
+		pr_err("%s:%d Invalid Args\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	if (i2c_set->is_settings_valid != 1) {
+		pr_err("%s: %d :Error: Invalid settings\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	list_for_each_entry(i2c_list,
+		&(i2c_set->list_head), list) {
+		if (i2c_list->op_code ==  CAM_SENSOR_I2C_WRITE_RANDOM) {
+			rc = camera_io_dev_write(&(a_ctrl->io_master_info),
+				&(i2c_list->i2c_settings));
+			if (rc < 0) {
+				pr_err("%s: %d :Error: Failed in Applying i2c write settings\n",
+					__func__, __LINE__);
+				return rc;
+			}
+		} else if (i2c_list->op_code == CAM_SENSOR_I2C_POLL) {
+			size = i2c_list->i2c_settings.size;
+			for (i = 0; i < size; i++) {
+				rc = camera_io_dev_poll(
+					&(a_ctrl->io_master_info),
+					i2c_list->i2c_settings.
+						reg_setting[i].reg_addr,
+					i2c_list->i2c_settings.
+						reg_setting[i].reg_data,
+					i2c_list->i2c_settings.
+						reg_setting[i].data_mask,
+					i2c_list->i2c_settings.addr_type,
+					i2c_list->i2c_settings.data_type,
+					i2c_list->i2c_settings.
+						reg_setting[i].delay);
+				if (rc < 0) {
+					pr_err("%s: %d :Error: Failed in Applying i2c poll settings\n",
+						__func__, __LINE__);
+					return rc;
+				}
+			}
+		}
+	}
+
+	return rc;
+}
+
+int32_t cam_actuator_apply_request(struct cam_req_mgr_apply_request *apply)
+{
+	int32_t rc = 0, request_id, del_req_id;
+	struct cam_actuator_ctrl_t *a_ctrl = NULL;
+
+	if (!apply) {
+		pr_err("%s:%d :Error: Invalid Input Args\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	a_ctrl = (struct cam_actuator_ctrl_t *)
+		cam_get_device_priv(apply->dev_hdl);
+	if (!a_ctrl) {
+		pr_err("%s: %d :Error: Device data is NULL\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+	request_id = apply->request_id % MAX_PER_FRAME_ARRAY;
+	CDBG("%s:%d Request Id: %lld\n",
+		__func__, __LINE__, apply->request_id);
+
+	if ((apply->request_id ==
+		a_ctrl->i2c_data.per_frame[request_id].request_id) &&
+		(a_ctrl->i2c_data.per_frame[request_id].is_settings_valid)
+		== 1) {
+		rc = cam_actuator_apply_settings(a_ctrl,
+			&a_ctrl->i2c_data.per_frame[request_id]);
+		if (rc < 0) {
+			pr_err("%s:%d Failed in applying the request: %lld\n",
+				__func__, __LINE__, apply->request_id);
+			return rc;
+		}
+	}
+	del_req_id = (request_id +
+		MAX_PER_FRAME_ARRAY - MAX_SYSTEM_PIPELINE_DELAY) %
+		MAX_PER_FRAME_ARRAY;
+
+	if (apply->request_id >
+		a_ctrl->i2c_data.per_frame[del_req_id].request_id) {
+		a_ctrl->i2c_data.per_frame[del_req_id].request_id = 0;
+		rc = delete_request(&a_ctrl->i2c_data.per_frame[del_req_id]);
+		if (rc < 0) {
+			pr_err("%s: %d :Error: Fail deleting the req: %d err: %d\n",
+				__func__, __LINE__, del_req_id, rc);
+			return rc;
+		}
+	} else {
+		CDBG("%s:%d No Valid Req to clean Up\n", __func__, __LINE__);
+	}
+
+	return rc;
+}
+
+int32_t cam_actuator_establish_link(
+	struct cam_req_mgr_core_dev_link_setup *link)
+{
+	struct cam_actuator_ctrl_t *a_ctrl = NULL;
+
+	if (!link) {
+		pr_err("%s:%d Invalid Args\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	a_ctrl = (struct cam_actuator_ctrl_t *)
+		cam_get_device_priv(link->dev_hdl);
+	if (!a_ctrl) {
+		pr_err("%s:%d :Error: Device data is NULL\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+	if (link->link_enable) {
+		a_ctrl->bridge_intf.link_hdl = link->link_hdl;
+		a_ctrl->bridge_intf.crm_cb = link->crm_cb;
+	} else {
+		a_ctrl->bridge_intf.link_hdl = -1;
+		a_ctrl->bridge_intf.crm_cb = NULL;
+	}
+
+	return 0;
+}
+
+int32_t cam_actuator_publish_dev_info(struct cam_req_mgr_device_info *info)
+{
+	if (!info) {
+		pr_err("%s:%d Invalid Args\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	info->dev_id = CAM_REQ_MGR_DEVICE_ACTUATOR;
+	strlcpy(info->name, CAM_ACTUATOR_NAME, sizeof(info->name));
+	info->p_delay = 0;
+
+	return 0;
+}
+
+int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl,
+	void *arg)
+{
+	int32_t rc = 0;
+	uint64_t generic_ptr;
+	struct cam_control *ioctl_ctrl = NULL;
+	struct cam_packet *csl_packet = NULL;
+	struct cam_config_dev_cmd config;
+	struct i2c_data_settings *i2c_data = NULL;
+	struct i2c_settings_array *i2c_reg_settings = NULL;
+	struct cam_cmd_buf_desc *cmd_desc = NULL;
+	size_t len_of_buff = 0;
+	uint32_t *offset = NULL, *cmd_buf;
+	struct cam_req_mgr_add_request add_req;
+
+	if (!a_ctrl || !arg) {
+		pr_err("%s:%d :Error: Invalid Args\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	ioctl_ctrl = (struct cam_control *)arg;
+	if (copy_from_user(&config, (void __user *) ioctl_ctrl->handle,
+		sizeof(config)))
+		return -EFAULT;
+	rc = cam_mem_get_cpu_buf(config.packet_handle,
+		(uint64_t *)&generic_ptr, &len_of_buff);
+	if (rc < 0) {
+		pr_err("%s:%d :Error: error in converting command Handle %d\n",
+			__func__, __LINE__, rc);
+		return rc;
+	}
+
+	if (config.offset > len_of_buff) {
+		pr_err("%s: %d offset is out of bounds: offset: %lld len: %zu\n",
+			__func__, __LINE__, config.offset, len_of_buff);
+		return -EINVAL;
+	}
+
+	csl_packet = (struct cam_packet *)(generic_ptr +
+		config.offset);
+	CDBG("%s:%d Pkt opcode: %d\n",
+		__func__, __LINE__, csl_packet->header.op_code);
+
+	if ((csl_packet->header.op_code & 0xFFFFFF) ==
+			CAM_ACTUATOR_PACKET_OPCODE_INIT) {
+		i2c_data = &(a_ctrl->i2c_data);
+		i2c_reg_settings = &i2c_data->init_settings;
+
+		offset = (uint32_t *)&csl_packet->payload;
+		offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t));
+		cmd_desc = (struct cam_cmd_buf_desc *)(offset);
+
+		if (csl_packet->num_cmd_buf != 2) {
+			pr_err("%s:: %d :Error: cmd Buffers in Init : %d\n",
+				__func__, __LINE__, csl_packet->num_cmd_buf);
+			return -EINVAL;
+		}
+
+		rc = cam_mem_get_cpu_buf(cmd_desc[0].mem_handle,
+			(uint64_t *)&generic_ptr, &len_of_buff);
+		if (rc < 0) {
+			pr_err("%s:%d Failed to get cpu buf\n",
+				__func__, __LINE__);
+			return rc;
+		}
+		cmd_buf = (uint32_t *)generic_ptr;
+		cmd_buf += cmd_desc->offset / sizeof(uint32_t);
+		rc = cam_actuator_slaveInfo_pkt_parser(a_ctrl, cmd_buf);
+		if (rc < 0) {
+			pr_err("%s:%d Failed in parsing the pkt\n",
+				__func__, __LINE__);
+			return rc;
+		}
+		cmd_buf += (sizeof(struct cam_cmd_i2c_info)/sizeof(uint32_t));
+		i2c_data->init_settings.request_id = 0;
+		i2c_reg_settings->is_settings_valid = 1;
+		rc = cam_sensor_i2c_pkt_parser(i2c_reg_settings,
+			&cmd_desc[1], 1);
+		if (rc < 0) {
+			pr_err("%s:%d :Error: actuator pkt parsing failed: %d\n",
+				__func__, __LINE__, rc);
+			return rc;
+		}
+	} else if ((csl_packet->header.op_code & 0xFFFFFF) ==
+		CAM_ACTUATOR_PACKET_AUTO_MOVE_LENS) {
+		a_ctrl->act_apply_state =
+			ACT_APPLY_SETTINGS_NOW;
+
+		i2c_data = &(a_ctrl->i2c_data);
+		i2c_reg_settings = &i2c_data->init_settings;
+
+		i2c_data->init_settings.request_id =
+			csl_packet->header.request_id;
+		i2c_reg_settings->is_settings_valid = 1;
+		offset = (uint32_t *)&csl_packet->payload;
+		offset += csl_packet->cmd_buf_offset / sizeof(uint32_t);
+		cmd_desc = (struct cam_cmd_buf_desc *)(offset);
+		rc = cam_sensor_i2c_pkt_parser(i2c_reg_settings,
+			cmd_desc, 1);
+		if (rc < 0) {
+			pr_err("%s:%d :Error: actuator pkt parsing failed: %d\n",
+				__func__, __LINE__, rc);
+			return rc;
+		}
+	} else if ((csl_packet->header.op_code & 0xFFFFFF) ==
+		CAM_ACTUATOR_PACKET_MANUAL_MOVE_LENS) {
+		i2c_data = &(a_ctrl->i2c_data);
+		i2c_reg_settings =
+			&i2c_data->per_frame
+			[csl_packet->header.request_id % MAX_PER_FRAME_ARRAY];
+
+		i2c_data->init_settings.request_id =
+			csl_packet->header.request_id;
+		i2c_reg_settings->is_settings_valid = 1;
+		offset = (uint32_t *)&csl_packet->payload;
+		offset += csl_packet->cmd_buf_offset / sizeof(uint32_t);
+		cmd_desc = (struct cam_cmd_buf_desc *)(offset);
+		rc = cam_sensor_i2c_pkt_parser(i2c_reg_settings,
+			cmd_desc, 1);
+		if (rc < 0) {
+			pr_err("%s:%d :Error: actuator pkt parsing failed: %d\n",
+				__func__, __LINE__, rc);
+			return rc;
+		}
+	}
+
+	if ((csl_packet->header.op_code & 0xFFFFFF) !=
+		CAM_ACTUATOR_PACKET_OPCODE_INIT) {
+		add_req.link_hdl = a_ctrl->bridge_intf.link_hdl;
+		add_req.req_id = csl_packet->header.request_id;
+		add_req.dev_hdl = a_ctrl->bridge_intf.device_hdl;
+		if (a_ctrl->bridge_intf.crm_cb &&
+			a_ctrl->bridge_intf.crm_cb->add_req)
+			a_ctrl->bridge_intf.crm_cb->add_req(&add_req);
+		CDBG("%s: %d Req Id: %lld added to Bridge\n",
+			__func__, __LINE__, add_req.req_id);
+	}
+
+	return rc;
+}
+
+static int32_t cam_actuator_vreg_control(struct cam_actuator_ctrl_t *a_ctrl,
+	int config)
+{
+	int rc = 0, i, cnt;
+	struct cam_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:%d Regulators more than supported %d\n",
+			__func__, __LINE__, cnt);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < cnt; i++) {
+		if (a_ctrl->io_master_info.master_type ==
+			CCI_MASTER) {
+			rc = msm_camera_config_single_vreg(
+				&(a_ctrl->v4l2_dev_str.pdev->dev),
+				&vreg_cfg->cam_vreg[i],
+				(struct regulator **)&vreg_cfg->data[i],
+				config);
+		} else if (a_ctrl->io_master_info.master_type ==
+			I2C_MASTER) {
+			rc = msm_camera_config_single_vreg(
+				&(a_ctrl->io_master_info.client->dev),
+				&vreg_cfg->cam_vreg[i],
+				(struct regulator **)&vreg_cfg->data[i],
+				config);
+		}
+	}
+
+	return rc;
+}
+
+static int32_t cam_actuator_power_up(struct cam_actuator_ctrl_t *a_ctrl)
+{
+	int rc = 0;
+
+	rc = cam_actuator_vreg_control(a_ctrl, 1);
+	if (rc < 0) {
+		pr_err("%s:%d Actuator Reg Failed %d\n",
+			__func__, __LINE__, rc);
+		return rc;
+	}
+
+	if (a_ctrl->gconf &&
+		a_ctrl->gconf->gpio_num_info &&
+		a_ctrl->gconf->gpio_num_info->valid[SENSOR_VAF] == 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("%s:%d :Error: Failed in req gpio: %d\n",
+				__func__, __LINE__, 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("%s:%d :Error: cannot set pin to active state: %d",
+					__func__, __LINE__, rc);
+		}
+
+		gpio_set_value_cansleep(
+			a_ctrl->gconf->gpio_num_info->gpio_num[SENSOR_VAF],
+			1);
+	}
+
+	/* VREG needs some delay to power up */
+	usleep_range(2000, 2050);
+
+	return rc;
+}
+
+static int32_t cam_actuator_power_down(struct cam_actuator_ctrl_t *a_ctrl)
+{
+	int32_t rc = 0;
+
+	rc = cam_actuator_vreg_control(a_ctrl, 0);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		return rc;
+	}
+
+	if (a_ctrl->gconf &&
+		a_ctrl->gconf->gpio_num_info &&
+		a_ctrl->gconf->gpio_num_info->
+			valid[SENSOR_VAF] == 1) {
+
+		gpio_set_value_cansleep(
+			a_ctrl->gconf->gpio_num_info->
+				gpio_num[SENSOR_VAF],
+			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("%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("%s:%d Failed in selecting state: %d\n",
+				__func__, __LINE__, rc);
+	}
+
+	return rc;
+}
+
+int32_t cam_actuator_driver_cmd(struct cam_actuator_ctrl_t *a_ctrl,
+	void *arg)
+{
+	int rc = 0;
+	struct cam_control *cmd = (struct cam_control *)arg;
+
+	if (!a_ctrl || !cmd) {
+		pr_err("%s: %d :Error: Invalid Args\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	pr_debug("%s:%d Opcode to Actuator: %d\n",
+		__func__, __LINE__, cmd->op_code);
+
+	mutex_lock(&(a_ctrl->actuator_mutex));
+	switch (cmd->op_code) {
+	case CAM_ACQUIRE_DEV: {
+		struct cam_sensor_acquire_dev actuator_acq_dev;
+		struct cam_create_dev_hdl bridge_params;
+
+		if (a_ctrl->bridge_intf.device_hdl != -1) {
+			pr_err("%s:%d Device is already acquired\n",
+				__func__, __LINE__);
+			rc = -EINVAL;
+			goto release_mutex;
+		}
+		rc = copy_from_user(&actuator_acq_dev,
+			(void __user *) cmd->handle,
+			sizeof(actuator_acq_dev));
+		if (rc < 0) {
+			pr_err("%s:%d :Error: Failed Copying from user\n",
+				__func__, __LINE__);
+			goto release_mutex;
+		}
+
+		bridge_params.session_hdl = actuator_acq_dev.session_handle;
+		bridge_params.ops = &a_ctrl->bridge_intf.ops;
+		bridge_params.v4l2_sub_dev_flag = 0;
+		bridge_params.media_entity_flag = 0;
+		bridge_params.priv = a_ctrl;
+
+		actuator_acq_dev.device_handle =
+			cam_create_device_hdl(&bridge_params);
+		a_ctrl->bridge_intf.device_hdl = actuator_acq_dev.device_handle;
+		a_ctrl->bridge_intf.session_hdl =
+			actuator_acq_dev.session_handle;
+
+		CDBG("%s:%d Device Handle: %d\n",
+			__func__, __LINE__, actuator_acq_dev.device_handle);
+		if (copy_to_user((void __user *) cmd->handle, &actuator_acq_dev,
+			sizeof(struct cam_sensor_acquire_dev))) {
+			pr_err("%s:%d :Error: Failed Copy to User\n",
+				__func__, __LINE__);
+			rc = -EFAULT;
+			goto release_mutex;
+		}
+
+	}
+		break;
+	case CAM_RELEASE_DEV: {
+		if (a_ctrl->bridge_intf.device_hdl == -1) {
+			pr_err("%s:%d :Error: link hdl: %d device hdl: %d\n",
+				__func__, __LINE__,
+				a_ctrl->bridge_intf.device_hdl,
+				a_ctrl->bridge_intf.link_hdl);
+			rc = -EINVAL;
+			goto release_mutex;
+		}
+		rc = cam_destroy_device_hdl(a_ctrl->bridge_intf.device_hdl);
+		if (rc < 0)
+			pr_err("%s:%d :Error: destroying the device hdl\n",
+				__func__, __LINE__);
+		a_ctrl->bridge_intf.device_hdl = -1;
+		a_ctrl->bridge_intf.link_hdl = -1;
+		a_ctrl->bridge_intf.session_hdl = -1;
+	}
+		break;
+	case CAM_QUERY_CAP: {
+		struct cam_actuator_query_cap actuator_cap;
+
+		actuator_cap.slot_info = a_ctrl->id;
+		if (copy_to_user((void __user *) cmd->handle, &actuator_cap,
+			sizeof(struct cam_actuator_query_cap))) {
+			pr_err("%s:%d :Error: Failed Copy to User\n",
+				__func__, __LINE__);
+			rc = -EFAULT;
+			goto release_mutex;
+		}
+	}
+		break;
+	case CAM_START_DEV: {
+		rc = cam_actuator_power_up(a_ctrl);
+		if (rc < 0) {
+			pr_err("%s: %d :Error: Actuator Power up failed\n",
+				__func__, __LINE__);
+			goto release_mutex;
+		}
+		rc = camera_io_init(&a_ctrl->io_master_info);
+		if (rc < 0) {
+			pr_err("%s:%d :Error: cci_init failed\n",
+				__func__, __LINE__);
+			cam_actuator_power_down(a_ctrl);
+		}
+
+		rc = cam_actuator_apply_settings(a_ctrl,
+			&a_ctrl->i2c_data.init_settings);
+		if (rc < 0)
+			pr_err("%s: %d :Error: Cannot apply Init settings\n",
+				__func__, __LINE__);
+
+		/* Delete the request even if the apply is failed */
+		rc = delete_request(&a_ctrl->i2c_data.init_settings);
+		if (rc < 0) {
+			pr_err("%s:%d Fail in deleting the Init settings\n",
+				__func__, __LINE__);
+			rc = -EINVAL;
+			goto release_mutex;
+		}
+	}
+		break;
+	case CAM_STOP_DEV: {
+		rc = camera_io_release(&a_ctrl->io_master_info);
+		if (rc < 0)
+			pr_err("%s:%d :Error: Failed in releasing CCI\n",
+				__func__, __LINE__);
+		rc = cam_actuator_power_down(a_ctrl);
+		if (rc < 0) {
+			pr_err("%s:%d :Error: Actuator Power down failed\n",
+				__func__, __LINE__);
+			goto release_mutex;
+		}
+	}
+		break;
+	case CAM_CONFIG_DEV: {
+		a_ctrl->act_apply_state =
+			ACT_APPLY_SETTINGS_LATER;
+		rc = cam_actuator_i2c_pkt_parse(a_ctrl, arg);
+		if (rc < 0) {
+			pr_err("%s:%d :Error: Failed in actuator Parsing\n",
+				__func__, __LINE__);
+		}
+
+		if (a_ctrl->act_apply_state ==
+			ACT_APPLY_SETTINGS_NOW) {
+			rc = cam_actuator_apply_settings(a_ctrl,
+				&a_ctrl->i2c_data.init_settings);
+			if (rc < 0)
+				pr_err("%s:%d :Error: Cannot apply Update settings\n",
+					__func__, __LINE__);
+
+			/* Delete the request even if the apply is failed */
+			rc = delete_request(&a_ctrl->i2c_data.init_settings);
+			if (rc < 0) {
+				pr_err("%s: %d :Error: Failed in Deleting the Init Pkt: %d\n",
+					__func__, __LINE__, rc);
+				goto release_mutex;
+			}
+		}
+	}
+		break;
+	default:
+		pr_err("%s:%d Invalid Opcode %d\n",
+			__func__, __LINE__, cmd->op_code);
+	}
+
+release_mutex:
+	mutex_unlock(&(a_ctrl->actuator_mutex));
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.h
new file mode 100644
index 0000000..d2cb96d
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_ACTUATOR_CORE_H_
+#define _CAM_ACTUATOR_CORE_H_
+
+#include "cam_actuator_dev.h"
+
+/**
+ * @apply: Req mgr structure for applying request
+ *
+ * This API applies the request that is mentioned
+ */
+int32_t cam_actuator_apply_request(struct cam_req_mgr_apply_request *apply);
+
+/**
+ * @info: Sub device info to req mgr
+ *
+ * This API publish the subdevice info to req mgr
+ */
+int32_t cam_actuator_publish_dev_info(struct cam_req_mgr_device_info *info);
+
+/**
+ * @link: Link setup info
+ *
+ * This API establishes link actuator subdevice with req mgr
+ */
+int32_t cam_actuator_establish_link(
+	struct cam_req_mgr_core_dev_link_setup *link);
+
+/**
+ * @a_ctrl: Actuator ctrl structure
+ * @arg:    Camera control command argument
+ *
+ * This API handles the camera control argument reached to actuator
+ */
+int32_t cam_actuator_driver_cmd(struct cam_actuator_ctrl_t *a_ctrl, void *arg);
+
+#endif /* _CAM_ACTUATOR_CORE_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c
new file mode 100644
index 0000000..3835680
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c
@@ -0,0 +1,334 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "cam_actuator_dev.h"
+#include "cam_req_mgr_dev.h"
+#include "cam_actuator_soc.h"
+#include "cam_actuator_core.h"
+
+static long cam_actuator_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	int rc = 0;
+	struct cam_actuator_ctrl_t *a_ctrl =
+		v4l2_get_subdevdata(sd);
+
+	switch (cmd) {
+	case VIDIOC_CAM_CONTROL:
+		rc = cam_actuator_driver_cmd(a_ctrl, arg);
+		break;
+	default:
+		pr_err("%s:%d Invalid ioctl cmd\n",
+			__func__, __LINE__);
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+static int32_t cam_actuator_driver_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int32_t rc = 0, i = 0;
+	struct cam_actuator_ctrl_t *a_ctrl;
+
+	if (client == NULL || id == NULL) {
+		pr_err("%s:%d: :Error: Invalid Args client: %pK id: %pK\n",
+			__func__, __LINE__, client, id);
+		return -EINVAL;
+	}
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_err("%s %s :Error: i2c_check_functionality failed\n",
+			__func__, client->name);
+		rc = -EFAULT;
+		return rc;
+	}
+
+	/* Create sensor control structure */
+	a_ctrl = kzalloc(sizeof(*a_ctrl), GFP_KERNEL);
+	if (!a_ctrl)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, a_ctrl);
+
+	a_ctrl->i2c_data.per_frame =
+		(struct i2c_settings_array *)
+		kzalloc(sizeof(struct i2c_settings_array) *
+		MAX_PER_FRAME_ARRAY, GFP_KERNEL);
+	if (a_ctrl->i2c_data.per_frame == NULL) {
+		rc = -ENOMEM;
+		goto free_ctrl;
+	}
+
+	INIT_LIST_HEAD(&(a_ctrl->i2c_data.init_settings.list_head));
+
+	for (i = 0; i < MAX_PER_FRAME_ARRAY; i++)
+		INIT_LIST_HEAD(&(a_ctrl->i2c_data.per_frame[i].list_head));
+
+	/* Initialize sensor device type */
+	a_ctrl->of_node = client->dev.of_node;
+	a_ctrl->io_master_info.master_type = I2C_MASTER;
+
+	rc = cam_actuator_parse_dt(a_ctrl, &client->dev);
+	if (rc < 0) {
+		pr_err("failed: cam_sensor_parse_dt rc %d", rc);
+		goto free_mem;
+	}
+
+	return rc;
+free_mem:
+	kfree(a_ctrl->i2c_data.per_frame);
+free_ctrl:
+	kfree(a_ctrl);
+	return rc;
+}
+
+static int32_t cam_actuator_platform_remove(struct platform_device *pdev)
+{
+	struct cam_actuator_ctrl_t  *a_ctrl;
+	int32_t rc = 0;
+
+	a_ctrl = platform_get_drvdata(pdev);
+	if (!a_ctrl) {
+		pr_err("%s: Actuator device is NULL\n", __func__);
+		return 0;
+	}
+
+	kfree(a_ctrl->io_master_info.cci_client);
+	a_ctrl->io_master_info.cci_client = NULL;
+	kfree(a_ctrl->i2c_data.per_frame);
+	a_ctrl->i2c_data.per_frame = NULL;
+	devm_kfree(&pdev->dev, a_ctrl);
+
+	return rc;
+}
+
+static int32_t cam_actuator_driver_i2c_remove(struct i2c_client *client)
+{
+	struct cam_actuator_ctrl_t  *a_ctrl = i2c_get_clientdata(client);
+	int32_t rc = 0;
+
+	/* Handle I2C Devices */
+	if (!a_ctrl) {
+		pr_err("%s: Actuator device is NULL\n", __func__);
+		return -EINVAL;
+	}
+	/*Free Allocated Mem */
+	kfree(a_ctrl->i2c_data.per_frame);
+	a_ctrl->i2c_data.per_frame = NULL;
+	kfree(a_ctrl);
+	return rc;
+}
+
+#ifdef CONFIG_COMPAT
+static long cam_actuator_init_subdev_do_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, unsigned long arg)
+{
+	struct cam_control cmd_data;
+	int32_t rc = 0;
+
+	if (copy_from_user(&cmd_data, (void __user *)arg,
+		sizeof(cmd_data))) {
+		pr_err("Failed to copy from user_ptr=%pK size=%zu\n",
+			(void __user *)arg, sizeof(cmd_data));
+		return -EFAULT;
+	}
+
+	switch (cmd) {
+	case VIDIOC_CAM_CONTROL:
+		cmd = VIDIOC_CAM_CONTROL;
+		rc = cam_actuator_subdev_ioctl(sd, cmd, &cmd_data);
+		if (rc < 0) {
+			pr_err("%s:%d Failed in actuator suddev handling",
+				__func__, __LINE__);
+			return rc;
+		}
+		break;
+	default:
+		pr_err("%s:%d Invalid compat ioctl: %d\n",
+			__func__, __LINE__, cmd);
+		rc = -EINVAL;
+	}
+
+	if (!rc) {
+		if (copy_to_user((void __user *)arg, &cmd_data,
+			sizeof(cmd_data))) {
+			pr_err("Failed to copy to user_ptr=%pK size=%zu\n",
+				(void __user *)arg, sizeof(cmd_data));
+			rc = -EFAULT;
+		}
+	}
+	return rc;
+}
+
+#endif
+
+static struct v4l2_subdev_core_ops cam_actuator_subdev_core_ops = {
+	.ioctl = cam_actuator_subdev_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl32 = cam_actuator_init_subdev_do_ioctl,
+#endif
+};
+
+static struct v4l2_subdev_ops cam_actuator_subdev_ops = {
+	.core = &cam_actuator_subdev_core_ops,
+};
+
+static const struct v4l2_subdev_internal_ops cam_actuator_internal_ops;
+
+static const struct of_device_id cam_actuator_driver_dt_match[] = {
+	{.compatible = "qcom,actuator"},
+	{}
+};
+
+static int32_t cam_actuator_driver_platform_probe(
+	struct platform_device *pdev)
+{
+	int32_t rc = 0, i = 0;
+	struct cam_actuator_ctrl_t *a_ctrl = NULL;
+
+	/* Create sensor control structure */
+	a_ctrl = devm_kzalloc(&pdev->dev,
+		sizeof(struct cam_actuator_ctrl_t), GFP_KERNEL);
+	if (!a_ctrl)
+		return -ENOMEM;
+
+	/* Initialize actuator device type */
+	a_ctrl->of_node = pdev->dev.of_node;
+
+	/*fill in platform device*/
+	a_ctrl->v4l2_dev_str.pdev = pdev;
+
+	a_ctrl->io_master_info.master_type = CCI_MASTER;
+
+	a_ctrl->io_master_info.cci_client = kzalloc(sizeof(
+		struct cam_sensor_cci_client), GFP_KERNEL);
+	if (!(a_ctrl->io_master_info.cci_client))
+		return -ENOMEM;
+
+	a_ctrl->i2c_data.per_frame =
+		(struct i2c_settings_array *)
+		kzalloc(sizeof(struct i2c_settings_array) *
+		MAX_PER_FRAME_ARRAY, GFP_KERNEL);
+	if (a_ctrl->i2c_data.per_frame == NULL)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&(a_ctrl->i2c_data.init_settings.list_head));
+
+	for (i = 0; i < MAX_PER_FRAME_ARRAY; i++)
+		INIT_LIST_HEAD(&(a_ctrl->i2c_data.per_frame[i].list_head));
+
+	rc = cam_actuator_parse_dt(a_ctrl, &(pdev->dev));
+	if (rc < 0) {
+		pr_err("%s:%d :Error: Paring actuator dt failed rc %d",
+			__func__, __LINE__, rc);
+		goto free_ctrl;
+	}
+
+	/* Fill platform device id*/
+	pdev->id = a_ctrl->id;
+
+	a_ctrl->v4l2_dev_str.internal_ops =
+		&cam_actuator_internal_ops;
+	a_ctrl->v4l2_dev_str.ops =
+		&cam_actuator_subdev_ops;
+	strlcpy(a_ctrl->device_name, CAMX_ACTUATOR_DEV_NAME,
+		sizeof(a_ctrl->device_name));
+	a_ctrl->v4l2_dev_str.name =
+		a_ctrl->device_name;
+	a_ctrl->v4l2_dev_str.sd_flags =
+		(V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS);
+	a_ctrl->v4l2_dev_str.ent_function =
+		CAM_ACTUATOR_DEVICE_TYPE;
+	a_ctrl->v4l2_dev_str.token = a_ctrl;
+
+	rc = cam_register_subdev(&(a_ctrl->v4l2_dev_str));
+	if (rc < 0) {
+		pr_err("%s:%d :ERROR: Fail with cam_register_subdev\n",
+			__func__, __LINE__);
+		goto free_mem;
+	}
+
+	a_ctrl->bridge_intf.device_hdl = -1;
+	a_ctrl->bridge_intf.ops.get_dev_info =
+		cam_actuator_publish_dev_info;
+	a_ctrl->bridge_intf.ops.link_setup =
+		cam_actuator_establish_link;
+	a_ctrl->bridge_intf.ops.apply_req =
+		cam_actuator_apply_request;
+
+	platform_set_drvdata(pdev, a_ctrl);
+	v4l2_set_subdevdata(&a_ctrl->v4l2_dev_str.sd, a_ctrl);
+
+	return rc;
+free_mem:
+	kfree(a_ctrl->i2c_data.per_frame);
+free_ctrl:
+	devm_kfree(&pdev->dev, a_ctrl);
+	return rc;
+}
+
+MODULE_DEVICE_TABLE(of, cam_actuator_driver_dt_match);
+
+static struct platform_driver cam_actuator_platform_driver = {
+	.probe = cam_actuator_driver_platform_probe,
+	.driver = {
+		.name = "qcom,actuator",
+		.owner = THIS_MODULE,
+		.of_match_table = cam_actuator_driver_dt_match,
+	},
+	.remove = cam_actuator_platform_remove,
+};
+
+static const struct i2c_device_id i2c_id[] = {
+	{ACTUATOR_DRIVER_I2C, (kernel_ulong_t)NULL},
+	{ }
+};
+
+static struct i2c_driver cam_actuator_driver_i2c = {
+	.id_table = i2c_id,
+	.probe  = cam_actuator_driver_i2c_probe,
+	.remove = cam_actuator_driver_i2c_remove,
+	.driver = {
+		.name = ACTUATOR_DRIVER_I2C,
+	},
+};
+
+static int __init cam_actuator_driver_init(void)
+{
+	int32_t rc = 0;
+
+	rc = platform_driver_register(&cam_actuator_platform_driver);
+	if (rc < 0) {
+		pr_err("%s platform_driver_register failed rc = %d",
+			__func__, rc);
+		return rc;
+	}
+	rc = i2c_add_driver(&cam_actuator_driver_i2c);
+	if (rc)
+		pr_err("%s:%d :Error: i2c_add_driver failed rc = %d",
+			__func__, __LINE__, rc);
+
+	return rc;
+}
+
+static void __exit cam_actuator_driver_exit(void)
+{
+	platform_driver_unregister(&cam_actuator_platform_driver);
+	i2c_del_driver(&cam_actuator_driver_i2c);
+}
+
+module_init(cam_actuator_driver_init);
+module_exit(cam_actuator_driver_exit);
+MODULE_DESCRIPTION("cam_actuator_driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.h
new file mode 100644
index 0000000..22ef29e
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.h
@@ -0,0 +1,125 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_ACTUATOR_DEV_H_
+#define _CAM_ACTUATOR_DEV_H_
+
+#include <cam_sensor_io.h>
+#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 <linux/ion.h>
+#include <linux/iommu.h>
+#include <linux/timer.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-subdev.h>
+#include <cam_cci_dev.h>
+#include <cam_sensor_cmn_header.h>
+#include <cam_subdev.h>
+#include "cam_sensor_util.h"
+#include "cam_sensor_soc_api.h"
+
+#define NUM_MASTERS 2
+#define NUM_QUEUES 2
+
+#define TRUE  1
+#define FALSE 0
+
+#undef CDBG
+#ifdef CAM_SENSOR_DEBUG
+#define CDBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+#define ACTUATOR_DRIVER_I2C "i2c_actuator"
+#define CAMX_ACTUATOR_DEV_NAME "cam-actuator-driver"
+
+#define MSM_ACTUATOR_MAX_VREGS (10)
+#define ACTUATOR_MAX_POLL_COUNT 10
+
+
+enum msm_actuator_state_t {
+	ACT_APPLY_SETTINGS_NOW,
+	ACT_APPLY_SETTINGS_LATER,
+};
+
+/**
+ * struct cam_actuator_vreg
+ * @cam_vreg: Regulator structure
+ * @data: Regulator data
+ * @num_vreg: Number of regulators
+ */
+struct cam_actuator_vreg {
+	struct camera_vreg_t *cam_vreg;
+	void *data[MSM_ACTUATOR_MAX_VREGS];
+	int num_vreg;
+};
+
+/**
+ * struct intf_params
+ * @device_hdl: Device Handle
+ * @session_hdl: Session Handle
+ * @ops: KMD operations
+ * @crm_cb: Callback API pointers
+ */
+struct intf_params {
+	int32_t device_hdl;
+	int32_t session_hdl;
+	int32_t link_hdl;
+	struct cam_req_mgr_kmd_ops ops;
+	struct cam_req_mgr_crm_cb *crm_cb;
+};
+
+/**
+ * struct cam_actuator_ctrl_t
+ * @i2c_driver: I2C device info
+ * @pdev: Platform device
+ * @cci_i2c_master: I2C structure
+ * @io_master_info: Information about the communication master
+ * @actuator_mutex: Actuator mutex
+ * @id: Cell Index
+ * @act_apply_state: Actuator settings aRegulator config
+ * @gconf: GPIO config
+ * @pinctrl_info: Pinctrl information
+ * @v4l2_dev_str: V4L2 device structure
+ * @i2c_data: I2C register settings structure
+ * @act_info: Sensor query cap structure
+ * @of_node: Node ptr
+ * @device_name: Device name
+ */
+struct cam_actuator_ctrl_t {
+	struct i2c_driver *i2c_driver;
+	enum cci_i2c_master_t cci_i2c_master;
+	struct camera_io_master io_master_info;
+	struct mutex actuator_mutex;
+	uint32_t id;
+	enum msm_actuator_state_t act_apply_state;
+	struct cam_actuator_vreg vreg_cfg;
+	struct msm_camera_gpio_conf *gconf;
+	struct msm_pinctrl_info pinctrl_info;
+	uint8_t cam_pinctrl_status;
+	struct cam_subdev v4l2_dev_str;
+	struct i2c_data_settings i2c_data;
+	struct cam_actuator_query_cap act_info;
+	struct intf_params bridge_intf;
+	struct device_node *of_node;
+	char device_name[20];
+};
+
+#endif /* _CAM_ACTUATOR_DEV_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_soc.c
new file mode 100644
index 0000000..767f3b0
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_soc.c
@@ -0,0 +1,77 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "cam_actuator_soc.h"
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <cam_sensor_cmn_header.h>
+#include <cam_sensor_util.h>
+#include <cam_sensor_io.h>
+#include <cam_req_mgr_util.h>
+
+int32_t cam_actuator_parse_dt(struct cam_actuator_ctrl_t *a_ctrl,
+	struct device *dev)
+{
+	int32_t                   rc = 0;
+	struct cam_actuator_vreg *vreg_cfg;
+
+	/* Initialize mutex */
+	mutex_init(&(a_ctrl->actuator_mutex));
+
+	rc = of_property_read_u32(a_ctrl->of_node, "cell-index",
+		&(a_ctrl->id));
+	CDBG("cell-index %d, rc %d\n", a_ctrl->id, rc);
+	if (rc < 0) {
+		pr_err("%s:%d :Error: parsing dt for cellindex rc %d\n",
+			__func__, __LINE__, rc);
+		return rc;
+	}
+
+	rc = of_property_read_u32(a_ctrl->of_node, "qcom,cci-master",
+		&(a_ctrl->cci_i2c_master));
+	CDBG("qcom,cci-master %d, rc %d\n", a_ctrl->cci_i2c_master, rc);
+	if (rc < 0 || a_ctrl->cci_i2c_master >= MASTER_MAX) {
+		pr_err("%s:%d :Error: Wrong info from dt CCI master as : %d\n",
+			__func__, __LINE__, a_ctrl->cci_i2c_master);
+		return rc;
+	}
+
+	if (of_find_property(a_ctrl->of_node,
+			"qcom,cam-vreg-name", NULL)) {
+		vreg_cfg = &(a_ctrl->vreg_cfg);
+		rc = cam_sensor_get_dt_vreg_data(dev->of_node,
+			&vreg_cfg->cam_vreg, &vreg_cfg->num_vreg);
+		if (rc < 0) {
+			pr_err("%s:%d :Error: parsing regulator dt: %d\n",
+				__func__, __LINE__, rc);
+			return rc;
+		}
+	}
+	rc = msm_sensor_driver_get_gpio_data(&(a_ctrl->gconf),
+		a_ctrl->of_node);
+	if (rc < 0) {
+		pr_err("%s:%d No/Error Actuator GPIOs\n",
+			__func__, __LINE__);
+	} else {
+		a_ctrl->cam_pinctrl_status = 1;
+		rc = msm_camera_pinctrl_init(
+			&(a_ctrl->pinctrl_info), dev);
+		if (rc < 0) {
+			pr_err("ERR:%s: Error in reading actuator pinctrl\n",
+				__func__);
+			a_ctrl->cam_pinctrl_status = 0;
+			rc = 0;
+		}
+	}
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_soc.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_soc.h
new file mode 100644
index 0000000..05d51f4
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_soc.h
@@ -0,0 +1,26 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_ACTUATOR_SOC_H_
+#define _CAM_ACTUATOR_SOC_H_
+
+#include "cam_actuator_dev.h"
+
+/**
+ * @a_ctrl: Actuator ctrl structure
+ *
+ * This API parses actuator device tree
+ */
+int cam_actuator_parse_dt(struct cam_actuator_ctrl_t *a_ctrl,
+	struct device *dev);
+
+#endif /* _CAM_ACTUATOR_SOC_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/Makefile b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/Makefile
new file mode 100644
index 0000000..57dfed5
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/Makefile
@@ -0,0 +1,7 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_cci_dev.o cam_cci_core.o cam_cci_soc.o
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
new file mode 100644
index 0000000..746b786
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c
@@ -0,0 +1,1303 @@
+/* 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/module.h>
+#include "cam_cci_core.h"
+#include "cam_cci_dev.h"
+
+static int32_t cam_cci_convert_type_to_num_bytes(
+	enum camera_sensor_i2c_type type)
+{
+	int32_t num_bytes;
+
+	switch (type) {
+	case CAMERA_SENSOR_I2C_TYPE_BYTE:
+		num_bytes = 1;
+		break;
+	case CAMERA_SENSOR_I2C_TYPE_WORD:
+		num_bytes = 2;
+		break;
+	case CAMERA_SENSOR_I2C_TYPE_3B:
+		num_bytes = 3;
+		break;
+	case CAMERA_SENSOR_I2C_TYPE_DWORD:
+		num_bytes = 4;
+		break;
+	default:
+		pr_err("%s: %d failed: %d\n", __func__, __LINE__, type);
+		num_bytes = 0;
+		break;
+	}
+	return num_bytes;
+}
+
+static void cam_cci_flush_queue(struct cci_device *cci_dev,
+	enum cci_i2c_master_t master)
+{
+	int32_t rc = 0;
+
+	cam_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)
+			cam_io_w_mb(CCI_M0_RESET_RMSK,
+				cci_dev->base + CCI_RESET_CMD_ADDR);
+		else
+			cam_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 cam_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;
+	uint32_t read_val = 0;
+	uint32_t reg_offset = master * 0x200 + queue * 0x100;
+
+	read_val = cam_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__);
+		cam_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);
+		cam_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__);
+		atomic_set(&cci_dev->cci_master_info[master].
+						done_pending[queue], 1);
+		cam_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);
+		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;
+			cam_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 cam_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;
+	}
+
+	rc = cam_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);
+	cam_io_w_mb(val, cci_dev->base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
+		reg_offset);
+	return rc;
+}
+
+static int32_t cam_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 cam_cci_write_i2c_queue(cci_dev, val, master, queue);
+}
+
+#ifdef DUMP_CCI_REGISTERS
+static void cam_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 = cam_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 = cam_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 = cam_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 = cam_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);
+	}
+}
+#endif
+
+static uint32_t cam_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) {
+#ifdef DUMP_CCI_REGISTERS
+		cam_cci_dump_registers(cci_dev, master, queue);
+#endif
+		pr_err("%s: %d wait for queue: %d\n",
+			 __func__, __LINE__, queue);
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		cam_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 void cam_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 = cam_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);
+	cam_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);
+	cam_io_w_mb(read_val, cci_dev->base +
+		CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset);
+}
+
+static int32_t cam_cci_wait_report_cmd(struct cci_device *cci_dev,
+	enum cci_i2c_master_t master,
+	enum cci_i2c_queue_t queue)
+{
+	uint32_t reg_val = 1 << ((master * 2) + queue);
+
+	cam_cci_load_report_cmd(cci_dev, master, queue);
+	atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 1);
+	atomic_set(&cci_dev->cci_master_info[master].done_pending[queue], 1);
+	cam_io_w_mb(reg_val, cci_dev->base +
+		CCI_QUEUE_START_ADDR);
+
+	return cam_cci_wait(cci_dev, master, queue);
+}
+
+static int32_t cam_cci_transfer_end(struct cci_device *cci_dev,
+	enum cci_i2c_master_t master,
+	enum cci_i2c_queue_t queue)
+{
+	int32_t rc = 0;
+
+	if (atomic_read(&cci_dev->cci_master_info[master].q_free[queue]) == 0) {
+		rc = cam_cci_lock_queue(cci_dev, master, queue, 0);
+		if (rc < 0) {
+			pr_err("%s failed line %d\n", __func__, __LINE__);
+			return rc;
+		}
+		rc = cam_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);
+		rc = cam_cci_wait(cci_dev, master, queue);
+		if (rc < 0) {
+			pr_err("%s: %d failed rc %d\n", __func__, __LINE__, rc);
+			return rc;
+		}
+		rc = cam_cci_lock_queue(cci_dev, master, queue, 0);
+		if (rc < 0) {
+			pr_err("%s failed line %d\n", __func__, __LINE__);
+			return rc;
+		}
+		rc = cam_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 cam_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 = cam_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 void cam_cci_process_half_q(struct cci_device *cci_dev,
+	enum cci_i2c_master_t master,
+	enum cci_i2c_queue_t queue)
+{
+	uint32_t reg_val = 1 << ((master * 2) + queue);
+
+	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, cci_dev->base +
+			CCI_QUEUE_START_ADDR);
+	}
+}
+
+static int32_t cam_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;
+
+	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);
+		rc = cam_cci_wait(cci_dev, master, queue);
+		if (rc < 0) {
+			pr_err("%s: %d failed rc %d\n", __func__, __LINE__, rc);
+			return rc;
+		}
+	} else {
+		rc = cam_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 cam_cci_calc_cmd_len(struct cci_device *cci_dev,
+	struct cam_cci_ctrl *c_ctrl, uint32_t cmd_size,
+	 struct cam_sensor_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 cam_sensor_i2c_reg_setting *msg;
+	struct cam_sensor_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 = cam_cci_convert_type_to_num_bytes(msg->addr_type);
+		len = (size + addr_len) <= (cci_dev->payload_size) ?
+			(size + addr_len):cci_dev->payload_size;
+	} else {
+		addr_len = cam_cci_convert_type_to_num_bytes(msg->addr_type);
+		data_len = cam_cci_convert_type_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;
+				*pack += data_len;
+			} else {
+				break;
+			}
+			i += data_len;
+			cmd++;
+		}
+	}
+
+	if (len > cci_dev->payload_size) {
+		pr_err("%s: %d Len error: %d",
+			__func__, __LINE__, len);
+		return -EINVAL;
+	}
+
+	len += 1; /*add i2c WR command*/
+	len = len/4 + 1;
+
+	return len;
+}
+
+static uint32_t cam_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;
+}
+
+uint32_t *cam_cci_get_clk_rates(struct cci_device *cci_dev,
+	struct cam_cci_ctrl *c_ctrl)
+{
+	uint32_t j;
+	int32_t idx;
+	uint32_t cci_clk_src;
+	unsigned long clk;
+	struct cam_cci_clk_params_t *clk_params = NULL;
+	struct device_node *of_node = cci_dev->v4l2_dev_str.pdev->dev.of_node;
+	enum i2c_freq_mode i2c_freq_mode = c_ctrl->cci_info->i2c_freq_mode;
+
+	if (i2c_freq_mode >= I2C_MAX_MODES ||
+		i2c_freq_mode < I2C_STANDARD_MODE) {
+		pr_err("%s:%d Invalid frequency mode: %d\n",
+			__func__, __LINE__, (int32_t)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 = cam_cci_cycles_per_ms(clk);
+		return cci_dev->cci_clk_rates[0];
+	}
+
+	CDBG("%s:%d CCI: 3 cases:%d idx: %d\n", __func__,
+		__LINE__, (int32_t)cci_dev->num_clk_cases, idx);
+	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 = cam_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 cam_cci_set_clk_param(struct cci_device *cci_dev,
+	struct cam_cci_ctrl *c_ctrl)
+{
+	struct cam_cci_clk_params_t *clk_params = NULL;
+	enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master;
+	enum i2c_freq_mode 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;
+	}
+
+	clk_params = &cci_dev->cci_clk_params[i2c_freq_mode];
+
+	if (cci_dev->i2c_freq_mode[master] == i2c_freq_mode)
+		return 0;
+	if (master == MASTER_0) {
+		cam_io_w_mb(clk_params->hw_thigh << 16 |
+			clk_params->hw_tlow,
+			cci_dev->base + CCI_I2C_M0_SCL_CTL_ADDR);
+		cam_io_w_mb(clk_params->hw_tsu_sto << 16 |
+			clk_params->hw_tsu_sta,
+			cci_dev->base + CCI_I2C_M0_SDA_CTL_0_ADDR);
+		cam_io_w_mb(clk_params->hw_thd_dat << 16 |
+			clk_params->hw_thd_sta,
+			cci_dev->base + CCI_I2C_M0_SDA_CTL_1_ADDR);
+		cam_io_w_mb(clk_params->hw_tbuf,
+			cci_dev->base + CCI_I2C_M0_SDA_CTL_2_ADDR);
+		cam_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) {
+		cam_io_w_mb(clk_params->hw_thigh << 16 |
+			clk_params->hw_tlow,
+			cci_dev->base + CCI_I2C_M1_SCL_CTL_ADDR);
+		cam_io_w_mb(clk_params->hw_tsu_sto << 16 |
+			clk_params->hw_tsu_sta,
+			cci_dev->base + CCI_I2C_M1_SDA_CTL_0_ADDR);
+		cam_io_w_mb(clk_params->hw_thd_dat << 16 |
+			clk_params->hw_thd_sta,
+			cci_dev->base + CCI_I2C_M1_SDA_CTL_1_ADDR);
+		cam_io_w_mb(clk_params->hw_tbuf,
+			cci_dev->base + CCI_I2C_M1_SDA_CTL_2_ADDR);
+		cam_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 int32_t cam_cci_data_queue(struct cci_device *cci_dev,
+	struct cam_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;
+	uint8_t data[12];
+	struct cam_sensor_i2c_reg_setting *i2c_msg =
+		&c_ctrl->cfg.cci_i2c_write_cfg;
+	struct cam_sensor_i2c_reg_array *i2c_cmd = i2c_msg->reg_setting;
+	enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master;
+	uint16_t reg_addr = 0, cmd_size = i2c_msg->size;
+	uint32_t read_val = 0, reg_offset, val, delay = 0;
+	uint32_t max_queue_size, queue_size = 0, cmd = 0;
+
+	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 >= CAMERA_SENSOR_I2C_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 >= CAMERA_SENSOR_I2C_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;
+
+	cam_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);
+	cam_io_w_mb(val, cci_dev->base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
+		reg_offset);
+
+	atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 0);
+
+	max_queue_size = cci_dev->cci_i2c_queue_info[master][queue].
+			max_queue_size;
+
+	if (c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ)
+		queue_size = max_queue_size;
+	else
+		queue_size = max_queue_size/2;
+	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);
+		cam_io_w_mb(val,
+			cci_dev->base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
+			reg_offset);
+	}
+
+	rc = cam_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 = cam_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 = cam_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) > queue_size) {
+			if ((read_val + len + 1) > max_queue_size) {
+				rc = cam_cci_process_full_q(cci_dev,
+					master, queue);
+				if (rc < 0) {
+					pr_err("%s failed line %d\n",
+						__func__, __LINE__);
+					return rc;
+				}
+				continue;
+			}
+			cam_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 == CAMERA_SENSOR_I2C_TYPE_BYTE)
+				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 == CAMERA_SENSOR_I2C_TYPE_BYTE) {
+				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 = cam_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 = cam_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);
+			cam_io_w_mb(cmd, cci_dev->base +
+				CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
+				master * 0x200 + queue * 0x100);
+
+			read_val += 1;
+			cam_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);
+			cam_io_w_mb(cmd, cci_dev->base +
+				CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
+				master * 0x200 + queue * 0x100);
+			read_val += 1;
+			cam_io_w_mb(read_val, cci_dev->base +
+				CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset);
+		}
+	}
+
+	rc = cam_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 cam_cci_read(struct v4l2_subdev *sd,
+	struct cam_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 cam_cci_read_cfg *read_cfg = NULL;
+
+	cci_dev = v4l2_get_subdevdata(sd);
+	master = c_ctrl->cci_info->cci_i2c_master;
+	read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg;
+
+	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;
+	}
+	mutex_lock(&cci_dev->cci_master_info[master].mutex_q[queue]);
+
+	/*
+	 * Todo: If there is a change in frequency of operation
+	 * Wait for previos transaction to complete
+	 */
+
+	/* Set the I2C Frequency */
+	rc = cam_cci_set_clk_param(cci_dev, c_ctrl);
+	if (rc < 0) {
+		pr_err("%s:%d cam_cci_set_clk_param failed rc = %d\n",
+			__func__, __LINE__, rc);
+		goto rel_mutex;
+	}
+
+	/*
+	 * 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 = cam_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 rel_mutex;
+	}
+
+	if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) {
+		pr_err("%s:%d More than max retries\n", __func__,
+			__LINE__);
+		goto rel_mutex;
+	}
+
+	if (read_cfg->data == NULL) {
+		pr_err("%s:%d Data ptr is NULL\n", __func__,
+			__LINE__);
+		goto rel_mutex;
+	}
+
+	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 = cam_cci_write_i2c_queue(cci_dev, val, master, queue);
+	if (rc < 0) {
+		CDBG("%s failed line %d\n", __func__, __LINE__);
+		goto rel_mutex;
+	}
+
+	val = CCI_I2C_LOCK_CMD;
+	rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue);
+	if (rc < 0) {
+		CDBG("%s failed line %d\n", __func__, __LINE__);
+		goto rel_mutex;
+	}
+
+	if (read_cfg->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) {
+		pr_err("%s failed line %d\n", __func__, __LINE__);
+		rc = -EINVAL;
+		goto rel_mutex;
+	}
+
+	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 = cam_cci_write_i2c_queue(cci_dev, val, master, queue);
+	if (rc < 0) {
+		CDBG("%s failed line %d\n", __func__, __LINE__);
+		goto rel_mutex;
+	}
+
+	val = CCI_I2C_READ_CMD | (read_cfg->num_byte << 4);
+	rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue);
+	if (rc < 0) {
+		CDBG("%s failed line %d\n", __func__, __LINE__);
+		goto rel_mutex;
+	}
+
+	val = CCI_I2C_UNLOCK_CMD;
+	rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue);
+	if (rc < 0) {
+		CDBG("%s failed line %d\n", __func__, __LINE__);
+		goto rel_mutex;
+	}
+
+	val = cam_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);
+	cam_io_w_mb(val, cci_dev->base + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR
+			+ master * 0x200 + queue * 0x100);
+
+	val = 1 << ((master * 2) + queue);
+	cam_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) {
+#ifdef DUMP_CCI_REGISTERS
+		cam_cci_dump_registers(cci_dev, master, queue);
+#endif
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		pr_err("%s: %d wait_for_completion_timeout rc = %d\n",
+			 __func__, __LINE__, rc);
+		cam_cci_flush_queue(cci_dev, master);
+		goto rel_mutex;
+	} else {
+		rc = 0;
+	}
+
+	read_words = cam_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 rel_mutex;
+	}
+	index = 0;
+	CDBG("%s index %d num_type %d\n", __func__, index,
+		read_cfg->num_byte);
+	first_byte = 0;
+	do {
+		val = cam_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);
+rel_mutex:
+	mutex_unlock(&cci_dev->cci_master_info[master].mutex_q[queue]);
+
+	return rc;
+}
+
+static int32_t cam_cci_i2c_write(struct v4l2_subdev *sd,
+	struct cam_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 = cam_cci_set_clk_param(cci_dev, c_ctrl);
+	if (rc < 0) {
+		pr_err("%s:%d cam_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 = cam_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);
+		return rc;
+	}
+	if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) {
+		pr_err("%s:%d More than max retries\n", __func__,
+			__LINE__);
+		return rc;
+	}
+	rc = cam_cci_data_queue(cci_dev, c_ctrl, queue, sync_en);
+	if (rc < 0) {
+		pr_err("%s failed line %d\n", __func__, __LINE__);
+		return rc;
+	}
+
+	return rc;
+}
+
+static void cam_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 cam_sensor_i2c_reg_setting *i2c_msg;
+	enum cci_i2c_master_t master;
+	struct cam_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 = cam_cci_i2c_write(&(cci_dev->v4l2_dev_str.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);
+}
+
+static int32_t cam_cci_i2c_write_async(struct v4l2_subdev *sd,
+	struct cam_cci_ctrl *c_ctrl, enum cci_i2c_queue_t queue,
+	enum cci_i2c_sync sync_en)
+{
+	int32_t rc = 0;
+	struct cci_write_async *write_async;
+	struct cci_device *cci_dev;
+	struct cam_sensor_i2c_reg_setting *cci_i2c_write_cfg;
+	struct cam_sensor_i2c_reg_setting *cci_i2c_write_cfg_w;
+
+	cci_dev = v4l2_get_subdevdata(sd);
+
+	write_async = kzalloc(sizeof(*write_async), GFP_KERNEL);
+	if (!write_async)
+		return -ENOMEM;
+
+
+	INIT_WORK(&write_async->work, cam_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) {
+		kfree(write_async);
+		return -EINVAL;
+	}
+
+	cci_i2c_write_cfg_w->reg_setting =
+		kzalloc(sizeof(struct cam_sensor_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 cam_sensor_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->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);
+
+	return rc;
+}
+
+static int32_t cam_cci_read_bytes(struct v4l2_subdev *sd,
+	struct cam_cci_ctrl *c_ctrl)
+{
+	int32_t rc = 0;
+	struct cci_device *cci_dev = NULL;
+	enum cci_i2c_master_t master;
+	struct cam_cci_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 = cam_cci_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 cam_cci_i2c_set_sync_prms(struct v4l2_subdev *sd,
+	struct cam_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 cam_cci_release(struct v4l2_subdev *sd)
+{
+	uint8_t rc = 0;
+	struct cci_device *cci_dev;
+
+	cci_dev = v4l2_get_subdevdata(sd);
+
+	rc = cam_cci_soc_release(cci_dev);
+	if (rc < 0) {
+		pr_err("%s:%d Failed in releasing the cci: %d\n",
+			__func__, __LINE__, rc);
+		cam_cpas_stop(cci_dev->cpas_handle);
+		return rc;
+	}
+	cam_cpas_stop(cci_dev->cpas_handle);
+
+	return rc;
+}
+
+static int32_t cam_cci_write(struct v4l2_subdev *sd,
+	struct cam_cci_ctrl *c_ctrl)
+{
+	int32_t rc = 0;
+	struct cci_device *cci_dev;
+	enum cci_i2c_master_t master;
+	struct cam_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;
+	}
+
+	master = c_ctrl->cci_info->cci_i2c_master;
+
+	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;
+	}
+
+	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 = cam_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 = cam_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 = cam_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 = cam_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 = cam_cci_i2c_write_async(sd, c_ctrl,
+			PRIORITY_QUEUE, MSM_SYNC_DISABLE);
+		break;
+	default:
+		rc = -ENOIOCTLCMD;
+	}
+
+	return rc;
+}
+
+int32_t cam_cci_core_cfg(struct v4l2_subdev *sd,
+	struct cam_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 = cam_cci_init(sd, cci_ctrl);
+		break;
+	case MSM_CCI_RELEASE:
+		rc = cam_cci_release(sd);
+		break;
+	case MSM_CCI_I2C_READ:
+		rc = cam_cci_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 = cam_cci_write(sd, cci_ctrl);
+		break;
+	case MSM_CCI_GPIO_WRITE:
+		break;
+	case MSM_CCI_SET_SYNC_CID:
+		rc = cam_cci_i2c_set_sync_prms(sd, cci_ctrl);
+		break;
+
+	default:
+		rc = -ENOIOCTLCMD;
+	}
+
+	cci_ctrl->status = rc;
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.h
new file mode 100644
index 0000000..f6e82dc
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.h
@@ -0,0 +1,46 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _CAM_CCI_CORE_H_
+#define _CAM_CCI_CORE_H_
+
+#include <linux/irqreturn.h>
+#include <media/cam_sensor.h>
+#include "cam_cci_dev.h"
+#include "cam_cci_soc.h"
+
+/**
+ * @cci_dev: CCI device structure
+ * @c_ctrl: CCI control structure
+ *
+ * This API gets CCI clk rates
+ */
+uint32_t *cam_cci_get_clk_rates(struct cci_device *cci_dev,
+	struct cam_cci_ctrl *c_ctrl);
+
+/**
+ * @sd: V4L2 sub device
+ * @c_ctrl: CCI control structure
+ *
+ * This API handles I2C operations for CCI
+ */
+int32_t cam_cci_core_cfg(struct v4l2_subdev *sd,
+	struct cam_cci_ctrl *cci_ctrl);
+
+/**
+ * @irq_num: IRQ number
+ * @data: CCI private structure
+ *
+ * This API handles CCI IRQs
+ */
+irqreturn_t cam_cci_irq(int irq_num, void *data);
+
+#endif /* _CAM_CCI_CORE_H_ */
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
new file mode 100644
index 0000000..789522d
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c
@@ -0,0 +1,276 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "cam_cci_dev.h"
+#include "cam_req_mgr_dev.h"
+#include "cam_cci_soc.h"
+#include "cam_cci_core.h"
+
+#define CCI_MAX_DELAY 1000000
+#define CCI_TIMEOUT msecs_to_jiffies(500)
+
+static struct v4l2_subdev *g_cci_subdev;
+
+struct v4l2_subdev *cam_cci_get_subdev(void)
+{
+	return g_cci_subdev;
+}
+
+static long cam_cci_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	int32_t rc = 0;
+
+	switch (cmd) {
+	case VIDIOC_MSM_CCI_CFG:
+		rc = cam_cci_core_cfg(sd, arg);
+		break;
+	default:
+		pr_err("%s:%d Invalid ioctl cmd: %d\n",
+			__func__, __LINE__, cmd);
+		rc = -ENOIOCTLCMD;
+	}
+
+	return rc;
+}
+
+irqreturn_t cam_cci_irq(int irq_num, void *data)
+{
+	uint32_t irq;
+	struct cci_device *cci_dev = data;
+
+	irq = cam_io_r_mb(cci_dev->base + CCI_IRQ_STATUS_0_ADDR);
+	cam_io_w_mb(irq, cci_dev->base + CCI_IRQ_CLEAR_0_ADDR);
+	cam_io_w_mb(0x1, cci_dev->base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR);
+
+	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 cam_cci_master_info *cci_master_info;
+
+		cci_master_info = &cci_dev->cci_master_info[MASTER_0];
+		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);
+		}
+	}
+	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];
+		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);
+		}
+	}
+	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 cam_cci_master_info *cci_master_info;
+
+		cci_master_info = &cci_dev->cci_master_info[MASTER_1];
+		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);
+		}
+	}
+	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];
+		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);
+		}
+	}
+	if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK) {
+		cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE;
+		cam_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;
+		cam_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;
+		cam_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;
+		cam_io_w_mb(CCI_M1_HALT_REQ_RMSK,
+			cci_dev->base + CCI_HALT_REQ_ADDR);
+	}
+	return IRQ_HANDLED;
+}
+
+static int cam_cci_irq_routine(struct v4l2_subdev *sd, u32 status,
+	bool *handled)
+{
+	struct cci_device *cci_dev = v4l2_get_subdevdata(sd);
+	irqreturn_t ret;
+
+	ret = cam_cci_irq(cci_dev->irq->start, cci_dev);
+	*handled = TRUE;
+	return 0;
+}
+
+static struct v4l2_subdev_core_ops cci_subdev_core_ops = {
+	.ioctl = cam_cci_subdev_ioctl,
+	.interrupt_service_routine = cam_cci_irq_routine,
+};
+
+static const struct v4l2_subdev_ops cci_subdev_ops = {
+	.core = &cci_subdev_core_ops,
+};
+
+static const struct v4l2_subdev_internal_ops cci_subdev_intern_ops;
+
+static int cam_cci_platform_probe(struct platform_device *pdev)
+{
+	struct cam_cpas_register_params cpas_parms;
+	struct cci_device *new_cci_dev;
+	int rc = 0;
+
+	new_cci_dev = kzalloc(sizeof(struct cci_device),
+		GFP_KERNEL);
+	if (!new_cci_dev)
+		return -ENOMEM;
+
+	new_cci_dev->v4l2_dev_str.pdev = pdev;
+
+	rc = cam_cci_parse_dt_info(pdev, new_cci_dev);
+	if (rc < 0) {
+		pr_err("%s: %d Resource get Failed: %d\n",
+			__func__, __LINE__, rc);
+		goto cci_no_resource;
+	}
+
+	new_cci_dev->v4l2_dev_str.internal_ops =
+		&cci_subdev_intern_ops;
+	new_cci_dev->v4l2_dev_str.ops =
+		&cci_subdev_ops;
+	strlcpy(new_cci_dev->device_name, CAMX_CCI_DEV_NAME,
+		sizeof(new_cci_dev->device_name));
+	new_cci_dev->v4l2_dev_str.name =
+		new_cci_dev->device_name;
+	new_cci_dev->v4l2_dev_str.sd_flags =
+		(V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS);
+	new_cci_dev->v4l2_dev_str.ent_function =
+		CAM_CCI_DEVICE_TYPE;
+	new_cci_dev->v4l2_dev_str.token =
+		new_cci_dev;
+
+	rc = cam_register_subdev(&(new_cci_dev->v4l2_dev_str));
+	if (rc < 0) {
+		pr_err("%s:%d :Error: Fail with cam_register_subdev\n",
+			__func__, __LINE__);
+		goto cci_no_resource;
+	}
+
+	platform_set_drvdata(pdev, &(new_cci_dev->v4l2_dev_str.sd));
+	v4l2_set_subdevdata(&new_cci_dev->v4l2_dev_str.sd, new_cci_dev);
+	g_cci_subdev = &new_cci_dev->v4l2_dev_str.sd;
+
+	cpas_parms.cam_cpas_client_cb = NULL;
+	cpas_parms.cell_index = 0;
+	cpas_parms.dev = &pdev->dev;
+	cpas_parms.userdata = new_cci_dev;
+	strlcpy(cpas_parms.identifier, "cci", CAM_HW_IDENTIFIER_LENGTH);
+	rc = cam_cpas_register_client(&cpas_parms);
+	if (rc) {
+		pr_err("%s:%d CPAS registration failed\n", __func__, __LINE__);
+		goto cci_no_resource;
+	}
+	CDBG("CPAS registration successful handle=%d\n",
+		cpas_parms.client_handle);
+	new_cci_dev->cpas_handle = cpas_parms.client_handle;
+
+	return rc;
+cci_no_resource:
+	kfree(new_cci_dev);
+	return rc;
+}
+
+static int cam_cci_device_remove(struct platform_device *pdev)
+{
+	struct v4l2_subdev *subdev = platform_get_drvdata(pdev);
+	struct cci_device *cci_dev =
+		v4l2_get_subdevdata(subdev);
+
+	cam_cpas_unregister_client(cci_dev->cpas_handle);
+	cam_cci_soc_remove(pdev, cci_dev);
+	devm_kfree(&pdev->dev, cci_dev);
+	return 0;
+}
+
+static const struct of_device_id cam_cci_dt_match[] = {
+	{.compatible = "qcom,cci"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, cam_cci_dt_match);
+
+static struct platform_driver cci_driver = {
+	.probe = cam_cci_platform_probe,
+	.remove = cam_cci_device_remove,
+	.driver = {
+		.name = CAMX_CCI_DEV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = cam_cci_dt_match,
+	},
+};
+
+static int __init cam_cci_init_module(void)
+{
+	return platform_driver_register(&cci_driver);
+}
+
+static void __exit cam_cci_exit_module(void)
+{
+	platform_driver_unregister(&cci_driver);
+}
+
+module_init(cam_cci_init_module);
+module_exit(cam_cci_exit_module);
+MODULE_DESCRIPTION("MSM CCI driver");
+MODULE_LICENSE("GPL v2");
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
new file mode 100644
index 0000000..996fc62
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h
@@ -0,0 +1,322 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_CCI_DEV_H_
+#define _CAM_CCI_DEV_H_
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+#include <linux/module.h>
+#include <linux/irqreturn.h>
+#include <linux/ion.h>
+#include <linux/iommu.h>
+#include <linux/timer.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <media/cam_sensor.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-subdev.h>
+#include <cam_sensor_cmn_header.h>
+#include <cam_sensor_soc_api.h>
+#include <cam_io_util.h>
+#include <cam_sensor_util.h>
+#include <cam_subdev.h>
+#include <cam_cpas_api.h>
+#include "cam_cci_hwreg.h"
+
+#define V4L2_IDENT_CCI 50005
+#define CCI_I2C_QUEUE_0_SIZE 128
+#define CCI_I2C_QUEUE_1_SIZE 32
+#define CYCLES_PER_MICRO_SEC_DEFAULT 4915
+#define CCI_MAX_DELAY 1000000
+
+#define CCI_TIMEOUT msecs_to_jiffies(500)
+
+#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
+#define MAX_LRME_V4l2_EVENTS 30
+
+/* 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 CAMX_CCI_DEV_NAME "cam-cci-driver"
+
+/* 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)
+
+#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
+
+enum cci_i2c_sync {
+	MSM_SYNC_DISABLE,
+	MSM_SYNC_ENABLE,
+};
+
+enum cam_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,
+};
+
+enum cci_i2c_queue_t {
+	QUEUE_0,
+	QUEUE_1,
+	QUEUE_INVALID,
+};
+
+struct cam_cci_wait_sync_cfg {
+	uint16_t cid;
+	int16_t csid;
+	uint16_t line;
+	uint16_t delay;
+};
+
+struct cam_cci_gpio_cfg {
+	uint16_t gpio_queue;
+	uint16_t i2c_queue;
+};
+
+struct cam_cci_read_cfg {
+	uint32_t addr;
+	uint16_t addr_type;
+	uint8_t *data;
+	uint16_t num_byte;
+};
+
+struct cam_cci_i2c_queue_info {
+	uint32_t max_queue_size;
+	uint32_t report_id;
+	uint32_t irq_en;
+	uint32_t capture_rep_data;
+};
+
+struct cam_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];
+};
+
+struct cam_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 cam_cci_state_t {
+	CCI_STATE_ENABLED,
+	CCI_STATE_DISABLED,
+};
+
+/**
+ * struct cci_device
+ * @pdev: Platform device
+ * @subdev: V4L2 sub device
+ * @base: Base address of CCI device
+ * @hw_version: Hardware version
+ * @ref_count: Reference Count
+ * @cci_state: CCI state machine
+ * @num_clk: Number of CCI clock
+ * @cci_clk: CCI clock structure
+ * @cci_clk_info: CCI clock information
+ * @cam_cci_i2c_queue_info: CCI queue information
+ * @i2c_freq_mode: I2C frequency of operations
+ * @cci_clk_params: CCI hw clk params
+ * @cci_gpio_tbl: CCI GPIO table
+ * @cci_gpio_tbl_size: GPIO table size
+ * @cci_pinctrl: Pinctrl structure
+ * @cci_pinctrl_status: CCI pinctrl status
+ * @cci_clk_src: CCI clk src rate
+ * @cci_vreg: CCI regulator structure
+ * @cci_reg_ptr: CCI individual regulator structure
+ * @regulator_count: Regulator count
+ * @support_seq_write:
+ *     Set this flag when sequential write is enabled
+ * @write_wq: Work queue structure
+ * @valid_sync: Is it a valid sync with CSID
+ * @v4l2_dev_str: V4L2 device structure
+ * @cci_wait_sync_cfg: CCI sync config
+ * @cycles_per_us: Cycles per micro sec
+ * @payload_size: CCI packet payload size
+ */
+struct cci_device {
+	struct v4l2_subdev subdev;
+	struct resource *irq;
+	void __iomem *base;
+	uint32_t hw_version;
+	uint8_t ref_count;
+	enum cam_cci_state_t cci_state;
+	size_t num_clk;
+	struct clk **cci_clk;
+	struct msm_cam_clk_info *cci_clk_info;
+	struct cam_cci_i2c_queue_info
+		cci_i2c_queue_info[NUM_MASTERS][NUM_QUEUES];
+	struct cam_cci_master_info cci_master_info[NUM_MASTERS];
+	enum i2c_freq_mode i2c_freq_mode[NUM_MASTERS];
+	struct cam_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 cci_clk_src;
+	struct camera_vreg_t *cci_vreg;
+	struct regulator *cci_reg_ptr[MAX_REGULATOR];
+	int32_t regulator_count;
+	uint8_t support_seq_write;
+	struct workqueue_struct *write_wq[MASTER_MAX];
+	struct cam_cci_wait_sync_cfg cci_wait_sync_cfg;
+	uint8_t valid_sync;
+	struct cam_subdev v4l2_dev_str;
+	uint32_t cycles_per_us;
+	uint8_t payload_size;
+	size_t num_clk_cases;
+	uint32_t **cci_clk_rates;
+	char device_name[20];
+	uint32_t cpas_handle;
+};
+
+enum cam_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 cam_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 cam_sensor_cci_client {
+	struct v4l2_subdev *cci_subdev;
+	uint32_t freq;
+	enum i2c_freq_mode 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;
+};
+
+struct cam_cci_ctrl {
+	int32_t status;
+	struct cam_sensor_cci_client *cci_info;
+	enum cam_cci_cmd_type cmd;
+	union {
+		struct cam_sensor_i2c_reg_setting cci_i2c_write_cfg;
+		struct cam_cci_read_cfg cci_i2c_read_cfg;
+		struct cam_cci_wait_sync_cfg cci_wait_sync_cfg;
+		struct cam_cci_gpio_cfg gpio_cfg;
+	} cfg;
+};
+
+struct cci_write_async {
+	struct cci_device *cci_dev;
+	struct cam_cci_ctrl c_ctrl;
+	enum cci_i2c_queue_t queue;
+	struct work_struct work;
+	enum cci_i2c_sync sync_en;
+};
+
+irqreturn_t cam_cci_irq(int irq_num, void *data);
+
+#ifdef CONFIG_SPECTRA_CAMERA
+struct v4l2_subdev *cam_cci_get_subdev(void);
+#else
+static inline struct v4l2_subdev *cam_cci_get_subdev(void)
+{
+	return NULL;
+}
+#endif
+
+#define VIDIOC_MSM_CCI_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct cam_cci_ctrl *)
+
+#endif /* _CAM_CCI_DEV_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_hwreg.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_hwreg.h
new file mode 100644
index 0000000..c18593e
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_hwreg.h
@@ -0,0 +1,69 @@
+/* Copyright (c) 2012-2015, 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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_CCI_HWREG_
+#define _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 /* _CAM_CCI_HWREG_ */
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
new file mode 100644
index 0000000..59cdfaa
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c
@@ -0,0 +1,624 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "cam_cci_dev.h"
+#include "cam_cci_core.h"
+
+static int32_t cam_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->v4l2_dev_str.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;
+}
+
+int cam_cci_init(struct v4l2_subdev *sd,
+	struct cam_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;
+	struct cam_ahb_vote ahb_vote;
+	struct cam_axi_vote axi_vote;
+
+	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->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);
+			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)
+				cam_io_w_mb(CCI_M0_RESET_RMSK,
+					cci_dev->base + CCI_RESET_CMD_ADDR);
+			else
+				cam_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);
+		}
+		return 0;
+	}
+
+	ahb_vote.type = CAM_VOTE_ABSOLUTE;
+	ahb_vote.vote.level = CAM_SVS_VOTE;
+	axi_vote.compressed_bw = CAM_CPAS_DEFAULT_AXI_BW;
+	axi_vote.uncompressed_bw = CAM_CPAS_DEFAULT_AXI_BW;
+
+	rc = cam_cpas_start(cci_dev->cpas_handle,
+		&ahb_vote, &axi_vote);
+	if (rc != 0) {
+		pr_err("%s:%d CPAS start failed\n",
+			__func__, __LINE__);
+	}
+
+	ret = cam_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->v4l2_dev_str.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->v4l2_dev_str.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 = cam_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->v4l2_dev_str.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__);
+		return -EINVAL;
+	}
+	cci_dev->hw_version = cam_io_r_mb(cci_dev->base +
+		CCI_HW_VERSION_ADDR);
+	CDBG("%s:%d: hw_version = 0x%x\n", __func__, __LINE__,
+		cci_dev->hw_version);
+
+	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)
+				cci_dev->cci_i2c_queue_info[i][j].
+					max_queue_size =
+						CCI_I2C_QUEUE_0_SIZE;
+			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;
+	cam_io_w_mb(CCI_RESET_CMD_RMSK, cci_dev->base +
+			CCI_RESET_CMD_ADDR);
+	cam_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;
+	cam_io_w_mb(CCI_IRQ_MASK_0_RMSK,
+		cci_dev->base + CCI_IRQ_MASK_0_ADDR);
+	cam_io_w_mb(CCI_IRQ_MASK_0_RMSK,
+		cci_dev->base + CCI_IRQ_CLEAR_0_ADDR);
+	cam_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->v4l2_dev_str.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->v4l2_dev_str.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--;
+	cam_cpas_stop(cci_dev->cpas_handle);
+
+	return rc;
+}
+
+void cam_cci_soc_remove(struct platform_device *pdev,
+	struct cci_device *cci_dev)
+{
+	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);
+}
+
+static void cam_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]);
+			}
+	}
+}
+
+static int32_t cam_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->v4l2_dev_str.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 -EINVAL;
+	}
+
+	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 -EINVAL;
+	}
+
+	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 free_gpio_tbl;
+	}
+
+	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 free_val_array;
+	}
+	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 free_val_array;
+		}
+	}
+
+	kfree(val_array);
+	return rc;
+
+free_val_array:
+	kfree(val_array);
+free_gpio_tbl:
+	kfree(cci_dev->cci_gpio_tbl);
+	cci_dev->cci_gpio_tbl = NULL;
+	cci_dev->cci_gpio_tbl_size = 0;
+	return rc;
+}
+
+static void cam_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 cam_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->v4l2_dev_str.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
+			cam_cci_init_default_clk_params(cci_dev, count);
+
+		of_node_put(src_node);
+	}
+}
+
+int cam_cci_parse_dt_info(struct platform_device *pdev,
+	struct cci_device *new_cci_dev)
+{
+	int rc = 0, i = 0;
+
+	/* Get Clock Info*/
+	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: cam_cci_get_clk_info() failed", __func__);
+		kfree(new_cci_dev);
+		new_cci_dev = NULL;
+		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__);
+		return -ENODEV;
+	}
+	new_cci_dev->irq = msm_camera_get_irq(pdev, "cci");
+	if (!new_cci_dev->irq) {
+		pr_err("%s: no irq resource?\n", __func__);
+		return -ENODEV;
+	}
+	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,
+		cam_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->v4l2_dev_str.pdev = pdev;
+	cam_cci_init_cci_params(new_cci_dev);
+	cam_cci_init_clk_params(new_cci_dev);
+	rc = cam_cci_init_gpio_params(new_cci_dev);
+	if (rc < 0) {
+		pr_err("%s:%d :Error: In Initializing GPIO params:%d\n",
+			__func__, __LINE__, rc);
+		goto cci_release_mem;
+	}
+
+	rc = cam_sensor_get_dt_vreg_data(new_cci_dev->
+		v4l2_dev_str.pdev->dev.of_node,
+		&(new_cci_dev->cci_vreg), &(new_cci_dev->regulator_count));
+	if (rc < 0) {
+		pr_err("%s: cam_sensor_get_dt_vreg_data fail\n", __func__);
+		rc = -EFAULT;
+		goto cci_release_mem;
+	}
+
+	/* Parse VREG data */
+	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);
+	for (i = 0; i < MASTER_MAX; i++) {
+		new_cci_dev->write_wq[i] = create_singlethread_workqueue(
+			"cam_cci_wq");
+		if (!new_cci_dev->write_wq[i])
+			pr_err("Failed to create write wq\n");
+	}
+	CDBG("%s line %d\n", __func__, __LINE__);
+	return 0;
+
+cci_invalid_vreg_data:
+	kfree(new_cci_dev->cci_vreg);
+	new_cci_dev->cci_vreg = NULL;
+cci_release_mem:
+	msm_camera_put_reg_base(pdev, new_cci_dev->base, "cci", true);
+
+	return rc;
+}
+
+int cam_cci_soc_release(struct cci_device *cci_dev)
+{
+	uint8_t i = 0, rc = 0;
+
+	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);
+		return -EINVAL;
+	}
+	if (--cci_dev->ref_count) {
+		CDBG("%s ref_count Exit %d\n", __func__, cci_dev->ref_count);
+		return 0;
+	}
+	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->v4l2_dev_str.pdev->dev,
+		cci_dev->cci_clk_info, cci_dev->cci_clk,
+		cci_dev->num_clk, false);
+
+	rc = msm_camera_enable_vreg(&cci_dev->v4l2_dev_str.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->v4l2_dev_str.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;
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.h
new file mode 100644
index 0000000..ca4bbe0
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.h
@@ -0,0 +1,51 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_CCI_SOC_H_
+#define _CAM_CCI_SOC_H_
+
+#include "cam_cci_core.h"
+
+/**
+ * @sd: V4L2 sub device
+ * @c_ctrl: CCI control structure
+ *
+ * This API initializes the CCI and acquires SOC resources
+ */
+int cam_cci_init(struct v4l2_subdev *sd,
+	struct cam_cci_ctrl *c_ctrl);
+
+/**
+ * @cci_dev: CCI device structure
+ *
+ * This API releases the CCI and its SOC resources
+ */
+int cam_cci_soc_release(struct cci_device *cci_dev);
+
+/**
+ * @pdev: Platform device
+ * @new_cci_dev: CCI device structure
+ *
+ * This API parses CCI device tree
+ */
+int cam_cci_parse_dt_info(struct platform_device *pdev,
+	struct cci_device *new_cci_dev);
+
+/**
+ * @pdev: Platform device
+ * @cci_dev: CCI device structure
+ *
+ * This API puts all SOC resources
+ */
+void cam_cci_soc_remove(struct platform_device *pdev,
+	struct cci_device *cci_dev);
+#endif /* _CAM_CCI_SOC_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/Makefile b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/Makefile
new file mode 100644
index 0000000..0337b32
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/Makefile
@@ -0,0 +1,8 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_cci
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_csiphy_soc.o cam_csiphy_dev.o cam_csiphy_core.o
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
new file mode 100644
index 0000000..8dc65f5
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c
@@ -0,0 +1,500 @@
+/* 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/module.h>
+#include "cam_csiphy_core.h"
+#include "cam_csiphy_dev.h"
+#include "cam_csiphy_soc.h"
+#include <cam_mem_mgr.h>
+
+void cam_csiphy_query_cap(struct csiphy_device *csiphy_dev,
+	struct cam_csiphy_query_cap *csiphy_cap)
+{
+	csiphy_cap->slot_info = csiphy_dev->v4l2_dev_str.pdev->id;
+	csiphy_cap->version = csiphy_dev->hw_version;
+	csiphy_cap->clk_lane = csiphy_dev->clk_lane;
+}
+
+void cam_csiphy_reset(struct csiphy_device *csiphy_dev)
+{
+	int32_t  i;
+	uint32_t size =
+		csiphy_dev->ctrl_reg->csiphy_reg.csiphy_reset_array_size;
+
+	for (i = 0; i < size; i++) {
+		cam_io_w(
+			csiphy_dev->ctrl_reg->
+			csiphy_reset_reg[i].reg_data,
+			csiphy_dev->base +
+			csiphy_dev->ctrl_reg->
+			csiphy_reset_reg[i].reg_addr);
+
+		usleep_range(csiphy_dev->ctrl_reg->
+			csiphy_reset_reg[i].delay * 100,
+			csiphy_dev->ctrl_reg->
+			csiphy_reset_reg[i].delay * 100 + 1000);
+	}
+}
+
+int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev,
+	struct cam_config_dev_cmd *cfg_dev)
+{
+	int32_t                 rc = 0;
+	uint64_t                generic_ptr;
+	struct cam_packet       *csl_packet = NULL;
+	struct cam_cmd_buf_desc *cmd_desc = NULL;
+	uint32_t                *cmd_buf = NULL;
+	struct cam_csiphy_info  *cam_cmd_csiphy_info = NULL;
+	size_t                  len;
+
+	if (!cfg_dev || !csiphy_dev) {
+		pr_err("%s:%d Invalid Args\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	csiphy_dev->csiphy_info =
+		kzalloc(sizeof(struct cam_csiphy_info), GFP_KERNEL);
+	if (!csiphy_dev->csiphy_info)
+		return -ENOMEM;
+
+	rc = cam_mem_get_cpu_buf((int32_t) cfg_dev->packet_handle,
+		(uint64_t *)&generic_ptr, &len);
+	if (rc < 0) {
+		pr_err("%s:%d :ERROR: Failed to get packet Mem address: %d\n",
+			__func__, __LINE__, rc);
+		kfree(csiphy_dev->csiphy_info);
+		csiphy_dev->csiphy_info = NULL;
+		return rc;
+	}
+
+	if (cfg_dev->offset > len) {
+		pr_err("%s: %d offset is out of bounds: offset: %lld len: %zu\n",
+			__func__, __LINE__, cfg_dev->offset, len);
+		kfree(csiphy_dev->csiphy_info);
+		csiphy_dev->csiphy_info = NULL;
+		return -EINVAL;
+	}
+
+	csl_packet = (struct cam_packet *)(generic_ptr + cfg_dev->offset);
+
+	cmd_desc = (struct cam_cmd_buf_desc *)
+		((uint32_t *)&csl_packet->payload +
+		csl_packet->cmd_buf_offset / 4);
+
+	rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle,
+		(uint64_t *)&generic_ptr, &len);
+	if (rc < 0) {
+		pr_err("%s:%d :ERROR: Failed to get cmd buf Mem address : %d\n",
+			__func__, __LINE__, rc);
+		kfree(csiphy_dev->csiphy_info);
+		csiphy_dev->csiphy_info = NULL;
+		return rc;
+	}
+
+	cmd_buf = (uint32_t *)generic_ptr;
+	cmd_buf += cmd_desc->offset / 4;
+	cam_cmd_csiphy_info = (struct cam_csiphy_info *)cmd_buf;
+
+	csiphy_dev->csiphy_info->lane_cnt = cam_cmd_csiphy_info->lane_cnt;
+	csiphy_dev->csiphy_info->lane_mask = cam_cmd_csiphy_info->lane_mask;
+	csiphy_dev->csiphy_info->csiphy_3phase =
+		cam_cmd_csiphy_info->csiphy_3phase;
+	csiphy_dev->csiphy_info->combo_mode = cam_cmd_csiphy_info->combo_mode;
+	csiphy_dev->csiphy_info->settle_time = cam_cmd_csiphy_info->settle_time;
+	csiphy_dev->csiphy_info->data_rate = cam_cmd_csiphy_info->data_rate;
+
+	return rc;
+}
+
+void cam_csiphy_cphy_irq_config(struct csiphy_device *csiphy_dev)
+{
+	int32_t i;
+
+	for (i = 0; i < csiphy_dev->num_irq_registers; i++)
+		cam_io_w(csiphy_dev->ctrl_reg->
+			csiphy_irq_reg[i].reg_data,
+			csiphy_dev->base +
+			csiphy_dev->ctrl_reg->
+			csiphy_irq_reg[i].reg_addr);
+}
+
+void cam_csiphy_cphy_irq_disable(struct csiphy_device *csiphy_dev)
+{
+	int32_t i;
+
+	for (i = 0; i < csiphy_dev->num_irq_registers; i++)
+		cam_io_w(0x0,
+			csiphy_dev->base +
+			csiphy_dev->ctrl_reg->
+			csiphy_irq_reg[i].reg_addr);
+}
+
+irqreturn_t cam_csiphy_irq(int irq_num, void *data)
+{
+	uint32_t irq;
+	uint8_t i;
+	struct csiphy_device *csiphy_dev =
+		(struct csiphy_device *)data;
+
+	if (!csiphy_dev) {
+		pr_err("%s:%d Invalid Args\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < csiphy_dev->num_irq_registers; i++) {
+		irq = cam_io_r(
+			csiphy_dev->base +
+			csiphy_dev->ctrl_reg->csiphy_reg.
+			mipi_csiphy_interrupt_status0_addr + 0x4*i);
+		cam_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->v4l2_dev_str.pdev->id, i, irq);
+		cam_io_w(0x0,
+			csiphy_dev->base +
+			csiphy_dev->ctrl_reg->csiphy_reg.
+			mipi_csiphy_interrupt_clear0_addr + 0x4*i);
+	}
+	cam_io_w(0x1, csiphy_dev->base +
+		csiphy_dev->ctrl_reg->
+		csiphy_reg.mipi_csiphy_glbl_irq_cmd_addr);
+	cam_io_w(0x0, csiphy_dev->base +
+		csiphy_dev->ctrl_reg->
+		csiphy_reg.mipi_csiphy_glbl_irq_cmd_addr);
+
+	return IRQ_HANDLED;
+}
+
+int32_t cam_csiphy_config_dev(struct csiphy_device *csiphy_dev)
+{
+	int32_t      rc = 0;
+	uint32_t     lane_enable = 0, mask = 1, size = 0;
+	uint16_t     lane_mask = 0, i = 0, cfg_size = 0;
+	uint8_t      settle_cnt, lane_cnt, lane_pos = 0;
+	void __iomem *csiphybase;
+	struct csiphy_reg_t (*reg_array)[MAX_SETTINGS_PER_LANE];
+
+	if (csiphy_dev->csiphy_info == NULL) {
+		pr_err("%s:%d csiphy_info is NULL, No/Fail CONFIG_DEV ?\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	lane_cnt = csiphy_dev->csiphy_info->lane_cnt;
+	lane_mask = csiphy_dev->csiphy_info->lane_mask & 0x1f;
+	settle_cnt = (csiphy_dev->csiphy_info->settle_time / 200000000);
+	csiphybase = csiphy_dev->base;
+
+	if (!csiphybase) {
+		pr_err("%s: csiphybase NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	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;
+	}
+
+	if (!csiphy_dev->csiphy_info->csiphy_3phase) {
+		if (csiphy_dev->csiphy_info->combo_mode == 1)
+			reg_array =
+				csiphy_dev->ctrl_reg->csiphy_2ph_combo_mode_reg;
+		else
+			reg_array =
+				csiphy_dev->ctrl_reg->csiphy_2ph_reg;
+		csiphy_dev->num_irq_registers = 11;
+		cfg_size = csiphy_dev->ctrl_reg->csiphy_reg.
+			csiphy_2ph_config_array_size;
+	} else {
+		if (csiphy_dev->csiphy_info->combo_mode == 1)
+			reg_array =
+				csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg;
+		else
+			reg_array =
+				csiphy_dev->ctrl_reg->csiphy_3ph_reg;
+		csiphy_dev->num_irq_registers = 20;
+		cfg_size = csiphy_dev->ctrl_reg->csiphy_reg.
+			csiphy_3ph_config_array_size;
+	}
+
+	size = csiphy_dev->ctrl_reg->csiphy_reg.csiphy_common_array_size;
+
+	for (i = 0; i < size; i++) {
+		switch (csiphy_dev->ctrl_reg->
+			csiphy_common_reg[i].csiphy_param_type) {
+			case CSIPHY_LANE_ENABLE:
+				cam_io_w(lane_enable,
+					csiphy_dev->base +
+					csiphy_dev->ctrl_reg->
+					csiphy_common_reg[i].reg_addr);
+			break;
+			case CSIPHY_DEFAULT_PARAMS:
+				cam_io_w(csiphy_dev->ctrl_reg->
+					csiphy_common_reg[i].reg_data,
+					csiphy_dev->base +
+					csiphy_dev->ctrl_reg->
+					csiphy_common_reg[i].reg_addr);
+			break;
+			default:
+			break;
+		}
+	}
+
+	while (lane_mask & 0x1f) {
+		if (!(lane_mask & 0x1)) {
+			lane_pos++;
+			lane_mask >>= 1;
+			continue;
+		}
+
+		for (i = 0; i < cfg_size; i++) {
+			switch (reg_array[lane_pos][i].csiphy_param_type) {
+			case CSIPHY_LANE_ENABLE:
+				cam_io_w(lane_enable,
+					csiphy_dev->base +
+					reg_array[lane_pos][i].reg_addr);
+			break;
+			case CSIPHY_DEFAULT_PARAMS:
+				cam_io_w(reg_array[lane_pos][i].reg_data,
+					csiphy_dev->base +
+					reg_array[lane_pos][i].reg_addr);
+			break;
+			case CSIPHY_SETTLE_CNT_LOWER_BYTE:
+				cam_io_w(settle_cnt & 0xFF,
+					csiphy_dev->base +
+					reg_array[lane_pos][i].reg_addr);
+			break;
+			case CSIPHY_SETTLE_CNT_HIGHER_BYTE:
+				cam_io_w((settle_cnt >> 8) & 0xFF,
+					csiphy_dev->base +
+					reg_array[lane_pos][i].reg_addr);
+			break;
+			default:
+				CDBG("%s: %d Do Nothing\n", __func__, __LINE__);
+			break;
+			}
+			usleep_range(reg_array[lane_pos][i].delay*1000,
+				reg_array[lane_pos][i].delay*1000 + 1000);
+		}
+		lane_mask >>= 1;
+		lane_pos++;
+	}
+
+	cam_csiphy_cphy_irq_config(csiphy_dev);
+
+	return rc;
+}
+
+int32_t cam_csiphy_core_cfg(void *phy_dev,
+			void *arg)
+{
+	struct csiphy_device *csiphy_dev =
+		(struct csiphy_device *)phy_dev;
+	struct cam_control   *cmd = (struct cam_control *)arg;
+	int32_t              rc = 0;
+
+	if (!csiphy_dev || !cmd) {
+		pr_err("%s:%d Invalid input args\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	pr_debug("%s:%d Opcode received: %d\n", __func__, __LINE__,
+		cmd->op_code);
+	mutex_lock(&csiphy_dev->mutex);
+	switch (cmd->op_code) {
+	case CAM_ACQUIRE_DEV: {
+		struct cam_sensor_acquire_dev csiphy_acq_dev;
+		struct cam_csiphy_acquire_dev_info csiphy_acq_params;
+
+		struct cam_create_dev_hdl bridge_params;
+
+		rc = copy_from_user(&csiphy_acq_dev,
+			(void __user *)cmd->handle,
+			sizeof(csiphy_acq_dev));
+		if (rc < 0) {
+			pr_err("%s:%d :ERROR: Failed copying from User\n",
+				__func__, __LINE__);
+			goto release_mutex;
+		}
+
+		csiphy_acq_params.combo_mode = 0;
+
+		if (csiphy_dev->acquire_count == 2) {
+			pr_err("%s:%d CSIPHY device do not allow more than 2 acquires\n",
+				__func__, __LINE__);
+			rc = -EINVAL;
+			goto release_mutex;
+		}
+
+		bridge_params.ops = NULL;
+		bridge_params.session_hdl = csiphy_acq_dev.session_handle;
+		bridge_params.v4l2_sub_dev_flag = 0;
+		bridge_params.media_entity_flag = 0;
+		bridge_params.priv = csiphy_dev;
+
+		csiphy_acq_dev.device_handle =
+			cam_create_device_hdl(&bridge_params);
+		csiphy_dev->bridge_intf.
+			device_hdl[csiphy_acq_params.combo_mode] =
+				csiphy_acq_dev.device_handle;
+		csiphy_dev->bridge_intf.
+			session_hdl[csiphy_acq_params.combo_mode] =
+			csiphy_acq_dev.session_handle;
+
+		if (copy_to_user((void __user *)cmd->handle,
+				&csiphy_acq_dev,
+				sizeof(struct cam_sensor_acquire_dev))) {
+			pr_err("%s:%d :ERROR: Failed copying from User\n",
+				__func__, __LINE__);
+			rc = -EINVAL;
+			goto release_mutex;
+		}
+		if (csiphy_acq_params.combo_mode == 1)
+			csiphy_dev->is_acquired_dev_combo_mode = 1;
+		csiphy_dev->acquire_count++;
+	}
+		break;
+	case CAM_QUERY_CAP: {
+		struct cam_csiphy_query_cap csiphy_cap;
+
+		cam_csiphy_query_cap(csiphy_dev, &csiphy_cap);
+		if (copy_to_user((void __user *)cmd->handle,
+			&csiphy_cap, sizeof(struct cam_csiphy_query_cap))) {
+			pr_err("%s:%d :ERROR: Failed copying from User\n",
+				__func__, __LINE__);
+			rc = -EINVAL;
+			goto release_mutex;
+		}
+	}
+		break;
+	case CAM_STOP_DEV: {
+		rc = cam_csiphy_soc_release(csiphy_dev);
+		if (rc < 0) {
+			pr_err("%s:%d Failed in csiphy release\n",
+				__func__, __LINE__);
+			cam_cpas_stop(csiphy_dev->cpas_handle);
+			goto release_mutex;
+		}
+		rc = cam_cpas_stop(csiphy_dev->cpas_handle);
+		if (rc < 0) {
+			pr_err("%s:%d :Error: de-voting CPAS: %d\n",
+				__func__, __LINE__, rc);
+			goto release_mutex;
+		}
+	}
+		break;
+	case CAM_RELEASE_DEV: {
+		struct cam_release_dev_cmd release;
+
+		if (!csiphy_dev->acquire_count) {
+			pr_err("%s:%d No valid devices to release\n",
+				__func__, __LINE__);
+			rc = -EINVAL;
+			goto release_mutex;
+		}
+
+		if (copy_from_user(&release, (void __user *) cmd->handle,
+			sizeof(release))) {
+			rc = -EFAULT;
+			goto release_mutex;
+		}
+
+		rc = cam_destroy_device_hdl(release.dev_handle);
+		if (rc < 0)
+			pr_err("%s:%d :ERROR: destroying the device hdl\n",
+				__func__, __LINE__);
+		if (release.dev_handle ==
+			csiphy_dev->bridge_intf.device_hdl[0]) {
+			csiphy_dev->bridge_intf.device_hdl[0] = -1;
+			csiphy_dev->bridge_intf.link_hdl[0] = -1;
+			csiphy_dev->bridge_intf.session_hdl[0] = -1;
+		} else {
+			csiphy_dev->bridge_intf.device_hdl[1] = -1;
+			csiphy_dev->bridge_intf.link_hdl[1] = -1;
+			csiphy_dev->bridge_intf.
+				session_hdl[1] = -1;
+		}
+		csiphy_dev->acquire_count--;
+	}
+		break;
+	case CAM_CONFIG_DEV: {
+		struct cam_config_dev_cmd config;
+
+		if (copy_from_user(&config, (void __user *)cmd->handle,
+					sizeof(config))) {
+			rc = -EFAULT;
+		} else {
+			rc = cam_cmd_buf_parser(csiphy_dev, &config);
+			if (rc < 0) {
+				pr_err("%s:%d Fail in cmd buf parser\n",
+					__func__, __LINE__);
+				goto release_mutex;
+			}
+		}
+		break;
+	}
+	case CAM_START_DEV: {
+		struct cam_ahb_vote ahb_vote;
+		struct cam_axi_vote axi_vote;
+
+		ahb_vote.type = CAM_VOTE_ABSOLUTE;
+		ahb_vote.vote.level = CAM_SVS_VOTE;
+		axi_vote.compressed_bw = CAM_CPAS_DEFAULT_AXI_BW;
+		axi_vote.uncompressed_bw = CAM_CPAS_DEFAULT_AXI_BW;
+
+		rc = cam_cpas_start(csiphy_dev->cpas_handle,
+			&ahb_vote, &axi_vote);
+		if (rc < 0) {
+			pr_err("%s:%d :Error: voting CPAS: %d\n",
+				__func__, __LINE__, rc);
+			goto release_mutex;
+		}
+
+		rc = cam_csiphy_enable_hw(csiphy_dev);
+		if (rc != 0) {
+			pr_err("%s: %d cam_csiphy_enable_hw failed\n",
+				__func__, __LINE__);
+			cam_cpas_stop(csiphy_dev->cpas_handle);
+			goto release_mutex;
+		}
+		rc = cam_csiphy_config_dev(csiphy_dev);
+		if (rc < 0) {
+			pr_err("%s: %d cam_csiphy_config_dev failed\n",
+				__func__, __LINE__);
+			cam_cpas_stop(csiphy_dev->cpas_handle);
+			goto release_mutex;
+		}
+	}
+		break;
+	default:
+		pr_err("%s:%d :Error: Invalid Opcode: %d\n",
+			__func__, __LINE__, cmd->op_code);
+		rc = -EINVAL;
+		goto release_mutex;
+	}
+
+release_mutex:
+	mutex_unlock(&csiphy_dev->mutex);
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.h
new file mode 100644
index 0000000..6eeeea4
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.h
@@ -0,0 +1,52 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_CSIPHY_CORE_H_
+#define _CAM_CSIPHY_CORE_H_
+
+#include <linux/irqreturn.h>
+#include "cam_csiphy_dev.h"
+#include <cam_mem_mgr.h>
+#include <cam_req_mgr_util.h>
+#include <cam_io_util.h>
+
+/**
+ * @csiphy_dev: CSIPhy device structure
+ *
+ * This API programs CSIPhy IRQ  registers
+ */
+void cam_csiphy_cphy_irq_config(struct csiphy_device *csiphy_dev);
+
+/**
+ * @csiphy_dev: CSIPhy device structure
+ *
+ * This API resets CSIPhy hardware
+ */
+void cam_csiphy_reset(struct csiphy_device *csiphy_dev);
+
+/**
+ * @csiphy_dev: CSIPhy device structure
+ * @arg:    Camera control command argument
+ *
+ * This API handles the camera control argument reached to CSIPhy
+ */
+int cam_csiphy_core_cfg(void *csiphy_dev, void *arg);
+
+/**
+ * @irq_num: IRQ number
+ * @data: CSIPhy device structure
+ *
+ * This API handles CSIPhy IRQs
+ */
+irqreturn_t cam_csiphy_irq(int irq_num, void *data);
+
+#endif /* _CAM_CSIPHY_CORE_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c
new file mode 100644
index 0000000..f2ece9d
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c
@@ -0,0 +1,239 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "cam_csiphy_dev.h"
+#include "cam_req_mgr_dev.h"
+#include "cam_csiphy_soc.h"
+#include "cam_csiphy_core.h"
+#include <media/cam_sensor.h>
+
+#undef CDBG
+#ifdef CAM_CSIPHY_DEV_DEBUG
+#define CDBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+static long cam_csiphy_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	struct csiphy_device *csiphy_dev = v4l2_get_subdevdata(sd);
+	int rc = 0;
+
+	switch (cmd) {
+	case VIDIOC_CAM_CONTROL:
+		rc = cam_csiphy_core_cfg(csiphy_dev, arg);
+		if (rc != 0) {
+			pr_err("%s: %d :ERROR: in configuring the device\n",
+				__func__, __LINE__);
+			return rc;
+		}
+		break;
+	default:
+		pr_err("%s:%d :ERROR: Wrong ioctl\n", __func__, __LINE__);
+		break;
+	}
+
+	return rc;
+}
+
+#ifdef CONFIG_COMPAT
+static long cam_csiphy_subdev_compat_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, unsigned long arg)
+{
+	int32_t rc = 0;
+	struct cam_control cmd_data;
+
+	if (copy_from_user(&cmd_data, (void __user *)arg,
+		sizeof(cmd_data))) {
+		pr_err("Failed to copy from user_ptr=%pK size=%zu\n",
+			(void __user *)arg, sizeof(cmd_data));
+		return -EFAULT;
+	}
+
+	/* All the arguments converted to 64 bit here
+	 * Passed to the api in core.c
+	 */
+	switch (cmd) {
+	case VIDIOC_CAM_CONTROL:
+		rc = cam_csiphy_subdev_ioctl(sd, cmd, &cmd_data);
+		break;
+	default:
+		pr_err("%s:%d Invalid compat ioctl cmd: %d\n",
+			__func__, __LINE__, cmd);
+		rc = -EINVAL;
+	}
+
+	if (!rc) {
+		if (copy_to_user((void __user *)arg, &cmd_data,
+			sizeof(cmd_data))) {
+			pr_err("Failed to copy to user_ptr=%pK size=%zu\n",
+				(void __user *)arg, sizeof(cmd_data));
+			rc = -EFAULT;
+		}
+	}
+
+	return rc;
+}
+#endif
+
+static struct v4l2_subdev_core_ops csiphy_subdev_core_ops = {
+	.ioctl = cam_csiphy_subdev_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl32 = cam_csiphy_subdev_compat_ioctl,
+#endif
+};
+
+static const struct v4l2_subdev_ops csiphy_subdev_ops = {
+	.core = &csiphy_subdev_core_ops,
+};
+
+static const struct v4l2_subdev_internal_ops csiphy_subdev_intern_ops;
+
+static int32_t cam_csiphy_platform_probe(struct platform_device *pdev)
+{
+	struct cam_cpas_register_params cpas_parms;
+	struct csiphy_device *new_csiphy_dev;
+	int32_t              rc = 0;
+
+	new_csiphy_dev = devm_kzalloc(&pdev->dev,
+		sizeof(struct csiphy_device), GFP_KERNEL);
+	if (!new_csiphy_dev)
+		return -ENOMEM;
+
+	new_csiphy_dev->ctrl_reg = kzalloc(sizeof(struct csiphy_ctrl_t),
+		GFP_KERNEL);
+	if (!new_csiphy_dev->ctrl_reg) {
+		devm_kfree(&pdev->dev, new_csiphy_dev);
+		return -ENOMEM;
+	}
+
+	mutex_init(&new_csiphy_dev->mutex);
+	new_csiphy_dev->v4l2_dev_str.pdev = pdev;
+
+	new_csiphy_dev->ref_count = 0;
+
+	rc = cam_csiphy_parse_dt_info(pdev, new_csiphy_dev);
+	if (rc < 0) {
+		pr_err("%s:%d :ERROR: dt paring failed: %d\n",
+			__func__, __LINE__, rc);
+		goto csiphy_no_resource;
+	}
+
+	new_csiphy_dev->v4l2_dev_str.internal_ops =
+		&csiphy_subdev_intern_ops;
+	new_csiphy_dev->v4l2_dev_str.ops =
+		&csiphy_subdev_ops;
+	strlcpy(new_csiphy_dev->device_name, CAMX_CSIPHY_DEV_NAME,
+		sizeof(new_csiphy_dev->device_name));
+	new_csiphy_dev->v4l2_dev_str.name =
+		new_csiphy_dev->device_name;
+	new_csiphy_dev->v4l2_dev_str.sd_flags =
+		(V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS);
+	new_csiphy_dev->v4l2_dev_str.ent_function =
+		CAM_CSIPHY_DEVICE_TYPE;
+	new_csiphy_dev->v4l2_dev_str.token =
+		new_csiphy_dev;
+
+	rc = cam_register_subdev(&(new_csiphy_dev->v4l2_dev_str));
+	if (rc < 0) {
+		pr_err("%s:%d :ERROR: In cam_register_subdev\n",
+			__func__, __LINE__);
+		goto csiphy_no_resource;
+	}
+
+	platform_set_drvdata(pdev, &(new_csiphy_dev->v4l2_dev_str.sd));
+	v4l2_set_subdevdata(&(new_csiphy_dev->v4l2_dev_str.sd), new_csiphy_dev);
+
+	new_csiphy_dev->bridge_intf.device_hdl[0] = -1;
+	new_csiphy_dev->bridge_intf.device_hdl[1] = -1;
+	new_csiphy_dev->bridge_intf.ops.get_dev_info =
+		NULL;
+	new_csiphy_dev->bridge_intf.ops.link_setup =
+		NULL;
+	new_csiphy_dev->bridge_intf.ops.apply_req =
+		NULL;
+
+	new_csiphy_dev->acquire_count = 0;
+	new_csiphy_dev->is_acquired_dev_combo_mode = 0;
+
+	cpas_parms.cam_cpas_client_cb = NULL;
+	cpas_parms.cell_index = pdev->id;
+	cpas_parms.dev = &pdev->dev;
+	cpas_parms.userdata = new_csiphy_dev;
+
+	strlcpy(cpas_parms.identifier, "csiphy", CAM_HW_IDENTIFIER_LENGTH);
+	rc = cam_cpas_register_client(&cpas_parms);
+	if (rc) {
+		pr_err("%s:%d CPAS registration failed\n",
+			__func__, __LINE__);
+		goto csiphy_no_resource;
+	}
+	CDBG("CPAS registration successful handle=%d\n",
+		cpas_parms.client_handle);
+	new_csiphy_dev->cpas_handle = cpas_parms.client_handle;
+
+	return rc;
+csiphy_no_resource:
+	mutex_destroy(&new_csiphy_dev->mutex);
+	kfree(new_csiphy_dev->ctrl_reg);
+	devm_kfree(&pdev->dev, new_csiphy_dev);
+	return rc;
+}
+
+
+static int32_t cam_csiphy_device_remove(struct platform_device *pdev)
+{
+	struct v4l2_subdev *subdev =
+		platform_get_drvdata(pdev);
+	struct csiphy_device *csiphy_dev =
+		v4l2_get_subdevdata(subdev);
+
+	cam_cpas_unregister_client(csiphy_dev->cpas_handle);
+	cam_csiphy_soc_release(csiphy_dev);
+	kfree(csiphy_dev->ctrl_reg);
+	devm_kfree(&pdev->dev, csiphy_dev);
+
+	return 0;
+}
+
+static const struct of_device_id cam_csiphy_dt_match[] = {
+	{.compatible = "qcom,csiphy"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, cam_csiphy_dt_match);
+
+static struct platform_driver csiphy_driver = {
+	.probe = cam_csiphy_platform_probe,
+	.remove = cam_csiphy_device_remove,
+	.driver = {
+		.name = CAMX_CSIPHY_DEV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = cam_csiphy_dt_match,
+	},
+};
+
+static int32_t __init cam_csiphy_init_module(void)
+{
+	return platform_driver_register(&csiphy_driver);
+}
+
+static void __exit cam_csiphy_exit_module(void)
+{
+	platform_driver_unregister(&csiphy_driver);
+}
+
+module_init(cam_csiphy_init_module);
+module_exit(cam_csiphy_exit_module);
+MODULE_DESCRIPTION("CAM CSIPHY driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h
new file mode 100644
index 0000000..9049e4e
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h
@@ -0,0 +1,209 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_CSIPHY_DEV_H_
+#define _CAM_CSIPHY_DEV_H_
+
+#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 <linux/ion.h>
+#include <linux/iommu.h>
+#include <linux/timer.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-subdev.h>
+#include <media/cam_defs.h>
+#include <cam_sensor_cmn_header.h>
+#include <cam_req_mgr_interface.h>
+#include <cam_subdev.h>
+#include <cam_sensor_soc_api.h>
+#include <cam_io_util.h>
+#include <cam_cpas_api.h>
+
+#define MAX_CSIPHY                  3
+#define MAX_DPHY_DATA_LN            4
+#define MAX_LRME_V4l2_EVENTS        30
+#define CSIPHY_NUM_CLK_MAX          16
+#define MAX_CSIPHY_REG_ARRAY        70
+#define MAX_CSIPHY_CMN_REG_ARRAY    5
+
+#define MAX_LANES             5
+#define MAX_SETTINGS_PER_LANE 20
+
+#define MAX_REGULATOR         5
+#define CAMX_CSIPHY_DEV_NAME "cam-csiphy-driver"
+
+#define CSIPHY_POWER_UP       0
+#define CSIPHY_POWER_DOWN     1
+
+#define CSIPHY_DEFAULT_PARAMS            0
+#define CSIPHY_LANE_ENABLE               1
+#define CSIPHY_SETTLE_CNT_LOWER_BYTE     2
+#define CSIPHY_SETTLE_CNT_HIGHER_BYTE    3
+#define CSIPHY_DNP_PARAMS                4
+
+#define ENABLE_IRQ false
+
+#undef CDBG
+#ifdef CAM_CSIPHY_CORE_DEBUG
+#define CDBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+/**
+ * struct csiphy_reg_parms_t
+ * @mipi_csiphy_glbl_irq_cmd_addr: CSIPhy irq addr
+ * @mipi_csiphy_interrupt_status0_addr:
+ *     CSIPhy interrupt status addr
+ * @mipi_csiphy_interrupt_mask0_addr:
+ *     CSIPhy interrupt mask addr
+ * @mipi_csiphy_interrupt_mask_val:
+ *      CSIPhy interrupt mask val
+ * @mipi_csiphy_interrupt_clear0_addr:
+ *     CSIPhy interrupt clear addr
+ * @csiphy_version: CSIPhy Version
+ * @csiphy_common_array_size: CSIPhy common array size
+ * @csiphy_reset_array_size: CSIPhy reset array size
+ */
+struct csiphy_reg_parms_t {
+/*MIPI CSI PHY registers*/
+	uint32_t mipi_csiphy_glbl_irq_cmd_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 csiphy_version;
+	uint32_t csiphy_common_array_size;
+	uint32_t csiphy_reset_array_size;
+	uint32_t csiphy_2ph_config_array_size;
+	uint32_t csiphy_3ph_config_array_size;
+};
+
+/**
+ * struct intf_params
+ * @device_hdl: Device Handle
+ * @session_hdl: Session Handle
+ * @ops: KMD operations
+ * @crm_cb: Callback API pointers
+ */
+struct intf_params {
+	int32_t device_hdl[2];
+	int32_t session_hdl[2];
+	int32_t link_hdl[2];
+	struct cam_req_mgr_kmd_ops ops;
+	struct cam_req_mgr_crm_cb *crm_cb;
+};
+
+/**
+ * struct csiphy_reg_t
+ * @reg_addr: Register address
+ * @reg_data: Register data
+ * @delay: Delay
+ * @csiphy_param_type: CSIPhy parameter type
+ */
+struct csiphy_reg_t {
+	int32_t  reg_addr;
+	int32_t  reg_data;
+	int32_t  delay;
+	uint32_t csiphy_param_type;
+};
+
+/**
+ * struct csiphy_ctrl_t
+ * @csiphy_reg: Register address
+ * @csiphy_common_reg: Common register set
+ * @csiphy_reset_reg: Reset register set
+ * @csiphy_2ph_reg: 2phase register set
+ * @csiphy_2ph_combo_mode_reg:
+ *     2phase combo register set
+ * @csiphy_3ph_reg: 3phase register set
+ * @csiphy_2ph_3ph_mode_reg:
+ *     2 phase 3phase combo register set
+ */
+struct csiphy_ctrl_t {
+	struct csiphy_reg_parms_t csiphy_reg;
+	struct csiphy_reg_t *csiphy_common_reg;
+	struct csiphy_reg_t *csiphy_irq_reg;
+	struct csiphy_reg_t *csiphy_reset_reg;
+	struct csiphy_reg_t (*csiphy_2ph_reg)[MAX_SETTINGS_PER_LANE];
+	struct csiphy_reg_t (*csiphy_2ph_combo_mode_reg)[MAX_SETTINGS_PER_LANE];
+	struct csiphy_reg_t (*csiphy_3ph_reg)[MAX_SETTINGS_PER_LANE];
+	struct csiphy_reg_t (*csiphy_2ph_3ph_mode_reg)[MAX_SETTINGS_PER_LANE];
+};
+
+/**
+ * struct csiphy_device
+ * @pdev: Platform device
+ * @irq: Interrupt structure
+ * @base: Base address
+ * @hw_version: Hardware Version
+ * @csiphy_state: CSIPhy state
+ * @ctrl_reg: CSIPhy control registers
+ * @num_clk: Number of clocks
+ * @csiphy_max_clk: Max timer clock rate
+ * @num_vreg: Number of regulators
+ * @csiphy_clk: Clock structure
+ * @csiphy_clk_info: Clock information structure
+ * @csiphy_vreg: Regulator structure
+ * @csiphy_reg_ptr: Regulator structure
+ * @csiphy_3p_clk_info: 3Phase clock information
+ * @csiphy_3p_clk: 3Phase clocks structure
+ * @csiphy_clk_index: Timer Src clk index
+ * @csi_3phase: Is it a 3Phase mode
+ * @ref_count: Reference count
+ * @clk_lane: Clock lane
+ * @acquire_count: Acquire device count
+ * @is_acquired_dev_combo_mode:
+ *    Flag that mentions whether already acquired
+ *   device is for combo mode
+ */
+struct csiphy_device {
+	struct resource *irq;
+	void __iomem *base;
+	struct mutex mutex;
+	uint32_t hw_version;
+	uint32_t csiphy_state;
+	struct csiphy_ctrl_t *ctrl_reg;
+	size_t num_clk;
+	uint32_t csiphy_max_clk;
+	int32_t num_vreg;
+	struct clk **csiphy_clk;
+	struct msm_cam_clk_info *csiphy_clk_info;
+	struct camera_vreg_t *csiphy_vreg;
+	struct regulator *csiphy_reg_ptr[MAX_REGULATOR];
+	struct msm_cam_clk_info csiphy_3p_clk_info[2];
+	struct clk *csiphy_3p_clk[2];
+	uint32_t csiphy_clk_index;
+	unsigned char csi_3phase;
+	int32_t ref_count;
+	uint16_t lane_mask[MAX_CSIPHY];
+	uint8_t is_csiphy_3phase_hw;
+	uint8_t num_irq_registers;
+	struct cam_subdev v4l2_dev_str;
+	struct cam_csiphy_info *csiphy_info;
+	struct intf_params bridge_intf;
+	uint32_t clk_lane;
+	uint32_t acquire_count;
+	char device_name[20];
+	uint32_t is_acquired_dev_combo_mode;
+	uint32_t cpas_handle;
+};
+
+#endif /* _CAM_CSIPHY_DEV_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c
new file mode 100644
index 0000000..540ec76
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c
@@ -0,0 +1,274 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "cam_csiphy_soc.h"
+#include "cam_csiphy_core.h"
+#include "include/cam_csiphy_1_0_hwreg.h"
+#include "cam_sensor_util.h"
+
+int32_t cam_csiphy_enable_hw(struct csiphy_device *csiphy_dev)
+{
+	int32_t rc = 0;
+	long clk_rate = 0;
+
+	if (csiphy_dev->ref_count++) {
+		pr_err("%s:%d csiphy refcount = %d\n", __func__,
+			__LINE__, csiphy_dev->ref_count);
+		return rc;
+	}
+
+	rc = msm_camera_config_vreg(&csiphy_dev->v4l2_dev_str.pdev->dev,
+		csiphy_dev->csiphy_vreg,
+		csiphy_dev->num_vreg, NULL, 0,
+		&csiphy_dev->csiphy_reg_ptr[0], 1);
+	if (rc < 0) {
+		pr_err("%s:%d failed regulator get\n", __func__, __LINE__);
+		goto csiphy_config_regulator_fail;
+	}
+
+	rc = msm_camera_enable_vreg(&csiphy_dev->v4l2_dev_str.pdev->dev,
+		csiphy_dev->csiphy_vreg,
+		csiphy_dev->num_vreg, NULL, 0,
+		&csiphy_dev->csiphy_reg_ptr[0], 1);
+	if (rc < 0) {
+		pr_err("%s:%d failed to enable regulators\n", __func__, rc);
+		goto csiphy_regulator_fail;
+	}
+
+	/*Enable clocks*/
+	rc = msm_camera_clk_enable(&csiphy_dev->v4l2_dev_str.pdev->dev,
+		csiphy_dev->csiphy_clk_info, csiphy_dev->csiphy_clk,
+		csiphy_dev->num_clk, true);
+	if (rc < 0) {
+		pr_err("%s: csiphy clk enable failed\n", __func__);
+		csiphy_dev->ref_count--;
+		goto csiphy_regulator_fail;
+	}
+
+	clk_rate = msm_camera_clk_set_rate(&csiphy_dev->v4l2_dev_str.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");
+		goto csiphy_clk_enable_fail;
+	}
+
+	rc = msm_camera_enable_irq(csiphy_dev->irq, ENABLE_IRQ);
+	if (rc < 0) {
+		pr_err("%s:%d :ERROR: irq enable failed\n",
+			__func__, __LINE__);
+		goto csiphy_clk_enable_fail;
+		return -EINVAL;
+	}
+
+	cam_csiphy_reset(csiphy_dev);
+
+	return rc;
+csiphy_clk_enable_fail:
+	msm_camera_clk_enable(&csiphy_dev->v4l2_dev_str.pdev->dev,
+		csiphy_dev->csiphy_clk_info, csiphy_dev->csiphy_clk,
+		csiphy_dev->num_clk, false);
+csiphy_regulator_fail:
+	msm_camera_enable_vreg(&csiphy_dev->v4l2_dev_str.pdev->dev,
+		csiphy_dev->csiphy_vreg,
+		csiphy_dev->num_vreg, NULL, 0,
+		&csiphy_dev->csiphy_reg_ptr[0], 0);
+csiphy_config_regulator_fail:
+	msm_camera_config_vreg(&csiphy_dev->v4l2_dev_str.pdev->dev,
+		csiphy_dev->csiphy_vreg,
+		csiphy_dev->num_vreg, NULL, 0,
+		&csiphy_dev->csiphy_reg_ptr[0], 0);
+
+	return rc;
+}
+
+int32_t cam_csiphy_disable_hw(struct platform_device *pdev)
+{
+	struct csiphy_device *csiphy_dev =
+		platform_get_drvdata(pdev);
+
+	/*Disable regulators*/
+	msm_camera_enable_vreg(&csiphy_dev->v4l2_dev_str.pdev->dev,
+		csiphy_dev->csiphy_vreg,
+		csiphy_dev->num_vreg, NULL, 0,
+		&csiphy_dev->csiphy_reg_ptr[0], 0);
+
+	/*Disable clocks*/
+	msm_camera_clk_enable(&csiphy_dev->v4l2_dev_str.pdev->dev,
+		csiphy_dev->csiphy_clk_info, csiphy_dev->csiphy_clk,
+		csiphy_dev->num_clk, false);
+
+	/*Disable IRQ*/
+	msm_camera_enable_irq(csiphy_dev->irq, false);
+
+	return 0;
+
+}
+
+int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev,
+	struct csiphy_device *csiphy_dev)
+{
+	int32_t   rc = 0, i = 0;
+	uint32_t  clk_cnt = 0;
+	char      *csi_3p_clk_name = "csi_phy_3p_clk";
+	char      *csi_3p_clk_src_name = "csiphy_3p_clk_src";
+
+	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);
+	}
+
+	csiphy_dev->is_csiphy_3phase_hw = 0;
+	if (of_device_is_compatible(csiphy_dev->v4l2_dev_str.pdev->dev.of_node,
+		"qcom,csiphy-v1.0")) {
+		csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v1_0_reg;
+		csiphy_dev->ctrl_reg->csiphy_2ph_combo_mode_reg =
+			csiphy_2ph_v1_0_combo_mode_reg;
+		csiphy_dev->ctrl_reg->csiphy_3ph_reg = csiphy_3ph_v1_0_reg;
+		csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg =
+			csiphy_3ph_v1_0_combo_mode_reg;
+		csiphy_dev->ctrl_reg->csiphy_irq_reg = csiphy_irq_reg_1_0;
+		csiphy_dev->ctrl_reg->csiphy_common_reg = csiphy_common_reg_1_0;
+		csiphy_dev->ctrl_reg->csiphy_reset_reg = csiphy_reset_reg_1_0;
+		csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v1_0;
+		csiphy_dev->hw_version = CSIPHY_VERSION_V10;
+		csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW;
+		csiphy_dev->clk_lane = 0;
+	} else {
+		pr_err("%s:%d, invalid hw version : 0x%x\n", __func__, __LINE__,
+		csiphy_dev->hw_version);
+		rc =  -EINVAL;
+		return rc;
+	}
+
+	rc = msm_camera_get_clk_info(csiphy_dev->v4l2_dev_str.pdev,
+		&csiphy_dev->csiphy_clk_info,
+		&csiphy_dev->csiphy_clk,
+		&csiphy_dev->num_clk);
+	if (rc < 0) {
+		pr_err("%s:%d failed clock get\n", __func__, __LINE__);
+		return rc;
+	}
+
+	if (csiphy_dev->num_clk > CSIPHY_NUM_CLK_MAX) {
+		pr_err("%s: invalid clk count=%zu, max is %d\n", __func__,
+			csiphy_dev->num_clk, CSIPHY_NUM_CLK_MAX);
+		goto clk_mem_ovf_err;
+	}
+
+	for (i = 0; i < csiphy_dev->num_clk; i++) {
+		if (!strcmp(csiphy_dev->csiphy_clk_info[i].clk_name,
+			csi_3p_clk_src_name)) {
+			csiphy_dev->csiphy_3p_clk_info[0].clk_name =
+				csiphy_dev->csiphy_clk_info[i].clk_name;
+			csiphy_dev->csiphy_3p_clk_info[0].clk_rate =
+				csiphy_dev->csiphy_clk_info[i].clk_rate;
+			csiphy_dev->csiphy_3p_clk[0] =
+				csiphy_dev->csiphy_clk[i];
+			continue;
+		} else if (!strcmp(csiphy_dev->csiphy_clk_info[i].clk_name,
+					csi_3p_clk_name)) {
+			csiphy_dev->csiphy_3p_clk_info[1].clk_name =
+				csiphy_dev->csiphy_clk_info[i].clk_name;
+			csiphy_dev->csiphy_3p_clk_info[1].clk_rate =
+				csiphy_dev->csiphy_clk_info[i].clk_rate;
+			csiphy_dev->csiphy_3p_clk[1] =
+				csiphy_dev->csiphy_clk[i];
+			continue;
+		}
+
+		if (!strcmp(csiphy_dev->csiphy_clk_info[clk_cnt].clk_name,
+			"csiphy_timer_src_clk")) {
+			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++;
+	}
+
+	rc = cam_sensor_get_dt_vreg_data(pdev->dev.of_node,
+		&(csiphy_dev->csiphy_vreg), &(csiphy_dev->num_vreg));
+	if (rc < 0) {
+		pr_err("%s:%d Reg get failed\n", __func__, __LINE__);
+		csiphy_dev->num_vreg = 0;
+	}
+
+	csiphy_dev->base = msm_camera_get_reg_base(pdev, "csiphy", true);
+	if (!csiphy_dev->base) {
+		pr_err("%s: no mem resource?\n", __func__);
+		rc = -ENODEV;
+		goto csiphy_no_resource;
+	}
+
+	csiphy_dev->irq = msm_camera_get_irq(pdev, "csiphy");
+	if (!csiphy_dev->irq) {
+		pr_err("%s: no irq resource?\n", __func__);
+		rc = -ENODEV;
+		goto csiphy_no_resource;
+	}
+
+	rc = msm_camera_register_irq(pdev, csiphy_dev->irq,
+		cam_csiphy_irq, IRQF_TRIGGER_RISING, "csiphy", csiphy_dev);
+	if (rc < 0) {
+		pr_err("%s: irq request fail\n", __func__);
+		rc = -EBUSY;
+		goto csiphy_no_resource;
+	}
+	msm_camera_enable_irq(csiphy_dev->irq, false);
+	return rc;
+
+csiphy_no_resource:
+	msm_camera_put_reg_base(pdev, csiphy_dev->base, "csiphy", true);
+clk_mem_ovf_err:
+	msm_camera_put_clk_info(csiphy_dev->v4l2_dev_str.pdev,
+		&csiphy_dev->csiphy_clk_info,
+		&csiphy_dev->csiphy_clk,
+		csiphy_dev->num_clk);
+	return rc;
+}
+
+int32_t cam_csiphy_soc_release(struct csiphy_device *csiphy_dev)
+{
+
+	if (!csiphy_dev || !csiphy_dev->ref_count) {
+		pr_err("%s csiphy dev NULL / ref_count ZERO\n", __func__);
+		return 0;
+	}
+
+	if (--csiphy_dev->ref_count) {
+		pr_err("%s:%d csiphy refcount = %d\n", __func__,
+			__LINE__, csiphy_dev->ref_count);
+		return 0;
+	}
+
+	cam_csiphy_reset(csiphy_dev);
+
+	msm_camera_enable_irq(csiphy_dev->irq, false);
+
+	msm_camera_clk_enable(&csiphy_dev->v4l2_dev_str.pdev->dev,
+		csiphy_dev->csiphy_clk_info, csiphy_dev->csiphy_clk,
+		csiphy_dev->num_clk, false);
+
+	msm_camera_enable_vreg(&csiphy_dev->v4l2_dev_str.pdev->dev,
+		csiphy_dev->csiphy_vreg, csiphy_dev->num_vreg,
+		NULL, 0, &csiphy_dev->csiphy_reg_ptr[0], 0);
+
+	msm_camera_config_vreg(&csiphy_dev->v4l2_dev_str.pdev->dev,
+		csiphy_dev->csiphy_vreg, csiphy_dev->num_vreg,
+		NULL, 0, &csiphy_dev->csiphy_reg_ptr[0], 0);
+
+
+	return 0;
+}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h
new file mode 100644
index 0000000..27de3fc
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h
@@ -0,0 +1,63 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_CSIPHY_SOC_H_
+#define _CAM_CSIPHY_SOC_H_
+
+#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 <linux/ion.h>
+#include <linux/iommu.h>
+#include <linux/timer.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-subdev.h>
+#include "cam_csiphy_dev.h"
+#include "cam_csiphy_core.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+#define CSI_3PHASE_HW                               1
+#define CSIPHY_VERSION_V35                        0x35
+#define CSIPHY_VERSION_V10                        0x10
+
+/**
+ * @csiphy_dev: CSIPhy device structure
+ *
+ * This API release SOC related parameters
+ */
+int cam_csiphy_soc_release(struct csiphy_device *csiphy_dev);
+
+/**
+ * @pdev: Platform device
+ * @csiphy_dev: CSIPhy device structure
+ *
+ * This API parses csiphy device tree information
+ */
+int cam_csiphy_parse_dt_info(struct platform_device *pdev,
+	struct csiphy_device *csiphy_dev);
+
+/**
+ * @csiphy_dev: CSIPhy device structure
+ *
+ * This API enables SOC related parameters
+ */
+int cam_csiphy_enable_hw(struct csiphy_device *csiphy_dev);
+
+#endif /* _CAM_CSIPHY_SOC_H_ */
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
new file mode 100644
index 0000000..7a4aede
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h
@@ -0,0 +1,351 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_CSIPHY_1_0_HWREG_H_
+#define _CAM_CSIPHY_1_0_HWREG_H_
+
+#include "../cam_csiphy_dev.h"
+
+struct csiphy_reg_parms_t csiphy_v1_0 = {
+	.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_2ph_config_array_size = 14,
+	.csiphy_3ph_config_array_size = 19,
+};
+
+struct csiphy_reg_t csiphy_common_reg_1_0[] = {
+	{0x0814, 0x00, 0x00, CSIPHY_LANE_ENABLE},
+	{0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+	{0x081C, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS},
+};
+
+struct csiphy_reg_t csiphy_reset_reg_1_0[] = {
+	{0x0814, 0x00, 0x50, CSIPHY_LANE_ENABLE},
+	{0x0818, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+	{0x081C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+};
+
+struct csiphy_reg_t csiphy_irq_reg_1_0[] = {
+	{0x082c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS},
+	{0x0830, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS},
+	{0x0834, 0xFB, 0x00, CSIPHY_DEFAULT_PARAMS},
+	{0x0838, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS},
+	{0x083c, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
+	{0x0840, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS},
+	{0x0844, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS},
+	{0x0848, 0xEF, 0x00, CSIPHY_DEFAULT_PARAMS},
+	{0x084c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS},
+	{0x0850, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS},
+	{0x0854, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS},
+};
+
+struct csiphy_reg_t csiphy_2ph_v1_0_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = {
+	{
+		{0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS},
+		{0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0008, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
+		{0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS},
+		{0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0060, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0064, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
+	},
+	{
+		{0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0708, 0x14, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
+		{0x070C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0760, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0764, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
+	},
+	{
+		{0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS},
+		{0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0208, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
+		{0x020C, 0x00, 0x00, CSIPHY_DNP_PARAMS},
+		{0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0260, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0264, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
+	},
+	{
+		{0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0428, 0x00, 0x00, CSIPHY_DNP_PARAMS},
+		{0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0408, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
+		{0x040C, 0x00, 0x00, CSIPHY_DNP_PARAMS},
+		{0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0460, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0464, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
+	},
+	{
+		{0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0628, 0x00, 0x00, CSIPHY_DNP_PARAMS},
+		{0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0608, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
+		{0x060C, 0x00, 0x00, CSIPHY_DNP_PARAMS},
+		{0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0660, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0664, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
+	},
+};
+
+struct csiphy_reg_t
+	csiphy_2ph_v1_0_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = {
+	{
+		{0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0028, 0x0A, 0x00, CSIPHY_DNP_PARAMS},
+		{0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0008, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
+		{0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0060, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0064, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
+	},
+	{
+		{0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0708, 0x14, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
+		{0x070C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0760, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0764, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
+	},
+	{
+		{0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0228, 0x0A, 0x00, CSIPHY_DNP_PARAMS},
+		{0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0208, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
+		{0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0260, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0264, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
+	},
+	{
+		{0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0408, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
+		{0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0460, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0464, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
+	},
+	{
+		{0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0628, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0600, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0608, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
+		{0x060C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0638, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0660, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0664, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
+	},
+};
+
+struct csiphy_reg_t csiphy_3ph_v1_0_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = {
+	{
+		{0x015C, 0x63, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0168, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x016C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x010C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
+		{0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE},
+		{0x0114, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0150, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0118, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x011C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0120, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0124, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0128, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x012C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0144, 0x12, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0160, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0164, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x01DC, 0x51, 0x00, CSIPHY_DEFAULT_PARAMS},
+	},
+	{
+		{0x035C, 0x63, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0368, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x036C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x030C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
+		{0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE},
+		{0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0350, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0318, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x031C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0320, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0324, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0328, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x032C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0344, 0x12, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0360, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0364, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x03DC, 0x51, 0x00, CSIPHY_DEFAULT_PARAMS},
+	},
+	{
+		{0x055C, 0x63, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0568, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x056C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x050C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
+		{0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE},
+		{0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0550, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0518, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x051C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0520, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0524, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0528, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x052C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0544, 0x12, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0560, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0564, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x05DC, 0x51, 0x00, CSIPHY_DEFAULT_PARAMS},
+	},
+};
+
+struct csiphy_reg_t
+	csiphy_3ph_v1_0_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = {
+	{
+		{0x015C, 0x63, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0168, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x016C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x010C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
+		{0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE},
+		{0x0114, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0150, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0118, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x011C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0120, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0124, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0128, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x012C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0144, 0x12, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0160, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0164, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x01DC, 0x51, 0x00, CSIPHY_DEFAULT_PARAMS},
+	},
+	{
+		{0x035C, 0x63, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0368, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x036C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x030C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
+		{0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE},
+		{0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0350, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0318, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x031C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0320, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0324, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0328, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x032C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0344, 0x12, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0360, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0364, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x03DC, 0x51, 0x00, CSIPHY_DEFAULT_PARAMS},
+	},
+	{
+		{0x055C, 0x63, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0568, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x056C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x050C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
+		{0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE},
+		{0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0550, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0518, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x051C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0520, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0524, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0528, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x052C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0544, 0x12, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0560, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0564, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x05DC, 0x51, 0x00, CSIPHY_DEFAULT_PARAMS},
+	},
+};
+
+#endif /* _CAM_CSIPHY_1_0_HWREG_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/Makefile b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/Makefile
new file mode 100644
index 0000000..d8c75fb
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/Makefile
@@ -0,0 +1,8 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_cci
+
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_dev.o cam_sensor_core.o cam_sensor_soc.o
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
new file mode 100644
index 0000000..7a03bdc
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
@@ -0,0 +1,1002 @@
+/* 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/module.h>
+#include <cam_sensor_cmn_header.h>
+#include "cam_sensor_core.h"
+#include <cam_sensor_util.h>
+
+static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl,
+	void *arg)
+{
+	int32_t rc = 0;
+	uint64_t generic_ptr;
+	struct cam_control *ioctl_ctrl = NULL;
+	struct cam_packet *csl_packet = NULL;
+	struct cam_cmd_buf_desc *cmd_desc = NULL;
+	struct i2c_settings_array *i2c_reg_settings = NULL;
+	size_t len_of_buff = 0;
+	uint32_t *offset = NULL;
+	struct cam_config_dev_cmd config;
+	struct i2c_data_settings *i2c_data = NULL;
+	struct cam_req_mgr_add_request add_req;
+
+	ioctl_ctrl = (struct cam_control *)arg;
+
+	if (ioctl_ctrl->handle_type != CAM_HANDLE_USER_POINTER) {
+		pr_err("%s:%d :Error: Invalid Handle Type\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&config, (void __user *) ioctl_ctrl->handle,
+		sizeof(config)))
+		return -EFAULT;
+
+	rc = cam_mem_get_cpu_buf(
+		config.packet_handle,
+		(uint64_t *)&generic_ptr,
+		&len_of_buff);
+	if (rc < 0) {
+		pr_err("%s:%d :Error: Failed in getting the buffer: %d\n",
+			__func__, __LINE__, rc);
+		return rc;
+	}
+
+	csl_packet = (struct cam_packet *)(generic_ptr +
+		config.offset);
+	if (config.offset > len_of_buff) {
+		pr_err("%s: %d offset is out of bounds: off: %lld len: %zu\n",
+			__func__, __LINE__, config.offset, len_of_buff);
+		return -EINVAL;
+	}
+
+	i2c_data = &(s_ctrl->i2c_data);
+	CDBG("%s:%d Header OpCode: %d\n",
+		__func__, __LINE__, csl_packet->header.op_code);
+	if ((csl_packet->header.op_code & 0xFFFFFF) ==
+		CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG) {
+		i2c_reg_settings = &i2c_data->init_settings;
+		i2c_reg_settings->request_id = 0;
+		i2c_reg_settings->is_settings_valid = 1;
+	} else if ((csl_packet->header.op_code & 0xFFFFFF) ==
+		CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE) {
+		i2c_reg_settings =
+			&i2c_data->
+			per_frame[csl_packet->header.request_id %
+			MAX_PER_FRAME_ARRAY];
+		CDBG("%s:%d Received Packet: %lld\n", __func__, __LINE__,
+			csl_packet->header.request_id % MAX_PER_FRAME_ARRAY);
+		if (i2c_reg_settings->is_settings_valid == 1) {
+			pr_err("%s:%d :Error: Already some pkt in offset req : %lld\n",
+				__func__, __LINE__,
+				csl_packet->header.request_id);
+			rc = delete_request(i2c_reg_settings);
+			if (rc < 0) {
+				pr_err("%s: %d :Error: Failed in Deleting the err: %d\n",
+					__func__, __LINE__, rc);
+				return rc;
+			}
+		}
+
+		i2c_reg_settings->request_id =
+			csl_packet->header.request_id;
+		i2c_reg_settings->is_settings_valid = 1;
+	} else if ((csl_packet->header.op_code & 0xFFFFFF) ==
+		CAM_PKT_NOP_OPCODE) {
+		goto update_req_mgr;
+	} else {
+		pr_err("%s:%d Invalid Packet Header\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	offset = (uint32_t *)&csl_packet->payload;
+	offset += csl_packet->cmd_buf_offset / 4;
+	cmd_desc = (struct cam_cmd_buf_desc *)(offset);
+
+	rc = cam_sensor_i2c_pkt_parser(i2c_reg_settings, cmd_desc, 1);
+	if (rc < 0) {
+		pr_err("%s:%d :Error: Fail parsing I2C Pkt: %d\n",
+			__func__, __LINE__, rc);
+		return rc;
+	}
+
+update_req_mgr:
+	if (((csl_packet->header.op_code & 0xFFFFFF) ==
+		CAM_PKT_NOP_OPCODE) || (csl_packet->header.op_code ==
+		CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE)) {
+		add_req.link_hdl = s_ctrl->bridge_intf.link_hdl;
+		add_req.req_id = csl_packet->header.request_id;
+		CDBG("%s:%d Rxed Req Id: %lld\n",
+			__func__, __LINE__, csl_packet->header.request_id);
+		add_req.dev_hdl = s_ctrl->bridge_intf.device_hdl;
+		if (s_ctrl->bridge_intf.crm_cb &&
+			s_ctrl->bridge_intf.crm_cb->add_req)
+			s_ctrl->bridge_intf.crm_cb->add_req(&add_req);
+		CDBG("%s:%d add req to req mgr: %lld\n",
+			__func__, __LINE__, add_req.req_id);
+	}
+	return rc;
+}
+
+int32_t cam_sensor_update_i2c_info(struct cam_cmd_i2c_info *i2c_info,
+	struct cam_sensor_ctrl_t *s_ctrl)
+{
+	int32_t rc = 0;
+	struct cam_sensor_cci_client   *cci_client = NULL;
+
+	if (s_ctrl->io_master_info.master_type == CCI_MASTER) {
+		cci_client = s_ctrl->io_master_info.cci_client;
+		if (!cci_client) {
+			pr_err("failed: cci_client %pK", cci_client);
+			return -EINVAL;
+		}
+		cci_client->cci_i2c_master = s_ctrl->cci_i2c_master;
+		cci_client->sid = i2c_info->slave_addr >> 1;
+		cci_client->retries = 3;
+		cci_client->id_map = 0;
+		cci_client->i2c_freq_mode = i2c_info->i2c_freq_mode;
+		CDBG("%s:%d Master: %d sid: %d freq_mode: %d\n",
+			__func__, __LINE__,
+			cci_client->cci_i2c_master, i2c_info->slave_addr,
+			i2c_info->i2c_freq_mode);
+	}
+
+	return rc;
+}
+
+int32_t cam_sensor_update_slave_info(struct cam_cmd_probe *probe_info,
+	struct cam_sensor_ctrl_t *s_ctrl)
+{
+	int32_t rc = 0;
+
+	s_ctrl->sensordata->slave_info.sensor_id_reg_addr =
+		probe_info->reg_addr;
+	s_ctrl->sensordata->slave_info.sensor_id =
+		probe_info->expected_data;
+	s_ctrl->sensordata->slave_info.sensor_id_mask =
+		probe_info->data_mask;
+
+	s_ctrl->sensor_probe_addr_type =  probe_info->addr_type;
+	s_ctrl->sensor_probe_data_type =  probe_info->data_type;
+	CDBG("%s:%d Sensor Addr: 0x%x sensor_id: 0x%x sensor_mask: 0x%x\n",
+		__func__, __LINE__,
+		s_ctrl->sensordata->slave_info.sensor_id_reg_addr,
+		s_ctrl->sensordata->slave_info.sensor_id,
+		s_ctrl->sensordata->slave_info.sensor_id_mask);
+	return rc;
+}
+
+int32_t cam_sensor_update_power_settings(void *cmd_buf,
+	int cmd_length, struct cam_sensor_ctrl_t *s_ctrl)
+{
+	int32_t rc = 0, tot_size = 0, last_cmd_type = 0;
+	int32_t i = 0, pwr_up = 0, pwr_down = 0;
+	void *ptr = cmd_buf, *scr;
+	struct cam_cmd_power *pwr_cmd = (struct cam_cmd_power *)cmd_buf;
+	struct common_header *cmm_hdr = (struct common_header *)cmd_buf;
+	struct cam_sensor_power_ctrl_t *power_info =
+		&s_ctrl->sensordata->power_info;
+
+	if (!pwr_cmd || !cmd_length) {
+		pr_err("%s:%d Invalid Args: pwr_cmd %pK, cmd_length: %d\n",
+			__func__, __LINE__, pwr_cmd, cmd_length);
+		return -EINVAL;
+	}
+
+	power_info->power_setting_size = 0;
+	power_info->power_setting =
+		(struct cam_sensor_power_setting *)
+		kzalloc(sizeof(struct cam_sensor_power_setting) *
+			MAX_POWER_CONFIG, GFP_KERNEL);
+	if (!power_info->power_setting)
+		return -ENOMEM;
+
+	power_info->power_down_setting =
+		(struct cam_sensor_power_setting *)
+		kzalloc(sizeof(struct cam_sensor_power_setting) *
+			MAX_POWER_CONFIG, GFP_KERNEL);
+	if (!power_info->power_down_setting) {
+		rc = -ENOMEM;
+		goto free_power_settings;
+	}
+
+	while (tot_size < cmd_length) {
+		if (cmm_hdr->cmd_type ==
+			CAMERA_SENSOR_CMD_TYPE_PWR_UP) {
+			struct cam_cmd_power *pwr_cmd =
+				(struct cam_cmd_power *)ptr;
+
+			power_info->
+				power_setting_size +=
+				pwr_cmd->count;
+			scr = ptr + sizeof(struct cam_cmd_power);
+			tot_size = tot_size + sizeof(struct cam_cmd_power);
+
+			if (pwr_cmd->count == 0)
+				CDBG("%s:%d Un expected Command\n",
+					__func__, __LINE__);
+
+			for (i = 0; i < pwr_cmd->count; i++, pwr_up++) {
+				power_info->
+					power_setting[pwr_up].seq_type =
+					pwr_cmd->power_settings[i].
+						power_seq_type;
+				power_info->
+					power_setting[pwr_up].config_val =
+					pwr_cmd->power_settings[i].
+						config_val_low;
+				power_info->power_setting[pwr_up].delay = 0;
+				if (i) {
+					scr = scr +
+						sizeof(
+						struct cam_power_settings);
+					tot_size = tot_size +
+						sizeof(
+						struct cam_power_settings);
+				}
+				if (tot_size > cmd_length) {
+					pr_err("%s:%d :Error: Command Buffer is wrong\n",
+						__func__, __LINE__);
+					rc = -EINVAL;
+					goto free_power_down_settings;
+				}
+				CDBG("Seq Type[%d]: %d Config_val: %ldn",
+					pwr_up,
+					power_info->
+						power_setting[pwr_up].seq_type,
+					power_info->
+						power_setting[pwr_up].
+						config_val);
+			}
+			last_cmd_type = CAMERA_SENSOR_CMD_TYPE_PWR_UP;
+			ptr = (void *) scr;
+			cmm_hdr = (struct common_header *)ptr;
+		} else if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_WAIT) {
+			struct cam_cmd_unconditional_wait *wait_cmd =
+				(struct cam_cmd_unconditional_wait *)ptr;
+			if (wait_cmd->op_code ==
+				CAMERA_SENSOR_WAIT_OP_SW_UCND) {
+				if (last_cmd_type ==
+					CAMERA_SENSOR_CMD_TYPE_PWR_UP) {
+					if (pwr_up > 0)
+						power_info->
+							power_setting
+							[pwr_up - 1].delay +=
+							wait_cmd->delay;
+					else
+						pr_err("%s:%d Delay is expected only after valid power up setting\n",
+							__func__, __LINE__);
+				} else if (last_cmd_type ==
+					CAMERA_SENSOR_CMD_TYPE_PWR_DOWN) {
+					if (pwr_down > 0)
+						power_info->
+							power_down_setting
+							[pwr_down - 1].delay +=
+							wait_cmd->delay;
+					else
+						pr_err("%s:%d Delay is expected only after valid power down setting\n",
+							__func__, __LINE__);
+				}
+			} else
+				CDBG("%s:%d Invalid op code: %d\n",
+					__func__, __LINE__, wait_cmd->op_code);
+			tot_size = tot_size +
+				sizeof(struct cam_cmd_unconditional_wait);
+			if (tot_size > cmd_length) {
+				pr_err("Command Buffer is wrong\n");
+				return -EINVAL;
+			}
+			scr = (void *) (wait_cmd);
+			ptr = (void *)
+				(scr +
+				sizeof(struct cam_cmd_unconditional_wait));
+			CDBG("%s:%d ptr: %pK sizeof: %d Next: %pK\n",
+				__func__, __LINE__, scr,
+				(int32_t)sizeof(
+				struct cam_cmd_unconditional_wait), ptr);
+
+			cmm_hdr = (struct common_header *)ptr;
+		} else if (cmm_hdr->cmd_type ==
+			CAMERA_SENSOR_CMD_TYPE_PWR_DOWN) {
+			struct cam_cmd_power *pwr_cmd =
+				(struct cam_cmd_power *)ptr;
+
+			scr = ptr + sizeof(struct cam_cmd_power);
+			tot_size = tot_size + sizeof(struct cam_cmd_power);
+			power_info->power_down_setting_size += pwr_cmd->count;
+
+			if (pwr_cmd->count == 0)
+				pr_err("%s:%d Invalid Command\n",
+					__func__, __LINE__);
+
+			for (i = 0; i < pwr_cmd->count; i++, pwr_down++) {
+				power_info->
+					power_down_setting[pwr_down].
+					seq_type =
+					pwr_cmd->power_settings[i].
+					power_seq_type;
+				power_info->
+					power_down_setting[pwr_down].
+					config_val =
+					pwr_cmd->power_settings[i].
+					config_val_low;
+				power_info->
+					power_down_setting[pwr_down].delay = 0;
+				if (i) {
+					scr = scr +
+						sizeof(
+						struct cam_power_settings);
+					tot_size =
+						tot_size +
+						sizeof(
+						struct cam_power_settings);
+				}
+				if (tot_size > cmd_length) {
+					pr_err("Command Buffer is wrong\n");
+					rc = -EINVAL;
+					goto free_power_down_settings;
+				}
+				CDBG("%s:%d Seq Type[%d]: %d Config_val: %ldn",
+					__func__, __LINE__,
+					pwr_down,
+					power_info->
+						power_down_setting[pwr_down].
+						seq_type,
+					power_info->
+						power_down_setting[pwr_down].
+						config_val);
+			}
+			last_cmd_type = CAMERA_SENSOR_CMD_TYPE_PWR_DOWN;
+			ptr = (void *) scr;
+			cmm_hdr = (struct common_header *)ptr;
+		} else {
+			pr_err("%s:%d: :Error: Un expected Header Type: %d\n",
+				__func__, __LINE__, cmm_hdr->cmd_type);
+		}
+	}
+
+	return rc;
+free_power_down_settings:
+	kfree(power_info->power_down_setting);
+free_power_settings:
+	kfree(power_info->power_setting);
+	return rc;
+}
+
+int32_t cam_handle_cmd_buffers_for_probe(void *cmd_buf,
+	struct cam_sensor_ctrl_t *s_ctrl,
+	int32_t cmd_buf_num, int cmd_buf_length)
+{
+	int32_t rc = 0;
+
+	switch (cmd_buf_num) {
+	case 0: {
+		struct cam_cmd_i2c_info *i2c_info = NULL;
+		struct cam_cmd_probe *probe_info;
+
+		i2c_info = (struct cam_cmd_i2c_info *)cmd_buf;
+		rc = cam_sensor_update_i2c_info(i2c_info, s_ctrl);
+		if (rc < 0) {
+			pr_err("%s:%d Failed in Updating the i2c Info\n",
+				__func__, __LINE__);
+			return rc;
+		}
+		probe_info = (struct cam_cmd_probe *)
+			(cmd_buf + sizeof(struct cam_cmd_i2c_info));
+		rc = cam_sensor_update_slave_info(probe_info, s_ctrl);
+		if (rc < 0) {
+			pr_err("%s:%d :Error: Updating the slave Info\n",
+				__func__, __LINE__);
+			return rc;
+		}
+		cmd_buf = probe_info;
+	}
+		break;
+	case 1: {
+		rc = cam_sensor_update_power_settings(cmd_buf,
+			cmd_buf_length, s_ctrl);
+		if (rc < 0) {
+			pr_err("Failed in updating power settings\n");
+			return rc;
+		}
+	}
+		break;
+	default:
+		pr_err("%s:%d Invalid command buffer\n",
+			__func__, __LINE__);
+		break;
+	}
+	return rc;
+}
+
+int32_t cam_handle_mem_ptr(uint64_t handle, struct cam_sensor_ctrl_t *s_ctrl)
+{
+	int rc = 0, i;
+	void *packet = NULL, *cmd_buf1 = NULL;
+	uint32_t *cmd_buf;
+	void *ptr;
+	size_t len;
+	struct cam_packet *pkt;
+	struct cam_cmd_buf_desc *cmd_desc;
+
+	rc = cam_mem_get_cpu_buf(handle,
+		(uint64_t *)&packet, &len);
+	if (rc < 0) {
+		pr_err("%s: %d Failed to get the command Buffer\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+	pkt = (struct cam_packet *)packet;
+	cmd_desc = (struct cam_cmd_buf_desc *)
+		((uint32_t *)&pkt->payload + pkt->cmd_buf_offset/4);
+	if (cmd_desc == NULL) {
+		pr_err("%s: %d command descriptor pos is invalid\n",
+		__func__, __LINE__);
+		return -EINVAL;
+	}
+	if (pkt->num_cmd_buf != 2) {
+		pr_err("%s: %d Expected More Command Buffers : %d\n",
+			__func__, __LINE__, pkt->num_cmd_buf);
+		return -EINVAL;
+	}
+	for (i = 0; i < pkt->num_cmd_buf; i++) {
+		if (!(cmd_desc[i].length))
+			continue;
+		rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle,
+			(uint64_t *)&cmd_buf1, &len);
+		if (rc < 0) {
+			pr_err("%s: %d Failed to parse the command Buffer Header\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		cmd_buf = (uint32_t *)cmd_buf1;
+		cmd_buf += cmd_desc[i].offset/4;
+		ptr = (void *) cmd_buf;
+
+		rc = cam_handle_cmd_buffers_for_probe(ptr, s_ctrl,
+			i, cmd_desc[i].length);
+		if (rc < 0) {
+			pr_err("%s: %d Failed to parse the command Buffer Header\n",
+			__func__, __LINE__);
+			return -EINVAL;
+		}
+	}
+	return rc;
+}
+
+void cam_sensor_query_cap(struct cam_sensor_ctrl_t *s_ctrl,
+	struct  cam_sensor_query_cap *query_cap)
+{
+	query_cap->pos_roll = s_ctrl->sensordata->pos_roll;
+	query_cap->pos_pitch = s_ctrl->sensordata->pos_pitch;
+	query_cap->pos_yaw = s_ctrl->sensordata->pos_yaw;
+	query_cap->secure_camera = 0;
+	query_cap->actuator_slot_id =
+		s_ctrl->sensordata->subdev_id[SUB_MODULE_ACTUATOR];
+	query_cap->csiphy_slot_id =
+		s_ctrl->sensordata->subdev_id[SUB_MODULE_CSIPHY];
+	query_cap->eeprom_slot_id =
+		s_ctrl->sensordata->subdev_id[SUB_MODULE_EEPROM];
+	query_cap->flash_slot_id =
+		s_ctrl->sensordata->subdev_id[SUB_MODULE_LED_FLASH];
+	query_cap->ois_slot_id =
+		s_ctrl->sensordata->subdev_id[SUB_MODULE_OIS];
+	query_cap->slot_info =
+		s_ctrl->id;
+}
+
+static uint16_t cam_sensor_id_by_mask(struct cam_sensor_ctrl_t *s_ctrl,
+	uint32_t chipid)
+{
+	uint16_t sensor_id = (uint16_t)(chipid & 0xFFFF);
+	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 cam_sensor_match_id(struct cam_sensor_ctrl_t *s_ctrl)
+{
+	int rc = 0;
+	uint32_t chipid = 0;
+	struct cam_camera_slave_info *slave_info;
+
+	slave_info = &(s_ctrl->sensordata->slave_info);
+
+	if (!slave_info) {
+		pr_err("%s:%d failed: %pK\n",
+			__func__, __LINE__, slave_info);
+		return -EINVAL;
+	}
+
+	rc = camera_io_dev_read(
+		&(s_ctrl->io_master_info),
+		slave_info->sensor_id_reg_addr,
+		&chipid, CAMERA_SENSOR_I2C_TYPE_WORD);
+
+	CDBG("%s:%d read id: 0x%x expected id 0x%x:\n",
+			__func__, __LINE__, chipid, slave_info->sensor_id);
+	if (cam_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;
+}
+
+int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl,
+	void *arg)
+{
+	int rc = 0;
+	struct cam_control *cmd = (struct cam_control *)arg;
+	struct cam_sensor_power_setting *pu = NULL;
+	struct cam_sensor_power_setting *pd = NULL;
+	struct cam_sensor_power_ctrl_t *power_info =
+		&s_ctrl->sensordata->power_info;
+
+	if (!s_ctrl || !arg) {
+		pr_err("%s: %d s_ctrl is NULL\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&(s_ctrl->cam_sensor_mutex));
+	switch (cmd->op_code) {
+	case CAM_SENSOR_PROBE_CMD: {
+		if (s_ctrl->is_probe_succeed == 1) {
+			pr_err("Already Sensor Probed in the slot\n");
+			break;
+		}
+		/* Allocate memory for power up setting */
+		pu = kzalloc(sizeof(struct cam_sensor_power_setting) *
+			MAX_POWER_CONFIG, GFP_KERNEL);
+		if (!pu) {
+			rc = -ENOMEM;
+			goto release_mutex;
+		}
+
+		pd = kzalloc(sizeof(struct cam_sensor_power_setting) *
+			MAX_POWER_CONFIG, GFP_KERNEL);
+		if (!pd) {
+			kfree(pu);
+			rc = -ENOMEM;
+			goto release_mutex;
+		}
+
+		power_info->power_setting = pu;
+		power_info->power_down_setting = pd;
+
+		if (cmd->handle_type ==
+			CAM_HANDLE_MEM_HANDLE) {
+			rc = cam_handle_mem_ptr(cmd->handle, s_ctrl);
+			if (rc < 0) {
+				pr_err("%s: %d Get Buffer Handle Failed\n",
+					__func__, __LINE__);
+				kfree(pu);
+				kfree(pd);
+				goto release_mutex;
+			}
+		} else {
+			pr_err("%s:%d :Error: Invalid Command Type: %d",
+				__func__, __LINE__, cmd->handle_type);
+		}
+
+		/* 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("%s:%d :Error: Fail in filling vreg params for PUP rc %d",
+				__func__, __LINE__, rc);
+			kfree(pu);
+			kfree(pd);
+			goto release_mutex;
+		}
+
+		/* 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("%s:%d :Error: Fail in filling vreg params for PDOWN rc %d",
+				__func__, __LINE__, rc);
+			kfree(pu);
+			kfree(pd);
+			goto release_mutex;
+		}
+
+		/* Power up and probe sensor */
+		rc = cam_sensor_power_up(s_ctrl);
+		if (rc < 0) {
+			pr_err("power up failed");
+			cam_sensor_power_down(s_ctrl);
+			kfree(pu);
+			kfree(pd);
+			goto release_mutex;
+		}
+
+		/* Match sensor ID */
+		rc = cam_sensor_match_id(s_ctrl);
+		if (rc < 0) {
+			cam_sensor_power_down(s_ctrl);
+			msleep(20);
+			kfree(pu);
+			kfree(pd);
+			goto release_mutex;
+		}
+
+		CDBG("%s:%d Probe Succeeded on the slot: %d\n",
+			__func__, __LINE__, s_ctrl->id);
+		rc = cam_sensor_power_down(s_ctrl);
+		if (rc < 0) {
+			pr_err("%s:%d :Error: fail in Sensor Power Down\n",
+				__func__, __LINE__);
+			kfree(pu);
+			kfree(pd);
+			goto release_mutex;
+		}
+		/*
+		 * Set probe succeeded flag to 1 so that no other camera shall
+		 * probed on this slot
+		 */
+		s_ctrl->is_probe_succeed = 1;
+	}
+		break;
+	case CAM_ACQUIRE_DEV: {
+		struct cam_sensor_acquire_dev sensor_acq_dev;
+		struct cam_create_dev_hdl bridge_params;
+
+		if (s_ctrl->bridge_intf.device_hdl != -1) {
+			pr_err("%s:%d Device is already acquired\n",
+				__func__, __LINE__);
+			rc = -EINVAL;
+			goto release_mutex;
+		}
+		rc = copy_from_user(&sensor_acq_dev,
+			(void __user *) cmd->handle, sizeof(sensor_acq_dev));
+		if (rc < 0) {
+			pr_err("Failed Copying from user\n");
+			goto release_mutex;
+		}
+
+		bridge_params.session_hdl = sensor_acq_dev.session_handle;
+		bridge_params.ops = &s_ctrl->bridge_intf.ops;
+		bridge_params.v4l2_sub_dev_flag = 0;
+		bridge_params.media_entity_flag = 0;
+		bridge_params.priv = s_ctrl;
+
+		sensor_acq_dev.device_handle =
+			cam_create_device_hdl(&bridge_params);
+		s_ctrl->bridge_intf.device_hdl = sensor_acq_dev.device_handle;
+		s_ctrl->bridge_intf.session_hdl = sensor_acq_dev.session_handle;
+
+		CDBG("%s:%d Device Handle: %d\n", __func__, __LINE__,
+			sensor_acq_dev.device_handle);
+		if (copy_to_user((void __user *) cmd->handle, &sensor_acq_dev,
+			sizeof(struct cam_sensor_acquire_dev))) {
+			pr_err("Failed Copy to User\n");
+			rc = -EFAULT;
+			goto release_mutex;
+		}
+	}
+		break;
+	case CAM_RELEASE_DEV: {
+		if (s_ctrl->bridge_intf.device_hdl == -1) {
+			pr_err("%s:%d Invalid Handles: link hdl: %d device hdl: %d\n",
+				__func__, __LINE__,
+				s_ctrl->bridge_intf.device_hdl,
+				s_ctrl->bridge_intf.link_hdl);
+			rc = -EINVAL;
+			goto release_mutex;
+		}
+		rc = cam_destroy_device_hdl(s_ctrl->bridge_intf.device_hdl);
+		if (rc < 0)
+			pr_err("%s:%d Failed in destroying the device hdl\n",
+			__func__, __LINE__);
+		s_ctrl->bridge_intf.device_hdl = -1;
+		s_ctrl->bridge_intf.link_hdl = -1;
+		s_ctrl->bridge_intf.session_hdl = -1;
+	}
+		break;
+	case CAM_QUERY_CAP: {
+		struct  cam_sensor_query_cap sensor_cap;
+
+		cam_sensor_query_cap(s_ctrl, &sensor_cap);
+		if (copy_to_user((void __user *) cmd->handle, &sensor_cap,
+			sizeof(struct  cam_sensor_query_cap))) {
+			pr_err("Failed Copy to User\n");
+			rc = -EFAULT;
+			goto release_mutex;
+		}
+		break;
+	}
+	case CAM_START_DEV: {
+		rc = cam_sensor_power_up(s_ctrl);
+		if (rc < 0) {
+			pr_err("%s:%d :Error: Sensor Power up failed\n",
+				__func__, __LINE__);
+			goto release_mutex;
+		}
+		rc = cam_sensor_apply_settings(s_ctrl, 0);
+		if (rc < 0) {
+			pr_err("cannot apply settings\n");
+			goto release_mutex;
+		}
+		rc = delete_request(&s_ctrl->i2c_data.init_settings);
+		if (rc < 0) {
+			pr_err("%s:%d Fail in deleting the Init settings\n",
+				__func__, __LINE__);
+			rc = -EINVAL;
+			goto release_mutex;
+		}
+	}
+		break;
+	case CAM_STOP_DEV: {
+		rc = cam_sensor_power_down(s_ctrl);
+		if (rc < 0) {
+			pr_err("%s:%d Sensor Power Down failed\n",
+				__func__, __LINE__);
+			goto release_mutex;
+		}
+	}
+		break;
+	case CAM_CONFIG_DEV: {
+		rc = cam_sensor_i2c_pkt_parse(s_ctrl, arg);
+		if (rc < 0) {
+			pr_err("%s:%d :Error: Failed CCI Config: %d\n",
+				__func__, __LINE__, rc);
+			goto release_mutex;
+		}
+	}
+		break;
+	default:
+		pr_err("%s:%d :Error: Invalid Opcode: %d\n",
+			__func__, __LINE__, cmd->op_code);
+		rc = -EINVAL;
+		goto release_mutex;
+	}
+
+release_mutex:
+	mutex_unlock(&(s_ctrl->cam_sensor_mutex));
+	return rc;
+}
+
+int cam_sensor_publish_dev_info(struct cam_req_mgr_device_info *info)
+{
+	int rc = 0;
+
+	if (!info)
+		return -EINVAL;
+
+	info->dev_id = CAM_REQ_MGR_DEVICE_SENSOR;
+	strlcpy(info->name, CAM_SENSOR_NAME, sizeof(info->name));
+	info->p_delay = 2;
+
+	return rc;
+}
+
+int cam_sensor_establish_link(struct cam_req_mgr_core_dev_link_setup *link)
+{
+	struct cam_sensor_ctrl_t *s_ctrl = NULL;
+
+	if (!link)
+		return -EINVAL;
+
+	s_ctrl = (struct cam_sensor_ctrl_t *)
+		cam_get_device_priv(link->dev_hdl);
+	if (!s_ctrl) {
+		pr_err("%s: Device data is NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (link->link_enable) {
+		s_ctrl->bridge_intf.link_hdl = link->link_hdl;
+		s_ctrl->bridge_intf.crm_cb = link->crm_cb;
+	} else {
+		s_ctrl->bridge_intf.link_hdl = -1;
+		s_ctrl->bridge_intf.crm_cb = NULL;
+	}
+
+	return 0;
+}
+
+int cam_sensor_power(struct v4l2_subdev *sd, int on)
+{
+	struct cam_sensor_ctrl_t *s_ctrl = v4l2_get_subdevdata(sd);
+
+	mutex_lock(&(s_ctrl->cam_sensor_mutex));
+	if (!on && s_ctrl->sensor_state == CAM_SENSOR_POWER_UP) {
+		cam_sensor_power_down(s_ctrl);
+		s_ctrl->sensor_state = CAM_SENSOR_POWER_DOWN;
+	}
+	mutex_unlock(&(s_ctrl->cam_sensor_mutex));
+
+	return 0;
+}
+
+int cam_sensor_power_up(struct cam_sensor_ctrl_t *s_ctrl)
+{
+	int rc;
+	struct cam_sensor_power_ctrl_t *power_info;
+	struct cam_camera_slave_info *slave_info;
+
+	if (!s_ctrl) {
+		pr_err("%s:%d failed: %pK\n",
+			__func__, __LINE__, s_ctrl);
+		return -EINVAL;
+	}
+
+	power_info = &s_ctrl->sensordata->power_info;
+	slave_info = &(s_ctrl->sensordata->slave_info);
+
+	if (!power_info || !slave_info) {
+		pr_err("%s:%d failed: %pK %pK\n",
+			__func__, __LINE__, power_info,
+			slave_info);
+		return -EINVAL;
+	}
+
+	rc = cam_sensor_core_power_up(power_info);
+	if (rc < 0) {
+		pr_err("%s:%d power up the core is failed:%d\n",
+			__func__, __LINE__, rc);
+		return rc;
+	}
+
+	if (s_ctrl->io_master_info.master_type == CCI_MASTER) {
+		rc = camera_io_init(&(s_ctrl->io_master_info));
+		if (rc < 0) {
+			pr_err("%s cci_init failed\n", __func__);
+			return -EINVAL;
+		}
+	}
+
+	s_ctrl->sensor_state = CAM_SENSOR_POWER_UP;
+
+	return rc;
+}
+
+int cam_sensor_power_down(struct cam_sensor_ctrl_t *s_ctrl)
+{
+	struct cam_sensor_power_ctrl_t *power_info;
+	int rc = 0;
+
+	if (!s_ctrl) {
+		pr_err("%s:%d failed: s_ctrl %pK\n",
+			__func__, __LINE__, s_ctrl);
+		return -EINVAL;
+	}
+
+	power_info = &s_ctrl->sensordata->power_info;
+
+	if (!power_info) {
+		pr_err("%s:%d failed: power_info %pK\n",
+			__func__, __LINE__, power_info);
+		return -EINVAL;
+	}
+	rc = msm_camera_power_down(power_info);
+	if (rc < 0) {
+		pr_err("%s:%d power down the core is failed:%d\n",
+			__func__, __LINE__, rc);
+		return rc;
+	}
+
+	if (s_ctrl->io_master_info.master_type == CCI_MASTER)
+		camera_io_release(&(s_ctrl->io_master_info));
+
+	s_ctrl->sensor_state = CAM_SENSOR_POWER_DOWN;
+
+	return rc;
+}
+
+int cam_sensor_apply_settings(struct cam_sensor_ctrl_t *s_ctrl,
+	int64_t req_id)
+{
+	int rc = 0, offset, del_req_id;
+	struct i2c_settings_array *i2c_set = NULL;
+	struct i2c_settings_list *i2c_list;
+
+	if (req_id == 0) {
+		i2c_set = &s_ctrl->i2c_data.init_settings;
+		if (i2c_set->is_settings_valid == 1) {
+			list_for_each_entry(i2c_list,
+				&(i2c_set->list_head), list) {
+				rc = camera_io_dev_write(
+					&(s_ctrl->io_master_info),
+					&(i2c_list->i2c_settings));
+				if (rc < 0) {
+					pr_err("Failed to write the I2C settings\n");
+					return rc;
+				}
+			}
+			rc = delete_request(&(s_ctrl->i2c_data.init_settings));
+			i2c_set->is_settings_valid = 0;
+			if (rc < 0) {
+				pr_err("%s:%d :Error: Failed in deleting the Init request: %d\n",
+					__func__, __LINE__, rc);
+			}
+		}
+	} else {
+		offset = req_id % MAX_PER_FRAME_ARRAY;
+		i2c_set = &(s_ctrl->i2c_data.per_frame[offset]);
+		if (i2c_set->is_settings_valid == 1 &&
+			i2c_set->request_id == req_id) {
+			list_for_each_entry(i2c_list,
+				&(i2c_set->list_head), list) {
+				rc = camera_io_dev_write(
+					&(s_ctrl->io_master_info),
+					&(i2c_list->i2c_settings));
+				if (rc < 0) {
+					pr_err("%s:%d :Error: Fail to write the I2C settings: %d\n",
+						__func__, __LINE__, rc);
+					return rc;
+				}
+			}
+			del_req_id = (req_id +
+				MAX_PER_FRAME_ARRAY -
+				MAX_SYSTEM_PIPELINE_DELAY) %
+				MAX_PER_FRAME_ARRAY;
+			CDBG("%s:%d Deleting the Request: %d\n",
+				__func__, __LINE__,	del_req_id);
+			if (req_id >
+				s_ctrl->i2c_data.per_frame[del_req_id].
+				request_id) {
+				s_ctrl->i2c_data.per_frame[del_req_id].
+					request_id = 0;
+				rc = delete_request(
+					&(s_ctrl->i2c_data.
+					per_frame[del_req_id]));
+				if (rc < 0)
+					pr_err("%s:%d :Error: Failed in deleting the request: %d rc: %d\n",
+						__func__, __LINE__,
+						del_req_id, rc);
+			}
+		} else {
+			pr_err("%s:%d Invalid/NOP request to apply: %lld\n",
+				__func__, __LINE__, req_id);
+		}
+	}
+	return rc;
+}
+
+int32_t cam_sensor_apply_request(struct cam_req_mgr_apply_request *apply)
+{
+	int32_t rc = 0;
+	struct cam_sensor_ctrl_t *s_ctrl = NULL;
+
+	if (!apply)
+		return -EINVAL;
+
+	s_ctrl = (struct cam_sensor_ctrl_t *)
+		cam_get_device_priv(apply->dev_hdl);
+	if (!s_ctrl) {
+		pr_err("%s: Device data is NULL\n", __func__);
+		return -EINVAL;
+	}
+	CDBG("%s:%d Req Id: %lld\n", __func__, __LINE__,
+		apply->request_id);
+	rc = cam_sensor_apply_settings(s_ctrl, apply->request_id);
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.h
new file mode 100644
index 0000000..b23edce
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.h
@@ -0,0 +1,77 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_SENSOR_CORE_H_
+#define _CAM_SENSOR_CORE_H_
+
+#include "cam_sensor_dev.h"
+
+/**
+ * @s_ctrl: Sensor ctrl structure
+ *
+ * This API powers up the camera sensor module
+ */
+int cam_sensor_power_up(struct cam_sensor_ctrl_t *s_ctrl);
+
+/**
+ * @s_ctrl: Sensor ctrl structure
+ *
+ * This API powers down the camera sensor module
+ */
+int cam_sensor_power_down(struct cam_sensor_ctrl_t *s_ctrl);
+
+/**
+ * @sd: V4L2 subdevice
+ * @on: Turn off/on flag
+ *
+ * This API powers down the sensor module
+ */
+int cam_sensor_power(struct v4l2_subdev *sd, int on);
+
+/**
+ * @s_ctrl: Sensor ctrl structure
+ * @req_id: Request id
+ *
+ * This API applies the req_id settings to sensor
+ */
+int cam_sensor_apply_settings(struct cam_sensor_ctrl_t *s_ctrl, int64_t req_id);
+
+/**
+ * @apply: Req mgr structure for applying request
+ *
+ * This API applies the request that is mentioned
+ */
+int cam_sensor_apply_request(struct cam_req_mgr_apply_request *apply);
+
+/**
+ * @info: Sub device info to req mgr
+ *
+ * Publish the subdevice info
+ */
+int cam_sensor_publish_dev_info(struct cam_req_mgr_device_info *info);
+
+/**
+ * @link: Link setup info
+ *
+ * This API establishes link with sensor subdevice with req mgr
+ */
+int cam_sensor_establish_link(struct cam_req_mgr_core_dev_link_setup *link);
+
+/**
+ * @s_ctrl: Sensor ctrl structure
+ * @arg:    Camera control command argument
+ *
+ * This API handles the camera control argument reached to sensor
+ */
+int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, void *arg);
+
+#endif /* _CAM_SENSOR_CORE_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.c
new file mode 100644
index 0000000..448ce51
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.c
@@ -0,0 +1,294 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "cam_sensor_dev.h"
+#include "cam_req_mgr_dev.h"
+#include "cam_sensor_soc.h"
+#include "cam_sensor_core.h"
+
+static long cam_sensor_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	int rc = 0;
+	struct cam_sensor_ctrl_t *s_ctrl =
+		v4l2_get_subdevdata(sd);
+
+	switch (cmd) {
+	case VIDIOC_CAM_CONTROL:
+		rc = cam_sensor_driver_cmd(s_ctrl, arg);
+		break;
+	default:
+		pr_err("%s:%d Invalid ioctl cmd: %d\n",
+			__func__, __LINE__, cmd);
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+static int32_t cam_sensor_driver_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int32_t rc = 0;
+	struct cam_sensor_ctrl_t *s_ctrl;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_err("%s %s :Error: i2c_check_functionality failed\n",
+			__func__, client->name);
+		return -EFAULT;
+	}
+
+	/* 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->of_node = client->dev.of_node;
+	s_ctrl->io_master_info.master_type = I2C_MASTER;
+
+	rc = cam_sensor_parse_dt(s_ctrl);
+	if (rc < 0) {
+		pr_err("%s:%d :Error: cam_sensor_parse_dt rc %d",
+			__func__, __LINE__, rc);
+		goto free_s_ctrl;
+	}
+
+	return rc;
+free_s_ctrl:
+	kfree(s_ctrl);
+	return rc;
+}
+
+static int cam_sensor_platform_remove(struct platform_device *pdev)
+{
+	struct cam_sensor_ctrl_t  *s_ctrl;
+
+	s_ctrl = platform_get_drvdata(pdev);
+	if (!s_ctrl) {
+		pr_err("%s: sensor device is NULL\n", __func__);
+		return 0;
+	}
+
+	kfree(s_ctrl->i2c_data.per_frame);
+	devm_kfree(&pdev->dev, s_ctrl);
+
+	return 0;
+}
+
+static int cam_sensor_driver_i2c_remove(struct i2c_client *client)
+{
+	struct cam_sensor_ctrl_t  *s_ctrl = i2c_get_clientdata(client);
+
+	if (!s_ctrl) {
+		pr_err("%s: sensor device is NULL\n", __func__);
+		return 0;
+	}
+
+	kfree(s_ctrl->i2c_data.per_frame);
+	kfree(s_ctrl);
+
+	return 0;
+}
+
+#ifdef CONFIG_COMPAT
+static long cam_sensor_init_subdev_do_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, unsigned long arg)
+{
+	struct cam_control cmd_data;
+	int32_t rc = 0;
+
+	if (copy_from_user(&cmd_data, (void __user *)arg,
+		sizeof(cmd_data))) {
+		pr_err("Failed to copy from user_ptr=%pK size=%zu\n",
+			(void __user *)arg, sizeof(cmd_data));
+		return -EFAULT;
+	}
+
+	switch (cmd) {
+	case VIDIOC_CAM_CONTROL:
+		rc = cam_sensor_subdev_ioctl(sd, cmd, &cmd_data);
+		if (rc < 0)
+			pr_err("%s:%d cam_sensor_subdev_ioctl failed\n",
+				__func__, __LINE__);
+		break;
+	default:
+		pr_err("%s:%d Invalid compat ioctl cmd_type: %d\n",
+			__func__, __LINE__, cmd);
+		rc = -EINVAL;
+	}
+
+	if (!rc) {
+		if (copy_to_user((void __user *)arg, &cmd_data,
+			sizeof(cmd_data))) {
+			pr_err("Failed to copy to user_ptr=%pK size=%zu\n",
+				(void __user *)arg, sizeof(cmd_data));
+			rc = -EFAULT;
+		}
+	}
+	return rc;
+}
+
+#endif
+
+static struct v4l2_subdev_core_ops cam_sensor_subdev_core_ops = {
+	.ioctl = cam_sensor_subdev_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl32 = cam_sensor_init_subdev_do_ioctl,
+#endif
+	.s_power = cam_sensor_power,
+};
+
+static struct v4l2_subdev_ops cam_sensor_subdev_ops = {
+	.core = &cam_sensor_subdev_core_ops,
+};
+
+static const struct v4l2_subdev_internal_ops cam_sensor_internal_ops;
+
+static const struct of_device_id cam_sensor_driver_dt_match[] = {
+	{.compatible = "qcom,cam-sensor"},
+	{}
+};
+
+static int32_t cam_sensor_driver_platform_probe(
+	struct platform_device *pdev)
+{
+	int32_t rc = 0, i = 0;
+	struct cam_sensor_ctrl_t *s_ctrl = NULL;
+
+	/* Create sensor control structure */
+	s_ctrl = devm_kzalloc(&pdev->dev,
+		sizeof(struct cam_sensor_ctrl_t), GFP_KERNEL);
+	if (!s_ctrl)
+		return -ENOMEM;
+
+	/* Initialize sensor device type */
+	s_ctrl->of_node = pdev->dev.of_node;
+	s_ctrl->is_probe_succeed = 0;
+
+	/*fill in platform device*/
+	s_ctrl->pdev = pdev;
+
+	s_ctrl->io_master_info.master_type = CCI_MASTER;
+
+	rc = cam_sensor_parse_dt(s_ctrl);
+	if (rc < 0) {
+		pr_err("failed: cam_sensor_parse_dt rc %d", rc);
+		goto free_s_ctrl;
+	}
+
+	/* Fill platform device id*/
+	pdev->id = s_ctrl->id;
+
+	s_ctrl->v4l2_dev_str.internal_ops =
+		&cam_sensor_internal_ops;
+	s_ctrl->v4l2_dev_str.ops =
+		&cam_sensor_subdev_ops;
+	strlcpy(s_ctrl->device_name, CAMX_SENSOR_DEV_NAME,
+		sizeof(s_ctrl->device_name));
+	s_ctrl->v4l2_dev_str.name =
+		s_ctrl->device_name;
+	s_ctrl->v4l2_dev_str.sd_flags =
+		(V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS);
+	s_ctrl->v4l2_dev_str.ent_function =
+		CAM_SENSOR_DEVICE_TYPE;
+	s_ctrl->v4l2_dev_str.token = s_ctrl;
+
+	rc = cam_register_subdev(&(s_ctrl->v4l2_dev_str));
+	if (rc < 0) {
+		pr_err("%s:%d :ERROR: Fail with cam_register_subdev\n",
+			__func__, __LINE__);
+		goto free_s_ctrl;
+	}
+
+	s_ctrl->i2c_data.per_frame =
+		(struct i2c_settings_array *)
+		kzalloc(sizeof(struct i2c_settings_array) *
+		MAX_PER_FRAME_ARRAY, GFP_KERNEL);
+	if (s_ctrl->i2c_data.per_frame == NULL) {
+		rc = -ENOMEM;
+		goto free_s_ctrl;
+	}
+
+	INIT_LIST_HEAD(&(s_ctrl->i2c_data.init_settings.list_head));
+
+	for (i = 0; i < MAX_PER_FRAME_ARRAY; i++)
+		INIT_LIST_HEAD(&(s_ctrl->i2c_data.per_frame[i].list_head));
+
+	s_ctrl->bridge_intf.device_hdl = -1;
+	s_ctrl->bridge_intf.ops.get_dev_info = cam_sensor_publish_dev_info;
+	s_ctrl->bridge_intf.ops.link_setup = cam_sensor_establish_link;
+	s_ctrl->bridge_intf.ops.apply_req = cam_sensor_apply_request;
+
+	s_ctrl->sensordata->power_info.dev = &pdev->dev;
+	platform_set_drvdata(pdev, s_ctrl);
+	v4l2_set_subdevdata(&(s_ctrl->v4l2_dev_str.sd), s_ctrl);
+
+	return rc;
+free_s_ctrl:
+	devm_kfree(&pdev->dev, s_ctrl);
+	return rc;
+}
+
+MODULE_DEVICE_TABLE(of, cam_sensor_driver_dt_match);
+
+static struct platform_driver cam_sensor_platform_driver = {
+	.probe = cam_sensor_driver_platform_probe,
+	.driver = {
+		.name = "qcom,camera",
+		.owner = THIS_MODULE,
+		.of_match_table = cam_sensor_driver_dt_match,
+	},
+	.remove = cam_sensor_platform_remove,
+};
+
+static const struct i2c_device_id i2c_id[] = {
+	{SENSOR_DRIVER_I2C, (kernel_ulong_t)NULL},
+	{ }
+};
+
+static struct i2c_driver cam_sensor_driver_i2c = {
+	.id_table = i2c_id,
+	.probe = cam_sensor_driver_i2c_probe,
+	.remove = cam_sensor_driver_i2c_remove,
+	.driver = {
+		.name = SENSOR_DRIVER_I2C,
+	},
+};
+
+static int __init cam_sensor_driver_init(void)
+{
+	int32_t rc = 0;
+
+	rc = platform_driver_register(&cam_sensor_platform_driver);
+	if (rc)
+		pr_err("%s platform_driver_register failed rc = %d",
+			__func__, rc);
+	rc = i2c_add_driver(&cam_sensor_driver_i2c);
+	if (rc)
+		pr_err("%s i2c_add_driver failed rc = %d", __func__, rc);
+
+	return rc;
+}
+
+static void __exit cam_sensor_driver_exit(void)
+{
+	platform_driver_unregister(&cam_sensor_platform_driver);
+	i2c_del_driver(&cam_sensor_driver_i2c);
+}
+
+module_init(cam_sensor_driver_init);
+module_exit(cam_sensor_driver_exit);
+MODULE_DESCRIPTION("cam_sensor_driver");
+MODULE_LICENSE("GPL v2");
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
new file mode 100644
index 0000000..f597c36
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.h
@@ -0,0 +1,111 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_SENSOR_DEV_H_
+#define _CAM_SENSOR_DEV_H_
+
+#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 <linux/ion.h>
+#include <linux/iommu.h>
+#include <linux/timer.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-subdev.h>
+#include <cam_cci_dev.h>
+#include <cam_sensor_cmn_header.h>
+#include <cam_subdev.h>
+#include <cam_sensor_soc_api.h>
+#include <cam_sensor_io.h>
+
+#define NUM_MASTERS 2
+#define NUM_QUEUES 2
+
+#define TRUE  1
+#define FALSE 0
+
+#undef CDBG
+#ifdef CAM_SENSOR_DEBUG
+#define CDBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+#define SENSOR_DRIVER_I2C "i2c_camera"
+#define CAMX_SENSOR_DEV_NAME "cam-sensor-driver"
+
+enum cam_sensor_state_t {
+	CAM_SENSOR_POWER_DOWN,
+	CAM_SENSOR_POWER_UP,
+};
+
+/**
+ * struct intf_params
+ * @device_hdl: Device Handle
+ * @session_hdl: Session Handle
+ * @link_hdl: Link Handle
+ * @ops: KMD operations
+ * @crm_cb: Callback API pointers
+ */
+struct intf_params {
+	int32_t device_hdl;
+	int32_t session_hdl;
+	int32_t link_hdl;
+	struct cam_req_mgr_kmd_ops ops;
+	struct cam_req_mgr_crm_cb *crm_cb;
+};
+
+/**
+ * struct cam_sensor_ctrl_t: Camera control structure
+ * @pdev: Platform device
+ * @cam_sensor_mutex: Sensor mutex
+ * @sensordata: Sensor board Information
+ * @cci_i2c_master: I2C structure
+ * @io_master_info: Information about the communication master
+ * @sensor_state: Sensor states
+ * @is_probe_succeed: Probe succeeded or not
+ * @id: Cell Index
+ * @of_node: Of node ptr
+ * @v4l2_dev_str: V4L2 device structure
+ * @sensor_probe_addr_type: Sensor probe address type
+ * @sensor_probe_data_type: Sensor probe data type
+ * @i2c_data: Sensor I2C register settings
+ * @sensor_info: Sensor query cap structure
+ * @bridge_intf: Bridge interface structure
+ * @device_name: Sensor device structure
+ */
+struct cam_sensor_ctrl_t {
+	struct platform_device *pdev;
+	struct mutex cam_sensor_mutex;
+	struct cam_sensor_board_info *sensordata;
+	enum cci_i2c_master_t cci_i2c_master;
+	struct camera_io_master io_master_info;
+	enum cam_sensor_state_t sensor_state;
+	uint8_t is_probe_succeed;
+	uint32_t id;
+	struct device_node *of_node;
+	struct cam_subdev v4l2_dev_str;
+	uint8_t sensor_probe_addr_type;
+	uint8_t sensor_probe_data_type;
+	struct i2c_data_settings i2c_data;
+	struct  cam_sensor_query_cap sensor_info;
+	struct intf_params bridge_intf;
+	char device_name[20];
+};
+
+#endif /* _CAM_SENSOR_DEV_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_soc.c
new file mode 100644
index 0000000..8cb1078
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_soc.c
@@ -0,0 +1,267 @@
+/* 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/of.h>
+#include <linux/of_gpio.h>
+#include <cam_sensor_cmn_header.h>
+#include <cam_sensor_util.h>
+#include <cam_sensor_io.h>
+#include <cam_req_mgr_util.h>
+#include "cam_sensor_soc.h"
+
+int32_t cam_sensor_get_sub_module_index(struct device_node *of_node,
+	struct cam_sensor_board_info *s_info)
+{
+	int rc = 0, i = 0;
+	uint32_t val = 0;
+	struct device_node *src_node = NULL;
+	struct cam_sensor_board_info *sensor_info;
+
+	sensor_info = s_info;
+
+	for (i = 0; i < SUB_MODULE_MAX; i++)
+		sensor_info->subdev_id[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__);
+			of_node_put(src_node);
+			return rc;
+		}
+		sensor_info->subdev_id[SUB_MODULE_ACTUATOR] = val;
+		of_node_put(src_node);
+	}
+
+	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__);
+			of_node_put(src_node);
+			return rc;
+		}
+		sensor_info->subdev_id[SUB_MODULE_OIS] = val;
+		of_node_put(src_node);
+	}
+
+	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__);
+			of_node_put(src_node);
+			return rc;
+		}
+		sensor_info->subdev_id[SUB_MODULE_EEPROM] = val;
+		of_node_put(src_node);
+	}
+
+	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);
+			of_node_put(src_node);
+			return rc;
+		}
+		sensor_info->subdev_id[SUB_MODULE_LED_FLASH] = val;
+		of_node_put(src_node);
+	}
+
+	rc = of_property_read_u32(of_node, "qcom,csiphy-sd-index", &val);
+	if (rc < 0)
+		pr_err("%s:%d :Error: paring the dt node for csiphy rc %d\n",
+			__func__, __LINE__, rc);
+	else
+		sensor_info->subdev_id[SUB_MODULE_CSIPHY] = val;
+
+	return rc;
+}
+
+static int32_t cam_sensor_driver_get_dt_data(struct cam_sensor_ctrl_t *s_ctrl)
+{
+	int32_t rc = 0;
+	struct cam_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;
+	}
+
+	/* Read subdev info */
+	rc = cam_sensor_get_sub_module_index(of_node, sensordata);
+	if (rc < 0) {
+		pr_err("failed");
+		goto FREE_SENSOR_DATA;
+	}
+
+	/* Read vreg information */
+	rc = cam_sensor_get_dt_vreg_data(of_node,
+		&sensordata->power_info.cam_vreg,
+		&sensordata->power_info.num_vreg);
+	if (rc < 0) {
+		pr_err("failed: cam_sensor_get_dt_vreg_data rc %d", rc);
+		goto FREE_SENSOR_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 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;
+	}
+
+	if (of_property_read_u32(of_node, "qcom,sensor-position-pitch",
+		&sensordata->pos_pitch) < 0) {
+		CDBG("%s:%d Invalid sensor position\n", __func__, __LINE__);
+		sensordata->pos_pitch = 360;
+	}
+	if (of_property_read_u32(of_node, "qcom,sensor-position-roll",
+		&sensordata->pos_roll) < 0) {
+		CDBG("%s:%d Invalid sensor position\n", __func__, __LINE__);
+		sensordata->pos_roll = 360;
+	}
+	if (of_property_read_u32(of_node, "qcom,sensor-position-yaw",
+		&sensordata->pos_yaw) < 0) {
+		CDBG("%s:%d Invalid sensor position\n", __func__, __LINE__);
+		sensordata->pos_yaw = 360;
+	}
+
+	return rc;
+
+FREE_VREG_DATA:
+	kfree(sensordata->power_info.cam_vreg);
+FREE_SENSOR_DATA:
+	kfree(sensordata);
+	return rc;
+}
+
+int32_t msm_sensor_init_default_params(struct cam_sensor_ctrl_t *s_ctrl)
+{
+	/* Validate input parameters */
+	if (!s_ctrl) {
+		pr_err("%s:%d failed: invalid params s_ctrl %pK\n", __func__,
+			__LINE__, s_ctrl);
+		return -EINVAL;
+	}
+
+	CDBG("%s: %d master_type: %d\n", __func__, __LINE__,
+		s_ctrl->io_master_info.master_type);
+	/* Initialize cci_client */
+	if (s_ctrl->io_master_info.master_type == CCI_MASTER) {
+		s_ctrl->io_master_info.cci_client = kzalloc(sizeof(
+			struct cam_sensor_cci_client), GFP_KERNEL);
+		if (!(s_ctrl->io_master_info.cci_client))
+			return -ENOMEM;
+
+	} else {
+		pr_err("%s:%d Invalid master / Master type Not supported\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int32_t cam_sensor_parse_dt(struct cam_sensor_ctrl_t *s_ctrl)
+{
+	int32_t rc = 0;
+
+	/* Parse dt information and store in sensor control structure */
+	rc = cam_sensor_driver_get_dt_data(s_ctrl);
+	if (rc < 0) {
+		pr_err("failed: rc %d", rc);
+		return rc;
+	}
+
+	/* Initialize mutex */
+	mutex_init(&(s_ctrl->cam_sensor_mutex));
+
+	pr_err("%s: %d\n", __func__, __LINE__);
+	/* 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;
+	}
+
+	/* 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_DT_DATA;
+	}
+
+	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);
+	s_ctrl->sensordata = NULL;
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_soc.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_soc.h
new file mode 100644
index 0000000..7f4a551
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_soc.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_SENSOR_SOC_H_
+#define _CAM_SENSOR_SOC_H_
+
+#include "cam_sensor_dev.h"
+
+/**
+ * @s_ctrl: Sensor ctrl structure
+ *
+ * Parses sensor dt
+ */
+int cam_sensor_parse_dt(struct cam_sensor_ctrl_t *s_ctrl);
+
+#endif /* _CAM_SENSOR_SOC_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/Makefile b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/Makefile
new file mode 100644
index 0000000..bdae1d1
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/Makefile
@@ -0,0 +1,8 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_cci
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_io.o cam_sensor_cci_i2c.o
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c
new file mode 100644
index 0000000..1709fd3
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c
@@ -0,0 +1,184 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "cam_sensor_cmn_header.h"
+#include "cam_sensor_i2c.h"
+#include "cam_cci_dev.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+int32_t cam_cci_i2c_read(struct cam_sensor_cci_client *cci_client,
+	uint32_t addr, uint32_t *data,
+	enum camera_sensor_i2c_type addr_type,
+	enum camera_sensor_i2c_type data_type)
+{
+	int32_t rc = -EINVAL;
+	unsigned char buf[data_type];
+	struct cam_cci_ctrl cci_ctrl;
+
+	if (addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID
+		|| addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX
+		|| data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID
+		|| data_type >= CAMERA_SENSOR_I2C_TYPE_MAX)
+		return rc;
+
+	cci_ctrl.cmd = MSM_CCI_I2C_READ;
+	cci_ctrl.cci_info = cci_client;
+	cci_ctrl.cfg.cci_i2c_read_cfg.addr = addr;
+	cci_ctrl.cfg.cci_i2c_read_cfg.addr_type = 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(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 == CAMERA_SENSOR_I2C_TYPE_BYTE)
+		*data = buf[0];
+	else if (data_type == CAMERA_SENSOR_I2C_TYPE_WORD)
+		*data = buf[0] << 8 | buf[1];
+	else if (data_type == CAMERA_SENSOR_I2C_TYPE_3B)
+		*data = buf[0] << 16 | buf[1] << 8 | buf[2];
+	else
+		*data = buf[0] << 24 | buf[1] << 16 |
+			buf[2] << 8 | buf[3];
+
+	return rc;
+}
+
+static int32_t cam_cci_i2c_write_table_cmd(
+	struct camera_io_master *client,
+	struct cam_sensor_i2c_reg_setting *write_setting,
+	enum cam_cci_cmd_type cmd)
+{
+	int32_t rc = -EINVAL;
+	struct cam_cci_ctrl cci_ctrl;
+
+	if (!client || !write_setting)
+		return rc;
+
+	if (write_setting->addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID
+		|| write_setting->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX
+		|| write_setting->data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID
+		|| write_setting->data_type >= CAMERA_SENSOR_I2C_TYPE_MAX)
+		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 = write_setting->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 cam_cci_i2c_write_table(
+	struct camera_io_master *client,
+	struct cam_sensor_i2c_reg_setting *write_setting)
+{
+	return cam_cci_i2c_write_table_cmd(client, write_setting,
+		MSM_CCI_I2C_WRITE);
+}
+
+static int32_t cam_cci_i2c_compare(struct cam_sensor_cci_client *client,
+	uint32_t addr, uint16_t data, uint16_t data_mask,
+	enum camera_sensor_i2c_type data_type,
+	enum camera_sensor_i2c_type addr_type)
+{
+	int32_t rc;
+	uint32_t reg_data = 0;
+
+	rc = cam_cci_i2c_read(client, addr, &reg_data,
+		addr_type, data_type);
+	if (rc < 0)
+		return rc;
+
+	reg_data = reg_data & 0xFFFF;
+	if (data == (reg_data & ~data_mask))
+		return I2C_COMPARE_MATCH;
+	return I2C_COMPARE_MISMATCH;
+}
+
+int32_t cam_cci_i2c_poll(struct cam_sensor_cci_client *client,
+	uint32_t addr, uint16_t data, uint16_t data_mask,
+	enum camera_sensor_i2c_type data_type,
+	enum camera_sensor_i2c_type addr_type,
+	uint32_t delay_ms)
+{
+	int32_t rc = -EINVAL;
+	int32_t i = 0;
+
+	CDBG("%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 = cam_cci_i2c_compare(client,
+			addr, data, data_mask, data_type, addr_type);
+		if (!rc) {
+			pr_err("%s:%d Fail in comparing the data in poll\n",
+				__func__, __LINE__);
+			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;
+}
+
+int32_t cam_sensor_cci_i2c_util(struct cam_sensor_cci_client *cci_client,
+	uint16_t cci_cmd)
+{
+	int32_t rc = 0;
+	struct cam_cci_ctrl cci_ctrl;
+
+	CDBG("%s line %d\n", __func__, __LINE__);
+	cci_ctrl.cmd = cci_cmd;
+	cci_ctrl.cci_info = cci_client;
+	rc = v4l2_subdev_call(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/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h
new file mode 100644
index 0000000..1261c4b
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h
@@ -0,0 +1,78 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_SENSOR_I2C_H_
+#define _CAM_SENSOR_I2C_H_
+
+#include <linux/delay.h>
+#include <media/v4l2-subdev.h>
+#include <media/cam_sensor.h>
+#include <media/cam_sensor.h>
+#include "cam_cci_dev.h"
+#include "cam_sensor_io.h"
+
+#define I2C_POLL_TIME_MS 5
+#define MAX_POLL_DELAY_MS 100
+
+#define I2C_COMPARE_MATCH 0
+#define I2C_COMPARE_MISMATCH 1
+
+/**
+ * @client: CCI client structure
+ * @data: I2C data
+ * @addr_type: I2c address type
+ * @data_type: I2C data type
+ *
+ * This API handles CCI read
+ */
+int32_t cam_cci_i2c_read(struct cam_sensor_cci_client *client,
+	uint32_t addr, uint32_t *data,
+	enum camera_sensor_i2c_type addr_type,
+	enum camera_sensor_i2c_type data_type);
+
+/**
+ * @client: CCI client structure
+ * @cci_cmd: CCI command type
+ *
+ * This API handles CCI random write
+ */
+int32_t cam_cci_i2c_write_table(
+	struct camera_io_master *client,
+	struct cam_sensor_i2c_reg_setting *write_setting);
+
+/**
+ * @cci_client: CCI client structure
+ * @cci_cmd: CCI command type
+ *
+ * Does I2C call to I2C functionalities
+ */
+int32_t cam_sensor_cci_i2c_util(struct cam_sensor_cci_client *cci_client,
+	uint16_t cci_cmd);
+
+/**
+ * @client: CCI client structure
+ * @addr: I2C address
+ * @data: I2C data
+ * @data_mask: I2C data mask
+ * @data_type: I2C data type
+ * @addr_type: I2C addr type
+ * @delay_ms: Delay in milli seconds
+ *
+ * This API implements CCI based I2C poll
+ */
+int32_t cam_cci_i2c_poll(struct cam_sensor_cci_client *client,
+	uint32_t addr, uint16_t data, uint16_t data_mask,
+	enum camera_sensor_i2c_type data_type,
+	enum camera_sensor_i2c_type addr_type,
+	uint32_t delay_ms);
+
+#endif /* _CAM_SENSOR_I2C_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
new file mode 100644
index 0000000..f889abc
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
@@ -0,0 +1,111 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "cam_sensor_io.h"
+#include "cam_sensor_i2c.h"
+
+int32_t camera_io_dev_poll(struct camera_io_master *io_master_info,
+	uint32_t addr, uint16_t data, uint32_t data_mask,
+	enum camera_sensor_i2c_type data_type,
+	enum camera_sensor_i2c_type addr_type,
+	uint32_t delay_ms)
+{
+	int16_t mask = data_mask & 0xFF;
+
+	if (!io_master_info) {
+		pr_err("%s:%d Invalid Args\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	if (io_master_info->master_type == CCI_MASTER) {
+		return cam_cci_i2c_poll(io_master_info->cci_client,
+			addr, data, mask, data_type, addr_type, delay_ms);
+	} else {
+		pr_err("%s:%d Invalid Comm. Master:%d\n", __func__,
+			__LINE__, io_master_info->master_type);
+		return -EINVAL;
+	}
+}
+
+int32_t camera_io_dev_read(struct camera_io_master *io_master_info,
+	uint32_t addr, uint32_t *data,
+	enum camera_sensor_i2c_type data_type)
+{
+	if (!io_master_info) {
+		pr_err("%s:%d Invalid Args\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	if (io_master_info->master_type == CCI_MASTER) {
+		return cam_cci_i2c_read(io_master_info->cci_client,
+			addr, data, data_type, data_type);
+	} else {
+		pr_err("%s:%d Invalid Comm. Master:%d\n", __func__,
+			__LINE__, io_master_info->master_type);
+		return -EINVAL;
+	}
+}
+
+int32_t camera_io_dev_write(struct camera_io_master *io_master_info,
+	struct cam_sensor_i2c_reg_setting *write_setting)
+{
+	if (!write_setting || !io_master_info) {
+		pr_err("Input parameters not valid ws: %pK ioinfo: %pK",
+			write_setting, io_master_info);
+		return -EINVAL;
+	}
+
+	if (io_master_info->master_type == CCI_MASTER) {
+		return cam_cci_i2c_write_table(io_master_info,
+			write_setting);
+	} else {
+		pr_err("%s:%d Invalid Comm. Master:%d\n", __func__,
+			__LINE__, io_master_info->master_type);
+		return -EINVAL;
+	}
+}
+
+int32_t camera_io_init(struct camera_io_master *io_master_info)
+{
+	if (!io_master_info) {
+		pr_err("%s:%d Invalid Args\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	if (io_master_info->master_type == CCI_MASTER) {
+		io_master_info->cci_client->cci_subdev =
+			cam_cci_get_subdev();
+		return cam_sensor_cci_i2c_util(io_master_info->cci_client,
+			MSM_CCI_INIT);
+	} else {
+		pr_err("%s:%d Invalid Comm. Master:%d\n", __func__,
+			__LINE__, io_master_info->master_type);
+		return -EINVAL;
+	}
+}
+
+int32_t camera_io_release(struct camera_io_master *io_master_info)
+{
+	if (!io_master_info) {
+		pr_err("%s:%d Invalid Args\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	if (io_master_info->master_type == CCI_MASTER) {
+		return cam_sensor_cci_i2c_util(io_master_info->cci_client,
+			MSM_CCI_RELEASE);
+	} else {
+		pr_err("%s:%d Invalid Comm. Master:%d\n", __func__,
+			__LINE__, io_master_info->master_type);
+		return -EINVAL;
+	}
+}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.h
new file mode 100644
index 0000000..757ac17
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.h
@@ -0,0 +1,89 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_SENSOR_IO_H_
+#define _CAM_SENSOR_IO_H_
+
+#include <media/cam_sensor.h>
+
+#include "cam_sensor_cmn_header.h"
+
+#define CCI_MASTER 1
+#define I2C_MASTER 2
+#define SPI_MASTER 3
+
+/**
+ * @master_type: CCI master type
+ * @client: I2C client information structure
+ * @cci_client: CCI client information structure
+ * @spi_client: SPI client information structure
+ */
+struct camera_io_master {
+	int master_type;
+	struct i2c_client *client;
+	struct cam_sensor_cci_client *cci_client;
+	struct cam_sensor_spi_client *spi_client;
+};
+
+/**
+ * @io_master_info: I2C/SPI master information
+ * @addr: I2C address
+ * @data: I2C data
+ * @data_type: I2C data type
+ *
+ * This API abstracts read functionality based on master type
+ */
+int32_t camera_io_dev_read(struct camera_io_master *io_master_info,
+	uint32_t addr, uint32_t *data,
+	enum camera_sensor_i2c_type data_type);
+
+/**
+ * @io_master_info: I2C/SPI master information
+ *
+ * This API initializes the I2C/SPI master based on master type
+ */
+int32_t camera_io_init(struct camera_io_master *io_master_info);
+
+/**
+ * @io_master_info: I2C/SPI master information
+ *
+ * This API releases the I2C/SPI master based on master type
+ */
+int32_t camera_io_release(struct camera_io_master *io_master_info);
+
+/**
+ * @io_master_info: I2C/SPI master information
+ * @write_setting: write settings information
+ *
+ * This API abstracts write functionality based on master type
+ */
+int32_t camera_io_dev_write(struct camera_io_master *io_master_info,
+	struct cam_sensor_i2c_reg_setting *write_setting);
+
+/**
+ * @io_master_info: I2C/SPI master information
+ * @addr: I2C address
+ * @data: I2C data
+ * @data_mask: I2C data mask
+ * @data_type: I2C data type
+ * @addr_type: I2C address type
+ * @delay_ms: delay in milli seconds
+ *
+ * This API abstracts poll functionality based on master type
+ */
+int32_t camera_io_dev_poll(struct camera_io_master *io_master_info,
+	uint32_t addr, uint16_t data, uint32_t data_mask,
+	enum camera_sensor_i2c_type data_type,
+	enum camera_sensor_i2c_type addr_type,
+	uint32_t delay_ms);
+
+#endif /* _CAM_SENSOR_IO_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/Makefile b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/Makefile
new file mode 100644
index 0000000..766828e
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/Makefile
@@ -0,0 +1,6 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_cci
+
+obj-$(CONFIG_SPECTRA_CAMERA) +=  cam_sensor_util.o cam_sensor_soc_api.o
\ No newline at end of file
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
new file mode 100644
index 0000000..e5e4872
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h
@@ -0,0 +1,375 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_SENSOR_CMN_HEADER_
+#define _CAM_SENSOR_CMN_HEADER_
+
+#include <linux/i2c.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <media/cam_sensor.h>
+#include <media/cam_req_mgr.h>
+
+#define MAX_REGULATOR 5
+#define MAX_POWER_CONFIG 12
+
+#define MAX_PER_FRAME_ARRAY 8
+
+#define CAM_SENSOR_NAME    "cam-sensor"
+#define CAM_ACTUATOR_NAME  "cam-actuator"
+#define CAM_CSIPHY_NAME    "cam-csiphy"
+
+#define MAX_SYSTEM_PIPELINE_DELAY 2
+
+#define CAM_PKT_NOP_OPCODE 127
+
+enum camera_sensor_cmd_type {
+	CAMERA_SENSOR_CMD_TYPE_INVALID,
+	CAMERA_SENSOR_CMD_TYPE_PROBE,
+	CAMERA_SENSOR_CMD_TYPE_PWR_UP,
+	CAMERA_SENSOR_CMD_TYPE_PWR_DOWN,
+	CAMERA_SENSOR_CMD_TYPE_I2C_INFO,
+	CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR,
+	CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_RD,
+	CAMERA_SENSOR_CMD_TYPE_I2C_CONT_WR,
+	CAMERA_SENSOR_CMD_TYPE_I2C_CONT_RD,
+	CAMERA_SENSOR_CMD_TYPE_WAIT,
+	CAMERA_SENSOR_CMD_TYPE_MAX,
+};
+
+enum camera_sensor_i2c_op_code {
+	CAMERA_SENSOR_I2C_OP_INVALID,
+	CAMERA_SENSOR_I2C_OP_RNDM_WR,
+	CAMERA_SENSOR_I2C_OP_RNDM_WR_VERF,
+	CAMERA_SENSOR_I2C_OP_CONT_WR_BRST,
+	CAMERA_SENSOR_I2C_OP_CONT_WR_BRST_VERF,
+	CAMERA_SENSOR_I2C_OP_CONT_WR_SEQN,
+	CAMERA_SENSOR_I2C_OP_CONT_WR_SEQN_VERF,
+	CAMERA_SENSOR_I2C_OP_MAX,
+};
+
+enum camera_sensor_wait_op_code {
+	CAMERA_SENSOR_WAIT_OP_INVALID,
+	CAMERA_SENSOR_WAIT_OP_COND,
+	CAMERA_SENSOR_WAIT_OP_HW_UCND,
+	CAMERA_SENSOR_WAIT_OP_SW_UCND,
+	CAMERA_SENSOR_WAIT_OP_MAX,
+};
+
+enum camera_sensor_i2c_type {
+	CAMERA_SENSOR_I2C_TYPE_INVALID,
+	CAMERA_SENSOR_I2C_TYPE_BYTE,
+	CAMERA_SENSOR_I2C_TYPE_WORD,
+	CAMERA_SENSOR_I2C_TYPE_3B,
+	CAMERA_SENSOR_I2C_TYPE_DWORD,
+	CAMERA_SENSOR_I2C_TYPE_MAX,
+};
+
+enum i2c_freq_mode {
+	I2C_STANDARD_MODE,
+	I2C_FAST_MODE,
+	I2C_CUSTOM_MODE,
+	I2C_FAST_PLUS_MODE,
+	I2C_MAX_MODES,
+};
+
+enum position_roll {
+	ROLL_0       = 0,
+	ROLL_90      = 90,
+	ROLL_180     = 180,
+	ROLL_270     = 270,
+	ROLL_INVALID = 360,
+};
+
+enum position_yaw {
+	FRONT_CAMERA_YAW = 0,
+	REAR_CAMERA_YAW  = 180,
+	INVALID_YAW      = 360,
+};
+
+enum position_pitch {
+	LEVEL_PITCH    = 0,
+	INVALID_PITCH  = 360,
+};
+
+enum sensor_sub_module {
+	SUB_MODULE_SENSOR,
+	SUB_MODULE_ACTUATOR,
+	SUB_MODULE_EEPROM,
+	SUB_MODULE_LED_FLASH,
+	SUB_MODULE_CSID,
+	SUB_MODULE_CSIPHY,
+	SUB_MODULE_OIS,
+	SUB_MODULE_EXT,
+	SUB_MODULE_MAX,
+};
+
+enum msm_camera_power_seq_type {
+	SENSOR_MCLK,
+	SENSOR_VANA,
+	SENSOR_VDIG,
+	SENSOR_VIO,
+	SENSOR_VAF,
+	SENSOR_VAF_PWDM,
+	SENSOR_CUSTOM_REG1,
+	SENSOR_CUSTOM_REG2,
+	SENSOR_RESET,
+	SENSOR_STANDBY,
+	SENSOR_CUSTOM_GPIO1,
+	SENSOR_CUSTOM_GPIO2,
+	SENSOR_SEQ_TYPE_MAX,
+};
+
+enum cam_sensor_packet_opcodes {
+	CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMON,
+	CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE,
+	CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG,
+	CAM_SENSOR_PACKET_OPCODE_SENSOR_PROBE
+};
+
+enum cam_actuator_packet_opcodes {
+	CAM_ACTUATOR_PACKET_OPCODE_INIT,
+	CAM_ACTUATOR_PACKET_AUTO_MOVE_LENS,
+	CAM_ACTUATOR_PACKET_MANUAL_MOVE_LENS
+};
+
+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
+};
+
+enum msm_camera_device_type_t {
+	MSM_CAMERA_I2C_DEVICE,
+	MSM_CAMERA_PLATFORM_DEVICE,
+	MSM_CAMERA_SPI_DEVICE,
+};
+
+enum cci_i2c_master_t {
+	MASTER_0,
+	MASTER_1,
+	MASTER_MAX,
+};
+
+enum camera_vreg_type {
+	VREG_TYPE_DEFAULT,
+	VREG_TYPE_CUSTOM,
+};
+
+enum cam_sensor_i2c_cmd_type {
+	CAM_SENSOR_I2C_WRITE_RANDOM,
+	CAM_SENSOR_I2C_READ,
+	CAM_SENSOR_I2C_POLL
+};
+
+struct common_header {
+	uint16_t    first_word;
+	uint8_t     third_byte;
+	uint8_t     cmd_type;
+};
+
+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 cam_sensor_module_power_setting {
+	enum msm_camera_power_seq_type seq_type;
+	unsigned short seq_val;
+	uint32_t config_val_low;
+	uint32_t config_val_high;
+	unsigned short delay;
+};
+
+struct msm_camera_gpio_num_info {
+	uint16_t gpio_num[SENSOR_SEQ_TYPE_MAX];
+	uint8_t valid[SENSOR_SEQ_TYPE_MAX];
+};
+
+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 cam_sensor_i2c_reg_array {
+	uint32_t reg_addr;
+	uint32_t reg_data;
+	uint32_t delay;
+	uint32_t data_mask;
+};
+
+struct cam_sensor_i2c_reg_setting {
+	struct cam_sensor_i2c_reg_array *reg_setting;
+	unsigned short size;
+	enum camera_sensor_i2c_type addr_type;
+	enum camera_sensor_i2c_type data_type;
+	unsigned short delay;
+};
+
+struct i2c_settings_list {
+	struct cam_sensor_i2c_reg_setting i2c_settings;
+	enum cam_sensor_i2c_cmd_type op_code;
+	struct list_head list;
+};
+
+struct i2c_settings_array {
+	struct list_head list_head;
+	int32_t is_settings_valid;
+	int64_t request_id;
+};
+
+struct i2c_data_settings {
+	struct i2c_settings_array init_settings;
+	struct i2c_settings_array *per_frame;
+};
+
+struct cam_sensor_power_ctrl_t {
+	struct device *dev;
+	struct cam_sensor_power_setting *power_setting;
+	uint16_t power_setting_size;
+	struct cam_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 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;
+};
+
+struct cam_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_sensor_init_params {
+	int modes_supported;
+	unsigned int sensor_mount_angle;
+};
+
+enum msm_sensor_camera_id_t {
+	CAMERA_0,
+	CAMERA_1,
+	CAMERA_2,
+	CAMERA_3,
+	MAX_CAMERAS,
+};
+
+struct msm_sensor_id_info_t {
+	unsigned short sensor_id_reg_addr;
+	unsigned short sensor_id;
+	unsigned short sensor_id_mask;
+};
+
+enum msm_sensor_output_format_t {
+	MSM_SENSOR_BAYER,
+	MSM_SENSOR_YCBCR,
+	MSM_SENSOR_META,
+};
+
+struct cam_sensor_power_setting {
+	enum msm_camera_power_seq_type seq_type;
+	unsigned short seq_val;
+	long config_val;
+	unsigned short delay;
+	void *data[10];
+};
+
+struct cam_sensor_power_setting_array {
+	struct cam_sensor_power_setting  power_setting_a[MAX_POWER_CONFIG];
+	struct cam_sensor_power_setting *power_setting;
+	unsigned short size;
+	struct cam_sensor_power_setting  power_down_setting_a[MAX_POWER_CONFIG];
+	struct cam_sensor_power_setting *power_down_setting;
+	unsigned short size_down;
+};
+
+struct msm_camera_sensor_slave_info {
+	enum msm_sensor_camera_id_t camera_id;
+	unsigned short slave_addr;
+	enum i2c_freq_mode i2c_freq_mode;
+	enum camera_sensor_i2c_type addr_type;
+	struct msm_sensor_id_info_t sensor_id_info;
+	struct cam_sensor_power_setting_array power_setting_array;
+	unsigned char  is_init_params_valid;
+	enum msm_sensor_output_format_t output_format;
+};
+
+struct cam_sensor_board_info {
+	struct cam_camera_slave_info slave_info;
+	int32_t sensor_mount_angle;
+	int32_t secure_mode;
+	int modes_supported;
+	int32_t pos_roll;
+	int32_t pos_yaw;
+	int32_t pos_pitch;
+	int32_t  subdev_id[SUB_MODULE_MAX];
+	int32_t  subdev_intf[SUB_MODULE_MAX];
+	const char *misc_regulator;
+	struct cam_sensor_power_ctrl_t power_info;
+};
+
+enum msm_camera_vreg_name_t {
+	CAM_VDIG,
+	CAM_VIO,
+	CAM_VANA,
+	CAM_VAF,
+	CAM_V_CUSTOM1,
+	CAM_V_CUSTOM2,
+	CAM_VREG_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;
+};
+
+#endif /* _CAM_SENSOR_CMN_HEADER_ */
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_soc_api.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_soc_api.c
new file mode 100644
index 0000000..2eed9ce
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_soc_api.c
@@ -0,0 +1,1331 @@
+/* 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/delay.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/msm-bus.h>
+#include "cam_sensor_soc_api.h"
+
+#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
+
+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 (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(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);
+					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(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;
+			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;
+}
+
+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 -EINVAL;
+}
+
+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;
+}
+
+/* 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 free_clk_info;
+	}
+
+	rates = devm_kcalloc(dev, cnt, sizeof(long), GFP_KERNEL);
+	if (!rates) {
+		rc = -ENOMEM;
+		goto free_clk_ptr;
+	}
+
+	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 free_rates;
+	}
+
+	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 free_rates;
+		}
+
+		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 free_rates;
+			}
+
+			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 = -EINVAL;
+				goto free_rates;
+			}
+		} 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 release_clk;
+		}
+		CDBG("clk ptr[%d] :%pK\n", i, (*clk_ptr)[i]);
+	}
+
+	devm_kfree(dev, rates);
+
+	return rc;
+
+release_clk:
+	for (--i; i >= 0; i--)
+		devm_clk_put(dev, (*clk_ptr)[i]);
+free_rates:
+	devm_kfree(dev, rates);
+free_clk_ptr:
+	devm_kfree(dev, *clk_ptr);
+free_clk_info:
+	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;
+	uint32_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 free_clk_info;
+	}
+
+	rates = devm_kcalloc(&pdev->dev, *num_set,
+		sizeof(uint32_t *), GFP_KERNEL);
+	if (!rates) {
+		rc = -ENOMEM;
+		goto free_clk;
+	}
+
+	for (i = 0; i < *num_set; i++) {
+		rates[i] = devm_kcalloc(&pdev->dev, *num_clk,
+			sizeof(uint32_t), GFP_KERNEL);
+		if (!rates[i]) {
+			rc = -ENOMEM;
+			for (--i; i >= 0; i--)
+				devm_kfree(&pdev->dev, rates[i]);
+			goto free_rate;
+		}
+	}
+
+	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 free_rate_array;
+			}
+			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 free_rate_array;
+		}
+
+		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 release_clk;
+		}
+		CDBG("clk ptr[%d] :%pK\n", i, clks[i]);
+	}
+	*pclk_info = clk_info;
+	*pclks = clks;
+	*pclk_rates = rates;
+
+	return rc;
+
+release_clk:
+	for (--i; i >= 0; i--)
+		devm_clk_put(&pdev->dev, clks[i]);
+free_rate_array:
+	for (i = 0; i < *num_set; i++)
+		devm_kfree(&pdev->dev, rates[i]);
+free_rate:
+	devm_kfree(&pdev->dev, rates);
+free_clk:
+	devm_kfree(&pdev->dev, clks);
+free_clk_info:
+	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++) {
+			pr_err("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) {
+				pr_err("%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);
+
+/* 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 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 disable_reg;
+				}
+			} else {
+				rc = regulator_disable(tmp->vdd);
+				if (rc < 0)
+					pr_err("regulator disable failed %d\n",
+						i);
+			}
+		}
+		tmp++;
+	}
+
+	return 0;
+disable_reg:
+	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);
+
+/* 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 *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);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_soc_api.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_soc_api.h
new file mode 100644
index 0000000..c316090
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_soc_api.h
@@ -0,0 +1,473 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_SENSOR_SOC_API_H_
+#define _CAM_SENSOR_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/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include "cam_sensor_cmn_header.h"
+
+struct msm_cam_regulator {
+	const char *name;
+	struct regulator *vdd;
+};
+
+struct msm_gpio_set_tbl {
+	unsigned int gpio;
+	unsigned long flags;
+	uint32_t delay;
+};
+
+/**
+ * @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 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      : 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      : 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);
+
+/**
+ * @brief      : Selects clock source
+ *
+ *
+ * @param dev : Token of the device
+ * @param clk_info : Clock Info structure
+ * @param clk_src_info : Clock Info structure
+ * @param num_clk : Number of clocks
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+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);
+
+/**
+ * @brief      : Enables the clock
+ *
+ *
+ * @param dev : Token of the device
+ * @param clk_info : Clock Info structure
+ * @param clk_tr : Pointer to lock strucure
+ * @param num_clk : Number of clocks
+ * @param enable : Enable/disable the clock
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info,
+		struct clk **clk_ptr, int num_clk, int enable);
+
+/**
+ * @brief      : Configures voltage regulator
+ *
+ *
+ * @param dev : Token of the device
+ * @param cam_vreg : Regulator dt structure
+ * @param num_vreg : Number of regulators
+ * @param vreg_seq : Regulator sequence type
+ * @param num_clk : Number of clocks
+ * @param reg_ptr : Regulator pointer
+ * @param config : Enable/disable configuring the regulator
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+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);
+
+/**
+ * @brief      : Enables voltage regulator
+ *
+ *
+ * @param dev : Token of the device
+ * @param cam_vreg : Regulator dt structure
+ * @param num_vreg : Number of regulators
+ * @param vreg_seq : Regulator sequence type
+ * @param num_clk : Number of clocks
+ * @param reg_ptr : Regulator pointer
+ * @param config : Enable/disable configuring the regulator
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+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);
+
+/**
+ * @brief      : Sets table of GPIOs
+ *
+ * @param gpio_tbl : GPIO table parsed from dt
+ * @param gpio_tbl_size : Size of GPIO table
+ * @param gpio_en : Enable/disable the GPIO
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int msm_camera_set_gpio_table(struct msm_gpio_set_tbl *gpio_tbl,
+	uint8_t gpio_tbl_size, int gpio_en);
+
+/**
+ * @brief      : Configures single voltage regulator
+ *
+ *
+ * @param dev : Token of the device
+ * @param cam_vreg : Regulator dt structure
+ * @param num_vreg : Number of regulators
+ * @param reg_ptr : Regulator pointer
+ * @param config : Enable/disable configuring the regulator
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int msm_camera_config_single_vreg(struct device *dev,
+	struct camera_vreg_t *cam_vreg, struct regulator **reg_ptr, int config);
+
+/**
+ * @brief      : Request table of gpios
+ *
+ *
+ * @param gpio_tbl : Table of GPIOs
+ * @param size : Size of table
+ * @param gpio_en : Enable/disable the gpio
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int msm_camera_request_gpio_table(struct gpio *gpio_tbl, uint8_t size,
+	int gpio_en);
+
+#endif /* _CAM_SENSOR_SOC_API_H_ */
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
new file mode 100644
index 0000000..44294e8
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
@@ -0,0 +1,1399 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include "cam_sensor_util.h"
+#include "cam_sensor_soc_api.h"
+
+#define CAM_SENSOR_PINCTRL_STATE_SLEEP "cam_suspend"
+#define CAM_SENSOR_PINCTRL_STATE_DEFAULT "cam_default"
+
+#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)
+
+static struct i2c_settings_list*
+	cam_sensor_get_i2c_ptr(struct i2c_settings_array *i2c_reg_settings,
+		uint32_t size)
+{
+	struct i2c_settings_list *tmp;
+
+	tmp = (struct i2c_settings_list *)
+		kzalloc(sizeof(struct i2c_settings_list), GFP_KERNEL);
+
+	if (tmp != NULL)
+		list_add_tail(&(tmp->list),
+			&(i2c_reg_settings->list_head));
+	else
+		return NULL;
+
+	tmp->i2c_settings.reg_setting = (struct cam_sensor_i2c_reg_array *)
+		kzalloc(sizeof(struct cam_sensor_i2c_reg_array) *
+		size, GFP_KERNEL);
+	if (tmp->i2c_settings.reg_setting == NULL) {
+		list_del(&(tmp->list));
+		kfree(tmp);
+		return NULL;
+	}
+	tmp->i2c_settings.size = size;
+
+	return tmp;
+}
+
+int32_t delete_request(struct i2c_settings_array *i2c_array)
+{
+	struct i2c_settings_list *i2c_list = NULL, *i2c_next = NULL;
+	int32_t rc = 0;
+
+	if (i2c_array == NULL) {
+		pr_err("%s:%d ::FATAL:: Invalid argument\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	list_for_each_entry_safe(i2c_list, i2c_next,
+		&(i2c_array->list_head), list) {
+		kfree(i2c_list->i2c_settings.reg_setting);
+		list_del(&(i2c_list->list));
+		kfree(i2c_list);
+	}
+	INIT_LIST_HEAD(&(i2c_array->list_head));
+	i2c_array->is_settings_valid = 0;
+
+	return rc;
+}
+
+int32_t cam_sensor_handle_delay(
+	uint32_t **cmd_buf,
+	uint16_t generic_op_code,
+	struct i2c_settings_array *i2c_reg_settings,
+	uint32_t offset, uint32_t *byte_cnt,
+	struct list_head *list_ptr)
+{
+	int32_t rc = 0;
+	struct cam_cmd_unconditional_wait *cmd_uncond_wait =
+		(struct cam_cmd_unconditional_wait *) *cmd_buf;
+	struct i2c_settings_list *i2c_list = NULL;
+
+	if (i2c_list == NULL) {
+		pr_err("%s:%d Invalid list ptr\n",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	if (offset > 0) {
+		i2c_list =
+			list_entry(list_ptr, struct i2c_settings_list, list);
+		if (generic_op_code ==
+			CAMERA_SENSOR_WAIT_OP_HW_UCND)
+			i2c_list->i2c_settings.
+				reg_setting[offset - 1].delay =
+				cmd_uncond_wait->delay;
+		else
+			i2c_list->i2c_settings.delay =
+				cmd_uncond_wait->delay;
+		(*cmd_buf) +=
+			sizeof(
+			struct cam_cmd_unconditional_wait) / sizeof(uint32_t);
+		(*byte_cnt) +=
+			sizeof(
+			struct cam_cmd_unconditional_wait);
+	} else {
+		pr_err("%s: %d Error: Delay Rxed Before any buffer: %d\n",
+			__func__, __LINE__, offset);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+int32_t cam_sensor_handle_poll(
+	uint32_t **cmd_buf,
+	struct i2c_settings_array *i2c_reg_settings,
+	uint32_t *byte_cnt, int32_t *offset,
+	struct list_head **list_ptr)
+{
+	struct i2c_settings_list  *i2c_list;
+	int32_t rc = 0;
+	struct cam_cmd_conditional_wait *cond_wait
+		= (struct cam_cmd_conditional_wait *) *cmd_buf;
+
+	i2c_list =
+		cam_sensor_get_i2c_ptr(i2c_reg_settings, 1);
+	if (!i2c_list || !i2c_list->i2c_settings.reg_setting) {
+		pr_err("%s: %d Failed in allocating mem for list\n",
+			__func__, __LINE__);
+		return -ENOMEM;
+	}
+
+	i2c_list->op_code = CAM_SENSOR_I2C_POLL;
+	i2c_list->i2c_settings.data_type =
+		cond_wait->data_type;
+	i2c_list->i2c_settings.addr_type =
+		cond_wait->addr_type;
+	i2c_list->i2c_settings.reg_setting->reg_addr =
+		cond_wait->reg_addr;
+	i2c_list->i2c_settings.reg_setting->reg_data =
+		cond_wait->reg_data;
+	i2c_list->i2c_settings.reg_setting->delay =
+		cond_wait->timeout;
+
+	(*cmd_buf) += sizeof(struct cam_cmd_conditional_wait) /
+		sizeof(uint32_t);
+	(*byte_cnt) += sizeof(struct cam_cmd_conditional_wait);
+
+	(*offset) += 1;
+	*list_ptr = &(i2c_list->list);
+
+	return rc;
+}
+
+int32_t cam_sensor_handle_random_write(
+	struct cam_cmd_i2c_random_wr *cam_cmd_i2c_random_wr,
+	struct i2c_settings_array *i2c_reg_settings,
+	uint16_t *cmd_length_in_bytes, int32_t *offset,
+	struct list_head **list)
+{
+	struct i2c_settings_list  *i2c_list;
+	int32_t rc = 0, cnt;
+
+	i2c_list = cam_sensor_get_i2c_ptr(i2c_reg_settings,
+		cam_cmd_i2c_random_wr->header.count);
+	if (i2c_list == NULL ||
+		i2c_list->i2c_settings.reg_setting == NULL) {
+		pr_err("%s: %d Failed in allocating i2c_list\n",
+			__func__, __LINE__);
+		return -ENOMEM;
+	}
+
+	*cmd_length_in_bytes = (sizeof(struct i2c_rdwr_header) +
+		sizeof(struct i2c_random_wr_payload) *
+		(cam_cmd_i2c_random_wr->header.count));
+	i2c_list->op_code = CAM_SENSOR_I2C_WRITE_RANDOM;
+	i2c_list->i2c_settings.addr_type =
+		cam_cmd_i2c_random_wr->header.addr_type;
+	i2c_list->i2c_settings.data_type =
+		cam_cmd_i2c_random_wr->header.data_type;
+
+	for (cnt = 0; cnt < (cam_cmd_i2c_random_wr->header.count);
+		cnt++) {
+		i2c_list->i2c_settings.reg_setting[cnt].reg_addr =
+			cam_cmd_i2c_random_wr->
+			random_wr_payload[cnt].reg_addr;
+		i2c_list->i2c_settings.
+			reg_setting[cnt].reg_data =
+			cam_cmd_i2c_random_wr->
+			random_wr_payload[cnt].reg_data;
+		i2c_list->i2c_settings.
+			reg_setting[cnt].data_mask = 0;
+	}
+	(*offset) += cnt;
+	*list = &(i2c_list->list);
+
+	return rc;
+}
+
+/**
+ * Name : cam_sensor_i2c_pkt_parser
+ * Description : Parse CSL CCI packet and apply register settings
+ * Parameters :  s_ctrl  input/output    sub_device
+ *              arg     input           cam_control
+ * Description :
+ * Handle multiple I2C RD/WR and WAIT cmd formats in one command
+ * buffer, for example, a command buffer of m x RND_WR + 1 x HW_
+ * WAIT + n x RND_WR with num_cmd_buf = 1. Do not exepect RD/WR
+ * with different cmd_type and op_code in one command buffer.
+ */
+int cam_sensor_i2c_pkt_parser(struct i2c_settings_array *i2c_reg_settings,
+	struct cam_cmd_buf_desc   *cmd_desc, int32_t num_cmd_buffers)
+{
+	int16_t                   rc = 0, i = 0;
+	size_t                    len_of_buff = 0;
+	uint64_t                  generic_ptr;
+
+	for (i = 0; i < num_cmd_buffers; i++) {
+		uint32_t                  *cmd_buf = NULL;
+		struct common_header      *cmm_hdr;
+		uint16_t                  generic_op_code;
+		uint32_t                  byte_cnt = 0;
+		uint32_t                  j = 0;
+		struct list_head          *list = NULL;
+
+		/*
+		 * It is not expected the same settings to
+		 * be spread across multiple cmd buffers
+		 */
+
+		CDBG("%s:%d Total cmd Buf in Bytes: %d\n", __func__,
+			__LINE__, cmd_desc[i].length);
+
+		if (!cmd_desc[i].length)
+			continue;
+
+		rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle,
+			(uint64_t *)&generic_ptr, &len_of_buff);
+		cmd_buf = (uint32_t *)generic_ptr;
+		if (rc < 0) {
+			pr_err("%s:%d Failed in getting cmd hdl: %d Err: %d Buffer Len: %ld\n",
+				__func__, __LINE__,
+				cmd_desc[i].mem_handle, rc,
+				len_of_buff);
+			return rc;
+		}
+		cmd_buf += cmd_desc[i].offset / sizeof(uint32_t);
+
+		while (byte_cnt < cmd_desc[i].length) {
+			cmm_hdr = (struct common_header *)cmd_buf;
+			generic_op_code = cmm_hdr->third_byte;
+			switch (cmm_hdr->cmd_type) {
+			case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR: {
+				uint16_t cmd_length_in_bytes   = 0;
+				struct cam_cmd_i2c_random_wr
+					*cam_cmd_i2c_random_wr =
+					(struct cam_cmd_i2c_random_wr *)cmd_buf;
+
+				rc = cam_sensor_handle_random_write(
+					cam_cmd_i2c_random_wr,
+					i2c_reg_settings,
+					&cmd_length_in_bytes, &j, &list);
+				if (rc < 0) {
+					pr_err("%s:%d :Error: Failed in random read %d\n",
+						__func__, __LINE__, rc);
+					return rc;
+				}
+
+				cmd_buf += cmd_length_in_bytes /
+					sizeof(uint32_t);
+				byte_cnt += cmd_length_in_bytes;
+				break;
+			}
+			case CAMERA_SENSOR_CMD_TYPE_WAIT: {
+				if (generic_op_code ==
+					CAMERA_SENSOR_WAIT_OP_HW_UCND ||
+					generic_op_code ==
+						CAMERA_SENSOR_WAIT_OP_SW_UCND) {
+
+					rc = cam_sensor_handle_delay(
+						&cmd_buf, generic_op_code,
+						i2c_reg_settings, j, &byte_cnt,
+						list);
+					if (rc < 0) {
+						pr_err("%s:%d :Error: Failed in handling delay %d\n",
+							__func__, __LINE__, rc);
+						return rc;
+					}
+
+				} else if (generic_op_code ==
+					CAMERA_SENSOR_WAIT_OP_COND) {
+					rc = cam_sensor_handle_poll(
+						&cmd_buf, i2c_reg_settings,
+						&byte_cnt, &j, &list);
+					if (rc < 0) {
+						pr_err("%s:%d :Error: Failed in random read %d\n",
+							__func__, __LINE__, rc);
+						return rc;
+					}
+				} else {
+					pr_err("%s: %d Wrong Wait Command: %d\n",
+						__func__, __LINE__,
+						generic_op_code);
+					return -EINVAL;
+				}
+				break;
+			}
+			default:
+				pr_err("%s:%d Invalid Command Type:%d\n",
+					__func__, __LINE__, cmm_hdr->cmd_type);
+				return -EINVAL;
+			}
+		}
+		i2c_reg_settings->is_settings_valid = 1;
+	}
+
+	return rc;
+}
+
+int32_t msm_camera_fill_vreg_params(struct camera_vreg_t *cam_vreg,
+	int num_vreg, struct cam_sensor_power_setting *power_setting,
+	uint16_t power_setting_size)
+{
+	int32_t rc = 0, j = 0, i = 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++) {
+		switch (power_setting[i].seq_type) {
+		case SENSOR_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;
+				}
+			}
+			if (j == num_vreg)
+				power_setting[i].seq_val = INVALID_VREG;
+			break;
+
+		case SENSOR_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;
+				}
+			}
+			if (j == num_vreg)
+				power_setting[i].seq_val = INVALID_VREG;
+			break;
+
+		case SENSOR_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;
+				}
+			}
+			if (j == num_vreg)
+				power_setting[i].seq_val = INVALID_VREG;
+			break;
+
+		case SENSOR_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;
+				}
+			}
+			if (j == num_vreg)
+				power_setting[i].seq_val = INVALID_VREG;
+			break;
+
+		case SENSOR_CUSTOM_REG1:
+			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;
+				}
+			}
+			if (j == num_vreg)
+				power_setting[i].seq_val = INVALID_VREG;
+			break;
+		case SENSOR_CUSTOM_REG2:
+			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;
+				}
+			}
+			if (j == num_vreg)
+				power_setting[i].seq_val = INVALID_VREG;
+			break;
+
+		default: {
+			pr_err("%s:%d invalid seq_val %d\n", __func__,
+				__LINE__, power_setting[i].seq_val);
+			break;
+			}
+		}
+	}
+
+	return rc;
+}
+
+int32_t 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)
+{
+	int32_t rc = 0, i = 0;
+	uint32_t count = 0, *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 free_val_array;
+	}
+	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 free_gpio_req_tbl;
+	}
+
+	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 free_gpio_req_tbl;
+	}
+
+	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 free_gpio_req_tbl;
+		}
+	}
+
+	kfree(val_array);
+
+	return rc;
+
+free_gpio_req_tbl:
+	kfree(gconf->cam_gpio_req_tbl);
+free_val_array:
+	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)
+		return -ENOMEM;
+
+	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 free_gpio_info;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-vana invalid %d\n",
+				__func__, __LINE__, val);
+			rc = -EINVAL;
+			goto free_gpio_info;
+		}
+		gconf->gpio_num_info->gpio_num[SENSOR_VANA] =
+			gpio_array[val];
+		gconf->gpio_num_info->valid[SENSOR_VANA] = 1;
+		CDBG("%s qcom,gpio-vana %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[SENSOR_VANA]);
+	}
+
+	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 free_gpio_info;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-vio invalid %d\n",
+				__func__, __LINE__, val);
+			goto free_gpio_info;
+		}
+		gconf->gpio_num_info->gpio_num[SENSOR_VIO] =
+			gpio_array[val];
+		gconf->gpio_num_info->valid[SENSOR_VIO] = 1;
+		CDBG("%s qcom,gpio-vio %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[SENSOR_VIO]);
+	}
+
+	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 free_gpio_info;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-vaf invalid %d\n",
+				__func__, __LINE__, val);
+			rc = -EINVAL;
+			goto free_gpio_info;
+		}
+		gconf->gpio_num_info->gpio_num[SENSOR_VAF] =
+			gpio_array[val];
+		gconf->gpio_num_info->valid[SENSOR_VAF] = 1;
+		CDBG("%s qcom,gpio-vaf %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[SENSOR_VAF]);
+	}
+
+	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 free_gpio_info;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-vdig invalid %d\n",
+				__func__, __LINE__, val);
+			rc = -EINVAL;
+			goto free_gpio_info;
+		}
+		gconf->gpio_num_info->gpio_num[SENSOR_VDIG] =
+			gpio_array[val];
+		gconf->gpio_num_info->valid[SENSOR_VDIG] = 1;
+		CDBG("%s qcom,gpio-vdig %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[SENSOR_VDIG]);
+	}
+
+	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 free_gpio_info;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-reset invalid %d\n",
+				__func__, __LINE__, val);
+			rc = -EINVAL;
+			goto free_gpio_info;
+		}
+		gconf->gpio_num_info->gpio_num[SENSOR_RESET] =
+			gpio_array[val];
+		gconf->gpio_num_info->valid[SENSOR_RESET] = 1;
+		CDBG("%s qcom,gpio-reset %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[SENSOR_RESET]);
+	}
+
+	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 free_gpio_info;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-standby invalid %d\n",
+				__func__, __LINE__, val);
+			rc = -EINVAL;
+			goto free_gpio_info;
+		}
+		gconf->gpio_num_info->gpio_num[SENSOR_STANDBY] =
+			gpio_array[val];
+		gconf->gpio_num_info->valid[SENSOR_STANDBY] = 1;
+		CDBG("%s qcom,gpio-standby %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[SENSOR_STANDBY]);
+	}
+
+	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 free_gpio_info;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-af-pwdm invalid %d\n",
+				__func__, __LINE__, val);
+			rc = -EINVAL;
+			goto free_gpio_info;
+		}
+		gconf->gpio_num_info->gpio_num[SENSOR_VAF_PWDM] =
+			gpio_array[val];
+		gconf->gpio_num_info->valid[SENSOR_VAF_PWDM] = 1;
+		CDBG("%s qcom,gpio-af-pwdm %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[SENSOR_VAF_PWDM]);
+	}
+
+	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 free_gpio_info;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-custom1 invalid %d\n",
+				__func__, __LINE__, val);
+			rc = -EINVAL;
+			goto free_gpio_info;
+		}
+		gconf->gpio_num_info->gpio_num[SENSOR_CUSTOM_GPIO1] =
+			gpio_array[val];
+		gconf->gpio_num_info->valid[SENSOR_CUSTOM_GPIO1] = 1;
+		CDBG("%s qcom,gpio-custom1 %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[SENSOR_CUSTOM_GPIO1]);
+	}
+
+	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 free_gpio_info;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-custom2 invalid %d\n",
+				__func__, __LINE__, val);
+			rc = -EINVAL;
+			goto free_gpio_info;
+		}
+		gconf->gpio_num_info->gpio_num[SENSOR_CUSTOM_GPIO2] =
+			gpio_array[val];
+		gconf->gpio_num_info->valid[SENSOR_CUSTOM_GPIO2] = 1;
+		CDBG("%s qcom,gpio-custom2 %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[SENSOR_CUSTOM_GPIO2]);
+	} else {
+		rc = 0;
+	}
+
+	return rc;
+
+free_gpio_info:
+	kfree(gconf->gpio_num_info);
+	gconf->gpio_num_info = NULL;
+	return rc;
+}
+
+int cam_sensor_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;
+
+	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 free_vreg;
+		}
+	}
+
+	vreg_array = kcalloc(count, sizeof(uint32_t), GFP_KERNEL);
+	if (!vreg_array) {
+		rc = -ENOMEM;
+		goto free_vreg;
+	}
+
+	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 free_vreg_array;
+		} 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 free_vreg_array;
+		} 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 free_vreg_array;
+		} 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 free_vreg_array;
+		} 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;
+
+free_vreg_array:
+	kfree(vreg_array);
+free_vreg:
+	kfree(vreg);
+	*num_vreg = 0;
+
+	return rc;
+}
+
+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;
+}
+
+int msm_cam_sensor_handle_reg_gpio(int seq_type,
+	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 type: %d, config: %d", __func__, __LINE__,
+		seq_type, val);
+
+	gpio_offset = seq_type;
+
+	if ((gconf->gpio_num_info->valid[gpio_offset] == 1)) {
+		CDBG("%s: %d VALID GPIO offset: %d, seqtype: %d\n",
+			__func__, __LINE__,	gpio_offset, seq_type);
+		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(*gconf), 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_array;
+	}
+
+	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_array:
+	kfree(gpio_array);
+free_gpio_conf:
+	kfree(gconf);
+	*gpio_conf = NULL;
+
+	return rc;
+}
+
+int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl)
+{
+	int rc = 0, index = 0, no_gpio = 0, ret = 0, num_vreg, j = 0;
+	struct cam_sensor_power_setting *power_setting = NULL;
+	struct camera_vreg_t *cam_vreg;
+
+	CDBG("%s:%d\n", __func__, __LINE__);
+	if (!ctrl) {
+		pr_err("failed ctrl %pK\n", ctrl);
+		return -EINVAL;
+	}
+
+	cam_vreg = ctrl->cam_vreg;
+	num_vreg = ctrl->num_vreg;
+
+	if (ctrl->gpio_conf->cam_gpiomux_conf_tbl != NULL)
+		CDBG("%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];
+
+		switch (power_setting->seq_type) {
+		case SENSOR_MCLK:
+			if (power_setting->seq_val >= ctrl->clk_info_size) {
+				pr_err("%s:%d :Error: clk index %d >= max %zu\n",
+					__func__, __LINE__,
+					power_setting->seq_val,
+					ctrl->clk_info_size);
+				goto power_up_failed;
+			}
+			for (j = 0; j < num_vreg; j++) {
+				if (!strcmp(cam_vreg[j].reg_name,
+					"cam_clk")) {
+					CDBG("%s:%d Enable cam_clk: %d\n",
+						__func__, __LINE__, j);
+					msm_camera_config_single_vreg(ctrl->dev,
+						&cam_vreg[j],
+						(struct regulator **)
+						&power_setting->data[0],
+						1);
+				}
+			}
+			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("%s: clk enable failed\n", __func__);
+				goto power_up_failed;
+			}
+			break;
+		case SENSOR_RESET:
+		case SENSOR_STANDBY:
+		case SENSOR_CUSTOM_GPIO1:
+		case SENSOR_CUSTOM_GPIO2:
+			if (no_gpio) {
+				pr_err("%s: request gpio failed\n", __func__);
+				return no_gpio;
+			}
+			if (power_setting->seq_val >= CAM_VREG_MAX ||
+				!ctrl->gpio_conf->gpio_num_info) {
+				pr_err("%s gpio index %d >= max %d\n", __func__,
+					power_setting->seq_val,
+					CAM_VREG_MAX);
+				goto power_up_failed;
+			}
+			CDBG("%s:%d gpio set val %d\n",
+				__func__, __LINE__,
+				ctrl->gpio_conf->gpio_num_info->gpio_num
+				[power_setting->seq_val]);
+
+			rc = msm_cam_sensor_handle_reg_gpio(
+				power_setting->seq_type,
+				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_VANA:
+		case SENSOR_VDIG:
+		case SENSOR_VIO:
+		case SENSOR_VAF:
+		case SENSOR_VAF_PWDM:
+		case SENSOR_CUSTOM_REG1:
+		case SENSOR_CUSTOM_REG2:
+			if (power_setting->seq_val == INVALID_VREG)
+				break;
+
+			if (power_setting->seq_val >= CAM_VREG_MAX) {
+				pr_err("%s vreg index %d >= max %d\n", __func__,
+					power_setting->seq_val,
+					CAM_VREG_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_type,
+				ctrl->gpio_conf, 1);
+			if (rc < 0) {
+				pr_err("ERR:%s Error in handling VREG GPIO\n",
+					__func__);
+				goto power_up_failed;
+			}
+			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);
+	}
+
+	return 0;
+power_up_failed:
+	pr_err("%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_RESET:
+		case SENSOR_STANDBY:
+		case SENSOR_CUSTOM_GPIO1:
+		case SENSOR_CUSTOM_GPIO2:
+			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_VANA:
+		case SENSOR_VDIG:
+		case SENSOR_VIO:
+		case SENSOR_VAF:
+		case SENSOR_VAF_PWDM:
+		case SENSOR_CUSTOM_REG1:
+		case SENSOR_CUSTOM_REG2:
+			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_type,
+				ctrl->gpio_conf, GPIOF_OUT_INIT_LOW);
+			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 cam_sensor_power_setting*
+msm_camera_get_power_settings(struct cam_sensor_power_ctrl_t *ctrl,
+				enum msm_camera_power_seq_type seq_type,
+				uint16_t seq_val)
+{
+	struct cam_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;
+}
+
+static int cam_config_mclk_reg(struct cam_sensor_power_ctrl_t *ctrl,
+	int32_t index)
+{
+	struct camera_vreg_t *cam_vreg;
+	int32_t num_vreg = 0, j = 0, rc = 0, idx = 0;
+	struct cam_sensor_power_setting *ps = NULL;
+	struct cam_sensor_power_setting *pd = NULL;
+
+	cam_vreg = ctrl->cam_vreg;
+	num_vreg = ctrl->num_vreg;
+	pd = &ctrl->power_down_setting[index];
+
+	for (j = 0; j < num_vreg; j++) {
+		if (!strcmp(cam_vreg[j].reg_name, "cam_clk")) {
+
+			ps = NULL;
+			for (idx = 0; idx <
+				ctrl->power_setting_size; idx++) {
+				if (ctrl->power_setting[idx].
+					seq_type == pd->seq_type) {
+					ps = &ctrl->power_setting[idx];
+					break;
+				}
+			}
+
+			if (ps != NULL)
+				msm_camera_config_single_vreg(
+					ctrl->dev,
+					&cam_vreg[j],
+					(struct regulator **)
+					&ps->data[0], 0);
+		}
+	}
+
+	return rc;
+}
+
+int msm_camera_power_down(struct cam_sensor_power_ctrl_t *ctrl)
+{
+	int index = 0, ret = 0, num_vreg = 0;
+	struct cam_sensor_power_setting *pd = NULL;
+	struct cam_sensor_power_setting *ps;
+	struct camera_vreg_t *cam_vreg;
+
+	CDBG("%s:%d\n", __func__, __LINE__);
+	if (!ctrl) {
+		pr_err("failed ctrl %pK\n", ctrl);
+		return -EINVAL;
+	}
+
+	cam_vreg = ctrl->cam_vreg;
+	num_vreg = ctrl->num_vreg;
+
+	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_MCLK:
+			ret = cam_config_mclk_reg(ctrl, index);
+			if (ret < 0) {
+				pr_err("%s:%d :Error: in config clk reg\n",
+					__func__, __LINE__);
+				return ret;
+			}
+			msm_camera_clk_enable(ctrl->dev,
+				ctrl->clk_info, ctrl->clk_ptr,
+				ctrl->clk_info_size, false);
+			break;
+		case SENSOR_RESET:
+		case SENSOR_STANDBY:
+		case SENSOR_CUSTOM_GPIO1:
+		case SENSOR_CUSTOM_GPIO2:
+			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_VANA:
+		case SENSOR_VDIG:
+		case SENSOR_VIO:
+		case SENSOR_VAF:
+		case SENSOR_VAF_PWDM:
+		case SENSOR_CUSTOM_REG1:
+		case SENSOR_CUSTOM_REG2:
+			if (pd->seq_val == INVALID_VREG)
+				break;
+			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_type,
+				ctrl->gpio_conf, GPIOF_OUT_INIT_LOW);
+			if (ret < 0)
+				pr_err("ERR:%s Error while disabling VREG GPIO\n",
+					__func__);
+			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);
+
+	return 0;
+}
+
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h
new file mode 100644
index 0000000..7e7fc35
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h
@@ -0,0 +1,62 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_SENSOR_UTIL_H_
+#define _CAM_SENSOR_UTIL_H_
+
+#include <linux/kernel.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/of.h>
+#include <cam_sensor_cmn_header.h>
+#include <cam_req_mgr_util.h>
+#include <cam_req_mgr_interface.h>
+#include <cam_mem_mgr.h>
+
+#define INVALID_VREG 100
+
+int msm_camera_get_dt_power_setting_data(struct device_node *of_node,
+	struct camera_vreg_t *cam_vreg, int num_vreg,
+	struct cam_sensor_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 cam_sensor_get_dt_vreg_data(struct device_node *of_node,
+	struct camera_vreg_t **cam_vreg, int *num_vreg);
+
+int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl);
+
+int msm_camera_power_down(struct cam_sensor_power_ctrl_t *ctrl);
+
+int msm_camera_fill_vreg_params(struct camera_vreg_t *cam_vreg,
+	int num_vreg, struct cam_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);
+
+int cam_sensor_i2c_pkt_parser(struct i2c_settings_array *i2c_reg_settings,
+	struct cam_cmd_buf_desc *cmd_desc, int32_t num_cmd_buffers);
+
+int32_t delete_request(struct i2c_settings_array *i2c_array);
+#endif /* _CAM_SENSOR_UTIL_H_ */
diff --git a/drivers/media/platform/msm/camera/icp/Makefile b/drivers/media/platform/msm/camera/icp/Makefile
new file mode 100644
index 0000000..c42b162
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/Makefile
@@ -0,0 +1,14 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_core
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sync
+ccflags-y += -Idrivers/media/platform/msm/camera/icp
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/include
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/fw_inc
+ccflags-y += -Idrivers/media/platform/msm/camera
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+
+
+obj-$(CONFIG_SPECTRA_CAMERA) += icp_hw/
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_icp_subdev.o cam_icp_context.o hfi.o
diff --git a/drivers/media/platform/msm/camera/icp/cam_icp_context.c b/drivers/media/platform/msm/camera/icp/cam_icp_context.c
new file mode 100644
index 0000000..41290f4
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/cam_icp_context.c
@@ -0,0 +1,195 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "CAM-ICP-CTXT %s:%d " fmt, __func__, __LINE__
+
+#include <linux/debugfs.h>
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <media/cam_sync.h>
+#include <media/cam_defs.h>
+#include "cam_sync_api.h"
+#include "cam_node.h"
+#include "cam_context.h"
+#include "cam_context_utils.h"
+#include "cam_icp_context.h"
+#include "cam_req_mgr_util.h"
+#include "cam_mem_mgr.h"
+
+static int __cam_icp_acquire_dev_in_available(struct cam_context *ctx,
+	struct cam_acquire_dev_cmd *cmd)
+{
+	int rc;
+
+	rc = cam_context_acquire_dev_to_hw(ctx, cmd);
+	if (!rc)
+		ctx->state = CAM_CTX_ACQUIRED;
+
+	return rc;
+}
+
+static int __cam_icp_release_dev_in_acquired(struct cam_context *ctx,
+	struct cam_release_dev_cmd *cmd)
+{
+	int rc;
+
+	rc = cam_context_release_dev_to_hw(ctx, cmd);
+	if (rc)
+		pr_err("Unable to release device\n");
+
+	ctx->state = CAM_CTX_AVAILABLE;
+	return rc;
+}
+
+static int __cam_icp_start_dev_in_acquired(struct cam_context *ctx,
+	struct cam_start_stop_dev_cmd *cmd)
+{
+	int rc;
+
+	rc = cam_context_start_dev_to_hw(ctx, cmd);
+	if (!rc)
+		ctx->state = CAM_CTX_READY;
+
+	return rc;
+}
+
+static int __cam_icp_config_dev_in_ready(struct cam_context *ctx,
+	struct cam_config_dev_cmd *cmd)
+{
+	int rc;
+
+	rc = cam_context_prepare_dev_to_hw(ctx, cmd);
+	if (rc)
+		pr_err("Unable to prepare device\n");
+
+	return rc;
+}
+
+static int __cam_icp_stop_dev_in_ready(struct cam_context *ctx,
+	struct cam_start_stop_dev_cmd *cmd)
+{
+	int rc;
+
+	rc = cam_context_stop_dev_to_hw(ctx);
+	if (rc)
+		pr_err("Unable to stop device\n");
+
+	ctx->state = CAM_CTX_ACQUIRED;
+	return rc;
+}
+
+static int __cam_icp_release_dev_in_ready(struct cam_context *ctx,
+	struct cam_release_dev_cmd *cmd)
+{
+	int rc;
+
+	rc = __cam_icp_stop_dev_in_ready(ctx, NULL);
+	if (rc)
+		pr_err("Unable to stop device\n");
+
+	rc = __cam_icp_release_dev_in_acquired(ctx, cmd);
+	if (rc)
+		pr_err("Unable to stop device\n");
+
+	return rc;
+}
+
+static int __cam_icp_handle_buf_done_in_ready(void *ctx,
+	uint32_t evt_id, void *done)
+{
+	return cam_context_buf_done_from_hw(ctx, done, 0);
+}
+
+static struct cam_ctx_ops
+	cam_icp_ctx_state_machine[CAM_CTX_STATE_MAX] = {
+	/* Uninit */
+	{
+		.ioctl_ops = {},
+		.crm_ops = {},
+		.irq_ops = NULL,
+	},
+	/* Available */
+	{
+		.ioctl_ops = {
+			.acquire_dev = __cam_icp_acquire_dev_in_available,
+		},
+		.crm_ops = {},
+		.irq_ops = NULL,
+	},
+	/* Acquired */
+	{
+		.ioctl_ops = {
+			.release_dev = __cam_icp_release_dev_in_acquired,
+			.start_dev = __cam_icp_start_dev_in_acquired,
+			.config_dev = __cam_icp_config_dev_in_ready,
+		},
+		.crm_ops = {},
+		.irq_ops = __cam_icp_handle_buf_done_in_ready,
+	},
+	/* Ready */
+	{
+		.ioctl_ops = {
+			.stop_dev = __cam_icp_stop_dev_in_ready,
+			.release_dev = __cam_icp_release_dev_in_ready,
+			.config_dev = __cam_icp_config_dev_in_ready,
+		},
+		.crm_ops = {},
+		.irq_ops = __cam_icp_handle_buf_done_in_ready,
+	},
+	/* Activated */
+	{
+		.ioctl_ops = {},
+		.crm_ops = {},
+		.irq_ops = NULL,
+	},
+};
+
+int cam_icp_context_init(struct cam_icp_context *ctx,
+	struct cam_hw_mgr_intf *hw_intf)
+{
+	int rc;
+
+	if ((!ctx) || (!ctx->base) || (!hw_intf)) {
+		pr_err("Invalid params: %pK %pK\n", ctx, hw_intf);
+		rc = -EINVAL;
+		goto err;
+	}
+
+	rc = cam_context_init(ctx->base, NULL, hw_intf, ctx->req_base,
+		CAM_CTX_REQ_MAX);
+	if (rc) {
+		pr_err("Camera Context Base init failed!\n");
+		goto err;
+	}
+
+	ctx->base->state_machine = cam_icp_ctx_state_machine;
+	ctx->base->ctx_priv = ctx;
+	ctx->ctxt_to_hw_map = NULL;
+
+err:
+	return rc;
+}
+
+int cam_icp_context_deinit(struct cam_icp_context *ctx)
+{
+	if ((!ctx) || (!ctx->base)) {
+		pr_err("Invalid params: %pK\n", ctx);
+		return -EINVAL;
+	}
+
+	cam_context_deinit(ctx->base);
+	memset(ctx, 0, sizeof(*ctx));
+
+	return 0;
+}
+
diff --git a/drivers/media/platform/msm/camera/icp/cam_icp_context.h b/drivers/media/platform/msm/camera/icp/cam_icp_context.h
new file mode 100644
index 0000000..709fc56
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/cam_icp_context.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_ICP_CONTEXT_H_
+#define _CAM_ICP_CONTEXT_H_
+
+#include "cam_context.h"
+
+/**
+ * struct cam_icp_context - icp context
+ * @base: icp context object
+ * @state_machine: state machine for ICP context
+ * @req_base: common request structure
+ * @state: icp context state
+ * @ctxt_to_hw_map: context to FW handle mapping
+ */
+struct cam_icp_context {
+	struct cam_context *base;
+	struct cam_ctx_ops *state_machine;
+	struct cam_ctx_request req_base[CAM_CTX_REQ_MAX];
+	uint32_t state;
+	void *ctxt_to_hw_map;
+};
+
+/**
+ * cam_icp_context_init() - ICP context init
+ * @ctx: Pointer to context
+ * @hw_intf: Pointer to ICP hardware interface
+ */
+int cam_icp_context_init(struct cam_icp_context *ctx,
+	struct cam_hw_mgr_intf *hw_intf);
+
+/**
+ * cam_icp_context_deinit() - ICP context deinit
+ * @ctx: Pointer to context
+ */
+int cam_icp_context_deinit(struct cam_icp_context *ctx);
+
+#endif /* _CAM_ICP_CONTEXT_H_ */
diff --git a/drivers/media/platform/msm/camera/icp/cam_icp_subdev.c b/drivers/media/platform/msm/camera/icp/cam_icp_subdev.c
new file mode 100644
index 0000000..703561d
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/cam_icp_subdev.c
@@ -0,0 +1,259 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "CAM-ICP %s:%d " fmt, __func__, __LINE__
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/iommu.h>
+#include <linux/timer.h>
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-subdev.h>
+#include <media/cam_req_mgr.h>
+#include <media/cam_defs.h>
+#include <media/cam_icp.h>
+#include "cam_req_mgr_dev.h"
+#include "cam_subdev.h"
+#include "cam_node.h"
+#include "cam_context.h"
+#include "cam_icp_context.h"
+#include "cam_hw_mgr_intf.h"
+#include "cam_icp_hw_mgr_intf.h"
+
+#define CAM_ICP_DEV_NAME        "cam-icp"
+
+struct cam_icp_subdev {
+	struct cam_subdev sd;
+	struct cam_node *node;
+	struct cam_context ctx[CAM_CTX_MAX];
+	struct cam_icp_context ctx_icp[CAM_CTX_MAX];
+	struct mutex icp_lock;
+	int32_t open_cnt;
+	int32_t reserved;
+};
+
+static struct cam_icp_subdev g_icp_dev;
+
+static const struct of_device_id cam_icp_dt_match[] = {
+	{.compatible = "qcom,cam-icp"},
+	{}
+};
+
+static int cam_icp_subdev_open(struct v4l2_subdev *sd,
+	struct v4l2_subdev_fh *fh)
+{
+	struct cam_hw_mgr_intf *hw_mgr_intf = NULL;
+	struct cam_node *node = v4l2_get_subdevdata(sd);
+	int rc = 0;
+
+	mutex_lock(&g_icp_dev.icp_lock);
+	if (g_icp_dev.open_cnt >= 1) {
+		pr_err("ICP subdev is already opened\n");
+		rc = -EALREADY;
+		goto end;
+	}
+
+	if (!node) {
+		pr_err("Invalid args\n");
+		rc = -EINVAL;
+		goto end;
+	}
+
+	hw_mgr_intf = &node->hw_mgr_intf;
+	rc = hw_mgr_intf->download_fw(hw_mgr_intf->hw_mgr_priv, NULL);
+	if (rc < 0) {
+		pr_err("FW download failed\n");
+		goto end;
+	}
+	g_icp_dev.open_cnt++;
+end:
+	mutex_unlock(&g_icp_dev.icp_lock);
+	return rc;
+}
+
+static int cam_icp_subdev_close(struct v4l2_subdev *sd,
+	struct v4l2_subdev_fh *fh)
+{
+	int rc = 0;
+	struct cam_hw_mgr_intf *hw_mgr_intf = NULL;
+	struct cam_node *node = v4l2_get_subdevdata(sd);
+
+	mutex_lock(&g_icp_dev.icp_lock);
+	if (g_icp_dev.open_cnt <= 0) {
+		pr_err("ICP subdev is already closed\n");
+		rc = -EINVAL;
+		goto end;
+	}
+	g_icp_dev.open_cnt--;
+	if (!node) {
+		pr_err("Invalid args\n");
+		rc = -EINVAL;
+		goto end;
+	}
+
+	hw_mgr_intf = &node->hw_mgr_intf;
+	if (!hw_mgr_intf) {
+		pr_err("hw_mgr_intf is not initialized\n");
+		rc = -EINVAL;
+		goto end;
+	}
+
+	rc = hw_mgr_intf->hw_close(hw_mgr_intf->hw_mgr_priv, NULL);
+	if (rc < 0) {
+		pr_err("HW close failed\n");
+		goto end;
+	}
+
+end:
+	mutex_unlock(&g_icp_dev.icp_lock);
+	return 0;
+}
+
+const struct v4l2_subdev_internal_ops cam_icp_subdev_internal_ops = {
+	.open = cam_icp_subdev_open,
+	.close = cam_icp_subdev_close,
+};
+
+static int cam_icp_probe(struct platform_device *pdev)
+{
+	int rc = 0, i = 0;
+	struct cam_node *node;
+	struct cam_hw_mgr_intf *hw_mgr_intf;
+
+	if (!pdev) {
+		pr_err("pdev is NULL\n");
+		return -EINVAL;
+	}
+
+	memset(&g_icp_dev, 0, sizeof(g_icp_dev));
+
+	g_icp_dev.sd.pdev = pdev;
+	g_icp_dev.sd.internal_ops = &cam_icp_subdev_internal_ops;
+	rc = cam_subdev_probe(&g_icp_dev.sd, pdev, CAM_ICP_DEV_NAME,
+		CAM_ICP_DEVICE_TYPE);
+	if (rc) {
+		pr_err("ICP cam_subdev_probe failed!\n");
+		goto probe_fail;
+	}
+
+	node = (struct cam_node *) g_icp_dev.sd.token;
+
+	hw_mgr_intf = kzalloc(sizeof(*hw_mgr_intf), GFP_KERNEL);
+	if (!hw_mgr_intf) {
+		rc = -EINVAL;
+		goto hw_alloc_fail;
+	}
+
+	rc = cam_icp_hw_mgr_init(pdev->dev.of_node, (uint64_t *)hw_mgr_intf);
+	if (rc) {
+		pr_err("ICP HW manager init failed: %d\n", rc);
+		goto hw_init_fail;
+	}
+
+	pr_debug("Initializing the ICP contexts\n");
+	for (i = 0; i < CAM_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);
+		if (rc) {
+			pr_err("ICP context init failed!\n");
+			goto ctx_fail;
+		}
+	}
+
+	pr_debug("Initializing the ICP Node\n");
+	rc = cam_node_init(node, hw_mgr_intf, g_icp_dev.ctx,
+				CAM_CTX_MAX, CAM_ICP_DEV_NAME);
+	if (rc) {
+		pr_err("ICP node init failed!\n");
+		goto ctx_fail;
+	}
+
+	g_icp_dev.open_cnt = 0;
+	mutex_init(&g_icp_dev.icp_lock);
+
+	return rc;
+
+ctx_fail:
+	for (--i; i >= 0; i--)
+		cam_icp_context_deinit(&g_icp_dev.ctx_icp[i]);
+hw_init_fail:
+	kfree(hw_mgr_intf);
+hw_alloc_fail:
+	cam_subdev_remove(&g_icp_dev.sd);
+probe_fail:
+	return rc;
+}
+
+static int cam_icp_remove(struct platform_device *pdev)
+{
+	int i;
+	struct v4l2_subdev *sd;
+	struct cam_subdev *subdev;
+
+	if (!pdev) {
+		pr_err("pdev is NULL\n");
+		return -EINVAL;
+	}
+
+	sd = platform_get_drvdata(pdev);
+	if (!sd) {
+		pr_err("V4l2 subdev is NULL\n");
+		return -EINVAL;
+	}
+
+	subdev = v4l2_get_subdevdata(sd);
+	if (!subdev) {
+		pr_err("cam subdev is NULL\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < CAM_CTX_MAX; i++)
+		cam_icp_context_deinit(&g_icp_dev.ctx_icp[i]);
+	cam_node_deinit(g_icp_dev.node);
+	cam_subdev_remove(&g_icp_dev.sd);
+	mutex_destroy(&g_icp_dev.icp_lock);
+
+	return 0;
+}
+
+static struct platform_driver cam_icp_driver = {
+	.probe = cam_icp_probe,
+	.remove = cam_icp_remove,
+	.driver = {
+		.name = "cam_icp",
+		.owner = THIS_MODULE,
+		.of_match_table = cam_icp_dt_match,
+	},
+};
+
+static int __init cam_icp_init_module(void)
+{
+	return platform_driver_register(&cam_icp_driver);
+}
+
+static void __exit cam_icp_exit_module(void)
+{
+	platform_driver_unregister(&cam_icp_driver);
+}
+module_init(cam_icp_init_module);
+module_exit(cam_icp_exit_module);
+MODULE_DESCRIPTION("MSM ICP driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera/icp/fw_inc/hfi_intf.h b/drivers/media/platform/msm/camera/icp/fw_inc/hfi_intf.h
new file mode 100644
index 0000000..1e42f75
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/fw_inc/hfi_intf.h
@@ -0,0 +1,105 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _HFI_INTF_H_
+#define _HFI_INTF_H_
+
+#include <linux/types.h>
+
+/**
+ * struct hfi_mem
+ * @len: length of memory
+ * @kva: kernel virtual address
+ * @iova: IO virtual address
+ * @reserved: reserved field
+ */
+struct hfi_mem {
+	uint64_t len;
+	uint64_t kva;
+	uint32_t iova;
+	uint32_t reserved;
+};
+
+/**
+ * struct hfi_mem_info
+ * @qtbl: qtable hfi memory
+ * @cmd_q: command queue hfi memory for host to firmware communication
+ * @msg_q: message queue hfi memory for firmware to host communication
+ * @dbg_q: debug queue hfi memory for firmware debug information
+ * @sec_heap: secondary heap hfi memory for firmware
+ * @icp_base: icp base address
+ */
+struct hfi_mem_info {
+	struct hfi_mem qtbl;
+	struct hfi_mem cmd_q;
+	struct hfi_mem msg_q;
+	struct hfi_mem dbg_q;
+	struct hfi_mem sec_heap;
+	void __iomem *icp_base;
+};
+
+/**
+ * hfi_write_cmd() - function for hfi write
+ * @cmd_ptr: pointer to command data for hfi write
+ *
+ * Returns success(zero)/failure(non zero)
+ */
+int hfi_write_cmd(void *cmd_ptr);
+
+/**
+ * hfi_read_message() - function for hfi read
+ * @pmsg: buffer to place read message for hfi queue
+ * @q_id: queue id
+ *
+ * Returns success(zero)/failure(non zero)
+ */
+int hfi_read_message(uint32_t *pmsg, uint8_t q_id);
+
+/**
+ * hfi_init() - function initialize hfi after firmware download
+ * @event_driven_mode: event mode
+ * @hfi_mem: hfi memory info
+ * @icp_base: icp base address
+ * @debug: debug flag
+ *
+ * Returns success(zero)/failure(non zero)
+ */
+int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem,
+	void *__iomem icp_base, bool debug);
+
+/**
+ * hfi_get_hw_caps() - hardware capabilities from firmware
+ * @query_caps: holds query information from hfi
+ *
+ * Returns success(zero)/failure(non zero)
+ */
+int hfi_get_hw_caps(void *query_caps);
+
+/**
+ * hfi_send_system_cmd() - send hfi system command to firmware
+ * @type: type of system command
+ * @data: command data
+ * @size: size of command data
+ */
+void hfi_send_system_cmd(uint32_t type, uint64_t data, uint32_t size);
+
+/**
+ * cam_hfi_enable_cpu() - enable A5 CPU
+ * @icp_base: icp base address
+ */
+void cam_hfi_enable_cpu(void __iomem *icp_base);
+/**
+ * cam_hfi_deinit() - cleanup HFI
+ */
+void cam_hfi_deinit(void);
+
+#endif /* _HFI_INTF_H_ */
diff --git a/drivers/media/platform/msm/camera/icp/fw_inc/hfi_reg.h b/drivers/media/platform/msm/camera/icp/fw_inc/hfi_reg.h
new file mode 100644
index 0000000..d1bbe01
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/fw_inc/hfi_reg.h
@@ -0,0 +1,308 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_HFI_REG_H_
+#define _CAM_HFI_REG_H_
+
+#include <linux/types.h>
+#include "hfi_intf.h"
+
+
+/* start of ICP CSR registers */
+#define HFI_REG_A5_HW_VERSION                   0x0
+#define HFI_REG_A5_CSR_NSEC_RESET               0x4
+#define HFI_REG_A5_CSR_A5_CONTROL               0x8
+#define HFI_REG_A5_CSR_ETM                      0xC
+#define HFI_REG_A5_CSR_A2HOSTINTEN              0x10
+#define HFI_REG_A5_CSR_A2HOSTINT                0x14
+#define HFI_REG_A5_CSR_A2HOSTINTCLR             0x18
+#define HFI_REG_A5_CSR_A2HOSTINTSTATUS          0x1C
+#define HFI_REG_A5_CSR_A2HOSTINTSET             0x20
+#define HFI_REG_A5_CSR_HOST2ICPINT              0x30
+#define HFI_REG_A5_CSR_A5_STATUS                0x200
+#define HFI_REG_A5_QGIC2_LM_ID                  0x204
+#define HFI_REG_A5_SPARE                        0x400
+
+/* general purpose registers from */
+#define HFI_REG_FW_VERSION                      0x44
+#define HFI_REG_HOST_ICP_INIT_REQUEST           0x48
+#define HFI_REG_ICP_HOST_INIT_RESPONSE          0x4C
+#define HFI_REG_SHARED_MEM_PTR                  0x50
+#define HFI_REG_SHARED_MEM_SIZE                 0x54
+#define HFI_REG_QTBL_PTR                        0x58
+#define HFI_REG_UNCACHED_HEAP_PTR               0x5C
+#define HFI_REG_UNCACHED_HEAP_SIZE              0x60
+/* end of ICP CSR registers */
+
+/* flags for ICP CSR registers */
+#define ICP_FLAG_CSR_WAKE_UP_EN                 (1 << 4)
+#define ICP_FLAG_CSR_A5_EN                      (1 << 9)
+#define ICP_CSR_EN_CLKGATE_WFI                  (1 << 12)
+#define ICP_CSR_EDBGRQ                          (1 << 14)
+#define ICP_CSR_DBGSWENABLE                     (1 << 22)
+
+/* start of Queue table and queues */
+#define MAX_ICP_HFI_QUEUES                      4
+#define ICP_QHDR_TX_TYPE_MASK                   0xFF000000
+#define ICP_QHDR_RX_TYPE_MASK                   0x00FF0000
+#define ICP_QHDR_PRI_TYPE_MASK                  0x0000FF00
+#define ICP_QHDR_Q_ID_MASK                      0x000000FF
+
+#define ICP_CMD_Q_SIZE_IN_BYTES                 4096
+#define ICP_MSG_Q_SIZE_IN_BYTES                 4096
+#define ICP_DBG_Q_SIZE_IN_BYTES                 8192
+
+#define ICP_SHARED_MEM_IN_BYTES                 (1024 * 1024)
+#define ICP_UNCACHED_HEAP_SIZE_IN_BYTES         (2 * 1024 * 1024)
+#define ICP_HFI_MAX_MSG_SIZE_IN_WORDS           128
+
+#define ICP_HFI_QTBL_HOSTID1                    0x01000000
+#define ICP_HFI_QTBL_STATUS_ENABLED             0x00000001
+#define ICP_HFI_NUMBER_OF_QS                    3
+#define ICP_HFI_NUMBER_OF_ACTIVE_QS             3
+#define ICP_HFI_QTBL_OFFSET                     0
+#define ICP_HFI_VAR_SIZE_PKT                    0
+#define ICP_HFI_MAX_MSG_SIZE_IN_WORDS           128
+
+
+/* Queue Header type masks. Use these to access bitfields in qhdr_type */
+#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 TX_EVENT_DRIVEN_MODE_1                  0
+#define RX_EVENT_DRIVEN_MODE_1                  0
+#define TX_EVENT_DRIVEN_MODE_2                  0x01000000
+#define RX_EVENT_DRIVEN_MODE_2                  0x00010000
+#define TX_EVENT_POLL_MODE_2                    0x02000000
+#define RX_EVENT_POLL_MODE_2                    0x00020000
+#define U32_OFFSET                              0x1
+#define BYTE_WORD_SHIFT                         2
+
+/**
+ * @INVALID: Invalid state
+ * @FW_LOAD_DONE: Firmware load is completed
+ * @FW_RESP_DONE: Firmware response is received
+ * @FW_START_SENT: firmware start is send
+ * @FW_READY: firmware is ready to accept commands
+ */
+enum hfi_state {
+	INVALID,
+	FW_LOAD_DONE,
+	FW_RESP_DONE,
+	FW_START_SENT,
+	FW_READY
+};
+
+/**
+ * @RESET: init success
+ * @SET: init failed
+ */
+enum reg_settings {
+	RESET,
+	SET
+};
+
+/**
+ * @INTR_DISABLE: Disable interrupt
+ * @INTR_ENABLE: Enable interrupt
+ */
+enum intr_status {
+	INTR_DISABLE,
+	INTR_ENABLE
+};
+
+/**
+ * @ICP_INIT_RESP_RESET: reset init state
+ * @ICP_INIT_RESP_SUCCESS: init success
+ * @ICP_INIT_RESP_FAILED: init failed
+ */
+enum host_init_resp {
+	ICP_INIT_RESP_RESET,
+	ICP_INIT_RESP_SUCCESS,
+	ICP_INIT_RESP_FAILED
+};
+
+/**
+ * @ICP_INIT_REQUEST_RESET: reset init request
+ * @ICP_INIT_REQUEST_SET: set init request
+ */
+enum host_init_request {
+	ICP_INIT_REQUEST_RESET,
+	ICP_INIT_REQUEST_SET
+};
+
+/**
+ * @QHDR_INACTIVE: Queue is inactive
+ * @QHDR_ACTIVE: Queue is active
+ */
+enum qhdr_status {
+	QHDR_INACTIVE,
+	QHDR_ACTIVE
+};
+
+/**
+ * @INTR_MODE: event driven mode 1, each send and receive generates interrupt
+ * @WM_MODE: event driven mode 2, interrupts based on watermark mechanism
+ * @POLL_MODE: poll method
+ */
+enum qhdr_event_drv_type {
+	INTR_MODE,
+	WM_MODE,
+	POLL_MODE
+};
+
+/**
+ * @TX_INT: event driven mode 1, each send and receive generates interrupt
+ * @TX_INT_WM: event driven mode 2, interrupts based on watermark mechanism
+ * @TX_POLL: poll method
+ * @ICP_QHDR_TX_TYPE_MASK defines position in qhdr_type
+ */
+enum qhdr_tx_type {
+	TX_INT,
+	TX_INT_WM,
+	TX_POLL
+};
+
+/**
+ * @RX_INT: event driven mode 1, each send and receive generates interrupt
+ * @RX_INT_WM: event driven mode 2, interrupts based on watermark mechanism
+ * @RX_POLL: poll method
+ * @ICP_QHDR_RX_TYPE_MASK defines position in qhdr_type
+ */
+enum qhdr_rx_type {
+	RX_INT,
+	RX_INT_WM,
+	RX_POLL
+};
+
+/**
+ * @Q_CMD: Host to FW command queue
+ * @Q_MSG: FW to Host message queue
+ * @Q_DEBUG: FW to Host debug queue
+ * @ICP_QHDR_Q_ID_MASK defines position in qhdr_type
+ */
+enum qhdr_q_id {
+	Q_CMD,
+	Q_MSG,
+	Q_DBG
+};
+
+/**
+ * struct hfi_qtbl_hdr
+ * @qtbl_version: Queue table version number
+ *                Higher 16 bits: Major version
+ *                Lower 16 bits: Minor version
+ * @qtbl_size: Queue table size from version to last parametr in qhdr entry
+ * @qtbl_qhdr0_offset: Offset to the start of first qhdr
+ * @qtbl_qhdr_size: Queue header size in bytes
+ * @qtbl_num_q: Total number of queues in Queue table
+ * @qtbl_num_active_q: Total number of active queues
+ */
+struct hfi_qtbl_hdr {
+	uint32_t qtbl_version;
+	uint32_t qtbl_size;
+	uint32_t qtbl_qhdr0_offset;
+	uint32_t qtbl_qhdr_size;
+	uint32_t qtbl_num_q;
+	uint32_t qtbl_num_active_q;
+} __packed;
+
+/**
+ * struct hfi_q_hdr
+ * @qhdr_status: Queue status, qhdr_state define possible status
+ * @qhdr_start_addr: Queue start address in non cached memory
+ * @qhdr_type: qhdr_tx, qhdr_rx, qhdr_q_id and priority defines qhdr type
+ * @qhdr_q_size: Queue size
+ *		Number of queue packets if qhdr_pkt_size is non-zero
+ *		Queue size in bytes if qhdr_pkt_size is zero
+ * @qhdr_pkt_size: Size of queue packet entries
+ *		0x0: variable queue packet size
+ *		non zero: size of queue packet entry, fixed
+ * @qhdr_pkt_drop_cnt: Number of packets dropped by sender
+ * @qhdr_rx_wm: Receiver watermark, applicable in event driven mode
+ * @qhdr_tx_wm: Sender watermark, applicable in event driven mode
+ * @qhdr_rx_req: Receiver sets this bit if queue is empty
+ * @qhdr_tx_req: Sender sets this bit if queue is full
+ * @qhdr_rx_irq_status: Receiver sets this bit and triggers an interrupt to
+ *		the sender after packets are dequeued. Sender clears this bit
+ * @qhdr_tx_irq_status: Sender sets this bit and triggers an interrupt to
+ *		the receiver after packets are queued. Receiver clears this bit
+ * @qhdr_read_idx: Read index
+ * @qhdr_write_idx: Write index
+ */
+struct hfi_q_hdr {
+	uint32_t dummy[15];
+	uint32_t qhdr_status;
+	uint32_t dummy1[15];
+	uint32_t qhdr_start_addr;
+	uint32_t dummy2[15];
+	uint32_t qhdr_type;
+	uint32_t dummy3[15];
+	uint32_t qhdr_q_size;
+	uint32_t dummy4[15];
+	uint32_t qhdr_pkt_size;
+	uint32_t dummy5[15];
+	uint32_t qhdr_pkt_drop_cnt;
+	uint32_t dummy6[15];
+	uint32_t qhdr_rx_wm;
+	uint32_t dummy7[15];
+	uint32_t qhdr_tx_wm;
+	uint32_t dummy8[15];
+	uint32_t qhdr_rx_req;
+	uint32_t dummy9[15];
+	uint32_t qhdr_tx_req;
+	uint32_t dummy10[15];
+	uint32_t qhdr_rx_irq_status;
+	uint32_t dummy11[15];
+	uint32_t qhdr_tx_irq_status;
+	uint32_t dummy12[15];
+	uint32_t qhdr_read_idx;
+	uint32_t dummy13[15];
+	uint32_t qhdr_write_idx;
+	uint32_t dummy14[15];
+};
+
+/**
+ * struct hfi_q_tbl
+ * @q_tbl_hdr: Queue table header
+ * @q_hdr: Queue header info, it holds info of cmd, msg and debug queues
+ */
+struct hfi_qtbl {
+	struct hfi_qtbl_hdr q_tbl_hdr;
+	struct hfi_q_hdr q_hdr[MAX_ICP_HFI_QUEUES];
+};
+
+/**
+ * struct hfi_info
+ * @map: Hfi shared memory info
+ * @smem_size: Shared memory size
+ * @uncachedheap_size: uncached heap size
+ * @msgpacket_buf: message buffer
+ * @hfi_state: State machine for hfi
+ * @cmd_q_lock: Lock for command queue
+ * @csr_base: CSR base address
+ */
+struct hfi_info {
+	struct hfi_mem_info map;
+	uint32_t smem_size;
+	uint32_t uncachedheap_size;
+	uint32_t msgpacket_buf[ICP_HFI_MAX_MSG_SIZE_IN_WORDS];
+	uint8_t hfi_state;
+	struct mutex cmd_q_lock;
+	struct mutex msg_q_lock;
+	void __iomem *csr_base;
+};
+
+#endif /* _CAM_HFI_REG_H_ */
diff --git a/drivers/media/platform/msm/camera/icp/fw_inc/hfi_session_defs.h b/drivers/media/platform/msm/camera/icp/fw_inc/hfi_session_defs.h
new file mode 100644
index 0000000..837efec
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/fw_inc/hfi_session_defs.h
@@ -0,0 +1,428 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_HFI_SESSION_DEFS_H
+#define _CAM_HFI_SESSION_DEFS_H
+
+#include <linux/types.h>
+
+#define HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO             0x1
+#define HFI_IPEBPS_CMD_OPCODE_BPS_FRAME_PROCESS         0x2
+#define HFI_IPEBPS_CMD_OPCODE_BPS_ABORT                 0x3
+#define HFI_IPEBPS_CMD_OPCODE_BPS_DESTROY               0x4
+
+#define HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO             0x5
+#define HFI_IPEBPS_CMD_OPCODE_IPE_FRAME_PROCESS         0x6
+#define HFI_IPEBPS_CMD_OPCODE_IPE_ABORT                 0x7
+#define HFI_IPEBPS_CMD_OPCODE_IPE_DESTROY               0x8
+
+#define HFI_IPEBPS_CMD_OPCODE_BPS_WAIT_FOR_IPE          0x9
+#define HFI_IPEBPS_CMD_OPCODE_BPS_WAIT_FOR_BPS          0xa
+#define HFI_IPEBPS_CMD_OPCODE_IPE_WAIT_FOR_BPS          0xb
+#define HFI_IPEBPS_CMD_OPCODE_IPE_WAIT_FOR_IPE          0xc
+
+#define HFI_IPEBPS_HANDLE_TYPE_BPS                      0x1
+#define HFI_IPEBPS_HANDLE_TYPE_IPE_RT                   0x2
+#define HFI_IPEBPS_HANDLE_TYPE_IPE_NON_RT               0x3
+
+/**
+ * struct hfi_cmd_abort_destroy
+ * @user_data: user supplied data
+ *
+ * IPE/BPS destroy/abort command
+ * @HFI_IPEBPS_CMD_OPCODE_IPE_ABORT
+ * @HFI_IPEBPS_CMD_OPCODE_BPS_ABORT
+ * @HFI_IPEBPS_CMD_OPCODE_IPE_DESTROY
+ * @HFI_IPEBPS_CMD_OPCODE_BPS_DESTROY
+ */
+struct hfi_cmd_abort_destroy {
+	uint64_t user_data;
+} __packed;
+
+/**
+ * struct hfi_cmd_chaining_ops
+ * @wait_hdl: current session handle waits on wait_hdl to complete operation
+ * @user_data: user supplied argument
+ *
+ * this structure for chaining opcodes
+ * BPS_WAITS_FOR_IPE
+ * BPS_WAITS_FOR_BPS
+ * IPE_WAITS_FOR_BPS
+ * IPE_WAITS_FOR_IPE
+ */
+struct hfi_cmd_chaining_ops {
+	uint32_t wait_hdl;
+	uint64_t user_data;
+} __packed;
+
+/**
+ * struct hfi_cmd_create_handle
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @handle_type: IPE/BPS firmware session handle type
+ * @user_data1: caller provided data1
+ * @user_data2: caller provided data2
+ *
+ * create firmware session handle
+ */
+struct hfi_cmd_create_handle {
+	uint32_t size;
+	uint32_t pkt_type;
+	uint32_t handle_type;
+	uint64_t user_data1;
+	uint64_t user_data2;
+} __packed;
+
+/**
+ * struct hfi_cmd_ipebps_async
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @opcode: opcode for IPE/BPS async operation
+ *          CONFIG_IO: configures I/O for IPE/BPS handle
+ *          FRAME_PROCESS: image frame to be processed by IPE/BPS
+ *          ABORT: abort all processing frames of IPE/BPS handle
+ *          DESTROY: destroy earlier created IPE/BPS handle
+ *          BPS_WAITS_FOR_IPE: sync for BPS to wait for IPE
+ *          BPS_WAITS_FOR_BPS: sync for BPS to wait for BPS
+ *          IPE_WAITS_FOR_IPE: sync for IPE to wait for IPE
+ *          IPE_WAITS_FOR_BPS: sync for IPE to wait for BPS
+ * @num_fw_handles: number of IPE/BPS firmware handles in fw_handles array
+ * @fw_handles: IPE/BPS handles array
+ * @payload: command payload for IPE/BPS opcodes
+ * @direct: points to actual payload
+ * @indirect: points to address of payload
+ *
+ * sends async command to the earlier created IPE or BPS handle
+ * for asynchronous operation.
+ */
+struct hfi_cmd_ipebps_async {
+	uint32_t size;
+	uint32_t pkt_type;
+	uint32_t opcode;
+	uint64_t user_data1;
+	uint64_t user_data2;
+	uint32_t num_fw_handles;
+	uint32_t fw_handles[1];
+	union {
+		uint32_t direct[1];
+		uint32_t indirect;
+	} payload;
+} __packed;
+
+/**
+ * struct hfi_msg_create_handle_ack
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @err_type: error code
+ * @fw_handle: output param for IPE/BPS handle
+ * @user_data1: user provided data1
+ * @user_data2: user provided data2
+ *
+ * ack for create handle command of IPE/BPS
+ * @HFI_MSG_IPEBPS_CREATE_HANDLE_ACK
+ */
+struct hfi_msg_create_handle_ack {
+	uint32_t size;
+	uint32_t pkt_type;
+	uint32_t err_type;
+	uint32_t fw_handle;
+	uint64_t user_data1;
+	uint64_t user_data2;
+} __packed;
+
+/**
+ * struct hfi_msg_ipebps_async
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @opcode: opcode of IPE/BPS async operation
+ * @user_data1: user provided data1
+ * @user_data2: user provided data2
+ * @err_type: error code
+ * @msg_data: IPE/BPS async done message data
+ *
+ * result of IPE/BPS async command
+ * @HFI_MSG_IPEBPS_ASYNC_COMMAND_ACK
+ */
+struct hfi_msg_ipebps_async_ack {
+	uint32_t size;
+	uint32_t pkt_type;
+	uint32_t opcode;
+	uint64_t user_data1;
+	uint64_t user_data2;
+	uint32_t err_type;
+	uint32_t msg_data[1];
+} __packed;
+
+/**
+ * struct hfi_msg_frame_process_done
+ * @result: result of frame process command
+ * @scratch_buffer_address: address of scratch buffer
+ */
+struct hfi_msg_frame_process_done {
+	uint32_t result;
+	uint32_t scratch_buffer_address;
+};
+
+/**
+ * struct hfi_msg_chaining_op
+ * @status: return status
+ * @user_data: user data provided as part of chaining ops
+ *
+ * IPE/BPS wait response
+ */
+struct hfi_msg_chaining_op {
+	uint32_t status;
+	uint64_t user_data;
+} __packed;
+
+/**
+ * struct hfi_msg_abort_destroy
+ * @status: return status
+ * @user_data: user data provided as part of abort/destroy ops
+ *
+ * IPE/BPS abort/destroy response
+ */
+struct hfi_msg_abort_destroy {
+	uint32_t status;
+	uint64_t user_data;
+} __packed;
+
+#define MAX_NUM_OF_IMAGE_PLANES	2
+
+enum hfi_ipe_io_images {
+	IPE_INPUT_IMAGE_FULL,
+	IPE_INPUT_IMAGE_DS4,
+	IPE_INPUT_IMAGE_DS16,
+	IPE_INPUT_IMAGE_DS64,
+	IPE_INPUT_IMAGE_FULL_REF,
+	IPE_INPUT_IMAGE_DS4_REF,
+	IPE_INPUT_IMAGE_DS16_REF,
+	IPE_INPUT_IMAGE_DS64_REF,
+	IPE_OUTPUT_IMAGE_DISPLAY,
+	IPE_OUTPUT_IMAGE_VIDEO,
+	IPE_OUTPUT_IMAGE_FULL_REF,
+	IPE_OUTPUT_IMAGE_DS4_REF,
+	IPE_OUTPUT_IMAGE_DS16_REF,
+	IPE_OUTPUT_IMAGE_DS64_REF,
+	IPE_INPUT_IMAGE_FIRST = IPE_INPUT_IMAGE_FULL,
+	IPE_INPUT_IMAGE_LAST = IPE_INPUT_IMAGE_DS64_REF,
+	IPE_OUTPUT_IMAGE_FIRST = IPE_OUTPUT_IMAGE_DISPLAY,
+	IPE_OUTPUT_IMAGE_LAST = IPE_OUTPUT_IMAGE_DS64_REF,
+	IPE_IO_IMAGES_MAX
+};
+
+enum hfi_ipe_image_format {
+	IMAGE_FORMAT_INVALID,
+	IMAGE_FORMAT_MIPI_8,
+	IMAGE_FORMAT_MIPI_10,
+	IMAGE_FORMAT_MIPI_12,
+	IMAGE_FORMAT_MIPI_14,
+	IMAGE_FORMAT_BAYER_8,
+	IMAGE_FORMAT_BAYER_10,
+	IMAGE_FORMAT_BAYER_12,
+	IMAGE_FORMAT_BAYER_14,
+	IMAGE_FORMAT_PDI_10,
+	IMAGE_FORMAT_PD_10,
+	IMAGE_FORMAT_PD_8,
+	IMAGE_FORMAT_INDICATIONS,
+	IMAGE_FORMAT_REFINEMENT,
+	IMAGE_FORMAT_UBWC_TP_10,
+	IMAGE_FORMAT_UBWC_NV_12,
+	IMAGE_FORMAT_UBWC_NV12_4R,
+	IMAGE_FORMAT_UBWC_P010,
+	IMAGE_FORMAT_LINEAR_TP_10,
+	IMAGE_FORMAT_LINEAR_P010,
+	IMAGE_FORMAT_LINEAR_NV12,
+	IMAGE_FORMAT_LINEAR_PLAIN_16,
+	IMAGE_FORMAT_YUV422_8,
+	IMAGE_FORMAT_YUV422_10,
+	IMAGE_FORMAT_STATISTICS_BAYER_GRID,
+	IMAGE_FORMAT_STATISTICS_BAYER_HISTOGRAM,
+	IMAGE_FORMAT_MAX
+};
+
+enum hfi_ipe_plane_format {
+	PLANE_FORMAT_INVALID = 0,
+	PLANE_FORMAT_MIPI_8,
+	PLANE_FORMAT_MIPI_10,
+	PLANE_FORMAT_MIPI_12,
+	PLANE_FORMAT_MIPI_14,
+	PLANE_FORMAT_BAYER_8,
+	PLANE_FORMAT_BAYER_10,
+	PLANE_FORMAT_BAYER_12,
+	PLANE_FORMAT_BAYER_14,
+	PLANE_FORMAT_PDI_10,
+	PLANE_FORMAT_PD_10,
+	PLANE_FORMAT_PD_8,
+	PLANE_FORMAT_INDICATIONS,
+	PLANE_FORMAT_REFINEMENT,
+	PLANE_FORMAT_UBWC_TP_10_Y,
+	PLANE_FORMAT_UBWC_TP_10_C,
+	PLANE_FORMAT_UBWC_NV_12_Y,
+	PLANE_FORMAT_UBWC_NV_12_C,
+	PLANE_FORMAT_UBWC_NV_12_4R_Y,
+	PLANE_FORMAT_UBWC_NV_12_4R_C,
+	PLANE_FORMAT_UBWC_P010_Y,
+	PLANE_FORMAT_UBWC_P010_C,
+	PLANE_FORMAT_LINEAR_TP_10_Y,
+	PLANE_FORMAT_LINEAR_TP_10_C,
+	PLANE_FORMAT_LINEAR_P010_Y,
+	PLANE_FORMAT_LINEAR_P010_C,
+	PLANE_FORMAT_LINEAR_NV12_Y,
+	PLANE_FORMAT_LINEAR_NV12_C,
+	PLANE_FORMAT_LINEAR_PLAIN_16_Y,
+	PLANE_FORMAT_LINEAR_PLAIN_16_C,
+	PLANE_FORMAT_YUV422_8,
+	PLANE_FORMAT_YUV422_10,
+	PLANE_FORMAT_STATISTICS_BAYER_GRID,
+	PLANE_FORMAT_STATISTICS_BAYER_HISTOGRAM,
+	PLANE_FORMAT_MAX
+};
+
+enum hfi_ipe_bayer_pixel_order {
+	FIRST_PIXEL_R,
+	FIRST_PIXEL_GR,
+	FIRST_PIXEL_B,
+	FIRST_PIXEL_GB,
+	FIRST_PIXEL_MAX
+};
+
+enum hfi_ipe_pixel_pack_alignment {
+	PIXEL_LSB_ALIGNED,
+	PIXEL_MSB_ALIGNED,
+};
+
+enum hfi_ipe_yuv_422_order {
+	PIXEL_ORDER_Y_U_Y_V,
+	PIXEL_ORDER_Y_V_Y_U,
+	PIXEL_ORDER_U_Y_V_Y,
+	PIXEL_ORDER_V_Y_U_Y,
+	PIXEL_ORDER_YUV422_MAX
+};
+
+enum ubwc_write_client {
+	IPE_WR_CLIENT_0 = 0,
+	IPE_WR_CLIENT_1,
+	IPE_WR_CLIENT_5,
+	IPE_WR_CLIENT_6,
+	IPE_WR_CLIENT_7,
+	IPE_WR_CLIENT_8,
+	IPE_WR_CLIENT_MAX
+};
+
+/**
+ * struct image_info
+ * @format: image format
+ * @img_width: image width
+ * @img_height: image height
+ * @bayer_order: pixel order
+ * @pix_align: alignment
+ * @yuv422_order: YUV order
+ * @byte_swap: byte swap
+ */
+struct image_info {
+	enum hfi_ipe_image_format format;
+	uint32_t img_width;
+	uint32_t img_height;
+	enum hfi_ipe_bayer_pixel_order bayer_order;
+	enum hfi_ipe_pixel_pack_alignment pix_align;
+	enum hfi_ipe_yuv_422_order yuv422_order;
+	uint32_t byte_swap;
+} __packed;
+
+/**
+ * struct buffer_layout
+ * @buf_stride: buffer stride
+ * @buf_height: buffer height
+ */
+struct buffer_layout {
+	uint32_t buf_stride;
+	uint32_t buf_height;
+} __packed;
+
+/**
+ * struct image_desc
+ * @info: image info
+ * @buf_layout: buffer layout
+ * @meta_buf_layout: meta buffer layout
+ */
+struct image_desc {
+	struct image_info info;
+	struct buffer_layout buf_layout[MAX_NUM_OF_IMAGE_PLANES];
+	struct buffer_layout meta_buf_layout[MAX_NUM_OF_IMAGE_PLANES];
+} __packed;
+
+/**
+ * struct hfi_cmd_ipe_config
+ * @images: images descreptions
+ * @user_data: user supplied data
+ *
+ * payload for IPE async command
+ */
+struct hfi_cmd_ipe_config {
+	struct image_desc images[IPE_IO_IMAGES_MAX];
+	uint64_t user_data;
+} __packed;
+
+/**
+ * struct frame_buffers
+ * @buf_ptr: buffer pointers for all planes
+ * @meta_buf_ptr: meta buffer pointers for all planes
+ */
+struct frame_buffers {
+	uint32_t buf_ptr[MAX_NUM_OF_IMAGE_PLANES];
+	uint32_t meta_buf_ptr[MAX_NUM_OF_IMAGE_PLANES];
+} __packed;
+
+/**
+ * struct hfi_msg_ipe_config
+ * @rc: result of ipe config command
+ * @scratch_mem_size: scratch mem size for a config
+ * @user_data: user data
+ */
+struct hfi_msg_ipe_config {
+	uint32_t rc;
+	uint32_t scratch_mem_size;
+	uint64_t user_data;
+} __packed;
+
+/**
+ * struct hfi_msg_bps_common
+ * @rc: result of ipe config command
+ * @user_data: user data
+ */
+struct hfi_msg_bps_common {
+	uint32_t rc;
+	uint64_t user_data;
+} __packed;
+
+/**
+ * struct ipe_bps_destroy
+ * @user_data: user data
+ */
+struct ipe_bps_destroy {
+	uint64_t userdata;
+};
+
+/**
+ * struct hfi_msg_ipe_frame_process
+ * @status: result of ipe frame process command
+ * @scratch_buf_addr: address of scratch buffer
+ * @user_data: user data
+ */
+struct hfi_msg_ipe_frame_process {
+	uint32_t status;
+	uint32_t scratch_buf_addr;
+	uint64_t user_data;
+} __packed;
+
+#endif /* _CAM_HFI_SESSION_DEFS_H */
diff --git a/drivers/media/platform/msm/camera/icp/fw_inc/hfi_sys_defs.h b/drivers/media/platform/msm/camera/icp/fw_inc/hfi_sys_defs.h
new file mode 100644
index 0000000..e7163ac
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/fw_inc/hfi_sys_defs.h
@@ -0,0 +1,483 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _HFI_DEFS_H_
+#define _HFI_DEFS_H_
+
+#include <linux/types.h>
+
+/*
+ * Following base acts as common starting points
+ * for all enumerations.
+ */
+#define HFI_COMMON_BASE                 0x0
+
+/* HFI Domain base offset for commands and messages */
+#define HFI_DOMAIN_SHFT                 (24)
+#define HFI_DOMAIN_BMSK                 (0x7 << HFI_DOMAIN_SHFT)
+#define HFI_DOMAIN_BASE_ICP             (0x0 << HFI_DOMAIN_SHFT)
+#define HFI_DOMAIN_BASE_IPE_BPS         (0x1 << HFI_DOMAIN_SHFT)
+#define HFI_DOMAIN_BASE_CDM             (0x2 << HFI_DOMAIN_SHFT)
+#define HFI_DOMAIN_BASE_DBG             (0x3 << HFI_DOMAIN_SHFT)
+
+/* Command base offset for commands */
+#define HFI_CMD_START_OFFSET            0x10000
+
+/* Command base offset for messages */
+#define HFI_MSG_START_OFFSET            0x20000
+
+/* System Level Error types */
+#define HFI_ERR_SYS_NONE                (HFI_COMMON_BASE)
+#define HFI_ERR_SYS_FATAL               (HFI_COMMON_BASE + 0x1)
+#define HFI_ERR_SYS_VERSION_MISMATCH    (HFI_COMMON_BASE + 0x2)
+#define HFI_ERR_SYS_UNSUPPORTED_DOMAIN  (HFI_COMMON_BASE + 0x3)
+#define HFI_ERR_SYS_UNSUPPORT_CMD       (HFI_COMMON_BASE + 0x4)
+#define HFI_ERR_SYS_CMDFAILED           (HFI_COMMON_BASE + 0x5)
+#define HFI_ERR_SYS_CMDSIZE             (HFI_COMMON_BASE + 0x6)
+
+/* System Level Event types */
+#define HFI_EVENT_SYS_ERROR             (HFI_COMMON_BASE + 0x1)
+#define HFI_EVENT_ICP_ERROR             (HFI_COMMON_BASE + 0x2)
+#define HFI_EVENT_IPE_BPS_ERROR         (HFI_COMMON_BASE + 0x3)
+#define HFI_EVENT_CDM_ERROR             (HFI_COMMON_BASE + 0x4)
+#define HFI_EVENT_DBG_ERROR             (HFI_COMMON_BASE + 0x5)
+
+/* Core level start Ranges for errors */
+#define HFI_ERR_ICP_START               (HFI_COMMON_BASE + 0x64)
+#define HFI_ERR_IPE_BPS_START           (HFI_ERR_ICP_START + 0x64)
+#define HFI_ERR_CDM_START               (HFI_ERR_IPE_BPS_START + 0x64)
+#define HFI_ERR_DBG_START               (HFI_ERR_CDM_START + 0x64)
+
+/*ICP Core level  error messages */
+#define HFI_ERR_NO_RES                  (HFI_ERR_ICP_START + 0x1)
+#define HFI_ERR_UNSUPPORTED_RES         (HFI_ERR_ICP_START + 0x2)
+#define HFI_ERR_UNSUPPORTED_PROP        (HFI_ERR_ICP_START + 0x3)
+#define HFI_ERR_INIT_EXPECTED           (HFI_ERR_ICP_START + 0x4)
+#define HFI_ERR_INIT_IGNORED            (HFI_ERR_ICP_START + 0x5)
+
+/* System level commands */
+#define HFI_CMD_COMMON_START \
+		(HFI_DOMAIN_BASE_ICP + HFI_CMD_START_OFFSET + 0x0)
+#define HFI_CMD_SYS_INIT               (HFI_CMD_COMMON_START + 0x1)
+#define HFI_CMD_SYS_PC_PREP            (HFI_CMD_COMMON_START + 0x2)
+#define HFI_CMD_SYS_SET_PROPERTY       (HFI_CMD_COMMON_START + 0x3)
+#define HFI_CMD_SYS_GET_PROPERTY       (HFI_CMD_COMMON_START + 0x4)
+#define HFI_CMD_SYS_PING               (HFI_CMD_COMMON_START + 0x5)
+#define HFI_CMD_SYS_RESET              (HFI_CMD_COMMON_START + 0x6)
+
+/* Core level commands */
+/* IPE/BPS core Commands */
+#define HFI_CMD_IPE_BPS_COMMON_START \
+		(HFI_DOMAIN_BASE_IPE_BPS + HFI_CMD_START_OFFSET + 0x0)
+#define HFI_CMD_IPEBPS_CREATE_HANDLE \
+		(HFI_CMD_IPE_BPS_COMMON_START + 0x8)
+#define HFI_CMD_IPEBPS_ASYNC_COMMAND_DIRECT \
+		(HFI_CMD_IPE_BPS_COMMON_START + 0xa)
+#define HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT \
+		(HFI_CMD_IPE_BPS_COMMON_START + 0xe)
+
+/* CDM core Commands */
+#define HFI_CMD_CDM_COMMON_START \
+		(HFI_DOMAIN_BASE_CDM + HFI_CMD_START_OFFSET + 0x0)
+#define HFI_CMD_CDM_TEST_START (HFI_CMD_CDM_COMMON_START + 0x800)
+#define HFI_CMD_CDM_END        (HFI_CMD_CDM_COMMON_START + 0xFFF)
+
+/* Debug/Test Commands */
+#define HFI_CMD_DBG_COMMON_START \
+		(HFI_DOMAIN_BASE_DBG + HFI_CMD_START_OFFSET + 0x0)
+#define HFI_CMD_DBG_TEST_START  (HFI_CMD_DBG_COMMON_START + 0x800)
+#define HFI_CMD_DBG_END         (HFI_CMD_DBG_COMMON_START + 0xFFF)
+
+/* System level messages */
+#define HFI_MSG_ICP_COMMON_START \
+		(HFI_DOMAIN_BASE_ICP + HFI_MSG_START_OFFSET + 0x0)
+#define HFI_MSG_SYS_INIT_DONE           (HFI_MSG_ICP_COMMON_START + 0x1)
+#define HFI_MSG_SYS_PC_PREP_DONE        (HFI_MSG_ICP_COMMON_START + 0x2)
+#define HFI_MSG_SYS_DEBUG               (HFI_MSG_ICP_COMMON_START + 0x3)
+#define HFI_MSG_SYS_IDLE                (HFI_MSG_ICP_COMMON_START + 0x4)
+#define HFI_MSG_SYS_PROPERTY_INFO       (HFI_MSG_ICP_COMMON_START + 0x5)
+#define HFI_MSG_SYS_PING_ACK            (HFI_MSG_ICP_COMMON_START + 0x6)
+#define HFI_MSG_SYS_RESET_ACK           (HFI_MSG_ICP_COMMON_START + 0x7)
+#define HFI_MSG_EVENT_NOTIFY            (HFI_MSG_ICP_COMMON_START + 0x8)
+
+/* Core level Messages */
+/* IPE/BPS core Messages */
+#define HFI_MSG_IPE_BPS_COMMON_START \
+		(HFI_DOMAIN_BASE_IPE_BPS + HFI_MSG_START_OFFSET + 0x0)
+#define HFI_MSG_IPEBPS_CREATE_HANDLE_ACK \
+		(HFI_MSG_IPE_BPS_COMMON_START + 0x08)
+#define HFI_MSG_IPEBPS_ASYNC_COMMAND_DIRECT_ACK \
+		(HFI_MSG_IPE_BPS_COMMON_START + 0x0a)
+#define HFI_MSG_IPEBPS_ASYNC_COMMAND_INDIRECT_ACK \
+		(HFI_MSG_IPE_BPS_COMMON_START + 0x0e)
+#define HFI_MSG_IPE_BPS_TEST_START	\
+		(HFI_MSG_IPE_BPS_COMMON_START + 0x800)
+#define HFI_MSG_IPE_BPS_END \
+		(HFI_MSG_IPE_BPS_COMMON_START + 0xFFF)
+
+/* CDM core Messages */
+#define HFI_MSG_CDM_COMMON_START \
+		(HFI_DOMAIN_BASE_CDM + HFI_MSG_START_OFFSET + 0x0)
+#define  HFI_MSG_PRI_CDM_PAYLOAD_ACK    (HFI_MSG_CDM_COMMON_START + 0xa)
+#define  HFI_MSG_PRI_LLD_PAYLOAD_ACK    (HFI_MSG_CDM_COMMON_START + 0xb)
+#define HFI_MSG_CDM_TEST_START          (HFI_MSG_CDM_COMMON_START + 0x800)
+#define HFI_MSG_CDM_END                 (HFI_MSG_CDM_COMMON_START + 0xFFF)
+
+/* core level test command ranges */
+/* ICP core level test command range */
+#define HFI_CMD_ICP_TEST_START          (HFI_CMD_ICP_COMMON_START + 0x800)
+#define HFI_CMD_ICP_END                 (HFI_CMD_ICP_COMMON_START + 0xFFF)
+
+/* IPE/BPS core level test command range */
+#define HFI_CMD_IPE_BPS_TEST_START \
+		(HFI_CMD_IPE_BPS_COMMON_START + 0x800)
+#define HFI_CMD_IPE_BPS_END (HFI_CMD_IPE_BPS_COMMON_START + 0xFFF)
+
+/* ICP core level test message range */
+#define HFI_MSG_ICP_TEST_START  (HFI_MSG_ICP_COMMON_START + 0x800)
+#define HFI_MSG_ICP_END         (HFI_MSG_ICP_COMMON_START + 0xFFF)
+
+/* ICP core level Debug test message range */
+#define HFI_MSG_DBG_COMMON_START \
+		(HFI_DOMAIN_BASE_DBG + 0x0)
+#define HFI_MSG_DBG_TEST_START  (HFI_MSG_DBG_COMMON_START + 0x800)
+#define HFI_MSG_DBG_END         (HFI_MSG_DBG_COMMON_START + 0xFFF)
+
+/* System  level property base offset */
+#define HFI_PROPERTY_ICP_COMMON_START  (HFI_DOMAIN_BASE_ICP + 0x0)
+
+#define HFI_PROP_SYS_DEBUG_CFG         (HFI_PROPERTY_ICP_COMMON_START + 0x1)
+#define HFI_PROP_SYS_IMAGE_VER         (HFI_PROPERTY_ICP_COMMON_START + 0x3)
+#define HFI_PROP_SYS_SUPPORTED         (HFI_PROPERTY_ICP_COMMON_START + 0x4)
+
+/* Capabilities reported at sys init */
+#define HFI_CAPS_PLACEHOLDER_1         (HFI_COMMON_BASE + 0x1)
+#define HFI_CAPS_PLACEHOLDER_2         (HFI_COMMON_BASE + 0x2)
+
+/* Section describes different debug levels (HFI_DEBUG_MSG_X)
+ * available for debug messages from FW
+ */
+#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
+/* Messages containing performance data */
+#define  HFI_DEBUG_MSG_PERF     0x00000020
+/* Disable ARM9 WFI in low power mode. */
+#define  HFI_DEBUG_CFG_WFI      0x01000000
+/* Disable ARM9 watchdog. */
+#define  HFI_DEBUG_CFG_ARM9WD   0x10000000
+
+/* Debug Msg Communication types:
+ * Section describes different modes (HFI_DEBUG_MODE_X)
+ * available to communicate the debug messages
+ */
+ /* Debug message output through   the interface debug queue. */
+#define HFI_DEBUG_MODE_QUEUE     0x00000001
+ /* Debug message output through QDSS. */
+#define HFI_DEBUG_MODE_QDSS      0x00000002
+
+
+#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_CFG_WFI        0x01000000
+#define HFI_DEBUG_CFG_ARM9WD     0x10000000
+
+#define HFI_DEBUG_MODE_QUEUE     0x00000001
+#define HFI_DEBUG_MODE_QDSS      0x00000002
+
+/**
+ * start of sys command packet types
+ * These commands are used to get system level information
+ * from firmware
+ */
+
+/**
+ * struct hfi_caps_support
+ * payload to report caps through HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED
+ * @type: capability type
+ * @min: minimum supported value for the capability
+ * @max: maximum supported value for the capability
+ * @step_size: supported steps between min-max
+ */
+struct hfi_caps_support {
+	uint32_t type;
+	uint32_t min;
+	uint32_t max;
+	uint32_t step_size;
+} __packed;
+
+/**
+ * struct hfi_caps_support_info
+ * capability report through HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED
+ * @num_caps: number of capabilities listed
+ * @caps_data: capabilities info array
+ */
+struct hfi_caps_support_info {
+	uint32_t num_caps;
+	struct hfi_caps_support caps_data[1];
+} __packed;
+
+/**
+ * struct hfi_debug
+ * payload structure to configure HFI_PROPERTY_SYS_DEBUG_CONFIG
+ * @debug_config: it is a result of HFI_DEBUG_MSG_X values that
+ *                are OR-ed together to specify the debug message types
+ *                to otput
+ * @debug_mode: debug message output through debug queue/qdss
+ * @HFI_PROPERTY_SYS_DEBUG_CONFIG
+ */
+struct hfi_debug {
+	uint32_t debug_config;
+	uint32_t debug_mode;
+} __packed;
+
+
+/**
+ * struct hfi_cmd_sys_init
+ * command to initialization of system session
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @HFI_CMD_SYS_INIT
+ */
+struct hfi_cmd_sys_init {
+	uint32_t size;
+	uint32_t pkt_type;
+} __packed;
+
+/**
+ * struct hfi_cmd_pc_prep
+ * command to firmware to prepare for power collapse
+ * @eize: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @HFI_CMD_SYS_PC_PREP
+ */
+struct hfi_cmd_pc_prep {
+	uint32_t size;
+	uint32_t pkt_type;
+} __packed;
+
+/**
+ * struct hfi_cmd_prop
+ * command to get/set properties of firmware
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @num_prop: number of properties queried/set
+ * @prop_data: array of property IDs being queried. size depends on num_prop
+ *             array of property IDs and associated structure pairs in set
+ * @HFI_CMD_SYS_GET_PROPERTY
+ * @HFI_CMD_SYS_SET_PROPERTY
+ */
+struct hfi_cmd_prop {
+	uint32_t size;
+	uint32_t pkt_type;
+	uint32_t num_prop;
+	uint32_t prop_data[1];
+} __packed;
+
+/**
+ * struct hfi_cmd_ping_pkt
+ * ping command pings the firmware to confirm whether
+ * it is alive.
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @user_data: client data, firmware returns this data
+ *             as part of HFI_MSG_SYS_PING_ACK
+ * @HFI_CMD_SYS_PING
+ */
+struct hfi_cmd_ping_pkt {
+	uint32_t size;
+	uint32_t pkt_type;
+	uint64_t user_data;
+} __packed;
+
+/**
+ * struct hfi_cmd_sys_reset_pkt
+ * sends the reset command to FW. FW responds in the same type
+ * of packet. so can be used for reset_ack_pkt type also
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @user_data: client data, firmware returns this data
+ *             as part of HFI_MSG_SYS_RESET_ACK
+ * @HFI_CMD_SYS_RESET
+ */
+
+struct hfi_cmd_sys_reset_pkt {
+	uint32_t size;
+	uint32_t pkt_type;
+	uint64_t user_data;
+} __packed;
+
+/* end of sys command packet types */
+
+/* start of sys message packet types */
+
+/**
+ * struct hfi_prop
+ * structure to report maximum supported features of firmware.
+ */
+struct hfi_sys_support {
+	uint32_t place_holder;
+} __packed;
+
+/**
+ * struct hfi_supported_prop
+ * structure to report HFI_PROPERTY_PARAM_PROPERTIES_SUPPORTED
+ * for a session
+ * @num_prop: number of properties supported
+ * @prop_data: array of supported property IDs
+ */
+struct hfi_supported_prop {
+	uint32_t num_prop;
+	uint32_t prop_data[1];
+} __packed;
+
+/**
+ * struct hfi_image_version
+ * system image version
+ * @major: major version number
+ * @minor: minor version number
+ * @ver_name_size: size of version name
+ * @ver_name: image version name
+ */
+struct hfi_image_version {
+	uint32_t major;
+	uint32_t minor;
+	uint32_t ver_name_size;
+	uint8_t  ver_name[1];
+} __packed;
+
+/**
+ * struct hfi_msg_init_done
+ * system init done message from firmware. Many system level properties
+ * are returned with the packet
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @err_type: error code associated with response
+ * @num_prop: number of default capability info
+ * @prop_data: array of property ids and corresponding structure pairs
+ */
+struct hfi_msg_init_done {
+	uint32_t size;
+	uint32_t pkt_type;
+	uint32_t err_type;
+	uint32_t num_prop;
+	uint32_t prop_data[1];
+} __packed;
+
+/**
+ * struct hfi_msg_pc_prep_done
+ * system power collapse preperation done message
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @err_type: error code associated with the response
+ */
+struct hfi_msg_pc_prep_done {
+	uint32_t size;
+	uint32_t pkt_type;
+	uint32_t err_type;
+} __packed;
+
+/**
+ * struct hfi_msg_prop
+ * system property info from firmware
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @num_prop: number of property info structures
+ * @prop_data: array of property IDs and associated structure pairs
+ */
+struct hfi_msg_prop {
+	uint32_t size;
+	uint32_t pkt_type;
+	uint32_t num_prop;
+	uint32_t prop_data[1];
+} __packed;
+
+/**
+ * struct hfi_msg_idle
+ * system idle message from firmware
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ */
+struct hfi_msg_idle {
+	uint32_t size;
+	uint32_t pkt_type;
+} __packed;
+
+/**
+ * struct hfi_msg_ping_ack
+ * system ping ack message
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @user_data: this data is sent as part of ping command from host
+ */
+struct hfi_msg_ping_ack {
+	uint32_t size;
+	uint32_t pkt_type;
+	uint64_t user_data;
+} __packed;
+
+/**
+ * struct hfi_msg_debug
+ * system debug message defination
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @msg_type: debug message type
+ * @msg_size: size of debug message in bytes
+ * @timestamp_hi: most significant 32 bits of the 64 bit timestamp field.
+ *                timestamp shall be interpreted as a signed 64-bit value
+ *                representing microseconds.
+ * @timestamp_lo: least significant 32 bits of the 64 bit timestamp field.
+ *                timestamp shall be interpreted as a signed 64-bit value
+ *                representing microseconds.
+ * @msg_data: message data in string form
+ */
+struct hfi_msg_debug {
+	uint32_t size;
+	uint32_t pkt_type;
+	uint32_t msg_type;
+	uint32_t msg_size;
+	uint32_t timestamp_hi;
+	uint32_t timestamp_lo;
+	uint8_t  msg_data[1];
+} __packed;
+/**
+ * struct hfi_msg_event_notify
+ * event notify message
+ * @size: packet size in bytes
+ * @pkt_type: opcode of a packet
+ * @fw_handle: firmware session handle
+ * @event_id: session event id
+ * @event_data1: event data corresponding to event ID
+ * @event_data2: event data corresponding to event ID
+ * @ext_event_data: info array, interpreted based on event_data1
+ * and event_data2
+ */
+struct hfi_msg_event_notify {
+	uint32_t size;
+	uint32_t pkt_type;
+	uint32_t fw_handle;
+	uint32_t event_id;
+	uint32_t event_data1;
+	uint32_t event_data2;
+	uint32_t ext_event_data[1];
+} __packed;
+/**
+ * end of sys message packet types
+ */
+
+#endif /* _HFI_DEFS_H_ */
diff --git a/drivers/media/platform/msm/camera/icp/hfi.c b/drivers/media/platform/msm/camera/icp/hfi.c
new file mode 100644
index 0000000..4315865
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/hfi.c
@@ -0,0 +1,522 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "HFI-FW %s:%d " fmt, __func__, __LINE__
+
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <asm/errno.h>
+#include <linux/timer.h>
+#include <media/cam_icp.h>
+#include "cam_io_util.h"
+#include "hfi_reg.h"
+#include "hfi_sys_defs.h"
+#include "hfi_session_defs.h"
+#include "hfi_intf.h"
+#include "cam_icp_hw_mgr_intf.h"
+
+#define HFI_VERSION_INFO_MAJOR_VAL  1
+#define HFI_VERSION_INFO_MINOR_VAL  1
+#define HFI_VERSION_INFO_STEP_VAL   0
+#define HFI_VERSION_INFO_STEP_VAL   0
+#define HFI_VERSION_INFO_MAJOR_BMSK  0xFF000000
+#define HFI_VERSION_INFO_MAJOR_SHFT  24
+#define HFI_VERSION_INFO_MINOR_BMSK  0xFFFF00
+#define HFI_VERSION_INFO_MINOR_SHFT  8
+#define HFI_VERSION_INFO_STEP_BMSK   0xFF
+#define HFI_VERSION_INFO_STEP_SHFT  0
+
+#undef  HFI_DBG
+#define HFI_DBG(fmt, args...) pr_debug(fmt, ##args)
+
+struct hfi_info *g_hfi;
+unsigned int g_icp_mmu_hdl;
+
+int hfi_write_cmd(void *cmd_ptr)
+{
+	uint32_t size_in_words, empty_space, new_write_idx, read_idx, temp;
+	uint32_t *write_q, *write_ptr;
+	struct hfi_qtbl *q_tbl;
+	struct hfi_q_hdr *q;
+	int rc = 0;
+	int i = 0;
+
+	if (!cmd_ptr) {
+		pr_err("Invalid args\n");
+		return -EINVAL;
+	}
+
+	if (!g_hfi || g_hfi->hfi_state < FW_START_SENT) {
+		pr_err("FW not ready yet\n");
+		return -EIO;
+	}
+
+	mutex_lock(&g_hfi->cmd_q_lock);
+
+	q_tbl = (struct hfi_qtbl *)g_hfi->map.qtbl.kva;
+	q = &q_tbl->q_hdr[Q_CMD];
+
+	write_q = (uint32_t *)g_hfi->map.cmd_q.kva;
+
+	size_in_words = (*(uint32_t *)cmd_ptr) >> BYTE_WORD_SHIFT;
+	if (!size_in_words) {
+		pr_debug("failed");
+		rc = -EINVAL;
+		goto err;
+	}
+
+	HFI_DBG("size_in_words : %u\n", size_in_words);
+	HFI_DBG("q->qhdr_write_idx %x\n", q->qhdr_write_idx);
+
+	read_idx = q->qhdr_read_idx;
+
+	empty_space = (q->qhdr_write_idx >= read_idx) ?
+		(q->qhdr_q_size - (q->qhdr_write_idx - read_idx)) :
+		(read_idx - q->qhdr_write_idx);
+	if (empty_space <= size_in_words) {
+		pr_err("failed");
+		rc = -EIO;
+		goto err;
+	}
+	HFI_DBG("empty_space : %u\n", empty_space);
+
+	new_write_idx = q->qhdr_write_idx + size_in_words;
+	write_ptr = (uint32_t *)(write_q + q->qhdr_write_idx);
+
+	if (new_write_idx < q->qhdr_q_size) {
+		memcpy(write_ptr, (uint8_t *)cmd_ptr,
+			size_in_words << BYTE_WORD_SHIFT);
+	} else {
+		new_write_idx -= q->qhdr_q_size;
+		temp = (size_in_words - new_write_idx) << BYTE_WORD_SHIFT;
+		memcpy(write_ptr, (uint8_t *)cmd_ptr, temp);
+		memcpy(write_q, (uint8_t *)cmd_ptr + temp,
+			new_write_idx << BYTE_WORD_SHIFT);
+	}
+	for (i = 0; i < size_in_words; i++)
+		pr_debug("%x\n", write_ptr[i]);
+
+	q->qhdr_write_idx = new_write_idx;
+	HFI_DBG("q->qhdr_write_idx %x\n", q->qhdr_write_idx);
+	cam_io_w((uint32_t)INTR_ENABLE,
+		g_hfi->csr_base + HFI_REG_A5_CSR_HOST2ICPINT);
+err:
+	mutex_unlock(&g_hfi->cmd_q_lock);
+	return 0;
+}
+
+int hfi_read_message(uint32_t *pmsg, uint8_t q_id)
+{
+	struct hfi_qtbl *q_tbl_ptr;
+	struct hfi_q_hdr *q;
+	uint32_t new_read_idx, size_in_words, temp;
+	uint32_t *read_q, *read_ptr;
+	int rc = 0;
+	int i = 0;
+
+	if (!pmsg || q_id > Q_DBG) {
+		pr_err("Inavlid args\n");
+		return -EINVAL;
+	}
+
+	q_tbl_ptr = (struct hfi_qtbl *)g_hfi->map.qtbl.kva;
+	q = &q_tbl_ptr->q_hdr[q_id];
+
+	if ((g_hfi->hfi_state < FW_START_SENT) ||
+		(q->qhdr_read_idx == q->qhdr_write_idx)) {
+		pr_debug("FW or Q not ready, hfi state : %u, r idx : %u, w idx : %u\n",
+			g_hfi->hfi_state, q->qhdr_read_idx, q->qhdr_write_idx);
+		return -EIO;
+	}
+
+	mutex_lock(&g_hfi->msg_q_lock);
+
+	if (q_id == Q_CMD)
+		read_q = (uint32_t *)g_hfi->map.cmd_q.kva;
+	else if (q_id == Q_MSG)
+		read_q = (uint32_t *)g_hfi->map.msg_q.kva;
+	else
+		read_q = (uint32_t *)g_hfi->map.dbg_q.kva;
+
+	read_ptr = (uint32_t *)(read_q + q->qhdr_read_idx);
+	size_in_words = (*read_ptr) >> BYTE_WORD_SHIFT;
+
+	HFI_DBG("size_in_words : %u\n", size_in_words);
+	HFI_DBG("read_ptr : %pK\n", (void *)read_ptr);
+
+	if ((size_in_words == 0) ||
+		(size_in_words > ICP_HFI_MAX_MSG_SIZE_IN_WORDS)) {
+		pr_err("invalid HFI message packet size - 0x%08x\n",
+			size_in_words << BYTE_WORD_SHIFT);
+		q->qhdr_read_idx = q->qhdr_write_idx;
+		rc = -EIO;
+		goto err;
+	}
+
+	new_read_idx = q->qhdr_read_idx + size_in_words;
+	HFI_DBG("new_read_idx : %u\n", new_read_idx);
+
+	if (new_read_idx < q->qhdr_q_size) {
+		memcpy(pmsg, read_ptr, size_in_words << BYTE_WORD_SHIFT);
+	} else {
+		new_read_idx -= q->qhdr_q_size;
+		temp = (size_in_words - new_read_idx) << BYTE_WORD_SHIFT;
+		memcpy(pmsg, read_ptr, temp);
+		memcpy((uint8_t *)pmsg + temp, read_q,
+			new_read_idx << BYTE_WORD_SHIFT);
+	}
+
+	for (i = 0; i < size_in_words; i++)
+		pr_debug("%x\n", read_ptr[i]);
+
+	q->qhdr_read_idx = new_read_idx;
+err:
+	mutex_unlock(&g_hfi->msg_q_lock);
+	HFI_DBG("Exit\n");
+	return 0;
+}
+
+void hfi_send_system_cmd(uint32_t type, uint64_t data, uint32_t size)
+{
+	switch (type) {
+	case HFI_CMD_SYS_INIT: {
+		struct hfi_cmd_sys_init init;
+
+		memset(&init, 0, sizeof(init));
+
+		init.size = sizeof(struct hfi_cmd_sys_init);
+		init.pkt_type = type;
+		hfi_write_cmd(&init);
+	}
+		break;
+	case HFI_CMD_SYS_PC_PREP: {
+		struct hfi_cmd_pc_prep prep;
+
+		prep.size = sizeof(struct hfi_cmd_pc_prep);
+		prep.pkt_type = type;
+		hfi_write_cmd(&prep);
+	}
+		break;
+	case HFI_CMD_SYS_SET_PROPERTY: {
+		struct hfi_cmd_prop prop;
+
+		if ((uint32_t)data == (uint32_t)HFI_PROP_SYS_DEBUG_CFG) {
+			prop.size = sizeof(struct hfi_cmd_prop);
+			prop.pkt_type = type;
+			prop.num_prop = 1;
+			prop.prop_data[0] = HFI_PROP_SYS_DEBUG_CFG;
+			hfi_write_cmd(&prop);
+		}
+	}
+		break;
+	case HFI_CMD_SYS_GET_PROPERTY:
+		break;
+	case HFI_CMD_SYS_PING: {
+		struct hfi_cmd_ping_pkt ping;
+
+		ping.size = sizeof(struct hfi_cmd_ping_pkt);
+		ping.pkt_type = type;
+		ping.user_data = (uint64_t)data;
+		hfi_write_cmd(&ping);
+	}
+		break;
+	case HFI_CMD_SYS_RESET: {
+		struct hfi_cmd_sys_reset_pkt reset;
+
+		reset.size = sizeof(struct hfi_cmd_sys_reset_pkt);
+		reset.pkt_type = type;
+		reset.user_data = (uint64_t)data;
+		hfi_write_cmd(&reset);
+	}
+		break;
+	case HFI_CMD_IPEBPS_CREATE_HANDLE: {
+		struct hfi_cmd_create_handle handle;
+
+		handle.size = sizeof(struct hfi_cmd_create_handle);
+		handle.pkt_type = type;
+		handle.handle_type = (uint32_t)data;
+		handle.user_data1 = 0;
+		hfi_write_cmd(&handle);
+	}
+		break;
+	case HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT:
+		break;
+	default:
+		pr_err("command not supported :%d\n", type);
+		break;
+	}
+}
+
+
+int hfi_get_hw_caps(void *query_buf)
+{
+	int i = 0;
+	struct cam_icp_query_cap_cmd *query_cmd = NULL;
+
+	if (!query_buf) {
+		pr_err("%s: query buf is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	query_cmd = (struct cam_icp_query_cap_cmd *)query_buf;
+	query_cmd->fw_version.major = 0x12;
+	query_cmd->fw_version.minor = 0x12;
+	query_cmd->fw_version.revision = 0x12;
+
+	query_cmd->api_version.major = 0x13;
+	query_cmd->api_version.minor = 0x13;
+	query_cmd->api_version.revision = 0x13;
+
+	query_cmd->num_ipe = 2;
+	query_cmd->num_bps = 1;
+
+	for (i = 0; i < CAM_ICP_DEV_TYPE_MAX; i++) {
+		query_cmd->dev_ver[i].dev_type = i;
+		query_cmd->dev_ver[i].hw_ver.major = 0x34 + i;
+		query_cmd->dev_ver[i].hw_ver.minor = 0x34 + i;
+		query_cmd->dev_ver[i].hw_ver.incr = 0x34 + i;
+	}
+	return 0;
+}
+
+
+void cam_hfi_enable_cpu(void __iomem *icp_base)
+{
+	cam_io_w((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);
+}
+
+int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem,
+		void __iomem *icp_base, bool debug)
+{
+	int rc = 0;
+	struct hfi_qtbl *qtbl;
+	struct hfi_qtbl_hdr *qtbl_hdr;
+	struct hfi_q_hdr *cmd_q_hdr, *msg_q_hdr, *dbg_q_hdr;
+	uint32_t hw_version, fw_version;
+	uint32_t status;
+
+	if (!g_hfi) {
+		g_hfi = kzalloc(sizeof(struct hfi_info), GFP_KERNEL);
+		if (!g_hfi) {
+			rc = -ENOMEM;
+			goto alloc_fail;
+		}
+	}
+
+	pr_debug("g_hfi: %pK\n", (void *)g_hfi);
+	if (g_hfi->hfi_state != INVALID) {
+		pr_err("hfi_init: invalid state\n");
+		return -EINVAL;
+	}
+
+	g_hfi->hfi_state = FW_LOAD_DONE;
+	memcpy(&g_hfi->map, hfi_mem, sizeof(g_hfi->map));
+
+	if (debug) {
+		cam_io_w_mb(
+		(uint32_t)(ICP_FLAG_CSR_A5_EN | ICP_FLAG_CSR_WAKE_UP_EN |
+		ICP_CSR_EDBGRQ | ICP_CSR_DBGSWENABLE),
+		icp_base + HFI_REG_A5_CSR_A5_CONTROL);
+		msleep(100);
+		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);
+	} else {
+		cam_io_w((uint32_t)ICP_FLAG_CSR_A5_EN |
+			ICP_FLAG_CSR_WAKE_UP_EN,
+			icp_base + HFI_REG_A5_CSR_A5_CONTROL);
+	}
+
+	mutex_init(&g_hfi->cmd_q_lock);
+	mutex_init(&g_hfi->msg_q_lock);
+
+	g_hfi->csr_base = icp_base;
+
+	qtbl = (struct hfi_qtbl *)hfi_mem->qtbl.kva;
+	qtbl_hdr = &qtbl->q_tbl_hdr;
+	qtbl_hdr->qtbl_version = 0xFFFFFFFF;
+	qtbl_hdr->qtbl_size = sizeof(struct hfi_qtbl);
+	qtbl_hdr->qtbl_qhdr0_offset = sizeof(struct hfi_qtbl_hdr);
+	qtbl_hdr->qtbl_qhdr_size = sizeof(struct hfi_q_hdr);
+	qtbl_hdr->qtbl_num_q = ICP_HFI_NUMBER_OF_QS;
+	qtbl_hdr->qtbl_num_active_q = ICP_HFI_NUMBER_OF_QS;
+
+	/* setup host-to-firmware command queue */
+	pr_debug("updating the command queue info\n");
+	cmd_q_hdr = &qtbl->q_hdr[Q_CMD];
+	cmd_q_hdr->qhdr_status = QHDR_ACTIVE;
+	cmd_q_hdr->qhdr_start_addr = hfi_mem->cmd_q.iova;
+	cmd_q_hdr->qhdr_q_size =  ICP_CMD_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT;
+	cmd_q_hdr->qhdr_pkt_size = ICP_HFI_VAR_SIZE_PKT;
+	cmd_q_hdr->qhdr_pkt_drop_cnt = RESET;
+	cmd_q_hdr->qhdr_read_idx = RESET;
+	cmd_q_hdr->qhdr_write_idx = RESET;
+
+	/* setup firmware-to-Host message queue */
+	pr_debug("updating the message queue info\n");
+	msg_q_hdr = &qtbl->q_hdr[Q_MSG];
+	msg_q_hdr->qhdr_status = QHDR_ACTIVE;
+	msg_q_hdr->qhdr_start_addr = hfi_mem->msg_q.iova;
+	msg_q_hdr->qhdr_q_size = ICP_MSG_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT;
+	msg_q_hdr->qhdr_pkt_size = ICP_HFI_VAR_SIZE_PKT;
+	msg_q_hdr->qhdr_pkt_drop_cnt = RESET;
+	msg_q_hdr->qhdr_read_idx = RESET;
+	msg_q_hdr->qhdr_write_idx = RESET;
+
+	/* setup firmware-to-Host message queue */
+	pr_debug("updating the debug queue info\n");
+	dbg_q_hdr = &qtbl->q_hdr[Q_DBG];
+	dbg_q_hdr->qhdr_status = QHDR_ACTIVE;
+	dbg_q_hdr->qhdr_start_addr = hfi_mem->dbg_q.iova;
+	dbg_q_hdr->qhdr_q_size = ICP_DBG_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT;
+	dbg_q_hdr->qhdr_pkt_size = ICP_HFI_VAR_SIZE_PKT;
+	dbg_q_hdr->qhdr_pkt_drop_cnt = RESET;
+	dbg_q_hdr->qhdr_read_idx = RESET;
+	dbg_q_hdr->qhdr_write_idx = RESET;
+	pr_debug("Done updating the debug queue info\n");
+
+	switch (event_driven_mode) {
+	case INTR_MODE:
+		cmd_q_hdr->qhdr_type = Q_CMD;
+		cmd_q_hdr->qhdr_rx_wm = SET;
+		cmd_q_hdr->qhdr_tx_wm = SET;
+		cmd_q_hdr->qhdr_rx_req = SET;
+		cmd_q_hdr->qhdr_tx_req = RESET;
+		cmd_q_hdr->qhdr_rx_irq_status = RESET;
+		cmd_q_hdr->qhdr_tx_irq_status = RESET;
+
+		msg_q_hdr->qhdr_type = Q_MSG;
+		msg_q_hdr->qhdr_rx_wm = SET;
+		msg_q_hdr->qhdr_tx_wm = SET;
+		msg_q_hdr->qhdr_rx_req = SET;
+		msg_q_hdr->qhdr_tx_req = RESET;
+		msg_q_hdr->qhdr_rx_irq_status = RESET;
+		msg_q_hdr->qhdr_tx_irq_status = RESET;
+
+		dbg_q_hdr->qhdr_type = Q_DBG;
+		dbg_q_hdr->qhdr_rx_wm = SET;
+		dbg_q_hdr->qhdr_tx_wm = SET;
+		dbg_q_hdr->qhdr_rx_req = SET;
+		dbg_q_hdr->qhdr_tx_req = RESET;
+		dbg_q_hdr->qhdr_rx_irq_status = RESET;
+		dbg_q_hdr->qhdr_tx_irq_status = RESET;
+
+		break;
+
+	case POLL_MODE:
+		cmd_q_hdr->qhdr_type = Q_CMD | TX_EVENT_POLL_MODE_2 |
+			RX_EVENT_POLL_MODE_2;
+		msg_q_hdr->qhdr_type = Q_MSG | TX_EVENT_POLL_MODE_2 |
+			RX_EVENT_POLL_MODE_2;
+		dbg_q_hdr->qhdr_type = Q_DBG | TX_EVENT_POLL_MODE_2 |
+			RX_EVENT_POLL_MODE_2;
+		break;
+
+	case WM_MODE:
+		cmd_q_hdr->qhdr_type = Q_CMD | TX_EVENT_DRIVEN_MODE_2 |
+			RX_EVENT_DRIVEN_MODE_2;
+		cmd_q_hdr->qhdr_rx_wm = SET;
+		cmd_q_hdr->qhdr_tx_wm = SET;
+		cmd_q_hdr->qhdr_rx_req = RESET;
+		cmd_q_hdr->qhdr_tx_req = SET;
+		cmd_q_hdr->qhdr_rx_irq_status = RESET;
+		cmd_q_hdr->qhdr_tx_irq_status = RESET;
+
+		msg_q_hdr->qhdr_type = Q_MSG | TX_EVENT_DRIVEN_MODE_2 |
+			RX_EVENT_DRIVEN_MODE_2;
+		msg_q_hdr->qhdr_rx_wm = SET;
+		msg_q_hdr->qhdr_tx_wm = SET;
+		msg_q_hdr->qhdr_rx_req = SET;
+		msg_q_hdr->qhdr_tx_req = RESET;
+		msg_q_hdr->qhdr_rx_irq_status = RESET;
+		msg_q_hdr->qhdr_tx_irq_status = RESET;
+
+		dbg_q_hdr->qhdr_type = Q_DBG | TX_EVENT_DRIVEN_MODE_2 |
+			RX_EVENT_DRIVEN_MODE_2;
+		dbg_q_hdr->qhdr_rx_wm = SET;
+		dbg_q_hdr->qhdr_tx_wm = SET;
+		dbg_q_hdr->qhdr_rx_req = SET;
+		dbg_q_hdr->qhdr_tx_req = RESET;
+		dbg_q_hdr->qhdr_rx_irq_status = RESET;
+		dbg_q_hdr->qhdr_tx_irq_status = RESET;
+		break;
+
+	default:
+		pr_err("Invalid event driven mode :%u", event_driven_mode);
+		break;
+	}
+
+	cam_io_w((uint32_t)hfi_mem->qtbl.iova, icp_base + HFI_REG_QTBL_PTR);
+	cam_io_w((uint32_t)0x7400000, icp_base + HFI_REG_SHARED_MEM_PTR);
+	cam_io_w((uint32_t)0x6400000, icp_base + HFI_REG_SHARED_MEM_SIZE);
+	cam_io_w((uint32_t)hfi_mem->sec_heap.iova,
+		icp_base + HFI_REG_UNCACHED_HEAP_PTR);
+	cam_io_w((uint32_t)hfi_mem->sec_heap.len,
+		icp_base + HFI_REG_UNCACHED_HEAP_SIZE);
+	cam_io_w((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);
+	pr_debug("hw version : %u[%x]\n", hw_version, hw_version);
+
+	do {
+		msleep(500);
+		status = cam_io_r(icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE);
+	} while (status != ICP_INIT_RESP_SUCCESS);
+
+	if (status == ICP_INIT_RESP_SUCCESS) {
+		g_hfi->hfi_state = FW_RESP_DONE;
+		rc = 0;
+	} else {
+		rc = -ENODEV;
+		pr_err("FW initialization failed");
+		goto regions_fail;
+	}
+
+	fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION);
+	g_hfi->hfi_state = FW_START_SENT;
+
+	pr_debug("fw version : %u[%x]\n", fw_version, fw_version);
+	pr_debug("hfi init is successful\n");
+	cam_io_w((uint32_t)INTR_ENABLE, icp_base + HFI_REG_A5_CSR_A2HOSTINTEN);
+
+	return rc;
+regions_fail:
+	kzfree(g_hfi);
+alloc_fail:
+	return rc;
+}
+
+
+void cam_hfi_deinit(void)
+{
+	kfree(g_hfi);
+	g_hfi = NULL;
+}
+
+void icp_enable_fw_debug(void)
+{
+	hfi_send_system_cmd(HFI_CMD_SYS_SET_PROPERTY,
+		(uint64_t)HFI_PROP_SYS_DEBUG_CFG, 0);
+}
+
+int icp_ping_fw(void)
+{
+	hfi_send_system_cmd(HFI_CMD_SYS_PING,
+		(uint64_t)0x12123434, 0);
+
+	return 0;
+}
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/Makefile b/drivers/media/platform/msm/camera/icp/icp_hw/Makefile
new file mode 100644
index 0000000..8e95286
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/Makefile
@@ -0,0 +1,9 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_core
+ccflags-y += -Idrivers/media/platform/msm/camera/icp
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/include
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+
+obj-$(CONFIG_SPECTRA_CAMERA) += icp_hw_mgr/ a5_hw/ ipe_hw/ bps_hw/
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/Makefile b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/Makefile
new file mode 100644
index 0000000..a4df0b8
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/Makefile
@@ -0,0 +1,11 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_core
+ccflags-y += -Idrivers/media/platform/msm/camera/icp
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/include
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/a5_hw
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/fw_inc
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+
+obj-$(CONFIG_SPECTRA_CAMERA) += a5_dev.o a5_core.o a5_soc.o
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_core.c b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_core.c
new file mode 100644
index 0000000..f562bb9
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_core.c
@@ -0,0 +1,459 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "A5-CORE %s:%d " fmt, __func__, __LINE__
+
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/debugfs.h>
+#include <linux/videodev2.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/elf.h>
+#include <media/cam_icp.h>
+#include "cam_io_util.h"
+#include "cam_a5_hw_intf.h"
+#include "cam_hw.h"
+#include "cam_hw_intf.h"
+#include "a5_core.h"
+#include "a5_soc.h"
+#include "cam_soc_util.h"
+#include "cam_io_util.h"
+#include "hfi_intf.h"
+#include "hfi_sys_defs.h"
+#include "cam_icp_hw_mgr_intf.h"
+#include "cam_cpas_api.h"
+
+static int cam_a5_cpas_vote(struct cam_a5_device_core_info *core_info,
+	struct cam_icp_cpas_vote *cpas_vote)
+{
+	int rc = 0;
+
+	if (cpas_vote->ahb_vote_valid)
+		rc = cam_cpas_update_ahb_vote(core_info->cpas_handle,
+			&cpas_vote->ahb_vote);
+
+	if (cpas_vote->axi_vote_valid)
+		rc = cam_cpas_update_axi_vote(core_info->cpas_handle,
+			&cpas_vote->axi_vote);
+
+	if (rc)
+		pr_err("cpas vote is failed: %d\n", rc);
+
+	return rc;
+}
+
+static int32_t cam_icp_validate_fw(const uint8_t *elf)
+{
+	struct elf32_hdr *elf_hdr;
+
+	if (!elf) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	elf_hdr = (struct elf32_hdr *)elf;
+
+	if (memcmp(elf_hdr->e_ident, ELFMAG, SELFMAG)) {
+		pr_err("ICP elf identifier is failed\n");
+		return -EINVAL;
+	}
+
+	/* check architecture */
+	if (elf_hdr->e_machine != EM_ARM) {
+		pr_err("unsupported arch\n");
+		return -EINVAL;
+	}
+
+	/* check elf bit format */
+	if (elf_hdr->e_ident[EI_CLASS] != ELFCLASS32) {
+		pr_err("elf doesn't support 32 bit format\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int32_t cam_icp_get_fw_size(const uint8_t *elf, uint32_t *fw_size)
+{
+	int32_t rc = 0;
+	int32_t i = 0;
+	uint32_t num_prg_hdrs;
+	unsigned char *icp_prg_hdr_tbl;
+	uint32_t seg_mem_size = 0;
+	struct elf32_hdr *elf_hdr;
+	struct elf32_phdr *prg_hdr;
+
+	if (!elf || !fw_size) {
+		pr_err("invalid args\n");
+		return -EINVAL;
+	}
+
+	*fw_size = 0;
+
+	elf_hdr = (struct elf32_hdr *)elf;
+	num_prg_hdrs = elf_hdr->e_phnum;
+	icp_prg_hdr_tbl = (unsigned char *)elf + elf_hdr->e_phoff;
+	prg_hdr = (struct elf32_phdr *)&icp_prg_hdr_tbl[0];
+
+	if (!prg_hdr) {
+		pr_err("failed to get elf program header attr\n");
+		return -EINVAL;
+	}
+
+	pr_debug("num_prg_hdrs = %d\n", num_prg_hdrs);
+	for (i = 0; i < num_prg_hdrs; i++, prg_hdr++) {
+		if (prg_hdr->p_flags == 0)
+			continue;
+
+		seg_mem_size = (prg_hdr->p_memsz + prg_hdr->p_align - 1) &
+					~(prg_hdr->p_align - 1);
+		seg_mem_size += prg_hdr->p_vaddr;
+		pr_debug("p_memsz = %x p_align = %x p_vaddr = %x seg_mem_size = %x\n",
+			(int)prg_hdr->p_memsz, (int)prg_hdr->p_align,
+			(int)prg_hdr->p_vaddr, (int)seg_mem_size);
+		if (*fw_size < seg_mem_size)
+			*fw_size = seg_mem_size;
+
+	}
+
+	if (*fw_size == 0) {
+		pr_err("invalid elf fw file\n");
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int32_t cam_icp_program_fw(const uint8_t *elf,
+		struct cam_a5_device_core_info *core_info)
+{
+	int32_t rc = 0;
+	uint32_t num_prg_hdrs;
+	unsigned char *icp_prg_hdr_tbl;
+	int32_t i = 0;
+	u8 *dest;
+	u8 *src;
+	struct elf32_hdr *elf_hdr;
+	struct elf32_phdr *prg_hdr;
+
+	elf_hdr = (struct elf32_hdr *)elf;
+	num_prg_hdrs = elf_hdr->e_phnum;
+	icp_prg_hdr_tbl = (unsigned char *)elf + elf_hdr->e_phoff;
+	prg_hdr = (struct elf32_phdr *)&icp_prg_hdr_tbl[0];
+
+	if (!prg_hdr) {
+		pr_err("failed to get elf program header attr\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < num_prg_hdrs; i++, prg_hdr++) {
+		if (prg_hdr->p_flags == 0)
+			continue;
+
+		pr_debug("Loading FW header size: %u\n", prg_hdr->p_filesz);
+		if (prg_hdr->p_filesz != 0) {
+			src = (u8 *)((u8 *)elf + prg_hdr->p_offset);
+			dest = (u8 *)(((u8 *)core_info->fw_kva_addr) +
+						prg_hdr->p_vaddr);
+
+			memcpy_toio(dest, src, prg_hdr->p_filesz);
+			pr_debug("fw kva: %pK, p_vaddr: 0x%x\n",
+					dest, prg_hdr->p_vaddr);
+		}
+	}
+
+	return rc;
+}
+
+static int32_t cam_a5_download_fw(void *device_priv)
+{
+	int32_t rc = 0;
+	uint32_t fw_size;
+	const uint8_t *fw_start = NULL;
+	struct cam_hw_info *a5_dev = device_priv;
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_a5_device_core_info *core_info = NULL;
+	struct cam_a5_device_hw_info *hw_info = NULL;
+	struct platform_device         *pdev = NULL;
+	struct a5_soc_info *cam_a5_soc_info = NULL;
+
+	if (!device_priv) {
+		pr_err("Invalid cam_dev_info\n");
+		return -EINVAL;
+	}
+
+	soc_info = &a5_dev->soc_info;
+	core_info = (struct cam_a5_device_core_info *)a5_dev->core_info;
+	hw_info = core_info->a5_hw_info;
+	pdev = soc_info->pdev;
+	cam_a5_soc_info = soc_info->soc_private;
+
+	rc = request_firmware(&core_info->fw_elf, "CAMERA_ICP.elf", &pdev->dev);
+	pr_debug("request_firmware: %d\n", rc);
+	if (rc < 0) {
+		pr_err("Failed to locate fw\n");
+		return rc;
+	}
+
+	if (!core_info->fw_elf) {
+		pr_err("request_firmware is failed\n");
+		return -EINVAL;
+	}
+
+	fw_start = core_info->fw_elf->data;
+	rc = cam_icp_validate_fw(fw_start);
+	if (rc < 0) {
+		pr_err("fw elf validation failed\n");
+		return -EINVAL;
+	}
+
+	rc = cam_icp_get_fw_size(fw_start, &fw_size);
+	if (rc < 0) {
+		pr_err("unable to get fw file size\n");
+		return rc;
+	}
+	pr_debug("cam_icp_get_fw_size: %u\n", fw_size);
+
+	/* Check FW firmware memory allocation is OK or not */
+	pr_debug("cam_icp_get_fw_size: %u %llu\n",
+		fw_size, core_info->fw_buf_len);
+
+	if (core_info->fw_buf_len < fw_size) {
+		pr_err("fw allocation failed\n");
+		goto fw_alloc_failed;
+	}
+
+	/* download fw */
+	rc = cam_icp_program_fw(fw_start, core_info);
+	if (rc < 0) {
+		pr_err("fw program is failed\n");
+		goto fw_program_failed;
+	}
+
+	return 0;
+fw_program_failed:
+fw_alloc_failed:
+	return rc;
+}
+
+int cam_a5_init_hw(void *device_priv,
+	void *init_hw_args, uint32_t arg_size)
+{
+	struct cam_hw_info *a5_dev = device_priv;
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_a5_device_core_info *core_info = NULL;
+	struct cam_icp_cpas_vote cpas_vote;
+	int rc = 0;
+
+	if (!device_priv) {
+		pr_err("Invalid cam_dev_info\n");
+		return -EINVAL;
+	}
+
+	soc_info = &a5_dev->soc_info;
+	core_info = (struct cam_a5_device_core_info *)a5_dev->core_info;
+
+	if ((!soc_info) || (!core_info)) {
+		pr_err("soc_info = %pK core_info = %pK\n", soc_info, core_info);
+		return -EINVAL;
+	}
+
+	cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE;
+	cpas_vote.ahb_vote.vote.level = CAM_TURBO_VOTE;
+	cpas_vote.axi_vote.compressed_bw = ICP_TURBO_VOTE;
+	cpas_vote.axi_vote.uncompressed_bw = ICP_TURBO_VOTE;
+
+	rc = cam_cpas_start(core_info->cpas_handle,
+		&cpas_vote.ahb_vote, &cpas_vote.axi_vote);
+	if (rc < 0) {
+		pr_err("cpass start failed: %d\n", rc);
+		return rc;
+	}
+
+	rc = cam_a5_enable_soc_resources(soc_info);
+	if (rc < 0) {
+		pr_err("soc enable is failed\n");
+		rc = cam_cpas_stop(core_info->cpas_handle);
+		return rc;
+	}
+
+	return 0;
+}
+
+int cam_a5_deinit_hw(void *device_priv,
+	void *init_hw_args, uint32_t arg_size)
+{
+	struct cam_hw_info *a5_dev = device_priv;
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_a5_device_core_info *core_info = NULL;
+	int rc = 0;
+
+	if (!device_priv) {
+		pr_err("Invalid cam_dev_info\n");
+		return -EINVAL;
+	}
+
+	soc_info = &a5_dev->soc_info;
+	core_info = (struct cam_a5_device_core_info *)a5_dev->core_info;
+	if ((!soc_info) || (!core_info)) {
+		pr_err("soc_info = %pK core_info = %pK\n", soc_info, core_info);
+		return -EINVAL;
+	}
+
+	rc = cam_a5_disable_soc_resources(soc_info);
+	if (rc < 0)
+		pr_err("soc enable is failed\n");
+
+	rc = cam_cpas_stop(core_info->cpas_handle);
+	if (rc < 0)
+		pr_err("cpas stop is failed: %d\n", rc);
+
+	return 0;
+}
+
+irqreturn_t cam_a5_irq(int irq_num, void *data)
+{
+	struct cam_hw_info *a5_dev = data;
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_a5_device_core_info *core_info = NULL;
+	struct cam_a5_device_hw_info *hw_info = NULL;
+	uint32_t irq_status = 0;
+
+	if (!data) {
+		pr_err("Invalid cam_dev_info or query_cap args\n");
+		return IRQ_HANDLED;
+	}
+
+	soc_info = &a5_dev->soc_info;
+	core_info = (struct cam_a5_device_core_info *)a5_dev->core_info;
+	hw_info = core_info->a5_hw_info;
+
+	irq_status = cam_io_r_mb(soc_info->reg_map[A5_SIERRA_BASE].mem_base +
+				core_info->a5_hw_info->a5_host_int_status);
+
+	cam_io_w_mb(irq_status,
+			soc_info->reg_map[A5_SIERRA_BASE].mem_base +
+			core_info->a5_hw_info->a5_host_int_clr);
+
+	pr_debug("irq_status = %x\n", irq_status);
+	if (irq_status & A5_HOST_INT)
+		pr_debug("A5 to Host interrupt, read msg Q\n");
+
+	if ((irq_status & A5_WDT_0) ||
+		(irq_status & A5_WDT_1)) {
+		pr_err_ratelimited("watch dog interrupt from A5\n");
+	}
+
+	if (core_info->irq_cb.icp_hw_mgr_cb)
+		core_info->irq_cb.icp_hw_mgr_cb(irq_status,
+					core_info->irq_cb.data);
+	return IRQ_HANDLED;
+}
+
+int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type,
+	void *cmd_args, uint32_t arg_size)
+{
+	struct cam_hw_info *a5_dev = device_priv;
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_a5_device_core_info *core_info = NULL;
+	struct cam_a5_device_hw_info *hw_info = NULL;
+	int rc = 0;
+
+	if (!device_priv) {
+		pr_err("Invalid arguments\n");
+		return -EINVAL;
+	}
+
+	if (cmd_type >= CAM_ICP_A5_CMD_MAX) {
+		pr_err("Invalid command : %x\n", cmd_type);
+		return -EINVAL;
+	}
+
+	soc_info = &a5_dev->soc_info;
+	core_info = (struct cam_a5_device_core_info *)a5_dev->core_info;
+	hw_info = core_info->a5_hw_info;
+
+	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;
+
+		if (!cmd_args) {
+			pr_err("cmd args NULL\n");
+			return -EINVAL;
+		}
+
+		core_info->fw_buf = fw_buf_info->iova;
+		core_info->fw_kva_addr = fw_buf_info->kva;
+		core_info->fw_buf_len = fw_buf_info->len;
+
+		pr_debug("fw buf info = %x %llx %lld\n", core_info->fw_buf,
+			core_info->fw_kva_addr, core_info->fw_buf_len);
+		break;
+	}
+	case CAM_ICP_A5_SET_IRQ_CB: {
+		struct cam_icp_a5_set_irq_cb *irq_cb = cmd_args;
+
+		if (!cmd_args) {
+			pr_err("cmd args NULL\n");
+			return -EINVAL;
+		}
+
+		core_info->irq_cb.icp_hw_mgr_cb = irq_cb->icp_hw_mgr_cb;
+		core_info->irq_cb.data = irq_cb->data;
+		break;
+	}
+
+	case CAM_ICP_A5_SEND_INIT:
+		hfi_send_system_cmd(HFI_CMD_SYS_INIT, 0, 0);
+		break;
+	case CAM_ICP_A5_CMD_VOTE_CPAS: {
+		struct cam_icp_cpas_vote *cpas_vote = cmd_args;
+
+		if (!cmd_args) {
+			pr_err("cmd args NULL\n");
+			return -EINVAL;
+		}
+
+		cam_a5_cpas_vote(core_info, cpas_vote);
+		break;
+	}
+
+	case CAM_ICP_A5_CMD_CPAS_START: {
+		struct cam_icp_cpas_vote *cpas_vote = cmd_args;
+
+		if (!cmd_args) {
+			pr_err("cmd args NULL\n");
+			return -EINVAL;
+		}
+
+		rc = cam_cpas_start(core_info->cpas_handle,
+				&cpas_vote->ahb_vote, &cpas_vote->axi_vote);
+		break;
+	}
+
+	case CAM_ICP_A5_CMD_CPAS_STOP:
+		cam_cpas_stop(core_info->cpas_handle);
+		break;
+	default:
+		break;
+	}
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_core.h b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_core.h
new file mode 100644
index 0000000..8b84270
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_core.h
@@ -0,0 +1,87 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CAM_A5_CORE_H
+#define CAM_A5_CORE_H
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/dma-buf.h>
+#include "cam_a5_hw_intf.h"
+
+#define A5_QGIC_BASE            0
+#define A5_SIERRA_BASE          1
+#define A5_CSR_BASE             2
+
+#define A5_HOST_INT             0x1
+#define A5_WDT_0                0x10
+#define A5_WDT_1                0x100
+
+#define ELF_GUARD_PAGE          (2 * 1024 * 1024)
+
+struct cam_a5_device_hw_info {
+	uint32_t hw_ver;
+	uint32_t nsec_reset;
+	uint32_t a5_control;
+	uint32_t a5_host_int_en;
+	uint32_t a5_host_int;
+	uint32_t a5_host_int_clr;
+	uint32_t a5_host_int_status;
+	uint32_t a5_host_int_set;
+	uint32_t host_a5_int;
+	uint32_t fw_version;
+	uint32_t init_req;
+	uint32_t init_response;
+	uint32_t shared_mem_ptr;
+	uint32_t shared_mem_size;
+	uint32_t qtbl_ptr;
+	uint32_t uncached_heap_ptr;
+	uint32_t uncached_heap_size;
+	uint32_t a5_status;
+};
+
+/**
+ * struct cam_a5_device_hw_info
+ * @a5_hw_info: A5 hardware info
+ * @fw_elf: start address of fw start with elf header
+ * @fw: start address of fw blob
+ * @fw_buf: smmu alloc/mapped fw buffer
+ * @fw_buf_len: fw buffer length
+ * @query_cap: A5 query info from firmware
+ * @a5_acquire: Acquire information of A5
+ * @irq_cb: IRQ callback
+ * @cpas_handle: CPAS handle for A5
+ */
+struct cam_a5_device_core_info {
+	struct cam_a5_device_hw_info *a5_hw_info;
+	const struct firmware *fw_elf;
+	void *fw;
+	uint32_t fw_buf;
+	uint64_t fw_kva_addr;
+	uint64_t fw_buf_len;
+	struct cam_icp_a5_query_cap query_cap;
+	struct cam_icp_a5_acquire_dev a5_acquire[8];
+	struct cam_icp_a5_set_irq_cb irq_cb;
+	uint32_t cpas_handle;
+};
+
+int cam_a5_init_hw(void *device_priv,
+	void *init_hw_args, uint32_t arg_size);
+int cam_a5_deinit_hw(void *device_priv,
+	void *init_hw_args, uint32_t arg_size);
+int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type,
+	void *cmd_args, uint32_t arg_size);
+
+irqreturn_t cam_a5_irq(int irq_num, void *data);
+#endif /* CAM_A5_CORE_H */
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_dev.c b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_dev.c
new file mode 100644
index 0000000..f649c3b
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_dev.c
@@ -0,0 +1,197 @@
+/* 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/module.h>
+#include <linux/slab.h>
+#include <linux/mod_devicetable.h>
+#include <linux/of_device.h>
+#include <linux/timer.h>
+#include "a5_core.h"
+#include "a5_soc.h"
+#include "cam_io_util.h"
+#include "cam_hw.h"
+#include "cam_hw_intf.h"
+#include "cam_a5_hw_intf.h"
+#include "cam_icp_hw_mgr_intf.h"
+#include "cam_cpas_api.h"
+
+struct a5_soc_info cam_a5_soc_info;
+EXPORT_SYMBOL(cam_a5_soc_info);
+
+struct cam_a5_device_hw_info cam_a5_hw_info = {
+	.hw_ver = 0x0,
+	.nsec_reset = 0x4,
+	.a5_control = 0x8,
+	.a5_host_int_en = 0x10,
+	.a5_host_int = 0x14,
+	.a5_host_int_clr = 0x18,
+	.a5_host_int_status = 0x1c,
+	.a5_host_int_set = 0x20,
+	.host_a5_int = 0x30,
+	.fw_version = 0x44,
+	.init_req = 0x48,
+	.init_response = 0x4c,
+	.shared_mem_ptr = 0x50,
+	.shared_mem_size = 0x54,
+	.qtbl_ptr = 0x58,
+	.uncached_heap_ptr = 0x5c,
+	.uncached_heap_size = 0x60,
+	.a5_status = 0x200,
+};
+EXPORT_SYMBOL(cam_a5_hw_info);
+
+int cam_a5_register_cpas(struct cam_hw_soc_info *soc_info,
+			struct cam_a5_device_core_info *core_info,
+			uint32_t hw_idx)
+{
+	struct cam_cpas_register_params cpas_register_params;
+	int rc;
+
+	cpas_register_params.dev = &soc_info->pdev->dev;
+	memcpy(cpas_register_params.identifier, "icp", sizeof("icp"));
+	cpas_register_params.cam_cpas_client_cb = NULL;
+	cpas_register_params.cell_index = hw_idx;
+	cpas_register_params.userdata = NULL;
+
+	rc = cam_cpas_register_client(&cpas_register_params);
+	if (rc < 0) {
+		pr_err("cam_cpas_register_client is failed: %d\n", rc);
+		return rc;
+	}
+
+	core_info->cpas_handle = cpas_register_params.client_handle;
+	return rc;
+}
+
+int cam_a5_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct cam_hw_info *a5_dev = NULL;
+	struct cam_hw_intf *a5_dev_intf = NULL;
+	const struct of_device_id *match_dev = NULL;
+	struct cam_a5_device_core_info *core_info = NULL;
+	struct cam_a5_device_hw_info *hw_info = NULL;
+
+	a5_dev_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL);
+	if (!a5_dev_intf)
+		return -ENOMEM;
+
+	of_property_read_u32(pdev->dev.of_node,
+		"cell-index", &a5_dev_intf->hw_idx);
+
+	a5_dev = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL);
+	if (!a5_dev) {
+		rc = -ENOMEM;
+		goto a5_dev_alloc_failure;
+	}
+
+	a5_dev->soc_info.pdev = pdev;
+	a5_dev_intf->hw_priv = a5_dev;
+	a5_dev_intf->hw_ops.init = cam_a5_init_hw;
+	a5_dev_intf->hw_ops.deinit = cam_a5_deinit_hw;
+	a5_dev_intf->hw_ops.process_cmd = cam_a5_process_cmd;
+	a5_dev_intf->hw_type = CAM_ICP_DEV_A5;
+
+	pr_debug("%s: type %d index %d\n", __func__,
+		a5_dev_intf->hw_type,
+		a5_dev_intf->hw_idx);
+
+	platform_set_drvdata(pdev, a5_dev_intf);
+
+	a5_dev->core_info = kzalloc(sizeof(struct cam_a5_device_core_info),
+					GFP_KERNEL);
+	if (!a5_dev->core_info) {
+		rc = -ENOMEM;
+		goto core_info_alloc_failure;
+	}
+	core_info = (struct cam_a5_device_core_info *)a5_dev->core_info;
+
+	match_dev = of_match_device(pdev->dev.driver->of_match_table,
+		&pdev->dev);
+	if (!match_dev) {
+		pr_err("%s: No a5 hardware info\n", __func__);
+		rc = -EINVAL;
+		goto pr_err;
+	}
+	hw_info = (struct cam_a5_device_hw_info *)match_dev->data;
+	core_info->a5_hw_info = hw_info;
+
+	a5_dev->soc_info.soc_private = &cam_a5_soc_info;
+
+	rc = cam_a5_init_soc_resources(&a5_dev->soc_info, cam_a5_irq,
+		a5_dev);
+	if (rc < 0) {
+		pr_err("%s: failed to init_soc\n", __func__);
+		goto init_soc_failure;
+	}
+
+	pr_debug("cam_a5_init_soc_resources : %pK\n",
+				(void *)&a5_dev->soc_info);
+	rc = cam_a5_register_cpas(&a5_dev->soc_info,
+			core_info, a5_dev_intf->hw_idx);
+	if (rc < 0) {
+		pr_err("a5 cpas registration failed\n");
+		goto cpas_reg_failed;
+	}
+	a5_dev->hw_state = CAM_HW_STATE_POWER_DOWN;
+	mutex_init(&a5_dev->hw_mutex);
+	spin_lock_init(&a5_dev->hw_lock);
+	init_completion(&a5_dev->hw_complete);
+
+	pr_debug("%s: A5%d probe successful\n", __func__,
+		a5_dev_intf->hw_idx);
+	return 0;
+
+cpas_reg_failed:
+init_soc_failure:
+pr_err:
+	kfree(a5_dev->core_info);
+core_info_alloc_failure:
+	kfree(a5_dev);
+a5_dev_alloc_failure:
+	kfree(a5_dev_intf);
+
+	return rc;
+}
+
+static const struct of_device_id cam_a5_dt_match[] = {
+	{
+		.compatible = "qcom,cam_a5",
+		.data = &cam_a5_hw_info,
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, cam_a5_dt_match);
+
+static struct platform_driver cam_a5_driver = {
+	.probe = cam_a5_probe,
+	.driver = {
+		.name = "cam_a5",
+		.owner = THIS_MODULE,
+		.of_match_table = cam_a5_dt_match,
+	},
+};
+
+static int __init cam_a5_init_module(void)
+{
+	return platform_driver_register(&cam_a5_driver);
+}
+
+static void __exit cam_a5_exit_module(void)
+{
+	platform_driver_unregister(&cam_a5_driver);
+}
+
+module_init(cam_a5_init_module);
+module_exit(cam_a5_exit_module);
+MODULE_DESCRIPTION("CAM A5 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_soc.c b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_soc.c
new file mode 100644
index 0000000..641c154
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_soc.c
@@ -0,0 +1,101 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/dma-buf.h>
+#include <media/cam_defs.h>
+#include <media/cam_icp.h>
+#include "a5_soc.h"
+#include "cam_soc_util.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+static int cam_a5_get_dt_properties(struct cam_hw_soc_info *soc_info)
+{
+	int rc = 0;
+	const char *fw_name;
+	struct a5_soc_info *camp_a5_soc_info;
+	struct device_node *of_node = NULL;
+	struct platform_device *pdev = NULL;
+
+	pdev = soc_info->pdev;
+	of_node = pdev->dev.of_node;
+
+	rc = cam_soc_util_get_dt_properties(soc_info);
+	if (rc < 0) {
+		pr_err("%s: get a5 dt prop is failed\n", __func__);
+		return rc;
+	}
+
+	camp_a5_soc_info = soc_info->soc_private;
+	fw_name = camp_a5_soc_info->fw_name;
+
+	rc = of_property_read_string(of_node, "fw_name", &fw_name);
+	if (rc < 0)
+		pr_err("%s: fw_name read failed\n", __func__);
+
+	return rc;
+}
+
+static int cam_a5_request_platform_resource(
+	struct cam_hw_soc_info *soc_info,
+	irq_handler_t a5_irq_handler, void *irq_data)
+{
+	int rc = 0;
+
+	rc = cam_soc_util_request_platform_resource(soc_info, a5_irq_handler,
+		irq_data);
+
+	return rc;
+}
+
+int cam_a5_init_soc_resources(struct cam_hw_soc_info *soc_info,
+	irq_handler_t a5_irq_handler, void *irq_data)
+{
+	int rc = 0;
+
+	rc = cam_a5_get_dt_properties(soc_info);
+	if (rc < 0)
+		return rc;
+
+	rc = cam_a5_request_platform_resource(soc_info, a5_irq_handler,
+		irq_data);
+	if (rc < 0)
+		return rc;
+
+	return rc;
+}
+
+int cam_a5_enable_soc_resources(struct cam_hw_soc_info *soc_info)
+{
+	int rc = 0;
+
+	rc = cam_soc_util_enable_platform_resource(soc_info, true, true);
+	if (rc)
+		pr_err("%s: enable platform failed\n", __func__);
+
+	return rc;
+}
+
+int cam_a5_disable_soc_resources(struct cam_hw_soc_info *soc_info)
+{
+	int rc = 0;
+
+	rc = cam_soc_util_disable_platform_resource(soc_info, true, true);
+	if (rc)
+		pr_err("%s: enable platform failed\n", __func__);
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_soc.h b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_soc.h
new file mode 100644
index 0000000..916143d
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_soc.h
@@ -0,0 +1,29 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CAM_A5_SOC_H
+#define CAM_A5_SOC_H
+
+#include "cam_soc_util.h"
+
+struct a5_soc_info {
+	char *fw_name;
+};
+
+int cam_a5_init_soc_resources(struct cam_hw_soc_info *soc_info,
+	irq_handler_t a5_irq_handler, void *irq_data);
+
+int cam_a5_enable_soc_resources(struct cam_hw_soc_info *soc_info);
+
+int cam_a5_disable_soc_resources(struct cam_hw_soc_info *soc_info);
+
+#endif
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/Makefile b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/Makefile
new file mode 100644
index 0000000..6aeb5f1
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/Makefile
@@ -0,0 +1,11 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_core
+ccflags-y += -Idrivers/media/platform/msm/camera/icp
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/include
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/bps_hw
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/fw_inc
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+
+obj-$(CONFIG_SPECTRA_CAMERA) += bps_dev.o bps_core.o bps_soc.o
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_core.c b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_core.c
new file mode 100644
index 0000000..50863a5
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_core.c
@@ -0,0 +1,189 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "BPS-CORE %s:%d " fmt, __func__, __LINE__
+
+#include <linux/of.h>
+#include <linux/debugfs.h>
+#include <linux/videodev2.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include "cam_io_util.h"
+#include "cam_hw.h"
+#include "cam_hw_intf.h"
+#include "bps_core.h"
+#include "bps_soc.h"
+#include "cam_soc_util.h"
+#include "cam_io_util.h"
+#include "cam_bps_hw_intf.h"
+#include "cam_icp_hw_intf.h"
+#include "cam_icp_hw_mgr_intf.h"
+#include "cam_cpas_api.h"
+
+static int cam_bps_cpas_vote(struct cam_bps_device_core_info *core_info,
+			struct cam_icp_cpas_vote *cpas_vote)
+{
+	int rc = 0;
+
+	if (cpas_vote->ahb_vote_valid)
+		rc = cam_cpas_update_ahb_vote(core_info->cpas_handle,
+				&cpas_vote->ahb_vote);
+	if (cpas_vote->axi_vote_valid)
+		rc = cam_cpas_update_axi_vote(core_info->cpas_handle,
+				&cpas_vote->axi_vote);
+
+	if (rc < 0)
+		pr_err("cpas vote is failed: %d\n", rc);
+
+	return rc;
+}
+
+
+int cam_bps_init_hw(void *device_priv,
+	void *init_hw_args, uint32_t arg_size)
+{
+	struct cam_hw_info *bps_dev = device_priv;
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_bps_device_core_info *core_info = NULL;
+	struct cam_icp_cpas_vote cpas_vote;
+	int rc = 0;
+
+	if (!device_priv) {
+		pr_err("Invalid cam_dev_info\n");
+		return -EINVAL;
+	}
+
+	soc_info = &bps_dev->soc_info;
+	core_info = (struct cam_bps_device_core_info *)bps_dev->core_info;
+
+	if ((!soc_info) || (!core_info)) {
+		pr_err("soc_info = %pK core_info = %pK\n", soc_info, core_info);
+		return -EINVAL;
+	}
+
+	cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE;
+	cpas_vote.ahb_vote.vote.level = CAM_TURBO_VOTE;
+	cpas_vote.axi_vote.compressed_bw = ICP_TURBO_VOTE;
+	cpas_vote.axi_vote.uncompressed_bw = ICP_TURBO_VOTE;
+
+	rc = cam_cpas_start(core_info->cpas_handle,
+			&cpas_vote.ahb_vote, &cpas_vote.axi_vote);
+	if (rc < 0) {
+		pr_err("cpass start failed: %d\n", rc);
+		return rc;
+	}
+
+	rc = cam_bps_enable_soc_resources(soc_info);
+	if (rc < 0) {
+		pr_err("soc enable is failed\n");
+		rc = cam_cpas_stop(core_info->cpas_handle);
+	}
+
+	return rc;
+}
+
+int cam_bps_deinit_hw(void *device_priv,
+	void *init_hw_args, uint32_t arg_size)
+{
+	struct cam_hw_info *bps_dev = device_priv;
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_bps_device_core_info *core_info = NULL;
+	int rc = 0;
+
+	if (!device_priv) {
+		pr_err("Invalid cam_dev_info\n");
+		return -EINVAL;
+	}
+
+	soc_info = &bps_dev->soc_info;
+	core_info = (struct cam_bps_device_core_info *)bps_dev->core_info;
+	if ((!soc_info) || (!core_info)) {
+		pr_err("soc_info = %pK core_info = %pK\n", soc_info, core_info);
+		return -EINVAL;
+	}
+
+	rc = cam_bps_disable_soc_resources(soc_info);
+	if (rc < 0)
+		pr_err("soc enable is failed\n");
+
+	rc = cam_cpas_stop(core_info->cpas_handle);
+	if (rc < 0)
+		pr_err("cpas stop is failed: %d\n", rc);
+
+	return rc;
+}
+
+int cam_bps_process_cmd(void *device_priv, uint32_t cmd_type,
+	void *cmd_args, uint32_t arg_size)
+{
+	struct cam_hw_info *bps_dev = device_priv;
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_bps_device_core_info *core_info = NULL;
+	struct cam_bps_device_hw_info *hw_info = NULL;
+	int rc = 0;
+
+	if (!device_priv) {
+		pr_err("Invalid arguments\n");
+		return -EINVAL;
+	}
+
+	if (cmd_type >= CAM_ICP_BPS_CMD_MAX) {
+		pr_err("Invalid command : %x\n", cmd_type);
+		return -EINVAL;
+	}
+
+	soc_info = &bps_dev->soc_info;
+	core_info = (struct cam_bps_device_core_info *)bps_dev->core_info;
+	hw_info = core_info->bps_hw_info;
+
+	switch (cmd_type) {
+	case CAM_ICP_BPS_CMD_VOTE_CPAS: {
+		struct cam_icp_cpas_vote *cpas_vote = cmd_args;
+
+		if (!cmd_args) {
+			pr_err("cmd args NULL\n");
+			return -EINVAL;
+		}
+
+		cam_bps_cpas_vote(core_info, cpas_vote);
+		break;
+	}
+
+	case CAM_ICP_BPS_CMD_CPAS_START: {
+		struct cam_icp_cpas_vote *cpas_vote = cmd_args;
+
+		if (!cmd_args) {
+			pr_err("cmd args NULL\n");
+			return -EINVAL;
+		}
+
+		rc = cam_cpas_start(core_info->cpas_handle,
+				&cpas_vote->ahb_vote, &cpas_vote->axi_vote);
+		break;
+	}
+
+	case CAM_ICP_BPS_CMD_CPAS_STOP:
+		cam_cpas_stop(core_info->cpas_handle);
+		break;
+	default:
+		break;
+	}
+	return rc;
+}
+
+irqreturn_t cam_bps_irq(int irq_num, void *data)
+{
+	return IRQ_HANDLED;
+}
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_core.h b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_core.h
new file mode 100644
index 0000000..67e1c03
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_core.h
@@ -0,0 +1,39 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CAM_BPS_CORE_H
+#define CAM_BPS_CORE_H
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/dma-buf.h>
+
+struct cam_bps_device_hw_info {
+	uint32_t reserved;
+};
+
+struct cam_bps_device_core_info {
+	struct cam_bps_device_hw_info *bps_hw_info;
+	uint32_t cpas_handle;
+};
+
+int cam_bps_init_hw(void *device_priv,
+	void *init_hw_args, uint32_t arg_size);
+int cam_bps_deinit_hw(void *device_priv,
+	void *init_hw_args, uint32_t arg_size);
+int cam_bps_process_cmd(void *device_priv, uint32_t cmd_type,
+	void *cmd_args, uint32_t arg_size);
+
+irqreturn_t cam_bps_irq(int irq_num, void *data);
+#endif /* CAM_BPS_CORE_H */
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_dev.c b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_dev.c
new file mode 100644
index 0000000..c3477ee
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_dev.c
@@ -0,0 +1,169 @@
+/* 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/module.h>
+#include <linux/slab.h>
+#include <linux/mod_devicetable.h>
+#include <linux/of_device.h>
+#include <linux/timer.h>
+#include "bps_core.h"
+#include "bps_soc.h"
+#include "cam_hw.h"
+#include "cam_hw_intf.h"
+#include "cam_io_util.h"
+#include "cam_icp_hw_intf.h"
+#include "cam_icp_hw_mgr_intf.h"
+#include "cam_cpas_api.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+struct cam_bps_device_hw_info cam_bps_hw_info = {
+	.reserved = 0,
+};
+EXPORT_SYMBOL(cam_bps_hw_info);
+
+int cam_bps_register_cpas(struct cam_hw_soc_info *soc_info,
+			struct cam_bps_device_core_info *core_info,
+			uint32_t hw_idx)
+{
+	struct cam_cpas_register_params cpas_register_params;
+	int rc;
+
+	cpas_register_params.dev = &soc_info->pdev->dev;
+	memcpy(cpas_register_params.identifier, "bps", sizeof("bps"));
+	cpas_register_params.cam_cpas_client_cb = NULL;
+	cpas_register_params.cell_index = hw_idx;
+	cpas_register_params.userdata = NULL;
+
+	rc = cam_cpas_register_client(&cpas_register_params);
+	if (rc < 0) {
+		pr_err("cam_cpas_register_client is failed: %d\n", rc);
+		return rc;
+	}
+	core_info->cpas_handle = cpas_register_params.client_handle;
+
+	return rc;
+}
+
+int cam_bps_probe(struct platform_device *pdev)
+{
+	struct cam_hw_info            *bps_dev = NULL;
+	struct cam_hw_intf            *bps_dev_intf = NULL;
+	const struct of_device_id         *match_dev = NULL;
+	struct cam_bps_device_core_info   *core_info = NULL;
+	struct cam_bps_device_hw_info     *hw_info = NULL;
+	int                                rc = 0;
+
+	bps_dev_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL);
+	if (!bps_dev_intf)
+		return -ENOMEM;
+
+	of_property_read_u32(pdev->dev.of_node,
+		"cell-index", &bps_dev_intf->hw_idx);
+
+	bps_dev = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL);
+	if (!bps_dev) {
+		kfree(bps_dev_intf);
+		return -ENOMEM;
+	}
+	bps_dev->soc_info.pdev = pdev;
+	bps_dev_intf->hw_priv = bps_dev;
+	bps_dev_intf->hw_ops.init = cam_bps_init_hw;
+	bps_dev_intf->hw_ops.deinit = cam_bps_deinit_hw;
+	bps_dev_intf->hw_ops.process_cmd = cam_bps_process_cmd;
+	bps_dev_intf->hw_type = CAM_ICP_DEV_BPS;
+	platform_set_drvdata(pdev, bps_dev_intf);
+	bps_dev->core_info = kzalloc(sizeof(struct cam_bps_device_core_info),
+					GFP_KERNEL);
+	if (!bps_dev->core_info) {
+		kfree(bps_dev);
+		kfree(bps_dev_intf);
+		return -ENOMEM;
+	}
+	core_info = (struct cam_bps_device_core_info *)bps_dev->core_info;
+
+	match_dev = of_match_device(pdev->dev.driver->of_match_table,
+		&pdev->dev);
+	if (!match_dev) {
+		pr_err("%s: No bps hardware info\n", __func__);
+		kfree(bps_dev->core_info);
+		kfree(bps_dev);
+		kfree(bps_dev_intf);
+		rc = -EINVAL;
+		return rc;
+	}
+	hw_info = (struct cam_bps_device_hw_info *)match_dev->data;
+	core_info->bps_hw_info = hw_info;
+
+	rc = cam_bps_init_soc_resources(&bps_dev->soc_info, cam_bps_irq,
+		bps_dev);
+	if (rc < 0) {
+		pr_err("%s: failed to init_soc\n", __func__);
+		kfree(bps_dev->core_info);
+		kfree(bps_dev);
+		kfree(bps_dev_intf);
+		return rc;
+	}
+	pr_debug("cam_bps_init_soc_resources : %pK\n",
+		(void *)&bps_dev->soc_info);
+
+	rc = cam_bps_register_cpas(&bps_dev->soc_info,
+			core_info, bps_dev_intf->hw_idx);
+	if (rc < 0) {
+		kfree(bps_dev->core_info);
+		kfree(bps_dev);
+		kfree(bps_dev_intf);
+		return rc;
+	}
+	bps_dev->hw_state = CAM_HW_STATE_POWER_DOWN;
+	mutex_init(&bps_dev->hw_mutex);
+	spin_lock_init(&bps_dev->hw_lock);
+	init_completion(&bps_dev->hw_complete);
+	pr_debug("%s: BPS%d probe successful\n", __func__,
+		bps_dev_intf->hw_idx);
+
+	return rc;
+}
+
+static const struct of_device_id cam_bps_dt_match[] = {
+	{
+		.compatible = "qcom,cam_bps",
+		.data = &cam_bps_hw_info,
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, cam_bps_dt_match);
+
+static struct platform_driver cam_bps_driver = {
+	.probe = cam_bps_probe,
+	.driver = {
+		.name = "cam_bps",
+		.owner = THIS_MODULE,
+		.of_match_table = cam_bps_dt_match,
+	},
+};
+
+static int __init cam_bps_init_module(void)
+{
+	return platform_driver_register(&cam_bps_driver);
+}
+
+static void __exit cam_bps_exit_module(void)
+{
+	platform_driver_unregister(&cam_bps_driver);
+}
+
+module_init(cam_bps_init_module);
+module_exit(cam_bps_exit_module);
+MODULE_DESCRIPTION("CAM BPS driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_soc.c b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_soc.c
new file mode 100644
index 0000000..76884bf
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_soc.c
@@ -0,0 +1,85 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/dma-buf.h>
+#include <media/cam_defs.h>
+#include <media/cam_icp.h>
+#include "bps_soc.h"
+#include "cam_soc_util.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+static int cam_bps_get_dt_properties(struct cam_hw_soc_info *soc_info)
+{
+	int rc = 0;
+
+	rc = cam_soc_util_get_dt_properties(soc_info);
+	if (rc < 0)
+		pr_err("get bps dt prop is failed\n");
+
+	return rc;
+}
+
+static int cam_bps_request_platform_resource(
+	struct cam_hw_soc_info *soc_info,
+	irq_handler_t bps_irq_handler, void *irq_data)
+{
+	int rc = 0;
+
+	rc = cam_soc_util_request_platform_resource(soc_info, bps_irq_handler,
+		irq_data);
+
+	return rc;
+}
+
+int cam_bps_init_soc_resources(struct cam_hw_soc_info *soc_info,
+	irq_handler_t bps_irq_handler, void *irq_data)
+{
+	int rc = 0;
+
+	rc = cam_bps_get_dt_properties(soc_info);
+	if (rc < 0)
+		return rc;
+
+	rc = cam_bps_request_platform_resource(soc_info, bps_irq_handler,
+		irq_data);
+	if (rc < 0)
+		return rc;
+
+	return rc;
+}
+
+int cam_bps_enable_soc_resources(struct cam_hw_soc_info *soc_info)
+{
+	int rc = 0;
+
+	rc = cam_soc_util_enable_platform_resource(soc_info, true, false);
+	if (rc)
+		pr_err("%s: enable platform failed\n", __func__);
+
+	return rc;
+}
+
+int cam_bps_disable_soc_resources(struct cam_hw_soc_info *soc_info)
+{
+	int rc = 0;
+
+	rc = cam_soc_util_disable_platform_resource(soc_info, true, false);
+	if (rc)
+		pr_err("%s: disable platform failed\n", __func__);
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_soc.h b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_soc.h
new file mode 100644
index 0000000..b16db01
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_soc.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_BPS_SOC_H_
+#define _CAM_BPS_SOC_H_
+
+#include "cam_soc_util.h"
+
+int cam_bps_init_soc_resources(struct cam_hw_soc_info *soc_info,
+	irq_handler_t bps_irq_handler, void *irq_data);
+
+int cam_bps_enable_soc_resources(struct cam_hw_soc_info *soc_info);
+
+int cam_bps_disable_soc_resources(struct cam_hw_soc_info *soc_info);
+
+#endif /* _CAM_BPS_SOC_H_*/
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/Makefile b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/Makefile
new file mode 100644
index 0000000..4a6c3c0
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/Makefile
@@ -0,0 +1,16 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/isp/isp_hw/include
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/include
+ccflags-y += -Idrivers/media/platform/msm/camera/isp/isp_hw/hw_utils/include
+ccflags-y += -Idrivers/media/platform/msm/camera/isp/isp_hw/isp_hw_mgr/
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/fw_inc/
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu/
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_core
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sync
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr/
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include/
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/a5_hw/
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_icp_hw_mgr.o
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
new file mode 100644
index 0000000..489ded1
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
@@ -0,0 +1,2007 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "ICP-HW-MGR %s:%d " fmt, __func__, __LINE__
+
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/timer.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <media/cam_defs.h>
+#include <media/cam_icp.h>
+#include "cam_sync_api.h"
+#include "cam_hw.h"
+#include "cam_hw_mgr_intf.h"
+#include "cam_icp_hw_mgr_intf.h"
+#include "cam_icp_hw_mgr.h"
+#include "cam_a5_hw_intf.h"
+#include "cam_bps_hw_intf.h"
+#include "cam_ipe_hw_intf.h"
+#include "cam_smmu_api.h"
+#include "cam_mem_mgr.h"
+#include "hfi_intf.h"
+#include "hfi_reg.h"
+#include "hfi_session_defs.h"
+#include "hfi_sys_defs.h"
+#include "cam_req_mgr_workq.h"
+#include "cam_mem_mgr.h"
+#include "a5_core.h"
+#include "hfi_sys_defs.h"
+
+#undef  ICP_DBG
+#define ICP_DBG(fmt, args...) pr_debug(fmt, ##args)
+
+#define ICP_WORKQ_NUM_TASK 30
+#define ICP_WORKQ_TASK_CMD_TYPE 1
+#define ICP_WORKQ_TASK_MSG_TYPE 2
+
+static struct cam_icp_hw_mgr icp_hw_mgr;
+
+static int cam_icp_stop_cpas(struct cam_icp_hw_mgr *hw_mgr_priv)
+{
+	struct cam_hw_intf *a5_dev_intf = NULL;
+	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_icp_hw_mgr *hw_mgr = hw_mgr_priv;
+	struct cam_icp_cpas_vote cpas_vote;
+	int rc = 0;
+
+	if (!hw_mgr) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0];
+	bps_dev_intf = hw_mgr->devices[CAM_ICP_DEV_BPS][0];
+	ipe0_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][0];
+
+	if ((!a5_dev_intf) || (!bps_dev_intf) || (!ipe0_dev_intf)) {
+		pr_err("dev intfs are NULL\n");
+		return -EINVAL;
+	}
+
+	rc = a5_dev_intf->hw_ops.process_cmd(
+		a5_dev_intf->hw_priv,
+		CAM_ICP_A5_CMD_CPAS_STOP,
+		&cpas_vote,
+		sizeof(struct cam_icp_cpas_vote));
+	if (rc < 0)
+		pr_err("CAM_ICP_A5_CMD_CPAS_STOP is failed: %d\n", rc);
+
+	rc = bps_dev_intf->hw_ops.process_cmd(
+		bps_dev_intf->hw_priv,
+		CAM_ICP_BPS_CMD_CPAS_STOP,
+		&cpas_vote,
+		sizeof(struct cam_icp_cpas_vote));
+	if (rc < 0)
+		pr_err("CAM_ICP_BPS_CMD_CPAS_STOP is failed: %d\n", rc);
+
+	rc = ipe0_dev_intf->hw_ops.process_cmd(
+		ipe0_dev_intf->hw_priv,
+		CAM_ICP_IPE_CMD_CPAS_STOP,
+		&cpas_vote,
+		sizeof(struct cam_icp_cpas_vote));
+	if (rc < 0)
+		pr_err("CAM_ICP_IPE_CMD_CPAS_STOP is failed: %d\n", rc);
+
+	ipe1_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][1];
+	if (!ipe1_dev_intf)
+		return rc;
+
+	rc = ipe1_dev_intf->hw_ops.process_cmd(
+		ipe1_dev_intf->hw_priv,
+		CAM_ICP_IPE_CMD_CPAS_STOP,
+		&cpas_vote,
+		sizeof(struct cam_icp_cpas_vote));
+	if (rc < 0)
+		pr_err("CAM_ICP_IPE_CMD_CPAS_STOP is failed: %d\n", rc);
+
+	return rc;
+}
+
+static int cam_icp_start_cpas(struct cam_icp_hw_mgr *hw_mgr_priv)
+{
+	struct cam_hw_intf *a5_dev_intf = NULL;
+	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_icp_hw_mgr *hw_mgr = hw_mgr_priv;
+	struct cam_icp_cpas_vote cpas_vote;
+	int rc = 0;
+
+	if (!hw_mgr) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0];
+	bps_dev_intf = hw_mgr->devices[CAM_ICP_DEV_BPS][0];
+	ipe0_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][0];
+
+	if ((!a5_dev_intf) || (!bps_dev_intf) || (!ipe0_dev_intf)) {
+		pr_err("dev intfs are null\n");
+		return -EINVAL;
+	}
+
+	cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE;
+	cpas_vote.ahb_vote.vote.level = CAM_TURBO_VOTE;
+	cpas_vote.axi_vote.compressed_bw = 640000000;
+	cpas_vote.axi_vote.uncompressed_bw = 640000000;
+
+	rc = a5_dev_intf->hw_ops.process_cmd(
+		a5_dev_intf->hw_priv,
+		CAM_ICP_A5_CMD_CPAS_START,
+		&cpas_vote,
+		sizeof(struct cam_icp_cpas_vote));
+	if (rc) {
+		pr_err("CAM_ICP_A5_CMD_CPAS_START is failed: %d\n", rc);
+		goto a5_cpas_start_failed;
+	}
+
+	rc = bps_dev_intf->hw_ops.process_cmd(
+		bps_dev_intf->hw_priv,
+		CAM_ICP_BPS_CMD_CPAS_START,
+		&cpas_vote,
+		sizeof(struct cam_icp_cpas_vote));
+	if (rc < 0) {
+		pr_err("CAM_ICP_BPS_CMD_CPAS_START is failed: %d\n", rc);
+		goto bps_cpas_start_failed;
+	}
+
+	rc = ipe0_dev_intf->hw_ops.process_cmd(
+		ipe0_dev_intf->hw_priv,
+		CAM_ICP_IPE_CMD_CPAS_START,
+		&cpas_vote,
+		sizeof(struct cam_icp_cpas_vote));
+	if (rc < 0) {
+		pr_err("CAM_ICP_IPE_CMD_CPAS_START is failed: %d\n", rc);
+		goto ipe0_cpas_start_failed;
+	}
+
+	ipe1_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][1];
+	if (!ipe1_dev_intf)
+		return rc;
+
+	rc = ipe1_dev_intf->hw_ops.process_cmd(
+		ipe1_dev_intf->hw_priv,
+		CAM_ICP_IPE_CMD_CPAS_START,
+		&cpas_vote,
+		sizeof(struct cam_icp_cpas_vote));
+	if (rc < 0) {
+		pr_err("CAM_ICP_IPE_CMD_CPAS_START is failed: %d\n", rc);
+		goto ipe1_cpas_start_failed;
+	}
+
+	return rc;
+
+ipe1_cpas_start_failed:
+	rc = ipe0_dev_intf->hw_ops.process_cmd(
+		ipe0_dev_intf->hw_priv,
+		CAM_ICP_IPE_CMD_CPAS_STOP,
+		&cpas_vote,
+		sizeof(struct cam_icp_cpas_vote));
+ipe0_cpas_start_failed:
+	rc = bps_dev_intf->hw_ops.process_cmd(
+		bps_dev_intf->hw_priv,
+		CAM_ICP_BPS_CMD_CPAS_STOP,
+		&cpas_vote,
+		sizeof(struct cam_icp_cpas_vote));
+bps_cpas_start_failed:
+	rc = a5_dev_intf->hw_ops.process_cmd(
+		a5_dev_intf->hw_priv,
+		CAM_ICP_A5_CMD_CPAS_STOP,
+		&cpas_vote,
+		sizeof(struct cam_icp_cpas_vote));
+a5_cpas_start_failed:
+	return rc;
+}
+
+static int cam_icp_mgr_process_cmd(void *priv, void *data)
+{
+	int rc;
+	struct hfi_cmd_work_data *task_data = NULL;
+	struct cam_icp_hw_mgr *hw_mgr;
+
+	if (!data || !priv) {
+		pr_err("Invalid params%pK %pK\n", data, priv);
+		return -EINVAL;
+	}
+
+	hw_mgr = priv;
+	task_data = (struct hfi_cmd_work_data *)data;
+
+	rc = hfi_write_cmd(task_data->data);
+	if (rc < 0)
+		pr_err("unable to write\n");
+
+	ICP_DBG("task type : %u, rc : %d\n", task_data->type, rc);
+	return rc;
+}
+
+static int cam_icp_mgr_process_msg_frame_process(uint32_t *msg_ptr)
+{
+	int i;
+	uint32_t idx;
+	uint32_t request_id;
+	struct cam_icp_hw_ctx_data *ctx_data = NULL;
+	struct hfi_msg_ipebps_async_ack *ioconfig_ack = NULL;
+	struct hfi_msg_frame_process_done *frame_done;
+	struct hfi_frame_process_info *hfi_frame_process;
+	struct cam_hw_done_event_data   buf_data;
+
+	ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr;
+	if (ioconfig_ack->err_type != HFI_ERR_SYS_NONE) {
+		pr_err("failed with error : %u\n", ioconfig_ack->err_type);
+		return -EIO;
+	}
+
+	frame_done =
+		(struct hfi_msg_frame_process_done *)ioconfig_ack->msg_data;
+	if (frame_done->result) {
+		pr_err("result : %u\n", frame_done->result);
+		return -EIO;
+	}
+	ICP_DBG("result : %u\n", frame_done->result);
+
+	ctx_data = (struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1;
+	request_id = ioconfig_ack->user_data2;
+	ICP_DBG("ctx : %pK, request_id :%d\n",
+		(void *)ctx_data->context_priv, request_id);
+
+	hfi_frame_process = &ctx_data->hfi_frame_process;
+	for (i = 0; i < CAM_FRAME_CMD_MAX; i++)
+		if (hfi_frame_process->request_id[i] == request_id)
+			break;
+
+	if (i >= CAM_FRAME_CMD_MAX) {
+		pr_err("unable to find pkt in ctx data for req_id =%d\n",
+			request_id);
+		return -EINVAL;
+	}
+	idx = i;
+
+	/* send event to ctx this needs to be done in msg handler */
+	buf_data.num_handles = hfi_frame_process->num_out_resources[idx];
+	for (i = 0; i < buf_data.num_handles; i++)
+		buf_data.resource_handle[i] =
+			hfi_frame_process->out_resource[idx][i];
+
+	ctx_data->ctxt_event_cb(ctx_data->context_priv, 0, &buf_data);
+
+	/* now release memory for hfi frame process command */
+	ICP_DBG("matching request id: %d\n",
+			hfi_frame_process->request_id[idx]);
+	mutex_lock(&ctx_data->hfi_frame_process.lock);
+	hfi_frame_process->request_id[idx] = 0;
+	clear_bit(idx, ctx_data->hfi_frame_process.bitmap);
+	mutex_unlock(&ctx_data->hfi_frame_process.lock);
+	return 0;
+}
+
+static int cam_icp_mgr_process_msg_config_io(uint32_t *msg_ptr)
+{
+	struct cam_icp_hw_ctx_data *ctx_data = NULL;
+	struct hfi_msg_ipebps_async_ack *ioconfig_ack = NULL;
+	struct hfi_msg_ipe_config *ipe_config_ack = NULL;
+	struct hfi_msg_bps_common *bps_config_ack = NULL;
+
+	ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr;
+	ICP_DBG("opcode : %u\n", ioconfig_ack->opcode);
+
+	if (ioconfig_ack->opcode == HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO) {
+		ipe_config_ack =
+			(struct hfi_msg_ipe_config *)(ioconfig_ack->msg_data);
+		if (ipe_config_ack->rc) {
+			pr_err("rc = %d err = %u\n",
+				ipe_config_ack->rc, ioconfig_ack->err_type);
+			return -EIO;
+		}
+		ctx_data =
+			(struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1;
+		mutex_lock(&ctx_data->ctx_mutex);
+		ctx_data->scratch_mem_size = ipe_config_ack->scratch_mem_size;
+		mutex_unlock(&ctx_data->ctx_mutex);
+		ICP_DBG("scratch_mem_size = %u\n",
+			ipe_config_ack->scratch_mem_size);
+	} else {
+		bps_config_ack =
+			(struct hfi_msg_bps_common *)(ioconfig_ack->msg_data);
+		if (bps_config_ack->rc) {
+			pr_err("rc : %u, opcode :%u\n",
+				bps_config_ack->rc, ioconfig_ack->opcode);
+			return -EIO;
+		}
+		ctx_data =
+			(struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1;
+	}
+	complete(&ctx_data->wait_complete);
+
+	return 0;
+}
+
+static int cam_icp_mgr_process_msg_create_handle(uint32_t *msg_ptr)
+{
+	struct hfi_msg_create_handle_ack *create_handle_ack = NULL;
+	struct cam_icp_hw_ctx_data *ctx_data = NULL;
+
+	create_handle_ack = (struct hfi_msg_create_handle_ack *)msg_ptr;
+	if (!create_handle_ack) {
+		pr_err("Invalid create_handle_ack\n");
+		return -EINVAL;
+	}
+
+	ICP_DBG("err type : %u\n", create_handle_ack->err_type);
+
+	ctx_data = (struct cam_icp_hw_ctx_data *)create_handle_ack->user_data1;
+	if (!ctx_data) {
+		pr_err("Invalid ctx_data\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&ctx_data->ctx_mutex);
+	ctx_data->fw_handle = create_handle_ack->fw_handle;
+	mutex_unlock(&ctx_data->ctx_mutex);
+	ICP_DBG("fw_handle = %x\n", ctx_data->fw_handle);
+	complete(&ctx_data->wait_complete);
+
+	return 0;
+}
+
+static int cam_icp_mgr_process_msg_ping_ack(uint32_t *msg_ptr)
+{
+	struct hfi_msg_ping_ack *ping_ack = NULL;
+	struct cam_icp_hw_ctx_data *ctx_data = NULL;
+
+	ping_ack = (struct hfi_msg_ping_ack *)msg_ptr;
+	if (!ping_ack) {
+		pr_err("Empty ping ack message\n");
+		return -EINVAL;
+	}
+
+	ctx_data = (struct cam_icp_hw_ctx_data *)ping_ack->user_data;
+	if (!ctx_data) {
+		pr_err("Invalid ctx_data\n");
+		return -EINVAL;
+	}
+
+	ICP_DBG("%x %x %pK\n", ping_ack->size, ping_ack->pkt_type,
+		(void *)ping_ack->user_data);
+	complete(&ctx_data->wait_complete);
+
+	return 0;
+}
+
+static int cam_icp_mgr_process_indirect_ack_msg(uint32_t *msg_ptr)
+{
+	int rc;
+
+	switch (msg_ptr[ICP_PACKET_IPCODE]) {
+	case HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO:
+	case HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO:
+		ICP_DBG("received HFI_IPEBPS_CMD_OPCODE_IPE/BPS_CONFIG_IO:\n");
+		rc = cam_icp_mgr_process_msg_config_io(msg_ptr);
+		if (rc < 0) {
+			pr_err("error in process_msg_config_io\n");
+			return rc;
+		}
+		break;
+
+	case HFI_IPEBPS_CMD_OPCODE_IPE_FRAME_PROCESS:
+	case HFI_IPEBPS_CMD_OPCODE_BPS_FRAME_PROCESS:
+		ICP_DBG("received OPCODE_IPE/BPS_FRAME_PROCESS:\n");
+		rc = cam_icp_mgr_process_msg_frame_process(msg_ptr);
+		if (rc < 0) {
+			pr_err("error in msg_frame_process\n");
+			return rc;
+		}
+		break;
+	default:
+		pr_err("Invalid opcode : %u\n",
+			msg_ptr[ICP_PACKET_IPCODE]);
+		break;
+	}
+
+	return 0;
+}
+
+static int cam_icp_mgr_process_direct_ack_msg(uint32_t *msg_ptr)
+{
+	struct cam_icp_hw_ctx_data *ctx_data = NULL;
+	struct hfi_msg_ipebps_async_ack *ioconfig_ack = NULL;
+
+	if (msg_ptr[ICP_PACKET_IPCODE] ==
+		HFI_IPEBPS_CMD_OPCODE_IPE_DESTROY ||
+		msg_ptr[ICP_PACKET_IPCODE] ==
+		HFI_IPEBPS_CMD_OPCODE_BPS_DESTROY) {
+		ICP_DBG("received HFI_IPEBPS_CMD_OPCODE_IPE/BPS_DESTROY:\n");
+		ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr;
+		ctx_data =
+			(struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1;
+		complete(&ctx_data->wait_complete);
+
+	} else {
+		pr_err("Invalid opcode : %u\n", msg_ptr[ICP_PACKET_IPCODE]);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int32_t cam_icp_mgr_process_msg(void *priv, void *data)
+{
+	int rc = 0;
+	uint32_t *msg_ptr = NULL;
+	struct hfi_msg_work_data *task_data;
+	struct cam_icp_hw_mgr *hw_mgr;
+	int read_len;
+
+	if (!data || !priv) {
+		pr_err("Invalid data\n");
+		return -EINVAL;
+	}
+
+	task_data = data;
+	hw_mgr = priv;
+	ICP_DBG("irq status : %u\n", task_data->irq_status);
+
+	read_len = hfi_read_message(icp_hw_mgr.msg_buf, Q_MSG);
+	if (read_len < 0) {
+		ICP_DBG("Unable to read msg q\n");
+		return read_len;
+	}
+
+	msg_ptr = (uint32_t *)icp_hw_mgr.msg_buf;
+	ICP_DBG("packet type: %x\n", msg_ptr[ICP_PACKET_TYPE]);
+
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	switch (msg_ptr[ICP_PACKET_TYPE]) {
+	case HFI_MSG_SYS_INIT_DONE:
+		ICP_DBG("received HFI_MSG_SYS_INIT_DONE\n");
+		complete(&hw_mgr->a5_complete);
+		break;
+
+	case HFI_MSG_SYS_PING_ACK:
+		ICP_DBG("received HFI_MSG_SYS_PING_ACK\n");
+		rc = cam_icp_mgr_process_msg_ping_ack(msg_ptr);
+		if (rc)
+			pr_err("fail process PING_ACK\n");
+		break;
+
+	case HFI_MSG_IPEBPS_CREATE_HANDLE_ACK:
+		ICP_DBG("received HFI_MSG_IPEBPS_CREATE_HANDLE_ACK\n");
+		rc = cam_icp_mgr_process_msg_create_handle(msg_ptr);
+		if (rc)
+			pr_err("fail process CREATE_HANDLE_ACK\n");
+		break;
+
+	case HFI_MSG_IPEBPS_ASYNC_COMMAND_INDIRECT_ACK:
+		rc = cam_icp_mgr_process_indirect_ack_msg(msg_ptr);
+		if (rc)
+			pr_err("fail process INDIRECT_ACK\n");
+		break;
+
+	case  HFI_MSG_IPEBPS_ASYNC_COMMAND_DIRECT_ACK:
+		rc = cam_icp_mgr_process_direct_ack_msg(msg_ptr);
+		if (rc)
+			pr_err("fail process DIRECT_ACK\n");
+		break;
+
+	case HFI_MSG_EVENT_NOTIFY:
+		ICP_DBG("received HFI_MSG_EVENT_NOTIFY\n");
+		break;
+
+	default:
+		pr_err("invalid msg : %u\n", msg_ptr[ICP_PACKET_TYPE]);
+		break;
+	}
+
+	mutex_unlock(&icp_hw_mgr.hw_mgr_mutex);
+
+	return rc;
+}
+
+int32_t cam_icp_hw_mgr_cb(uint32_t irq_status, void *data)
+{
+	int32_t rc = 0;
+	unsigned long flags;
+	struct cam_icp_hw_mgr *hw_mgr = data;
+	struct crm_workq_task *task;
+	struct hfi_msg_work_data *task_data;
+
+	spin_lock_irqsave(&hw_mgr->hw_mgr_lock, flags);
+	task = cam_req_mgr_workq_get_task(icp_hw_mgr.msg_work);
+	if (!task) {
+		pr_err("no empty task\n");
+		spin_unlock_irqrestore(&hw_mgr->hw_mgr_lock, flags);
+		return -ENOMEM;
+	}
+
+	task_data = (struct hfi_msg_work_data *)task->payload;
+	task_data->data = hw_mgr;
+	task_data->irq_status = irq_status;
+	task_data->type = ICP_WORKQ_TASK_MSG_TYPE;
+	task->process_cb = cam_icp_mgr_process_msg;
+	rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr,
+		CRM_TASK_PRIORITY_0);
+	spin_unlock_irqrestore(&hw_mgr->hw_mgr_lock, flags);
+
+	return rc;
+}
+
+static int cam_icp_free_hfi_mem(void)
+{
+	cam_smmu_dealloc_firmware(icp_hw_mgr.iommu_hdl);
+	cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.qtbl);
+	cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.cmd_q);
+	cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.msg_q);
+	cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.dbg_q);
+	cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.sec_heap);
+
+	return 0;
+}
+
+static int cam_icp_allocate_hfi_mem(void)
+{
+	int rc;
+	struct cam_mem_mgr_request_desc alloc;
+	struct cam_mem_mgr_memory_desc out;
+	dma_addr_t iova;
+	uint64_t kvaddr;
+	size_t len;
+
+	pr_err("Allocating FW for iommu handle: %x\n", icp_hw_mgr.iommu_hdl);
+	rc = cam_smmu_alloc_firmware(icp_hw_mgr.iommu_hdl,
+		&iova, &kvaddr, &len);
+	if (rc < 0) {
+		pr_err("Unable to allocate FW memory\n");
+		return -ENOMEM;
+	}
+
+	icp_hw_mgr.hfi_mem.fw_buf.len = len;
+	icp_hw_mgr.hfi_mem.fw_buf.kva = kvaddr;
+	icp_hw_mgr.hfi_mem.fw_buf.iova = iova;
+	icp_hw_mgr.hfi_mem.fw_buf.smmu_hdl = icp_hw_mgr.iommu_hdl;
+
+	ICP_DBG("kva = %llX\n", kvaddr);
+	ICP_DBG("IOVA = %llX\n", iova);
+	ICP_DBG("length = %zu\n", len);
+
+	memset(&alloc, 0, sizeof(alloc));
+	memset(&out, 0, sizeof(out));
+	alloc.size = SZ_1M;
+	alloc.align = 0;
+	alloc.region = CAM_MEM_MGR_REGION_SHARED;
+	alloc.smmu_hdl = icp_hw_mgr.iommu_hdl;
+	rc = cam_mem_mgr_request_mem(&alloc, &out);
+	if (rc < 0) {
+		pr_err("Unable to allocate qtbl memory\n");
+		goto qtbl_alloc_failed;
+	}
+	icp_hw_mgr.hfi_mem.qtbl = out;
+
+	ICP_DBG("kva = %llX\n", out.kva);
+	ICP_DBG("qtbl IOVA = %X\n", out.iova);
+	ICP_DBG("SMMU HDL = %X\n", out.smmu_hdl);
+	ICP_DBG("MEM HDL = %X\n", out.mem_handle);
+	ICP_DBG("length = %lld\n", out.len);
+	ICP_DBG("region = %d\n", out.region);
+
+	/* Allocate memory for cmd queue */
+	memset(&alloc, 0, sizeof(alloc));
+	memset(&out, 0, sizeof(out));
+	alloc.size = SZ_1M;
+	alloc.align = 0;
+	alloc.region = CAM_MEM_MGR_REGION_SHARED;
+	alloc.smmu_hdl = icp_hw_mgr.iommu_hdl;
+	rc = cam_mem_mgr_request_mem(&alloc, &out);
+	if (rc < 0) {
+		pr_err("Unable to allocate cmd q memory\n");
+		goto cmd_q_alloc_failed;
+	}
+	icp_hw_mgr.hfi_mem.cmd_q = out;
+
+	ICP_DBG("kva = %llX\n", out.kva);
+	ICP_DBG("cmd_q IOVA = %X\n", out.iova);
+	ICP_DBG("SMMU HDL = %X\n", out.smmu_hdl);
+	ICP_DBG("MEM HDL = %X\n", out.mem_handle);
+	ICP_DBG("length = %lld\n", out.len);
+	ICP_DBG("region = %d\n", out.region);
+
+	/* Allocate memory for msg queue */
+	memset(&alloc, 0, sizeof(alloc));
+	memset(&out, 0, sizeof(out));
+	alloc.size = SZ_1M;
+	alloc.align = 0;
+	alloc.region = CAM_MEM_MGR_REGION_SHARED;
+	alloc.smmu_hdl = icp_hw_mgr.iommu_hdl;
+	rc = cam_mem_mgr_request_mem(&alloc, &out);
+	if (rc < 0) {
+		pr_err("Unable to allocate msg q memory\n");
+		goto msg_q_alloc_failed;
+	}
+	icp_hw_mgr.hfi_mem.msg_q = out;
+
+	ICP_DBG("kva = %llX\n", out.kva);
+	ICP_DBG("msg_q IOVA = %X\n", out.iova);
+	ICP_DBG("SMMU HDL = %X\n", out.smmu_hdl);
+	ICP_DBG("MEM HDL = %X\n", out.mem_handle);
+	ICP_DBG("length = %lld\n", out.len);
+	ICP_DBG("region = %d\n", out.region);
+
+	/* Allocate memory for dbg queue */
+	memset(&alloc, 0, sizeof(alloc));
+	memset(&out, 0, sizeof(out));
+	alloc.size = SZ_1M;
+	alloc.align = 0;
+	alloc.region = CAM_MEM_MGR_REGION_SHARED;
+	alloc.smmu_hdl = icp_hw_mgr.iommu_hdl;
+	rc = cam_mem_mgr_request_mem(&alloc, &out);
+	if (rc < 0) {
+		pr_err("Unable to allocate dbg q memory\n");
+		goto dbg_q_alloc_failed;
+	}
+	icp_hw_mgr.hfi_mem.dbg_q = out;
+
+	ICP_DBG("kva = %llX\n", out.kva);
+	ICP_DBG("dbg_q IOVA = %X\n", out.iova);
+	ICP_DBG("SMMU HDL = %X\n",  out.smmu_hdl);
+	ICP_DBG("MEM HDL = %X\n", out.mem_handle);
+	ICP_DBG("length = %lld\n", out.len);
+	ICP_DBG("region = %d\n", out.region);
+
+	/* Allocate memory for sec heap queue */
+	memset(&alloc, 0, sizeof(alloc));
+	memset(&out, 0, sizeof(out));
+	alloc.size = SZ_1M;
+	alloc.align = 0;
+	alloc.region = CAM_MEM_MGR_REGION_SHARED;
+	alloc.smmu_hdl = icp_hw_mgr.iommu_hdl;
+	rc = cam_mem_mgr_request_mem(&alloc, &out);
+	if (rc < 0) {
+		pr_err("Unable to allocate sec heap q memory\n");
+		goto sec_heap_alloc_failed;
+	}
+	icp_hw_mgr.hfi_mem.sec_heap = out;
+
+	ICP_DBG("kva = %llX\n", out.kva);
+	ICP_DBG("sec_heap IOVA = %X\n", out.iova);
+	ICP_DBG("SMMU HDL = %X\n", out.smmu_hdl);
+	ICP_DBG("MEM HDL = %X\n", out.mem_handle);
+	ICP_DBG("length = %lld\n", out.len);
+	ICP_DBG("region = %d\n", out.region);
+
+	return rc;
+
+sec_heap_alloc_failed:
+	cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.dbg_q);
+dbg_q_alloc_failed:
+	cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.msg_q);
+msg_q_alloc_failed:
+	cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.cmd_q);
+cmd_q_alloc_failed:
+	cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.qtbl);
+qtbl_alloc_failed:
+	cam_smmu_dealloc_firmware(icp_hw_mgr.iommu_hdl);
+	pr_err("returned with error : %d\n", rc);
+
+	return rc;
+}
+
+static int cam_icp_mgr_get_free_ctx(struct cam_icp_hw_mgr *hw_mgr)
+{
+	int i = 0;
+	int num_ctx = CAM_ICP_CTX_MAX;
+
+	for (i = 0; i < num_ctx; i++) {
+		mutex_lock(&hw_mgr->ctx_data[i].ctx_mutex);
+		if (hw_mgr->ctx_data[i].in_use == 0) {
+			hw_mgr->ctx_data[i].in_use = 1;
+			mutex_unlock(&hw_mgr->ctx_data[i].ctx_mutex);
+			break;
+		}
+		mutex_unlock(&hw_mgr->ctx_data[i].ctx_mutex);
+	}
+
+	return i;
+}
+
+static int cam_icp_mgr_destroy_handle(
+		struct cam_icp_hw_ctx_data *ctx_data,
+		struct crm_workq_task *task)
+{
+	int rc = 0;
+	int timeout = 5000;
+	struct hfi_cmd_work_data *task_data;
+	struct hfi_cmd_ipebps_async destroy_cmd;
+	unsigned long rem_jiffies;
+
+	destroy_cmd.size =
+		sizeof(struct hfi_cmd_ipebps_async) +
+		sizeof(struct ipe_bps_destroy) -
+		sizeof(destroy_cmd.payload.direct);
+	destroy_cmd.pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_DIRECT;
+	if (ctx_data->icp_dev_acquire_info.dev_type == CAM_ICP_RES_TYPE_BPS)
+		destroy_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_BPS_DESTROY;
+	else
+		destroy_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_IPE_DESTROY;
+
+	reinit_completion(&ctx_data->wait_complete);
+	destroy_cmd.num_fw_handles = 1;
+	destroy_cmd.fw_handles[0] = ctx_data->fw_handle;
+	destroy_cmd.user_data1 = (uint64_t)ctx_data;
+	destroy_cmd.user_data2 = (uint64_t)0x0;
+	memcpy(destroy_cmd.payload.direct, &ctx_data->temp_payload,
+						sizeof(uint32_t));
+
+	task_data = (struct hfi_cmd_work_data *)task->payload;
+	task_data->data = (void *)&destroy_cmd;
+	task_data->request_id = 0;
+	task_data->type = ICP_WORKQ_TASK_CMD_TYPE;
+	task->process_cb = cam_icp_mgr_process_cmd;
+	cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, CRM_TASK_PRIORITY_0);
+	ICP_DBG("fw_handle = %x ctx_data = %pK\n",
+		ctx_data->fw_handle, ctx_data);
+	rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete,
+			msecs_to_jiffies((timeout)));
+	if (!rem_jiffies) {
+		rc = -ETIMEDOUT;
+		pr_err("timeout/err in iconfig command: %d\n", rc);
+	}
+
+	return rc;
+}
+
+static int cam_icp_mgr_release_ctx(struct cam_icp_hw_mgr *hw_mgr, int ctx_id)
+{
+	struct crm_workq_task *task;
+	int i = 0;
+
+	if (ctx_id >= CAM_ICP_CTX_MAX) {
+		pr_err("ctx_id is wrong: %d\n", ctx_id);
+		return -EINVAL;
+	}
+
+	mutex_lock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
+	if (!hw_mgr->ctx_data[ctx_id].in_use) {
+		pr_err("ctx is already in use: %d\n", ctx_id);
+		mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
+		return -EINVAL;
+	}
+	mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
+
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work);
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+	if (task)
+		cam_icp_mgr_destroy_handle(&hw_mgr->ctx_data[ctx_id], task);
+
+	mutex_lock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
+	hw_mgr->ctx_data[ctx_id].in_use = 0;
+	hw_mgr->ctx_data[ctx_id].fw_handle = 0;
+	hw_mgr->ctx_data[ctx_id].scratch_mem_size = 0;
+	mutex_lock(&hw_mgr->ctx_data[ctx_id].hfi_frame_process.lock);
+	for (i = 0; i < CAM_FRAME_CMD_MAX; i++)
+		clear_bit(i, hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap);
+	mutex_unlock(&hw_mgr->ctx_data[ctx_id].hfi_frame_process.lock);
+	mutex_destroy(&hw_mgr->ctx_data[ctx_id].hfi_frame_process.lock);
+	mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
+	kfree(hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap);
+
+	return 0;
+}
+
+static int cam_icp_mgr_get_ctx_from_fw_handle(struct cam_icp_hw_mgr *hw_mgr,
+							uint32_t fw_handle)
+{
+	int ctx_id;
+
+	for (ctx_id = 0; ctx_id < CAM_ICP_CTX_MAX; ctx_id++) {
+		mutex_lock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
+		if (hw_mgr->ctx_data[ctx_id].in_use) {
+			if (hw_mgr->ctx_data[ctx_id].fw_handle == fw_handle) {
+				mutex_unlock(
+					&hw_mgr->ctx_data[ctx_id].ctx_mutex);
+				return ctx_id;
+			}
+		}
+		mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
+	}
+	ICP_DBG("Invalid fw handle to get ctx\n");
+
+	return -EINVAL;
+}
+
+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_intf *ipe0_dev_intf = NULL;
+	struct cam_hw_intf *ipe1_dev_intf = NULL;
+	struct cam_hw_intf *bps_dev_intf = NULL;
+	int rc = 0;
+
+	a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0];
+	ipe0_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][0];
+	bps_dev_intf = hw_mgr->devices[CAM_ICP_DEV_BPS][0];
+
+	if ((!a5_dev_intf) || (!ipe0_dev_intf) || (!bps_dev_intf)) {
+		pr_err("dev intfs are wrong\n");
+		return rc;
+	}
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	rc = a5_dev_intf->hw_ops.deinit(a5_dev_intf->hw_priv, NULL, 0);
+	if (rc < 0)
+		pr_err("a5 dev de-init failed\n");
+
+	rc = bps_dev_intf->hw_ops.deinit(bps_dev_intf->hw_priv, NULL, 0);
+	if (rc < 0)
+		pr_err("bps dev de-init failed\n");
+
+	rc = ipe0_dev_intf->hw_ops.deinit(ipe0_dev_intf->hw_priv, NULL, 0);
+	if (rc < 0)
+		pr_err("ipe0 dev de-init failed\n");
+
+	ipe1_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][1];
+	if (ipe1_dev_intf) {
+		rc = ipe1_dev_intf->hw_ops.deinit(ipe1_dev_intf->hw_priv,
+						NULL, 0);
+		if (rc < 0)
+			pr_err("ipe1 dev de-init failed\n");
+	}
+
+	cam_icp_free_hfi_mem();
+	hw_mgr->fw_download = false;
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+
+	return 0;
+}
+
+static int cam_icp_mgr_download_fw(void *hw_mgr_priv, void *download_fw_args)
+{
+	struct cam_hw_intf *a5_dev_intf = NULL;
+	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_info *a5_dev = NULL;
+	struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv;
+	struct cam_icp_a5_set_irq_cb irq_cb;
+	struct cam_icp_a5_set_fw_buf_info fw_buf_info;
+	struct hfi_mem_info hfi_mem;
+	int rc = 0;
+
+	if (!hw_mgr) {
+		pr_err("hw_mgr is NULL\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	if (hw_mgr->fw_download) {
+		ICP_DBG("FW already downloaded\n");
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+		return rc;
+	}
+
+	/* Allocate memory for FW and shared memory */
+	rc = cam_icp_allocate_hfi_mem();
+	if (rc < 0) {
+		pr_err("hfi mem alloc failed\n");
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+		return rc;
+	}
+
+	a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0];
+	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];
+
+	if ((!a5_dev_intf) || (!ipe0_dev_intf) || (!bps_dev_intf)) {
+		pr_err("dev intfs are wrong\n");
+		goto dev_intf_fail;
+	}
+
+	a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv;
+
+	rc = a5_dev_intf->hw_ops.init(a5_dev_intf->hw_priv, NULL, 0);
+	if (rc < 0) {
+		pr_err("a5 dev init failed\n");
+		goto a5_dev_init_failed;
+	}
+	rc = bps_dev_intf->hw_ops.init(bps_dev_intf->hw_priv, NULL, 0);
+	if (rc < 0) {
+		pr_err("bps dev init failed\n");
+		goto bps_dev_init_failed;
+	}
+	rc = ipe0_dev_intf->hw_ops.init(ipe0_dev_intf->hw_priv, NULL, 0);
+	if (rc < 0) {
+		pr_err("ipe0 dev init failed\n");
+		goto ipe0_dev_init_failed;
+	}
+
+	if (ipe1_dev_intf) {
+		rc = ipe1_dev_intf->hw_ops.init(ipe1_dev_intf->hw_priv,
+						NULL, 0);
+		if (rc < 0) {
+			pr_err("ipe1 dev init failed\n");
+			goto ipe1_dev_init_failed;
+		}
+	}
+	/* Set IRQ callback */
+	irq_cb.icp_hw_mgr_cb = cam_icp_hw_mgr_cb;
+	irq_cb.data = hw_mgr_priv;
+	rc = a5_dev_intf->hw_ops.process_cmd(
+				a5_dev_intf->hw_priv,
+				CAM_ICP_A5_SET_IRQ_CB,
+				&irq_cb, sizeof(irq_cb));
+	if (rc < 0) {
+		pr_err("CAM_ICP_A5_SET_IRQ_CB failed\n");
+		rc = -EINVAL;
+		goto set_irq_failed;
+	}
+
+	fw_buf_info.kva = icp_hw_mgr.hfi_mem.fw_buf.kva;
+	fw_buf_info.iova = icp_hw_mgr.hfi_mem.fw_buf.iova;
+	fw_buf_info.len = icp_hw_mgr.hfi_mem.fw_buf.len;
+
+	rc = a5_dev_intf->hw_ops.process_cmd(
+			a5_dev_intf->hw_priv,
+			CAM_ICP_A5_CMD_SET_FW_BUF,
+			&fw_buf_info,
+			sizeof(fw_buf_info));
+	if (rc < 0) {
+		pr_err("CAM_ICP_A5_CMD_SET_FW_BUF failed\n");
+		goto set_irq_failed;
+	}
+
+	cam_hfi_enable_cpu(a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base);
+
+	rc = a5_dev_intf->hw_ops.process_cmd(
+			a5_dev_intf->hw_priv,
+			CAM_ICP_A5_CMD_FW_DOWNLOAD,
+			NULL, 0);
+	if (rc < 0) {
+		pr_err("FW download is failed\n");
+		goto set_irq_failed;
+	}
+
+	hfi_mem.qtbl.kva = icp_hw_mgr.hfi_mem.qtbl.kva;
+	hfi_mem.qtbl.iova = icp_hw_mgr.hfi_mem.qtbl.iova;
+	hfi_mem.qtbl.len = icp_hw_mgr.hfi_mem.qtbl.len;
+	ICP_DBG("kva = %llX\n", hfi_mem.qtbl.kva);
+	ICP_DBG("IOVA = %X\n", hfi_mem.qtbl.iova);
+	ICP_DBG("length = %lld\n", hfi_mem.qtbl.len);
+
+	hfi_mem.cmd_q.kva = icp_hw_mgr.hfi_mem.cmd_q.kva;
+	hfi_mem.cmd_q.iova = icp_hw_mgr.hfi_mem.cmd_q.iova;
+	hfi_mem.cmd_q.len = icp_hw_mgr.hfi_mem.cmd_q.len;
+	ICP_DBG("kva = %llX\n", hfi_mem.cmd_q.kva);
+	ICP_DBG("IOVA = %X\n", hfi_mem.cmd_q.iova);
+	ICP_DBG("length = %lld\n", hfi_mem.cmd_q.len);
+
+	hfi_mem.msg_q.kva = icp_hw_mgr.hfi_mem.msg_q.kva;
+	hfi_mem.msg_q.iova = icp_hw_mgr.hfi_mem.msg_q.iova;
+	hfi_mem.msg_q.len = icp_hw_mgr.hfi_mem.msg_q.len;
+	ICP_DBG("kva = %llX\n", hfi_mem.msg_q.kva);
+	ICP_DBG("IOVA = %X\n", hfi_mem.msg_q.iova);
+	ICP_DBG("length = %lld\n", hfi_mem.msg_q.len);
+
+	hfi_mem.dbg_q.kva = icp_hw_mgr.hfi_mem.dbg_q.kva;
+	hfi_mem.dbg_q.iova = icp_hw_mgr.hfi_mem.dbg_q.iova;
+	hfi_mem.dbg_q.len = icp_hw_mgr.hfi_mem.dbg_q.len;
+	ICP_DBG("kva = %llX\n", hfi_mem.dbg_q.kva);
+	ICP_DBG("IOVA = %X\n",  hfi_mem.dbg_q.iova);
+	ICP_DBG("length = %lld\n", hfi_mem.dbg_q.len);
+
+	hfi_mem.sec_heap.kva = icp_hw_mgr.hfi_mem.sec_heap.kva;
+	hfi_mem.sec_heap.iova = icp_hw_mgr.hfi_mem.sec_heap.iova;
+	hfi_mem.sec_heap.len = icp_hw_mgr.hfi_mem.sec_heap.len;
+
+	rc = cam_hfi_init(0, &hfi_mem,
+		a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base,
+		false);
+	if (rc < 0) {
+		pr_err("hfi_init is failed\n");
+		goto set_irq_failed;
+	}
+
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+
+	ICP_DBG("Sending HFI init command\n");
+	reinit_completion(&hw_mgr->a5_complete);
+
+	rc = a5_dev_intf->hw_ops.process_cmd(
+		a5_dev_intf->hw_priv,
+		CAM_ICP_A5_SEND_INIT,
+		NULL, 0);
+
+	ICP_DBG("Wait for INIT DONE Message\n");
+	wait_for_completion(&hw_mgr->a5_complete);
+
+	ICP_DBG("Done Waiting for INIT DONE Message\n");
+
+	rc = a5_dev_intf->hw_ops.process_cmd(
+		a5_dev_intf->hw_priv,
+		CAM_ICP_A5_CMD_POWER_COLLAPSE,
+		NULL, 0);
+
+	hw_mgr->fw_download = true;
+
+	rc = cam_icp_stop_cpas(hw_mgr);
+	if (rc) {
+		pr_err("cpas stop failed\n");
+		goto set_irq_failed;
+	}
+
+	hw_mgr->ctxt_cnt = 0;
+
+	return rc;
+
+set_irq_failed:
+	if (ipe1_dev_intf)
+		rc = ipe1_dev_intf->hw_ops.deinit(ipe1_dev_intf->hw_priv,
+			NULL, 0);
+ipe1_dev_init_failed:
+	rc = ipe0_dev_intf->hw_ops.deinit(ipe0_dev_intf->hw_priv, NULL, 0);
+ipe0_dev_init_failed:
+	rc = bps_dev_intf->hw_ops.deinit(bps_dev_intf->hw_priv, NULL, 0);
+bps_dev_init_failed:
+	rc = a5_dev_intf->hw_ops.deinit(a5_dev_intf->hw_priv, NULL, 0);
+a5_dev_init_failed:
+dev_intf_fail:
+	cam_icp_free_hfi_mem();
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+	return rc;
+}
+
+static int cam_icp_mgr_config_hw(void *hw_mgr_priv, void *config_hw_args)
+{
+	int rc = 0;
+	struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv;
+	struct cam_hw_config_args *config_args = config_hw_args;
+	uint32_t fw_handle;
+	int ctx_id = 0;
+	struct cam_icp_hw_ctx_data *ctx_data = NULL;
+	int32_t request_id = 0;
+	struct cam_hw_update_entry *hw_update_entries;
+	struct crm_workq_task *task;
+	struct hfi_cmd_work_data *task_data;
+	struct hfi_cmd_ipebps_async *hfi_cmd;
+
+	if (!hw_mgr || !config_args) {
+		pr_err("Invalid arguments %pK %pK\n",
+			hw_mgr, config_args);
+		return -EINVAL;
+	}
+
+	if (!config_args->num_hw_update_entries) {
+		pr_err("No hw update enteries are available\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	fw_handle = *(uint32_t *)config_args->ctxt_to_hw_map;
+	ctx_id = cam_icp_mgr_get_ctx_from_fw_handle(hw_mgr, fw_handle);
+	if (ctx_id < 0) {
+		pr_err("Fw handle to ctx mapping is failed\n");
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+		return -EINVAL;
+	}
+
+	ctx_data = &hw_mgr->ctx_data[ctx_id];
+	if (!ctx_data->in_use) {
+		pr_err("ctx is not in use\n");
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+		return -EINVAL;
+	}
+
+	request_id = *(uint32_t *)config_args->priv;
+	hw_update_entries = config_args->hw_update_entries;
+	ICP_DBG("req_id = %d\n", request_id);
+	ICP_DBG("fw_handle = %x req_id = %d %pK\n",
+		fw_handle, request_id, config_args->priv);
+	task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work);
+	if (!task) {
+		pr_err("no empty task\n");
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+		return -ENOMEM;
+	}
+
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+
+	task_data = (struct hfi_cmd_work_data *)task->payload;
+	if (!task_data) {
+		pr_err("task_data is NULL\n");
+		return -EINVAL;
+	}
+
+	task_data->data = (void *)hw_update_entries->addr;
+	hfi_cmd = (struct hfi_cmd_ipebps_async *)hw_update_entries->addr;
+	ICP_DBG("request from hfi_cmd :%llu, hfi_cmd: %pK\n",
+		hfi_cmd->user_data2, hfi_cmd);
+	task_data->request_id = request_id;
+	task_data->type = ICP_WORKQ_TASK_CMD_TYPE;
+	task->process_cb = cam_icp_mgr_process_cmd;
+	rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr,
+			CRM_TASK_PRIORITY_0);
+	return rc;
+}
+
+static int cam_icp_mgr_prepare_frame_process_cmd(
+			struct cam_icp_hw_ctx_data *ctx_data,
+			struct hfi_cmd_ipebps_async *hfi_cmd,
+			uint32_t request_id,
+			uint32_t fw_cmd_buf_iova_addr)
+{
+	hfi_cmd->size = sizeof(struct hfi_cmd_ipebps_async);
+	hfi_cmd->pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT;
+	if (ctx_data->icp_dev_acquire_info.dev_type == CAM_ICP_RES_TYPE_BPS)
+		hfi_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_BPS_FRAME_PROCESS;
+	else
+		hfi_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_IPE_FRAME_PROCESS;
+	hfi_cmd->num_fw_handles = 1;
+	hfi_cmd->fw_handles[0] = ctx_data->fw_handle;
+	hfi_cmd->payload.indirect = fw_cmd_buf_iova_addr;
+	hfi_cmd->user_data1 = (uint64_t)ctx_data;
+	hfi_cmd->user_data2 = request_id;
+
+	ICP_DBG("ctx_data : %pK, request_id :%d cmd_buf %x\n",
+		(void *)ctx_data->context_priv,
+		request_id, fw_cmd_buf_iova_addr);
+
+	return 0;
+}
+
+static int cam_icp_mgr_prepare_hw_update(void *hw_mgr_priv,
+				void *prepare_hw_update_args)
+{
+	int        rc = 0, i, j;
+	int        ctx_id = 0;
+	uint32_t   fw_handle;
+	int32_t    idx;
+	uint64_t   iova_addr, cpu_addr;
+	uint32_t   fw_cmd_buf_iova_addr;
+	uint32_t   temp;
+	uint32_t  *dst_cpu_addr;
+	uint32_t  *src_buf_iova_addr;
+	size_t     fw_cmd_buf_len;
+	size_t     dst_buf_len;
+	size_t     src_buf_size;
+	int32_t    sync_in_obj[CAM_ICP_IPE_IMAGE_MAX];
+	int32_t    merged_sync_in_obj;
+
+
+	struct cam_hw_prepare_update_args *prepare_args =
+		prepare_hw_update_args;
+	struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv;
+	struct cam_icp_hw_ctx_data *ctx_data = NULL;
+	struct cam_packet *packet = NULL;
+	struct cam_cmd_buf_desc *cmd_desc = NULL;
+	struct cam_buf_io_cfg *io_cfg_ptr = NULL;
+	struct cam_patch_desc *patch_desc = NULL;
+	struct hfi_cmd_ipebps_async *hfi_cmd = NULL;
+
+	if ((!prepare_args) || (!hw_mgr)) {
+		pr_err("Invalid args\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	fw_handle = *(uint32_t *)prepare_args->ctxt_to_hw_map;
+	ctx_id = cam_icp_mgr_get_ctx_from_fw_handle(hw_mgr, fw_handle);
+	if (ctx_id < 0) {
+		pr_err("Fw handle to ctx mapping is failed\n");
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+		return -EINVAL;
+	}
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+
+	ctx_data = &hw_mgr->ctx_data[ctx_id];
+	if (!ctx_data->in_use) {
+		pr_err("ctx is not in use\n");
+		return -EINVAL;
+	}
+
+	packet = prepare_args->packet;
+	if (!packet) {
+		pr_err("received packet is NULL\n");
+		return -EINVAL;
+	}
+
+	ICP_DBG("packet header : opcode = %x size = %x",
+			packet->header.op_code,
+			packet->header.size);
+
+	ICP_DBG(" req_id = %x flags = %x\n",
+			(uint32_t)packet->header.request_id,
+			packet->header.flags);
+
+	ICP_DBG("packet data : c_off = %x c_num = %x\n",
+			packet->cmd_buf_offset,
+			packet->num_cmd_buf);
+
+	ICP_DBG("io_off = %x io_num = %x p_off = %x p_num = %x %x %x\n",
+			packet->io_configs_offset,
+			packet->num_io_configs, packet->patch_offset,
+			packet->num_patches, packet->kmd_cmd_buf_index,
+			packet->kmd_cmd_buf_offset);
+
+	if (((packet->header.op_code & 0xff) !=
+		CAM_ICP_OPCODE_IPE_UPDATE) &&
+		((packet->header.op_code & 0xff) !=
+		CAM_ICP_OPCODE_BPS_UPDATE)) {
+		pr_err("Invalid Opcode in pkt: %d\n",
+			packet->header.op_code & 0xff);
+		return -EINVAL;
+	}
+
+	if ((packet->num_cmd_buf > 1) || (!packet->num_patches) ||
+					(!packet->num_io_configs)) {
+		pr_err("wrong number of cmd/patch info: %u %u\n",
+				packet->num_cmd_buf,
+				packet->num_patches);
+		return -EINVAL;
+	}
+
+	/* process command buffer descriptors */
+	cmd_desc = (struct cam_cmd_buf_desc *)
+			((uint32_t *) &packet->payload +
+				packet->cmd_buf_offset/4);
+	ICP_DBG("packet = %pK cmd_desc = %pK size = %lu\n",
+			(void *)packet, (void *)cmd_desc,
+			sizeof(struct cam_cmd_buf_desc));
+
+	rc = cam_mem_get_io_buf(cmd_desc->mem_handle,
+		hw_mgr->iommu_hdl, &iova_addr, &fw_cmd_buf_len);
+	if (rc < 0) {
+		pr_err("unable to get src buf info for cmd buf: %x\n",
+						hw_mgr->iommu_hdl);
+		return rc;
+	}
+	ICP_DBG("cmd_buf desc cpu and iova address: %pK %zu\n",
+				(void *)iova_addr, fw_cmd_buf_len);
+	fw_cmd_buf_iova_addr = iova_addr;
+	fw_cmd_buf_iova_addr = (fw_cmd_buf_iova_addr + cmd_desc->offset);
+
+	/* process patch descriptor */
+	patch_desc = (struct cam_patch_desc *)
+			((uint32_t *) &packet->payload +
+			packet->patch_offset/4);
+	ICP_DBG("packet = %pK patch_desc = %pK size = %lu\n",
+			(void *)packet, (void *)patch_desc,
+			sizeof(struct cam_patch_desc));
+
+	for (i = 0; i < packet->num_patches; i++) {
+		rc = cam_mem_get_io_buf(patch_desc[i].src_buf_hdl,
+			hw_mgr->iommu_hdl, &iova_addr, &src_buf_size);
+		if (rc < 0) {
+			pr_err("unable to get src buf address\n");
+			return rc;
+		}
+		src_buf_iova_addr = (uint32_t *)iova_addr;
+		temp = iova_addr;
+
+		rc = cam_mem_get_cpu_buf(patch_desc[i].dst_buf_hdl,
+			&cpu_addr, &dst_buf_len);
+		if (rc < 0) {
+			pr_err("unable to get dst buf address\n");
+			return rc;
+		}
+		dst_cpu_addr = (uint32_t *)cpu_addr;
+
+		ICP_DBG("i = %d patch info = %x %x %x %x\n", i,
+			patch_desc[i].dst_buf_hdl, patch_desc[i].dst_offset,
+			patch_desc[i].src_buf_hdl, patch_desc[i].src_offset);
+
+		dst_cpu_addr = (uint32_t *)((uint8_t *)dst_cpu_addr +
+			patch_desc[i].dst_offset);
+		temp += patch_desc[i].src_offset;
+
+		*dst_cpu_addr = temp;
+
+		ICP_DBG("patch is done for dst %pK with src %pK value %llx\n",
+			dst_cpu_addr, src_buf_iova_addr,
+			*((uint64_t *)dst_cpu_addr));
+	}
+
+	/* process io config out descriptors */
+	io_cfg_ptr = (struct cam_buf_io_cfg *) ((uint32_t *) &packet->payload +
+				packet->io_configs_offset/4);
+	ICP_DBG("packet = %pK io_cfg_ptr = %pK size = %lu\n",
+			(void *)packet, (void *)io_cfg_ptr,
+			sizeof(struct cam_buf_io_cfg));
+
+	prepare_args->num_out_map_entries = 0;
+	for (i = 0, j = 0; i < packet->num_io_configs; i++) {
+		if (io_cfg_ptr[i].direction == CAM_BUF_INPUT) {
+			ICP_DBG("direction is i : %d :%u\n",
+					i, io_cfg_ptr[i].direction);
+			ICP_DBG("fence is i : %d :%d\n",
+					i, io_cfg_ptr[i].fence);
+			continue;
+		}
+
+		prepare_args->out_map_entries[j].sync_id = io_cfg_ptr[i].fence;
+		prepare_args->out_map_entries[j++].resource_handle =
+							io_cfg_ptr[i].fence;
+		prepare_args->num_out_map_entries++;
+		ICP_DBG(" out fence = %x index = %d\n", io_cfg_ptr[i].fence, i);
+	}
+	ICP_DBG("out buf entries processing is done\n");
+
+	/* process io config in descriptors */
+	for (i = 0, j = 0; i < packet->num_io_configs; i++) {
+		if (io_cfg_ptr[i].direction == CAM_BUF_INPUT) {
+			sync_in_obj[j++] = io_cfg_ptr[i].fence;
+			ICP_DBG(" in fence = %x index = %d\n",
+					io_cfg_ptr[i].fence, i);
+		}
+	}
+
+	if (j == 1)
+		merged_sync_in_obj = sync_in_obj[j - 1];
+	else if (j > 1) {
+		rc = cam_sync_merge(&sync_in_obj[0], j, &merged_sync_in_obj);
+		if (rc < 0) {
+			pr_err("unable to create in merged object: %d\n",
+								rc);
+			return rc;
+		}
+	} else {
+		pr_err("no input fence provided %u\n", j);
+		return -EINVAL;
+	}
+
+	prepare_args->in_map_entries[0].sync_id = merged_sync_in_obj;
+	prepare_args->in_map_entries[0].resource_handle =
+			ctx_data->icp_dev_acquire_info.dev_type;
+	prepare_args->num_in_map_entries = 1;
+	ICP_DBG("out buf entries processing is done\n");
+
+	mutex_lock(&ctx_data->hfi_frame_process.lock);
+	idx = find_first_zero_bit(ctx_data->hfi_frame_process.bitmap,
+			ctx_data->hfi_frame_process.bits);
+	if (idx < 0 || idx >= CAM_FRAME_CMD_MAX) {
+		pr_err("request idx is wrong: %d\n", idx);
+		mutex_unlock(&ctx_data->hfi_frame_process.lock);
+		return -EINVAL;
+	}
+	set_bit(idx, ctx_data->hfi_frame_process.bitmap);
+	mutex_unlock(&ctx_data->hfi_frame_process.lock);
+
+	ctx_data->hfi_frame_process.request_id[idx] = packet->header.request_id;
+	ICP_DBG("slot[%d]: %d\n", idx,
+		ctx_data->hfi_frame_process.request_id[idx]);
+	ctx_data->hfi_frame_process.num_out_resources[idx] =
+				prepare_args->num_out_map_entries;
+	for (i = 0; i < prepare_args->num_out_map_entries; i++)
+		ctx_data->hfi_frame_process.out_resource[idx][i] =
+			prepare_args->out_map_entries[i].resource_handle;
+
+	hfi_cmd = (struct hfi_cmd_ipebps_async *)
+			&ctx_data->hfi_frame_process.hfi_frame_cmd[idx];
+
+	cam_icp_mgr_prepare_frame_process_cmd(
+			ctx_data, hfi_cmd, packet->header.request_id,
+			fw_cmd_buf_iova_addr);
+
+	prepare_args->num_hw_update_entries = 1;
+	prepare_args->hw_update_entries[0].addr = (uint64_t)hfi_cmd;
+
+	prepare_args->priv = &ctx_data->hfi_frame_process.request_id[idx];
+
+	ICP_DBG("slot : %d, hfi_cmd : %pK, request : %d\n",	idx,
+		(void *)hfi_cmd,
+		ctx_data->hfi_frame_process.request_id[idx]);
+
+	return rc;
+}
+
+static int cam_icp_mgr_release_hw(void *hw_mgr_priv, void *release_hw_args)
+{
+	int rc = 0;
+	int ctx_id = 0;
+	int i;
+	uint32_t fw_handle;
+	struct cam_hw_release_args *release_hw = release_hw_args;
+	struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv;
+	struct cam_icp_hw_ctx_data *ctx_data = NULL;
+
+	if (!release_hw || !hw_mgr) {
+		pr_err("Invalid args\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < CAM_ICP_CTX_MAX; i++) {
+		ctx_data = &hw_mgr->ctx_data[i];
+		ICP_DBG("i = %d in_use = %u fw_handle = %u\n", i,
+				ctx_data->in_use, ctx_data->fw_handle);
+	}
+
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	fw_handle = *(uint32_t *)release_hw->ctxt_to_hw_map;
+	ctx_id = cam_icp_mgr_get_ctx_from_fw_handle(hw_mgr, fw_handle);
+	if (ctx_id < 0) {
+		pr_err("Invalid ctx id\n");
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+		return -EINVAL;
+	}
+
+	rc = cam_icp_mgr_release_ctx(hw_mgr, ctx_id);
+	if (rc) {
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+		return -EINVAL;
+	}
+
+	--hw_mgr->ctxt_cnt;
+	if (!hw_mgr->ctxt_cnt) {
+		ICP_DBG("stop cpas for last context\n");
+		cam_icp_stop_cpas(hw_mgr);
+	}
+	ICP_DBG("context count : %u\n", hw_mgr->ctxt_cnt);
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+
+	ICP_DBG("fw handle %d\n", fw_handle);
+	return rc;
+}
+
+static int cam_icp_mgr_send_config_io(struct cam_icp_hw_ctx_data *ctx_data,
+			struct crm_workq_task *task, uint32_t io_buf_addr)
+{
+	int rc = 0;
+	struct hfi_cmd_work_data *task_data;
+	struct hfi_cmd_ipebps_async ioconfig_cmd;
+
+	ioconfig_cmd.size = sizeof(struct hfi_cmd_ipebps_async);
+	ioconfig_cmd.pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT;
+	if (ctx_data->icp_dev_acquire_info.dev_type == CAM_ICP_RES_TYPE_BPS)
+		ioconfig_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO;
+	else
+		ioconfig_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO;
+
+	reinit_completion(&ctx_data->wait_complete);
+	ICP_DBG("Sending HFI_CMD_IPEBPS_ASYNC_COMMAND: opcode :%u\n",
+						ioconfig_cmd.opcode);
+	ioconfig_cmd.num_fw_handles = 1;
+	ioconfig_cmd.fw_handles[0] = ctx_data->fw_handle;
+	ioconfig_cmd.payload.indirect = io_buf_addr;
+	ioconfig_cmd.user_data1 = (uint64_t)ctx_data;
+	ioconfig_cmd.user_data2 = (uint64_t)0x0;
+	task_data = (struct hfi_cmd_work_data *)task->payload;
+	task_data->data = (void *)&ioconfig_cmd;
+	task_data->request_id = 0;
+	task_data->type = ICP_WORKQ_TASK_CMD_TYPE;
+	task->process_cb = cam_icp_mgr_process_cmd;
+	cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, CRM_TASK_PRIORITY_0);
+	ICP_DBG("fw_hdl = %x ctx_data = %pK\n", ctx_data->fw_handle, ctx_data);
+	wait_for_completion(&ctx_data->wait_complete);
+
+	return rc;
+}
+
+static int cam_icp_mgr_create_handle(uint32_t dev_type,
+	struct cam_icp_hw_ctx_data *ctx_data,
+	struct crm_workq_task *task)
+{
+	struct hfi_cmd_create_handle create_handle;
+	struct hfi_cmd_work_data *task_data;
+	int rc = 0;
+
+	create_handle.size = sizeof(struct hfi_cmd_create_handle);
+	create_handle.pkt_type = HFI_CMD_IPEBPS_CREATE_HANDLE;
+	create_handle.handle_type = dev_type;
+	create_handle.user_data1 = (uint64_t)ctx_data;
+	ICP_DBG("%x %x %x %pK\n", create_handle.size,	create_handle.pkt_type,
+		create_handle.handle_type, (void *)create_handle.user_data1);
+	ICP_DBG("Sending HFI_CMD_IPEBPS_CREATE_HANDLE\n");
+
+	reinit_completion(&ctx_data->wait_complete);
+	task_data = (struct hfi_cmd_work_data *)task->payload;
+	task_data->data = (void *)&create_handle;
+	task_data->request_id = 0;
+	task_data->type = ICP_WORKQ_TASK_CMD_TYPE;
+	task->process_cb = cam_icp_mgr_process_cmd;
+	cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, CRM_TASK_PRIORITY_0);
+	wait_for_completion(&ctx_data->wait_complete);
+
+	return rc;
+}
+
+static int cam_icp_mgr_send_ping(struct cam_icp_hw_ctx_data *ctx_data,
+	struct crm_workq_task *task)
+{
+	struct hfi_cmd_ping_pkt ping_pkt;
+	struct hfi_cmd_work_data *task_data;
+	int rc = 0;
+
+	ping_pkt.size = sizeof(struct hfi_cmd_ping_pkt);
+	ping_pkt.pkt_type = HFI_CMD_SYS_PING;
+	ping_pkt.user_data = (uint64_t)ctx_data;
+	ICP_DBG("Sending HFI_CMD_SYS_PING\n");
+	ICP_DBG("%x %x %pK\n", ping_pkt.size,	ping_pkt.pkt_type,
+		(void *)ping_pkt.user_data);
+
+	init_completion(&ctx_data->wait_complete);
+	task_data = (struct hfi_cmd_work_data *)task->payload;
+	task_data->data = (void *)&ping_pkt;
+	task_data->request_id = 0;
+	task_data->type = ICP_WORKQ_TASK_CMD_TYPE;
+	task->process_cb = cam_icp_mgr_process_cmd;
+	cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, CRM_TASK_PRIORITY_0);
+	wait_for_completion(&ctx_data->wait_complete);
+
+	return rc;
+}
+
+static int cam_icp_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args)
+{
+	int rc = 0, i, bitmap_size = 0, tmp_size;
+	uint32_t ctx_id = 0;
+	uint64_t io_buf_addr;
+	size_t io_buf_size;
+	struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv;
+	struct cam_icp_hw_ctx_data *ctx_data = NULL;
+	struct cam_hw_acquire_args *args = acquire_hw_args;
+	struct cam_icp_acquire_dev_info icp_dev_acquire_info;
+	struct cam_icp_res_info *p_icp_out = NULL;
+	struct crm_workq_task *task;
+	uint8_t *tmp_acquire;
+
+	if ((!hw_mgr_priv) || (!acquire_hw_args)) {
+		pr_err("Invalid params: %pK %pK\n", hw_mgr_priv,
+			acquire_hw_args);
+		return -EINVAL;
+	}
+
+	if (args->num_acq > 1) {
+		pr_err("number of resources are wrong: %u\n", args->num_acq);
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&icp_dev_acquire_info,
+			(void __user *)args->acquire_info,
+			sizeof(icp_dev_acquire_info)))
+		return -EFAULT;
+
+	if (icp_dev_acquire_info.num_out_res > ICP_IPE_MAX_OUTPUT_SUPPORTED) {
+		pr_err("num of out resources exceeding : %u\n",
+			icp_dev_acquire_info.num_out_res);
+		return -EINVAL;
+	}
+
+	ICP_DBG("%x %x %x %x %x %x %x\n",
+		icp_dev_acquire_info.dev_type,
+		icp_dev_acquire_info.in_res.format,
+		icp_dev_acquire_info.in_res.width,
+		icp_dev_acquire_info.in_res.height,
+		icp_dev_acquire_info.in_res.fps,
+		icp_dev_acquire_info.num_out_res,
+		icp_dev_acquire_info.scratch_mem_size);
+
+	tmp_size = sizeof(icp_dev_acquire_info) +
+			icp_dev_acquire_info.num_out_res *
+			sizeof(struct cam_icp_res_info);
+
+	tmp_acquire = kzalloc(tmp_size, GFP_KERNEL);
+	if (!tmp_acquire)
+		return -EINVAL;
+
+	if (copy_from_user(tmp_acquire,
+			(void __user *)args->acquire_info,
+			tmp_size)) {
+		kfree(tmp_acquire);
+		return -EFAULT;
+	}
+
+	p_icp_out =
+		(struct cam_icp_res_info *)(tmp_acquire +
+		sizeof(icp_dev_acquire_info)-
+		sizeof(struct cam_icp_res_info));
+	ICP_DBG("out[0] %x %x %x %x\n",
+		p_icp_out[0].format,
+		p_icp_out[0].width,
+		p_icp_out[0].height,
+		p_icp_out[0].fps);
+
+	ICP_DBG("out[1] %x %x %x %x\n",
+		p_icp_out[1].format,
+		p_icp_out[1].width,
+		p_icp_out[1].height,
+		p_icp_out[1].fps);
+
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	ctx_id = cam_icp_mgr_get_free_ctx(hw_mgr);
+	if (ctx_id >= CAM_ICP_CTX_MAX) {
+		pr_err("No free ctx space in hw_mgr\n");
+		kfree(tmp_acquire);
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+		return -EFAULT;
+	}
+
+	/* Fill ctx with acquire info */
+	ctx_data = &hw_mgr->ctx_data[ctx_id];
+
+	if (!hw_mgr->ctxt_cnt++) {
+		ICP_DBG("starting cpas\n");
+		cam_icp_start_cpas(hw_mgr);
+	}
+	ICP_DBG("context count : %u\n", hw_mgr->ctxt_cnt);
+
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+
+	/* Fill ctx with acquire info */
+	mutex_lock(&ctx_data->ctx_mutex);
+	ctx_data->icp_dev_acquire_info = icp_dev_acquire_info;
+	for (i = 0; i < icp_dev_acquire_info.num_out_res; i++)
+		ctx_data->icp_out_acquire_info[i] = p_icp_out[i];
+	mutex_unlock(&ctx_data->ctx_mutex);
+
+	/* Get IOCONFIG command info */
+	if (ctx_data->icp_dev_acquire_info.secure_mode)
+		rc = cam_mem_get_io_buf(
+			icp_dev_acquire_info.io_config_cmd_handle,
+			hw_mgr->iommu_sec_hdl,
+			&io_buf_addr, &io_buf_size);
+	else
+		rc = cam_mem_get_io_buf(
+			icp_dev_acquire_info.io_config_cmd_handle,
+			hw_mgr->iommu_hdl,
+			&io_buf_addr, &io_buf_size);
+
+	ICP_DBG("io_config_cmd_handle : %d\n",
+		icp_dev_acquire_info.io_config_cmd_handle);
+	ICP_DBG("io_buf_addr : %pK\n", (void *)io_buf_addr);
+	ICP_DBG("io_buf_size : %zu\n", io_buf_size);
+	if (rc < 0) {
+		pr_err("unable to get src buf info from io desc\n");
+		goto cmd_cpu_buf_failed;
+	}
+
+	mutex_lock(&icp_hw_mgr.hw_mgr_mutex);
+	task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work);
+	if (!task) {
+		pr_err("no free task\n");
+		mutex_unlock(&icp_hw_mgr.hw_mgr_mutex);
+		goto get_create_task_failed;
+	}
+	mutex_unlock(&icp_hw_mgr.hw_mgr_mutex);
+
+	rc = cam_icp_mgr_send_ping(ctx_data, task);
+	if (rc) {
+		pr_err("ping ack not received\n");
+		goto create_handle_failed;
+	}
+	mutex_lock(&icp_hw_mgr.hw_mgr_mutex);
+	task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work);
+	if (!task) {
+		pr_err("no free task\n");
+		mutex_unlock(&icp_hw_mgr.hw_mgr_mutex);
+		goto get_create_task_failed;
+	}
+	mutex_unlock(&icp_hw_mgr.hw_mgr_mutex);
+
+	/* Send create fw handle command */
+	rc = cam_icp_mgr_create_handle(icp_dev_acquire_info.dev_type,
+			ctx_data, task);
+	if (rc) {
+		pr_err("create handle failed\n");
+		goto create_handle_failed;
+	}
+
+	/* Send IOCONFIG command */
+	mutex_lock(&icp_hw_mgr.hw_mgr_mutex);
+	task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work);
+	if (!task) {
+		pr_err("no empty task\n");
+		mutex_unlock(&icp_hw_mgr.hw_mgr_mutex);
+		goto get_ioconfig_task_failed;
+	}
+	mutex_unlock(&icp_hw_mgr.hw_mgr_mutex);
+
+	rc = cam_icp_mgr_send_config_io(ctx_data, task, io_buf_addr);
+	if (rc) {
+		pr_err("IO Config command failed\n");
+		goto ioconfig_failed;
+	}
+
+	mutex_lock(&ctx_data->ctx_mutex);
+	ctx_data->context_priv = args->context_data;
+	args->ctxt_to_hw_map = &ctx_data->fw_handle;
+
+	bitmap_size = BITS_TO_LONGS(CAM_FRAME_CMD_MAX) * sizeof(long);
+	ctx_data->hfi_frame_process.bitmap =
+			kzalloc(sizeof(bitmap_size), GFP_KERNEL);
+	ctx_data->hfi_frame_process.bits = bitmap_size * BITS_PER_BYTE;
+	mutex_init(&ctx_data->hfi_frame_process.lock);
+	mutex_unlock(&ctx_data->ctx_mutex);
+
+	hw_mgr->ctx_data[ctx_id].ctxt_event_cb = args->event_cb;
+
+	icp_dev_acquire_info.scratch_mem_size = ctx_data->scratch_mem_size;
+	if (copy_to_user((void __user *)args->acquire_info,
+				&icp_dev_acquire_info,
+			sizeof(icp_dev_acquire_info)))
+		goto copy_to_user_failed;
+
+	ICP_DBG("scratch mem size = %x fw_handle = %x\n",
+			(unsigned int)icp_dev_acquire_info.scratch_mem_size,
+			(unsigned int)ctx_data->fw_handle);
+	kfree(tmp_acquire);
+	return 0;
+
+copy_to_user_failed:
+ioconfig_failed:
+get_ioconfig_task_failed:
+	mutex_lock(&icp_hw_mgr.hw_mgr_mutex);
+	task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work);
+	mutex_unlock(&icp_hw_mgr.hw_mgr_mutex);
+	if (task)
+		cam_icp_mgr_destroy_handle(ctx_data, task);
+create_handle_failed:
+get_create_task_failed:
+cmd_cpu_buf_failed:
+	--hw_mgr->ctxt_cnt;
+	if (!hw_mgr->ctxt_cnt)
+		cam_icp_stop_cpas(hw_mgr);
+	cam_icp_mgr_release_ctx(hw_mgr, ctx_id);
+	kfree(tmp_acquire);
+	return rc;
+}
+
+static int cam_icp_mgr_get_hw_caps(void *hw_mgr_priv, void *hw_caps_args)
+{
+	int rc = 0;
+	struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv;
+	struct cam_query_cap_cmd *query_cap = hw_caps_args;
+
+	if ((!hw_mgr_priv) || (!hw_caps_args)) {
+		pr_err("Invalid params: %pK %pK\n", hw_mgr_priv, hw_caps_args);
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&icp_hw_mgr.icp_caps,
+			(void __user *)query_cap->caps_handle,
+			sizeof(struct cam_icp_query_cap_cmd))) {
+		pr_err("copy_from_user failed\n");
+		return -EFAULT;
+	}
+
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	rc = hfi_get_hw_caps(&icp_hw_mgr.icp_caps);
+	if (rc < 0) {
+		pr_err("Unable to get caps from HFI: %d\n", rc);
+		goto hfi_get_caps_fail;
+	}
+
+	icp_hw_mgr.icp_caps.dev_iommu_handle.non_secure = hw_mgr->iommu_hdl;
+	icp_hw_mgr.icp_caps.dev_iommu_handle.secure = hw_mgr->iommu_sec_hdl;
+
+	if (copy_to_user((void __user *)query_cap->caps_handle,
+			&icp_hw_mgr.icp_caps,
+			sizeof(struct cam_icp_query_cap_cmd))) {
+		pr_err("copy_to_user failed\n");
+		rc = -EFAULT;
+		goto hfi_get_caps_fail;
+	}
+
+hfi_get_caps_fail:
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+	return rc;
+}
+
+int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl)
+{
+	int count, i, rc = 0;
+	uint32_t num_dev;
+	uint32_t num_ipe_dev;
+	const char *name = NULL;
+	struct device_node *child_node = NULL;
+	struct platform_device *child_pdev = NULL;
+	struct cam_hw_intf *child_dev_intf = NULL;
+	struct cam_hw_mgr_intf *hw_mgr_intf;
+
+
+	hw_mgr_intf = (struct cam_hw_mgr_intf *)hw_mgr_hdl;
+	if (!of_node || !hw_mgr_intf) {
+		pr_err("Invalid args of_node %pK hw_mgr %pK\n",
+			of_node, hw_mgr_intf);
+		return -EINVAL;
+	}
+
+	hw_mgr_intf->hw_mgr_priv = &icp_hw_mgr;
+	hw_mgr_intf->hw_get_caps = cam_icp_mgr_get_hw_caps;
+	hw_mgr_intf->hw_acquire = cam_icp_mgr_acquire_hw;
+	hw_mgr_intf->hw_release = cam_icp_mgr_release_hw;
+	hw_mgr_intf->hw_prepare_update = cam_icp_mgr_prepare_hw_update;
+	hw_mgr_intf->hw_config = cam_icp_mgr_config_hw;
+	hw_mgr_intf->download_fw = cam_icp_mgr_download_fw;
+	hw_mgr_intf->hw_close = cam_icp_mgr_hw_close;
+
+	mutex_init(&icp_hw_mgr.hw_mgr_mutex);
+	spin_lock_init(&icp_hw_mgr.hw_mgr_lock);
+
+	for (i = 0; i < CAM_ICP_CTX_MAX; i++)
+		mutex_init(&icp_hw_mgr.ctx_data[i].ctx_mutex);
+
+	/* Get number of device objects */
+	count = of_property_count_strings(of_node, "compat-hw-name");
+	if (!count) {
+		pr_err("no compat hw found in dev tree, count = %d\n", count);
+		rc = -EINVAL;
+		goto num_dev_failed;
+	}
+
+	/* Get number of a5 device nodes and a5 mem allocation */
+	rc = of_property_read_u32(of_node, "num-a5", &num_dev);
+	if (rc < 0) {
+		pr_err("getting num of a5 failed\n");
+		goto num_dev_failed;
+	}
+
+	icp_hw_mgr.devices[CAM_ICP_DEV_A5] = kzalloc(
+		sizeof(struct cam_hw_intf *) * num_dev, GFP_KERNEL);
+	if (!icp_hw_mgr.devices[CAM_ICP_DEV_A5]) {
+		rc = -ENOMEM;
+		goto num_dev_failed;
+	}
+
+	/* Get number of ipe device nodes and ipe mem allocation */
+	rc = of_property_read_u32(of_node, "num-ipe", &num_ipe_dev);
+	if (rc < 0) {
+		pr_err("getting number of ipe dev nodes failed\n");
+		goto num_ipe_failed;
+	}
+
+	icp_hw_mgr.devices[CAM_ICP_DEV_IPE] = kzalloc(
+		sizeof(struct cam_hw_intf *) * num_ipe_dev, GFP_KERNEL);
+	if (!icp_hw_mgr.devices[CAM_ICP_DEV_IPE]) {
+		rc = -ENOMEM;
+		goto num_ipe_failed;
+	}
+
+	/* Get number of bps device nodes and bps mem allocation */
+	rc = of_property_read_u32(of_node, "num-bps", &num_dev);
+	if (rc < 0) {
+		pr_err("read num bps devices failed\n");
+		goto num_bps_failed;
+	}
+	icp_hw_mgr.devices[CAM_ICP_DEV_BPS] = kzalloc(
+		sizeof(struct cam_hw_intf *) * num_dev, GFP_KERNEL);
+	if (!icp_hw_mgr.devices[CAM_ICP_DEV_BPS]) {
+		rc = -ENOMEM;
+		goto num_bps_failed;
+	}
+
+	for (i = 0; i < count; i++) {
+		rc = of_property_read_string_index(of_node, "compat-hw-name",
+								i, &name);
+		if (rc < 0) {
+			pr_err("getting dev object name failed\n");
+			goto compat_hw_name_failed;
+		}
+
+		child_node = of_find_node_by_name(NULL, name);
+		if (!child_node) {
+			pr_err("error! Cannot find node in dtsi %s\n", name);
+			rc = -ENODEV;
+			goto compat_hw_name_failed;
+		}
+
+		child_pdev = of_find_device_by_node(child_node);
+		if (!child_pdev) {
+			pr_err("failed to find device on bus %s\n",
+				child_node->name);
+			rc = -ENODEV;
+			of_node_put(child_node);
+			goto compat_hw_name_failed;
+		}
+
+		child_dev_intf = (struct cam_hw_intf *)platform_get_drvdata(
+								child_pdev);
+		if (!child_dev_intf) {
+			pr_err("no child device\n");
+			of_node_put(child_node);
+			goto compat_hw_name_failed;
+		}
+		ICP_DBG("child_intf %pK\n", child_dev_intf);
+		ICP_DBG("child type %d index %d\n",	child_dev_intf->hw_type,
+				child_dev_intf->hw_idx);
+
+		icp_hw_mgr.devices[child_dev_intf->hw_type]
+			[child_dev_intf->hw_idx] = child_dev_intf;
+
+		of_node_put(child_node);
+	}
+
+	rc = cam_smmu_get_handle("icp", &icp_hw_mgr.iommu_hdl);
+	if (rc < 0) {
+		pr_err("icp get iommu handle failed\n");
+		goto compat_hw_name_failed;
+	}
+
+	pr_err("mmu handle :%d\n", icp_hw_mgr.iommu_hdl);
+	rc = cam_smmu_ops(icp_hw_mgr.iommu_hdl, CAM_SMMU_ATTACH);
+	if (rc < 0) {
+		pr_err("icp attach failed: %d\n", rc);
+		goto icp_attach_failed;
+	}
+
+	rc = cam_req_mgr_workq_create("icp_command_queue", ICP_WORKQ_NUM_TASK,
+					&icp_hw_mgr.cmd_work);
+	if (rc < 0) {
+		pr_err("unable to create a worker\n");
+		goto cmd_work_failed;
+	}
+
+	rc = cam_req_mgr_workq_create("icp_message_queue", ICP_WORKQ_NUM_TASK,
+					&icp_hw_mgr.msg_work);
+	if (rc < 0) {
+		pr_err("unable to create a worker\n");
+		goto msg_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);
+	if (!icp_hw_mgr.cmd_work_data)
+		goto cmd_work_data_failed;
+
+	icp_hw_mgr.msg_work_data = (struct hfi_msg_work_data *)
+		kzalloc(sizeof(struct hfi_msg_work_data) * ICP_WORKQ_NUM_TASK,
+		GFP_KERNEL);
+	if (!icp_hw_mgr.msg_work_data)
+		goto msg_work_data_failed;
+
+
+	for (i = 0; i < ICP_WORKQ_NUM_TASK; i++)
+		icp_hw_mgr.msg_work->task.pool[i].payload =
+				&icp_hw_mgr.msg_work_data[i];
+
+	for (i = 0; i < ICP_WORKQ_NUM_TASK; i++)
+		icp_hw_mgr.cmd_work->task.pool[i].payload =
+				&icp_hw_mgr.cmd_work_data[i];
+
+	init_completion(&icp_hw_mgr.a5_complete);
+
+	pr_err("Exit\n");
+	return rc;
+
+msg_work_data_failed:
+	kfree(icp_hw_mgr.cmd_work_data);
+cmd_work_data_failed:
+	cam_req_mgr_workq_destroy(&icp_hw_mgr.msg_work);
+msg_work_failed:
+	cam_req_mgr_workq_destroy(&icp_hw_mgr.cmd_work);
+cmd_work_failed:
+	cam_smmu_ops(icp_hw_mgr.iommu_hdl, CAM_SMMU_DETACH);
+icp_attach_failed:
+	icp_hw_mgr.iommu_hdl = 0;
+compat_hw_name_failed:
+	kfree(icp_hw_mgr.devices[CAM_ICP_DEV_BPS]);
+num_bps_failed:
+	kfree(icp_hw_mgr.devices[CAM_ICP_DEV_IPE]);
+num_ipe_failed:
+	kfree(icp_hw_mgr.devices[CAM_ICP_DEV_A5]);
+num_dev_failed:
+	mutex_destroy(&icp_hw_mgr.hw_mgr_mutex);
+	for (i = 0; i < CAM_ICP_CTX_MAX; i++)
+		mutex_destroy(&icp_hw_mgr.ctx_data[i].ctx_mutex);
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
new file mode 100644
index 0000000..e5ffa7a
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
@@ -0,0 +1,181 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CAM_ICP_HW_MGR_H
+#define CAM_ICP_HW_MGR_H
+
+#include <linux/types.h>
+#include <linux/completion.h>
+#include <media/cam_icp.h>
+#include "cam_icp_hw_intf.h"
+#include "cam_hw_mgr_intf.h"
+#include "cam_hw_intf.h"
+#include "cam_a5_hw_intf.h"
+#include "hfi_session_defs.h"
+#include "cam_req_mgr_workq.h"
+#include "cam_mem_mgr.h"
+
+#define CAM_ICP_ROLE_PARENT     1
+#define CAM_ICP_ROLE_CHILD      2
+
+#define CAM_FRAME_CMD_MAX       20
+
+#define CAM_MAX_OUT_RES         6
+
+#define ICP_WORKQ_NUM_TASK      30
+#define ICP_WORKQ_TASK_CMD_TYPE 1
+#define ICP_WORKQ_TASK_MSG_TYPE 2
+
+#define ICP_PACKET_SIZE         0
+#define ICP_PACKET_TYPE         1
+#define ICP_PACKET_IPCODE       2
+#define ICP_IPE_MAX_OUTPUT_SUPPORTED 6
+
+/**
+ * struct icp_hfi_mem_info
+ * @qtbl: Memory info of queue table
+ * @cmd_q: Memory info of command queue
+ * @msg_q: Memory info of message queue
+ * @dbg_q: Memory info of debug queue
+ * @sec_heap: Memory info of secondary heap
+ * @fw_buf: Memory info of firmware
+ */
+struct icp_hfi_mem_info {
+	struct cam_mem_mgr_memory_desc qtbl;
+	struct cam_mem_mgr_memory_desc cmd_q;
+	struct cam_mem_mgr_memory_desc msg_q;
+	struct cam_mem_mgr_memory_desc dbg_q;
+	struct cam_mem_mgr_memory_desc sec_heap;
+	struct cam_mem_mgr_memory_desc fw_buf;
+};
+
+/**
+ * struct hfi_cmd_work_data
+ * @type: Task type
+ * @data: Pointer to command data
+ * @request_id: Request id
+ */
+struct hfi_cmd_work_data {
+	uint32_t type;
+	void *data;
+	int32_t request_id;
+};
+
+/**
+ * struct hfi_msg_work_data
+ * @type: Task type
+ * @data: Pointer to message data
+ * @irq_status: IRQ status
+ */
+struct hfi_msg_work_data {
+	uint32_t type;
+	void *data;
+	uint32_t irq_status;
+};
+
+/**
+ * struct hfi_frame_process_info
+ * @hfi_frame_cmd: Frame process command info
+ * @bitmap: Bitmap for hfi_frame_cmd
+ * @bits: Used in hfi_frame_cmd bitmap
+ * @lock: Lock for hfi_frame_cmd
+ * @request_id: Request id list
+ * @num_out_resources: Number of out syncs
+ * @out_resource: Out sync info
+ */
+struct hfi_frame_process_info {
+	struct hfi_cmd_ipebps_async hfi_frame_cmd[CAM_FRAME_CMD_MAX];
+	void *bitmap;
+	size_t bits;
+	struct mutex lock;
+	int32_t request_id[CAM_FRAME_CMD_MAX];
+	uint32_t num_out_resources[CAM_FRAME_CMD_MAX];
+	uint32_t out_resource[CAM_FRAME_CMD_MAX][CAM_MAX_OUT_RES];
+};
+
+/**
+ * struct cam_icp_hw_ctx_data
+ * @context_priv: Context private data
+ * @ctx_mutex: Mutex for context
+ * @fw_handle: Firmware handle
+ * @scratch_mem_size: Scratch memory size
+ * @acquire_dev_cmd: Acquire command
+ * @icp_dev_acquire_info: Acquire device info
+ * @icp_out_acquire_info: Acquire out resource info
+ * @ctxt_event_cb: Context callback function
+ * @in_use: Flag for context usage
+ * @role: Role of a context in case of chaining
+ * @chain_ctx: Peer context
+ * @hfi_frame_process: Frame process command
+ * @wait_complete: Completion info
+ * @temp_payload: Payload for destroy handle data
+ */
+struct cam_icp_hw_ctx_data {
+	void *context_priv;
+	struct mutex ctx_mutex;
+	uint32_t fw_handle;
+	uint32_t scratch_mem_size;
+	struct cam_acquire_dev_cmd acquire_dev_cmd;
+	struct cam_icp_acquire_dev_info icp_dev_acquire_info;
+	struct cam_icp_res_info icp_out_acquire_info[CAM_MAX_OUT_RES];
+	cam_hw_event_cb_func ctxt_event_cb;
+	uint32_t in_use;
+	uint32_t role;
+	struct cam_icp_hw_ctx_data *chain_ctx;
+	struct hfi_frame_process_info hfi_frame_process;
+	struct completion wait_complete;
+	struct ipe_bps_destroy temp_payload;
+};
+
+/**
+ * struct cam_icp_hw_mgr
+ * @hw_mgr_mutex: Mutex for ICP hardware manager
+ * @hw_mgr_lock: Spinlock for ICP hardware manager
+ * @devices: Devices of ICP hardware manager
+ * @ctx_data: Context data
+ * @icp_caps: ICP capabilities
+ * @fw_download: Firmware download state
+ * @iommu_hdl: Non secure IOMMU handle
+ * @iommu_sec_hdl: Secure IOMMU handle
+ * @hfi_mem: Memory for hfi
+ * @cmd_work: Work queue for hfi commands
+ * @msg_work: Work queue for hfi messages
+ * @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
+ * @ctxt_cnt: Active context count
+ */
+struct cam_icp_hw_mgr {
+	struct mutex hw_mgr_mutex;
+	spinlock_t hw_mgr_lock;
+
+	struct cam_hw_intf **devices[CAM_ICP_DEV_MAX];
+	struct cam_icp_hw_ctx_data ctx_data[CAM_ICP_CTX_MAX];
+	struct cam_icp_query_cap_cmd icp_caps;
+
+	bool fw_download;
+	int32_t iommu_hdl;
+	int32_t iommu_sec_hdl;
+	struct icp_hfi_mem_info hfi_mem;
+	struct cam_req_mgr_core_workq *cmd_work;
+	struct cam_req_mgr_core_workq *msg_work;
+	uint32_t msg_buf[256];
+	uint32_t dbg_buf[256];
+	struct completion a5_complete;
+	struct hfi_cmd_work_data *cmd_work_data;
+	struct hfi_msg_work_data *msg_work_data;
+	uint32_t ctxt_cnt;
+};
+
+#endif /* CAM_ICP_HW_MGR_H */
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h
new file mode 100644
index 0000000..2686877
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h
@@ -0,0 +1,79 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CAM_A5_HW_INTF_H
+#define CAM_A5_HW_INTF_H
+
+#include <linux/timer.h>
+#include <uapi/media/cam_defs.h>
+#include <media/cam_icp.h>
+#include "cam_hw_mgr_intf.h"
+#include "cam_icp_hw_intf.h"
+
+enum cam_icp_a5_cmd_type {
+	CAM_ICP_A5_CMD_FW_DOWNLOAD,
+	CAM_ICP_A5_CMD_POWER_COLLAPSE,
+	CAM_ICP_A5_CMD_POWER_RESUME,
+	CAM_ICP_A5_CMD_SET_FW_BUF,
+	CAM_ICP_A5_CMD_ACQUIRE,
+	CAM_ICP_A5_SET_IRQ_CB,
+	CAM_ICP_A5_TEST_IRQ,
+	CAM_ICP_A5_SEND_INIT,
+	CAM_ICP_A5_CMD_VOTE_CPAS,
+	CAM_ICP_A5_CMD_CPAS_START,
+	CAM_ICP_A5_CMD_CPAS_STOP,
+	CAM_ICP_A5_CMD_MAX,
+};
+
+struct cam_icp_a5_set_fw_buf_info {
+	uint32_t iova;
+	uint64_t kva;
+	uint64_t len;
+};
+
+/**
+ * struct cam_icp_a5_query_cap - ICP query device capability payload
+ * @fw_version: firmware version info
+ * @api_version: api version info
+ * @num_ipe: number of ipes
+ * @num_bps: number of bps
+ * @num_dev: number of device capabilities in dev_caps
+ * @reserved: reserved
+ * @dev_ver: returned device capability array
+ * @CAM_QUERY_CAP IOCTL
+ */
+struct cam_icp_a5_query_cap {
+	struct cam_icp_ver fw_version;
+	struct cam_icp_ver api_version;
+	uint32_t num_ipe;
+	uint32_t num_bps;
+	uint32_t num_dev;
+	uint32_t reserved;
+	struct cam_icp_dev_ver dev_ver[CAM_ICP_DEV_TYPE_MAX];
+};
+
+struct cam_icp_a5_acquire_dev {
+	uint32_t ctx_id;
+	struct cam_icp_acquire_dev_info icp_acquire_info;
+	struct cam_icp_res_info icp_out_acquire_info[2];
+	uint32_t fw_handle;
+};
+
+struct cam_icp_a5_set_irq_cb {
+	int32_t (*icp_hw_mgr_cb)(uint32_t irq_status, void *data);
+	void *data;
+};
+
+struct cam_icp_a5_test_irq {
+	uint32_t test_irq;
+};
+#endif /* CAM_A5_HW_INTF_H */
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h
new file mode 100644
index 0000000..4427a30
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h
@@ -0,0 +1,32 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CAM_BPS_HW_INTF_H
+#define CAM_BPS_HW_INTF_H
+
+#include <uapi/media/cam_defs.h>
+#include <media/cam_icp.h>
+#include "cam_hw_mgr_intf.h"
+#include "cam_icp_hw_intf.h"
+
+enum cam_icp_bps_cmd_type {
+	CAM_ICP_BPS_CMD_FW_DOWNLOAD,
+	CAM_ICP_BPS_CMD_POWER_COLLAPSE,
+	CAM_ICP_BPS_CMD_POWER_RESUME,
+	CAM_ICP_BPS_CMD_SET_FW_BUF,
+	CAM_ICP_BPS_CMD_VOTE_CPAS,
+	CAM_ICP_BPS_CMD_CPAS_START,
+	CAM_ICP_BPS_CMD_CPAS_STOP,
+	CAM_ICP_BPS_CMD_MAX,
+};
+
+#endif /* CAM_BPS_HW_INTF_H */
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h
new file mode 100644
index 0000000..9300ea8
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h
@@ -0,0 +1,27 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CAM_ICP_HW_INTF_H
+#define CAM_ICP_HW_INTF_H
+
+#define CAM_ICP_CTX_MAX                 8
+
+#define CAM_ICP_CMD_BUF_MAX_SIZE     128
+#define CAM_ICP_MSG_BUF_MAX_SIZE     CAM_ICP_CMD_BUF_MAX_SIZE
+
+enum cam_a5_hw_type {
+	CAM_ICP_DEV_A5,
+	CAM_ICP_DEV_IPE,
+	CAM_ICP_DEV_BPS,
+	CAM_ICP_DEV_MAX,
+};
+#endif
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h
new file mode 100644
index 0000000..0db66c0
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h
@@ -0,0 +1,32 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CAM_IPE_HW_INTF_H
+#define CAM_IPE_HW_INTF_H
+
+#include <uapi/media/cam_defs.h>
+#include <media/cam_icp.h>
+#include "cam_hw_mgr_intf.h"
+#include "cam_icp_hw_intf.h"
+
+enum cam_icp_ipe_cmd_type {
+	CAM_ICP_IPE_CMD_FW_DOWNLOAD,
+	CAM_ICP_IPE_CMD_POWER_COLLAPSE,
+	CAM_ICP_IPE_CMD_POWER_RESUME,
+	CAM_ICP_IPE_CMD_SET_FW_BUF,
+	CAM_ICP_IPE_CMD_VOTE_CPAS,
+	CAM_ICP_IPE_CMD_CPAS_START,
+	CAM_ICP_IPE_CMD_CPAS_STOP,
+	CAM_ICP_IPE_CMD_MAX,
+};
+
+#endif /* CAM_IPE_HW_INTF_H */
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/include/cam_icp_hw_mgr_intf.h b/drivers/media/platform/msm/camera/icp/icp_hw/include/cam_icp_hw_mgr_intf.h
new file mode 100644
index 0000000..2f100ca
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/include/cam_icp_hw_mgr_intf.h
@@ -0,0 +1,40 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CAM_ICP_HW_MGR_INTF_H
+#define CAM_ICP_HW_MGR_INTF_H
+
+#include <uapi/media/cam_icp.h>
+#include <uapi/media/cam_defs.h>
+#include <linux/of.h>
+#include "cam_cpas_api.h"
+
+#define ICP_TURBO_VOTE           640000000
+
+int cam_icp_hw_mgr_init(struct device_node *of_node,
+	uint64_t *hw_mgr_hdl);
+
+/**
+ * struct cam_icp_cpas_vote
+ * @ahb_vote: AHB vote info
+ * @axi_vote: AXI vote info
+ * @ahb_vote_valid: Flag for ahb vote data
+ * @axi_vote_valid: flag for axi vote data
+ */
+struct cam_icp_cpas_vote {
+	struct cam_ahb_vote ahb_vote;
+	struct cam_axi_vote axi_vote;
+	uint32_t ahb_vote_valid;
+	uint32_t axi_vote_valid;
+};
+
+#endif /* CAM_ICP_HW_MGR_INTF_H */
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/Makefile b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/Makefile
new file mode 100644
index 0000000..8af20ae
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/Makefile
@@ -0,0 +1,11 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_core
+ccflags-y += -Idrivers/media/platform/msm/camera/icp
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/include
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/include
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/icp_hw/ipe_hw
+ccflags-y += -Idrivers/media/platform/msm/camera/icp/fw_inc
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+
+obj-$(CONFIG_SPECTRA_CAMERA) += ipe_dev.o ipe_core.o ipe_soc.o
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_core.c b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_core.c
new file mode 100644
index 0000000..15cb943
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_core.c
@@ -0,0 +1,183 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "IPE-CORE %s:%d " fmt, __func__, __LINE__
+
+#include <linux/of.h>
+#include <linux/debugfs.h>
+#include <linux/videodev2.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include "cam_io_util.h"
+#include "cam_hw.h"
+#include "cam_hw_intf.h"
+#include "ipe_core.h"
+#include "ipe_soc.h"
+#include "cam_soc_util.h"
+#include "cam_io_util.h"
+#include "cam_ipe_hw_intf.h"
+#include "cam_icp_hw_mgr_intf.h"
+#include "cam_cpas_api.h"
+
+static int cam_ipe_caps_vote(struct cam_ipe_device_core_info *core_info,
+	struct cam_icp_cpas_vote *cpas_vote)
+{
+	int rc = 0;
+
+	if (cpas_vote->ahb_vote_valid)
+		rc = cam_cpas_update_ahb_vote(core_info->cpas_handle,
+			&cpas_vote->ahb_vote);
+	if (cpas_vote->axi_vote_valid)
+		rc = cam_cpas_update_axi_vote(core_info->cpas_handle,
+			&cpas_vote->axi_vote);
+
+	if (rc < 0)
+		pr_err("cpas vote is failed: %d\n", rc);
+
+	return rc;
+}
+
+int cam_ipe_init_hw(void *device_priv,
+	void *init_hw_args, uint32_t arg_size)
+{
+	struct cam_hw_info *ipe_dev = device_priv;
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_ipe_device_core_info *core_info = NULL;
+	struct cam_icp_cpas_vote cpas_vote;
+	int rc = 0;
+
+	if (!device_priv) {
+		pr_err("Invalid cam_dev_info\n");
+		return -EINVAL;
+	}
+
+	soc_info = &ipe_dev->soc_info;
+	core_info = (struct cam_ipe_device_core_info *)ipe_dev->core_info;
+
+	if ((!soc_info) || (!core_info)) {
+		pr_err("soc_info = %pK core_info = %pK\n", soc_info, core_info);
+		return -EINVAL;
+	}
+
+	cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE;
+	cpas_vote.ahb_vote.vote.level = CAM_TURBO_VOTE;
+	cpas_vote.axi_vote.compressed_bw = ICP_TURBO_VOTE;
+	cpas_vote.axi_vote.uncompressed_bw = ICP_TURBO_VOTE;
+
+	rc = cam_cpas_start(core_info->cpas_handle,
+		&cpas_vote.ahb_vote, &cpas_vote.axi_vote);
+	if (rc < 0) {
+		pr_err("cpass start failed: %d\n", rc);
+		return rc;
+	}
+
+	rc = cam_ipe_enable_soc_resources(soc_info);
+	if (rc < 0) {
+		pr_err("soc enable is failed\n");
+		rc = cam_cpas_stop(core_info->cpas_handle);
+	}
+
+	return rc;
+}
+
+int cam_ipe_deinit_hw(void *device_priv,
+	void *init_hw_args, uint32_t arg_size)
+{
+	struct cam_hw_info *ipe_dev = device_priv;
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_ipe_device_core_info *core_info = NULL;
+	int rc = 0;
+
+	if (!device_priv) {
+		pr_err("Invalid cam_dev_info\n");
+		return -EINVAL;
+	}
+
+	soc_info = &ipe_dev->soc_info;
+	core_info = (struct cam_ipe_device_core_info *)ipe_dev->core_info;
+	if ((!soc_info) || (!core_info)) {
+		pr_err("soc_info = %pK core_info = %pK\n", soc_info, core_info);
+		return -EINVAL;
+	}
+
+	rc = cam_ipe_disable_soc_resources(soc_info);
+	if (rc < 0)
+		pr_err("soc enable is failed\n");
+
+	rc = cam_cpas_stop(core_info->cpas_handle);
+	if (rc < 0)
+		pr_err("cpas stop is failed: %d\n", rc);
+
+	return rc;
+}
+
+int cam_ipe_process_cmd(void *device_priv, uint32_t cmd_type,
+	void *cmd_args, uint32_t arg_size)
+{
+	struct cam_hw_info *ipe_dev = device_priv;
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_ipe_device_core_info *core_info = NULL;
+	struct cam_ipe_device_hw_info *hw_info = NULL;
+	int rc = 0;
+
+	if (!device_priv) {
+		pr_err("Invalid arguments\n");
+		return -EINVAL;
+	}
+
+	if (cmd_type >= CAM_ICP_IPE_CMD_MAX) {
+		pr_err("Invalid command : %x\n", cmd_type);
+		return -EINVAL;
+	}
+
+	soc_info = &ipe_dev->soc_info;
+	core_info = (struct cam_ipe_device_core_info *)ipe_dev->core_info;
+	hw_info = core_info->ipe_hw_info;
+
+	switch (cmd_type) {
+	case CAM_ICP_IPE_CMD_VOTE_CPAS: {
+		struct cam_icp_cpas_vote *cpas_vote = cmd_args;
+
+		if (!cmd_args)
+			return -EINVAL;
+
+		cam_ipe_caps_vote(core_info, cpas_vote);
+		break;
+	}
+
+	case CAM_ICP_IPE_CMD_CPAS_START: {
+		struct cam_icp_cpas_vote *cpas_vote = cmd_args;
+
+		if (!cmd_args)
+			return -EINVAL;
+
+		rc = cam_cpas_start(core_info->cpas_handle,
+			&cpas_vote->ahb_vote, &cpas_vote->axi_vote);
+		break;
+	}
+
+	case CAM_ICP_IPE_CMD_CPAS_STOP:
+		cam_cpas_stop(core_info->cpas_handle);
+		break;
+	default:
+		break;
+	}
+	return rc;
+}
+
+irqreturn_t cam_ipe_irq(int irq_num, void *data)
+{
+	return IRQ_HANDLED;
+}
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_core.h b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_core.h
new file mode 100644
index 0000000..4818846
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_core.h
@@ -0,0 +1,39 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CAM_IPE_CORE_H
+#define CAM_IPE_CORE_H
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/dma-buf.h>
+
+struct cam_ipe_device_hw_info {
+	uint32_t reserved;
+};
+
+struct cam_ipe_device_core_info {
+	struct cam_ipe_device_hw_info *ipe_hw_info;
+	uint32_t cpas_handle;
+};
+
+int cam_ipe_init_hw(void *device_priv,
+	void *init_hw_args, uint32_t arg_size);
+int cam_ipe_deinit_hw(void *device_priv,
+	void *init_hw_args, uint32_t arg_size);
+int cam_ipe_process_cmd(void *device_priv, uint32_t cmd_type,
+	void *cmd_args, uint32_t arg_size);
+irqreturn_t cam_ipe_irq(int irq_num, void *data);
+
+#endif /* CAM_IPE_CORE_H */
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_dev.c b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_dev.c
new file mode 100644
index 0000000..0efb1de
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_dev.c
@@ -0,0 +1,176 @@
+/* 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/module.h>
+#include <linux/slab.h>
+#include <linux/mod_devicetable.h>
+#include <linux/of_device.h>
+#include <linux/timer.h>
+#include "ipe_core.h"
+#include "ipe_soc.h"
+#include "cam_hw.h"
+#include "cam_hw_intf.h"
+#include "cam_io_util.h"
+#include "cam_icp_hw_intf.h"
+#include "cam_icp_hw_mgr_intf.h"
+#include "cam_cpas_api.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+struct cam_ipe_device_hw_info cam_ipe_hw_info = {
+	.reserved = 0,
+};
+EXPORT_SYMBOL(cam_ipe_hw_info);
+
+int cam_ipe_register_cpas(struct cam_hw_soc_info *soc_info,
+	struct cam_ipe_device_core_info *core_info,
+	uint32_t hw_idx)
+{
+	struct cam_cpas_register_params cpas_register_params;
+	int rc;
+
+	cpas_register_params.dev = &soc_info->pdev->dev;
+	memcpy(cpas_register_params.identifier, "ipe", sizeof("ipe"));
+	cpas_register_params.cam_cpas_client_cb = NULL;
+	cpas_register_params.cell_index = hw_idx;
+	cpas_register_params.userdata = NULL;
+
+	rc = cam_cpas_register_client(&cpas_register_params);
+	if (rc < 0) {
+		pr_err("cam_cpas_register_client is failed: %d\n", rc);
+		return rc;
+	}
+	core_info->cpas_handle = cpas_register_params.client_handle;
+
+	return rc;
+}
+
+int cam_ipe_probe(struct platform_device *pdev)
+{
+	struct cam_hw_info            *ipe_dev = NULL;
+	struct cam_hw_intf            *ipe_dev_intf = NULL;
+	const struct of_device_id         *match_dev = NULL;
+	struct cam_ipe_device_core_info   *core_info = NULL;
+	struct cam_ipe_device_hw_info     *hw_info = NULL;
+	int                                rc = 0;
+
+	ipe_dev_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL);
+	if (!ipe_dev_intf)
+		return -ENOMEM;
+
+	of_property_read_u32(pdev->dev.of_node,
+		"cell-index", &ipe_dev_intf->hw_idx);
+
+	ipe_dev = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL);
+	if (!ipe_dev) {
+		kfree(ipe_dev_intf);
+		return -ENOMEM;
+	}
+	ipe_dev->soc_info.pdev = pdev;
+	ipe_dev_intf->hw_priv = ipe_dev;
+	ipe_dev_intf->hw_ops.init = cam_ipe_init_hw;
+	ipe_dev_intf->hw_ops.deinit = cam_ipe_deinit_hw;
+	ipe_dev_intf->hw_ops.process_cmd = cam_ipe_process_cmd;
+	ipe_dev_intf->hw_type = CAM_ICP_DEV_IPE;
+
+	pr_debug("%s: type %d index %d\n", __func__,
+		ipe_dev_intf->hw_type,
+		ipe_dev_intf->hw_idx);
+
+	platform_set_drvdata(pdev, ipe_dev_intf);
+
+	ipe_dev->core_info = kzalloc(sizeof(struct cam_ipe_device_core_info),
+		GFP_KERNEL);
+	if (!ipe_dev->core_info) {
+		kfree(ipe_dev);
+		kfree(ipe_dev_intf);
+		return -ENOMEM;
+	}
+	core_info = (struct cam_ipe_device_core_info *)ipe_dev->core_info;
+
+	match_dev = of_match_device(pdev->dev.driver->of_match_table,
+		&pdev->dev);
+	if (!match_dev) {
+		pr_debug("%s: No ipe hardware info\n", __func__);
+		kfree(ipe_dev->core_info);
+		kfree(ipe_dev);
+		kfree(ipe_dev_intf);
+		rc = -EINVAL;
+		return rc;
+	}
+	hw_info = (struct cam_ipe_device_hw_info *)match_dev->data;
+	core_info->ipe_hw_info = hw_info;
+
+	rc = cam_ipe_init_soc_resources(&ipe_dev->soc_info, cam_ipe_irq,
+		ipe_dev);
+	if (rc < 0) {
+		pr_err("%s: failed to init_soc\n", __func__);
+		kfree(ipe_dev->core_info);
+		kfree(ipe_dev);
+		kfree(ipe_dev_intf);
+		return rc;
+	}
+
+	pr_debug("cam_ipe_init_soc_resources : %pK\n",
+		(void *)&ipe_dev->soc_info);
+	rc = cam_ipe_register_cpas(&ipe_dev->soc_info,
+		core_info, ipe_dev_intf->hw_idx);
+	if (rc < 0) {
+		kfree(ipe_dev->core_info);
+		kfree(ipe_dev);
+		kfree(ipe_dev_intf);
+		return rc;
+	}
+	ipe_dev->hw_state = CAM_HW_STATE_POWER_DOWN;
+	mutex_init(&ipe_dev->hw_mutex);
+	spin_lock_init(&ipe_dev->hw_lock);
+	init_completion(&ipe_dev->hw_complete);
+
+	pr_debug("%s: IPE%d probe successful\n", __func__,
+		ipe_dev_intf->hw_idx);
+
+	return rc;
+}
+
+static const struct of_device_id cam_ipe_dt_match[] = {
+	{
+		.compatible = "qcom,cam_ipe",
+		.data = &cam_ipe_hw_info,
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, cam_ipe_dt_match);
+
+static struct platform_driver cam_ipe_driver = {
+	.probe = cam_ipe_probe,
+	.driver = {
+		.name = "cam_ipe",
+		.owner = THIS_MODULE,
+		.of_match_table = cam_ipe_dt_match,
+	},
+};
+
+static int __init cam_ipe_init_module(void)
+{
+	return platform_driver_register(&cam_ipe_driver);
+}
+
+static void __exit cam_ipe_exit_module(void)
+{
+	platform_driver_unregister(&cam_ipe_driver);
+}
+
+module_init(cam_ipe_init_module);
+module_exit(cam_ipe_exit_module);
+MODULE_DESCRIPTION("CAM IPE driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_soc.c b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_soc.c
new file mode 100644
index 0000000..527e716
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_soc.c
@@ -0,0 +1,87 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/dma-buf.h>
+#include <media/cam_defs.h>
+#include <media/cam_icp.h>
+#include "ipe_soc.h"
+#include "cam_soc_util.h"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+static int cam_ipe_get_dt_properties(struct cam_hw_soc_info *soc_info)
+{
+	int rc = 0;
+
+	rc = cam_soc_util_get_dt_properties(soc_info);
+	if (rc < 0)
+		pr_err("get ipe dt prop is failed\n");
+
+	return rc;
+}
+
+static int cam_ipe_request_platform_resource(
+	struct cam_hw_soc_info *soc_info,
+	irq_handler_t ipe_irq_handler, void *irq_data)
+{
+	int rc = 0;
+
+	rc = cam_soc_util_request_platform_resource(soc_info, ipe_irq_handler,
+		irq_data);
+
+	return rc;
+}
+
+int cam_ipe_init_soc_resources(struct cam_hw_soc_info *soc_info,
+	irq_handler_t ipe_irq_handler, void *irq_data)
+{
+	int rc = 0;
+
+	rc = cam_ipe_get_dt_properties(soc_info);
+	if (rc < 0)
+		return rc;
+
+	rc = cam_ipe_request_platform_resource(soc_info, ipe_irq_handler,
+		irq_data);
+	if (rc < 0)
+		return rc;
+
+	return rc;
+}
+
+int cam_ipe_enable_soc_resources(struct cam_hw_soc_info *soc_info)
+{
+	int rc = 0;
+
+	rc = cam_soc_util_enable_platform_resource(soc_info, true, false);
+	if (rc) {
+		pr_err("%s: enable platform failed\n", __func__);
+		return rc;
+	}
+
+	return rc;
+}
+
+int cam_ipe_disable_soc_resources(struct cam_hw_soc_info *soc_info)
+{
+	int rc = 0;
+
+	rc = cam_soc_util_disable_platform_resource(soc_info, true, false);
+	if (rc)
+		pr_err("%s: enable platform failed\n", __func__);
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_soc.h b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_soc.h
new file mode 100644
index 0000000..12ab444
--- /dev/null
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_soc.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CAM_IPE_SOC_H
+#define CAM_IPE_SOC_H
+
+#include "cam_soc_util.h"
+
+int cam_ipe_init_soc_resources(struct cam_hw_soc_info *soc_info,
+	irq_handler_t ipe_irq_handler, void *irq_data);
+
+int cam_ipe_enable_soc_resources(struct cam_hw_soc_info *soc_info);
+
+int cam_ipe_disable_soc_resources(struct cam_hw_soc_info *soc_info);
+
+#endif /* CAM_IPE_SOC_H */
diff --git a/drivers/misc/memory_state_time.c b/drivers/misc/memory_state_time.c
index 34c797a..ba94dcf 100644
--- a/drivers/misc/memory_state_time.c
+++ b/drivers/misc/memory_state_time.c
@@ -296,27 +296,31 @@
 	struct device_node *node = dev->of_node;
 
 	of_property_read_u32(node, NUM_SOURCES, &num_sources);
-	if (of_find_property(node, BW_TBL, &lenb)) {
-		bandwidths = devm_kzalloc(dev,
-				sizeof(*bandwidths) * num_sources, GFP_KERNEL);
-		if (!bandwidths)
-			return -ENOMEM;
-		lenb /= sizeof(*bw_buckets);
-		bw_buckets = devm_kzalloc(dev, lenb * sizeof(*bw_buckets),
-				GFP_KERNEL);
-		if (!bw_buckets) {
-			devm_kfree(dev, bandwidths);
-			return -ENOMEM;
-		}
-		ret = of_property_read_u32_array(node, BW_TBL, bw_buckets,
-				lenb);
-		if (ret < 0) {
-			devm_kfree(dev, bandwidths);
-			devm_kfree(dev, bw_buckets);
-			pr_err("Unable to read bandwidth table from device tree.\n");
-			return ret;
-		}
+	if (!of_find_property(node, BW_TBL, &lenb)) {
+		pr_err("Missing %s property\n", BW_TBL);
+		return -ENODATA;
 	}
+
+	bandwidths = devm_kzalloc(dev,
+			sizeof(*bandwidths) * num_sources, GFP_KERNEL);
+	if (!bandwidths)
+		return -ENOMEM;
+	lenb /= sizeof(*bw_buckets);
+	bw_buckets = devm_kzalloc(dev, lenb * sizeof(*bw_buckets),
+			GFP_KERNEL);
+	if (!bw_buckets) {
+		devm_kfree(dev, bandwidths);
+		return -ENOMEM;
+	}
+	ret = of_property_read_u32_array(node, BW_TBL, bw_buckets,
+			lenb);
+	if (ret < 0) {
+		devm_kfree(dev, bandwidths);
+		devm_kfree(dev, bw_buckets);
+		pr_err("Unable to read bandwidth table from device tree.\n");
+		return ret;
+	}
+
 	curr_bw = 0;
 	num_buckets = lenb;
 	return 0;
@@ -332,22 +336,26 @@
 	int ret, lenf;
 	struct device_node *node = dev->of_node;
 
-	if (of_find_property(node, FREQ_TBL, &lenf)) {
-		lenf /= sizeof(*freq_buckets);
-		freq_buckets = devm_kzalloc(dev, lenf * sizeof(*freq_buckets),
-				GFP_KERNEL);
-		if (!freq_buckets)
-			return -ENOMEM;
-		pr_debug("freqs found len %d\n", lenf);
-		ret = of_property_read_u32_array(node, FREQ_TBL, freq_buckets,
-				lenf);
-		if (ret < 0) {
-			devm_kfree(dev, freq_buckets);
-			pr_err("Unable to read frequency table from device tree.\n");
-			return ret;
-		}
-		pr_debug("ret freq %d\n", ret);
+	if (!of_find_property(node, FREQ_TBL, &lenf)) {
+		pr_err("Missing %s property\n", FREQ_TBL);
+		return -ENODATA;
 	}
+
+	lenf /= sizeof(*freq_buckets);
+	freq_buckets = devm_kzalloc(dev, lenf * sizeof(*freq_buckets),
+			GFP_KERNEL);
+	if (!freq_buckets)
+		return -ENOMEM;
+	pr_debug("freqs found len %d\n", lenf);
+	ret = of_property_read_u32_array(node, FREQ_TBL, freq_buckets,
+			lenf);
+	if (ret < 0) {
+		devm_kfree(dev, freq_buckets);
+		pr_err("Unable to read frequency table from device tree.\n");
+		return ret;
+	}
+	pr_debug("ret freq %d\n", ret);
+
 	num_freqs = lenf;
 	curr_freq = freq_buckets[LOWEST_FREQ];
 
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 1397d03..790f191 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -4321,6 +4321,7 @@
 		mmc_power_up(host, host->ocr_avail);
 
 	mmc_gpiod_request_cd_irq(host);
+	mmc_register_extcon(host);
 	mmc_release_host(host);
 	_mmc_detect_change(host, 0, false);
 }
@@ -4357,6 +4358,8 @@
 
 	BUG_ON(host->card);
 
+	mmc_register_extcon(host);
+
 	mmc_claim_host(host);
 	mmc_power_off(host);
 	mmc_release_host(host);
diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c
index 27117ba..b5c81e4 100644
--- a/drivers/mmc/core/slot-gpio.c
+++ b/drivers/mmc/core/slot-gpio.c
@@ -17,6 +17,7 @@
 #include <linux/mmc/slot-gpio.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/extcon.h>
 
 #include "slot-gpio.h"
 
@@ -154,6 +155,53 @@
 }
 EXPORT_SYMBOL(mmc_gpiod_request_cd_irq);
 
+static int mmc_card_detect_notifier(struct notifier_block *nb,
+				       unsigned long event, void *ptr)
+{
+	struct mmc_host *host = container_of(nb, struct mmc_host,
+					     card_detect_nb);
+
+	host->trigger_card_event = true;
+	mmc_detect_change(host, 0);
+
+	return NOTIFY_DONE;
+}
+
+void mmc_register_extcon(struct mmc_host *host)
+{
+	struct extcon_dev *extcon = host->extcon;
+	int err;
+
+	if (!extcon)
+		return;
+
+	host->card_detect_nb.notifier_call = mmc_card_detect_notifier;
+	err = extcon_register_notifier(extcon, EXTCON_MECHANICAL,
+				       &host->card_detect_nb);
+	if (err) {
+		dev_err(mmc_dev(host), "%s: extcon_register_notifier() failed ret=%d\n",
+			__func__, err);
+		host->caps |= MMC_CAP_NEEDS_POLL;
+	}
+}
+EXPORT_SYMBOL(mmc_register_extcon);
+
+void mmc_unregister_extcon(struct mmc_host *host)
+{
+	struct extcon_dev *extcon = host->extcon;
+	int err;
+
+	if (!extcon)
+		return;
+
+	err = extcon_unregister_notifier(extcon, EXTCON_MECHANICAL,
+					 &host->card_detect_nb);
+	if (err)
+		dev_err(mmc_dev(host), "%s: extcon_unregister_notifier() failed ret=%d\n",
+			__func__, err);
+}
+EXPORT_SYMBOL(mmc_unregister_extcon);
+
 /* Register an alternate interrupt service routine for
  * the card-detect GPIO.
  */
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 515abb2..dff6631 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -401,6 +401,8 @@
 	depends on MMC_SDHCI_PLTFM
 	select PM_DEVFREQ
 	select DEVFREQ_GOV_SIMPLE_ONDEMAND
+	select EXTCON
+	select EXTCON_GPIO
 	help
 	  This selects the Secure Digital Host Controller Interface (SDHCI)
 	  support present in Qualcomm Technologies, Inc. SOCs. The controller
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
index ad49bfa..b6122e9 100644
--- a/drivers/mmc/host/sdhci-pltfm.c
+++ b/drivers/mmc/host/sdhci-pltfm.c
@@ -121,6 +121,7 @@
 	struct resource *iomem;
 	void __iomem *ioaddr;
 	int irq, ret;
+	struct extcon_dev *extcon;
 
 	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	ioaddr = devm_ioremap_resource(&pdev->dev, iomem);
@@ -156,6 +157,15 @@
 		host->quirks2 = pdata->quirks2;
 	}
 
+	extcon = extcon_get_edev_by_phandle(&pdev->dev, 0);
+	if (IS_ERR(extcon) && PTR_ERR(extcon) != -ENODEV) {
+		ret = PTR_ERR(extcon);
+		goto err;
+	}
+	if (!IS_ERR(extcon))
+		host->mmc->extcon = extcon;
+
+
 	platform_set_drvdata(pdev, host);
 
 	return host;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 53a6ae8..83be863 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -4095,7 +4095,7 @@
 	if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) &&
 	    mmc_card_is_removable(mmc) &&
 	    mmc_gpio_get_cd(host->mmc) < 0 &&
-	    !(mmc->caps2 & MMC_CAP2_NONHOTPLUG))
+	    !(mmc->caps2 & MMC_CAP2_NONHOTPLUG) && !host->mmc->extcon)
 		mmc->caps |= MMC_CAP_NEEDS_POLL;
 
 	/* If vqmmc regulator and no 1.8V signalling, then there's no UHS */
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index f08a20b..48ee411 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -2867,7 +2867,8 @@
 		INIT_HLIST_HEAD(&bp->ntp_fltr_hash_tbl[i]);
 
 	bp->ntp_fltr_count = 0;
-	bp->ntp_fltr_bmap = kzalloc(BITS_TO_LONGS(BNXT_NTP_FLTR_MAX_FLTR),
+	bp->ntp_fltr_bmap = kcalloc(BITS_TO_LONGS(BNXT_NTP_FLTR_MAX_FLTR),
+				    sizeof(long),
 				    GFP_KERNEL);
 
 	if (!bp->ntp_fltr_bmap)
diff --git a/drivers/net/ethernet/msm/ecm_ipa.c b/drivers/net/ethernet/msm/ecm_ipa.c
index ce8f7ac..105294a 100644
--- a/drivers/net/ethernet/msm/ecm_ipa.c
+++ b/drivers/net/ethernet/msm/ecm_ipa.c
@@ -97,8 +97,8 @@
 };
 
 #define ECM_IPA_STATE_DEBUG(ecm_ipa_ctx) \
-	(ECM_IPA_DEBUG("Driver state - %s\n",\
-	ecm_ipa_state_string((ecm_ipa_ctx)->state)))
+	ECM_IPA_DEBUG("Driver state - %s\n",\
+	ecm_ipa_state_string((ecm_ipa_ctx)->state))
 
 /**
  * struct ecm_ipa_dev - main driver context parameters
@@ -163,8 +163,6 @@
 static netdev_tx_t ecm_ipa_start_xmit
 	(struct sk_buff *skb, struct net_device *net);
 static int ecm_ipa_debugfs_atomic_open(struct inode *inode, struct file *file);
-static ssize_t ecm_ipa_debugfs_enable_read
-	(struct file *file, char __user *ubuf, size_t count, loff_t *ppos);
 static ssize_t ecm_ipa_debugfs_atomic_read
 	(struct file *file, char __user *ubuf, size_t count, loff_t *ppos);
 static void ecm_ipa_debugfs_init(struct ecm_ipa_dev *ecm_ipa_ctx);
@@ -558,7 +556,7 @@
 	netdev_tx_t status = NETDEV_TX_BUSY;
 	struct ecm_ipa_dev *ecm_ipa_ctx = netdev_priv(net);
 
-	net->trans_start = jiffies;
+	netif_trans_update(net);
 
 	ECM_IPA_DEBUG
 		("Tx, len=%d, skb->protocol=%d, outstanding=%d\n",
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index f7c6a40..a5d66e2 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -617,7 +617,8 @@
 
 static struct aead_request *macsec_alloc_req(struct crypto_aead *tfm,
 					     unsigned char **iv,
-					     struct scatterlist **sg)
+					     struct scatterlist **sg,
+					     int num_frags)
 {
 	size_t size, iv_offset, sg_offset;
 	struct aead_request *req;
@@ -629,7 +630,7 @@
 
 	size = ALIGN(size, __alignof__(struct scatterlist));
 	sg_offset = size;
-	size += sizeof(struct scatterlist) * (MAX_SKB_FRAGS + 1);
+	size += sizeof(struct scatterlist) * num_frags;
 
 	tmp = kmalloc(size, GFP_ATOMIC);
 	if (!tmp)
@@ -649,6 +650,7 @@
 {
 	int ret;
 	struct scatterlist *sg;
+	struct sk_buff *trailer;
 	unsigned char *iv;
 	struct ethhdr *eth;
 	struct macsec_eth_header *hh;
@@ -723,7 +725,14 @@
 		return ERR_PTR(-EINVAL);
 	}
 
-	req = macsec_alloc_req(tx_sa->key.tfm, &iv, &sg);
+	ret = skb_cow_data(skb, 0, &trailer);
+	if (unlikely(ret < 0)) {
+		macsec_txsa_put(tx_sa);
+		kfree_skb(skb);
+		return ERR_PTR(ret);
+	}
+
+	req = macsec_alloc_req(tx_sa->key.tfm, &iv, &sg, ret);
 	if (!req) {
 		macsec_txsa_put(tx_sa);
 		kfree_skb(skb);
@@ -732,7 +741,7 @@
 
 	macsec_fill_iv(iv, secy->sci, pn);
 
-	sg_init_table(sg, MAX_SKB_FRAGS + 1);
+	sg_init_table(sg, ret);
 	skb_to_sgvec(skb, sg, 0, skb->len);
 
 	if (tx_sc->encrypt) {
@@ -914,6 +923,7 @@
 {
 	int ret;
 	struct scatterlist *sg;
+	struct sk_buff *trailer;
 	unsigned char *iv;
 	struct aead_request *req;
 	struct macsec_eth_header *hdr;
@@ -924,7 +934,12 @@
 	if (!skb)
 		return ERR_PTR(-ENOMEM);
 
-	req = macsec_alloc_req(rx_sa->key.tfm, &iv, &sg);
+	ret = skb_cow_data(skb, 0, &trailer);
+	if (unlikely(ret < 0)) {
+		kfree_skb(skb);
+		return ERR_PTR(ret);
+	}
+	req = macsec_alloc_req(rx_sa->key.tfm, &iv, &sg, ret);
 	if (!req) {
 		kfree_skb(skb);
 		return ERR_PTR(-ENOMEM);
@@ -933,7 +948,7 @@
 	hdr = (struct macsec_eth_header *)skb->data;
 	macsec_fill_iv(iv, sci, ntohl(hdr->packet_number));
 
-	sg_init_table(sg, MAX_SKB_FRAGS + 1);
+	sg_init_table(sg, ret);
 	skb_to_sgvec(skb, sg, 0, skb->len);
 
 	if (hdr->tci_an & MACSEC_TCI_E) {
@@ -2709,7 +2724,7 @@
 }
 
 #define MACSEC_FEATURES \
-	(NETIF_F_SG | NETIF_F_HIGHDMA)
+	(NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST)
 static struct lock_class_key macsec_netdev_addr_lock_key;
 
 static int macsec_dev_init(struct net_device *dev)
diff --git a/drivers/net/phy/mdio-mux-bcm-iproc.c b/drivers/net/phy/mdio-mux-bcm-iproc.c
index 0a04125..0a5f62e 100644
--- a/drivers/net/phy/mdio-mux-bcm-iproc.c
+++ b/drivers/net/phy/mdio-mux-bcm-iproc.c
@@ -203,11 +203,14 @@
 			   &md->mux_handle, md, md->mii_bus);
 	if (rc) {
 		dev_info(md->dev, "mdiomux initialization failed\n");
-		goto out;
+		goto out_register;
 	}
 
 	dev_info(md->dev, "iProc mdiomux registered\n");
 	return 0;
+
+out_register:
+	mdiobus_unregister(bus);
 out:
 	mdiobus_free(bus);
 	return rc;
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 0d519a9..34d997c 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -902,6 +902,7 @@
 	{QMI_FIXED_INTF(0x2357, 0x0201, 4)},	/* TP-LINK HSUPA Modem MA180 */
 	{QMI_FIXED_INTF(0x2357, 0x9000, 4)},	/* TP-LINK MA260 */
 	{QMI_QUIRK_SET_DTR(0x1bc7, 0x1040, 2)},	/* Telit LE922A */
+	{QMI_FIXED_INTF(0x1bc7, 0x1100, 3)},	/* Telit ME910 */
 	{QMI_FIXED_INTF(0x1bc7, 0x1200, 5)},	/* Telit LE920 */
 	{QMI_FIXED_INTF(0x1bc7, 0x1201, 2)},	/* Telit LE920 */
 	{QMI_FIXED_INTF(0x1c9e, 0x9b01, 3)},	/* XS Stick W100-2 from 4G Systems */
diff --git a/drivers/net/wireless/ath/wil6210/Kconfig b/drivers/net/wireless/ath/wil6210/Kconfig
index 8f0bde5..0e66348 100644
--- a/drivers/net/wireless/ath/wil6210/Kconfig
+++ b/drivers/net/wireless/ath/wil6210/Kconfig
@@ -44,7 +44,7 @@
 config WIL6210_WRITE_IOCTL
 	bool "wil6210 write ioctl to the device"
 	depends on WIL6210
-	default n
+	default y
 	---help---
 	  Say Y here to allow write-access from user-space to
 	  the device memory through ioctl. This is useful for
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 4e111cb..a83f8f6 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -25,6 +25,10 @@
 module_param(disable_ap_sme, bool, 0444);
 MODULE_PARM_DESC(disable_ap_sme, " let user space handle AP mode SME");
 
+static bool ignore_reg_hints = true;
+module_param(ignore_reg_hints, bool, 0444);
+MODULE_PARM_DESC(ignore_reg_hints, " Ignore OTA regulatory hints (Default: true)");
+
 #define CHAN60G(_channel, _flags) {				\
 	.band			= NL80211_BAND_60GHZ,		\
 	.center_freq		= 56160 + (2160 * (_channel)),	\
@@ -1413,6 +1417,8 @@
 	wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
 	wil_set_recovery_state(wil, fw_recovery_idle);
 
+	set_bit(wil_status_resetting, wil->status);
+
 	mutex_lock(&wil->mutex);
 
 	wmi_pcp_stop(wil);
@@ -1647,12 +1653,6 @@
 {
 	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
 	enum wmi_ps_profile_type ps_profile;
-	int rc;
-
-	if (!test_bit(WMI_FW_CAPABILITY_PS_CONFIG, wil->fw_capabilities)) {
-		wil_err(wil, "set_power_mgmt not supported\n");
-		return -EOPNOTSUPP;
-	}
 
 	wil_dbg_misc(wil, "enabled=%d, timeout=%d\n",
 		     enabled, timeout);
@@ -1662,11 +1662,7 @@
 	else
 		ps_profile = WMI_PS_PROFILE_TYPE_PS_DISABLED;
 
-	rc  = wmi_ps_dev_profile_cfg(wil, ps_profile);
-	if (rc)
-		wil_err(wil, "wmi_ps_dev_profile_cfg failed (%d)\n", rc);
-
-	return rc;
+	return wil_ps_update(wil, ps_profile);
 }
 
 static struct cfg80211_ops wil_cfg80211_ops = {
@@ -1740,6 +1736,11 @@
 	wiphy->vendor_commands = wil_nl80211_vendor_commands;
 	wiphy->vendor_events = wil_nl80211_vendor_events;
 	wiphy->n_vendor_events = ARRAY_SIZE(wil_nl80211_vendor_events);
+
+	if (ignore_reg_hints) {
+		wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS;
+		wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE;
+	}
 }
 
 struct wireless_dev *wil_cfg80211_init(struct device *dev)
diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c
index f490158..e01acac 100644
--- a/drivers/net/wireless/ath/wil6210/fw_inc.c
+++ b/drivers/net/wireless/ath/wil6210/fw_inc.c
@@ -554,5 +554,7 @@
 	rc = request_firmware(&fw, name, wil_to_dev(wil));
 	if (!rc)
 		release_firmware(fw);
-	return rc != -ENOENT;
+	else
+		wil_dbg_fw(wil, "<%s> not available: %d\n", name, rc);
+	return !rc;
 }
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 36959a3..1fc4580 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -130,9 +130,15 @@
 	u32 *d = dst;
 	const volatile u32 __iomem *s = src;
 
-	/* size_t is unsigned, if (count%4 != 0) it will wrap */
-	for (count += 4; count > 4; count -= 4)
+	for (; count >= 4; count -= 4)
 		*d++ = __raw_readl(s++);
+
+	if (unlikely(count)) {
+		/* count can be 1..3 */
+		u32 tmp = __raw_readl(s);
+
+		memcpy(d, &tmp, count);
+	}
 }
 
 void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
@@ -141,8 +147,16 @@
 	volatile u32 __iomem *d = dst;
 	const u32 *s = src;
 
-	for (count += 4; count > 4; count -= 4)
+	for (; count >= 4; count -= 4)
 		__raw_writel(*s++, d++);
+
+	if (unlikely(count)) {
+		/* count can be 1..3 */
+		u32 tmp = 0;
+
+		memcpy(&tmp, s, count);
+		__raw_writel(tmp, d);
+	}
 }
 
 static void wil_disconnect_cid(struct wil6210_priv *wil, int cid,
@@ -176,6 +190,7 @@
 			break;
 		}
 		sta->status = wil_sta_unused;
+		sta->fst_link_loss = false;
 	}
 	/* reorder buffers */
 	for (i = 0; i < WIL_STA_TID_NUM; i++) {
@@ -561,6 +576,9 @@
 
 	if (rx_ring_overflow_thrsh == WIL6210_RX_HIGH_TRSH_INIT)
 		rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_DEFAULT;
+
+	wil->ps_profile =  WMI_PS_PROFILE_TYPE_DEFAULT;
+
 	return 0;
 
 out_wmi_wq:
@@ -889,6 +907,24 @@
 	}
 }
 
+int wil_ps_update(struct wil6210_priv *wil, enum wmi_ps_profile_type ps_profile)
+{
+	int rc;
+
+	if (!test_bit(WMI_FW_CAPABILITY_PS_CONFIG, wil->fw_capabilities)) {
+		wil_err(wil, "set_power_mgmt not supported\n");
+		return -EOPNOTSUPP;
+	}
+
+	rc  = wmi_ps_dev_profile_cfg(wil, ps_profile);
+	if (rc)
+		wil_err(wil, "wmi_ps_dev_profile_cfg failed (%d)\n", rc);
+	else
+		wil->ps_profile = ps_profile;
+
+	return rc;
+}
+
 /*
  * We reset all the structures, and we reset the UMAC.
  * After calling this routine, you're expected to reload
@@ -938,15 +974,15 @@
 	/* Disable device led before reset*/
 	wmi_led_cfg(wil, false);
 
+	mutex_lock(&wil->p2p_wdev_mutex);
+	wil_abort_scan(wil, false);
+	mutex_unlock(&wil->p2p_wdev_mutex);
+
 	/* prevent NAPI from being scheduled and prevent wmi commands */
 	mutex_lock(&wil->wmi_mutex);
 	bitmap_zero(wil->status, wil_status_last);
 	mutex_unlock(&wil->wmi_mutex);
 
-	mutex_lock(&wil->p2p_wdev_mutex);
-	wil_abort_scan(wil, false);
-	mutex_unlock(&wil->p2p_wdev_mutex);
-
 	wil_mask_irq(wil);
 
 	wmi_event_flush(wil);
@@ -1023,6 +1059,12 @@
 			return rc;
 		}
 
+		if (wil->ps_profile != WMI_PS_PROFILE_TYPE_DEFAULT)
+			wil_ps_update(wil, wil->ps_profile);
+
+		if (wil->tt_data_set)
+			wmi_set_tt_cfg(wil, &wil->tt_data);
+
 		wil_collect_fw_info(wil);
 
 		if (wil->platform_ops.notify) {
diff --git a/drivers/net/wireless/ath/wil6210/pmc.c b/drivers/net/wireless/ath/wil6210/pmc.c
index b067fdf..2e301b6 100644
--- a/drivers/net/wireless/ath/wil6210/pmc.c
+++ b/drivers/net/wireless/ath/wil6210/pmc.c
@@ -200,7 +200,7 @@
 
 release_pmc_skbs:
 	wil_err(wil, "exit on error: Releasing skbs...\n");
-	for (i = 0; pmc->descriptors[i].va && i < num_descriptors; i++) {
+	for (i = 0; i < num_descriptors && pmc->descriptors[i].va; i++) {
 		dma_free_coherent(dev,
 				  descriptor_size,
 				  pmc->descriptors[i].va,
@@ -283,7 +283,7 @@
 		int i;
 
 		for (i = 0;
-		     pmc->descriptors[i].va && i < pmc->num_descriptors; i++) {
+		     i < pmc->num_descriptors && pmc->descriptors[i].va; i++) {
 			dma_free_coherent(dev,
 					  pmc->descriptor_size,
 					  pmc->descriptors[i].va,
diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c
index 7404b6f..a43cffc 100644
--- a/drivers/net/wireless/ath/wil6210/rx_reorder.c
+++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c
@@ -343,8 +343,16 @@
 		wil_err(wil, "BACK requested unsupported ba_policy == 1\n");
 		status = WLAN_STATUS_INVALID_QOS_PARAM;
 	}
-	if (status == WLAN_STATUS_SUCCESS)
-		agg_wsize = wil_agg_size(wil, req_agg_wsize);
+	if (status == WLAN_STATUS_SUCCESS) {
+		if (req_agg_wsize == 0) {
+			wil_dbg_misc(wil, "Suggest BACK wsize %d\n",
+				     WIL_MAX_AGG_WSIZE);
+			agg_wsize = WIL_MAX_AGG_WSIZE;
+		} else {
+			agg_wsize = min_t(u16,
+					  WIL_MAX_AGG_WSIZE, req_agg_wsize);
+		}
+	}
 
 	rc = wmi_addba_rx_resp(wil, cid, tid, dialog_token, status,
 			       agg_amsdu, agg_wsize, agg_timeout);
diff --git a/drivers/net/wireless/ath/wil6210/sysfs.c b/drivers/net/wireless/ath/wil6210/sysfs.c
index 0faa26c..b4c4d09 100644
--- a/drivers/net/wireless/ath/wil6210/sysfs.c
+++ b/drivers/net/wireless/ath/wil6210/sysfs.c
@@ -94,8 +94,184 @@
 		   wil_ftm_txrx_offset_sysfs_show,
 		   wil_ftm_txrx_offset_sysfs_store);
 
+static ssize_t
+wil_tt_sysfs_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct wil6210_priv *wil = dev_get_drvdata(dev);
+	ssize_t len;
+	struct wmi_tt_data tt_data;
+	int i, rc;
+
+	rc = wmi_get_tt_cfg(wil, &tt_data);
+	if (rc)
+		return rc;
+
+	len = snprintf(buf, PAGE_SIZE, "    high      max       critical\n");
+
+	len += snprintf(buf + len, PAGE_SIZE - len, "bb: ");
+	if (tt_data.bb_enabled)
+		for (i = 0; i < WMI_NUM_OF_TT_ZONES; ++i)
+			len += snprintf(buf + len, PAGE_SIZE - len,
+					"%03d-%03d   ",
+					tt_data.bb_zones[i].temperature_high,
+					tt_data.bb_zones[i].temperature_low);
+	else
+		len += snprintf(buf + len, PAGE_SIZE - len, "* disabled *");
+	len += snprintf(buf + len, PAGE_SIZE - len, "\nrf: ");
+	if (tt_data.rf_enabled)
+		for (i = 0; i < WMI_NUM_OF_TT_ZONES; ++i)
+			len += snprintf(buf + len, PAGE_SIZE - len,
+					"%03d-%03d   ",
+					tt_data.rf_zones[i].temperature_high,
+					tt_data.rf_zones[i].temperature_low);
+	else
+		len += snprintf(buf + len, PAGE_SIZE - len, "* disabled *");
+	len += snprintf(buf + len, PAGE_SIZE - len, "\n");
+
+	return len;
+}
+
+static ssize_t
+wil_tt_sysfs_store(struct device *dev, struct device_attribute *attr,
+		   const char *buf, size_t count)
+{
+	struct wil6210_priv *wil = dev_get_drvdata(dev);
+	int i, rc = -EINVAL;
+	char *token, *dupbuf, *tmp;
+	struct wmi_tt_data tt_data = {
+		.bb_enabled = 0,
+		.rf_enabled = 0,
+	};
+
+	tmp = kmemdup(buf, count + 1, GFP_KERNEL);
+	if (!tmp)
+		return -ENOMEM;
+	tmp[count] = '\0';
+	dupbuf = tmp;
+
+	/* Format for writing is 12 unsigned bytes separated by spaces:
+	 * <bb_z1_h> <bb_z1_l> <bb_z2_h> <bb_z2_l> <bb_z3_h> <bb_z3_l> \
+	 * <rf_z1_h> <rf_z1_l> <rf_z2_h> <rf_z2_l> <rf_z3_h> <rf_z3_l>
+	 * To disable thermal throttling for bb or for rf, use 0 for all
+	 * its six set points.
+	 */
+
+	/* bb */
+	for (i = 0; i < WMI_NUM_OF_TT_ZONES; ++i) {
+		token = strsep(&dupbuf, " ");
+		if (!token)
+			goto out;
+		if (kstrtou8(token, 0, &tt_data.bb_zones[i].temperature_high))
+			goto out;
+		token = strsep(&dupbuf, " ");
+		if (!token)
+			goto out;
+		if (kstrtou8(token, 0, &tt_data.bb_zones[i].temperature_low))
+			goto out;
+
+		if (tt_data.bb_zones[i].temperature_high > 0 ||
+		    tt_data.bb_zones[i].temperature_low > 0)
+			tt_data.bb_enabled = 1;
+	}
+	/* rf */
+	for (i = 0; i < WMI_NUM_OF_TT_ZONES; ++i) {
+		token = strsep(&dupbuf, " ");
+		if (!token)
+			goto out;
+		if (kstrtou8(token, 0, &tt_data.rf_zones[i].temperature_high))
+			goto out;
+		token = strsep(&dupbuf, " ");
+		if (!token)
+			goto out;
+		if (kstrtou8(token, 0, &tt_data.rf_zones[i].temperature_low))
+			goto out;
+
+		if (tt_data.rf_zones[i].temperature_high > 0 ||
+		    tt_data.rf_zones[i].temperature_low > 0)
+			tt_data.rf_enabled = 1;
+	}
+
+	rc = wmi_set_tt_cfg(wil, &tt_data);
+	if (rc)
+		goto out;
+
+	rc = count;
+out:
+	kfree(tmp);
+	return rc;
+}
+
+static DEVICE_ATTR(thermal_throttling, 0644,
+		   wil_tt_sysfs_show, wil_tt_sysfs_store);
+
+static ssize_t
+wil_fst_link_loss_sysfs_show(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct wil6210_priv *wil = dev_get_drvdata(dev);
+	ssize_t len = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(wil->sta); i++)
+		if (wil->sta[i].status == wil_sta_connected)
+			len += snprintf(buf + len, PAGE_SIZE - len,
+					"[%d] %pM %s\n", i, wil->sta[i].addr,
+					wil->sta[i].fst_link_loss ?
+					"On" : "Off");
+
+	return len;
+}
+
+static ssize_t
+wil_fst_link_loss_sysfs_store(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	struct wil6210_priv *wil = dev_get_drvdata(dev);
+	u8 addr[ETH_ALEN];
+	char *token, *dupbuf, *tmp;
+	int rc = -EINVAL;
+	bool fst_link_loss;
+
+	tmp = kmemdup(buf, count + 1, GFP_KERNEL);
+	if (!tmp)
+		return -ENOMEM;
+
+	tmp[count] = '\0';
+	dupbuf = tmp;
+
+	token = strsep(&dupbuf, " ");
+	if (!token)
+		goto out;
+
+	/* mac address */
+	if (sscanf(token, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+		   &addr[0], &addr[1], &addr[2],
+		   &addr[3], &addr[4], &addr[5]) != 6)
+		goto out;
+
+	/* On/Off */
+	if (strtobool(dupbuf, &fst_link_loss))
+		goto out;
+
+	wil_dbg_misc(wil, "set [%pM] with %d\n", addr, fst_link_loss);
+
+	rc = wmi_link_maintain_cfg_write(wil, addr, fst_link_loss);
+	if (!rc)
+		rc = count;
+
+out:
+	kfree(tmp);
+	return rc;
+}
+
+static DEVICE_ATTR(fst_link_loss, 0644,
+		   wil_fst_link_loss_sysfs_show,
+		   wil_fst_link_loss_sysfs_store);
+
 static struct attribute *wil6210_sysfs_entries[] = {
 	&dev_attr_ftm_txrx_offset.attr,
+	&dev_attr_thermal_throttling.attr,
+	&dev_attr_fst_link_loss.attr,
 	NULL
 };
 
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 8b5411e..35bbf3a 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -37,6 +37,10 @@
 module_param(rx_align_2, bool, 0444);
 MODULE_PARM_DESC(rx_align_2, " align Rx buffers on 4*n+2, default - no");
 
+bool rx_large_buf;
+module_param(rx_large_buf, bool, 0444);
+MODULE_PARM_DESC(rx_large_buf, " allocate 8KB RX buffers, default - no");
+
 static inline uint wil_rx_snaplen(void)
 {
 	return rx_align_2 ? 6 : 0;
@@ -255,7 +259,7 @@
 			       u32 i, int headroom)
 {
 	struct device *dev = wil_to_dev(wil);
-	unsigned int sz = mtu_max + ETH_HLEN + wil_rx_snaplen();
+	unsigned int sz = wil->rx_buf_len + ETH_HLEN + wil_rx_snaplen();
 	struct vring_rx_desc dd, *d = &dd;
 	volatile struct vring_rx_desc *_d = &vring->va[i].rx;
 	dma_addr_t pa;
@@ -419,7 +423,7 @@
 	struct sk_buff *skb;
 	dma_addr_t pa;
 	unsigned int snaplen = wil_rx_snaplen();
-	unsigned int sz = mtu_max + ETH_HLEN + snaplen;
+	unsigned int sz = wil->rx_buf_len + ETH_HLEN + snaplen;
 	u16 dmalen;
 	u8 ftype;
 	int cid;
@@ -780,6 +784,20 @@
 	wil_rx_refill(wil, v->size);
 }
 
+static void wil_rx_buf_len_init(struct wil6210_priv *wil)
+{
+	wil->rx_buf_len = rx_large_buf ?
+		WIL_MAX_ETH_MTU : TXRX_BUF_LEN_DEFAULT - WIL_MAX_MPDU_OVERHEAD;
+	if (mtu_max > wil->rx_buf_len) {
+		/* do not allow RX buffers to be smaller than mtu_max, for
+		 * backward compatibility (mtu_max parameter was also used
+		 * to support receiving large packets)
+		 */
+		wil_info(wil, "Override RX buffer to mtu_max(%d)\n", mtu_max);
+		wil->rx_buf_len = mtu_max;
+	}
+}
+
 int wil_rx_init(struct wil6210_priv *wil, u16 size)
 {
 	struct vring *vring = &wil->vring_rx;
@@ -792,6 +810,8 @@
 		return -EINVAL;
 	}
 
+	wil_rx_buf_len_init(wil);
+
 	vring->size = size;
 	rc = wil_vring_alloc(wil, vring);
 	if (rc)
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 734449d..d05bb36 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -33,6 +33,7 @@
 extern int agg_wsize;
 extern u32 vring_idle_trsh;
 extern bool rx_align_2;
+extern bool rx_large_buf;
 extern bool debug_fw;
 extern bool disable_ap_sme;
 
@@ -531,6 +532,7 @@
 	struct wil_tid_crypto_rx tid_crypto_rx[WIL_STA_TID_NUM];
 	struct wil_tid_crypto_rx group_crypto_rx;
 	u8 aid; /* 1-254; 0 if unknown/not reported */
+	bool fst_link_loss;
 };
 
 enum {
@@ -661,6 +663,7 @@
 	struct work_struct probe_client_worker;
 	/* DMA related */
 	struct vring vring_rx;
+	unsigned int rx_buf_len;
 	struct vring vring_tx[WIL6210_MAX_TX_RINGS];
 	struct vring_tx_data vring_tx_data[WIL6210_MAX_TX_RINGS];
 	u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */
@@ -696,7 +699,11 @@
 	/* High Access Latency Policy voting */
 	struct wil_halp halp;
 
+	enum wmi_ps_profile_type ps_profile;
+
 	struct wil_ftm_priv ftm;
+	bool tt_data_set;
+	struct wmi_tt_data tt_data;
 
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM_SLEEP
@@ -813,6 +820,8 @@
 void wil_if_remove(struct wil6210_priv *wil);
 int wil_priv_init(struct wil6210_priv *wil);
 void wil_priv_deinit(struct wil6210_priv *wil);
+int wil_ps_update(struct wil6210_priv *wil,
+		  enum wmi_ps_profile_type ps_profile);
 int wil_reset(struct wil6210_priv *wil, bool no_fw);
 void wil_fw_error_recovery(struct wil6210_priv *wil);
 void wil_set_recovery_state(struct wil6210_priv *wil, int state);
@@ -861,6 +870,8 @@
 int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short);
 int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short);
 int wmi_new_sta(struct wil6210_priv *wil, const u8 *mac, u8 aid);
+int wmi_set_tt_cfg(struct wil6210_priv *wil, struct wmi_tt_data *tt_data);
+int wmi_get_tt_cfg(struct wil6210_priv *wil, struct wmi_tt_data *tt_data);
 int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid,
 			 u8 dialog_token, __le16 ba_param_set,
 			 __le16 ba_timeout, __le16 ba_seq_ctrl);
@@ -983,5 +994,9 @@
 void wil_aoa_evt_meas(struct wil6210_priv *wil,
 		      struct wmi_aoa_meas_event *evt,
 		      int len);
+/* link loss */
+int wmi_link_maintain_cfg_write(struct wil6210_priv *wil,
+				const u8 *addr,
+				bool fst_link_loss);
 
 #endif /* __WIL6210_H__ */
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 31d6ab9..f085fb3 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -519,16 +519,16 @@
 		assoc_resp_ielen = 0;
 	}
 
-	mutex_lock(&wil->mutex);
 	if (test_bit(wil_status_resetting, wil->status) ||
 	    !test_bit(wil_status_fwready, wil->status)) {
 		wil_err(wil, "status_resetting, cancel connect event, CID %d\n",
 			evt->cid);
-		mutex_unlock(&wil->mutex);
 		/* no need for cleanup, wil_reset will do that */
 		return;
 	}
 
+	mutex_lock(&wil->mutex);
+
 	if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
 	    (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
 		if (!test_bit(wil_status_fwconnecting, wil->status)) {
@@ -632,6 +632,13 @@
 
 	wil->sinfo_gen++;
 
+	if (test_bit(wil_status_resetting, wil->status) ||
+	    !test_bit(wil_status_fwready, wil->status)) {
+		wil_err(wil, "status_resetting, cancel disconnect event\n");
+		/* no need for cleanup, wil_reset will do that */
+		return;
+	}
+
 	mutex_lock(&wil->mutex);
 	wil6210_disconnect(wil, evt->bssid, reason_code, true);
 	mutex_unlock(&wil->mutex);
@@ -1430,7 +1437,8 @@
 	struct wmi_cfg_rx_chain_cmd cmd = {
 		.action = WMI_RX_CHAIN_ADD,
 		.rx_sw_ring = {
-			.max_mpdu_size = cpu_to_le16(wil_mtu2macbuf(mtu_max)),
+			.max_mpdu_size = cpu_to_le16(
+				wil_mtu2macbuf(wil->rx_buf_len)),
 			.ring_mem_base = cpu_to_le64(vring->pa),
 			.ring_size = cpu_to_le16(vring->size),
 		},
@@ -1769,6 +1777,67 @@
 	return rc;
 }
 
+int wmi_set_tt_cfg(struct wil6210_priv *wil, struct wmi_tt_data *tt_data)
+{
+	int rc;
+	struct wmi_set_thermal_throttling_cfg_cmd cmd = {
+		.tt_data = *tt_data,
+	};
+	struct {
+		struct wmi_cmd_hdr wmi;
+		struct wmi_set_thermal_throttling_cfg_event evt;
+	} __packed reply;
+
+	if (!test_bit(WMI_FW_CAPABILITY_THERMAL_THROTTLING,
+		      wil->fw_capabilities))
+		return -EOPNOTSUPP;
+
+	memset(&reply, 0, sizeof(reply));
+	rc = wmi_call(wil, WMI_SET_THERMAL_THROTTLING_CFG_CMDID, &cmd,
+		      sizeof(cmd), WMI_SET_THERMAL_THROTTLING_CFG_EVENTID,
+		      &reply, sizeof(reply), 100);
+	if (rc) {
+		wil_err(wil, "failed to set thermal throttling\n");
+		return rc;
+	}
+	if (reply.evt.status) {
+		wil_err(wil, "set thermal throttling failed, error %d\n",
+			reply.evt.status);
+		return -EIO;
+	}
+
+	wil->tt_data = *tt_data;
+	wil->tt_data_set = true;
+
+	return 0;
+}
+
+int wmi_get_tt_cfg(struct wil6210_priv *wil, struct wmi_tt_data *tt_data)
+{
+	int rc;
+	struct {
+		struct wmi_cmd_hdr wmi;
+		struct wmi_get_thermal_throttling_cfg_event evt;
+	} __packed reply;
+
+	if (!test_bit(WMI_FW_CAPABILITY_THERMAL_THROTTLING,
+		      wil->fw_capabilities))
+		return -EOPNOTSUPP;
+
+	rc = wmi_call(wil, WMI_GET_THERMAL_THROTTLING_CFG_CMDID, NULL, 0,
+		      WMI_GET_THERMAL_THROTTLING_CFG_EVENTID, &reply,
+		      sizeof(reply), 100);
+	if (rc) {
+		wil_err(wil, "failed to get thermal throttling\n");
+		return rc;
+	}
+
+	if (tt_data)
+		*tt_data = reply.evt.tt_data;
+
+	return 0;
+}
+
 void wmi_event_flush(struct wil6210_priv *wil)
 {
 	ulong flags;
@@ -1786,6 +1855,61 @@
 	spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
 }
 
+int wmi_link_maintain_cfg_write(struct wil6210_priv *wil,
+				const u8 *addr,
+				bool fst_link_loss)
+{
+	int rc;
+	int cid = wil_find_cid(wil, addr);
+	u32 cfg_type;
+	struct wmi_link_maintain_cfg_write_cmd cmd;
+	struct {
+		struct wmi_cmd_hdr wmi;
+		struct wmi_link_maintain_cfg_write_done_event evt;
+	} __packed reply;
+
+	if (cid < 0)
+		return cid;
+
+	switch (wil->wdev->iftype) {
+	case NL80211_IFTYPE_STATION:
+		cfg_type = fst_link_loss ?
+			   WMI_LINK_MAINTAIN_CFG_TYPE_DEFAULT_FST_STA :
+			   WMI_LINK_MAINTAIN_CFG_TYPE_DEFAULT_NORMAL_STA;
+		break;
+	case NL80211_IFTYPE_AP:
+		cfg_type = fst_link_loss ?
+			   WMI_LINK_MAINTAIN_CFG_TYPE_DEFAULT_FST_AP :
+			   WMI_LINK_MAINTAIN_CFG_TYPE_DEFAULT_NORMAL_AP;
+		break;
+	default:
+		wil_err(wil, "Unsupported for iftype %d", wil->wdev->iftype);
+		return -EINVAL;
+	}
+
+	wil_dbg_misc(wil, "Setting cid:%d with cfg_type:%d\n", cid, cfg_type);
+
+	cmd.cfg_type = cpu_to_le32(cfg_type);
+	cmd.cid = cpu_to_le32(cid);
+
+	reply.evt.status = cpu_to_le32(WMI_FW_STATUS_FAILURE);
+
+	rc = wmi_call(wil, WMI_LINK_MAINTAIN_CFG_WRITE_CMDID, &cmd, sizeof(cmd),
+		      WMI_LINK_MAINTAIN_CFG_WRITE_DONE_EVENTID, &reply,
+		      sizeof(reply), 250);
+	if (rc) {
+		wil_err(wil, "Failed to %s FST link loss",
+			fst_link_loss ? "enable" : "disable");
+	} else if (reply.evt.status == WMI_FW_STATUS_SUCCESS) {
+		wil->sta[cid].fst_link_loss = fst_link_loss;
+	} else {
+		wil_err(wil, "WMI_LINK_MAINTAIN_CFG_WRITE_CMDID returned status %d",
+			reply.evt.status);
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
 static bool wmi_evt_call_handler(struct wil6210_priv *wil, int id,
 				 void *d, int len)
 {
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
index 7c9fee5..f7f5f4f 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.h
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -58,6 +58,7 @@
 	WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT	= 3,
 	WMI_FW_CAPABILITY_DISABLE_AP_SME	= 4,
 	WMI_FW_CAPABILITY_WMI_ONLY		= 5,
+	WMI_FW_CAPABILITY_THERMAL_THROTTLING	= 7,
 	WMI_FW_CAPABILITY_MAX,
 };
 
@@ -142,8 +143,6 @@
 	WMI_MAINTAIN_RESUME_CMDID			= 0x851,
 	WMI_RS_MGMT_CMDID				= 0x852,
 	WMI_RF_MGMT_CMDID				= 0x853,
-	WMI_THERMAL_THROTTLING_CTRL_CMDID		= 0x854,
-	WMI_THERMAL_THROTTLING_GET_STATUS_CMDID		= 0x855,
 	WMI_OTP_READ_CMDID				= 0x856,
 	WMI_OTP_WRITE_CMDID				= 0x857,
 	WMI_LED_CFG_CMDID				= 0x858,
@@ -192,6 +191,8 @@
 	WMI_GET_MGMT_RETRY_LIMIT_CMDID			= 0x931,
 	WMI_NEW_STA_CMDID				= 0x935,
 	WMI_DEL_STA_CMDID				= 0x936,
+	WMI_SET_THERMAL_THROTTLING_CFG_CMDID		= 0x940,
+	WMI_GET_THERMAL_THROTTLING_CFG_CMDID		= 0x941,
 	WMI_TOF_SESSION_START_CMDID			= 0x991,
 	WMI_TOF_GET_CAPABILITIES_CMDID			= 0x992,
 	WMI_TOF_SET_LCR_CMDID				= 0x993,
@@ -438,16 +439,6 @@
 	__le32 rf_mgmt_type;
 } __packed;
 
-/* WMI_THERMAL_THROTTLING_CTRL_CMDID */
-#define THERMAL_THROTTLING_USE_DEFAULT_MAX_TXOP_LENGTH	(0xFFFFFFFF)
-
-/* WMI_THERMAL_THROTTLING_CTRL_CMDID */
-struct wmi_thermal_throttling_ctrl_cmd {
-	__le32 time_on_usec;
-	__le32 time_off_usec;
-	__le32 max_txop_length_usec;
-} __packed;
-
 /* WMI_RF_RX_TEST_CMDID */
 struct wmi_rf_rx_test_cmd {
 	__le32 sector;
@@ -549,7 +540,7 @@
 	u8 hidden_ssid;
 	u8 is_go;
 	u8 reserved0[5];
-	/* abft_len override if non-0 */
+	/* A-BFT length override if non-0 */
 	u8 abft_len;
 	u8 disable_ap_sme;
 	u8 network_type;
@@ -910,6 +901,39 @@
 	u8 reserved[3];
 } __packed;
 
+/* Zones: HIGH, MAX, CRITICAL */
+#define WMI_NUM_OF_TT_ZONES	(3)
+
+struct wmi_tt_zone_limits {
+	/* Above this temperature this zone is active */
+	u8 temperature_high;
+	/* Below this temperature the adjacent lower zone is active */
+	u8 temperature_low;
+	u8 reserved[2];
+} __packed;
+
+/* Struct used for both configuration and status commands of thermal
+ * throttling
+ */
+struct wmi_tt_data {
+	/* Enable/Disable TT algorithm for baseband */
+	u8 bb_enabled;
+	u8 reserved0[3];
+	/* Define zones for baseband */
+	struct wmi_tt_zone_limits bb_zones[WMI_NUM_OF_TT_ZONES];
+	/* Enable/Disable TT algorithm for radio */
+	u8 rf_enabled;
+	u8 reserved1[3];
+	/* Define zones for all radio chips */
+	struct wmi_tt_zone_limits rf_zones[WMI_NUM_OF_TT_ZONES];
+} __packed;
+
+/* WMI_SET_THERMAL_THROTTLING_CFG_CMDID */
+struct wmi_set_thermal_throttling_cfg_cmd {
+	/* Command data */
+	struct wmi_tt_data tt_data;
+} __packed;
+
 /* WMI_NEW_STA_CMDID */
 struct wmi_new_sta_cmd {
 	u8 dst_mac[WMI_MAC_LEN];
@@ -1040,7 +1064,6 @@
 	WMI_BF_RXSS_MGMT_DONE_EVENTID			= 0x1839,
 	WMI_RS_MGMT_DONE_EVENTID			= 0x1852,
 	WMI_RF_MGMT_STATUS_EVENTID			= 0x1853,
-	WMI_THERMAL_THROTTLING_STATUS_EVENTID		= 0x1855,
 	WMI_BF_SM_MGMT_DONE_EVENTID			= 0x1838,
 	WMI_RX_MGMT_PACKET_EVENTID			= 0x1840,
 	WMI_TX_MGMT_PACKET_EVENTID			= 0x1841,
@@ -1090,6 +1113,8 @@
 	WMI_BRP_SET_ANT_LIMIT_EVENTID			= 0x1924,
 	WMI_SET_MGMT_RETRY_LIMIT_EVENTID		= 0x1930,
 	WMI_GET_MGMT_RETRY_LIMIT_EVENTID		= 0x1931,
+	WMI_SET_THERMAL_THROTTLING_CFG_EVENTID		= 0x1940,
+	WMI_GET_THERMAL_THROTTLING_CFG_EVENTID		= 0x1941,
 	WMI_TOF_SESSION_END_EVENTID			= 0x1991,
 	WMI_TOF_GET_CAPABILITIES_EVENTID		= 0x1992,
 	WMI_TOF_SET_LCR_EVENTID				= 0x1993,
@@ -1133,13 +1158,6 @@
 	__le32 rf_status;
 } __packed;
 
-/* WMI_THERMAL_THROTTLING_STATUS_EVENTID */
-struct wmi_thermal_throttling_status_event {
-	__le32 time_on_usec;
-	__le32 time_off_usec;
-	__le32 max_txop_length_usec;
-} __packed;
-
 /* WMI_GET_STATUS_DONE_EVENTID */
 struct wmi_get_status_done_event {
 	__le32 is_associated;
@@ -2206,6 +2224,19 @@
 	__le32 aoa_supported_types;
 } __packed;
 
+/* WMI_SET_THERMAL_THROTTLING_CFG_EVENTID */
+struct wmi_set_thermal_throttling_cfg_event {
+	/* wmi_fw_status */
+	u8 status;
+	u8 reserved[3];
+} __packed;
+
+/* WMI_GET_THERMAL_THROTTLING_CFG_EVENTID */
+struct wmi_get_thermal_throttling_cfg_event {
+	/* Status data */
+	struct wmi_tt_data tt_data;
+} __packed;
+
 enum wmi_tof_session_end_status {
 	WMI_TOF_SESSION_END_NO_ERROR		= 0x00,
 	WMI_TOF_SESSION_END_FAIL		= 0x01,
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
index 5eaac13..f877301 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -198,7 +198,7 @@
 	int ret;
 	struct brcmf_if *ifp = netdev_priv(ndev);
 	struct brcmf_pub *drvr = ifp->drvr;
-	struct ethhdr *eh = (struct ethhdr *)(skb->data);
+	struct ethhdr *eh;
 
 	brcmf_dbg(DATA, "Enter, bsscfgidx=%d\n", ifp->bsscfgidx);
 
@@ -211,22 +211,13 @@
 		goto done;
 	}
 
-	/* Make sure there's enough room for any header */
-	if (skb_headroom(skb) < drvr->hdrlen) {
-		struct sk_buff *skb2;
-
-		brcmf_dbg(INFO, "%s: insufficient headroom\n",
+	/* Make sure there's enough writable headroom*/
+	ret = skb_cow_head(skb, drvr->hdrlen);
+	if (ret < 0) {
+		brcmf_err("%s: skb_cow_head failed\n",
 			  brcmf_ifname(ifp));
-		drvr->bus_if->tx_realloc++;
-		skb2 = skb_realloc_headroom(skb, drvr->hdrlen);
 		dev_kfree_skb(skb);
-		skb = skb2;
-		if (skb == NULL) {
-			brcmf_err("%s: skb_realloc_headroom failed\n",
-				  brcmf_ifname(ifp));
-			ret = -ENOMEM;
-			goto done;
-		}
+		goto done;
 	}
 
 	/* validate length for ether packet */
@@ -236,6 +227,8 @@
 		goto done;
 	}
 
+	eh = (struct ethhdr *)(skb->data);
+
 	if (eh->h_proto == htons(ETH_P_PAE))
 		atomic_inc(&ifp->pend_8021x_cnt);
 
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-6000.c b/drivers/net/wireless/intel/iwlwifi/iwl-6000.c
index 0b9f6a7..39335b7 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-6000.c
@@ -371,4 +371,4 @@
 MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL6005_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX));
-MODULE_FIRMWARE(IWL6030_MODULE_FIRMWARE(IWL6000G2B_UCODE_API_MAX));
+MODULE_FIRMWARE(IWL6030_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX));
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
index b88e204..207d8ae 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
@@ -1262,12 +1262,15 @@
 	iwl_trans_d3_suspend(mvm->trans, test, !unified_image);
  out:
 	if (ret < 0) {
-		iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
-		if (mvm->restart_fw > 0) {
-			mvm->restart_fw--;
-			ieee80211_restart_hw(mvm->hw);
-		}
 		iwl_mvm_free_nd(mvm);
+
+		if (!unified_image) {
+			iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
+			if (mvm->restart_fw > 0) {
+				mvm->restart_fw--;
+				ieee80211_restart_hw(mvm->hw);
+			}
+		}
 	}
  out_noreset:
 	mutex_unlock(&mvm->mutex);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
index 7b7d2a1..0bda91f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
@@ -1056,6 +1056,8 @@
 
 	if (ret)
 		return ret;
+	if (count == 0)
+		return 0;
 
 	iwl_mvm_fw_dbg_collect(mvm, FW_DBG_TRIGGER_USER, buf,
 			       (count - 1), NULL);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
index d89d0a1..700d244 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
@@ -784,12 +784,16 @@
 			struct iwl_fw_error_dump_paging *paging;
 			struct page *pages =
 				mvm->fw_paging_db[i].fw_paging_block;
+			dma_addr_t addr = mvm->fw_paging_db[i].fw_paging_phys;
 
 			dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PAGING);
 			dump_data->len = cpu_to_le32(sizeof(*paging) +
 						     PAGING_BLOCK_SIZE);
 			paging = (void *)dump_data->data;
 			paging->index = cpu_to_le32(i);
+			dma_sync_single_for_cpu(mvm->trans->dev, addr,
+						PAGING_BLOCK_SIZE,
+						DMA_BIDIRECTIONAL);
 			memcpy(paging->data, page_address(pages),
 			       PAGING_BLOCK_SIZE);
 			dump_data = iwl_fw_error_next_data(dump_data);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index 8720663..2ec3a91 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -214,6 +214,10 @@
 	memcpy(page_address(mvm->fw_paging_db[0].fw_paging_block),
 	       image->sec[sec_idx].data,
 	       mvm->fw_paging_db[0].fw_paging_size);
+	dma_sync_single_for_device(mvm->trans->dev,
+				   mvm->fw_paging_db[0].fw_paging_phys,
+				   mvm->fw_paging_db[0].fw_paging_size,
+				   DMA_BIDIRECTIONAL);
 
 	IWL_DEBUG_FW(mvm,
 		     "Paging: copied %d CSS bytes to first block\n",
@@ -228,9 +232,16 @@
 	 * loop stop at num_of_paging_blk since that last block is not full.
 	 */
 	for (idx = 1; idx < mvm->num_of_paging_blk; idx++) {
-		memcpy(page_address(mvm->fw_paging_db[idx].fw_paging_block),
+		struct iwl_fw_paging *block = &mvm->fw_paging_db[idx];
+
+		memcpy(page_address(block->fw_paging_block),
 		       image->sec[sec_idx].data + offset,
-		       mvm->fw_paging_db[idx].fw_paging_size);
+		       block->fw_paging_size);
+		dma_sync_single_for_device(mvm->trans->dev,
+					   block->fw_paging_phys,
+					   block->fw_paging_size,
+					   DMA_BIDIRECTIONAL);
+
 
 		IWL_DEBUG_FW(mvm,
 			     "Paging: copied %d paging bytes to block %d\n",
@@ -242,9 +253,15 @@
 
 	/* copy the last paging block */
 	if (mvm->num_of_pages_in_last_blk > 0) {
-		memcpy(page_address(mvm->fw_paging_db[idx].fw_paging_block),
+		struct iwl_fw_paging *block = &mvm->fw_paging_db[idx];
+
+		memcpy(page_address(block->fw_paging_block),
 		       image->sec[sec_idx].data + offset,
 		       FW_PAGING_SIZE * mvm->num_of_pages_in_last_blk);
+		dma_sync_single_for_device(mvm->trans->dev,
+					   block->fw_paging_phys,
+					   block->fw_paging_size,
+					   DMA_BIDIRECTIONAL);
 
 		IWL_DEBUG_FW(mvm,
 			     "Paging: copied %d pages in the last block %d\n",
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
index 6c802ce..a481eb4 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
@@ -409,7 +409,7 @@
 
 	/* ignore nssn smaller than head sn - this can happen due to timeout */
 	if (iwl_mvm_is_sn_less(nssn, ssn, reorder_buf->buf_size))
-		return;
+		goto set_timer;
 
 	while (iwl_mvm_is_sn_less(ssn, nssn, reorder_buf->buf_size)) {
 		int index = ssn % reorder_buf->buf_size;
@@ -432,6 +432,7 @@
 	}
 	reorder_buf->head_sn = nssn;
 
+set_timer:
 	if (reorder_buf->num_stored && !reorder_buf->removed) {
 		u16 index = reorder_buf->head_sn % reorder_buf->buf_size;
 
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index 52de3c6..e64aeb4 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -1466,6 +1466,7 @@
 {
 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 	struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
+	u8 sta_id = mvm_sta->sta_id;
 	int ret;
 
 	lockdep_assert_held(&mvm->mutex);
@@ -1474,7 +1475,7 @@
 		kfree(mvm_sta->dup_data);
 
 	if ((vif->type == NL80211_IFTYPE_STATION &&
-	     mvmvif->ap_sta_id == mvm_sta->sta_id) ||
+	     mvmvif->ap_sta_id == sta_id) ||
 	    iwl_mvm_is_dqa_supported(mvm)){
 		ret = iwl_mvm_drain_sta(mvm, mvm_sta, true);
 		if (ret)
@@ -1497,6 +1498,15 @@
 			iwl_mvm_disable_sta_queues(mvm, vif, mvm_sta);
 
 			/*
+			 * If pending_frames is set at this point - it must be
+			 * driver internal logic error, since queues are empty
+			 * and removed successuly.
+			 * warn on it but set it to 0 anyway to avoid station
+			 * not being removed later in the function
+			 */
+			WARN_ON(atomic_xchg(&mvm->pending_frames[sta_id], 0));
+
+			/*
 			 * If no traffic has gone through the reserved TXQ - it
 			 * is still marked as IWL_MVM_QUEUE_RESERVED, and
 			 * should be manually marked as free again
@@ -1506,7 +1516,7 @@
 			if (WARN((*status != IWL_MVM_QUEUE_RESERVED) &&
 				 (*status != IWL_MVM_QUEUE_FREE),
 				 "sta_id %d reserved txq %d status %d",
-				 mvm_sta->sta_id, reserved_txq, *status)) {
+				 sta_id, reserved_txq, *status)) {
 				spin_unlock_bh(&mvm->queue_info_lock);
 				return -EINVAL;
 			}
@@ -1516,7 +1526,7 @@
 		}
 
 		if (vif->type == NL80211_IFTYPE_STATION &&
-		    mvmvif->ap_sta_id == mvm_sta->sta_id) {
+		    mvmvif->ap_sta_id == sta_id) {
 			/* if associated - we can't remove the AP STA now */
 			if (vif->bss_conf.assoc)
 				return ret;
@@ -1525,7 +1535,7 @@
 			mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
 
 			/* clear d0i3_ap_sta_id if no longer relevant */
-			if (mvm->d0i3_ap_sta_id == mvm_sta->sta_id)
+			if (mvm->d0i3_ap_sta_id == sta_id)
 				mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT;
 		}
 	}
@@ -1534,7 +1544,7 @@
 	 * This shouldn't happen - the TDLS channel switch should be canceled
 	 * before the STA is removed.
 	 */
-	if (WARN_ON_ONCE(mvm->tdls_cs.peer.sta_id == mvm_sta->sta_id)) {
+	if (WARN_ON_ONCE(mvm->tdls_cs.peer.sta_id == sta_id)) {
 		mvm->tdls_cs.peer.sta_id = IWL_MVM_STATION_COUNT;
 		cancel_delayed_work(&mvm->tdls_cs.dwork);
 	}
@@ -1544,21 +1554,20 @@
 	 * calls the drain worker.
 	 */
 	spin_lock_bh(&mvm_sta->lock);
+
 	/*
 	 * There are frames pending on the AC queues for this station.
 	 * We need to wait until all the frames are drained...
 	 */
-	if (atomic_read(&mvm->pending_frames[mvm_sta->sta_id])) {
-		rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id],
+	if (atomic_read(&mvm->pending_frames[sta_id])) {
+		rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id],
 				   ERR_PTR(-EBUSY));
 		spin_unlock_bh(&mvm_sta->lock);
 
 		/* disable TDLS sta queues on drain complete */
 		if (sta->tdls) {
-			mvm->tfd_drained[mvm_sta->sta_id] =
-							mvm_sta->tfd_queue_msk;
-			IWL_DEBUG_TDLS(mvm, "Draining TDLS sta %d\n",
-				       mvm_sta->sta_id);
+			mvm->tfd_drained[sta_id] = mvm_sta->tfd_queue_msk;
+			IWL_DEBUG_TDLS(mvm, "Draining TDLS sta %d\n", sta_id);
 		}
 
 		ret = iwl_mvm_drain_sta(mvm, mvm_sta, true);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
index 66957ac..0556d13 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
@@ -202,7 +202,6 @@
 			struct iwl_tx_cmd *tx_cmd,
 			struct ieee80211_tx_info *info, u8 sta_id)
 {
-	struct ieee80211_tx_info *skb_info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_hdr *hdr = (void *)skb->data;
 	__le16 fc = hdr->frame_control;
 	u32 tx_flags = le32_to_cpu(tx_cmd->tx_flags);
@@ -284,9 +283,8 @@
 		tx_flags |= TX_CMD_FLG_WRITE_TX_POWER;
 
 	tx_cmd->tx_flags = cpu_to_le32(tx_flags);
-	/* Total # bytes to be transmitted */
-	tx_cmd->len = cpu_to_le16((u16)skb->len +
-		(uintptr_t)skb_info->driver_data[0]);
+	/* Total # bytes to be transmitted - PCIe code will adjust for A-MSDU */
+	tx_cmd->len = cpu_to_le16((u16)skb->len);
 	tx_cmd->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
 	tx_cmd->sta_id = sta_id;
 
@@ -459,7 +457,6 @@
 		      struct ieee80211_sta *sta, u8 sta_id)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	struct ieee80211_tx_info *skb_info = IEEE80211_SKB_CB(skb);
 	struct iwl_device_cmd *dev_cmd;
 	struct iwl_tx_cmd *tx_cmd;
 
@@ -479,12 +476,18 @@
 
 	iwl_mvm_set_tx_cmd_rate(mvm, tx_cmd, info, sta, hdr->frame_control);
 
+	return dev_cmd;
+}
+
+static void iwl_mvm_skb_prepare_status(struct sk_buff *skb,
+				       struct iwl_device_cmd *cmd)
+{
+	struct ieee80211_tx_info *skb_info = IEEE80211_SKB_CB(skb);
+
 	memset(&skb_info->status, 0, sizeof(skb_info->status));
 	memset(skb_info->driver_data, 0, sizeof(skb_info->driver_data));
 
-	skb_info->driver_data[1] = dev_cmd;
-
-	return dev_cmd;
+	skb_info->driver_data[1] = cmd;
 }
 
 static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm,
@@ -550,9 +553,6 @@
 			  info.hw_queue != info.control.vif->cab_queue)))
 		return -1;
 
-	/* This holds the amsdu headers length */
-	skb_info->driver_data[0] = (void *)(uintptr_t)0;
-
 	queue = info.hw_queue;
 
 	/*
@@ -563,9 +563,10 @@
 	 * (this is not possible for unicast packets as a TLDS discovery
 	 * response are sent without a station entry); otherwise use the
 	 * AUX station.
-	 * In DQA mode, if vif is of type STATION and frames are not multicast,
-	 * they should be sent from the BSS queue. For example, TDLS setup
-	 * frames should be sent on this queue, as they go through the AP.
+	 * In DQA mode, if vif is of type STATION and frames are not multicast
+	 * or offchannel, they should be sent from the BSS queue.
+	 * For example, TDLS setup frames should be sent on this queue,
+	 * as they go through the AP.
 	 */
 	sta_id = mvm->aux_sta.sta_id;
 	if (info.control.vif) {
@@ -587,7 +588,8 @@
 			if (ap_sta_id != IWL_MVM_STATION_COUNT)
 				sta_id = ap_sta_id;
 		} else if (iwl_mvm_is_dqa_supported(mvm) &&
-			   info.control.vif->type == NL80211_IFTYPE_STATION) {
+			   info.control.vif->type == NL80211_IFTYPE_STATION &&
+			   queue != mvm->aux_queue) {
 			queue = IWL_MVM_DQA_BSS_CLIENT_QUEUE;
 		}
 	}
@@ -598,6 +600,9 @@
 	if (!dev_cmd)
 		return -1;
 
+	/* From now on, we cannot access info->control */
+	iwl_mvm_skb_prepare_status(skb, dev_cmd);
+
 	tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload;
 
 	/* Copy MAC header from skb into command buffer */
@@ -634,7 +639,7 @@
 	unsigned int num_subframes, tcp_payload_len, subf_len, max_amsdu_len;
 	bool ipv4 = (skb->protocol == htons(ETH_P_IP));
 	u16 ip_base_id = ipv4 ? ntohs(ip_hdr(skb)->id) : 0;
-	u16 amsdu_add, snap_ip_tcp, pad, i = 0;
+	u16 snap_ip_tcp, pad, i = 0;
 	unsigned int dbg_max_amsdu_len;
 	netdev_features_t netdev_features = NETIF_F_CSUM_MASK | NETIF_F_SG;
 	u8 *qc, tid, txf;
@@ -736,21 +741,6 @@
 
 	/* This skb fits in one single A-MSDU */
 	if (num_subframes * mss >= tcp_payload_len) {
-		struct ieee80211_tx_info *skb_info = IEEE80211_SKB_CB(skb);
-
-		/*
-		 * Compute the length of all the data added for the A-MSDU.
-		 * This will be used to compute the length to write in the TX
-		 * command. We have: SNAP + IP + TCP for n -1 subframes and
-		 * ETH header for n subframes. Note that the original skb
-		 * already had one set of SNAP / IP / TCP headers.
-		 */
-		num_subframes = DIV_ROUND_UP(tcp_payload_len, mss);
-		amsdu_add = num_subframes * sizeof(struct ethhdr) +
-			(num_subframes - 1) * (snap_ip_tcp + pad);
-		/* This holds the amsdu headers length */
-		skb_info->driver_data[0] = (void *)(uintptr_t)amsdu_add;
-
 		__skb_queue_tail(mpdus_skb, skb);
 		return 0;
 	}
@@ -789,14 +779,6 @@
 			ip_hdr(tmp)->id = htons(ip_base_id + i * num_subframes);
 
 		if (tcp_payload_len > mss) {
-			struct ieee80211_tx_info *skb_info =
-				IEEE80211_SKB_CB(tmp);
-
-			num_subframes = DIV_ROUND_UP(tcp_payload_len, mss);
-			amsdu_add = num_subframes * sizeof(struct ethhdr) +
-				(num_subframes - 1) * (snap_ip_tcp + pad);
-			skb_info->driver_data[0] =
-				(void *)(uintptr_t)amsdu_add;
 			skb_shinfo(tmp)->gso_size = mss;
 		} else {
 			qc = ieee80211_get_qos_ctl((void *)tmp->data);
@@ -908,7 +890,6 @@
 		goto drop;
 
 	tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload;
-	/* From now on, we cannot access info->control */
 
 	/*
 	 * we handle that entirely ourselves -- for uAPSD the firmware
@@ -1015,6 +996,9 @@
 	IWL_DEBUG_TX(mvm, "TX to [%d|%d] Q:%d - seq: 0x%x\n", mvmsta->sta_id,
 		     tid, txq_id, IEEE80211_SEQ_TO_SN(seq_number));
 
+	/* From now on, we cannot access info->control */
+	iwl_mvm_skb_prepare_status(skb, dev_cmd);
+
 	if (iwl_trans_tx(mvm->trans, skb, dev_cmd, txq_id))
 		goto drop_unlock_sta;
 
@@ -1024,7 +1008,10 @@
 	spin_unlock(&mvmsta->lock);
 
 	/* Increase pending frames count if this isn't AMPDU */
-	if (!is_ampdu)
+	if ((iwl_mvm_is_dqa_supported(mvm) &&
+	     mvmsta->tid_data[tx_cmd->tid_tspec].state != IWL_AGG_ON &&
+	     mvmsta->tid_data[tx_cmd->tid_tspec].state != IWL_AGG_STARTING) ||
+	    (!iwl_mvm_is_dqa_supported(mvm) && !is_ampdu))
 		atomic_inc(&mvm->pending_frames[mvmsta->sta_id]);
 
 	return 0;
@@ -1040,7 +1027,6 @@
 		   struct ieee80211_sta *sta)
 {
 	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
-	struct ieee80211_tx_info *skb_info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_tx_info info;
 	struct sk_buff_head mpdus_skbs;
 	unsigned int payload_len;
@@ -1054,9 +1040,6 @@
 
 	memcpy(&info, skb->cb, sizeof(info));
 
-	/* This holds the amsdu headers length */
-	skb_info->driver_data[0] = (void *)(uintptr_t)0;
-
 	if (!skb_is_gso(skb))
 		return iwl_mvm_tx_mpdu(mvm, skb, &info, sta);
 
@@ -1295,8 +1278,6 @@
 
 		memset(&info->status, 0, sizeof(info->status));
 
-		info->flags &= ~IEEE80211_TX_CTL_AMPDU;
-
 		/* inform mac80211 about what happened with the frame */
 		switch (status & TX_STATUS_MSK) {
 		case TX_STATUS_SUCCESS:
@@ -1319,10 +1300,11 @@
 			(void *)(uintptr_t)le32_to_cpu(tx_resp->initial_rate);
 
 		/* Single frame failure in an AMPDU queue => send BAR */
-		if (txq_id >= mvm->first_agg_queue &&
+		if (info->flags & IEEE80211_TX_CTL_AMPDU &&
 		    !(info->flags & IEEE80211_TX_STAT_ACK) &&
 		    !(info->flags & IEEE80211_TX_STAT_TX_FILTERED))
 			info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
+		info->flags &= ~IEEE80211_TX_CTL_AMPDU;
 
 		/* W/A FW bug: seq_ctl is wrong when the status isn't success */
 		if (status != TX_STATUS_SUCCESS) {
@@ -1357,7 +1339,7 @@
 		ieee80211_tx_status(mvm->hw, skb);
 	}
 
-	if (txq_id >= mvm->first_agg_queue) {
+	if (iwl_mvm_is_dqa_supported(mvm) || txq_id >= mvm->first_agg_queue) {
 		/* If this is an aggregation queue, we use the ssn since:
 		 * ssn = wifi seq_num % 256.
 		 * The seq_ctl is the sequence control of the packet to which
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
index cac6d99..e3cede9 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
@@ -279,7 +279,7 @@
 	bool frozen;
 	u8 active;
 	bool ampdu;
-	bool block;
+	int block;
 	unsigned long wd_timeout;
 	struct sk_buff_head overflow_q;
 
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index ae95533..10ef44e 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -868,17 +868,13 @@
 				      int cpu,
 				      int *first_ucode_section)
 {
-	int shift_param;
 	int i, ret = 0;
 	u32 last_read_idx = 0;
 
-	if (cpu == 1) {
-		shift_param = 0;
+	if (cpu == 1)
 		*first_ucode_section = 0;
-	} else {
-		shift_param = 16;
+	else
 		(*first_ucode_section)++;
-	}
 
 	for (i = *first_ucode_section; i < IWL_UCODE_SECTION_MAX; i++) {
 		last_read_idx = i;
@@ -2933,16 +2929,12 @@
 				       PCIE_LINK_STATE_CLKPM);
 	}
 
-	if (cfg->mq_rx_supported)
-		addr_size = 64;
-	else
-		addr_size = 36;
-
 	if (cfg->use_tfh) {
+		addr_size = 64;
 		trans_pcie->max_tbs = IWL_TFH_NUM_TBS;
 		trans_pcie->tfd_size = sizeof(struct iwl_tfh_tfd);
-
 	} else {
+		addr_size = 36;
 		trans_pcie->max_tbs = IWL_NUM_OF_TBS;
 		trans_pcie->tfd_size = sizeof(struct iwl_tfd);
 	}
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
index 5f840f1..e1bfc95 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
@@ -2096,6 +2096,7 @@
 				   struct iwl_cmd_meta *out_meta,
 				   struct iwl_device_cmd *dev_cmd, u16 tb1_len)
 {
+	struct iwl_tx_cmd *tx_cmd = (void *)dev_cmd->payload;
 	struct iwl_trans_pcie *trans_pcie = txq->trans_pcie;
 	struct ieee80211_hdr *hdr = (void *)skb->data;
 	unsigned int snap_ip_tcp_hdrlen, ip_hdrlen, total_len, hdr_room;
@@ -2145,6 +2146,13 @@
 	 */
 	skb_pull(skb, hdr_len + iv_len);
 
+	/*
+	 * Remove the length of all the headers that we don't actually
+	 * have in the MPDU by themselves, but that we duplicate into
+	 * all the different MSDUs inside the A-MSDU.
+	 */
+	le16_add_cpu(&tx_cmd->len, -snap_ip_tcp_hdrlen);
+
 	tso_start(skb, &tso);
 
 	while (total_len) {
@@ -2155,7 +2163,7 @@
 		unsigned int hdr_tb_len;
 		dma_addr_t hdr_tb_phys;
 		struct tcphdr *tcph;
-		u8 *iph;
+		u8 *iph, *subf_hdrs_start = hdr_page->pos;
 
 		total_len -= data_left;
 
@@ -2216,6 +2224,8 @@
 				       hdr_tb_len, false);
 		trace_iwlwifi_dev_tx_tso_chunk(trans->dev, start_hdr,
 					       hdr_tb_len);
+		/* add this subframe's headers' length to the tx_cmd */
+		le16_add_cpu(&tx_cmd->len, hdr_page->pos - subf_hdrs_start);
 
 		/* prepare the start_hdr for the next subframe */
 		start_hdr = hdr_page->pos;
@@ -2408,9 +2418,10 @@
 		tb1_len = len;
 	}
 
-	/* The first TB points to bi-directional DMA data */
-	memcpy(&txq->first_tb_bufs[txq->write_ptr], &dev_cmd->hdr,
-	       IWL_FIRST_TB_SIZE);
+	/*
+	 * The first TB points to bi-directional DMA data, we'll
+	 * memcpy the data into it later.
+	 */
 	iwl_pcie_txq_build_tfd(trans, txq, tb0_phys,
 			       IWL_FIRST_TB_SIZE, true);
 
@@ -2434,6 +2445,10 @@
 		goto out_err;
 	}
 
+	/* building the A-MSDU might have changed this data, so memcpy it now */
+	memcpy(&txq->first_tb_bufs[txq->write_ptr], &dev_cmd->hdr,
+	       IWL_FIRST_TB_SIZE);
+
 	tfd = iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr);
 	/* Set up entry for this TFD in Tx byte-count array */
 	iwl_pcie_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len),
diff --git a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c
index c47d636..a75013a 100644
--- a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c
+++ b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c
@@ -101,13 +101,6 @@
 {
 	struct txpd *local_tx_pd;
 	struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb);
-	unsigned int pad;
-	int headroom = (priv->adapter->iface_type ==
-			MWIFIEX_USB) ? 0 : INTF_HEADER_LEN;
-
-	pad = ((void *)skb->data - sizeof(*local_tx_pd) -
-		headroom - NULL) & (MWIFIEX_DMA_ALIGN_SZ - 1);
-	skb_push(skb, pad);
 
 	skb_push(skb, sizeof(*local_tx_pd));
 
@@ -121,12 +114,10 @@
 	local_tx_pd->bss_num = priv->bss_num;
 	local_tx_pd->bss_type = priv->bss_type;
 	/* Always zero as the data is followed by struct txpd */
-	local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd) +
-						 pad);
+	local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd));
 	local_tx_pd->tx_pkt_type = cpu_to_le16(PKT_TYPE_AMSDU);
 	local_tx_pd->tx_pkt_length = cpu_to_le16(skb->len -
-						 sizeof(*local_tx_pd) -
-						 pad);
+						 sizeof(*local_tx_pd));
 
 	if (tx_info->flags & MWIFIEX_BUF_FLAG_TDLS_PKT)
 		local_tx_pd->flags |= MWIFIEX_TXPD_FLAGS_TDLS_PACKET;
@@ -190,7 +181,11 @@
 				       ra_list_flags);
 		return -1;
 	}
-	skb_reserve(skb_aggr, MWIFIEX_MIN_DATA_HEADER_LEN);
+
+	/* skb_aggr->data already 64 byte align, just reserve bus interface
+	 * header and txpd.
+	 */
+	skb_reserve(skb_aggr, headroom + sizeof(struct txpd));
 	tx_info_aggr =  MWIFIEX_SKB_TXCB(skb_aggr);
 
 	memset(tx_info_aggr, 0, sizeof(*tx_info_aggr));
diff --git a/drivers/net/wireless/marvell/mwifiex/debugfs.c b/drivers/net/wireless/marvell/mwifiex/debugfs.c
index b9284b5..ae2b69d 100644
--- a/drivers/net/wireless/marvell/mwifiex/debugfs.c
+++ b/drivers/net/wireless/marvell/mwifiex/debugfs.c
@@ -114,7 +114,8 @@
 	if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) {
 		p += sprintf(p, "multicast_count=\"%d\"\n",
 			     netdev_mc_count(netdev));
-		p += sprintf(p, "essid=\"%s\"\n", info.ssid.ssid);
+		p += sprintf(p, "essid=\"%.*s\"\n", info.ssid.ssid_len,
+			     info.ssid.ssid);
 		p += sprintf(p, "bssid=\"%pM\"\n", info.bssid);
 		p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan);
 		p += sprintf(p, "country_code = \"%s\"\n", info.country_code);
diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c
index 644f3a2..1532ac9 100644
--- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c
@@ -1159,8 +1159,6 @@
 			encrypt_key.is_rx_seq_valid = true;
 		}
 	} else {
-		if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP)
-			return 0;
 		encrypt_key.key_disable = true;
 		if (mac_addr)
 			memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN);
diff --git a/drivers/net/wireless/ti/wl18xx/event.c b/drivers/net/wireless/ti/wl18xx/event.c
index b36ce18..86fa0fc 100644
--- a/drivers/net/wireless/ti/wl18xx/event.c
+++ b/drivers/net/wireless/ti/wl18xx/event.c
@@ -218,5 +218,33 @@
 	if (vector & FW_LOGGER_INDICATION)
 		wlcore_event_fw_logger(wl);
 
+	if (vector & RX_BA_WIN_SIZE_CHANGE_EVENT_ID) {
+		struct wl12xx_vif *wlvif;
+		struct ieee80211_vif *vif;
+		struct ieee80211_sta *sta;
+		u8 link_id = mbox->rx_ba_link_id;
+		u8 win_size = mbox->rx_ba_win_size;
+		const u8 *addr;
+
+		wlvif = wl->links[link_id].wlvif;
+		vif = wl12xx_wlvif_to_vif(wlvif);
+
+		/* Update RX aggregation window size and call
+		 * MAC routine to stop active RX aggregations for this link
+		 */
+		if (wlvif->bss_type != BSS_TYPE_AP_BSS)
+			addr = vif->bss_conf.bssid;
+		else
+			addr = wl->links[link_id].addr;
+
+		sta = ieee80211_find_sta(vif, addr);
+		if (sta) {
+			sta->max_rx_aggregation_subframes = win_size;
+			ieee80211_stop_rx_ba_session(vif,
+						wl->links[link_id].ba_bitmap,
+						addr);
+		}
+	}
+
 	return 0;
 }
diff --git a/drivers/net/wireless/ti/wl18xx/event.h b/drivers/net/wireless/ti/wl18xx/event.h
index ce8ea9c0..4af297f 100644
--- a/drivers/net/wireless/ti/wl18xx/event.h
+++ b/drivers/net/wireless/ti/wl18xx/event.h
@@ -38,6 +38,7 @@
 	REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID      = BIT(18),
 	DFS_CHANNELS_CONFIG_COMPLETE_EVENT       = BIT(19),
 	PERIODIC_SCAN_REPORT_EVENT_ID            = BIT(20),
+	RX_BA_WIN_SIZE_CHANGE_EVENT_ID           = BIT(21),
 	SMART_CONFIG_SYNC_EVENT_ID               = BIT(22),
 	SMART_CONFIG_DECODE_EVENT_ID             = BIT(23),
 	TIME_SYNC_EVENT_ID                       = BIT(24),
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index 06d6943..5bdf7a0 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -1041,7 +1041,8 @@
 		SMART_CONFIG_SYNC_EVENT_ID |
 		SMART_CONFIG_DECODE_EVENT_ID |
 		TIME_SYNC_EVENT_ID |
-		FW_LOGGER_INDICATION;
+		FW_LOGGER_INDICATION |
+		RX_BA_WIN_SIZE_CHANGE_EVENT_ID;
 
 	wl->ap_event_mask = MAX_TX_FAILURE_EVENT_ID;
 
diff --git a/drivers/net/wireless/ti/wlcore/acx.c b/drivers/net/wireless/ti/wlcore/acx.c
index 26cc23f..a485999 100644
--- a/drivers/net/wireless/ti/wlcore/acx.c
+++ b/drivers/net/wireless/ti/wlcore/acx.c
@@ -1419,7 +1419,8 @@
 
 /* setup BA session receiver setting in the FW. */
 int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index,
-				       u16 ssn, bool enable, u8 peer_hlid)
+				       u16 ssn, bool enable, u8 peer_hlid,
+				       u8 win_size)
 {
 	struct wl1271_acx_ba_receiver_setup *acx;
 	int ret;
@@ -1435,7 +1436,7 @@
 	acx->hlid = peer_hlid;
 	acx->tid = tid_index;
 	acx->enable = enable;
-	acx->win_size = wl->conf.ht.rx_ba_win_size;
+	acx->win_size =	win_size;
 	acx->ssn = ssn;
 
 	ret = wlcore_cmd_configure_failsafe(wl, ACX_BA_SESSION_RX_SETUP, acx,
diff --git a/drivers/net/wireless/ti/wlcore/acx.h b/drivers/net/wireless/ti/wlcore/acx.h
index 6321ed4..f46d7fd 100644
--- a/drivers/net/wireless/ti/wlcore/acx.h
+++ b/drivers/net/wireless/ti/wlcore/acx.h
@@ -1113,7 +1113,8 @@
 int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl,
 				       struct wl12xx_vif *wlvif);
 int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index,
-				       u16 ssn, bool enable, u8 peer_hlid);
+				       u16 ssn, bool enable, u8 peer_hlid,
+				       u8 win_size);
 int wl12xx_acx_tsf_info(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 			u64 *mactime);
 int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 471521a..5438975 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -5285,7 +5285,9 @@
 		}
 
 		ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
-							 hlid);
+				hlid,
+				params->buf_size);
+
 		if (!ret) {
 			*ba_bitmap |= BIT(tid);
 			wl->ba_rx_session_count++;
@@ -5306,7 +5308,7 @@
 		}
 
 		ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
-							 hlid);
+							 hlid, 0);
 		if (!ret) {
 			*ba_bitmap &= ~BIT(tid);
 			wl->ba_rx_session_count--;
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index fe00f91..7dc726d 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -456,6 +456,7 @@
 config PHY_TUSB1210
 	tristate "TI TUSB1210 ULPI PHY module"
 	depends on USB_ULPI_BUS
+	depends on EXTCON || !EXTCON # if EXTCON=m, this cannot be built-in
 	select GENERIC_PHY
 	help
 	  Support for TI TUSB1210 USB ULPI PHY.
diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c
index 5fdb4e9..7fca7aa 100644
--- a/drivers/platform/msm/gsi/gsi.c
+++ b/drivers/platform/msm/gsi/gsi.c
@@ -649,6 +649,13 @@
 			GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_BMSK) >>
 			GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_SHFT;
 		break;
+	case GSI_VER_2_0:
+		reg = gsi_readl(gsi_ctx->base +
+			GSI_V2_0_EE_n_GSI_HW_PARAM_2_OFFS(gsi_ctx->per.ee));
+		reg = (reg &
+			GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_BMSK) >>
+			GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_SHFT;
+		break;
 	default:
 		GSIERR("bad gsi version %d\n", ver);
 		WARN_ON(1);
@@ -684,6 +691,13 @@
 			GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_BMSK) >>
 			GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_SHFT;
 		break;
+	case GSI_VER_2_0:
+		reg = gsi_readl(gsi_ctx->base +
+			GSI_V2_0_EE_n_GSI_HW_PARAM_2_OFFS(gsi_ctx->per.ee));
+		reg = (reg &
+			GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_BMSK) >>
+			GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_SHFT;
+		break;
 	default:
 		GSIERR("bad gsi version %d\n", ver);
 		WARN_ON(1);
diff --git a/drivers/platform/msm/gsi/gsi_dbg.c b/drivers/platform/msm/gsi/gsi_dbg.c
index f5e23c68..154ac26 100644
--- a/drivers/platform/msm/gsi/gsi_dbg.c
+++ b/drivers/platform/msm/gsi/gsi_dbg.c
@@ -293,6 +293,16 @@
 		val = gsi_readl(gsi_ctx->base +
 			GSI_V1_3_EE_n_GSI_HW_PARAM_2_OFFS(gsi_ctx->per.ee));
 		TERR("EE%2d HW_PARAM_2 0x%x\n", gsi_ctx->per.ee, val);
+	} else if (gsi_ctx->per.ver == GSI_VER_2_0) {
+		val = gsi_readl(gsi_ctx->base +
+			GSI_V1_3_EE_n_GSI_HW_PARAM_0_OFFS(gsi_ctx->per.ee));
+		TERR("EE%2d HW_PARAM_0 0x%x\n", gsi_ctx->per.ee, val);
+		val = gsi_readl(gsi_ctx->base +
+			GSI_V1_3_EE_n_GSI_HW_PARAM_1_OFFS(gsi_ctx->per.ee));
+		TERR("EE%2d HW_PARAM_1 0x%x\n", gsi_ctx->per.ee, val);
+		val = gsi_readl(gsi_ctx->base +
+			GSI_V2_0_EE_n_GSI_HW_PARAM_2_OFFS(gsi_ctx->per.ee));
+		TERR("EE%2d HW_PARAM_2 0x%x\n", gsi_ctx->per.ee, val);
 	} else {
 		WARN_ON(1);
 	}
diff --git a/drivers/platform/msm/gsi/gsi_reg.h b/drivers/platform/msm/gsi/gsi_reg.h
index 653cdd4..7817613 100644
--- a/drivers/platform/msm/gsi/gsi_reg.h
+++ b/drivers/platform/msm/gsi/gsi_reg.h
@@ -1518,6 +1518,34 @@
 #define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_ONE_KB_FVAL 0x0
 #define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_KB_FVAL 0x1
 
+/* v2.0 */
+#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_OFFS(n) \
+	(GSI_GSI_REG_BASE_OFFS + 0x0001f040 + 0x4000 * (n))
+#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_RMSK 0x7fff
+#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_MAXn 2
+#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_BMSK 0x38000000
+#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_SHFT 0x1b
+#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_BMSK 0x7F80000
+#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_SHFT 0x13
+#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_BMSK 0x70000
+#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_SHFT 0x10
+#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_BMSK 0x8000
+#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_SHFT 0xf
+#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_BMSK 0x4000
+#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_SHFT 0xe
+#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_BMSK 0x2000
+#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_SHFT 0xd
+#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_BMSK 0x1f00
+#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_SHFT 0x8
+#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_BMSK 0xf8
+#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_SHFT 0x3
+#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_BMSK 0x7
+#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_SHFT 0x0
+#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_ONE_KB_FVAL 0x0
+#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_KB_FVAL 0x1
+#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_N_HALF_KB_FVAL 0x2
+#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_THREE_KB_FVAL 0x3
+
 #define GSI_EE_n_GSI_SW_VERSION_OFFS(n) \
 	(GSI_GSI_REG_BASE_OFFS + 0x0001f044 + 0x4000 * (n))
 #define GSI_EE_n_GSI_SW_VERSION_RMSK 0xffffffff
diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c
index e958433..50171fd 100644
--- a/drivers/power/supply/bq24190_charger.c
+++ b/drivers/power/supply/bq24190_charger.c
@@ -144,10 +144,7 @@
  * so the first read after a fault returns the latched value and subsequent
  * reads return the current value.  In order to return the fault status
  * to the user, have the interrupt handler save the reg's value and retrieve
- * it in the appropriate health/status routine.  Each routine has its own
- * flag indicating whether it should use the value stored by the last run
- * of the interrupt handler or do an actual reg read.  That way each routine
- * can report back whatever fault may have occured.
+ * it in the appropriate health/status routine.
  */
 struct bq24190_dev_info {
 	struct i2c_client		*client;
@@ -159,10 +156,6 @@
 	unsigned int			gpio_int;
 	unsigned int			irq;
 	struct mutex			f_reg_lock;
-	bool				first_time;
-	bool				charger_health_valid;
-	bool				battery_health_valid;
-	bool				battery_status_valid;
 	u8				f_reg;
 	u8				ss_reg;
 	u8				watchdog;
@@ -636,21 +629,11 @@
 		union power_supply_propval *val)
 {
 	u8 v;
-	int health, ret;
+	int health;
 
 	mutex_lock(&bdi->f_reg_lock);
-
-	if (bdi->charger_health_valid) {
-		v = bdi->f_reg;
-		bdi->charger_health_valid = false;
-		mutex_unlock(&bdi->f_reg_lock);
-	} else {
-		mutex_unlock(&bdi->f_reg_lock);
-
-		ret = bq24190_read(bdi, BQ24190_REG_F, &v);
-		if (ret < 0)
-			return ret;
-	}
+	v = bdi->f_reg;
+	mutex_unlock(&bdi->f_reg_lock);
 
 	if (v & BQ24190_REG_F_BOOST_FAULT_MASK) {
 		/*
@@ -937,18 +920,8 @@
 	int status, ret;
 
 	mutex_lock(&bdi->f_reg_lock);
-
-	if (bdi->battery_status_valid) {
-		chrg_fault = bdi->f_reg;
-		bdi->battery_status_valid = false;
-		mutex_unlock(&bdi->f_reg_lock);
-	} else {
-		mutex_unlock(&bdi->f_reg_lock);
-
-		ret = bq24190_read(bdi, BQ24190_REG_F, &chrg_fault);
-		if (ret < 0)
-			return ret;
-	}
+	chrg_fault = bdi->f_reg;
+	mutex_unlock(&bdi->f_reg_lock);
 
 	chrg_fault &= BQ24190_REG_F_CHRG_FAULT_MASK;
 	chrg_fault >>= BQ24190_REG_F_CHRG_FAULT_SHIFT;
@@ -996,21 +969,11 @@
 		union power_supply_propval *val)
 {
 	u8 v;
-	int health, ret;
+	int health;
 
 	mutex_lock(&bdi->f_reg_lock);
-
-	if (bdi->battery_health_valid) {
-		v = bdi->f_reg;
-		bdi->battery_health_valid = false;
-		mutex_unlock(&bdi->f_reg_lock);
-	} else {
-		mutex_unlock(&bdi->f_reg_lock);
-
-		ret = bq24190_read(bdi, BQ24190_REG_F, &v);
-		if (ret < 0)
-			return ret;
-	}
+	v = bdi->f_reg;
+	mutex_unlock(&bdi->f_reg_lock);
 
 	if (v & BQ24190_REG_F_BAT_FAULT_MASK) {
 		health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
@@ -1197,9 +1160,12 @@
 static irqreturn_t bq24190_irq_handler_thread(int irq, void *data)
 {
 	struct bq24190_dev_info *bdi = data;
-	bool alert_userspace = false;
+	const u8 battery_mask_ss = BQ24190_REG_SS_CHRG_STAT_MASK;
+	const u8 battery_mask_f = BQ24190_REG_F_BAT_FAULT_MASK
+				| BQ24190_REG_F_NTC_FAULT_MASK;
+	bool alert_charger = false, alert_battery = false;
 	u8 ss_reg = 0, f_reg = 0;
-	int ret;
+	int i, ret;
 
 	pm_runtime_get_sync(bdi->dev);
 
@@ -1209,6 +1175,32 @@
 		goto out;
 	}
 
+	i = 0;
+	do {
+		ret = bq24190_read(bdi, BQ24190_REG_F, &f_reg);
+		if (ret < 0) {
+			dev_err(bdi->dev, "Can't read F reg: %d\n", ret);
+			goto out;
+		}
+	} while (f_reg && ++i < 2);
+
+	if (f_reg != bdi->f_reg) {
+		dev_info(bdi->dev,
+			"Fault: boost %d, charge %d, battery %d, ntc %d\n",
+			!!(f_reg & BQ24190_REG_F_BOOST_FAULT_MASK),
+			!!(f_reg & BQ24190_REG_F_CHRG_FAULT_MASK),
+			!!(f_reg & BQ24190_REG_F_BAT_FAULT_MASK),
+			!!(f_reg & BQ24190_REG_F_NTC_FAULT_MASK));
+
+		mutex_lock(&bdi->f_reg_lock);
+		if ((bdi->f_reg & battery_mask_f) != (f_reg & battery_mask_f))
+			alert_battery = true;
+		if ((bdi->f_reg & ~battery_mask_f) != (f_reg & ~battery_mask_f))
+			alert_charger = true;
+		bdi->f_reg = f_reg;
+		mutex_unlock(&bdi->f_reg_lock);
+	}
+
 	if (ss_reg != bdi->ss_reg) {
 		/*
 		 * The device is in host mode so when PG_STAT goes from 1->0
@@ -1225,47 +1217,17 @@
 					ret);
 		}
 
+		if ((bdi->ss_reg & battery_mask_ss) != (ss_reg & battery_mask_ss))
+			alert_battery = true;
+		if ((bdi->ss_reg & ~battery_mask_ss) != (ss_reg & ~battery_mask_ss))
+			alert_charger = true;
 		bdi->ss_reg = ss_reg;
-		alert_userspace = true;
 	}
 
-	mutex_lock(&bdi->f_reg_lock);
-
-	ret = bq24190_read(bdi, BQ24190_REG_F, &f_reg);
-	if (ret < 0) {
-		mutex_unlock(&bdi->f_reg_lock);
-		dev_err(bdi->dev, "Can't read F reg: %d\n", ret);
-		goto out;
-	}
-
-	if (f_reg != bdi->f_reg) {
-		bdi->f_reg = f_reg;
-		bdi->charger_health_valid = true;
-		bdi->battery_health_valid = true;
-		bdi->battery_status_valid = true;
-
-		alert_userspace = true;
-	}
-
-	mutex_unlock(&bdi->f_reg_lock);
-
-	/*
-	 * Sometimes bq24190 gives a steady trickle of interrupts even
-	 * though the watchdog timer is turned off and neither the STATUS
-	 * nor FAULT registers have changed.  Weed out these sprurious
-	 * interrupts so userspace isn't alerted for no reason.
-	 * In addition, the chip always generates an interrupt after
-	 * register reset so we should ignore that one (the very first
-	 * interrupt received).
-	 */
-	if (alert_userspace) {
-		if (!bdi->first_time) {
-			power_supply_changed(bdi->charger);
-			power_supply_changed(bdi->battery);
-		} else {
-			bdi->first_time = false;
-		}
-	}
+	if (alert_charger)
+		power_supply_changed(bdi->charger);
+	if (alert_battery)
+		power_supply_changed(bdi->battery);
 
 out:
 	pm_runtime_put_sync(bdi->dev);
@@ -1300,6 +1262,10 @@
 		goto out;
 
 	ret = bq24190_set_mode_host(bdi);
+	if (ret < 0)
+		goto out;
+
+	ret = bq24190_read(bdi, BQ24190_REG_SS, &bdi->ss_reg);
 out:
 	pm_runtime_put_sync(bdi->dev);
 	return ret;
@@ -1375,10 +1341,8 @@
 	bdi->model = id->driver_data;
 	strncpy(bdi->model_name, id->name, I2C_NAME_SIZE);
 	mutex_init(&bdi->f_reg_lock);
-	bdi->first_time = true;
-	bdi->charger_health_valid = false;
-	bdi->battery_health_valid = false;
-	bdi->battery_status_valid = false;
+	bdi->f_reg = 0;
+	bdi->ss_reg = BQ24190_REG_SS_VBUS_STAT_MASK; /* impossible state */
 
 	i2c_set_clientdata(client, bdi);
 
@@ -1392,22 +1356,13 @@
 		return -EINVAL;
 	}
 
-	ret = devm_request_threaded_irq(dev, bdi->irq, NULL,
-			bq24190_irq_handler_thread,
-			IRQF_TRIGGER_RISING | IRQF_ONESHOT,
-			"bq24190-charger", bdi);
-	if (ret < 0) {
-		dev_err(dev, "Can't set up irq handler\n");
-		goto out1;
-	}
-
 	pm_runtime_enable(dev);
 	pm_runtime_resume(dev);
 
 	ret = bq24190_hw_init(bdi);
 	if (ret < 0) {
 		dev_err(dev, "Hardware init failed\n");
-		goto out2;
+		goto out1;
 	}
 
 	charger_cfg.drv_data = bdi;
@@ -1418,7 +1373,7 @@
 	if (IS_ERR(bdi->charger)) {
 		dev_err(dev, "Can't register charger\n");
 		ret = PTR_ERR(bdi->charger);
-		goto out2;
+		goto out1;
 	}
 
 	battery_cfg.drv_data = bdi;
@@ -1427,24 +1382,34 @@
 	if (IS_ERR(bdi->battery)) {
 		dev_err(dev, "Can't register battery\n");
 		ret = PTR_ERR(bdi->battery);
-		goto out3;
+		goto out2;
 	}
 
 	ret = bq24190_sysfs_create_group(bdi);
 	if (ret) {
 		dev_err(dev, "Can't create sysfs entries\n");
+		goto out3;
+	}
+
+	ret = devm_request_threaded_irq(dev, bdi->irq, NULL,
+			bq24190_irq_handler_thread,
+			IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+			"bq24190-charger", bdi);
+	if (ret < 0) {
+		dev_err(dev, "Can't set up irq handler\n");
 		goto out4;
 	}
 
 	return 0;
 
 out4:
-	power_supply_unregister(bdi->battery);
+	bq24190_sysfs_remove_group(bdi);
 out3:
-	power_supply_unregister(bdi->charger);
+	power_supply_unregister(bdi->battery);
 out2:
-	pm_runtime_disable(dev);
+	power_supply_unregister(bdi->charger);
 out1:
+	pm_runtime_disable(dev);
 	if (bdi->gpio_int)
 		gpio_free(bdi->gpio_int);
 
@@ -1488,12 +1453,13 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct bq24190_dev_info *bdi = i2c_get_clientdata(client);
 
-	bdi->charger_health_valid = false;
-	bdi->battery_health_valid = false;
-	bdi->battery_status_valid = false;
+	bdi->f_reg = 0;
+	bdi->ss_reg = BQ24190_REG_SS_VBUS_STAT_MASK; /* impossible state */
 
 	pm_runtime_get_sync(bdi->dev);
 	bq24190_register_reset(bdi);
+	bq24190_set_mode_host(bdi);
+	bq24190_read(bdi, BQ24190_REG_SS, &bdi->ss_reg);
 	pm_runtime_put_sync(bdi->dev);
 
 	/* Things may have changed while suspended so alert upper layer */
diff --git a/drivers/power/supply/lp8788-charger.c b/drivers/power/supply/lp8788-charger.c
index 7321b72..cd614fe 100644
--- a/drivers/power/supply/lp8788-charger.c
+++ b/drivers/power/supply/lp8788-charger.c
@@ -654,7 +654,7 @@
 {
 	struct lp8788_charger *pchg = dev_get_drvdata(dev);
 	char *stime[] = { "400ms", "5min", "10min", "15min",
-			"20min", "25min", "30min" "No timeout" };
+			"20min", "25min", "30min", "No timeout" };
 	u8 val;
 
 	lp8788_read_byte(pchg->lp, LP8788_CHG_EOC, &val);
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 3e2bdb9..17b1574 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -1497,7 +1497,7 @@
 
 config MAC_SCSI
 	tristate "Macintosh NCR5380 SCSI"
-	depends on MAC && SCSI=y
+	depends on MAC && SCSI
 	select SCSI_SPI_ATTRS
 	help
 	  This is the NCR 5380 SCSI controller included on most of the 68030
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 734e592..f9b52a4 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -1464,7 +1464,8 @@
 				/* Don't abort commands in adapter during EEH
 				 * recovery as it's not accessible/responding.
 				 */
-				if (GET_CMD_SP(sp) && !ha->flags.eeh_busy) {
+				if (GET_CMD_SP(sp) && !ha->flags.eeh_busy &&
+				    (sp->type == SRB_SCSI_CMD)) {
 					/* Get a reference to the sp and drop the lock.
 					 * The reference ensures this sp->done() call
 					 * - and not the call in qla2xxx_eh_abort() -
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c
index a535b26..96a343e 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -533,8 +533,7 @@
 	size_t buffer_length;
 	time64_t local_time;
 	unsigned int year;
-	struct timeval time;
-	struct rtc_time tm;
+	struct tm tm;
 
 	buffer_length = sizeof(*buffer);
 
@@ -551,9 +550,8 @@
 	put_unaligned_le16(sizeof(buffer->time),
 		&buffer->time_length);
 
-	do_gettimeofday(&time);
-	local_time = time.tv_sec - (sys_tz.tz_minuteswest * 60);
-	rtc_time64_to_tm(local_time, &tm);
+	local_time = ktime_get_real_seconds();
+	time64_to_tm(local_time, -sys_tz.tz_minuteswest * 60, &tm);
 	year = tm.tm_year + 1900;
 
 	buffer->time[0] = bin2bcd(tm.tm_hour);
diff --git a/drivers/sensors/Kconfig b/drivers/sensors/Kconfig
new file mode 100644
index 0000000..0e2da79
--- /dev/null
+++ b/drivers/sensors/Kconfig
@@ -0,0 +1,6 @@
+config SENSORS_SSC
+	bool "Enable Sensors Driver Support for SSC"
+	help
+	  Add support for sensors SSC driver.
+	  This driver is used for exercising sensors use case,
+	  time syncing with ADSP clock.
diff --git a/drivers/sensors/Makefile b/drivers/sensors/Makefile
new file mode 100644
index 0000000..08d8a63
--- /dev/null
+++ b/drivers/sensors/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SENSORS_SSC)	+= sensors_ssc.o
diff --git a/drivers/sensors/sensors_ssc.c b/drivers/sensors/sensors_ssc.c
new file mode 100644
index 0000000..d738767
--- /dev/null
+++ b/drivers/sensors/sensors_ssc.c
@@ -0,0 +1,419 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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/msm_dsps.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/of_device.h>
+#include <asm/arch_timer.h>
+#include <linux/uaccess.h>
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/sysfs.h>
+#include <linux/workqueue.h>
+
+#include <soc/qcom/subsystem_restart.h>
+
+#define IMAGE_LOAD_CMD 1
+#define IMAGE_UNLOAD_CMD 0
+#define CLASS_NAME	"ssc"
+#define DRV_NAME	"sensors"
+#define DRV_VERSION	"2.00"
+#ifdef CONFIG_COMPAT
+#define DSPS_IOCTL_READ_SLOW_TIMER32	_IOR(DSPS_IOCTL_MAGIC, 3, compat_uint_t)
+#endif
+
+#define QTICK_DIV_FACTOR	0x249F
+
+struct sns_ssc_control_s {
+	struct class *dev_class;
+	dev_t dev_num;
+	struct device *dev;
+	struct cdev *cdev;
+};
+static struct sns_ssc_control_s sns_ctl;
+
+static ssize_t slpi_boot_store(struct kobject *kobj,
+	struct kobj_attribute *attr,
+	const char *buf, size_t count);
+
+struct slpi_loader_private {
+	void *pil_h;
+	struct kobject *boot_slpi_obj;
+	struct attribute_group *attr_group;
+};
+
+static struct kobj_attribute slpi_boot_attribute =
+	__ATTR(boot, 0220, NULL, slpi_boot_store);
+
+static struct attribute *attrs[] = {
+	&slpi_boot_attribute.attr,
+	NULL,
+};
+
+static struct platform_device *slpi_private;
+static struct work_struct slpi_ldr_work;
+
+static void slpi_load_fw(struct work_struct *slpi_ldr_work)
+{
+	struct platform_device *pdev = slpi_private;
+	struct slpi_loader_private *priv = NULL;
+	int ret;
+	const char *firmware_name = NULL;
+
+	if (!pdev) {
+		dev_err(&pdev->dev, "%s: Platform device null\n", __func__);
+		goto fail;
+	}
+
+	if (!pdev->dev.of_node) {
+		dev_err(&pdev->dev,
+			"%s: Device tree information missing\n", __func__);
+		goto fail;
+	}
+
+	ret = of_property_read_string(pdev->dev.of_node,
+		"qcom,firmware-name", &firmware_name);
+	if (ret < 0) {
+		pr_err("can't get fw name.\n");
+		goto fail;
+	}
+
+	priv = platform_get_drvdata(pdev);
+	if (!priv) {
+		dev_err(&pdev->dev,
+		" %s: Private data get failed\n", __func__);
+		goto fail;
+	}
+
+	priv->pil_h = subsystem_get_with_fwname("slpi", firmware_name);
+	if (IS_ERR(priv->pil_h)) {
+		dev_err(&pdev->dev, "%s: pil get failed,\n",
+			__func__);
+		goto fail;
+	}
+
+	dev_dbg(&pdev->dev, "%s: SLPI image is loaded\n", __func__);
+	return;
+
+fail:
+	dev_err(&pdev->dev, "%s: SLPI image loading failed\n", __func__);
+}
+
+static void slpi_loader_do(struct platform_device *pdev)
+{
+	dev_dbg(&pdev->dev, "%s: scheduling work to load SLPI fw\n", __func__);
+	schedule_work(&slpi_ldr_work);
+}
+
+static void slpi_loader_unload(struct platform_device *pdev)
+{
+	struct slpi_loader_private *priv = NULL;
+
+	priv = platform_get_drvdata(pdev);
+
+	if (!priv)
+		return;
+
+	if (priv->pil_h) {
+		dev_dbg(&pdev->dev, "%s: calling subsystem put\n", __func__);
+		subsystem_put(priv->pil_h);
+		priv->pil_h = NULL;
+	}
+}
+
+static ssize_t slpi_boot_store(struct kobject *kobj,
+	struct kobj_attribute *attr,
+	const char *buf,
+	size_t count)
+{
+	int boot = 0;
+
+	if (sscanf(buf, "%du", &boot) != 1)
+		return -EINVAL;
+
+	if (boot == IMAGE_LOAD_CMD) {
+		pr_debug("%s: going to call slpi_loader_do\n", __func__);
+		slpi_loader_do(slpi_private);
+	} else if (boot == IMAGE_UNLOAD_CMD) {
+		pr_debug("%s: going to call slpi_unloader\n", __func__);
+		slpi_loader_unload(slpi_private);
+	}
+	return count;
+}
+
+static int slpi_loader_init_sysfs(struct platform_device *pdev)
+{
+	int ret = -EINVAL;
+	struct slpi_loader_private *priv = NULL;
+
+	slpi_private = NULL;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		ret = -ENOMEM;
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, priv);
+
+	priv->pil_h = NULL;
+	priv->boot_slpi_obj = NULL;
+	priv->attr_group = devm_kzalloc(&pdev->dev,
+				sizeof(*(priv->attr_group)),
+				GFP_KERNEL);
+	if (!priv->attr_group) {
+		dev_err(&pdev->dev, "%s: malloc attr_group failed\n",
+						__func__);
+		ret = -ENOMEM;
+		goto error_return;
+	}
+
+	priv->attr_group->attrs = attrs;
+
+	priv->boot_slpi_obj = kobject_create_and_add("boot_slpi", kernel_kobj);
+	if (!priv->boot_slpi_obj) {
+		dev_err(&pdev->dev, "%s: sysfs create and add failed\n",
+						__func__);
+		ret = -ENOMEM;
+		goto error_return;
+	}
+
+	ret = sysfs_create_group(priv->boot_slpi_obj, priv->attr_group);
+	if (ret) {
+		dev_err(&pdev->dev, "%s: sysfs create group failed %d\n",
+							__func__, ret);
+		goto error_return;
+	}
+
+	slpi_private = pdev;
+
+	return 0;
+
+error_return:
+
+	if (priv->boot_slpi_obj) {
+		kobject_del(priv->boot_slpi_obj);
+		priv->boot_slpi_obj = NULL;
+	}
+
+	return ret;
+}
+
+static int slpi_loader_remove(struct platform_device *pdev)
+{
+	struct slpi_loader_private *priv = NULL;
+
+	priv = platform_get_drvdata(pdev);
+
+	if (!priv)
+		return 0;
+
+	if (priv->pil_h) {
+		subsystem_put(priv->pil_h);
+		priv->pil_h = NULL;
+	}
+
+	if (priv->boot_slpi_obj) {
+		sysfs_remove_group(priv->boot_slpi_obj, priv->attr_group);
+		kobject_del(priv->boot_slpi_obj);
+		priv->boot_slpi_obj = NULL;
+	}
+
+	return 0;
+}
+
+/*
+ * Read virtual QTimer clock ticks and scale down to 32KHz clock as used
+ * in DSPS
+ */
+static u32 sns_read_qtimer(void)
+{
+	u64 val;
+
+	val = arch_counter_get_cntvct();
+	/*
+	 * To convert ticks from 19.2 Mhz clock to 32768 Hz clock:
+	 * x = (value * 32768) / 19200000
+	 * This is same as first left shift the value by 4 bits, i.e. multiply
+	 * by 16, and then divide by 0x249F. The latter is preferable since
+	 * QTimer tick (value) is 56-bit, so (value * 32768) could overflow,
+	 * while (value * 16) will never do
+	 */
+	val <<= 4;
+	do_div(val, QTICK_DIV_FACTOR);
+
+	return (u32)val;
+}
+
+static int sensors_ssc_open(struct inode *ip, struct file *fp)
+{
+	return 0;
+}
+
+static int sensors_ssc_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static long sensors_ssc_ioctl(struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	int ret = 0;
+	u32 val = 0;
+
+	switch (cmd) {
+	case DSPS_IOCTL_READ_SLOW_TIMER:
+#ifdef CONFIG_COMPAT
+	case DSPS_IOCTL_READ_SLOW_TIMER32:
+#endif
+		val = sns_read_qtimer();
+		ret = put_user(val, (u32 __user *) arg);
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+const struct file_operations sensors_ssc_fops = {
+	.owner = THIS_MODULE,
+	.open = sensors_ssc_open,
+	.release = sensors_ssc_release,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = sensors_ssc_ioctl,
+#endif
+	.unlocked_ioctl = sensors_ssc_ioctl
+};
+
+static int sensors_ssc_probe(struct platform_device *pdev)
+{
+	int ret = slpi_loader_init_sysfs(pdev);
+
+	if (ret != 0) {
+		dev_err(&pdev->dev, "%s: Error in initing sysfs\n", __func__);
+		return ret;
+	}
+
+	sns_ctl.dev_class = class_create(THIS_MODULE, CLASS_NAME);
+	if (sns_ctl.dev_class == NULL) {
+		pr_err("%s: class_create fail.\n", __func__);
+		goto res_err;
+	}
+
+	ret = alloc_chrdev_region(&sns_ctl.dev_num, 0, 1, DRV_NAME);
+	if (ret) {
+		pr_err("%s: alloc_chrdev_region fail.\n", __func__);
+		goto alloc_chrdev_region_err;
+	}
+
+	sns_ctl.dev = device_create(sns_ctl.dev_class, NULL,
+				     sns_ctl.dev_num,
+				     &sns_ctl, DRV_NAME);
+	if (IS_ERR(sns_ctl.dev)) {
+		pr_err("%s: device_create fail.\n", __func__);
+		goto device_create_err;
+	}
+
+	sns_ctl.cdev = cdev_alloc();
+	if (sns_ctl.cdev == NULL) {
+		pr_err("%s: cdev_alloc fail.\n", __func__);
+		goto cdev_alloc_err;
+	}
+	cdev_init(sns_ctl.cdev, &sensors_ssc_fops);
+	sns_ctl.cdev->owner = THIS_MODULE;
+
+	ret = cdev_add(sns_ctl.cdev, sns_ctl.dev_num, 1);
+	if (ret) {
+		pr_err("%s: cdev_add fail.\n", __func__);
+		goto cdev_add_err;
+	}
+
+	INIT_WORK(&slpi_ldr_work, slpi_load_fw);
+
+	return 0;
+
+cdev_add_err:
+	kfree(sns_ctl.cdev);
+cdev_alloc_err:
+	device_destroy(sns_ctl.dev_class, sns_ctl.dev_num);
+device_create_err:
+	unregister_chrdev_region(sns_ctl.dev_num, 1);
+alloc_chrdev_region_err:
+	class_destroy(sns_ctl.dev_class);
+res_err:
+	return -ENODEV;
+}
+
+static int sensors_ssc_remove(struct platform_device *pdev)
+{
+	slpi_loader_remove(pdev);
+	cdev_del(sns_ctl.cdev);
+	kfree(sns_ctl.cdev);
+	sns_ctl.cdev = NULL;
+	device_destroy(sns_ctl.dev_class, sns_ctl.dev_num);
+	unregister_chrdev_region(sns_ctl.dev_num, 1);
+	class_destroy(sns_ctl.dev_class);
+
+	return 0;
+}
+
+static const struct of_device_id msm_ssc_sensors_dt_match[] = {
+	{.compatible = "qcom,msm-ssc-sensors"},
+	{},
+};
+MODULE_DEVICE_TABLE(of, msm_ssc_sensors_dt_match);
+
+static struct platform_driver sensors_ssc_driver = {
+	.driver = {
+		.name = "sensors-ssc",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_ssc_sensors_dt_match,
+	},
+	.probe = sensors_ssc_probe,
+	.remove = sensors_ssc_remove,
+};
+
+static int __init sensors_ssc_init(void)
+{
+	int rc;
+
+	pr_debug("%s driver version %s.\n", DRV_NAME, DRV_VERSION);
+	rc = platform_driver_register(&sensors_ssc_driver);
+	if (rc) {
+		pr_err("%s: Failed to register sensors ssc driver\n",
+			__func__);
+		return rc;
+	}
+
+	return 0;
+}
+
+static void __exit sensors_ssc_exit(void)
+{
+	platform_driver_unregister(&sensors_ssc_driver);
+}
+
+module_init(sensors_ssc_init);
+module_exit(sensors_ssc_exit);
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Sensors SSC driver");
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index b759776..69e0ebc 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -197,6 +197,7 @@
 	ICNSS_MSA0_ASSIGNED,
 	ICNSS_WLFW_EXISTS,
 	ICNSS_WDOG_BITE,
+	ICNSS_SHUTDOWN_DONE,
 };
 
 struct ce_irq_list {
@@ -1983,9 +1984,13 @@
 	if (!priv->ops || !priv->ops->shutdown)
 		goto out;
 
+	if (test_bit(ICNSS_SHUTDOWN_DONE, &penv->state))
+		goto out;
+
 	icnss_pr_dbg("Calling driver shutdown state: 0x%lx\n", priv->state);
 
 	priv->ops->shutdown(&priv->pdev->dev);
+	set_bit(ICNSS_SHUTDOWN_DONE, &penv->state);
 
 out:
 	return 0;
@@ -2023,6 +2028,7 @@
 	}
 
 out:
+	clear_bit(ICNSS_SHUTDOWN_DONE, &penv->state);
 	return 0;
 
 call_probe:
@@ -2101,7 +2107,6 @@
 
 power_off:
 	icnss_hw_power_off(penv);
-	penv->ops = NULL;
 out:
 	return ret;
 }
@@ -2633,7 +2638,7 @@
 	}
 
 	ret = icnss_driver_event_post(ICNSS_DRIVER_EVENT_REGISTER_DRIVER,
-				      ICNSS_EVENT_SYNC, ops);
+				      0, ops);
 
 	if (ret == -EINTR)
 		ret = 0;
@@ -3655,6 +3660,9 @@
 		case ICNSS_WDOG_BITE:
 			seq_puts(s, "MODEM WDOG BITE");
 			continue;
+		case ICNSS_SHUTDOWN_DONE:
+			seq_puts(s, "SHUTDOWN DONE");
+			continue;
 		}
 
 		seq_printf(s, "UNKNOWN-%d", i);
diff --git a/drivers/soc/qcom/icnss_utils.c b/drivers/soc/qcom/icnss_utils.c
index 5e187d5..a7a0ffa 100644
--- a/drivers/soc/qcom/icnss_utils.c
+++ b/drivers/soc/qcom/icnss_utils.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -16,7 +16,7 @@
 #define ICNSS_MAX_CH_NUM 45
 
 static DEFINE_MUTEX(unsafe_channel_list_lock);
-static DEFINE_MUTEX(dfs_nol_info_lock);
+static DEFINE_SPINLOCK(dfs_nol_info_lock);
 
 static struct icnss_unsafe_channel_list {
 	u16 unsafe_ch_count;
@@ -77,27 +77,24 @@
 int icnss_wlan_set_dfs_nol(const void *info, u16 info_len)
 {
 	void *temp;
+	void *old_nol_info;
 	struct icnss_dfs_nol_info *dfs_info;
 
-	mutex_lock(&dfs_nol_info_lock);
-	if (!info || !info_len) {
-		mutex_unlock(&dfs_nol_info_lock);
+	if (!info || !info_len)
 		return -EINVAL;
-	}
 
-	temp = kmalloc(info_len, GFP_KERNEL);
-	if (!temp) {
-		mutex_unlock(&dfs_nol_info_lock);
+	temp = kmalloc(info_len, GFP_ATOMIC);
+	if (!temp)
 		return -ENOMEM;
-	}
 
 	memcpy(temp, info, info_len);
+	spin_lock_bh(&dfs_nol_info_lock);
 	dfs_info = &dfs_nol_info;
-	kfree(dfs_info->dfs_nol_info);
-
+	old_nol_info = 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);
+	spin_unlock_bh(&dfs_nol_info_lock);
+	kfree(old_nol_info);
 
 	return 0;
 }
@@ -108,24 +105,21 @@
 	int len;
 	struct icnss_dfs_nol_info *dfs_info;
 
-	mutex_lock(&dfs_nol_info_lock);
-	if (!info || !info_len) {
-		mutex_unlock(&dfs_nol_info_lock);
+	if (!info || !info_len)
 		return -EINVAL;
-	}
+
+	spin_lock_bh(&dfs_nol_info_lock);
 
 	dfs_info = &dfs_nol_info;
-
 	if (dfs_info->dfs_nol_info == NULL ||
 	    dfs_info->dfs_nol_info_len == 0) {
-		mutex_unlock(&dfs_nol_info_lock);
+		spin_unlock_bh(&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);
+	spin_unlock_bh(&dfs_nol_info_lock);
 
 	return len;
 }
diff --git a/drivers/soc/qcom/rpm_stats.c b/drivers/soc/qcom/rpm_stats.c
index 15d8b1b..8bf990e 100644
--- a/drivers/soc/qcom/rpm_stats.c
+++ b/drivers/soc/qcom/rpm_stats.c
@@ -231,34 +231,28 @@
 static ssize_t rpmstats_show(struct kobject *kobj,
 			struct kobj_attribute *attr, char *buf)
 {
-	struct msm_rpmstats_private_data *prvdata = NULL;
+	struct msm_rpmstats_private_data prvdata;
 	struct msm_rpmstats_platform_data *pdata = NULL;
 
 	pdata = GET_PDATA_OF_ATTR(attr);
 
-	prvdata =
-		kmalloc(sizeof(*prvdata), GFP_KERNEL);
-	if (!prvdata)
-		return -ENOMEM;
-
-	prvdata->reg_base = ioremap_nocache(pdata->phys_addr_base,
+	prvdata.reg_base = ioremap_nocache(pdata->phys_addr_base,
 					pdata->phys_size);
-	if (!prvdata->reg_base) {
-		kfree(prvdata);
+	if (!prvdata.reg_base) {
 		pr_err("%s: ERROR could not ioremap start=%pa, len=%u\n",
 			__func__, &pdata->phys_addr_base,
 			pdata->phys_size);
 		return -EBUSY;
 	}
 
-	prvdata->read_idx = prvdata->len = 0;
-	prvdata->platform_data = pdata;
-	prvdata->num_records = RPM_STATS_NUM_REC;
+	prvdata.read_idx = prvdata.len = 0;
+	prvdata.platform_data = pdata;
+	prvdata.num_records = RPM_STATS_NUM_REC;
 
-	if (prvdata->read_idx < prvdata->num_records)
-		prvdata->len = msm_rpmstats_copy_stats(prvdata);
+	if (prvdata.read_idx < prvdata.num_records)
+		prvdata.len = msm_rpmstats_copy_stats(&prvdata);
 
-	return snprintf(buf, prvdata->len, prvdata->buf);
+	return snprintf(buf, prvdata.len, prvdata.buf);
 }
 
 static int msm_rpmstats_create_sysfs(struct msm_rpmstats_platform_data *pd)
diff --git a/drivers/staging/emxx_udc/emxx_udc.c b/drivers/staging/emxx_udc/emxx_udc.c
index c3e2988..1055649 100644
--- a/drivers/staging/emxx_udc/emxx_udc.c
+++ b/drivers/staging/emxx_udc/emxx_udc.c
@@ -3160,7 +3160,7 @@
 };
 
 /*-------------------------------------------------------------------------*/
-static void __init nbu2ss_drv_ep_init(struct nbu2ss_udc *udc)
+static void nbu2ss_drv_ep_init(struct nbu2ss_udc *udc)
 {
 	int	i;
 
@@ -3191,7 +3191,7 @@
 
 /*-------------------------------------------------------------------------*/
 /* platform_driver */
-static int __init nbu2ss_drv_contest_init(
+static int nbu2ss_drv_contest_init(
 	struct platform_device *pdev,
 	struct nbu2ss_udc *udc)
 {
diff --git a/drivers/staging/lustre/lustre/llite/lproc_llite.c b/drivers/staging/lustre/lustre/llite/lproc_llite.c
index 23fda9d..13ec24d 100644
--- a/drivers/staging/lustre/lustre/llite/lproc_llite.c
+++ b/drivers/staging/lustre/lustre/llite/lproc_llite.c
@@ -924,27 +924,29 @@
 }
 LPROC_SEQ_FOPS(ll_unstable_stats);
 
-static ssize_t root_squash_show(struct kobject *kobj, struct attribute *attr,
-				char *buf)
+static int ll_root_squash_seq_show(struct seq_file *m, void *v)
 {
-	struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info,
-					      ll_kobj);
+	struct super_block *sb = m->private;
+	struct ll_sb_info *sbi = ll_s2sbi(sb);
 	struct root_squash_info *squash = &sbi->ll_squash;
 
-	return sprintf(buf, "%u:%u\n", squash->rsi_uid, squash->rsi_gid);
+	seq_printf(m, "%u:%u\n", squash->rsi_uid, squash->rsi_gid);
+	return 0;
 }
 
-static ssize_t root_squash_store(struct kobject *kobj, struct attribute *attr,
-				 const char *buffer, size_t count)
+static ssize_t ll_root_squash_seq_write(struct file *file,
+					const char __user *buffer,
+					size_t count, loff_t *off)
 {
-	struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info,
-					      ll_kobj);
+	struct seq_file *m = file->private_data;
+	struct super_block *sb = m->private;
+	struct ll_sb_info *sbi = ll_s2sbi(sb);
 	struct root_squash_info *squash = &sbi->ll_squash;
 
 	return lprocfs_wr_root_squash(buffer, count, squash,
-				      ll_get_fsname(sbi->ll_sb, NULL, 0));
+				      ll_get_fsname(sb, NULL, 0));
 }
-LUSTRE_RW_ATTR(root_squash);
+LPROC_SEQ_FOPS(ll_root_squash);
 
 static int ll_nosquash_nids_seq_show(struct seq_file *m, void *v)
 {
@@ -997,6 +999,8 @@
 	{ "statahead_stats",  &ll_statahead_stats_fops, NULL, 0 },
 	{ "unstable_stats",   &ll_unstable_stats_fops, NULL },
 	{ "sbi_flags",	      &ll_sbi_flags_fops, NULL, 0 },
+	{ .name =       "root_squash",
+	  .fops =       &ll_root_squash_fops			},
 	{ .name =		"nosquash_nids",
 	  .fops =		&ll_nosquash_nids_fops		},
 	{ NULL }
@@ -1027,7 +1031,6 @@
 	&lustre_attr_max_easize.attr,
 	&lustre_attr_default_easize.attr,
 	&lustre_attr_xattr_cache.attr,
-	&lustre_attr_root_squash.attr,
 	NULL,
 };
 
diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c
index 825a63a..2e075a6 100644
--- a/drivers/staging/wlan-ng/p80211netdev.c
+++ b/drivers/staging/wlan-ng/p80211netdev.c
@@ -232,7 +232,7 @@
 	struct p80211_hdr_a3 *hdr;
 
 	hdr = (struct p80211_hdr_a3 *)skb->data;
-	if (p80211_rx_typedrop(wlandev, hdr->fc))
+	if (p80211_rx_typedrop(wlandev, le16_to_cpu(hdr->fc)))
 		return CONV_TO_ETHER_SKIPPED;
 
 	/* perform mcast filtering: allow my local address through but reject
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index f4eb807..da31159 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -1237,7 +1237,8 @@
 	pm_runtime_put_autosuspend(&pdev->dev);
 	return 0;
 err:
-	pm_runtime_put(&pdev->dev);
+	pm_runtime_dont_use_autosuspend(&pdev->dev);
+	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 	return ret;
 }
@@ -1246,6 +1247,7 @@
 {
 	struct omap8250_priv *priv = platform_get_drvdata(pdev);
 
+	pm_runtime_dont_use_autosuspend(&pdev->dev);
 	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 	serial8250_unregister_port(priv->line);
@@ -1345,6 +1347,10 @@
 	struct omap8250_priv *priv = dev_get_drvdata(dev);
 	struct uart_8250_port *up;
 
+	/* In case runtime-pm tries this before we are setup */
+	if (!priv)
+		return 0;
+
 	up = serial8250_get_port(priv->line);
 	/*
 	 * When using 'no_console_suspend', the console UART must not be
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index cd41455..05bc4d6 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -428,9 +428,6 @@
 
 u8 hw_port_test_get(struct ci_hdrc *ci);
 
-int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask,
-				u32 value, unsigned int timeout_ms);
-
 void ci_platform_configure(struct ci_hdrc *ci);
 
 int dbg_create_files(struct ci_hdrc *ci);
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 3dbb4a2..6e0d614 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -516,38 +516,6 @@
 	return 0;
 }
 
-/**
- * hw_wait_reg: wait the register value
- *
- * Sometimes, it needs to wait register value before going on.
- * Eg, when switch to device mode, the vbus value should be lower
- * than OTGSC_BSV before connects to host.
- *
- * @ci: the controller
- * @reg: register index
- * @mask: mast bit
- * @value: the bit value to wait
- * @timeout_ms: timeout in millisecond
- *
- * This function returns an error code if timeout
- */
-int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask,
-				u32 value, unsigned int timeout_ms)
-{
-	unsigned long elapse = jiffies + msecs_to_jiffies(timeout_ms);
-
-	while (hw_read(ci, reg, mask) != value) {
-		if (time_after(jiffies, elapse)) {
-			dev_err(ci->dev, "timeout waiting for %08x in %d\n",
-					mask, reg);
-			return -ETIMEDOUT;
-		}
-		msleep(20);
-	}
-
-	return 0;
-}
-
 static irqreturn_t ci_irq(int irq, void *data)
 {
 	struct ci_hdrc *ci = data;
diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c
index 03b6743..0cf149e 100644
--- a/drivers/usb/chipidea/otg.c
+++ b/drivers/usb/chipidea/otg.c
@@ -44,12 +44,15 @@
 		else
 			val &= ~OTGSC_BSVIS;
 
-		cable->changed = false;
-
 		if (cable->state)
 			val |= OTGSC_BSV;
 		else
 			val &= ~OTGSC_BSV;
+
+		if (cable->enabled)
+			val |= OTGSC_BSVIE;
+		else
+			val &= ~OTGSC_BSVIE;
 	}
 
 	cable = &ci->platdata->id_extcon;
@@ -59,15 +62,18 @@
 		else
 			val &= ~OTGSC_IDIS;
 
-		cable->changed = false;
-
 		if (cable->state)
 			val |= OTGSC_ID;
 		else
 			val &= ~OTGSC_ID;
+
+		if (cable->enabled)
+			val |= OTGSC_IDIE;
+		else
+			val &= ~OTGSC_IDIE;
 	}
 
-	return val;
+	return val & mask;
 }
 
 /**
@@ -77,6 +83,36 @@
  */
 void hw_write_otgsc(struct ci_hdrc *ci, u32 mask, u32 data)
 {
+	struct ci_hdrc_cable *cable;
+
+	cable = &ci->platdata->vbus_extcon;
+	if (!IS_ERR(cable->edev)) {
+		if (data & mask & OTGSC_BSVIS)
+			cable->changed = false;
+
+		/* Don't enable vbus interrupt if using external notifier */
+		if (data & mask & OTGSC_BSVIE) {
+			cable->enabled = true;
+			data &= ~OTGSC_BSVIE;
+		} else if (mask & OTGSC_BSVIE) {
+			cable->enabled = false;
+		}
+	}
+
+	cable = &ci->platdata->id_extcon;
+	if (!IS_ERR(cable->edev)) {
+		if (data & mask & OTGSC_IDIS)
+			cable->changed = false;
+
+		/* Don't enable id interrupt if using external notifier */
+		if (data & mask & OTGSC_IDIE) {
+			cable->enabled = true;
+			data &= ~OTGSC_IDIE;
+		} else if (mask & OTGSC_IDIE) {
+			cable->enabled = false;
+		}
+	}
+
 	hw_write(ci, OP_OTGSC, mask | OTGSC_INT_STATUS_BITS, data);
 }
 
@@ -104,7 +140,31 @@
 		usb_gadget_vbus_disconnect(&ci->gadget);
 }
 
-#define CI_VBUS_STABLE_TIMEOUT_MS 5000
+/**
+ * When we switch to device mode, the vbus value should be lower
+ * than OTGSC_BSV before connecting to host.
+ *
+ * @ci: the controller
+ *
+ * This function returns an error code if timeout
+ */
+static int hw_wait_vbus_lower_bsv(struct ci_hdrc *ci)
+{
+	unsigned long elapse = jiffies + msecs_to_jiffies(5000);
+	u32 mask = OTGSC_BSV;
+
+	while (hw_read_otgsc(ci, mask)) {
+		if (time_after(jiffies, elapse)) {
+			dev_err(ci->dev, "timeout waiting for %08x in OTGSC\n",
+					mask);
+			return -ETIMEDOUT;
+		}
+		msleep(20);
+	}
+
+	return 0;
+}
+
 static void ci_handle_id_switch(struct ci_hdrc *ci)
 {
 	enum ci_role role = ci_otg_role(ci);
@@ -116,9 +176,11 @@
 		ci_role_stop(ci);
 
 		if (role == CI_ROLE_GADGET)
-			/* wait vbus lower than OTGSC_BSV */
-			hw_wait_reg(ci, OP_OTGSC, OTGSC_BSV, 0,
-					CI_VBUS_STABLE_TIMEOUT_MS);
+			/*
+			 * wait vbus lower than OTGSC_BSV before connecting
+			 * to host
+			 */
+			hw_wait_vbus_lower_bsv(ci);
 
 		ci_role_start(ci, role);
 	}
diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
index 4c0fa0b..f6759c6 100644
--- a/drivers/usb/dwc2/core.c
+++ b/drivers/usb/dwc2/core.c
@@ -455,7 +455,7 @@
 	dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);
 
 	if (dwc2_iddig_filter_enabled(hsotg))
-		usleep_range(100000, 110000);
+		msleep(100);
 }
 
 /*
diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c
index 42e5b66..7a603f6 100644
--- a/drivers/usb/host/ehci-exynos.c
+++ b/drivers/usb/host/ehci-exynos.c
@@ -77,10 +77,12 @@
 		if (IS_ERR(phy)) {
 			ret = PTR_ERR(phy);
 			if (ret == -EPROBE_DEFER) {
+				of_node_put(child);
 				return ret;
 			} else if (ret != -ENOSYS && ret != -ENODEV) {
 				dev_err(dev,
 					"Error retrieving usb2 phy: %d\n", ret);
+				of_node_put(child);
 				return ret;
 			}
 		}
diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c
index 2cd105b..6865b91 100644
--- a/drivers/usb/host/ohci-exynos.c
+++ b/drivers/usb/host/ohci-exynos.c
@@ -66,10 +66,12 @@
 		if (IS_ERR(phy)) {
 			ret = PTR_ERR(phy);
 			if (ret == -EPROBE_DEFER) {
+				of_node_put(child);
 				return ret;
 			} else if (ret != -ENOSYS && ret != -ENODEV) {
 				dev_err(dev,
 					"Error retrieving usb2 phy: %d\n", ret);
+				of_node_put(child);
 				return ret;
 			}
 		}
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index 7812052..754fc3e 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -373,23 +373,29 @@
 		dev_dbg(&port->dev,
 			"%s - usb_serial_generic_open failed: %d\n",
 			__func__, result);
-		goto err_out;
+		goto err_free;
 	}
 
 	/* remove any data still left: also clears error state */
 	ark3116_read_reg(serial, UART_RX, buf);
 
 	/* read modem status */
-	priv->msr = ark3116_read_reg(serial, UART_MSR, buf);
+	result = ark3116_read_reg(serial, UART_MSR, buf);
+	if (result < 0)
+		goto err_close;
+	priv->msr = *buf;
+
 	/* read line status */
-	priv->lsr = ark3116_read_reg(serial, UART_LSR, buf);
+	result = ark3116_read_reg(serial, UART_LSR, buf);
+	if (result < 0)
+		goto err_close;
+	priv->lsr = *buf;
 
 	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 	if (result) {
 		dev_err(&port->dev, "submit irq_in urb failed %d\n",
 			result);
-		ark3116_close(port);
-		goto err_out;
+		goto err_close;
 	}
 
 	/* activate interrupts */
@@ -402,8 +408,15 @@
 	if (tty)
 		ark3116_set_termios(tty, port, NULL);
 
-err_out:
 	kfree(buf);
+
+	return 0;
+
+err_close:
+	usb_serial_generic_close(port);
+err_free:
+	kfree(buf);
+
 	return result;
 }
 
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 30bf0f5..7ab3235 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -1398,25 +1398,30 @@
 {
 	struct usb_serial_port *port = urb->context;
 	struct digi_port *priv = usb_get_serial_port_data(port);
-	int opcode = ((unsigned char *)urb->transfer_buffer)[0];
-	int len = ((unsigned char *)urb->transfer_buffer)[1];
-	int port_status = ((unsigned char *)urb->transfer_buffer)[2];
-	unsigned char *data = ((unsigned char *)urb->transfer_buffer) + 3;
+	unsigned char *buf = urb->transfer_buffer;
+	int opcode;
+	int len;
+	int port_status;
+	unsigned char *data;
 	int flag, throttled;
-	int status = urb->status;
-
-	/* do not process callbacks on closed ports */
-	/* but do continue the read chain */
-	if (urb->status == -ENOENT)
-		return 0;
 
 	/* short/multiple packet check */
+	if (urb->actual_length < 2) {
+		dev_warn(&port->dev, "short packet received\n");
+		return -1;
+	}
+
+	opcode = buf[0];
+	len = buf[1];
+
 	if (urb->actual_length != len + 2) {
-		dev_err(&port->dev, "%s: INCOMPLETE OR MULTIPLE PACKET, "
-			"status=%d, port=%d, opcode=%d, len=%d, "
-			"actual_length=%d, status=%d\n", __func__, status,
-			priv->dp_port_num, opcode, len, urb->actual_length,
-			port_status);
+		dev_err(&port->dev, "malformed packet received: port=%d, opcode=%d, len=%d, actual_length=%u\n",
+			priv->dp_port_num, opcode, len, urb->actual_length);
+		return -1;
+	}
+
+	if (opcode == DIGI_CMD_RECEIVE_DATA && len < 1) {
+		dev_err(&port->dev, "malformed data packet received\n");
 		return -1;
 	}
 
@@ -1430,6 +1435,9 @@
 
 	/* receive data */
 	if (opcode == DIGI_CMD_RECEIVE_DATA) {
+		port_status = buf[2];
+		data = &buf[3];
+
 		/* get flag from port_status */
 		flag = 0;
 
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 99a0a5f..d8d13ee 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -1439,10 +1439,13 @@
 			     FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE,
 			     0, priv->interface,
 			     buf, 1, WDR_TIMEOUT);
-	if (rv < 0)
+	if (rv < 1) {
 		dev_err(&port->dev, "Unable to read latency timer: %i\n", rv);
-	else
+		if (rv >= 0)
+			rv = -EIO;
+	} else {
 		priv->latency = buf[0];
+	}
 
 	kfree(buf);
 
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 36dfe99..464db17 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -492,20 +492,24 @@
 	int result;
 	struct usb_serial *serial = ep->serial;
 	struct edgeport_product_info *product_info = &ep->product_info;
-	struct edge_compatibility_descriptor *epic = &ep->epic_descriptor;
+	struct edge_compatibility_descriptor *epic;
 	struct edge_compatibility_bits *bits;
 	struct device *dev = &serial->dev->dev;
 
 	ep->is_epic = 0;
+
+	epic = kmalloc(sizeof(*epic), GFP_KERNEL);
+	if (!epic)
+		return -ENOMEM;
+
 	result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
 				 USB_REQUEST_ION_GET_EPIC_DESC,
 				 0xC0, 0x00, 0x00,
-				 &ep->epic_descriptor,
-				 sizeof(struct edge_compatibility_descriptor),
+				 epic, sizeof(*epic),
 				 300);
-
-	if (result > 0) {
+	if (result == sizeof(*epic)) {
 		ep->is_epic = 1;
+		memcpy(&ep->epic_descriptor, epic, sizeof(*epic));
 		memset(product_info, 0, sizeof(struct edgeport_product_info));
 
 		product_info->NumPorts = epic->NumPorts;
@@ -534,8 +538,16 @@
 		dev_dbg(dev, "  IOSPWriteLCR     : %s\n", bits->IOSPWriteLCR	? "TRUE": "FALSE");
 		dev_dbg(dev, "  IOSPSetBaudRate  : %s\n", bits->IOSPSetBaudRate	? "TRUE": "FALSE");
 		dev_dbg(dev, "  TrueEdgeport     : %s\n", bits->TrueEdgeport	? "TRUE": "FALSE");
+
+		result = 0;
+	} else if (result >= 0) {
+		dev_warn(&serial->interface->dev, "short epic descriptor received: %d\n",
+			 result);
+		result = -EIO;
 	}
 
+	kfree(epic);
+
 	return result;
 }
 
@@ -2093,8 +2105,7 @@
  * rom_read
  *	reads a number of bytes from the Edgeport device starting at the given
  *	address.
- *	If successful returns the number of bytes read, otherwise it returns
- *	a negative error number of the problem.
+ *	Returns zero on success or a negative error number.
  ****************************************************************************/
 static int rom_read(struct usb_serial *serial, __u16 extAddr,
 					__u16 addr, __u16 length, __u8 *data)
@@ -2119,12 +2130,17 @@
 					USB_REQUEST_ION_READ_ROM,
 					0xC0, addr, extAddr, transfer_buffer,
 					current_length, 300);
-		if (result < 0)
+		if (result < current_length) {
+			if (result >= 0)
+				result = -EIO;
 			break;
+		}
 		memcpy(data, transfer_buffer, current_length);
 		length -= current_length;
 		addr += current_length;
 		data += current_length;
+
+		result = 0;
 	}
 
 	kfree(transfer_buffer);
@@ -2578,9 +2594,10 @@
 				EDGE_MANUF_DESC_LEN,
 				(__u8 *)(&edge_serial->manuf_descriptor));
 
-	if (response < 1)
-		dev_err(dev, "error in getting manufacturer descriptor\n");
-	else {
+	if (response < 0) {
+		dev_err(dev, "error in getting manufacturer descriptor: %d\n",
+				response);
+	} else {
 		char string[30];
 		dev_dbg(dev, "**Manufacturer Descriptor\n");
 		dev_dbg(dev, "  RomSize:        %dK\n",
@@ -2637,9 +2654,10 @@
 				EDGE_BOOT_DESC_LEN,
 				(__u8 *)(&edge_serial->boot_descriptor));
 
-	if (response < 1)
-		dev_err(dev, "error in getting boot descriptor\n");
-	else {
+	if (response < 0) {
+		dev_err(dev, "error in getting boot descriptor: %d\n",
+				response);
+	} else {
 		dev_dbg(dev, "**Boot Descriptor:\n");
 		dev_dbg(dev, "  BootCodeLength: %d\n",
 			le16_to_cpu(edge_serial->boot_descriptor.BootCodeLength));
@@ -2782,7 +2800,7 @@
 	dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name);
 
 	/* Read the epic descriptor */
-	if (get_epic_descriptor(edge_serial) <= 0) {
+	if (get_epic_descriptor(edge_serial) < 0) {
 		/* memcpy descriptor to Supports structures */
 		memcpy(&edge_serial->epic_descriptor.Supports, descriptor,
 		       sizeof(struct edge_compatibility_bits));
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 83523fc..d2dab2a 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -139,6 +139,7 @@
 {
 	struct usb_serial_port *port = urb->context;
 	unsigned char *data = urb->transfer_buffer;
+	unsigned int len = urb->actual_length;
 	int retval;
 	int status = urb->status;
 	struct keyspan_pda_private *priv;
@@ -159,18 +160,26 @@
 		goto exit;
 	}
 
+	if (len < 1) {
+		dev_warn(&port->dev, "short message received\n");
+		goto exit;
+	}
+
 	/* see if the message is data or a status interrupt */
 	switch (data[0]) {
 	case 0:
 		 /* rest of message is rx data */
-		if (urb->actual_length) {
-			tty_insert_flip_string(&port->port, data + 1,
-						urb->actual_length - 1);
-			tty_flip_buffer_push(&port->port);
-		}
+		if (len < 2)
+			break;
+		tty_insert_flip_string(&port->port, data + 1, len - 1);
+		tty_flip_buffer_push(&port->port);
 		break;
 	case 1:
 		/* status interrupt */
+		if (len < 3) {
+			dev_warn(&port->dev, "short interrupt message received\n");
+			break;
+		}
 		dev_dbg(&port->dev, "rx int, d1=%d, d2=%d\n", data[1], data[2]);
 		switch (data[1]) {
 		case 1: /* modemline change */
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 8856553..edbc81f 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -322,8 +322,12 @@
 			MCT_U232_GET_REQUEST_TYPE,
 			0, 0, buf, MCT_U232_GET_MODEM_STAT_SIZE,
 			WDR_TIMEOUT);
-	if (rc < 0) {
+	if (rc < MCT_U232_GET_MODEM_STAT_SIZE) {
 		dev_err(&port->dev, "Get MODEM STATus failed (error = %d)\n", rc);
+
+		if (rc >= 0)
+			rc = -EIO;
+
 		*msr = 0;
 	} else {
 		*msr = buf[0];
diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c
index bd1a130..1d17779 100644
--- a/drivers/usb/serial/quatech2.c
+++ b/drivers/usb/serial/quatech2.c
@@ -188,22 +188,22 @@
 }
 
 
-static inline int qt2_getdevice(struct usb_device *dev, u8 *data)
-{
-	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-			       QT_SET_GET_DEVICE, 0xc0, 0, 0,
-			       data, 3, QT2_USB_TIMEOUT);
-}
-
 static inline int qt2_getregister(struct usb_device *dev,
 				  u8 uart,
 				  u8 reg,
 				  u8 *data)
 {
-	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-			       QT_SET_GET_REGISTER, 0xc0, reg,
-			       uart, data, sizeof(*data), QT2_USB_TIMEOUT);
+	int ret;
 
+	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+			      QT_SET_GET_REGISTER, 0xc0, reg,
+			      uart, data, sizeof(*data), QT2_USB_TIMEOUT);
+	if (ret < sizeof(*data)) {
+		if (ret >= 0)
+			ret = -EIO;
+	}
+
+	return ret;
 }
 
 static inline int qt2_setregister(struct usb_device *dev,
@@ -372,9 +372,11 @@
 				 0xc0, 0,
 				 device_port, data, 2, QT2_USB_TIMEOUT);
 
-	if (status < 0) {
+	if (status < 2) {
 		dev_err(&port->dev, "%s - open port failed %i\n", __func__,
 			status);
+		if (status >= 0)
+			status = -EIO;
 		kfree(data);
 		return status;
 	}
diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c
index 70a098d..886e129 100644
--- a/drivers/usb/serial/ssu100.c
+++ b/drivers/usb/serial/ssu100.c
@@ -80,9 +80,17 @@
 
 static inline int ssu100_getdevice(struct usb_device *dev, u8 *data)
 {
-	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-			       QT_SET_GET_DEVICE, 0xc0, 0, 0,
-			       data, 3, 300);
+	int ret;
+
+	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+			      QT_SET_GET_DEVICE, 0xc0, 0, 0,
+			      data, 3, 300);
+	if (ret < 3) {
+		if (ret >= 0)
+			ret = -EIO;
+	}
+
+	return ret;
 }
 
 static inline int ssu100_getregister(struct usb_device *dev,
@@ -90,10 +98,17 @@
 				     unsigned short reg,
 				     u8 *data)
 {
-	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-			       QT_SET_GET_REGISTER, 0xc0, reg,
-			       uart, data, sizeof(*data), 300);
+	int ret;
 
+	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+			      QT_SET_GET_REGISTER, 0xc0, reg,
+			      uart, data, sizeof(*data), 300);
+	if (ret < sizeof(*data)) {
+		if (ret >= 0)
+			ret = -EIO;
+	}
+
+	return ret;
 }
 
 
@@ -289,8 +304,10 @@
 				 QT_OPEN_CLOSE_CHANNEL,
 				 QT_TRANSFER_IN, 0x01,
 				 0, data, 2, 300);
-	if (result < 0) {
+	if (result < 2) {
 		dev_dbg(&port->dev, "%s - open failed %i\n", __func__, result);
+		if (result >= 0)
+			result = -EIO;
 		kfree(data);
 		return result;
 	}
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index bdbddbc..6bcb874b 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -1556,13 +1556,10 @@
 		(USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT),
 		value, moduleid, data, size, 1000);
 
-	if (status == size)
-		status = 0;
+	if (status < 0)
+		return status;
 
-	if (status > 0)
-		status = -ECOMM;
-
-	return status;
+	return 0;
 }
 
 
@@ -1578,8 +1575,7 @@
 
 	if (status == size)
 		status = 0;
-
-	if (status > 0)
+	else if (status >= 0)
 		status = -ECOMM;
 
 	return status;
diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c
index 9ecfcdc..d5dbdb9 100644
--- a/drivers/xen/events/events_base.c
+++ b/drivers/xen/events/events_base.c
@@ -1314,6 +1314,9 @@
 	if (!VALID_EVTCHN(evtchn))
 		return -1;
 
+	if (!xen_support_evtchn_rebind())
+		return -1;
+
 	/* Send future instances of this interrupt to other vcpu. */
 	bind_vcpu.port = evtchn;
 	bind_vcpu.vcpu = xen_vcpu_nr(tcpu);
@@ -1647,15 +1650,20 @@
 {
 	int rc;
 	uint64_t callback_via;
-
-	callback_via = HVM_CALLBACK_VECTOR(HYPERVISOR_CALLBACK_VECTOR);
-	rc = xen_set_callback_via(callback_via);
-	BUG_ON(rc);
-	pr_info("Xen HVM callback vector for event delivery is enabled\n");
-	/* in the restore case the vector has already been allocated */
-	if (!test_bit(HYPERVISOR_CALLBACK_VECTOR, used_vectors))
-		alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR,
-				xen_hvm_callback_vector);
+	if (xen_have_vector_callback) {
+		callback_via = HVM_CALLBACK_VECTOR(HYPERVISOR_CALLBACK_VECTOR);
+		rc = xen_set_callback_via(callback_via);
+		if (rc) {
+			pr_err("Request for Xen HVM callback vector failed\n");
+			xen_have_vector_callback = 0;
+			return;
+		}
+		pr_info("Xen HVM callback vector for event delivery is enabled\n");
+		/* in the restore case the vector has already been allocated */
+		if (!test_bit(HYPERVISOR_CALLBACK_VECTOR, used_vectors))
+			alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR,
+					xen_hvm_callback_vector);
+	}
 }
 #else
 void xen_callback_vector(void) {}
diff --git a/drivers/xen/platform-pci.c b/drivers/xen/platform-pci.c
index b59c9455..cf96666 100644
--- a/drivers/xen/platform-pci.c
+++ b/drivers/xen/platform-pci.c
@@ -42,6 +42,7 @@
 static unsigned long platform_mmio;
 static unsigned long platform_mmio_alloc;
 static unsigned long platform_mmiolen;
+static uint64_t callback_via;
 
 static unsigned long alloc_xen_mmio(unsigned long len)
 {
@@ -54,6 +55,51 @@
 	return addr;
 }
 
+static uint64_t get_callback_via(struct pci_dev *pdev)
+{
+	u8 pin;
+	int irq;
+
+	irq = pdev->irq;
+	if (irq < 16)
+		return irq; /* ISA IRQ */
+
+	pin = pdev->pin;
+
+	/* We don't know the GSI. Specify the PCI INTx line instead. */
+	return ((uint64_t)0x01 << 56) | /* PCI INTx identifier */
+		((uint64_t)pci_domain_nr(pdev->bus) << 32) |
+		((uint64_t)pdev->bus->number << 16) |
+		((uint64_t)(pdev->devfn & 0xff) << 8) |
+		((uint64_t)(pin - 1) & 3);
+}
+
+static irqreturn_t do_hvm_evtchn_intr(int irq, void *dev_id)
+{
+	xen_hvm_evtchn_do_upcall();
+	return IRQ_HANDLED;
+}
+
+static int xen_allocate_irq(struct pci_dev *pdev)
+{
+	return request_irq(pdev->irq, do_hvm_evtchn_intr,
+			IRQF_NOBALANCING | IRQF_TRIGGER_RISING,
+			"xen-platform-pci", pdev);
+}
+
+static int platform_pci_resume(struct pci_dev *pdev)
+{
+	int err;
+	if (xen_have_vector_callback)
+		return 0;
+	err = xen_set_callback_via(callback_via);
+	if (err) {
+		dev_err(&pdev->dev, "platform_pci_resume failure!\n");
+		return err;
+	}
+	return 0;
+}
+
 static int platform_pci_probe(struct pci_dev *pdev,
 			      const struct pci_device_id *ent)
 {
@@ -92,6 +138,21 @@
 	platform_mmio = mmio_addr;
 	platform_mmiolen = mmio_len;
 
+	if (!xen_have_vector_callback) {
+		ret = xen_allocate_irq(pdev);
+		if (ret) {
+			dev_warn(&pdev->dev, "request_irq failed err=%d\n", ret);
+			goto out;
+		}
+		callback_via = get_callback_via(pdev);
+		ret = xen_set_callback_via(callback_via);
+		if (ret) {
+			dev_warn(&pdev->dev, "Unable to set the evtchn callback "
+					 "err=%d\n", ret);
+			goto out;
+		}
+	}
+
 	max_nr_gframes = gnttab_max_grant_frames();
 	grant_frames = alloc_xen_mmio(PAGE_SIZE * max_nr_gframes);
 	ret = gnttab_setup_auto_xlat_frames(grant_frames);
@@ -123,6 +184,9 @@
 	.name =           DRV_NAME,
 	.probe =          platform_pci_probe,
 	.id_table =       platform_pci_tbl,
+#ifdef CONFIG_PM
+	.resume_early =   platform_pci_resume,
+#endif
 };
 
 static int __init platform_pci_init(void)
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 092a2eed..9ad527f 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -1165,7 +1165,6 @@
 
 	if (disk->fops->revalidate_disk)
 		ret = disk->fops->revalidate_disk(disk);
-	blk_integrity_revalidate(disk);
 	bdev = bdget_disk(disk, 0);
 	if (!bdev)
 		return ret;
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 013c6a5..7e0c002 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -1405,6 +1405,13 @@
 		return 1;
 	}
 
+	if (le32_to_cpu(raw_super->segment_count) > F2FS_MAX_SEGMENT) {
+		f2fs_msg(sb, KERN_INFO,
+			"Invalid segment count (%u)",
+			le32_to_cpu(raw_super->segment_count));
+		return 1;
+	}
+
 	/* check CP/SIT/NAT/SSA/MAIN_AREA area boundary */
 	if (sanity_check_area_boundary(sbi, bh))
 		return 1;
diff --git a/fs/sdcardfs/dentry.c b/fs/sdcardfs/dentry.c
index afd9771..ae2b4ba 100644
--- a/fs/sdcardfs/dentry.c
+++ b/fs/sdcardfs/dentry.c
@@ -60,6 +60,14 @@
 	lower_dentry = lower_path.dentry;
 	lower_cur_parent_dentry = dget_parent(lower_dentry);
 
+	if ((lower_dentry->d_flags & DCACHE_OP_REVALIDATE)) {
+		err = lower_dentry->d_op->d_revalidate(lower_dentry, flags);
+		if (err == 0) {
+			d_drop(dentry);
+			goto out;
+		}
+	}
+
 	spin_lock(&lower_dentry->d_lock);
 	if (d_unhashed(lower_dentry)) {
 		spin_unlock(&lower_dentry->d_lock);
diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c
index 2964527..5a0ef38 100644
--- a/fs/sdcardfs/derived_perm.c
+++ b/fs/sdcardfs/derived_perm.c
@@ -215,16 +215,16 @@
 		gid = AID_MEDIA_OBB;
 		break;
 	case PERM_ANDROID_PACKAGE:
-		if (info->d_uid != 0)
+		if (uid_is_app(info->d_uid))
 			gid = multiuser_get_ext_gid(info->d_uid);
 		else
-			gid = multiuser_get_uid(info->userid, uid);
+			gid = multiuser_get_uid(info->userid, AID_MEDIA_RW);
 		break;
 	case PERM_ANDROID_PACKAGE_CACHE:
-		if (info->d_uid != 0)
+		if (uid_is_app(info->d_uid))
 			gid = multiuser_get_ext_cache_gid(info->d_uid);
 		else
-			gid = multiuser_get_uid(info->userid, uid);
+			gid = multiuser_get_uid(info->userid, AID_MEDIA_RW);
 		break;
 	case PERM_PRE_ROOT:
 	default:
diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c
index 1f6921e..6076c34 100644
--- a/fs/sdcardfs/file.c
+++ b/fs/sdcardfs/file.c
@@ -358,9 +358,12 @@
 	get_file(lower_file); /* prevent lower_file from being released */
 	iocb->ki_filp = lower_file;
 	err = lower_file->f_op->read_iter(iocb, iter);
-	/* ? wait IO finish to update atime as ecryptfs ? */
 	iocb->ki_filp = file;
 	fput(lower_file);
+	/* update upper inode atime as needed */
+	if (err >= 0 || err == -EIOCBQUEUED)
+		fsstack_copy_attr_atime(file->f_path.dentry->d_inode,
+					file_inode(lower_file));
 out:
 	return err;
 }
@@ -384,6 +387,13 @@
 	err = lower_file->f_op->write_iter(iocb, iter);
 	iocb->ki_filp = file;
 	fput(lower_file);
+	/* update upper inode times/sizes as needed */
+	if (err >= 0 || err == -EIOCBQUEUED) {
+		fsstack_copy_inode_size(file->f_path.dentry->d_inode,
+					file_inode(lower_file));
+		fsstack_copy_attr_times(file->f_path.dentry->d_inode,
+					file_inode(lower_file));
+	}
 out:
 	return err;
 }
diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c
index 92afceb..4d558b8 100644
--- a/fs/sdcardfs/inode.c
+++ b/fs/sdcardfs/inode.c
@@ -622,11 +622,8 @@
 	struct inode tmp;
 	struct inode *top = grab_top(SDCARDFS_I(inode));
 
-	if (!top) {
-		release_top(SDCARDFS_I(inode));
-		WARN(1, "Top value was null!\n");
+	if (!top)
 		return -EINVAL;
-	}
 
 	/*
 	 * Permission check on sdcardfs inode.
@@ -701,10 +698,8 @@
 	inode = d_inode(dentry);
 	top = grab_top(SDCARDFS_I(inode));
 
-	if (!top) {
-		release_top(SDCARDFS_I(inode));
+	if (!top)
 		return -EINVAL;
-	}
 
 	/*
 	 * Permission check on sdcardfs inode.
diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c
index 19154b7..706329d 100644
--- a/fs/sdcardfs/lookup.c
+++ b/fs/sdcardfs/lookup.c
@@ -366,19 +366,22 @@
 	/* instatiate a new negative dentry */
 	dname.name = name->name;
 	dname.len = name->len;
-	dname.hash = full_name_hash(lower_dir_dentry, dname.name, dname.len);
-	lower_dentry = d_lookup(lower_dir_dentry, &dname);
-	if (lower_dentry)
-		goto setup_lower;
 
-	lower_dentry = d_alloc(lower_dir_dentry, &dname);
+	/* See if the low-level filesystem might want
+	 * to use its own hash
+	 */
+	lower_dentry = d_hash_and_lookup(lower_dir_dentry, &dname);
+	if (IS_ERR(lower_dentry))
+		return lower_dentry;
 	if (!lower_dentry) {
-		err = -ENOMEM;
+		/* We called vfs_path_lookup earlier, and did not get a negative
+		 * dentry then. Don't confuse the lower filesystem by forcing
+		 * one on it now...
+		 */
+		err = -ENOENT;
 		goto out;
 	}
-	d_add(lower_dentry, NULL); /* instantiate and hash */
 
-setup_lower:
 	lower_path.dentry = lower_dentry;
 	lower_path.mnt = mntget(lower_dir_mnt);
 	sdcardfs_set_lower_path(dentry, &lower_path);
diff --git a/fs/sdcardfs/multiuser.h b/fs/sdcardfs/multiuser.h
index d0c925c..85341e7 100644
--- a/fs/sdcardfs/multiuser.h
+++ b/fs/sdcardfs/multiuser.h
@@ -35,6 +35,13 @@
 	return (user_id * AID_USER_OFFSET) + (app_id % AID_USER_OFFSET);
 }
 
+static inline bool uid_is_app(uid_t uid)
+{
+	appid_t appid = uid % AID_USER_OFFSET;
+
+	return appid >= AID_APP_START && appid <= AID_APP_END;
+}
+
 static inline gid_t multiuser_get_ext_cache_gid(uid_t uid)
 {
 	return uid - AID_APP_START + AID_EXT_CACHE_GID_START;
diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c
index a3393e9..8a9c9c7 100644
--- a/fs/sdcardfs/super.c
+++ b/fs/sdcardfs/super.c
@@ -192,9 +192,16 @@
 	return &i->vfs_inode;
 }
 
+static void i_callback(struct rcu_head *head)
+{
+	struct inode *inode = container_of(head, struct inode, i_rcu);
+
+	kmem_cache_free(sdcardfs_inode_cachep, SDCARDFS_I(inode));
+}
+
 static void sdcardfs_destroy_inode(struct inode *inode)
 {
-	kmem_cache_free(sdcardfs_inode_cachep, SDCARDFS_I(inode));
+	call_rcu(&inode->i_rcu, i_callback);
 }
 
 /* sdcardfs inode cache constructor */
diff --git a/include/dt-bindings/clock/qcom,gcc-sdm845.h b/include/dt-bindings/clock/qcom,gcc-sdm845.h
index e411e8e..a95d494 100644
--- a/include/dt-bindings/clock/qcom,gcc-sdm845.h
+++ b/include/dt-bindings/clock/qcom,gcc-sdm845.h
@@ -197,6 +197,7 @@
 #define GCC_AGGRE_UFS_PHY_AXI_HW_CTL_CLK			179
 #define GCC_UFS_CARD_PHY_AUX_HW_CTL_CLK				180
 #define GCC_UFS_PHY_PHY_AUX_HW_CTL_CLK				181
+#define GCC_GPU_IREF_CLK					182
 
 /* GCC reset clocks */
 #define GCC_GPU_BCR						0
diff --git a/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h b/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h
index 6243588..915ac08 100644
--- a/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h
+++ b/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h
@@ -63,37 +63,39 @@
 #define GCC_PCIE_AUX_CLK					45
 #define GCC_PCIE_AUX_PHY_CLK_SRC				46
 #define GCC_PCIE_CFG_AHB_CLK					47
-#define GCC_PCIE_MSTR_AXI_CLK					48
-#define GCC_PCIE_PHY_REFGEN_CLK					49
-#define GCC_PCIE_PHY_REFGEN_CLK_SRC				50
-#define GCC_PCIE_PIPE_CLK					51
-#define GCC_PCIE_SLEEP_CLK					52
-#define GCC_PCIE_SLV_AXI_CLK					53
-#define GCC_PCIE_SLV_Q2A_AXI_CLK				54
-#define GCC_PDM2_CLK						55
-#define GCC_PDM2_CLK_SRC					56
-#define GCC_PDM_AHB_CLK						57
-#define GCC_PDM_XO4_CLK						58
-#define GCC_PRNG_AHB_CLK					59
-#define GCC_SDCC1_AHB_CLK					60
-#define GCC_SDCC1_APPS_CLK					61
-#define GCC_SDCC1_APPS_CLK_SRC					62
-#define GCC_SPMI_FETCHER_AHB_CLK				63
-#define GCC_SPMI_FETCHER_CLK					64
-#define GCC_SPMI_FETCHER_CLK_SRC				65
-#define GCC_SYS_NOC_CPUSS_AHB_CLK				66
-#define GCC_USB30_MASTER_CLK					67
-#define GCC_USB30_MASTER_CLK_SRC				68
-#define GCC_USB30_MOCK_UTMI_CLK					69
-#define GCC_USB30_MOCK_UTMI_CLK_SRC				70
-#define GCC_USB30_SLEEP_CLK					71
-#define GCC_USB3_PHY_AUX_CLK					72
-#define GCC_USB3_PHY_AUX_CLK_SRC				73
-#define GCC_USB3_PHY_PIPE_CLK					74
-#define GCC_USB_PHY_CFG_AHB2PHY_CLK				75
-#define GCC_XO_DIV4_CLK						76
-#define GPLL0							77
-#define GPLL0_OUT_EVEN						78
+#define GCC_PCIE_0_CLKREF_EN					48
+#define GCC_PCIE_MSTR_AXI_CLK					49
+#define GCC_PCIE_PHY_REFGEN_CLK					50
+#define GCC_PCIE_PHY_REFGEN_CLK_SRC				51
+#define GCC_PCIE_PIPE_CLK					52
+#define GCC_PCIE_SLEEP_CLK					53
+#define GCC_PCIE_SLV_AXI_CLK					54
+#define GCC_PCIE_SLV_Q2A_AXI_CLK				55
+#define GCC_PDM2_CLK						56
+#define GCC_PDM2_CLK_SRC					57
+#define GCC_PDM_AHB_CLK						58
+#define GCC_PDM_XO4_CLK						59
+#define GCC_PRNG_AHB_CLK					60
+#define GCC_SDCC1_AHB_CLK					61
+#define GCC_SDCC1_APPS_CLK					62
+#define GCC_SDCC1_APPS_CLK_SRC					63
+#define GCC_SPMI_FETCHER_AHB_CLK				64
+#define GCC_SPMI_FETCHER_CLK					65
+#define GCC_SPMI_FETCHER_CLK_SRC				66
+#define GCC_SYS_NOC_CPUSS_AHB_CLK				67
+#define GCC_USB30_MASTER_CLK					68
+#define GCC_USB30_MASTER_CLK_SRC				69
+#define GCC_USB30_MOCK_UTMI_CLK					70
+#define GCC_USB30_MOCK_UTMI_CLK_SRC				71
+#define GCC_USB30_SLEEP_CLK					72
+#define GCC_USB3_PRIM_CLKREF_CLK				73
+#define GCC_USB3_PHY_AUX_CLK					74
+#define GCC_USB3_PHY_AUX_CLK_SRC				75
+#define GCC_USB3_PHY_PIPE_CLK					76
+#define GCC_USB_PHY_CFG_AHB2PHY_CLK				77
+#define GCC_XO_DIV4_CLK						78
+#define GPLL0							79
+#define GPLL0_OUT_EVEN						80
 
 /* GDSCs */
 #define PCIE_GDSC						0
@@ -118,6 +120,9 @@
 #define GCC_SDCC1_BCR						12
 #define GCC_SPMI_FETCHER_BCR					13
 #define GCC_USB30_BCR						14
-#define GCC_USB_PHY_CFG_AHB2PHY_BCR				15
+#define GCC_USB3_PHY_BCR					15
+#define GCC_USB3PHY_PHY_BCR					16
+#define GCC_QUSB2PHY_BCR					17
+#define GCC_USB_PHY_CFG_AHB2PHY_BCR				18
 
 #endif
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1325b23..094b152 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -430,6 +430,16 @@
  */
 int clk_set_flags(struct clk *clk, unsigned long flags);
 
+/**
+ * clk_list_frequnecy - enumerate supported frequencies
+ * @clk: clock source
+ * @index: identify frequency to list
+ *
+ * Returns a non-negative integer frequency for success
+ * or negative errno in case of failure.
+ */
+unsigned long clk_list_frequency(struct clk *clk, unsigned int index);
+
 #else /* !CONFIG_HAVE_CLK */
 
 static inline struct clk *clk_get(struct device *dev, const char *id)
diff --git a/include/linux/extcon/extcon-gpio.h b/include/linux/extcon/extcon-gpio.h
index 7cacafb..8c463a8 100644
--- a/include/linux/extcon/extcon-gpio.h
+++ b/include/linux/extcon/extcon-gpio.h
@@ -33,6 +33,8 @@
  * @irq_flags:		IRQ Flags (e.g., IRQF_TRIGGER_LOW).
  * @check_on_resume:	Boolean describing whether to check the state of gpio
  *			while resuming from sleep.
+ * @pctrl:		GPIO pinctrl handle
+ * @pctrl_default:	GPIO pinctrl default state handle
  */
 struct gpio_extcon_pdata {
 	unsigned int extcon_id;
@@ -42,6 +44,9 @@
 	unsigned long irq_flags;
 
 	bool check_on_resume;
+
+	struct pinctrl          *pctrl;
+	struct pinctrl_state    *pins_default;
 };
 
 #endif /* __EXTCON_GPIO_H__ */
diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h
index 422630b..e46e7d1 100644
--- a/include/linux/f2fs_fs.h
+++ b/include/linux/f2fs_fs.h
@@ -286,6 +286,12 @@
 #define SIT_ENTRY_PER_BLOCK (PAGE_SIZE / sizeof(struct f2fs_sit_entry))
 
 /*
+ * F2FS uses 4 bytes to represent block address. As a result, supported size of
+ * disk is 16 TB and it equals to 16 * 1024 * 1024 / 2 segments.
+ */
+#define F2FS_MAX_SEGMENT       ((16 * 1024 * 1024) / 2)
+
+/*
  * Note that f2fs_sit_entry->vblocks has the following bit-field information.
  * [15:10] : allocation type such as CURSEG_XXXX_TYPE
  * [9:0] : valid block count
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index e0341af..3c99fb6 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -731,11 +731,9 @@
 #if defined(CONFIG_BLK_DEV_INTEGRITY)
 extern void blk_integrity_add(struct gendisk *);
 extern void blk_integrity_del(struct gendisk *);
-extern void blk_integrity_revalidate(struct gendisk *);
 #else	/* CONFIG_BLK_DEV_INTEGRITY */
 static inline void blk_integrity_add(struct gendisk *disk) { }
 static inline void blk_integrity_del(struct gendisk *disk) { }
-static inline void blk_integrity_revalidate(struct gendisk *disk) { }
 #endif	/* CONFIG_BLK_DEV_INTEGRITY */
 
 #else /* CONFIG_BLOCK */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index ecfc173..0e6a54c 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -18,6 +18,7 @@
 #include <linux/devfreq.h>
 #include <linux/fault-inject.h>
 #include <linux/blkdev.h>
+#include <linux/extcon.h>
 
 #include <linux/mmc/core.h>
 #include <linux/mmc/card.h>
@@ -594,6 +595,8 @@
 	 * actually disabling the clock from it's source.
 	 */
 	bool			card_clock_off;
+	struct extcon_dev	*extcon;
+	struct notifier_block card_detect_nb;
 
 #ifdef CONFIG_MMC_PERF_PROFILING
 	struct {
diff --git a/include/linux/mmc/slot-gpio.h b/include/linux/mmc/slot-gpio.h
index 3945a8c..f2c8d13 100644
--- a/include/linux/mmc/slot-gpio.h
+++ b/include/linux/mmc/slot-gpio.h
@@ -29,5 +29,7 @@
 void mmc_gpio_set_cd_isr(struct mmc_host *host,
 			 irqreturn_t (*isr)(int irq, void *dev_id));
 void mmc_gpiod_request_cd_irq(struct mmc_host *host);
+void mmc_register_extcon(struct mmc_host *host);
+void mmc_unregister_extcon(struct mmc_host *host);
 
 #endif
diff --git a/include/linux/msm_gsi.h b/include/linux/msm_gsi.h
index f5d2f72..0c460a0 100644
--- a/include/linux/msm_gsi.h
+++ b/include/linux/msm_gsi.h
@@ -18,6 +18,7 @@
 	GSI_VER_1_0 = 1,
 	GSI_VER_1_2 = 2,
 	GSI_VER_1_3 = 3,
+	GSI_VER_2_0 = 4,
 	GSI_VER_MAX,
 };
 
diff --git a/include/linux/netfilter/xt_qtaguid.h b/include/linux/netfilter/xt_qtaguid.h
index ca60fbd..1c67155 100644
--- a/include/linux/netfilter/xt_qtaguid.h
+++ b/include/linux/netfilter/xt_qtaguid.h
@@ -10,4 +10,5 @@
 #define XT_QTAGUID_SOCKET XT_OWNER_SOCKET
 #define xt_qtaguid_match_info xt_owner_match_info
 
+int qtaguid_untag(struct socket *sock, bool kernel);
 #endif /* _XT_QTAGUID_MATCH_H */
diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h
index 5dd75fa..f9be467 100644
--- a/include/linux/usb/chipidea.h
+++ b/include/linux/usb/chipidea.h
@@ -14,6 +14,7 @@
  * struct ci_hdrc_cable - structure for external connector cable state tracking
  * @state: current state of the line
  * @changed: set to true when extcon event happen
+ * @enabled: set to true if we've enabled the vbus or id interrupt
  * @edev: device which generate events
  * @ci: driver state of the chipidea device
  * @nb: hold event notification callback
@@ -22,6 +23,7 @@
 struct ci_hdrc_cable {
 	bool				state;
 	bool				changed;
+	bool				enabled;
 	struct extcon_dev		*edev;
 	struct ci_hdrc			*ci;
 	struct notifier_block		nb;
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index e1bd2bc..858f308 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -20,6 +20,8 @@
 #define ADDRCONF_TIMER_FUZZ		(HZ / 4)
 #define ADDRCONF_TIMER_FUZZ_MAX		(HZ)
 
+#define ADDRCONF_NOTIFY_PRIORITY	0
+
 #include <linux/in.h>
 #include <linux/in6.h>
 
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index 9dc2c18..f5e625f 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -84,6 +84,7 @@
 struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
 			       int ifindex, struct flowi6 *fl6, int flags);
 
+void ip6_route_init_special_entries(void);
 int ip6_route_init(void);
 void ip6_route_cleanup(void);
 
diff --git a/include/xen/xen.h b/include/xen/xen.h
index f0f0252..0c0e3ef 100644
--- a/include/xen/xen.h
+++ b/include/xen/xen.h
@@ -38,7 +38,8 @@
  */
 #include <xen/features.h>
 #define xen_pvh_domain() (xen_pv_domain() && \
-			  xen_feature(XENFEAT_auto_translated_physmap))
+			  xen_feature(XENFEAT_auto_translated_physmap) && \
+			  xen_have_vector_callback)
 #else
 #define xen_pvh_domain()	(0)
 #endif
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 7c9f94c..44c17f4 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -279,7 +279,8 @@
 	[BPF_EXIT >> 4] = "exit",
 };
 
-static void print_bpf_insn(struct bpf_insn *insn)
+static void print_bpf_insn(const struct bpf_verifier_env *env,
+			   const struct bpf_insn *insn)
 {
 	u8 class = BPF_CLASS(insn->code);
 
@@ -343,9 +344,19 @@
 				insn->code,
 				bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
 				insn->src_reg, insn->imm);
-		} else if (BPF_MODE(insn->code) == BPF_IMM) {
-			verbose("(%02x) r%d = 0x%x\n",
-				insn->code, insn->dst_reg, insn->imm);
+		} else if (BPF_MODE(insn->code) == BPF_IMM &&
+			   BPF_SIZE(insn->code) == BPF_DW) {
+			/* At this point, we already made sure that the second
+			 * part of the ldimm64 insn is accessible.
+			 */
+			u64 imm = ((u64)(insn + 1)->imm << 32) | (u32)insn->imm;
+			bool map_ptr = insn->src_reg == BPF_PSEUDO_MAP_FD;
+
+			if (map_ptr && !env->allow_ptr_leaks)
+				imm = 0;
+
+			verbose("(%02x) r%d = 0x%llx\n", insn->code,
+				insn->dst_reg, (unsigned long long)imm);
 		} else {
 			verbose("BUG_ld_%02x\n", insn->code);
 			return;
@@ -1749,6 +1760,17 @@
 			return 0;
 		} else if (opcode == BPF_ADD &&
 			   BPF_CLASS(insn->code) == BPF_ALU64 &&
+			   dst_reg->type == PTR_TO_STACK &&
+			   ((BPF_SRC(insn->code) == BPF_X &&
+			     regs[insn->src_reg].type == CONST_IMM) ||
+			    BPF_SRC(insn->code) == BPF_K)) {
+			if (BPF_SRC(insn->code) == BPF_X)
+				dst_reg->imm += regs[insn->src_reg].imm;
+			else
+				dst_reg->imm += insn->imm;
+			return 0;
+		} else if (opcode == BPF_ADD &&
+			   BPF_CLASS(insn->code) == BPF_ALU64 &&
 			   (dst_reg->type == PTR_TO_PACKET ||
 			    (BPF_SRC(insn->code) == BPF_X &&
 			     regs[insn->src_reg].type == PTR_TO_PACKET))) {
@@ -2663,7 +2685,7 @@
 
 		if (log_level) {
 			verbose("%d: ", insn_idx);
-			print_bpf_insn(insn);
+			print_bpf_insn(env, insn);
 		}
 
 		err = ext_analyzer_insn_hook(env, insn_idx, prev_insn_idx);
diff --git a/kernel/configs/android-base.config b/kernel/configs/android-base.config
index 3c32c74..b7b997f 100644
--- a/kernel/configs/android-base.config
+++ b/kernel/configs/android-base.config
@@ -3,7 +3,6 @@
 # CONFIG_DEVMEM is not set
 # CONFIG_FHANDLE is not set
 # CONFIG_INET_LRO is not set
-# CONFIG_MODULES is not set
 # CONFIG_OABI_COMPAT is not set
 # CONFIG_SYSVIPC is not set
 # CONFIG_USELIB is not set
@@ -86,7 +85,6 @@
 CONFIG_NETFILTER_XT_MATCH_POLICY=y
 CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA=y
 CONFIG_NETFILTER_XT_MATCH_SOCKET=y
 CONFIG_NETFILTER_XT_MATCH_STATE=y
diff --git a/lib/test_bpf.c b/lib/test_bpf.c
index 0362da0..2e38502 100644
--- a/lib/test_bpf.c
+++ b/lib/test_bpf.c
@@ -4656,6 +4656,51 @@
 		{ },
 		{ { 0, 1 } },
 	},
+	{
+		/* Mainly testing JIT + imm64 here. */
+		"JMP_JGE_X: ldimm64 test 1",
+		.u.insns_int = {
+			BPF_ALU32_IMM(BPF_MOV, R0, 0),
+			BPF_LD_IMM64(R1, 3),
+			BPF_LD_IMM64(R2, 2),
+			BPF_JMP_REG(BPF_JGE, R1, R2, 2),
+			BPF_LD_IMM64(R0, 0xffffffffffffffffUL),
+			BPF_LD_IMM64(R0, 0xeeeeeeeeeeeeeeeeUL),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 0xeeeeeeeeU } },
+	},
+	{
+		"JMP_JGE_X: ldimm64 test 2",
+		.u.insns_int = {
+			BPF_ALU32_IMM(BPF_MOV, R0, 0),
+			BPF_LD_IMM64(R1, 3),
+			BPF_LD_IMM64(R2, 2),
+			BPF_JMP_REG(BPF_JGE, R1, R2, 0),
+			BPF_LD_IMM64(R0, 0xffffffffffffffffUL),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 0xffffffffU } },
+	},
+	{
+		"JMP_JGE_X: ldimm64 test 3",
+		.u.insns_int = {
+			BPF_ALU32_IMM(BPF_MOV, R0, 1),
+			BPF_LD_IMM64(R1, 3),
+			BPF_LD_IMM64(R2, 2),
+			BPF_JMP_REG(BPF_JGE, R1, R2, 4),
+			BPF_LD_IMM64(R0, 0xffffffffffffffffUL),
+			BPF_LD_IMM64(R0, 0xeeeeeeeeeeeeeeeeUL),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 1 } },
+	},
 	/* BPF_JMP | BPF_JNE | BPF_X */
 	{
 		"JMP_JNE_X: if (3 != 2) return 1",
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index b7f9ae7..b490af6 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -1059,7 +1059,7 @@
 		return err;
 	}
 
-	if (nla_put(skb, IFLA_PHYS_PORT_NAME, strlen(name), name))
+	if (nla_put_string(skb, IFLA_PHYS_PORT_NAME, name))
 		return -EMSGSIZE;
 
 	return 0;
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 8bc6c4e..39e9acf 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -89,6 +89,7 @@
 #include <linux/netfilter_ipv4.h>
 #include <linux/random.h>
 #include <linux/slab.h>
+#include <linux/netfilter/xt_qtaguid.h>
 
 #include <asm/uaccess.h>
 
@@ -412,6 +413,9 @@
 	if (sk) {
 		long timeout;
 
+#ifdef CONFIG_NETFILTER_XT_MATCH_QTAGUID
+		qtaguid_untag(sock, true);
+#endif
 		/* Applications forget to leave groups before exiting */
 		ip_mc_drop_socket(sk);
 
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 7525f5e..ab0bbcb 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -356,6 +356,9 @@
 			       rt->dst.dev->mtu);
 		return -EMSGSIZE;
 	}
+	if (length < sizeof(struct iphdr))
+		return -EINVAL;
+
 	if (flags&MSG_PROBE)
 		goto out;
 
diff --git a/net/ipv4/tcp_lp.c b/net/ipv4/tcp_lp.c
index c67ece1..7d86fc5 100644
--- a/net/ipv4/tcp_lp.c
+++ b/net/ipv4/tcp_lp.c
@@ -264,13 +264,15 @@
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct lp *lp = inet_csk_ca(sk);
+	u32 delta;
 
 	if (sample->rtt_us > 0)
 		tcp_lp_rtt_sample(sk, sample->rtt_us);
 
 	/* calc inference */
-	if (tcp_time_stamp > tp->rx_opt.rcv_tsecr)
-		lp->inference = 3 * (tcp_time_stamp - tp->rx_opt.rcv_tsecr);
+	delta = tcp_time_stamp - tp->rx_opt.rcv_tsecr;
+	if ((s32)delta > 0)
+		lp->inference = 3 * delta;
 
 	/* test if within inference */
 	if (lp->last_drop && (tcp_time_stamp - lp->last_drop < lp->inference))
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 8615a6b..64e1ba4 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -543,6 +543,7 @@
 			newicsk->icsk_ack.last_seg_size = skb->len - newtp->tcp_header_len;
 		newtp->rx_opt.mss_clamp = req->mss;
 		tcp_ecn_openreq_child(newtp, req);
+		newtp->fastopen_req = NULL;
 		newtp->fastopen_rsk = NULL;
 		newtp->syn_data_acked = 0;
 		newtp->rack.mstamp.v64 = 0;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 0e7c05b..e6bf011 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -1246,7 +1246,7 @@
  * eventually). The difference is that pulled data not copied, but
  * immediately discarded.
  */
-static void __pskb_trim_head(struct sk_buff *skb, int len)
+static int __pskb_trim_head(struct sk_buff *skb, int len)
 {
 	struct skb_shared_info *shinfo;
 	int i, k, eat;
@@ -1256,7 +1256,7 @@
 		__skb_pull(skb, eat);
 		len -= eat;
 		if (!len)
-			return;
+			return 0;
 	}
 	eat = len;
 	k = 0;
@@ -1282,23 +1282,28 @@
 	skb_reset_tail_pointer(skb);
 	skb->data_len -= len;
 	skb->len = skb->data_len;
+	return len;
 }
 
 /* Remove acked data from a packet in the transmit queue. */
 int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len)
 {
+	u32 delta_truesize;
+
 	if (skb_unclone(skb, GFP_ATOMIC))
 		return -ENOMEM;
 
-	__pskb_trim_head(skb, len);
+	delta_truesize = __pskb_trim_head(skb, len);
 
 	TCP_SKB_CB(skb)->seq += len;
 	skb->ip_summed = CHECKSUM_PARTIAL;
 
-	skb->truesize	     -= len;
-	sk->sk_wmem_queued   -= len;
-	sk_mem_uncharge(sk, len);
-	sock_set_flag(sk, SOCK_QUEUE_SHRUNK);
+	if (delta_truesize) {
+		skb->truesize	   -= delta_truesize;
+		sk->sk_wmem_queued -= delta_truesize;
+		sk_mem_uncharge(sk, delta_truesize);
+		sock_set_flag(sk, SOCK_QUEUE_SHRUNK);
+	}
 
 	/* Any change of skb->len requires recalculation of tso factor. */
 	if (tcp_skb_pcount(skb) > 1)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 553138d..58d7c1d 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -3318,7 +3318,8 @@
 				      idev->dev, 0, 0);
 	}
 
-	addrconf_dad_start(ifp);
+	if (ifp->state == INET6_IFADDR_STATE_PREDAD)
+		addrconf_dad_start(ifp);
 
 	return 0;
 }
@@ -3531,6 +3532,7 @@
  */
 static struct notifier_block ipv6_dev_notf = {
 	.notifier_call = addrconf_notify,
+	.priority = ADDRCONF_NOTIFY_PRIORITY,
 };
 
 static void addrconf_type_change(struct net_device *dev, unsigned long event)
@@ -3667,7 +3669,7 @@
 		if (keep) {
 			/* set state to skip the notifier below */
 			state = INET6_IFADDR_STATE_DEAD;
-			ifa->state = 0;
+			ifa->state = INET6_IFADDR_STATE_PREDAD;
 			if (!(ifa->flags & IFA_F_NODAD))
 				ifa->flags |= IFA_F_TENTATIVE;
 
@@ -6319,6 +6321,8 @@
 		goto errlo;
 	}
 
+	ip6_route_init_special_entries();
+
 	for (i = 0; i < IN6_ADDR_HSIZE; i++)
 		INIT_HLIST_HEAD(&inet6_addr_lst[i]);
 
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 1a34da0..83c7d2b 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -630,6 +630,8 @@
 		ipv6_local_error(sk, EMSGSIZE, fl6, rt->dst.dev->mtu);
 		return -EMSGSIZE;
 	}
+	if (length < sizeof(struct ipv6hdr))
+		return -EINVAL;
 	if (flags&MSG_PROBE)
 		goto out;
 
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 7d17670..0b21d61 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -3455,7 +3455,10 @@
 	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
 	struct net *net = dev_net(dev);
 
-	if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) {
+	if (!(dev->flags & IFF_LOOPBACK))
+		return NOTIFY_OK;
+
+	if (event == NETDEV_REGISTER) {
 		net->ipv6.ip6_null_entry->dst.dev = dev;
 		net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
@@ -3464,6 +3467,12 @@
 		net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
 		net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
 #endif
+	 } else if (event == NETDEV_UNREGISTER) {
+		in6_dev_put(net->ipv6.ip6_null_entry->rt6i_idev);
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+		in6_dev_put(net->ipv6.ip6_prohibit_entry->rt6i_idev);
+		in6_dev_put(net->ipv6.ip6_blk_hole_entry->rt6i_idev);
+#endif
 	}
 
 	return NOTIFY_OK;
@@ -3770,9 +3779,24 @@
 
 static struct notifier_block ip6_route_dev_notifier = {
 	.notifier_call = ip6_route_dev_notify,
-	.priority = 0,
+	.priority = ADDRCONF_NOTIFY_PRIORITY - 10,
 };
 
+void __init ip6_route_init_special_entries(void)
+{
+	/* Registering of the loopback is done before this portion of code,
+	 * the loopback reference in rt6_info will not be taken, do it
+	 * manually for init_net */
+	init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
+	init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
+  #ifdef CONFIG_IPV6_MULTIPLE_TABLES
+	init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
+	init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
+	init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
+	init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
+  #endif
+}
+
 int __init ip6_route_init(void)
 {
 	int ret;
@@ -3799,17 +3823,6 @@
 
 	ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
 
-	/* Registering of the loopback is done before this portion of code,
-	 * the loopback reference in rt6_info will not be taken, do it
-	 * manually for init_net */
-	init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
-	init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
-  #ifdef CONFIG_IPV6_MULTIPLE_TABLES
-	init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
-	init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
-	init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
-	init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
-  #endif
 	ret = fib6_init();
 	if (ret)
 		goto out_register_subsys;
diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c
index 3c7ae04..1fbe4b6 100644
--- a/net/netfilter/xt_qtaguid.c
+++ b/net/netfilter/xt_qtaguid.c
@@ -321,7 +321,7 @@
 			 st_entry->tag,
 			 get_uid_from_tag(st_entry->tag));
 		rb_erase(&st_entry->sock_node, st_to_free_tree);
-		sockfd_put(st_entry->socket);
+		sock_put(st_entry->sk);
 		kfree(st_entry);
 	}
 }
@@ -1922,12 +1922,12 @@
 {
 	struct sock_tag *sock_tag_entry = v;
 	uid_t uid;
-	long f_count;
 
 	CT_DEBUG("qtaguid: proc ctrl pid=%u tgid=%u uid=%u\n",
 		 current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()));
 
 	if (sock_tag_entry != SEQ_START_TOKEN) {
+		int sk_ref_count;
 		uid = get_uid_from_tag(sock_tag_entry->tag);
 		CT_DEBUG("qtaguid: proc_read(): sk=%p tag=0x%llx (uid=%u) "
 			 "pid=%u\n",
@@ -1936,13 +1936,13 @@
 			 uid,
 			 sock_tag_entry->pid
 			);
-		f_count = atomic_long_read(
-			&sock_tag_entry->socket->file->f_count);
+		sk_ref_count = atomic_read(
+			&sock_tag_entry->sk->sk_refcnt);
 		seq_printf(m, "sock=%pK tag=0x%llx (uid=%u) pid=%u "
-			   "f_count=%lu\n",
+			   "f_count=%d\n",
 			   sock_tag_entry->sk,
 			   sock_tag_entry->tag, uid,
-			   sock_tag_entry->pid, f_count);
+			   sock_tag_entry->pid, sk_ref_count);
 	} else {
 		seq_printf(m, "events: sockets_tagged=%llu "
 			   "sockets_untagged=%llu "
@@ -2238,8 +2238,8 @@
 			from_kuid(&init_user_ns, current_fsuid()));
 		goto err;
 	}
-	CT_DEBUG("qtaguid: ctrl_tag(%s): socket->...->f_count=%ld ->sk=%p\n",
-		 input, atomic_long_read(&el_socket->file->f_count),
+	CT_DEBUG("qtaguid: ctrl_tag(%s): socket->...->sk_refcnt=%d ->sk=%p\n",
+		 input, atomic_read(&el_socket->sk->sk_refcnt),
 		 el_socket->sk);
 	if (argc < 3) {
 		acct_tag = make_atag_from_value(0);
@@ -2283,16 +2283,9 @@
 		struct tag_ref *prev_tag_ref_entry;
 
 		CT_DEBUG("qtaguid: ctrl_tag(%s): retag for sk=%p "
-			 "st@%p ...->f_count=%ld\n",
+			 "st@%p ...->sk_refcnt=%d\n",
 			 input, el_socket->sk, sock_tag_entry,
-			 atomic_long_read(&el_socket->file->f_count));
-		/*
-		 * This is a re-tagging, so release the sock_fd that was
-		 * locked at the time of the 1st tagging.
-		 * There is still the ref from this call's sockfd_lookup() so
-		 * it can be done within the spinlock.
-		 */
-		sockfd_put(sock_tag_entry->socket);
+			 atomic_read(&el_socket->sk->sk_refcnt));
 		prev_tag_ref_entry = lookup_tag_ref(sock_tag_entry->tag,
 						    &uid_tag_data_entry);
 		BUG_ON(IS_ERR_OR_NULL(prev_tag_ref_entry));
@@ -2312,8 +2305,12 @@
 			res = -ENOMEM;
 			goto err_tag_unref_put;
 		}
+		/*
+		 * Hold the sk refcount here to make sure the sk pointer cannot
+		 * be freed and reused
+		 */
+		sock_hold(el_socket->sk);
 		sock_tag_entry->sk = el_socket->sk;
-		sock_tag_entry->socket = el_socket;
 		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);
@@ -2340,10 +2337,11 @@
 		atomic64_inc(&qtu_events.sockets_tagged);
 	}
 	spin_unlock_bh(&sock_tag_list_lock);
-	/* We keep the ref to the socket (file) until it is untagged */
-	CT_DEBUG("qtaguid: ctrl_tag(%s): done st@%p ...->f_count=%ld\n",
+	/* We keep the ref to the sk until it is untagged */
+	CT_DEBUG("qtaguid: ctrl_tag(%s): done st@%p ...->sk_refcnt=%d\n",
 		 input, sock_tag_entry,
-		 atomic_long_read(&el_socket->file->f_count));
+		 atomic_read(&el_socket->sk->sk_refcnt));
+	sockfd_put(el_socket);
 	return 0;
 
 err_tag_unref_put:
@@ -2351,8 +2349,8 @@
 	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. ...->f_count=%ld\n",
-		 input, atomic_long_read(&el_socket->file->f_count) - 1);
+	CT_DEBUG("qtaguid: ctrl_tag(%s): done. ...->sk_refcnt=%d\n",
+		 input, atomic_read(&el_socket->sk->sk_refcnt) - 1);
 	/* Release the sock_fd that was grabbed by sockfd_lookup(). */
 	sockfd_put(el_socket);
 	return res;
@@ -2368,17 +2366,13 @@
 	int sock_fd = 0;
 	struct socket *el_socket;
 	int res, argc;
-	struct sock_tag *sock_tag_entry;
-	struct tag_ref *tag_ref_entry;
-	struct uid_tag_data *utd_entry;
-	struct proc_qtu_data *pqd_entry;
 
 	argc = sscanf(input, "%c %d", &cmd, &sock_fd);
 	CT_DEBUG("qtaguid: ctrl_untag(%s): argc=%d cmd=%c sock_fd=%d\n",
 		 input, argc, cmd, sock_fd);
 	if (argc < 2) {
 		res = -EINVAL;
-		goto err;
+		return res;
 	}
 	el_socket = sockfd_lookup(sock_fd, &res);  /* This locks the file */
 	if (!el_socket) {
@@ -2386,17 +2380,31 @@
 			" sock_fd=%d err=%d pid=%u tgid=%u uid=%u\n",
 			input, sock_fd, res, current->pid, current->tgid,
 			from_kuid(&init_user_ns, current_fsuid()));
-		goto err;
+		return res;
 	}
 	CT_DEBUG("qtaguid: ctrl_untag(%s): socket->...->f_count=%ld ->sk=%p\n",
 		 input, atomic_long_read(&el_socket->file->f_count),
 		 el_socket->sk);
+	res = qtaguid_untag(el_socket, false);
+	sockfd_put(el_socket);
+	return res;
+}
+
+int qtaguid_untag(struct socket *el_socket, bool kernel)
+{
+	int res;
+	pid_t pid;
+	struct sock_tag *sock_tag_entry;
+	struct tag_ref *tag_ref_entry;
+	struct uid_tag_data *utd_entry;
+	struct proc_qtu_data *pqd_entry;
+
 	spin_lock_bh(&sock_tag_list_lock);
 	sock_tag_entry = get_sock_stat_nl(el_socket->sk);
 	if (!sock_tag_entry) {
 		spin_unlock_bh(&sock_tag_list_lock);
 		res = -EINVAL;
-		goto err_put;
+		return res;
 	}
 	/*
 	 * The socket already belongs to the current process
@@ -2408,20 +2416,26 @@
 	BUG_ON(!tag_ref_entry);
 	BUG_ON(tag_ref_entry->num_sock_tags <= 0);
 	spin_lock_bh(&uid_tag_data_tree_lock);
+	if (kernel)
+		pid = sock_tag_entry->pid;
+	else
+		pid = current->tgid;
 	pqd_entry = proc_qtu_data_tree_search(
-		&proc_qtu_data_tree, current->tgid);
+		&proc_qtu_data_tree, pid);
 	/*
 	 * TODO: remove if, and start failing.
 	 * At first, we want to catch user-space code that is not
 	 * opening the /dev/xt_qtaguid.
 	 */
-	if (IS_ERR_OR_NULL(pqd_entry))
+	if (IS_ERR_OR_NULL(pqd_entry) || !sock_tag_entry->list.next) {
 		pr_warn_once("qtaguid: %s(): "
 			     "User space forgot to open /dev/xt_qtaguid? "
-			     "pid=%u tgid=%u uid=%u\n", __func__,
-			     current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()));
-	else
+			     "pid=%u tgid=%u sk_pid=%u, uid=%u\n", __func__,
+			     current->pid, current->tgid, sock_tag_entry->pid,
+			     from_kuid(&init_user_ns, current_fsuid()));
+	} else {
 		list_del(&sock_tag_entry->list);
+	}
 	spin_unlock_bh(&uid_tag_data_tree_lock);
 	/*
 	 * We don't free tag_ref from the utd_entry here,
@@ -2430,30 +2444,17 @@
 	tag_ref_entry->num_sock_tags--;
 	spin_unlock_bh(&sock_tag_list_lock);
 	/*
-	 * Release the sock_fd that was grabbed at tag time,
-	 * and once more for the sockfd_lookup() here.
+	 * Release the sock_fd that was grabbed at tag time.
 	 */
-	sockfd_put(sock_tag_entry->socket);
-	CT_DEBUG("qtaguid: ctrl_untag(%s): done. st@%p ...->f_count=%ld\n",
-		 input, sock_tag_entry,
-		 atomic_long_read(&el_socket->file->f_count) - 1);
-	sockfd_put(el_socket);
+	sock_put(sock_tag_entry->sk);
+	CT_DEBUG("qtaguid: done. st@%p ...->sk_refcnt=%d\n",
+		 sock_tag_entry,
+		 atomic_read(&el_socket->sk->sk_refcnt));
 
 	kfree(sock_tag_entry);
 	atomic64_inc(&qtu_events.sockets_untagged);
 
 	return 0;
-
-err_put:
-	CT_DEBUG("qtaguid: ctrl_untag(%s): done. socket->...->f_count=%ld\n",
-		 input, atomic_long_read(&el_socket->file->f_count) - 1);
-	/* Release the sock_fd that was grabbed by sockfd_lookup(). */
-	sockfd_put(el_socket);
-	return res;
-
-err:
-	CT_DEBUG("qtaguid: ctrl_untag(%s): done.\n", input);
-	return res;
 }
 
 static ssize_t qtaguid_ctrl_parse(const char *input, size_t count)
diff --git a/net/netfilter/xt_qtaguid_internal.h b/net/netfilter/xt_qtaguid_internal.h
index 6dc14a9..8178fbd 100644
--- a/net/netfilter/xt_qtaguid_internal.h
+++ b/net/netfilter/xt_qtaguid_internal.h
@@ -256,8 +256,6 @@
 struct sock_tag {
 	struct rb_node sock_node;
 	struct sock *sk;  /* Only used as a number, never dereferenced */
-	/* The socket is needed for sockfd_put() */
-	struct socket *socket;
 	/* Used to associate with a given pid */
 	struct list_head list;   /* in proc_qtu_data.sock_tag_list */
 	pid_t pid;
diff --git a/net/netfilter/xt_qtaguid_print.c b/net/netfilter/xt_qtaguid_print.c
index f6a00a3..2a7190d 100644
--- a/net/netfilter/xt_qtaguid_print.c
+++ b/net/netfilter/xt_qtaguid_print.c
@@ -24,7 +24,7 @@
 #include <linux/rbtree.h>
 #include <linux/slab.h>
 #include <linux/spinlock_types.h>
-
+#include <net/sock.h>
 
 #include "xt_qtaguid_internal.h"
 #include "xt_qtaguid_print.h"
@@ -237,10 +237,10 @@
 	tag_str = pp_tag_t(&st->tag);
 	res = kasprintf(GFP_ATOMIC, "sock_tag@%p{"
 			"sock_node=rb_node{...}, "
-			"sk=%p socket=%p (f_count=%lu), list=list_head{...}, "
+			"sk=%p (f_count=%d), list=list_head{...}, "
 			"pid=%u, tag=%s}",
-			st, st->sk, st->socket, atomic_long_read(
-				&st->socket->file->f_count),
+			st, st->sk, atomic_read(
+				&st->sk->sk_refcnt),
 			st->pid, tag_str);
 	_bug_on_err_or_null(res);
 	kfree(tag_str);
diff --git a/net/rfkill/core.c b/net/rfkill/core.c
index 9b4260d..a9a7128 100644
--- a/net/rfkill/core.c
+++ b/net/rfkill/core.c
@@ -796,8 +796,7 @@
 }
 EXPORT_SYMBOL(rfkill_resume_polling);
 
-#ifdef CONFIG_RFKILL_PM
-static int rfkill_suspend(struct device *dev)
+static __maybe_unused int rfkill_suspend(struct device *dev)
 {
 	struct rfkill *rfkill = to_rfkill(dev);
 
@@ -807,7 +806,7 @@
 	return 0;
 }
 
-static int rfkill_resume(struct device *dev)
+static __maybe_unused int rfkill_resume(struct device *dev)
 {
 	struct rfkill *rfkill = to_rfkill(dev);
 	bool cur;
@@ -827,19 +826,13 @@
 }
 
 static SIMPLE_DEV_PM_OPS(rfkill_pm_ops, rfkill_suspend, rfkill_resume);
-#define RFKILL_PM_OPS (&rfkill_pm_ops)
-#else
-#define RFKILL_PM_OPS NULL
-#endif
 
 static struct class rfkill_class = {
 	.name		= "rfkill",
 	.dev_release	= rfkill_release,
 	.dev_groups	= rfkill_dev_groups,
 	.dev_uevent	= rfkill_dev_uevent,
-#ifdef CONFIG_RFKILL_PM
-	.pm		= RFKILL_PM_OPS,
-#endif
+	.pm		= IS_ENABLED(CONFIG_RFKILL_PM) ? &rfkill_pm_ops : NULL,
 };
 
 bool rfkill_blocked(struct rfkill *rfkill)
diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c
index 44ac85f..d0ca0db 100644
--- a/net/xfrm/xfrm_algo.c
+++ b/net/xfrm/xfrm_algo.c
@@ -241,7 +241,7 @@
 
 	.uinfo = {
 		.auth = {
-			.icv_truncbits = 96,
+			.icv_truncbits = 128,
 			.icv_fullbits = 256,
 		}
 	},
diff --git a/samples/bpf/test_verifier.c b/samples/bpf/test_verifier.c
index 369ffaa..dc7dec9 100644
--- a/samples/bpf/test_verifier.c
+++ b/samples/bpf/test_verifier.c
@@ -1218,16 +1218,22 @@
 		.result = ACCEPT,
 	},
 	{
-		"unpriv: obfuscate stack pointer",
+		"stack pointer arithmetic",
 		.insns = {
-			BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
-			BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
-			BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+			BPF_MOV64_IMM(BPF_REG_1, 4),
+			BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+			BPF_MOV64_REG(BPF_REG_7, BPF_REG_10),
+			BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -10),
+			BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -10),
+			BPF_MOV64_REG(BPF_REG_2, BPF_REG_7),
+			BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_1),
+			BPF_ST_MEM(0, BPF_REG_2, 4, 0),
+			BPF_MOV64_REG(BPF_REG_2, BPF_REG_7),
+			BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, 8),
+			BPF_ST_MEM(0, BPF_REG_2, 4, 0),
 			BPF_MOV64_IMM(BPF_REG_0, 0),
 			BPF_EXIT_INSN(),
 		},
-		.errstr_unpriv = "R2 pointer arithmetic",
-		.result_unpriv = REJECT,
 		.result = ACCEPT,
 	},
 	{
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index bc44626..5cb7e04 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -2155,7 +2155,20 @@
 		/* cancel the pending probing work */
 		chip = card->private_data;
 		hda = container_of(chip, struct hda_intel, chip);
+		/* FIXME: below is an ugly workaround.
+		 * Both device_release_driver() and driver_probe_device()
+		 * take *both* the device's and its parent's lock before
+		 * calling the remove() and probe() callbacks.  The codec
+		 * probe takes the locks of both the codec itself and its
+		 * parent, i.e. the PCI controller dev.  Meanwhile, when
+		 * the PCI controller is unbound, it takes its lock, too
+		 * ==> ouch, a deadlock!
+		 * As a workaround, we unlock temporarily here the controller
+		 * device during cancel_work_sync() call.
+		 */
+		device_unlock(&pci->dev);
 		cancel_work_sync(&hda->probe_work);
+		device_lock(&pci->dev);
 
 		snd_card_free(card);
 	}
diff --git a/sound/soc/codecs/wcd_cpe_core.c b/sound/soc/codecs/wcd_cpe_core.c
index cf014d7..0c2f41a 100644
--- a/sound/soc/codecs/wcd_cpe_core.c
+++ b/sound/soc/codecs/wcd_cpe_core.c
@@ -1725,10 +1725,10 @@
 	if (pos)
 		copy_count = pos - buf;
 
-	if (copy_count > WCD_CPE_IMAGE_FNAME_MAX) {
+	if (copy_count > (WCD_CPE_IMAGE_FNAME_MAX - 1)) {
 		dev_err(core->dev,
 			"%s: Invalid length %d, max allowed %d\n",
-			__func__, copy_count, WCD_CPE_IMAGE_FNAME_MAX);
+			__func__, copy_count, WCD_CPE_IMAGE_FNAME_MAX - 1);
 		return -EINVAL;
 	}
 
diff --git a/tools/power/cpupower/utils/helpers/cpuid.c b/tools/power/cpupower/utils/helpers/cpuid.c
index 93b0aa7..39c2c7d 100644
--- a/tools/power/cpupower/utils/helpers/cpuid.c
+++ b/tools/power/cpupower/utils/helpers/cpuid.c
@@ -156,6 +156,7 @@
 					 */
 			case 0x2C:	/* Westmere EP - Gulftown */
 				cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
+				break;
 			case 0x2A:	/* SNB */
 			case 0x2D:	/* SNB Xeon */
 			case 0x3A:	/* IVB */
diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile
index a89f80a..6300c1a 100644
--- a/tools/testing/selftests/x86/Makefile
+++ b/tools/testing/selftests/x86/Makefile
@@ -5,7 +5,7 @@
 .PHONY: all all_32 all_64 warn_32bit_failure clean
 
 TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall test_mremap_vdso \
-			check_initial_reg_state sigreturn ldt_gdt iopl \
+			check_initial_reg_state sigreturn ldt_gdt iopl mpx-mini-test \
 			protection_keys
 TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \
 			test_FCMOV test_FCOMI test_FISTTP \