Merge "msm: camera: Port msm-4.4 camera kernel on msm-4.9 kernel"
diff --git a/Documentation/devicetree/bindings/arm/msm/clock-controller.txt b/Documentation/devicetree/bindings/arm/msm/clock-controller.txt
index 83a1601..4afbb24b 100644
--- a/Documentation/devicetree/bindings/arm/msm/clock-controller.txt
+++ b/Documentation/devicetree/bindings/arm/msm/clock-controller.txt
@@ -20,6 +20,28 @@
                         "qcom,gcc-gfx-8953"
                         "qcom,gcc-gfx-sdm450"
                         "qcom,gcc-gfx-sdm632"
+			"qcom,gcc-8992"
+			"qcom,gcc-8952"
+			"qcom,gcc-8937"
+			"qcom,gcc-8917"
+			"qcom,gcc-8940"
+			"qcom,gcc-8920"
+			"qcom,gcc-spm-8952"
+			"qcom,gcc-spm-8937"
+			"qcom,cc-debug-8952"
+			"qcom,cc-debug-8953"
+			"qcom,cc-debug-8937"
+			"qcom,cc-debug-8917"
+			"qcom,cc-debug-8940"
+			"qcom,cc-debug-8920"
+			"qcom,gcc-mdss-8953"
+			"qcom,gcc-mdss-8952"
+			"qcom,gcc-mdss-8937"
+			"qcom,gcc-mdss-8917"
+			"qcom,gcc-mdss-8940"
+			"qcom,gcc-mdss-8920"
+			"qcom,gcc-gfx-8953"
+			"qcom,gcc-gfx-sdm450"
 
 - reg:                  Pairs of physical base addresses and region sizes of
                         memory mapped registers.
diff --git a/Documentation/devicetree/bindings/arm/msm/clock-cpu-8939.txt b/Documentation/devicetree/bindings/arm/msm/clock-cpu-8939.txt
new file mode 100644
index 0000000..d9e1510
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/clock-cpu-8939.txt
@@ -0,0 +1,78 @@
+Qualcomm Technology MSM8939 CPU clock tree
+
+clock-cpu-8939 is a device that represents the MSM8939 or MSM8952 CPU
+subsystem clock tree. It lists the various power supplies that need to be
+scaled when the clocks are scaled and also other HW specific parameters like
+fmax tables, avs settings table, etc.
+
+Required properties:
+- compatible:		Must be one of "qcom,clock-cpu-8939" or
+			"qcom,cpu-clock-8952", "qcom,cpu-clock-8917".
+- reg:			Pairs of physical base addresses and region sizes of
+			memory mapped registers.
+- reg-names:		Names of the bases for the above registers. Expected
+			bases are:
+			"apcs-c0-rcg-base", "apcs-c1-rcg-base",
+			"apcs-cci-rcg-base", "efuse", "efuse1", "efuse2"
+- vdd-c0-supply:	The regulator powering the little cluster
+- vdd-c1-supply:	The regulator powering the big cluster
+- vdd-cci-supply:	The regulator powering the CCI cluster
+- qcom,speedX-bin-vY-ZZZ:
+			A table of CPU frequency (Hz) to voltage (corner)
+			mapping that represents the max frequency possible
+			for each supported voltage level for a CPU. 'X' is
+			the speed bin into which the device falls into - a
+			bin will have unique frequency-voltage relationships.
+			'Y' is the characterization version, implying that
+			characterization (deciding what speed bin a device
+			falls into) methods and/or encoding may change. The
+			values 'X' and 'Y' are read from efuse registers, and
+			the right table is picked from multiple possible tables.
+			'ZZZ' can be c1, c0 or cci depending on whether the table
+			is for the big cluster, little cluster or cci.
+Optional properties:
+- qcom,cpu-pcnoc-vote:  Boolean to indicate cpu clocks would need to keep
+			active pcnoc vote.
+- qcom,num-cluster:     Boolean to indicate cpu clock code is used for single
+			cluster.
+Example:
+	clock_cpu: qcom,cpu-clock-8939@f9015000 {
+		compatible = "qcom,cpu-clock-8939";
+		reg = <0xf9015000 0x1000>,
+		      <0xf9016000 0x1000>,
+		      <0xf9011000 0x1000>,
+		      <0xf900d000 0x1000>,
+		      <0xf900f000 0x1000>,
+		      <0xf9112000 0x1000>;
+		reg-names = "apcs-c0-rcg-base", "apcs-c1-rcg-base",
+			     "apcs-cci-rcg-base", "efuse", "efuse1",
+				"efuse2";
+                vdd-c0-supply = <&apc_vreg_corner>;
+		vdd-c1-supply = <&apc_vreg_corner>;
+		vdd-cci-supply = <&apc_vreg_corner>;
+		qcom,speed0-bin-v0-c0 =
+			<         0 0>,
+			< 384000000 1>,
+			< 787200000 2>,
+			<1286400000 3>;
+		qcom,speed0-bin-v0-c1 =
+			<         0 0>,
+			< 384000000 1>,
+			< 787200000 2>,
+			<1785600000 3>;
+		qcom,speed0-bin-v0-cci =
+			<         0 0>,
+			< 150000000 1>,
+			< 300000000 2>,
+			< 600000000 3>;
+		clocks = <&clock_gcc clk_gpll0_ao>,
+			<&clock_gcc clk_a53ss_c0_pll>,
+			<&clock_gcc clk_gpll0_ao>,
+			<&clock_gcc clk_a53ss_c1_pll>,
+			<&clock_gcc clk_gpll0_ao>,
+			<&clock_gcc clk_a53ss_cci_pll>;
+			clock-names = "clk-c0-4", "clk-c0-5",
+			"clk-c1-4", "clk-c1-5",
+			"clk-cci-4", "clk-cci-5";
+		#clock-cells = <1>;
+};
diff --git a/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt b/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt
index 36e1a69..a53eba5 100644
--- a/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt
+++ b/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt
@@ -4,15 +4,28 @@
 It tells about the individual masters information at any given
 time like "system sleep counts", "system sleep last entered at"
 and "system sleep accumulated duration" etc. These stats can be
-show to the user using the debugfs interface of the kernel.
+displayed using the sysfs interface.
 To achieve this, device tree node has been added.
 
+Additionally, RPMH master stats also maintains application processor's
+master stats. It uses profiling units to calculate power down and power
+up stats.
+
 The required properties for rpmh-master-stats are:
 
-- compatible: "qcom,rpmh-master-stats".
+- compatible:
+	Usage: required
+	Value type: <string>
+	Definition: Should be "qcom,rpmh-master-stats-v1".
+
+- reg:
+	Usage: required
+	Value type: <prop-encoded-array>
+	Definition: Specifies physical address of start of profiling unit.
 
 Example:
 
 qcom,rpmh-master-stats {
 	compatible = "qcom,rpmh-master-stats";
+	reg = <0xb221200 0x60>;
 };
diff --git a/Documentation/devicetree/bindings/display/bridge/lt9611.txt b/Documentation/devicetree/bindings/display/bridge/lt9611.txt
new file mode 100644
index 0000000..61688b5
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/lt9611.txt
@@ -0,0 +1,125 @@
+LT9611 DSI to HDMI bridge
+
+
+Required properties:
+	- compatible:				Must be "lt,lt9611"
+	- reg:					Main I2C slave ID (for I2C host driver)
+	- lt,irq-gpio:				Main IRQ gpio mapping
+	- lt,reset-gpio				Main reset gpio mapping
+
+
+	Optional properties:
+	- lt,hdmi-ps-gpio:			gpio mapping for HDMI PS
+	- lt,hdmi-en-gpio:			gpio mapping for HDMI EN
+
+	- lt,supply-entries:			A node that lists the elements of the supply used to
+						power the bridge. There can be more than one instance
+						of this binding, in which case the entry would be
+						appended with the supply entry index.
+	e.g. lt,supply-entry@0
+	-- lt,supply-name: name of the supply (vdd/vcc)
+	-- lt,supply-min-voltage: minimum voltage level (uV)
+	-- lt,supply-max-voltage: maximum voltage level (uV)
+	-- lt,supply-enable-load: load drawn (uA) from enabled supply
+	-- lt,supply-disable-load: load drawn (uA) from disabled supply
+	-- lt,supply-ulp-load: load drawn (uA) from supply in ultra-low power mode
+	-- lt,supply-pre-on-sleep: time to sleep (ms) before turning on
+	-- lt,supply-post-on-sleep: time to sleep (ms) after turning on
+	-- lt,supply-pre-off-sleep: time to sleep (ms) before turning off
+	-- lt,supply-post-off-sleep: time to sleep (ms) after turning off
+
+	- lt,non-pluggable: Boolean to indicate if display is non pluggable.
+	- lt,customize-modes: Customized modes when it's non-pluggable display.
+	e.g. lt,customize-mode-id@0
+	-- lt,mode-h-active: Horizontal active pixels for this mode.
+	-- lt,mode-h-front-porch: Horizontal front porch in pixels for this mode.
+	-- lt,mode-h-pulse-width: Horizontal sync width in pixels for this mode.
+	-- lt,mode-h-back-porch: Horizontal back porch in pixels for this mode.
+	-- lt,mode-h-active-high: Boolean to indicate if mode horizontal polarity is active high.
+	-- lt,mode-v-active: Vertical active lines for this mode.
+	-- lt,mode-v-front-porch: Vertical front porch in lines for this mode.
+	-- lt,mode-v-pulse-width: Vertical sync width in lines for this mode.
+	-- lt,mode-v-back-porch: Vertical back porch in lines for this mode.
+	-- lt,mode-v-active-high: Boolean to indicate if mode vertical polarity is active high.
+	-- lt,mode-refersh-rate: Mode refresh rate in hertz.
+	-- lt,mode-clock-in-khz: Mode pclk in KHz.
+
+Required nodes:
+
+The LT9611 has one video port. Its connection is modelled using the OF
+graph bindings specified in Documentation/devicetree/bindings/graph.txt.
+Video port 0 is for the DSI input. The remote endpoint phandle should
+be a reference to a valid mipi_dsi_host device node.
+
+
+Example:
+
+&qupv3_se9_i2c {
+	status = "okay";
+	lt9611@3b {
+		compatible = "lt,lt9611";
+		reg = <0x3b>;
+		interrupt-parent = <&tlmm>;
+		interrupts = <125 0>;
+		interrupt-names = "lt_irq";
+		lt,irq-gpio = <&tlmm 125 0x0>;
+		lt,reset-gpio = <&tlmm 134 0x0>;
+		lt,hdmi-ps-gpio = <&tlmm 136 0x0>;
+		lt,hdmi-en-gpio = <&tlmm 137 0x0>;
+
+		vcc-supply = <&pm660l_l6>;
+		vdd-supply = <&pm660_l11>;
+		lt,supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			lt,supply-entry@0 {
+				reg = <0>;
+				lt,supply-name = "vcc";
+				lt,supply-min-voltage = <3300000>;
+				lt,supply-max-voltage = <3300000>;
+				lt,supply-enable-load = <200000>;
+				lt,supply-post-on-sleep = <50>;
+			};
+
+			lt,supply-entry@1 {
+				reg = <1>;
+				lt,supply-name = "vdd";
+				lt,supply-min-voltage = <1800000>;
+				lt,supply-max-voltage = <1800000>;
+				lt,supply-enable-load = <200000>;
+				lt,supply-post-on-sleep = <50>;
+			};
+		};
+
+		lt,customize-modes {
+			lt,customize-mode-id@0 {
+				lt,mode-h-active = <1920>;
+				lt,mode-h-front-porch = <88>;
+				lt,mode-h-pulse-width = <44>;
+				lt,mode-h-back-porch = <148>;
+				lt,mode-h-active-high;
+				lt,mode-v-active = <1080>;
+				lt,mode-v-front-porch = <4>;
+				lt,mode-v-pulse-width = <5>;
+				lt,mode-v-back-porch = <36>;
+				lt,mode-v-active-high;
+				lt,mode-refresh-rate = <60>;
+				lt,mode-clock-in-khz = <148500>;
+			};
+		};
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				lt9611_in: endpoint {
+				remote-endpoint = <&ext_dsi_out>;
+				};
+			};
+		};
+	};
+};
+
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt
index 176f9e1..169f848 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt
@@ -182,6 +182,10 @@
 				  be edge triggered. Otherwise, it is level triggered.
 - qcom,hw-strobe-active-low	: Boolean property to select strobe signal polarity. If defined, hw-strobe
 				  signal polarity is set to active-low, else it is active-high.
+- qcom,symmetry-en	: Boolean property to specify if the flash LEDs under a
+			  switch node are controlled symmetrically. This needs
+			  to be specified if a group of flash LED channels are
+			  connected to a single LED.
 Example:
 	qcom,leds@d300 {
 		compatible = "qcom,qpnp-flash-led-v2";
@@ -302,6 +306,7 @@
 			qcom,led-mask = <3>;
 			qcom,default-led-trigger =
 						"switch0_trigger";
+			qcom,symmetry-en;
 		};
 
 		pmi8998_switch1: qcom,led_switch_1 {
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt
new file mode 100644
index 0000000..3481b80
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt
@@ -0,0 +1,201 @@
+Qualcomm Techonologies, Inc. QPNP PMIC QGAUGE (QG) Device
+
+QPNP PMIC QGAUGE device provides the ability to gauge the State-of-Charge
+of the battery. It provides an interface to the clients to read various
+battery related parameters.
+
+=======================
+Required Node Structure
+=======================
+
+Qgauge device must be described in two level of nodes. The first level
+describes the properties of the Qgauge device and the second level
+describes the peripherals managed/used of the module.
+
+====================================
+First Level Node - QGAUGE device
+====================================
+
+- compatible
+	Usage:      required
+	Value type: <string>
+	Definition: Should be "qcom,qpnp-qg".
+
+- qcom,pmic-revid
+	Usage:      required
+	Value type: <phandle>
+	Definition: Should specify the phandle of PMIC revid module. This is
+		    used to identify the PMIC subtype.
+
+- qcom,qg-vadc
+	Usage:      required
+	Value type: <phandle>
+	Definition: Phandle for the VADC node, it is used for BATT_ID and
+		    BATT_THERM readings.
+
+- qcom,vbatt-empty-mv
+	Usage:      optional
+	Value type: <u32>
+	Definition: The battery voltage threshold (in mV) at which the
+		    vbatt-empty interrupt fires. The SOC is forced to 0
+		    when this interrupt fires. If not specified, the
+		    default value is 3200 mV.
+
+- qcom,vbatt-cutoff-mv
+	Usage:      optional
+	Value type: <u32>
+	Definition: The battery voltage threshold (in mV) at which the
+		    the Qgauge algorithm converges to 0 SOC. If not specified
+		    the default value is 3400 mV.
+
+- qcom,vbatt-low-mv
+	Usage:      optional
+	Value type: <u32>
+	Definition: The battery voltage threshold (in mV) at which the
+		    the VBAT_LOW interrupt fires. Software can take necessary
+		    the action when this interrupt fires. If not specified
+		    the default value is 3500 mV.
+
+- qcom,qg-iterm-ma
+	Usage:      optional
+	Value type: <u32>
+	Definition: The battery current (in mA) at which the the QG algorithm
+		    converges the SOC to 100% during charging and can be used to
+		    terminate charging. If not specified, the default value is
+		    100mA.
+
+- qcom,delta-soc
+	Usage:      optional
+	Value type: <u32>
+	Definition: The SOC percentage increase at which the SOC is
+		    periodically reported to the userspace. If not specified,
+		    the value defaults to 1%.
+
+- qcom,s2-fifo-length
+	Usage:      optional
+	Value type: <u32>
+	Definition: The total number if FIFO samples which need to be filled up
+		    in S2 state of QG to fire the FIFO DONE interrupt.
+		    Minimum value = 1 Maximum Value = 8. If not specified,
+		    the default value is 5.
+
+- qcom,s2-acc-length
+	Usage:      optional
+	Value type: <u32>
+	Definition: The number of distinct V & I samples to be accumulated
+		    in each FIFO in the S2 state of QG.
+		    Minimum Value = 0 Maximum Value = 256. If not specified,
+		    the default value is 128.
+
+- qcom,s2-acc-interval-ms
+	Usage:      optional
+	Value type: <u32>
+	Definition: The time (in ms) between each of the V & I samples being
+		    accumulated in FIFO.
+		    Minimum Value = 0 ms Maximum Value = 2550 ms. If not
+		    specified the default value is 100 ms.
+
+- qcom,ocv-timer-expiry-min
+	Usage:      optional
+	Value type: <u32>
+	Definition: The maximum time (in minutes) for the QG to transition from
+		    S3 to S2 state.
+		    Minimum Value = 2 min Maximum Value = 30 min. If not
+		    specified the hardware default is set to 14 min.
+
+- qcom,ocv-tol-threshold-uv
+	Usage:      optional
+	Value type: <u32>
+	Definition: The OCV detection error tolerance (in uV). The maximum
+		    voltage allowed between 2 VBATT readings in the S3 state
+		    to qualify for a valid OCV.
+		    Minimum Value = 0 uV Maximum Value = 12262 uV  Step = 195 uV
+
+- qcom,s3-entry-fifo-length
+	Usage:      optional
+	Value type: <u32>
+	Definition: The minimum number if FIFO samples which have to qualify the
+		    S3 IBAT entry threshold (qcom,s3-entry-ibat-ua) for QG
+		    to enter into S3 state.
+		    Minimum Value = 1 Maximum Value = 8. The hardware default
+		    is configured to 3.
+
+- qcom,s3-entry-ibat-ua
+	Usage:      optional
+	Value type: <u32>
+	Definition: The battery current (in uA) for the QG to enter into the S3
+		    state. The QG algorithm enters into S3 if the battery
+		    current is lower than this threshold consecutive for
+		    the FIFO length specified in 'qcom,s3-entry-fifo-length'.
+		    Minimum Value = 0 uA Maximum Value = 155550 uA
+		    Step = 610 uA.
+
+- qcom,s3-exit-ibat-ua
+	Usage:      optional
+	Value type: <u32>
+	Definition: The battery current (in uA) for the QG to exit S3 state.
+		    If the battery current is higher than this threshold QG
+		    exists S3 state.
+		    Minimum Value = 0 uA Maximum Value = 155550 uA
+		    Step = 610 uA.
+
+- qcom,rbat-conn-mohm
+	Usage:      optional
+	Value type: <u32>
+	Definition: Resistance of the battery connectors in mOhms.
+
+==========================================================
+Second Level Nodes - Peripherals managed by QGAUGE driver
+==========================================================
+- reg
+	Usage:      required
+	Value type: <prop-encoded-array>
+	Definition: Addresses and sizes for the specified peripheral
+
+- interrupts
+	Usage:      optional
+	Value type: <prop-encoded-array>
+	Definition: Interrupt mapping as per the interrupt encoding
+
+- interrupt-names
+	Usage:      optional
+	Value type: <stringlist>
+	Definition: Interrupt names.  This list must match up 1-to-1 with the
+		    interrupts specified in the 'interrupts' property.
+
+========
+Example
+========
+
+pmi632_qg: qpnp,qg {
+	compatible = "qcom,qpnp-qg";
+	qcom,pmic-revid = <&pmi632_revid>;
+	qcom,qg-vadc = <&pmi632_vadc>;
+	qcom,vbatt-empty-mv = <3200>;
+	qcom,vbatt-low-mv = <3500>;
+	qcom,vbatt-cutoff-mv = <3400>;
+	qcom,qg-iterm-ma = <100>;
+
+	qcom,qgauge@4800 {
+		status = "okay";
+		reg = <0x4800 0x100>;
+		interrupts = <0x2 0x48 0x0 IRQ_TYPE_EDGE_BOTH>,
+			     <0x2 0x48 0x1 IRQ_TYPE_EDGE_BOTH>,
+			     <0x2 0x48 0x2 IRQ_TYPE_EDGE_BOTH>,
+			     <0x2 0x48 0x4 IRQ_TYPE_EDGE_BOTH>,
+			     <0x2 0x48 0x5 IRQ_TYPE_EDGE_BOTH>,
+			     <0x2 0x48 0x6 IRQ_TYPE_EDGE_BOTH>;
+		interrupt-names = "qg-batt-missing",
+				  "qg-vbat-low",
+				  "qg-vbat-empty",
+				  "qg-fifo-done",
+				  "qg-good-ocv",
+				  "qg-fsm-state-chg",
+				  "qg-event";
+	};
+
+	qcom,qg-sdam@b000 {
+		status = "okay";
+		reg = <0xb000 0x100>;
+	};
+};
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 58c9bf8..fa11e70 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -293,16 +293,17 @@
 
  - compatible : "qcom,msm-pcm-hostless"
 
-* audio-load-mod
+* msm-audio-apr
 
 Required properties:
 
- - compatible : "qcom,audio-load-mod"
+ - compatible : "qcom,msm-audio-apr"
+		This device is added to represent APR module.
 
 Optional properties:
 
- - compatible : "qcom,audio-test-mod"
-		Add this compatible as child device to load-module device.
+ - compatible : "qcom,msm-audio-apr-dummy"
+		Add this compatible as child device to msm-audio-apr device.
 		This child device is added after lpass is up to invoke
 		deferred probe devices.
 
@@ -655,10 +656,10 @@
                 compatible = "qcom,msm-pcm-hostless";
         };
 
-	audio_load_mod {
-		compatible = "qcom,audio-load-mod";
-		audio_test_mod {
-			compatible = "qcom,audio-test-mod";
+	qcom,msm-audio-apr {
+		compatible = "qcom,msm-audio-apr";
+		msm_audio_apr_dummy {
+			compatible = "qcom,msm-audio-apr-dummy";
 		};
 	};
 
diff --git a/Documentation/devicetree/bindings/thermal/tsens.txt b/Documentation/devicetree/bindings/thermal/tsens.txt
index 67ffaed..6ff6e9b 100644
--- a/Documentation/devicetree/bindings/thermal/tsens.txt
+++ b/Documentation/devicetree/bindings/thermal/tsens.txt
@@ -19,6 +19,7 @@
 	       should be "qcom,sdm630-tsens" for 630 TSENS driver.
 	       should be "qcom,sdm845-tsens" for SDM845 TSENS driver.
 	       should be "qcom,tsens24xx" for 2.4 TSENS controller.
+	       should be "qcom,msm8937-tsens" for 8937 TSENS driver.
 	       The compatible property is used to identify the respective controller to use
 	       for the corresponding SoC.
 - reg : offset and length of the TSENS registers with associated property in reg-names
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index e996ba5..01acb65 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -161,6 +161,7 @@
 linux	Linux-specific binding
 lltc	Linear Technology Corporation
 lsi	LSI Corp. (LSI Logic)
+lt	Lontium Semiconductor Corporation
 marvell	Marvell Technology Group Ltd.
 maxim	Maxim Integrated Products
 meas	Measurement Specialties
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts
index 8339f9a..e90d97d 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts
@@ -20,3 +20,11 @@
 		"qcom,sdxpoorwills", "qcom,cdp";
 	qcom,board-id = <1 0x1>, <1 0x101>;
 };
+
+&pcie_ep {
+	status = "okay";
+};
+
+&pcie0 {
+	status = "disabled";
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts
index 2240133..86d8636 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts
@@ -20,3 +20,11 @@
 		"qcom,sdxpoorwills", "qcom,mtp";
 	qcom,board-id = <8 0x1>, <8 0x101>;
 };
+
+&pcie_ep {
+	status = "okay";
+};
+
+&pcie0 {
+	status = "disabled";
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
index d684fb2..c23d48b 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
@@ -911,6 +911,11 @@
 		qcom,bark-time = <11000>;
 		qcom,pet-time = <10000>;
 	};
+
+	qcom,msm-rtb {
+		compatible = "qcom,msm-rtb";
+		qcom,rtb-size = <0x100000>;
+	};
 };
 
 #include "pmxpoorwills.dtsi"
diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig
index 29e6335..b1405c4 100644
--- a/arch/arm/configs/sdxpoorwills-perf_defconfig
+++ b/arch/arm/configs/sdxpoorwills-perf_defconfig
@@ -221,6 +221,7 @@
 CONFIG_SPI_SPIDEV=m
 CONFIG_SPMI=y
 CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
+CONFIG_PTP_1588_CLOCK=y
 CONFIG_PINCTRL_SDXPOORWILLS=y
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_DEBUG_GPIO=y
@@ -318,6 +319,8 @@
 CONFIG_IPA_UT=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_EP_PCIE=y
+CONFIG_EP_PCIE_HW=y
 CONFIG_QPNP_REVID=y
 CONFIG_GPIO_USB_DETECT=y
 CONFIG_USB_BAM=y
diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig
index 865406f..acd5f3a 100644
--- a/arch/arm/configs/sdxpoorwills_defconfig
+++ b/arch/arm/configs/sdxpoorwills_defconfig
@@ -216,6 +216,7 @@
 CONFIG_SLIMBUS=y
 CONFIG_SPMI=y
 CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
+CONFIG_PTP_1588_CLOCK=y
 CONFIG_PINCTRL_SDXPOORWILLS=y
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_POWER_RESET=y
@@ -317,6 +318,8 @@
 CONFIG_IPA_UT=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_EP_PCIE=y
+CONFIG_EP_PCIE_HW=y
 CONFIG_QPNP_REVID=y
 CONFIG_GPIO_USB_DETECT=y
 CONFIG_USB_BAM=y
@@ -387,6 +390,7 @@
 CONFIG_FAULT_INJECTION_DEBUG_FS=y
 CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
 CONFIG_IPC_LOGGING=y
+CONFIG_QCOM_RTB=y
 CONFIG_BLK_DEV_IO_TRACE=y
 CONFIG_DEBUG_USER=y
 CONFIG_CORESIGHT=y
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index 28dcd44..dad9fcb 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -21,6 +21,7 @@
 #include <linux/of.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/sched_energy.h>
 
 #include <asm/cputype.h>
 #include <asm/topology.h>
@@ -505,125 +506,31 @@
 	update_cpu_capacity(cpuid);
 }
 
-/*
- * ARM TC2 specific energy cost model data. There are no unit requirements for
- * the data. Data can be normalized to any reference point, but the
- * normalization must be consistent. That is, one bogo-joule/watt must be the
- * same quantity for all data, but we don't care what it is.
- */
-static struct idle_state idle_states_cluster_a7[] = {
-	 { .power = 25 }, /* arch_cpu_idle() (active idle) = WFI */
-	 { .power = 25 }, /* WFI */
-	 { .power = 10 }, /* cluster-sleep-l */
-	};
-
-static struct idle_state idle_states_cluster_a15[] = {
-	 { .power = 70 }, /* arch_cpu_idle() (active idle) = WFI */
-	 { .power = 70 }, /* WFI */
-	 { .power = 25 }, /* cluster-sleep-b */
-	};
-
-static struct capacity_state cap_states_cluster_a7[] = {
-	/* Cluster only power */
-	 { .cap =  150, .power = 2967, }, /*  350 MHz */
-	 { .cap =  172, .power = 2792, }, /*  400 MHz */
-	 { .cap =  215, .power = 2810, }, /*  500 MHz */
-	 { .cap =  258, .power = 2815, }, /*  600 MHz */
-	 { .cap =  301, .power = 2919, }, /*  700 MHz */
-	 { .cap =  344, .power = 2847, }, /*  800 MHz */
-	 { .cap =  387, .power = 3917, }, /*  900 MHz */
-	 { .cap =  430, .power = 4905, }, /* 1000 MHz */
-	};
-
-static struct capacity_state cap_states_cluster_a15[] = {
-	/* Cluster only power */
-	 { .cap =  426, .power =  7920, }, /*  500 MHz */
-	 { .cap =  512, .power =  8165, }, /*  600 MHz */
-	 { .cap =  597, .power =  8172, }, /*  700 MHz */
-	 { .cap =  682, .power =  8195, }, /*  800 MHz */
-	 { .cap =  768, .power =  8265, }, /*  900 MHz */
-	 { .cap =  853, .power =  8446, }, /* 1000 MHz */
-	 { .cap =  938, .power = 11426, }, /* 1100 MHz */
-	 { .cap = 1024, .power = 15200, }, /* 1200 MHz */
-	};
-
-static struct sched_group_energy energy_cluster_a7 = {
-	  .nr_idle_states = ARRAY_SIZE(idle_states_cluster_a7),
-	  .idle_states    = idle_states_cluster_a7,
-	  .nr_cap_states  = ARRAY_SIZE(cap_states_cluster_a7),
-	  .cap_states     = cap_states_cluster_a7,
-};
-
-static struct sched_group_energy energy_cluster_a15 = {
-	  .nr_idle_states = ARRAY_SIZE(idle_states_cluster_a15),
-	  .idle_states    = idle_states_cluster_a15,
-	  .nr_cap_states  = ARRAY_SIZE(cap_states_cluster_a15),
-	  .cap_states     = cap_states_cluster_a15,
-};
-
-static struct idle_state idle_states_core_a7[] = {
-	 { .power = 0 }, /* arch_cpu_idle (active idle) = WFI */
-	 { .power = 0 }, /* WFI */
-	 { .power = 0 }, /* cluster-sleep-l */
-	};
-
-static struct idle_state idle_states_core_a15[] = {
-	 { .power = 0 }, /* arch_cpu_idle (active idle) = WFI */
-	 { .power = 0 }, /* WFI */
-	 { .power = 0 }, /* cluster-sleep-b */
-	};
-
-static struct capacity_state cap_states_core_a7[] = {
-	/* Power per cpu */
-	 { .cap =  150, .power =  187, }, /*  350 MHz */
-	 { .cap =  172, .power =  275, }, /*  400 MHz */
-	 { .cap =  215, .power =  334, }, /*  500 MHz */
-	 { .cap =  258, .power =  407, }, /*  600 MHz */
-	 { .cap =  301, .power =  447, }, /*  700 MHz */
-	 { .cap =  344, .power =  549, }, /*  800 MHz */
-	 { .cap =  387, .power =  761, }, /*  900 MHz */
-	 { .cap =  430, .power = 1024, }, /* 1000 MHz */
-	};
-
-static struct capacity_state cap_states_core_a15[] = {
-	/* Power per cpu */
-	 { .cap =  426, .power = 2021, }, /*  500 MHz */
-	 { .cap =  512, .power = 2312, }, /*  600 MHz */
-	 { .cap =  597, .power = 2756, }, /*  700 MHz */
-	 { .cap =  682, .power = 3125, }, /*  800 MHz */
-	 { .cap =  768, .power = 3524, }, /*  900 MHz */
-	 { .cap =  853, .power = 3846, }, /* 1000 MHz */
-	 { .cap =  938, .power = 5177, }, /* 1100 MHz */
-	 { .cap = 1024, .power = 6997, }, /* 1200 MHz */
-	};
-
-static struct sched_group_energy energy_core_a7 = {
-	  .nr_idle_states = ARRAY_SIZE(idle_states_core_a7),
-	  .idle_states    = idle_states_core_a7,
-	  .nr_cap_states  = ARRAY_SIZE(cap_states_core_a7),
-	  .cap_states     = cap_states_core_a7,
-};
-
-static struct sched_group_energy energy_core_a15 = {
-	  .nr_idle_states = ARRAY_SIZE(idle_states_core_a15),
-	  .idle_states    = idle_states_core_a15,
-	  .nr_cap_states  = ARRAY_SIZE(cap_states_core_a15),
-	  .cap_states     = cap_states_core_a15,
-};
-
 /* sd energy functions */
 static inline
 const struct sched_group_energy * const cpu_cluster_energy(int cpu)
 {
-	return cpu_topology[cpu].socket_id ? &energy_cluster_a7 :
-			&energy_cluster_a15;
+	struct sched_group_energy *sge = sge_array[cpu][SD_LEVEL1];
+
+	if (sched_is_energy_aware() && !sge) {
+		pr_warn("Invalid sched_group_energy for Cluster%d\n", cpu);
+		return NULL;
+	}
+
+	return sge;
 }
 
 static inline
 const struct sched_group_energy * const cpu_core_energy(int cpu)
 {
-	return cpu_topology[cpu].socket_id ? &energy_core_a7 :
-			&energy_core_a15;
+	struct sched_group_energy *sge = sge_array[cpu][SD_LEVEL0];
+
+	if (sched_is_energy_aware() && !sge) {
+		pr_warn("Invalid sched_group_energy for CPU%d\n", cpu);
+		return NULL;
+	}
+
+	return sge;
 }
 
 static inline int cpu_corepower_flags(void)
@@ -688,4 +595,5 @@
 
 	/* Set scheduler topology descriptor */
 	set_sched_topology(arm_topology);
+	init_sched_energy_costs();
 }
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 7e5cdf2..caed4e1 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -205,7 +205,8 @@
 	qcs605-360camera.dtb \
 	qcs605-mtp.dtb \
 	qcs605-cdp.dtb \
-	qcs605-external-codec-mtp.dtb
+	qcs605-external-codec-mtp.dtb \
+	qcs605-lc-mtp.dtb
 endif
 
 ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y)
diff --git a/arch/arm64/boot/dts/qcom/apq8053.dts b/arch/arm64/boot/dts/qcom/apq8053.dts
index bf9e2f2..6bb67c3 100644
--- a/arch/arm64/boot/dts/qcom/apq8053.dts
+++ b/arch/arm64/boot/dts/qcom/apq8053.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "apq8053.dtsi"
+#include "pmi8950.dtsi"
+#include "msm8953-pmi8950.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. APQ8053 + PMI8950 SOC";
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-fhd-plus-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-fhd-plus-video.dtsi
new file mode 100644
index 0000000..77f2a1d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-fhd-plus-video.dtsi
@@ -0,0 +1,133 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&mdss_mdp {
+	dsi_hx8399c_truly_vid: qcom,mdss_dsi_hx8399c_truly_video{
+		qcom,mdss-dsi-panel-name =
+			"hx8399c video mode dsi truly panel";
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1080>;
+		qcom,mdss-dsi-panel-height = <2160>;
+		qcom,mdss-dsi-h-front-porch = <24>;
+		qcom,mdss-dsi-h-back-porch = <24>;
+		qcom,mdss-dsi-h-pulse-width = <16>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <40>;
+		qcom,mdss-dsi-v-front-porch = <36>;
+		qcom,mdss-dsi-v-pulse-width = <2>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-color-order = "rgb_swap_rgb";
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [
+			39 01 00 00 00 00 04
+				b9 ff 83 99
+			39 01 00 00 00 00 02
+				d2 88
+			39 01 00 00 00 00 10
+				b1 02 04 74 94 01 32 33
+				11 11 e6 5d 56 73 02 02
+			39 01 00 00 00 00 10
+				b2 00 80 80 cc 05 07 5a
+				11 10 10 00 1e 70 03 D4
+			39 01 00 00 00 00 2d
+				b4 00 ff 59 59 0c ac 00
+				00 0c 00 07 0a 00 28 07
+				08 0c 21 03 00 00 00 ae
+				87 59 59 0c ac 00 00 0c
+				00 07 0a 00 28 07 08 0c
+				01 00 00 ae 01
+			39 01 00 00 05 00 22
+				d3 00 00 01 01 00 00 10
+				10 00 00 03 00 03 00 08
+				78 08 78 00 00 00 00 00
+				24 02 05 05 03 00 00 00
+				05 40
+			39 01 00 00 05 00 21
+				d5 20 20 19 19 18 18 02
+				03 00 01 24 24 18 18 18
+				18 24 24 00 00 00 00 00
+				00 00 00 2f 2f 30 30 31
+				31
+			39 01 00 00 05 00 21
+				d6 24 24 18 18 19 19 01
+				00 03 02 24 24 18 18 18
+				18 20 20 40 40 40 40 40
+				40 40 40 2f 2f 30 30 31
+				31
+			39 01 00 00 00 00 02
+				bd 00
+			39 01 00 00 00 00 11
+				d8 aa aa aa aa aa aa aa
+				aa aa ba aa aa aa ba aa
+				aa
+			39 01 00 00 00 00 02
+				bd 01
+			39 01 00 00 00 00 11
+				d8 82 ea aa aa 82 ea aa
+				aa 82 ea aa aa 82 ea aa
+				aa
+			39 01 00 00 00 00 02
+				bd 02
+			39 01 00 00 00 00 09
+				d8 ff ff c0 3f ff ff c0
+				3f
+			39 01 00 00 00 00 02
+				bd 00
+			39 01 00 00 05 00 37
+				e0 08 2a 39 35 74 7c 87
+				7f 84 8a 8e 91 93 96 9b
+				9c 9e a5 a6 ae a1 af b2
+				5c 58 63 74 08 2a 39 35
+				74 7c 87 7f 84 8a 8e 91
+				93 96 9b 9c 9e a5 a6 ae
+				a1 af b2 5c 58 63 74
+			39 01 00 00 00 00 03
+				b6 7e 7e
+			39 01 00 00 00 00 02
+				cc 08
+			39 01 00 00 00 00 06
+				c7 00 08 00 01 08
+			39 01 00 00 00 00 03
+				c0 25 5a
+			05 01 00 00 78 00 02 11 00
+			05 01 00 00 14 00 02 29 00];
+		qcom,mdss-dsi-off-command = [
+			05 01 00 00 14 00 02 28 00
+			05 01 00 00 78 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-h-sync-pulse = <0>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
+		qcom,mdss-dsi-lane-map = "lane_map_0123";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-tx-eot-append;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-t-clk-post = <0x0e>;
+		qcom,mdss-dsi-t-clk-pre = <0x31>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-lp11-init;
+		qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-mdss-panels.dtsi b/arch/arm64/boot/dts/qcom/msm8937-mdss-panels.dtsi
new file mode 100644
index 0000000..7fdcb2d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-mdss-panels.dtsi
@@ -0,0 +1,52 @@
+/* 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 "dsi-panel-sim-video.dtsi"
+#include "dsi-panel-sim-cmd.dtsi"
+#include "dsi-panel-truly-1080p-video.dtsi"
+#include "dsi-panel-truly-1080p-cmd.dtsi"
+#include "dsi-panel-r69006-1080p-cmd.dtsi"
+#include "dsi-panel-r69006-1080p-video.dtsi"
+#include "dsi-panel-hx8394f-720p-video.dtsi"
+#include "dsi-adv7533-1080p.dtsi"
+#include "dsi-adv7533-720p.dtsi"
+#include "dsi-panel-truly-720p-video.dtsi"
+#include "dsi-panel-truly-wuxga-video.dtsi"
+#include "dsi-panel-truly-720p-cmd.dtsi"
+#include "dsi-panel-lead-fl10802-fwvga-video.dtsi"
+#include "dsi-panel-icn9706-720-1440p-video.dtsi"
+
+&soc {
+	dsi_panel_pwr_supply: dsi_panel_pwr_supply {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		qcom,panel-supply-entry@0 {
+			reg = <0>;
+			qcom,supply-name = "vdd";
+			qcom,supply-min-voltage = <2850000>;
+			qcom,supply-max-voltage = <2850000>;
+			qcom,supply-enable-load = <100000>;
+			qcom,supply-disable-load = <100>;
+		};
+
+		qcom,panel-supply-entry@1 {
+			reg = <1>;
+			qcom,supply-name = "vddio";
+			qcom,supply-min-voltage = <1800000>;
+			qcom,supply-max-voltage = <1800000>;
+			qcom,supply-enable-load = <100000>;
+			qcom,supply-disable-load = <100>;
+		};
+
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-mdss-pll.dtsi b/arch/arm64/boot/dts/qcom/msm8937-mdss-pll.dtsi
new file mode 100644
index 0000000..6987716
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-mdss-pll.dtsi
@@ -0,0 +1,103 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	mdss_dsi0_pll: qcom,mdss_dsi_pll@1a94a00 {
+		compatible = "qcom,mdss_dsi_pll_8937";
+		label = "MDSS DSI 0 PLL";
+		cell-index = <0>;
+		#clock-cells = <1>;
+
+		reg = <0x001a94a00 0xd4>,
+			<0x0184d074 0x8>;
+		reg-names = "pll_base", "gdsc_base";
+
+		gdsc-supply = <&gdsc_mdss>;
+		vddio-supply = <&pm8937_l6>;
+
+		clocks = <&clock_gcc clk_gcc_mdss_ahb_clk>;
+		clock-names = "iface_clk";
+		clock-rate = <0>;
+		qcom,dsi-pll-ssc-en;
+		qcom,dsi-pll-ssc-mode = "down-spread";
+		qcom,ssc-frequency-hz = <30000>;
+		qcom,ssc-ppm = <5000>;
+
+		qcom,platform-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,platform-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "gdsc";
+				qcom,supply-min-voltage = <0>;
+				qcom,supply-max-voltage = <0>;
+				qcom,supply-enable-load = <0>;
+				qcom,supply-disable-load = <0>;
+			};
+
+			qcom,platform-supply-entry@1 {
+				reg = <1>;
+				qcom,supply-name = "vddio";
+				qcom,supply-min-voltage = <1800000>;
+				qcom,supply-max-voltage = <1800000>;
+				qcom,supply-enable-load = <100000>;
+				qcom,supply-disable-load = <100>;
+			};
+		};
+	};
+
+	mdss_dsi1_pll: qcom,mdss_dsi_pll@1a96a00 {
+		compatible = "qcom,mdss_dsi_pll_8937";
+		label = "MDSS DSI 1 PLL";
+		cell-index = <1>;
+		#clock-cells = <1>;
+
+		reg = <0x001a96a00 0xd4>,
+			<0x0184d074 0x8>;
+		reg-names = "pll_base", "gdsc_base";
+
+		gdsc-supply = <&gdsc_mdss>;
+		vddio-supply = <&pm8937_l6>;
+
+		clocks = <&clock_gcc clk_gcc_mdss_ahb_clk>;
+		clock-names = "iface_clk";
+		clock-rate = <0>;
+		qcom,dsi-pll-ssc-en;
+		qcom,dsi-pll-ssc-mode = "down-spread";
+		qcom,ssc-frequency-hz = <30000>;
+		qcom,ssc-ppm = <5000>;
+
+		qcom,platform-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,platform-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "gdsc";
+				qcom,supply-min-voltage = <0>;
+				qcom,supply-max-voltage = <0>;
+				qcom,supply-enable-load = <0>;
+				qcom,supply-disable-load = <0>;
+			};
+
+			qcom,platform-supply-entry@1 {
+				reg = <1>;
+				qcom,supply-name = "vddio";
+				qcom,supply-min-voltage = <1800000>;
+				qcom,supply-max-voltage = <1800000>;
+				qcom,supply-enable-load = <100000>;
+				qcom,supply-disable-load = <100>;
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-mdss.dtsi b/arch/arm64/boot/dts/qcom/msm8937-mdss.dtsi
new file mode 100644
index 0000000..07ff464
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-mdss.dtsi
@@ -0,0 +1,410 @@
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	mdss_mdp: qcom,mdss_mdp@1a00000 {
+		compatible = "qcom,mdss_mdp";
+		reg = <0x01a00000 0x90000>,
+		      <0x01ab0000 0x1040>;
+		reg-names = "mdp_phys", "vbif_phys";
+		interrupts = <0 72 0>;
+		vdd-supply = <&gdsc_mdss>;
+
+		/* Bus Scale Settings */
+		qcom,msm-bus,name = "mdss_mdp";
+		qcom,msm-bus,num-cases = <3>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<22 512 0 0>,
+			<22 512 0 6400000>,
+			<22 512 0 6400000>;
+
+		/* Fudge factors */
+		qcom,mdss-ab-factor = <1 1>;		/* 1 time  */
+		qcom,mdss-ib-factor = <1 1>;		/* 1 time  */
+		qcom,mdss-clk-factor = <105 100>;	/* 1.05 times */
+
+		qcom,max-mixer-width = <2048>;
+		qcom,max-pipe-width = <2048>;
+
+		/* VBIF QoS remapper settings*/
+		qcom,mdss-vbif-qos-rt-setting = <1 2 2 2>;
+		qcom,mdss-vbif-qos-nrt-setting = <1 1 1 1>;
+
+		qcom,mdss-has-panic-ctrl;
+		qcom,mdss-per-pipe-panic-luts = <0x000f>,
+						<0xffff>,
+						<0xfffc>,
+						<0xff00>;
+
+		qcom,mdss-mdp-reg-offset = <0x00001000>;
+		qcom,max-bandwidth-low-kbps = <3100000>;
+		qcom,max-bandwidth-high-kbps = <3100000>;
+		qcom,max-bandwidth-per-pipe-kbps = <2300000>;
+
+		/* Bandwidth limit settings */
+		qcom,max-bw-settings = <1 3100000>,	/* Default */
+				       <2 1700000>;	/* Camera */
+
+		qcom,max-clk-rate = <320000000>;
+		qcom,mdss-default-ot-rd-limit = <32>;
+		qcom,mdss-default-ot-wr-limit = <16>;
+
+		qcom,mdss-pipe-vig-off = <0x00005000>;
+		qcom,mdss-pipe-rgb-off = <0x00015000 0x00017000>;
+		qcom,mdss-pipe-dma-off = <0x00025000>;
+		qcom,mdss-pipe-cursor-off = <0x00035000>;
+
+		qcom,mdss-pipe-vig-xin-id = <0>;
+		qcom,mdss-pipe-rgb-xin-id = <1 5>;
+		qcom,mdss-pipe-dma-xin-id = <2>;
+		qcom,mdss-pipe-cursor-xin-id = <7>;
+
+		/* Offsets relative to "mdp_phys + mdp-reg-offset" address */
+		qcom,mdss-pipe-vig-clk-ctrl-offsets = <0x2AC 0 0>;
+		qcom,mdss-pipe-rgb-clk-ctrl-offsets = <0x2AC 4 8>,
+						      <0x2B4 4 8>;
+		qcom,mdss-pipe-dma-clk-ctrl-offsets = <0x2AC 8 12>;
+		qcom,mdss-pipe-cursor-clk-ctrl-offsets = <0x3A8 16 15>;
+
+
+		qcom,mdss-ctl-off = <0x00002000 0x00002200 0x00002400>;
+		qcom,mdss-mixer-intf-off = <0x00045000 0x00046000>;
+		qcom,mdss-dspp-off = <0x00055000>;
+		qcom,mdss-wb-off = <0x00065000 0x00066000>;
+		qcom,mdss-intf-off = <0x00000000 0x0006B800 0x0006C000>;
+		qcom,mdss-pingpong-off = <0x00071000 0x00071800>;
+		qcom,mdss-slave-pingpong-off = <0x00073000>;
+		qcom,mdss-cdm-off = <0x0007a200>;
+		qcom,mdss-wfd-mode = "intf";
+		qcom,mdss-highest-bank-bit = <0x1>;
+		qcom,mdss-has-decimation;
+		qcom,mdss-has-non-scalar-rgb;
+		qcom,mdss-has-rotator-downscale;
+		qcom,mdss-rot-downscale-min = <2>;
+		qcom,mdss-rot-downscale-max = <16>;
+		qcom,mdss-idle-power-collapse-enabled;
+		qcom,mdss-rot-block-size = <64>;
+
+		clocks = <&clock_gcc clk_gcc_mdss_ahb_clk>,
+			 <&clock_gcc clk_gcc_mdss_axi_clk>,
+			 <&clock_gcc clk_mdp_clk_src>,
+			 <&clock_gcc_mdss clk_mdss_mdp_vote_clk>,
+			 <&clock_gcc clk_gcc_mdss_vsync_clk>;
+		clock-names = "iface_clk", "bus_clk", "core_clk_src",
+				"core_clk", "vsync_clk";
+
+		qcom,mdp-settings = <0x0506c 0x00000000>,
+				    <0x1506c 0x00000000>,
+				    <0x1706c 0x00000000>,
+				    <0x2506c 0x00000000>;
+
+		qcom,vbif-settings = <0x0d0 0x00000010>;
+
+		qcom,regs-dump-mdp = <0x01000 0x01454>,
+				     <0x02000 0x02064>,
+				     <0x02200 0x02264>,
+				     <0x02400 0x02464>,
+				     <0x05000 0x05150>,
+				     <0x05200 0x05230>,
+				     <0x15000 0x15150>,
+				     <0x17000 0x17150>,
+				     <0x25000 0x25150>,
+				     <0x35000 0x35150>,
+				     <0x45000 0x452bc>,
+				     <0x46000 0x462bc>,
+				     <0x55000 0x5522c>,
+				     <0x65000 0x652c0>,
+				     <0x66000 0x662c0>,
+				     <0x6b800 0x6ba68>,
+				     <0x6c000 0x6c268>,
+				     <0x71000 0x710d4>,
+				     <0x71800 0x718d4>;
+
+		qcom,regs-dump-names-mdp = "MDP",
+			"CTL_0",    "CTL_1", "CTL_2",
+			"VIG0_SSPP", "VIG0",
+			"RGB0_SSPP", "RGB1_SSPP",
+			"DMA0_SSPP",
+			"CURSOR0_SSPP",
+			"LAYER_0", "LAYER_1",
+			"DSPP_0",
+			"WB_0",    "WB_2",
+			"INTF_1",  "INTF_2",
+			"PP_0",    "PP_1";
+
+		/* buffer parameters to calculate prefill bandwidth */
+		qcom,mdss-prefill-outstanding-buffer-bytes = <0>;
+		qcom,mdss-prefill-y-buffer-bytes = <0>;
+		qcom,mdss-prefill-scaler-buffer-lines-bilinear = <2>;
+		qcom,mdss-prefill-scaler-buffer-lines-caf = <4>;
+		qcom,mdss-prefill-post-scaler-buffer-pixels = <2048>;
+		qcom,mdss-prefill-pingpong-buffer-pixels = <4096>;
+
+		qcom,mdss-pp-offsets {
+			qcom,mdss-sspp-mdss-igc-lut-off = <0x2000>;
+			qcom,mdss-sspp-vig-pcc-off = <0x1780>;
+			qcom,mdss-sspp-rgb-pcc-off = <0x380>;
+			qcom,mdss-sspp-dma-pcc-off = <0x380>;
+			qcom,mdss-lm-pgc-off = <0x3C0>;
+			qcom,mdss-dspp-pcc-off = <0x1700>;
+			qcom,mdss-dspp-pgc-off = <0x17C0>;
+		};
+
+		qcom,mdss-reg-bus {
+			/* Reg Bus Scale Settings */
+			qcom,msm-bus,name = "mdss_reg";
+			qcom,msm-bus,num-cases = <4>;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,active-only;
+			qcom,msm-bus,vectors-KBps =
+				<1 590 0 0>,
+				<1 590 0 76800>,
+				<1 590 0 160000>,
+				<1 590 0 320000>;
+		};
+
+		qcom,mdss-hw-rt-bus {
+			/* Bus Scale Settings */
+			qcom,msm-bus,name = "mdss_hw_rt";
+			qcom,msm-bus,num-cases = <2>;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,vectors-KBps =
+				<22 512 0 0>,
+				<22 512 0 1000>;
+		};
+
+		smmu_mdp_unsec: qcom,smmu_mdp_unsec_cb {
+			compatible = "qcom,smmu_mdp_unsec";
+			iommus = <&apps_iommu 0xC00 0>; /* For NS ctx bank */
+		};
+		smmu_mdp_sec: qcom,smmu_mdp_sec_cb {
+			compatible = "qcom,smmu_mdp_sec";
+			iommus = <&apps_iommu 0xC01 0>; /* For SEC Ctx Bank */
+		};
+
+		mdss_fb0: qcom,mdss_fb_primary {
+			cell-index = <0>;
+			compatible = "qcom,mdss-fb";
+			qcom,cont-splash-memory {
+				linux,contiguous-region = <&cont_splash_mem>;
+			};
+		};
+
+		mdss_fb1: qcom,mdss_fb_wfd {
+			cell-index = <1>;
+			compatible = "qcom,mdss-fb";
+		};
+
+		mdss_fb2: qcom,mdss_fb_secondary {
+			cell-index = <2>;
+			compatible = "qcom,mdss-fb";
+		};
+	};
+
+	mdss_dsi: qcom,mdss_dsi@0 {
+		compatible = "qcom,mdss-dsi";
+		hw-config = "single_dsi";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		gdsc-supply = <&gdsc_mdss>;
+		vdda-supply = <&pm8937_l2>;
+		vddio-supply = <&pm8937_l6>;
+
+		/* Bus Scale Settings */
+		qcom,msm-bus,name = "mdss_dsi";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<22 512 0 0>,
+			<22 512 0 1000>;
+
+		ranges = <0x1a94000 0x1a94000 0x300
+			0x1a94400 0x1a94400 0x280
+			0x1a94b80 0x1a94b80 0x30
+			0x193e000 0x193e000 0x30
+			0x1a96000 0x1a96000 0x300
+			0x1a96400 0x1a96400 0x280
+			0x1a96b80 0x1a96b80 0x30
+			0x193e000 0x193e000 0x30>;
+
+		clocks = <&clock_gcc_mdss clk_mdss_mdp_vote_clk>,
+			<&clock_gcc clk_gcc_mdss_ahb_clk>,
+			<&clock_gcc clk_gcc_mdss_axi_clk>,
+			<&clock_gcc_mdss clk_ext_byte0_clk_src>,
+			<&clock_gcc_mdss clk_ext_byte1_clk_src>,
+			<&clock_gcc_mdss clk_ext_pclk0_clk_src>,
+			<&clock_gcc_mdss clk_ext_pclk1_clk_src>;
+		clock-names = "mdp_core_clk", "iface_clk", "bus_clk",
+			"ext_byte0_clk", "ext_byte1_clk", "ext_pixel0_clk",
+			"ext_pixel1_clk";
+
+		qcom,mmss-ulp-clamp-ctrl-offset = <0x20>;
+		qcom,mmss-phyreset-ctrl-offset = <0x24>;
+
+		qcom,mdss-fb-map-prim = <&mdss_fb0>;
+		qcom,mdss-fb-map-sec = <&mdss_fb2>;
+		qcom,core-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,core-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "gdsc";
+				qcom,supply-min-voltage = <0>;
+				qcom,supply-max-voltage = <0>;
+				qcom,supply-enable-load = <0>;
+				qcom,supply-disable-load = <0>;
+			};
+		};
+
+		qcom,ctrl-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,ctrl-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "vdda";
+				qcom,supply-min-voltage = <1200000>;
+				qcom,supply-max-voltage = <1200000>;
+				qcom,supply-enable-load = <100000>;
+				qcom,supply-disable-load = <100>;
+				qcom,supply-post-on-sleep = <20>;
+			};
+		};
+
+		qcom,phy-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,phy-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "vddio";
+				qcom,supply-min-voltage = <1800000>;
+				qcom,supply-max-voltage = <1800000>;
+				qcom,supply-enable-load = <100000>;
+				qcom,supply-disable-load = <100>;
+			};
+		};
+
+		mdss_dsi0: qcom,mdss_dsi_ctrl0@1a94000 {
+			compatible = "qcom,mdss-dsi-ctrl";
+			label = "MDSS DSI CTRL->0";
+			cell-index = <0>;
+			reg = <0x1a94000 0x300>,
+				<0x1a94400 0x280>,
+				<0x1a94b80 0x30>,
+				<0x193e000 0x30>;
+			reg-names = "dsi_ctrl", "dsi_phy",
+			      "dsi_phy_regulator", "mmss_misc_phys";
+
+			qcom,timing-db-mode;
+			qcom,mdss-mdp = <&mdss_mdp>;
+			vdd-supply = <&pm8937_l17>;
+			vddio-supply = <&pm8937_l6>;
+
+			clocks = <&clock_gcc_mdss clk_gcc_mdss_byte0_clk>,
+				<&clock_gcc_mdss clk_gcc_mdss_pclk0_clk>,
+				<&clock_gcc clk_gcc_mdss_esc0_clk>,
+				<&clock_gcc_mdss clk_byte0_clk_src>,
+				<&clock_gcc_mdss clk_pclk0_clk_src>;
+			clock-names = "byte_clk", "pixel_clk", "core_clk",
+				"byte_clk_rcg", "pixel_clk_rcg";
+
+			qcom,platform-strength-ctrl = [ff 06];
+			qcom,platform-bist-ctrl = [00 00 b1 ff 00 00];
+			qcom,platform-regulator-settings = [03 08 07 00
+				20 07 01];
+			qcom,platform-lane-config = [01 c0 00 00 00 00 00 01 97
+				01 c0 00 00 05 00 00 01 97
+				01 c0 00 00 0a 00 00 01 97
+				01 c0 00 00 0f 00 00 01 97
+				00 40 00 00 00 00 00 01 ff];
+		};
+
+		mdss_dsi1: qcom,mdss_dsi_ctrl1@1a96000 {
+			compatible = "qcom,mdss-dsi-ctrl";
+			label = "MDSS DSI CTRL->1";
+			cell-index = <1>;
+			reg = <0x1a96000 0x300>,
+			      <0x1a96400 0x280>,
+			      <0x1a94b80 0x30>,
+			      <0x193e000 0x30>;
+			reg-names = "dsi_ctrl", "dsi_phy",
+			      "dsi_phy_regulator", "mmss_misc_phys";
+
+			qcom,mdss-mdp = <&mdss_mdp>;
+			vdd-supply = <&pm8937_l17>;
+			vddio-supply = <&pm8937_l6>;
+
+			clocks = <&clock_gcc_mdss clk_gcc_mdss_byte1_clk>,
+				<&clock_gcc_mdss clk_gcc_mdss_pclk1_clk>,
+				<&clock_gcc clk_gcc_mdss_esc1_clk>,
+				<&clock_gcc_mdss clk_byte1_clk_src>,
+				<&clock_gcc_mdss clk_pclk1_clk_src>;
+			clock-names = "byte_clk", "pixel_clk", "core_clk",
+				"byte_clk_rcg", "pixel_clk_rcg";
+
+			qcom,platform-strength-ctrl = [ff 06];
+			qcom,platform-bist-ctrl = [00 00 b1 ff 00 00];
+			qcom,platform-regulator-settings = [03 08 07 00
+				20 07 01];
+			qcom,platform-lane-config = [01 c0 00 00 00 00 00 01 97
+				01 c0 00 00 05 00 00 01 97
+				01 c0 00 00 0a 00 00 01 97
+				01 c0 00 00 0f 00 00 01 97
+				00 40 00 00 00 00 00 01 ff];
+
+		};
+
+	};
+
+	qcom,mdss_wb_panel {
+		compatible = "qcom,mdss_wb";
+		qcom,mdss_pan_res = <640 640>;
+		qcom,mdss_pan_bpp = <24>;
+		qcom,mdss-fb-map = <&mdss_fb1>;
+	};
+
+	mdss_rotator: qcom,mdss_rotator {
+		compatible = "qcom,mdss_rotator";
+		qcom,mdss-wb-count = <1>;
+		qcom,mdss-has-downscale;
+		qcom,mdss-has-ubwc;
+		/* Bus Scale Settings */
+		qcom,msm-bus,name = "mdss_rotator";
+		qcom,msm-bus,num-cases = <3>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<22 512 0 0>,
+			<22 512 0 6400000>,
+			<22 512 0 6400000>;
+
+		rot-vdd-supply = <&gdsc_mdss>;
+		qcom,supply-names = "rot-vdd";
+		qcom,mdss-has-reg-bus;
+		clocks = <&clock_gcc clk_gcc_mdss_ahb_clk>,
+			<&clock_gcc_mdss clk_mdss_rotator_vote_clk>;
+		clock-names = "iface_clk", "rot_core_clk";
+
+		qcom,mdss-rot-reg-bus {
+			/* Reg Bus Scale Settings */
+			qcom,msm-bus,name = "mdss_rot_reg";
+			qcom,msm-bus,num-cases = <2>;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,active-only;
+			qcom,msm-bus,vectors-KBps =
+				<1 590 0 0>,
+				<1 590 0 76800>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dtsi
index d0eff96..3da16e4 100644
--- a/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dtsi
@@ -33,11 +33,11 @@
 	};
 };
 
-&pmi8950_fg {
+&qpnp_fg {
 	qcom,battery-data = <&mtp_batterydata>;
 };
 
-&pmi8950_charger {
+&qpnp_smbcharger {
 	qcom,battery-data = <&mtp_batterydata>;
 	qcom,chg-led-sw-controls;
 	qcom,chg-led-support;
diff --git a/arch/arm64/boot/dts/qcom/msm8937.dtsi b/arch/arm64/boot/dts/qcom/msm8937.dtsi
index ecab236..a26968f 100644
--- a/arch/arm64/boot/dts/qcom/msm8937.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8937.dtsi
@@ -15,6 +15,7 @@
 #include <dt-bindings/regulator/qcom,rpm-smd-regulator.h>
 #include <dt-bindings/spmi/spmi.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/msm-clocks-8952.h>
 
 / {
 	model = "Qualcomm Technologies, Inc. MSM8937";
@@ -235,6 +236,174 @@
 		qcom,pipe-attr-ee;
 	};
 
+	thermal_zones: thermal-zones {
+		aoss0-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-governor = "user_space";
+			thermal-sensors = <&tsens0 0>;
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		mdm-core-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-governor = "user_space";
+			thermal-sensors = <&tsens0 1>;
+			trips {
+				active-config0 {
+						temperature = <125000>;
+						hysteresis = <1000>;
+						type = "passive";
+				};
+			};
+		};
+
+		mdss-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-governor = "user_space";
+			thermal-sensors = <&tsens0 2>;
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		camera-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-governor = "user_space";
+			thermal-sensors = <&tsens0 3>;
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		cpuss-0-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 4>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		apc1_cpu1-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 5>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		apc1_cpu2-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 6>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		apc1_cpu3-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 7>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		apc1_cpu4-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 8>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		apc0_cpu0-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 9>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		gpu0-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 10>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+	};
+
+	tsens0: tsens@4a8000 {
+		compatible = "qcom,msm8937-tsens";
+		reg = <0x4a8000 0x1000>,
+			<0x4a9000 0x1000>,
+			<0xa4000  0x1000>;
+		reg-names = "tsens_srot_physical",
+			"tsens_tm_physical", "tsens_eeprom_physical";
+		interrupts = <0 184 0>;
+		interrupt-names = "tsens-upper-lower";
+		#thermal-sensor-cells = <1>;
+	};
+
 	slim_msm: slim@c140000{
 		cell-index = <1>;
 		compatible = "qcom,slim-ngd";
@@ -271,6 +440,120 @@
 		qcom,summing-threshold = <10>;
 	};
 
+	clock_gcc: qcom,gcc@1800000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "qcom,gcc-8937";
+		reg = <0x1800000 0x80000>,
+			<0xb016000 0x00040>,
+			<0xb116000 0x00040>,
+			<0x00a6018 0x00004>;
+		reg-names = "cc_base", "apcs_c1_base",
+				"apcs_c0_base", "efuse";
+		vdd_dig-supply = <&pm8937_s2_level>;
+		vdd_sr2_dig-supply = <&pm8937_s2_level_ao>;
+		vdd_sr2_pll-supply = <&pm8937_l7_ao>;
+		vdd_hf_dig-supply = <&pm8937_s2_level_ao>;
+		vdd_hf_pll-supply = <&pm8937_l7_ao>;
+		#clock-cells = <1>;
+		#reset-cells = <1>;
+		ranges;
+		qcom,spm@0 {
+			compatible = "qcom,gcc-spm-8937";
+			reg = <0x0b111200 0x100>,
+				<0x0b011200 0x100>;
+			reg-names = "spm_c0_base", "spm_c1_base";
+		};
+	};
+
+	clock_debug: qcom,cc-debug@1874000 {
+		compatible = "qcom,cc-debug-8937";
+		reg = <0x1874000 0x4>,
+			<0xb11101c 0x8>;
+		reg-names = "cc_base", "meas";
+		#clock-cells = <1>;
+	};
+
+	clock_cpu: qcom,cpu-clock-8939@b111050 {
+		compatible = "qcom,cpu-clock-8939";
+		reg =   <0xb011050 0x8>,
+			<0xb111050 0x8>,
+			<0xb1d1050 0x8>,
+			<0x00a412c 0x8>;
+		reg-names = "apcs-c1-rcg-base", "apcs-c0-rcg-base",
+				"apcs-cci-rcg-base", "efuse";
+		vdd-c0-supply = <&apc_vreg_corner>;
+		vdd-c1-supply = <&apc_vreg_corner>;
+		vdd-cci-supply = <&apc_vreg_corner>;
+		clocks = <&clock_gcc clk_gpll0_ao_clk_src>,
+			<&clock_gcc clk_a53ss_c0_pll>,
+			<&clock_gcc clk_gpll0_ao_clk_src>,
+			<&clock_gcc clk_a53ss_c1_pll>,
+			<&clock_gcc clk_gpll0_ao_clk_src>,
+			<&clock_gcc clk_gpll0_ao_clk_src>;
+		clock-names = "clk-c0-4", "clk-c0-5",
+				"clk-c1-4", "clk-c1-5",
+				"clk-cci-4", "clk-cci-2";
+		qcom,speed0-bin-v0-c0 =
+			<          0 0>,
+			<  768000000 1>,
+			<  902400000 2>,
+			<  998400000 4>,
+			< 1094400000 6>;
+
+		qcom,speed0-bin-v0-c1 =
+			<          0 0>,
+			<  960000000 1>,
+			< 1094400000 2>,
+			< 1248000000 4>,
+			< 1344000000 5>,
+			< 1401000000 6>;
+
+		qcom,speed0-bin-v0-cci =
+			<          0 0>,
+			<  400000000 1>,
+			<  533333333 3>;
+
+		qcom,speed1-bin-v0-c0 =
+			<          0 0>,
+			<  768000000 1>,
+			<  902400000 2>,
+			<  998400000 4>,
+			< 1094400000 6>,
+			< 1209600000 7>;
+
+		qcom,speed1-bin-v0-c1 =
+			<          0 0>,
+			<  960000000 1>,
+			< 1094400000 2>,
+			< 1248000000 4>,
+			< 1344000000 5>,
+			< 1401000000 6>,
+			< 1497600000 7>;
+
+		qcom,speed1-bin-v0-cci =
+			<          0 0>,
+			<  400000000 1>,
+			<  533333333 3>;
+
+		qcom,speed2-bin-v0-c0 =
+			<          0 0>,
+			<  768000000 1>,
+			<  902400000 2>,
+			<  998400000 3>;
+
+		qcom,speed2-bin-v0-c1 =
+			<          0 0>,
+			<  960000000 1>,
+			< 1094400000 2>,
+			< 1209600000 3>;
+
+		qcom,speed2-bin-v0-cci =
+			<          0 0>,
+			<  400000000 1>,
+			<  533333333 3>;
+		#clock-cells = <1>;
+	};
 
 	cpubw: qcom,cpubw {
 		compatible = "qcom,devbw";
@@ -622,3 +905,75 @@
 #include "pm8937-rpm-regulator.dtsi"
 #include "msm8937-regulator.dtsi"
 #include "pm8937.dtsi"
+#include "msm-gdsc-8916.dtsi"
+
+&gdsc_venus {
+	clock-names = "bus_clk", "core_clk";
+	clocks = <&clock_gcc clk_gcc_venus0_axi_clk>,
+		<&clock_gcc clk_gcc_venus0_vcodec0_clk>;
+	status = "okay";
+};
+
+&gdsc_venus_core0 {
+	qcom,support-hw-trigger;
+	clock-names ="core0_clk";
+	clocks = <&clock_gcc clk_gcc_venus0_core0_vcodec0_clk>;
+	status = "okay";
+};
+
+&gdsc_mdss {
+	clock-names = "core_clk", "bus_clk";
+	clocks = <&clock_gcc clk_gcc_mdss_mdp_clk>,
+		<&clock_gcc clk_gcc_mdss_axi_clk>;
+	qcom,disallow-clear;
+	status = "okay";
+};
+
+&gdsc_jpeg {
+	clock-names = "core_clk", "bus_clk";
+	clocks = <&clock_gcc clk_gcc_camss_jpeg0_clk>,
+		<&clock_gcc clk_gcc_camss_jpeg_axi_clk>;
+	status = "okay";
+};
+
+&gdsc_vfe {
+	clock-names = "core_clk", "bus_clk", "micro_clk",
+			"csi_clk";
+	clocks = <&clock_gcc clk_gcc_camss_vfe0_clk>,
+		<&clock_gcc clk_gcc_camss_vfe_axi_clk>,
+		<&clock_gcc clk_gcc_camss_micro_ahb_clk>,
+		<&clock_gcc clk_gcc_camss_csi_vfe0_clk>;
+	status = "okay";
+};
+
+&gdsc_vfe1 {
+	clock-names = "core_clk", "bus_clk", "micro_clk",
+			"csi_clk";
+	clocks = <&clock_gcc clk_gcc_camss_vfe1_clk>,
+		<&clock_gcc clk_gcc_camss_vfe1_axi_clk>,
+		<&clock_gcc clk_gcc_camss_micro_ahb_clk>,
+		<&clock_gcc clk_gcc_camss_csi_vfe1_clk>;
+	status = "okay";
+};
+
+&gdsc_cpp {
+	clock-names = "core_clk", "bus_clk";
+	clocks = <&clock_gcc clk_gcc_camss_cpp_clk>,
+		<&clock_gcc clk_gcc_camss_cpp_axi_clk>;
+	status = "okay";
+};
+
+&gdsc_oxili_gx {
+	clock-names = "core_root_clk";
+	clocks =<&clock_gcc clk_gfx3d_clk_src>;
+	qcom,enable-root-clk;
+	qcom,clk-dis-wait-val = <0x5>;
+	status = "okay";
+};
+
+&gdsc_oxili_cx {
+	reg = <0x1859044 0x4>;
+	clock-names = "core_clk";
+	clocks = <&clock_gcc clk_gcc_oxili_gfx3d_clk>;
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-ion.dtsi b/arch/arm64/boot/dts/qcom/msm8953-ion.dtsi
index 34004b0..00203a2 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-ion.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-ion.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -32,5 +32,11 @@
 			memory-region = <&qseecom_mem>;
 			qcom,ion-heap-type = "DMA";
 		};
+
+		qcom,ion-heap@19 { /* QSEECOM TA HEAP */
+			reg = <19>;
+			memory-region = <&qseecom_ta_mem>;
+			qcom,ion-heap-type = "DMA";
+		};
 	};
 };
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi b/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi
index cb59ac3..28a6b74 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi
@@ -23,6 +23,7 @@
 #include "dsi-panel-truly-wuxga-video.dtsi"
 #include "dsi-panel-lt8912-480p-video.dtsi"
 #include "dsi-panel-lt8912-1080p-video.dtsi"
+#include "dsi-panel-hx8399c-fhd-plus-video.dtsi"
 
 &soc {
 	dsi_panel_pwr_supply: dsi_panel_pwr_supply {
@@ -86,6 +87,27 @@
 		24 1b 08 09 05 03 04 a0];
 };
 
+&dsi_hx8399c_truly_vid {
+	qcom,mdss-dsi-panel-timings-phy-v2 = [24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1c 08 09 05 03 04 a0];
+	qcom,esd-check-enabled;
+	qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+	qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
+	qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode";
+	qcom,mdss-dsi-panel-status-value = <0x9d 0x9d 0x9d 0x9d>;
+	qcom,mdss-dsi-panel-on-check-value = <0x9d 0x9d 0x9d 0x9d>;
+	qcom,mdss-dsi-panel-status-read-length = <4>;
+	qcom,mdss-dsi-panel-max-error-count = <3>;
+	qcom,mdss-dsi-min-refresh-rate = <55>;
+	qcom,mdss-dsi-max-refresh-rate = <60>;
+	qcom,mdss-dsi-pan-enable-dynamic-fps;
+	qcom,mdss-dsi-pan-fps-update =
+		"dfps_immediate_porch_mode_vfp";
+};
+
 &dsi_adv7533_1080p {
 	qcom,mdss-dsi-panel-timings-phy-v2 = [24 1f 08 09 05 03 04 a0
 		24 1f 08 09 05 03 04 a0
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts
index 49956df..c6ae512 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts
@@ -20,3 +20,21 @@
 	model = "MTP";
 	qcom,board-id = <8 0>;
 };
+
+/{
+	mtp_batterydata: qcom,battery-data {
+		qcom,batt-id-range-pct = <15>;
+		#include "batterydata-itech-3000mah.dtsi"
+		#include "batterydata-ascent-3450mAh.dtsi"
+	};
+};
+
+&qpnp_fg {
+	qcom,battery-data = <&mtp_batterydata>;
+};
+
+&qpnp_smbcharger {
+	qcom,battery-data = <&mtp_batterydata>;
+	qcom,chg-led-sw-controls;
+	qcom,chg-led-support;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mtp.dts b/arch/arm64/boot/dts/qcom/msm8953-mtp.dts
index b53f7b8..97c6db3 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-mtp.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -33,16 +33,12 @@
 	};
 };
 
-&pmi8950_fg {
+&qpnp_fg {
 	qcom,battery-data = <&mtp_batterydata>;
 };
 
-&pmi8950_charger {
+&qpnp_smbcharger {
 	qcom,battery-data = <&mtp_batterydata>;
 	qcom,chg-led-sw-controls;
 	qcom,chg-led-support;
 };
-
-&usb3 {
-	extcon = <&pmi8950_charger>;
-};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts
index a9f64a4..5ec92ae 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "msm8953.dtsi"
+#include "pmi8937.dtsi"
+#include "msm8953-pmi8937.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. MSM8953 + PMI8937 SOC";
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dtsi
index a208e1a..80050c4 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dtsi
@@ -24,10 +24,10 @@
 
 &usb3 {
 	vbus_dwc3-supply = <&smbcharger_charger_otg>;
-	extcon = <&pmi8937_charger>;
+	extcon = <&qpnp_smbcharger>;
 };
 
-&pmi8937_charger {
+&qpnp_smbcharger {
 	qcom,external-typec;
 	qcom,typec-psy-name = "typec";
 };
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts
index e9c80a0d..ba5c3c7 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "msm8953.dtsi"
+#include "pmi8940.dtsi"
+#include "msm8953-pmi8940.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. MSM8953 + PMI8940 SOC";
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dtsi
index 28fc0d7..c36dd1b 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dtsi
@@ -24,7 +24,7 @@
 
 &usb3 {
 	vbus_dwc3-supply = <&smbcharger_charger_otg>;
-	extcon = <&pmi8940_charger>;
+	extcon = <&qpnp_smbcharger>;
 };
 
 &labibb {
@@ -36,7 +36,7 @@
 	qcom,qpnp-ibb-discharge-resistor = <32>;
 };
 
-&pmi8940_charger {
+&qpnp_smbcharger {
 	qcom,external-typec;
 	qcom,typec-psy-name = "typec";
 };
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi
index 139ef1e..d81a0a5 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi
@@ -29,10 +29,10 @@
 
 &usb3 {
 	vbus_dwc3-supply = <&smbcharger_charger_otg>;
-	extcon = <&pmi8950_charger>;
+	extcon = <&qpnp_smbcharger>;
 };
 
-&pmi8950_charger {
+&qpnp_smbcharger {
 	qcom,external-typec;
 	qcom,typec-psy-name = "typec";
 };
@@ -46,23 +46,3 @@
 	lab-supply = <&lab_regulator>;
 	ibb-supply = <&ibb_regulator>;
 };
-
-&dsi_panel_pwr_supply {
-		qcom,panel-supply-entry@2 {
-			reg = <2>;
-			qcom,supply-name = "lab";
-			qcom,supply-min-voltage = <4600000>;
-			qcom,supply-max-voltage = <6000000>;
-			qcom,supply-enable-load = <100000>;
-			qcom,supply-disable-load = <100>;
-		};
-		qcom,panel-supply-entry@3 {
-			reg = <3>;
-			qcom,supply-name = "ibb";
-			qcom,supply-min-voltage = <4600000>;
-			qcom,supply-max-voltage = <6000000>;
-			qcom,supply-enable-load = <100000>;
-			qcom,supply-disable-load = <100>;
-			qcom,supply-post-on-sleep = <10>;
-		};
-};
diff --git a/arch/arm64/boot/dts/qcom/msm8953.dts b/arch/arm64/boot/dts/qcom/msm8953.dts
index ddf2218..2f6cbc4 100644
--- a/arch/arm64/boot/dts/qcom/msm8953.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "msm8953.dtsi"
+#include "pmi8950.dtsi"
+#include "msm8953-pmi8950.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. MSM8953 + PMI8950 SOC";
diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi
index d488fff..d6f7bf2 100644
--- a/arch/arm64/boot/dts/qcom/msm8953.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi
@@ -103,6 +103,14 @@
 			compatible = "shared-dma-pool";
 			reusable;
 			alignment = <0 0x400000>;
+			size = <0 0x0400000>;
+		};
+
+		qseecom_ta_mem: qseecom_ta_region {
+			compatible = "shared-dma-pool";
+			alloc-ranges = <0 0x00000000 0 0xffffffff>;
+			reusable;
+			alignment = <0 0x400000>;
 			size = <0 0x1000000>;
 		};
 
@@ -1162,6 +1170,11 @@
 			reg = <0x94c 200>;
 
 		};
+
+		diag_dload@c8 {
+			compatible = "qcom,msm-imem-diag-dload";
+			reg = <0xc8 200>;
+		};
 	};
 
 	qcom,memshare {
diff --git a/arch/arm64/boot/dts/qcom/pm8953.dtsi b/arch/arm64/boot/dts/qcom/pm8953.dtsi
index d77de72..a7d25de 100644
--- a/arch/arm64/boot/dts/qcom/pm8953.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8953.dtsi
@@ -85,15 +85,17 @@
 			reg = <0xc000 0x800>;
 
 			interrupts = <0x0 0xc0 0 IRQ_TYPE_NONE>,
+				<0x0 0xc1 0 IRQ_TYPE_NONE>,
 				<0x0 0xc3 0 IRQ_TYPE_NONE>,
 				<0x0 0xc6 0 IRQ_TYPE_NONE>,
 				<0x0 0xc7 0 IRQ_TYPE_NONE>;
-			interrupt-names = "pm8953_gpio1", "pm8953_gpio4",
-					"pm8953_gpio7", "pm8953_gpio8";
+			interrupt-names = "pm8953_gpio1", "pm8953_gpio2",
+					"pm8953_gpio4", "pm8953_gpio7",
+					"pm8953_gpio8";
 
 			gpio-controller;
 			#gpio-cells = <2>;
-			qcom,gpios-disallowed = <2 3 5 6>;
+			qcom,gpios-disallowed = <3 5 6>;
 		};
 
 		pm8953_vadc: vadc@3100 {
diff --git a/arch/arm64/boot/dts/qcom/pmi632.dtsi b/arch/arm64/boot/dts/qcom/pmi632.dtsi
index e5963ef..d5a3c35 100644
--- a/arch/arm64/boot/dts/qcom/pmi632.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi632.dtsi
@@ -214,6 +214,185 @@
 			#gpio-cells = <2>;
 			qcom,gpios-disallowed = <1>;
 		};
+
+		pmi632_charger: qcom,qpnp-smb5 {
+			compatible = "qcom,qpnp-smb5";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			qcom,pmic-revid = <&pmi632_revid>;
+			dpdm-supply = <&qusb_phy>;
+
+			qcom,chgr@1000 {
+				reg = <0x1000 0x100>;
+				interrupts =
+					<0x2 0x10 0x0 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x10 0x1 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x10 0x2 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x10 0x3 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x10 0x4 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x10 0x5 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x10 0x6 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x10 0x7 IRQ_TYPE_LEVEL_HIGH>;
+
+				interrupt-names = "chgr-error",
+						  "chg-state-change",
+						  "step-chg-state-change",
+						  "step-chg-soc-update-fail",
+						  "step-chg-soc-update-req",
+						  "fg-fvcal-qualified",
+						  "vph-alarm",
+						  "vph-drop-prechg";
+			};
+
+			qcom,dcdc@1100 {
+				reg = <0x1100 0x100>;
+				interrupts =
+					<0x2 0x11 0x0 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x11 0x1 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x11 0x2 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x11 0x3 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x11 0x4 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x11 0x5 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x11 0x6 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x11 0x7 IRQ_TYPE_EDGE_BOTH>;
+
+				interrupt-names = "otg-fail",
+						  "otg-oc-disable-sw",
+						  "otg-oc-hiccup",
+						  "bsm-active",
+						  "high-duty-cycle",
+						  "input-current-limiting",
+						  "concurrent-mode-disable",
+						  "switcher-power-ok";
+			};
+
+			qcom,batif@1200 {
+				reg = <0x1200 0x100>;
+				interrupts =
+					<0x2 0x12 0x0 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x12 0x1 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x12 0x2 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x12 0x3 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x12 0x4 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x12 0x5 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x12 0x6 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x12 0x7 IRQ_TYPE_LEVEL_HIGH>;
+
+				interrupt-names = "bat-temp",
+						  "all-chnl-conv-done",
+						  "bat-ov",
+						  "bat-low",
+						  "bat-therm-or-id-missing",
+						  "bat-terminal-missing",
+						  "buck-oc",
+						  "vph-ov";
+			};
+
+			qcom,usb@1300 {
+				reg = <0x1300 0x100>;
+				interrupts =
+					<0x2 0x13 0x0 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x13 0x1 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x13 0x2 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x13 0x3 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x13 0x4 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x13 0x5 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x13 0x6 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x13 0x7 IRQ_TYPE_EDGE_RISING>;
+
+				interrupt-names = "usbin-collapse",
+						  "usbin-vashdn",
+						  "usbin-uv",
+						  "usbin-ov",
+						  "usbin-plugin",
+						  "usbin-revi-change",
+						  "usbin-src-change",
+						  "usbin-icl-change";
+			};
+
+			qcom,typec@1500 {
+				reg = <0x1500 0x100>;
+				interrupts =
+					<0x2 0x15 0x0 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x15 0x1 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x15 0x2 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x15 0x3 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x15 0x4 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x15 0x5 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x15 0x6 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x15 0x7 IRQ_TYPE_EDGE_RISING>;
+
+				interrupt-names = "typec-or-rid-detect-change",
+						  "typec-vpd-detect",
+						  "typec-cc-state-change",
+						  "typec-vconn-oc",
+						  "typec-vbus-change",
+						  "typec-attach-detach",
+						  "typec-legacy-cable-detect",
+						  "typec-try-snk-src-detect";
+			};
+
+			qcom,misc@1600 {
+				reg = <0x1600 0x100>;
+				interrupts =
+					<0x2 0x16 0x0 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x16 0x1 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x16 0x2 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x16 0x3 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x16 0x4 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x16 0x5 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x16 0x6 IRQ_TYPE_EDGE_FALLING>,
+					<0x2 0x16 0x7 IRQ_TYPE_EDGE_RISING>;
+
+				interrupt-names = "wdog-snarl",
+						  "wdog-bark",
+						  "aicl-fail",
+						  "aicl-done",
+						  "smb-en",
+						  "imp-trigger",
+						  "temp-change",
+						  "temp-change-smb";
+			};
+
+			smb5_vbus: qcom,smb5-vbus {
+				regulator-name = "smb5-vbus";
+			};
+		};
+
+		pmi632_qg: qpnp,qg {
+			compatible = "qcom,qpnp-qg";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			qcom,vbatt-empty-mv = <3200>;
+			qcom,vbatt-low-mv = <3500>;
+			qcom,vbatt-cutoff-mv = <3400>;
+			qcom,qg-iterm-ma = <100>;
+
+			qcom,qg-vadc = <&pmi632_vadc>;
+			qcom,pmic-revid = <&pmi632_revid>;
+
+			qcom,qgauge@4800 {
+				status = "okay";
+				reg = <0x4800 0x100>;
+				interrupts = <0x2 0x48 0x0 IRQ_TYPE_EDGE_BOTH>,
+					     <0x2 0x48 0x1 IRQ_TYPE_EDGE_BOTH>,
+					     <0x2 0x48 0x2 IRQ_TYPE_EDGE_BOTH>,
+					     <0x2 0x48 0x3 IRQ_TYPE_EDGE_BOTH>,
+					     <0x2 0x48 0x4 IRQ_TYPE_EDGE_BOTH>;
+				interrupt-names = "qg-batt-missing",
+						  "qg-vbat-low",
+						  "qg-vbat-empty",
+						  "qg-fifo-done",
+						  "qg-good-ocv";
+			};
+
+			qcom,qg-sdam@b100 {
+				status = "okay";
+				reg = <0xb100 0x100>;
+			};
+		};
 	};
 
 	pmi632_3: qcom,pmi632@3 {
diff --git a/arch/arm64/boot/dts/qcom/pmi8937.dtsi b/arch/arm64/boot/dts/qcom/pmi8937.dtsi
index a7aa08a..c72225d 100644
--- a/arch/arm64/boot/dts/qcom/pmi8937.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8937.dtsi
@@ -153,7 +153,7 @@
 			#gpio-cells = <2>;
 		};
 
-		pmi8937_charger: qcom,qpnp-smbcharger {
+		qpnp_smbcharger: qcom,qpnp-smbcharger {
 			compatible = "qcom,qpnp-smbcharger";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -268,7 +268,7 @@
 			};
 		};
 
-		pmi8937_fg: qcom,fg {
+		qpnp_fg: qcom,fg {
 			compatible = "qcom,qpnp-fg";
 			#address-cells = <1>;
 			#size-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/pmi8940.dtsi b/arch/arm64/boot/dts/qcom/pmi8940.dtsi
index c6d5c87..d83145c 100644
--- a/arch/arm64/boot/dts/qcom/pmi8940.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8940.dtsi
@@ -152,7 +152,7 @@
 			#gpio-cells = <2>;
 		};
 
-		pmi8940_charger: qcom,qpnp-smbcharger {
+		qpnp_smbcharger: qcom,qpnp-smbcharger {
 			compatible = "qcom,qpnp-smbcharger";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -264,7 +264,7 @@
 			};
 		};
 
-		pmi8940_fg: qcom,fg {
+		qpnp_fg: qcom,fg {
 			compatible = "qcom,qpnp-fg";
 			#address-cells = <1>;
 			#size-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/pmi8950.dtsi b/arch/arm64/boot/dts/qcom/pmi8950.dtsi
index 4e82cfe..e3388c1 100644
--- a/arch/arm64/boot/dts/qcom/pmi8950.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8950.dtsi
@@ -168,7 +168,7 @@
 			#gpio-cells = <2>;
 		};
 
-		pmi8950_charger: qcom,qpnp-smbcharger {
+		qpnp_smbcharger: qcom,qpnp-smbcharger {
 			compatible = "qcom,qpnp-smbcharger";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -284,7 +284,7 @@
 			};
 		};
 
-		pmi8950_fg: qcom,fg {
+		qpnp_fg: qcom,fg {
 			compatible = "qcom,qpnp-fg";
 			#address-cells = <1>;
 			#size-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/qcs605-360camera.dtsi b/arch/arm64/boot/dts/qcom/qcs605-360camera.dtsi
index bf2241a..bad4fd7 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-360camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/qcs605-360camera.dtsi
@@ -43,10 +43,94 @@
 	status = "disabled";
 };
 
-&dsi_dual_nt35597_truly_video {
+&dsi_dual_nt35597_truly_video_display {
 	status = "disabled";
 };
 
+&qupv3_se9_i2c {
+	status = "okay";
+	lt9611@3b {
+		compatible = "lt,lt9611";
+		reg = <0x3b>;
+		interrupt-parent = <&tlmm>;
+		interrupts = <125 0>;
+		interrupt-names = "lt_irq";
+		lt,irq-gpio = <&tlmm 125 0x0>;
+		lt,reset-gpio = <&tlmm 134 0x0>;
+		lt,hdmi-ps-gpio = <&tlmm 136 0x0>;
+		lt,hdmi-en-gpio = <&tlmm 137 0x0>;
+		lt,non-pluggable;
+
+		vcc-supply = <&pm660l_l6>;
+		vdd-supply = <&pm660_l11>;
+		lt,supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			lt,supply-entry@0 {
+				reg = <0>;
+				lt,supply-name = "vcc";
+				lt,supply-min-voltage = <3300000>;
+				lt,supply-max-voltage = <3300000>;
+				lt,supply-enable-load = <200000>;
+				lt,supply-post-on-sleep = <50>;
+			};
+
+			lt,supply-entry@1 {
+				reg = <1>;
+				lt,supply-name = "vdd";
+				lt,supply-min-voltage = <1800000>;
+				lt,supply-max-voltage = <1800000>;
+				lt,supply-enable-load = <200000>;
+				lt,supply-post-on-sleep = <50>;
+			};
+		};
+
+		lt,customize-modes {
+			lt,customize-mode-id@0 {
+				lt,mode-h-active = <1920>;
+				lt,mode-h-front-porch = <88>;
+				lt,mode-h-pulse-width = <44>;
+				lt,mode-h-back-porch = <148>;
+				lt,mode-h-active-high;
+				lt,mode-v-active = <1080>;
+				lt,mode-v-front-porch = <4>;
+				lt,mode-v-pulse-width = <5>;
+				lt,mode-v-back-porch = <36>;
+				lt,mode-v-active-high;
+				lt,mode-refresh-rate = <60>;
+				lt,mode-clock-in-khz = <148500>;
+			};
+		};
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				lt9611_in: endpoint {
+					remote-endpoint = <&ext_dsi_out>;
+				};
+			};
+		};
+	};
+};
+
+&soc {
+	qcom,dsi-display@17 {
+		qcom,dsi-display-active;
+
+		ports {
+			port@0 {
+				endpoint {
+					remote-endpoint = <&lt9611_in>;
+				};
+			};
+		};
+	};
+};
+
 &int_codec {
 	qcom,model = "sdm670-360cam-snd-card";
 	qcom,audio-routing =
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
new file mode 100644
index 0000000..3ca53b7
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "qcs605-lc.dtsi"
+#include "qcs605-lc-mtp.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
+	compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
+	qcom,board-id = <8 4>;
+};
diff --git a/arch/arm64/boot/dts/qcom/qg-batterydata-ascent-3450mah.dtsi b/arch/arm64/boot/dts/qcom/qg-batterydata-ascent-3450mah.dtsi
new file mode 100644
index 0000000..4d35628
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qg-batterydata-ascent-3450mah.dtsi
@@ -0,0 +1,1024 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+qcom,ascent_3450mah {
+	/* Ascent_wConn_3450mAh_Fresh_averaged_MasterSlave_Feb7th2018 */
+	qcom,max-voltage-uv = <4350000>;
+	qcom,fg-cc-cv-threshold-mv = <4340>;
+	qcom,fastchg-current-ma = <3450>;
+	qcom,batt-id-kohm = <60>;
+	qcom,battery-beta = <3435>;
+	qcom,battery-therm-kohm = <68>;
+	qcom,battery-type =
+		"Ascent_wConn_3450mAh_Fresh_averaged_MasterSlave_Feb7th2018";
+	qcom,qg-batt-profile-ver = <100>;
+
+	qcom,jeita-fcc-ranges = <0   100  1725000
+				101  400  3450000
+				401  450  2760000>;
+	qcom,jeita-fv-ranges = <0   100  4250000
+				101 400  4350000
+				401 450  4250000>;
+	qcom,step-chg-ranges = <3600000  4200000  3450000
+				4201000  4300000  2760000
+				4301000  4350000  2070000>;
+
+	qcom,fcc1-temp-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-data = <3377 3428 3481 3496 3500>;
+	};
+
+	qcom,fcc2-temp-lut {
+		qcom,lut-col-legend = <(-20) (-10) 0 10 25 40 50>;
+		qcom,lut-data = <3474 3480 3482 3476 3492 3478 3466>;
+	};
+
+	qcom,pc-temp-v1-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <43212 43315 43370 43380 43383>,
+			<42963 43071 43141 43149 43152>,
+			<42723 42832 42902 42916 42922>,
+			<42488 42597 42662 42683 42693>,
+			<42262 42367 42430 42454 42465>,
+			<42043 42143 42202 42225 42238>,
+			<41832 41924 41976 41999 42013>,
+			<41624 41709 41754 41775 41791>,
+			<41419 41497 41536 41556 41571>,
+			<41220 41288 41322 41341 41355>,
+			<41039 41091 41113 41132 41143>,
+			<40866 40911 40916 40928 40936>,
+			<40676 40732 40729 40729 40734>,
+			<40449 40526 40541 40538 40541>,
+			<40230 40302 40340 40351 40355>,
+			<40061 40115 40146 40170 40176>,
+			<39918 39974 39984 40002 40007>,
+			<39787 39846 39843 39845 39846>,
+			<39672 39712 39697 39690 39689>,
+			<39560 39579 39548 39536 39538>,
+			<39426 39419 39388 39376 39384>,
+			<39271 39170 39192 39187 39198>,
+			<39112 38928 38961 38960 38967>,
+			<38934 38809 38788 38776 38775>,
+			<38764 38736 38674 38650 38646>,
+			<38660 38665 38581 38546 38539>,
+			<38589 38587 38491 38448 38439>,
+			<38533 38513 38408 38359 38347>,
+			<38487 38444 38334 38278 38263>,
+			<38448 38381 38265 38204 38187>,
+			<38407 38323 38204 38138 38118>,
+			<38364 38269 38149 38078 38055>,
+			<38322 38219 38099 38026 37999>,
+			<38284 38175 38053 37975 37942>,
+			<38249 38137 38014 37930 37889>,
+			<38211 38098 37974 37884 37834>,
+			<38174 38061 37930 37831 37767>,
+			<38129 38020 37882 37771 37691>,
+			<38055 37954 37816 37698 37610>,
+			<37946 37848 37718 37605 37524>,
+			<37825 37726 37602 37497 37426>,
+			<37689 37595 37474 37372 37301>,
+			<37541 37451 37332 37231 37156>,
+			<37372 37290 37178 37080 36999>,
+			<37271 37162 37061 36964 36886>,
+			<37191 37093 36992 36897 36819>,
+			<37157 37064 36970 36870 36798>,
+			<37128 37039 36949 36844 36770>,
+			<37084 37007 36903 36788 36714>,
+			<36927 36851 36683 36562 36488>,
+			<36555 36481 36290 36180 36108>,
+			<36071 35999 35771 35687 35620>,
+			<35450 35376 35098 35050 34994>,
+			<34604 34523 34174 34184 34150>,
+			<33275 33138 32725 32851 32862>,
+			<30000 30000 30000 30000 30000>;
+	};
+
+	qcom,pc-temp-v2-lut {
+		qcom,lut-col-legend = <(-20) (-10) 0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000 8800>,
+			<8600 8400 8200 8000 7800 7600 7400>,
+			<7200 7000 6800 6600 6400 6200 6000>,
+			<5800 5600 5400 5200 5000 4800 4600>,
+			<4400 4200 4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200 2000 1800>,
+			<1600 1400 1200 1000 900 800 700>,
+			<600 500 400 300 200 100 0>;
+		qcom,lut-data = <43435 43425 43415 43385 43360 43315 43295>,
+			<43032 43070 43109 43097 43094 43052 43033>,
+			<42666 42748 42821 42826 42838 42799 42781>,
+			<42342 42462 42555 42571 42594 42557 42541>,
+			<42053 42208 42308 42333 42361 42326 42312>,
+			<41788 41968 42072 42101 42133 42099 42086>,
+			<41531 41736 41844 41872 41904 41872 41860>,
+			<41298 41516 41625 41649 41680 41649 41637>,
+			<41128 41303 41405 41431 41460 41430 41419>,
+			<41009 41100 41186 41217 41243 41215 41204>,
+			<40843 40896 40979 41012 41034 41005 40994>,
+			<40462 40694 40796 40826 40840 40802 40789>,
+			<40004 40482 40616 40642 40648 40604 40590>,
+			<39736 40220 40407 40432 40445 40411 40399>,
+			<39556 39903 40175 40199 40233 40222 40214>,
+			<39382 39636 39954 39996 40043 40042 40036>,
+			<39187 39443 39759 39844 39886 39877 39868>,
+			<39001 39272 39570 39700 39736 39717 39706>,
+			<38839 39091 39370 39511 39573 39556 39547>,
+			<38695 38908 39162 39283 39399 39396 39391>,
+			<38574 38742 38973 39072 39208 39217 39217>,
+			<38477 38591 38806 38886 38975 38988 38994>,
+			<38393 38460 38655 38721 38760 38766 38771>,
+			<38314 38358 38519 38585 38613 38613 38614>,
+			<38242 38274 38396 38468 38496 38494 38494>,
+			<38176 38201 38287 38362 38390 38388 38387>,
+			<38117 38138 38189 38265 38294 38291 38288>,
+			<38062 38080 38106 38177 38206 38202 38198>,
+			<38006 38027 38039 38096 38126 38120 38114>,
+			<37953 37980 37983 38021 38051 38044 38037>,
+			<37900 37934 37935 37954 37984 37976 37967>,
+			<37847 37889 37895 37891 37921 37915 37905>,
+			<37795 37843 37856 37838 37862 37856 37846>,
+			<37742 37795 37815 37799 37803 37790 37781>,
+			<37690 37746 37774 37768 37746 37720 37707>,
+			<37635 37692 37727 37728 37685 37643 37621>,
+			<37574 37633 37677 37677 37620 37554 37517>,
+			<37509 37568 37618 37617 37550 37465 37411>,
+			<37441 37491 37546 37548 37475 37387 37327>,
+			<37368 37404 37459 37466 37395 37313 37256>,
+			<37292 37310 37360 37369 37301 37226 37174>,
+			<37209 37206 37243 37246 37187 37117 37069>,
+			<37119 37103 37111 37106 37050 36988 36945>,
+			<37020 37005 36964 36946 36900 36839 36796>,
+			<36901 36909 36860 36837 36818 36761 36712>,
+			<36762 36808 36782 36769 36775 36718 36673>,
+			<36671 36746 36740 36732 36741 36690 36651>,
+			<36552 36670 36688 36684 36692 36649 36612>,
+			<36386 36553 36594 36591 36575 36542 36528>,
+			<36157 36329 36380 36368 36272 36271 36278>,
+			<35824 35961 35991 35957 35796 35833 35867>,
+			<35340 35436 35452 35401 35193 35271 35340>,
+			<34648 34709 34745 34680 34409 34550 34676>,
+			<33623 33672 33759 33677 33330 33585 33791>,
+			<31758 31857 32191 32244 31867 32001 32517>,
+			<27623 28160 28896 29014 27510 28586 29617>;
+	};
+
+	qcom,pc-temp-z1-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <13703 12983 12375 12138 12079>,
+			<13647 12967 12370 12145 12092>,
+			<13621 12953 12363 12143 12093>,
+			<13606 12942 12357 12142 12093>,
+			<13594 12927 12349 12140 12093>,
+			<13585 12916 12342 12137 12093>,
+			<13577 12905 12339 12136 12092>,
+			<13569 12898 12337 12135 12092>,
+			<13560 12896 12337 12135 12091>,
+			<13551 12895 12339 12135 12091>,
+			<13540 12896 12342 12136 12091>,
+			<13527 12899 12342 12136 12091>,
+			<13512 12901 12342 12137 12093>,
+			<13488 12896 12342 12139 12095>,
+			<13469 12887 12343 12141 12097>,
+			<13469 12883 12347 12144 12098>,
+			<13473 12891 12352 12147 12101>,
+			<13478 12904 12360 12151 12103>,
+			<13489 12912 12369 12155 12106>,
+			<13502 12919 12378 12160 12109>,
+			<13514 12927 12387 12165 12113>,
+			<13525 12937 12396 12171 12117>,
+			<13538 12948 12404 12177 12122>,
+			<13555 12957 12412 12184 12127>,
+			<13572 12965 12422 12189 12131>,
+			<13578 12971 12431 12195 12135>,
+			<13580 12978 12440 12200 12139>,
+			<13582 12985 12448 12206 12143>,
+			<13594 12992 12456 12212 12147>,
+			<13613 13004 12464 12218 12151>,
+			<13625 13010 12472 12224 12156>,
+			<13631 13010 12479 12230 12160>,
+			<13632 13010 12486 12237 12165>,
+			<13627 13015 12494 12244 12171>,
+			<13618 13033 12505 12253 12177>,
+			<13619 13047 12517 12262 12183>,
+			<13629 13056 12529 12271 12190>,
+			<13640 13065 12541 12280 12196>,
+			<13647 13068 12553 12290 12203>,
+			<13654 13070 12565 12301 12210>,
+			<13663 13071 12577 12311 12217>,
+			<13678 13085 12588 12322 12224>,
+			<13694 13098 12598 12332 12232>,
+			<13718 13107 12607 12344 12239>,
+			<13717 13110 12621 12356 12248>,
+			<13717 13111 12638 12367 12256>,
+			<13693 13110 12640 12374 12262>,
+			<13712 13131 12642 12382 12269>,
+			<13714 13118 12659 12395 12280>,
+			<13717 13140 12677 12408 12291>,
+			<13717 13160 12678 12422 12303>,
+			<13740 13166 12691 12436 12316>,
+			<13739 13183 12711 12456 12332>,
+			<13754 13201 12735 12479 12355>,
+			<13754 13201 12735 12479 12355>,
+			<13754 13201 12735 12479 12355>;
+	};
+
+	qcom,pc-temp-z2-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <9983 10351 10639 10481 10418>,
+			<10020 10341 10669 10329 10279>,
+			<10051 10333 10528 10319 10282>,
+			<10083 10331 10397 10312 10281>,
+			<10100 10329 10358 10299 10263>,
+			<10094 10325 10328 10285 10234>,
+			<10081 10303 10324 10279 10227>,
+			<10069 10281 10328 10277 10237>,
+			<10058 10278 10330 10276 10251>,
+			<10050 10280 10326 10276 10266>,
+			<10044 10285 10321 10281 10280>,
+			<10039 10298 10323 10288 10285>,
+			<10038 10310 10324 10308 10284>,
+			<10045 10309 10318 10321 10285>,
+			<10054 10304 10304 10319 10295>,
+			<10056 10302 10291 10314 10309>,
+			<10056 10312 10297 10316 10321>,
+			<10058 10329 10320 10326 10335>,
+			<10070 10353 10339 10334 10341>,
+			<10090 10386 10349 10339 10346>,
+			<10111 10400 10358 10343 10354>,
+			<10138 10396 10373 10334 10340>,
+			<10157 10388 10395 10289 10270>,
+			<10169 10381 10400 10243 10212>,
+			<10178 10372 10354 10197 10174>,
+			<10183 10364 10306 10161 10144>,
+			<10190 10352 10304 10160 10141>,
+			<10194 10341 10307 10170 10149>,
+			<10185 10335 10310 10181 10158>,
+			<10169 10332 10311 10196 10169>,
+			<10165 10332 10314 10216 10183>,
+			<10168 10343 10327 10238 10202>,
+			<10171 10357 10356 10267 10226>,
+			<10175 10368 10381 10298 10253>,
+			<10180 10376 10405 10333 10288>,
+			<10183 10384 10422 10367 10326>,
+			<10186 10393 10431 10393 10358>,
+			<10189 10403 10438 10416 10387>,
+			<10187 10410 10442 10437 10405>,
+			<10181 10419 10455 10461 10418>,
+			<10175 10423 10465 10476 10426>,
+			<10164 10407 10466 10476 10430>,
+			<10152 10385 10468 10474 10428>,
+			<10142 10373 10453 10473 10402>,
+			<10064 10371 10455 10479 10389>,
+			<10173 10285 10486 10517 10402>,
+			<10003 10290 10490 10530 10416>,
+			<10151 10295 10531 10566 10477>,
+			<10255 10515 10588 10612 10540>,
+			<10077 10376 10556 10524 10421>,
+			<9948 10240 10480 10454 10314>,
+			<9854 10122 10384 10398 10256>,
+			<9640 9998 10319 10342 10182>,
+			<9440 9830 10255 10261 10065>,
+			<9440 9830 10255 10261 10065>,
+			<9440 9830 10255 10261 10065>;
+	};
+
+	qcom,pc-temp-z3-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <19441 19367 19362 19326 19316>,
+			<19560 19428 19358 19334 19329>,
+			<19615 19467 19373 19341 19335>,
+			<19645 19480 19383 19346 19340>,
+			<19658 19487 19385 19351 19344>,
+			<19657 19488 19387 19354 19347>,
+			<19657 19486 19386 19355 19348>,
+			<19655 19483 19384 19354 19347>,
+			<19651 19481 19382 19352 19346>,
+			<19647 19479 19380 19350 19345>,
+			<19645 19477 19378 19347 19344>,
+			<19642 19470 19377 19345 19342>,
+			<19642 19464 19374 19345 19342>,
+			<19642 19464 19372 19344 19341>,
+			<19643 19467 19372 19343 19338>,
+			<19639 19467 19372 19342 19336>,
+			<19626 19460 19371 19340 19334>,
+			<19615 19450 19369 19338 19332>,
+			<19604 19448 19368 19337 19330>,
+			<19596 19446 19368 19337 19328>,
+			<19597 19447 19369 19337 19326>,
+			<19605 19452 19372 19340 19328>,
+			<19612 19460 19378 19350 19341>,
+			<19619 19462 19386 19357 19350>,
+			<19626 19464 19394 19361 19353>,
+			<19627 19466 19401 19364 19355>,
+			<19626 19472 19400 19364 19355>,
+			<19624 19480 19398 19362 19352>,
+			<19620 19480 19395 19359 19349>,
+			<19615 19476 19391 19356 19346>,
+			<19611 19473 19388 19353 19343>,
+			<19609 19469 19384 19350 19340>,
+			<19606 19466 19381 19347 19336>,
+			<19604 19463 19379 19343 19332>,
+			<19601 19461 19377 19338 19327>,
+			<19597 19458 19375 19335 19324>,
+			<19592 19454 19373 19334 19325>,
+			<19587 19451 19370 19334 19329>,
+			<19584 19448 19368 19334 19330>,
+			<19582 19446 19366 19334 19328>,
+			<19579 19443 19364 19334 19326>,
+			<19575 19441 19362 19334 19326>,
+			<19571 19438 19360 19334 19327>,
+			<19565 19434 19359 19336 19329>,
+			<19361 19423 19353 19335 19328>,
+			<19262 19382 19344 19323 19324>,
+			<19263 19371 19336 19321 19317>,
+			<19261 19361 19332 19317 19313>,
+			<19261 19273 19326 19317 19309>,
+			<19262 19274 19335 19327 19319>,
+			<19263 19303 19337 19330 19324>,
+			<19263 19274 19357 19333 19327>,
+			<19266 19275 19361 19337 19335>,
+			<19272 19280 19368 19349 19345>,
+			<19272 19280 19368 19349 19345>,
+			<19272 19280 19368 19349 19345>;
+	};
+
+	qcom,pc-temp-z4-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <15627 15107 14765 14761 14758>,
+			<15711 15099 14864 14812 14796>,
+			<15693 15080 14843 14798 14788>,
+			<15530 15036 14821 14778 14775>,
+			<15355 14952 14794 14760 14761>,
+			<15246 14887 14764 14740 14745>,
+			<15155 14845 14741 14726 14731>,
+			<15085 14812 14721 14713 14719>,
+			<15031 14784 14710 14705 14711>,
+			<14985 14760 14705 14700 14707>,
+			<14938 14745 14702 14697 14705>,
+			<14895 14735 14696 14693 14702>,
+			<14876 14729 14689 14688 14699>,
+			<14872 14730 14686 14684 14697>,
+			<14869 14735 14686 14681 14694>,
+			<14856 14737 14686 14680 14692>,
+			<14830 14720 14682 14677 14689>,
+			<14808 14702 14673 14672 14684>,
+			<14790 14701 14669 14669 14681>,
+			<14778 14706 14676 14670 14679>,
+			<14782 14717 14687 14675 14677>,
+			<14805 14815 14716 14690 14685>,
+			<14835 14927 14778 14733 14726>,
+			<14898 14927 14803 14755 14750>,
+			<14965 14883 14774 14738 14735>,
+			<14974 14842 14741 14715 14712>,
+			<14963 14813 14728 14705 14703>,
+			<14950 14789 14721 14700 14699>,
+			<14932 14778 14717 14696 14696>,
+			<14910 14771 14715 14693 14692>,
+			<14892 14767 14713 14691 14688>,
+			<14878 14766 14712 14688 14683>,
+			<14867 14765 14712 14684 14677>,
+			<14856 14764 14710 14681 14673>,
+			<14847 14763 14709 14676 14668>,
+			<14838 14761 14706 14673 14666>,
+			<14826 14756 14703 14673 14669>,
+			<14816 14748 14700 14674 14680>,
+			<14809 14744 14697 14674 14683>,
+			<14804 14742 14695 14673 14677>,
+			<14797 14739 14693 14671 14673>,
+			<14787 14730 14687 14667 14673>,
+			<14774 14718 14678 14663 14675>,
+			<14753 14708 14673 14662 14682>,
+			<14897 14683 14660 14653 14674>,
+			<14965 14689 14638 14630 14635>,
+			<14964 14694 14635 14621 14624>,
+			<14958 14699 14630 14614 14617>,
+			<14951 14794 14633 14616 14620>,
+			<14945 14795 14637 14644 14655>,
+			<14957 14769 14642 14654 14664>,
+			<14968 14805 14636 14660 14668>,
+			<14977 14809 14655 14668 14668>,
+			<14993 14817 14684 14674 14665>,
+			<14993 14817 14684 14674 14665>,
+			<14993 14817 14684 14674 14665>;
+	};
+
+	qcom,pc-temp-z5-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <11983 12740 15393 15537 15330>,
+			<13357 14824 16249 17310 17529>,
+			<14286 16482 17811 18377 18523>,
+			<14945 17642 19175 19223 19510>,
+			<15486 18555 20024 20275 20513>,
+			<15957 19327 20723 21346 21540>,
+			<16368 19918 21568 22345 22519>,
+			<16781 20541 22514 23454 23469>,
+			<17187 21683 23120 24074 24236>,
+			<17674 23224 23449 23971 24698>,
+			<18442 24060 23713 23757 25052>,
+			<19483 24549 23914 23816 25554>,
+			<20437 24925 24207 24637 26312>,
+			<21361 25257 24451 25542 26851>,
+			<22105 25909 24697 26092 27021>,
+			<22478 26475 25087 26614 27131>,
+			<22735 27141 26348 27394 27470>,
+			<23076 28081 28954 28566 28331>,
+			<23809 29715 30229 29356 28825>,
+			<24938 32251 30431 29724 28646>,
+			<27176 33544 30446 29885 28135>,
+			<31932 33025 28578 28445 26783>,
+			<35226 31860 23567 23249 22747>,
+			<36819 29994 21621 20580 20432>,
+			<37874 26035 23092 21806 21763>,
+			<37147 24128 25214 23841 23948>,
+			<34993 26078 27156 25488 25430>,
+			<32825 29127 29386 27105 26647>,
+			<30980 31187 31134 28441 27481>,
+			<29376 32887 32400 29515 28206>,
+			<28873 34208 33430 30375 28775>,
+			<28786 35400 34311 31101 29161>,
+			<28801 36250 35051 31824 29873>,
+			<28836 36325 35497 32045 30283>,
+			<28862 36122 35938 31861 30590>,
+			<28907 35854 36221 31646 31106>,
+			<28980 35186 35497 31570 32686>,
+			<29132 34291 33694 31549 35494>,
+			<29670 33796 32315 31543 36261>,
+			<30652 33516 31332 31469 34185>,
+			<30992 33114 30388 31412 32325>,
+			<29938 32130 29262 32046 32870>,
+			<29033 30867 28327 33225 34089>,
+			<28928 29512 27958 34867 35083>,
+			<16971 28826 27177 35407 35456>,
+			<11113 18542 25875 28236 38118>,
+			<11084 16735 22486 31621 32274>,
+			<11037 15601 21798 36765 39261>,
+			<11035 11499 20071 40032 37713>,
+			<11055 11574 22201 35765 26327>,
+			<11017 12415 21829 29484 22484>,
+			<10951 11419 39496 26044 20817>,
+			<10890 11348 40899 24307 20580>,
+			<10822 11392 37952 25288 21070>,
+			<10822 11392 37952 25288 21070>,
+			<10822 11392 37952 25288 21070>;
+	};
+
+	qcom,pc-temp-z6-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <15711 15103 14773 14710 14694>,
+			<15778 15117 14813 14736 14718>,
+			<15776 15120 14809 14733 14717>,
+			<15702 15106 14804 14728 14716>,
+			<15620 15065 14793 14722 14713>,
+			<15561 15031 14779 14715 14707>,
+			<15508 15007 14768 14709 14701>,
+			<15467 14987 14758 14703 14696>,
+			<15435 14971 14751 14698 14692>,
+			<15407 14959 14748 14695 14689>,
+			<15379 14949 14746 14692 14687>,
+			<15353 14940 14743 14689 14685>,
+			<15339 14935 14739 14687 14684>,
+			<15332 14935 14736 14685 14682>,
+			<15326 14938 14737 14684 14680>,
+			<15316 14939 14738 14683 14678>,
+			<15302 14930 14736 14681 14676>,
+			<15293 14921 14733 14679 14673>,
+			<15289 14921 14732 14677 14671>,
+			<15286 14926 14736 14678 14670>,
+			<15291 14936 14744 14682 14669>,
+			<15312 14986 14761 14691 14674>,
+			<15338 15040 14795 14718 14702>,
+			<15373 15042 14808 14732 14717>,
+			<15408 15027 14802 14727 14713>,
+			<15415 15016 14795 14720 14706>,
+			<15414 15011 14791 14717 14702>,
+			<15412 15007 14788 14714 14699>,
+			<15408 15006 14786 14712 14697>,
+			<15402 15004 14785 14710 14694>,
+			<15399 15004 14784 14708 14691>,
+			<15398 15005 14784 14706 14688>,
+			<15397 15006 14784 14704 14684>,
+			<15397 15009 14784 14701 14680>,
+			<15398 15012 14784 14699 14677>,
+			<15400 15015 14785 14696 14674>,
+			<15402 15016 14785 14697 14677>,
+			<15405 15017 14786 14699 14684>,
+			<15410 15020 14787 14700 14687>,
+			<15416 15026 14789 14702 14685>,
+			<15423 15031 14791 14703 14683>,
+			<15430 15034 14791 14703 14684>,
+			<15437 15037 14791 14704 14687>,
+			<15444 15040 14792 14706 14693>,
+			<15425 15039 14789 14704 14690>,
+			<15419 15030 14781 14691 14673>,
+			<15424 15030 14778 14688 14665>,
+			<15425 15032 14777 14685 14661>,
+			<15431 15036 14780 14688 14662>,
+			<15438 15047 14792 14708 14685>,
+			<15458 15060 14801 14718 14695>,
+			<15477 15072 14815 14726 14702>,
+			<15501 15088 14835 14737 14710>,
+			<15534 15114 14862 14753 14720>,
+			<15534 15114 14862 14753 14720>,
+			<15534 15114 14862 14753 14720>;
+	};
+
+	qcom,pc-temp-y1-lut {
+		qcom,lut-col-legend = <(-20) (-10) 0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000 8800>,
+			<8600 8400 8200 8000 7800 7600 7400>,
+			<7200 7000 6800 6600 6400 6200 6000>,
+			<5800 5600 5400 5200 5000 4800 4600>,
+			<4400 4200 4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200 2000 1800>,
+			<1600 1400 1200 1000 900 800 700>,
+			<600 500 400 300 200 100 0>;
+		qcom,lut-data = <7619 6963 6363 6007 5630 5512 5470>,
+			<7591 6945 6361 6003 5629 5510 5471>,
+			<7573 6934 6357 5999 5628 5508 5471>,
+			<7563 6929 6354 5995 5627 5506 5471>,
+			<7558 6928 6353 5992 5626 5505 5470>,
+			<7556 6928 6357 5988 5625 5503 5470>,
+			<7563 6934 6366 5985 5624 5502 5469>,
+			<7573 6942 6374 5981 5624 5501 5467>,
+			<7583 6939 6374 5982 5623 5500 5467>,
+			<7616 6920 6366 5984 5624 5499 5467>,
+			<7634 6910 6360 5985 5624 5498 5466>,
+			<7600 6919 6357 5980 5623 5498 5466>,
+			<7557 6931 6356 5973 5622 5498 5465>,
+			<7560 6935 6362 5973 5622 5499 5465>,
+			<7590 6938 6380 5978 5625 5500 5466>,
+			<7605 6939 6390 5981 5628 5501 5467>,
+			<7608 6942 6389 5985 5631 5501 5468>,
+			<7612 6946 6387 5990 5634 5502 5469>,
+			<7604 6943 6388 5989 5637 5503 5470>,
+			<7584 6932 6391 5988 5639 5506 5471>,
+			<7570 6929 6394 5987 5643 5508 5472>,
+			<7557 6957 6397 5989 5647 5510 5473>,
+			<7546 6985 6400 5994 5653 5513 5475>,
+			<7543 6976 6405 6001 5658 5515 5478>,
+			<7542 6942 6414 6012 5663 5518 5480>,
+			<7542 6928 6418 6018 5668 5522 5483>,
+			<7552 6934 6419 6019 5674 5525 5486>,
+			<7565 6942 6418 6020 5681 5529 5488>,
+			<7569 6951 6418 6021 5687 5533 5491>,
+			<7568 6972 6418 6023 5692 5537 5493>,
+			<7564 6978 6418 6025 5698 5541 5497>,
+			<7549 6971 6422 6028 5705 5545 5500>,
+			<7534 6961 6425 6032 5712 5550 5504>,
+			<7531 6947 6422 6038 5720 5554 5507>,
+			<7529 6929 6416 6048 5727 5559 5509>,
+			<7527 6925 6416 6055 5734 5563 5512>,
+			<7537 6932 6428 6059 5741 5569 5516>,
+			<7548 6939 6438 6062 5748 5575 5522>,
+			<7546 6939 6433 6063 5757 5580 5526>,
+			<7534 6942 6422 6064 5767 5585 5529>,
+			<7527 6944 6417 6067 5775 5591 5533>,
+			<7526 6946 6416 6077 5783 5596 5537>,
+			<7530 6941 6418 6083 5787 5603 5541>,
+			<7568 6923 6429 6090 5790 5610 5546>,
+			<7559 6953 6428 6086 5808 5622 5555>,
+			<7568 6932 6433 6091 5813 5631 5561>,
+			<7570 6928 6433 6099 5818 5635 5565>,
+			<7608 6933 6442 6113 5834 5640 5567>,
+			<7652 6932 6430 6105 5835 5645 5571>,
+			<7693 6936 6436 6106 5848 5654 5578>,
+			<7737 6965 6440 6099 5858 5666 5585>,
+			<7770 6990 6464 6110 5873 5684 5600>,
+			<7830 7027 6445 6123 5887 5704 5613>,
+			<7848 7064 6471 6136 5914 5726 5633>,
+			<7848 7064 6471 6136 5914 5726 5633>,
+			<7848 7064 6471 6136 5914 5726 5633>;
+	};
+
+	qcom,pc-temp-y2-lut {
+		qcom,lut-col-legend = <(-20) (-10) 0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000 8800>,
+			<8600 8400 8200 8000 7800 7600 7400>,
+			<7200 7000 6800 6600 6400 6200 6000>,
+			<5800 5600 5400 5200 5000 4800 4600>,
+			<4400 4200 4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200 2000 1800>,
+			<1600 1400 1200 1000 900 800 700>,
+			<600 500 400 300 200 100 0>;
+		qcom,lut-data = <9652 9643 10780 11037 11216 11097 11009>,
+			<9653 9653 10747 10993 11177 11076 11016>,
+			<9654 9867 10710 10945 11129 11053 11018>,
+			<9655 10082 10673 10898 11080 11031 11018>,
+			<9655 10246 10642 10860 11037 11010 11015>,
+			<9655 10308 10624 10837 11007 10992 11010>,
+			<9655 10281 10616 10826 10987 10977 10981>,
+			<9655 10241 10610 10820 10968 10962 10937>,
+			<9655 10275 10600 10816 10953 10942 10920>,
+			<9655 10440 10586 10802 10939 10913 10908>,
+			<9655 10531 10580 10792 10927 10894 10901>,
+			<9654 10522 10610 10786 10915 10881 10897>,
+			<9654 10502 10665 10780 10900 10869 10890>,
+			<9653 10430 10721 10797 10878 10869 10877>,
+			<9653 10226 10789 10873 10846 10876 10849>,
+			<9653 10115 10817 10940 10834 10878 10831>,
+			<9653 9949 10805 10988 10876 10871 10840>,
+			<9653 9749 10791 11021 10939 10863 10860>,
+			<9653 9704 10791 11014 10991 10869 10866>,
+			<9653 9683 10795 10979 11041 10898 10870>,
+			<9653 9677 10801 10965 11063 10936 10877>,
+			<9653 9676 10808 10997 11078 11004 10940>,
+			<9653 9676 10820 11042 11093 11066 11026>,
+			<9652 9674 10836 11062 11099 11074 11055>,
+			<9652 9670 10861 11077 11105 11063 11066>,
+			<9652 9667 10915 11082 11111 11064 11068>,
+			<9652 9665 11341 11085 11126 11092 11072>,
+			<9652 9663 11748 11091 11149 11125 11083>,
+			<9652 9661 11516 11099 11179 11148 11096>,
+			<9652 9659 10816 11110 11217 11174 11118>,
+			<9652 9658 10376 11118 11236 11190 11131>,
+			<9652 9657 10155 11117 11245 11208 11140>,
+			<9652 9656 10000 11109 11252 11224 11152>,
+			<9652 9655 9892 11094 11259 11233 11175>,
+			<9652 9654 9812 11060 11260 11250 11208>,
+			<9652 9654 9762 11020 11250 11255 11218>,
+			<9652 9653 9725 10915 11227 11244 11186>,
+			<9652 9653 9701 10784 11207 11227 11146>,
+			<9652 9653 9688 10695 11192 11211 11135>,
+			<9651 9652 9678 10615 11172 11194 11131>,
+			<9651 9652 9671 10480 11143 11192 11126>,
+			<9651 9652 9665 10201 11106 11216 11112>,
+			<9651 9651 9661 10108 11076 11220 11105>,
+			<9651 9651 9658 10159 11042 11183 11120>,
+			<9650 9651 9656 9965 10929 11157 11073>,
+			<9650 9651 9654 9856 10889 11090 11023>,
+			<9650 9651 9653 9796 10823 11057 10968>,
+			<9649 9650 9653 9741 10794 11051 10955>,
+			<9649 9650 9652 9696 10740 11029 10918>,
+			<9649 9650 9652 9680 10652 10968 10907>,
+			<9648 9650 9651 9670 10540 10916 10868>,
+			<9648 9649 9651 9663 10397 10801 10776>,
+			<9647 9648 9650 9657 10262 10712 10696>,
+			<9647 9648 9650 9654 10448 10584 10596>,
+			<9647 9648 9650 9654 10448 10584 10596>,
+			<9647 9648 9650 9654 10448 10584 10596>;
+	};
+
+	qcom,pc-temp-y3-lut {
+		qcom,lut-col-legend = <(-20) (-10) 0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000 8800>,
+			<8600 8400 8200 8000 7800 7600 7400>,
+			<7200 7000 6800 6600 6400 6200 6000>,
+			<5800 5600 5400 5200 5000 4800 4600>,
+			<4400 4200 4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200 2000 1800>,
+			<1600 1400 1200 1000 900 800 700>,
+			<600 500 400 300 200 100 0>;
+		qcom,lut-data = <14249 13491 13351 13296 13276 13275 13272>,
+			<14289 13481 13348 13297 13278 13275 13272>,
+			<14293 13476 13346 13298 13280 13275 13273>,
+			<14269 13476 13347 13300 13282 13276 13274>,
+			<14223 13480 13349 13302 13283 13276 13274>,
+			<14165 13486 13352 13303 13283 13276 13275>,
+			<14057 13513 13358 13303 13283 13276 13275>,
+			<13951 13546 13363 13304 13283 13276 13275>,
+			<13946 13543 13365 13306 13283 13277 13275>,
+			<13996 13505 13365 13310 13284 13278 13275>,
+			<14024 13476 13366 13315 13285 13278 13276>,
+			<13979 13465 13371 13319 13285 13278 13276>,
+			<13920 13456 13377 13322 13285 13278 13276>,
+			<13916 13446 13376 13322 13286 13278 13276>,
+			<13935 13434 13369 13321 13288 13279 13277>,
+			<13956 13428 13363 13320 13290 13279 13277>,
+			<13974 13428 13359 13318 13291 13280 13278>,
+			<13993 13428 13354 13316 13292 13282 13278>,
+			<14013 13414 13349 13313 13292 13283 13279>,
+			<14037 13377 13343 13308 13291 13283 13281>,
+			<14068 13356 13338 13304 13290 13284 13281>,
+			<14115 13351 13336 13301 13286 13280 13278>,
+			<14171 13349 13333 13299 13283 13276 13274>,
+			<14221 13354 13323 13298 13282 13275 13273>,
+			<14271 13374 13301 13297 13281 13275 13273>,
+			<14325 13397 13289 13297 13281 13275 13273>,
+			<14385 13424 13273 13297 13280 13275 13273>,
+			<14448 13457 13259 13297 13280 13275 13273>,
+			<14513 13494 13259 13296 13280 13275 13273>,
+			<14578 13537 13259 13296 13280 13275 13273>,
+			<14647 13586 13260 13295 13280 13274 13272>,
+			<14717 13644 13261 13291 13280 13274 13272>,
+			<14792 13708 13262 13288 13279 13274 13272>,
+			<14878 13777 13264 13289 13279 13274 13272>,
+			<14972 13853 13268 13293 13279 13273 13272>,
+			<15069 13939 13274 13295 13279 13273 13272>,
+			<15166 14040 13285 13294 13279 13274 13272>,
+			<15270 14153 13299 13292 13280 13274 13273>,
+			<15386 14276 13317 13292 13279 13274 13273>,
+			<15514 14412 13340 13293 13279 13274 13273>,
+			<15658 14564 13372 13291 13279 13274 13273>,
+			<15825 14738 13423 13271 13280 13275 13273>,
+			<16019 14925 13493 13262 13280 13275 13273>,
+			<16253 15128 13598 13261 13280 13274 13273>,
+			<16581 15354 13729 13263 13279 13275 13274>,
+			<16918 15547 13885 13266 13284 13276 13275>,
+			<17576 15700 13996 13270 13284 13277 13277>,
+			<18634 15883 14139 13280 13288 13279 13277>,
+			<20075 16098 14305 13309 13290 13280 13277>,
+			<22149 16340 14489 13343 13292 13280 13276>,
+			<25271 16656 14726 13389 13294 13281 13277>,
+			<29950 17634 15025 13481 13299 13283 13278>,
+			<37310 19636 15401 13635 13309 13286 13283>,
+			<47876 22946 16005 13899 13335 13293 13287>,
+			<47876 22946 16005 13899 13335 13293 13287>,
+			<47876 22946 16005 13899 13335 13293 13287>;
+	};
+
+	qcom,pc-temp-y4-lut {
+		qcom,lut-col-legend = <(-20) (-10) 0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000 8800>,
+			<8600 8400 8200 8000 7800 7600 7400>,
+			<7200 7000 6800 6600 6400 6200 6000>,
+			<5800 5600 5400 5200 5000 4800 4600>,
+			<4400 4200 4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200 2000 1800>,
+			<1600 1400 1200 1000 900 800 700>,
+			<600 500 400 300 200 100 0>;
+		qcom,lut-data = <17711 16973 16623 16526 16458 16452 16456>,
+			<17567 16999 16632 16525 16457 16452 16456>,
+			<17504 17030 16641 16525 16457 16452 16456>,
+			<17504 17060 16652 16526 16457 16452 16456>,
+			<17547 17082 16663 16528 16457 16452 16456>,
+			<17613 17089 16674 16531 16457 16452 16456>,
+			<17765 17077 16687 16535 16459 16452 16456>,
+			<17948 17059 16701 16539 16462 16453 16456>,
+			<18024 17098 16711 16545 16465 16453 16456>,
+			<18066 17276 16720 16552 16468 16454 16457>,
+			<18080 17396 16735 16563 16473 16455 16457>,
+			<17811 17426 16824 16584 16480 16458 16458>,
+			<17427 17443 16930 16612 16490 16461 16460>,
+			<17319 17384 16951 16638 16498 16465 16462>,
+			<17285 17155 16958 16663 16504 16470 16465>,
+			<17245 17028 16959 16695 16515 16476 16469>,
+			<17166 17014 16934 16758 16539 16486 16475>,
+			<17085 17005 16887 16816 16571 16502 16486>,
+			<17039 16980 16831 16800 16609 16530 16506>,
+			<17007 16933 16754 16713 16656 16576 16541>,
+			<16985 16886 16692 16635 16664 16593 16558>,
+			<16968 16837 16644 16572 16570 16535 16521>,
+			<16957 16797 16610 16522 16475 16468 16470>,
+			<16954 16783 16607 16507 16460 16455 16458>,
+			<16953 16776 16623 16498 16454 16451 16455>,
+			<16953 16770 16632 16494 16453 16449 16454>,
+			<16951 16765 16645 16493 16454 16449 16453>,
+			<16951 16761 16659 16493 16455 16448 16453>,
+			<16953 16761 16662 16492 16457 16449 16453>,
+			<16959 16761 16663 16493 16461 16452 16454>,
+			<16965 16762 16667 16493 16466 16456 16455>,
+			<16974 16764 16677 16492 16474 16464 16461>,
+			<16982 16767 16687 16492 16479 16471 16470>,
+			<16985 16770 16690 16494 16478 16474 16476>,
+			<16987 16775 16693 16500 16474 16474 16483>,
+			<16990 16778 16693 16505 16467 16471 16482>,
+			<16999 16782 16689 16508 16455 16458 16467>,
+			<17010 16784 16685 16510 16448 16447 16453>,
+			<17021 16783 16685 16511 16449 16450 16455>,
+			<17033 16781 16683 16512 16452 16456 16465>,
+			<17048 16779 16681 16517 16455 16459 16471>,
+			<17066 16770 16670 16558 16460 16458 16470>,
+			<17087 16768 16654 16579 16464 16456 16468>,
+			<17112 16776 16634 16584 16465 16448 16452>,
+			<17124 16801 16629 16593 16474 16448 16444>,
+			<17066 16819 16647 16617 16493 16467 16470>,
+			<17161 16856 16669 16641 16507 16488 16496>,
+			<17324 16905 16699 16672 16536 16520 16521>,
+			<17559 16944 16754 16675 16565 16529 16536>,
+			<17893 16949 16780 16683 16555 16503 16488>,
+			<18450 16941 16767 16681 16554 16495 16479>,
+			<19496 17078 16794 16695 16582 16508 16485>,
+			<21979 17565 16874 16751 16646 16545 16510>,
+			<30091 19162 17124 16888 16859 16671 16581>,
+			<30091 19162 17124 16888 16859 16671 16581>,
+			<30091 19162 17124 16888 16859 16671 16581>;
+	};
+
+	qcom,pc-temp-y5-lut {
+		qcom,lut-col-legend = <(-20) (-10) 0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000 8800>,
+			<8600 8400 8200 8000 7800 7600 7400>,
+			<7200 7000 6800 6600 6400 6200 6000>,
+			<5800 5600 5400 5200 5000 4800 4600>,
+			<4400 4200 4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200 2000 1800>,
+			<1600 1400 1200 1000 900 800 700>,
+			<600 500 400 300 200 100 0>;
+		qcom,lut-data = <9336 11501 16034 14767 13793 19407 15565>,
+			<10230 11603 15822 15156 15683 19413 16938>,
+			<10807 11875 15497 15333 17017 19416 18058>,
+			<11133 12285 15152 15352 17855 19416 18894>,
+			<11279 12803 14881 15266 18259 19413 19416>,
+			<11310 13403 14778 15128 18284 19405 19590>,
+			<11059 14551 14807 14793 17405 18933 19301>,
+			<10701 15710 14848 14419 16236 18269 18809>,
+			<11143 15425 14688 14471 15943 18195 18561>,
+			<13343 13533 13983 14951 15873 18327 18385>,
+			<14582 12513 13556 15219 15744 18394 18198>,
+			<13448 13803 13493 14892 15050 17832 17726>,
+			<11924 15473 13460 14418 14306 16921 17099>,
+			<11782 15394 13744 14254 14381 16318 16821>,
+			<12065 14258 14851 14181 14869 15815 16673>,
+			<12212 13562 15643 14199 15070 15556 16471>,
+			<12106 13428 15965 14556 14786 15450 15954>,
+			<11900 13274 16199 15160 14490 15387 15465>,
+			<11618 12936 16398 15863 14755 15446 15449>,
+			<11196 12423 16588 16824 15793 15777 15650>,
+			<11019 11952 16732 17460 16919 16267 15980>,
+			<11074 11476 16879 17821 18292 17600 16933>,
+			<11141 11117 16964 18087 19430 19112 18163>,
+			<11133 11033 16245 18242 19821 19838 19000>,
+			<11069 11009 14141 18325 19945 20331 19696>,
+			<11046 11024 12876 18331 19914 20756 20093>,
+			<11109 11056 11798 18517 19842 21457 20297>,
+			<11170 11084 10948 18759 19785 21999 20418>,
+			<11161 11132 10879 18828 19716 21658 20286>,
+			<11138 11232 10862 18868 19575 20509 19563>,
+			<11111 11269 10868 18768 19409 19604 18813>,
+			<11071 11345 11005 17096 19184 18920 18072>,
+			<11039 11421 11165 15478 19049 18499 17524>,
+			<11083 11456 11261 16038 19331 18661 17776>,
+			<11207 11520 11350 17571 20041 19331 19034>,
+			<11252 11543 11387 18037 20606 20274 20444>,
+			<11213 11613 11553 17270 21412 23017 22060>,
+			<11168 11678 11697 16300 21789 25208 23225>,
+			<11151 11640 11640 15861 20914 24442 22731>,
+			<11145 11545 11511 15530 19618 22425 21047>,
+			<11154 11506 11463 14798 19274 21559 20283>,
+			<11189 11457 11412 12697 19217 21506 20308>,
+			<11250 11415 11500 11853 18717 21719 20486>,
+			<11392 11368 11742 11779 17923 22443 22679>,
+			<11471 11364 11818 11639 16687 21754 22971>,
+			<11412 11379 11581 11310 17555 18408 18279>,
+			<11284 11464 11576 11214 16686 17313 17483>,
+			<10955 11729 11969 11315 17033 16467 15409>,
+			<10501 12142 11899 11677 16717 15881 14424>,
+			<10146 11979 11895 11966 17491 17177 15372>,
+			<9743 11649 12007 11983 17478 18213 16253>,
+			<9402 11017 11938 11964 17190 17836 15973>,
+			<9188 10265 11845 11923 16780 17343 17751>,
+			<8988 9626 11312 12185 16916 17400 17911>,
+			<8988 9626 11312 12185 16916 17400 17911>,
+			<8988 9626 11312 12185 16916 17400 17911>;
+	};
+
+	qcom,pc-temp-y6-lut {
+		qcom,lut-col-legend = <(-20) (-10) 0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000 8800>,
+			<8600 8400 8200 8000 7800 7600 7400>,
+			<7200 7000 6800 6600 6400 6200 6000>,
+			<5800 5600 5400 5200 5000 4800 4600>,
+			<4400 4200 4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200 2000 1800>,
+			<1600 1400 1200 1000 900 800 700>,
+			<600 500 400 300 200 100 0>;
+		qcom,lut-data = <7520 6106 5405 5178 5064 5046 5042>,
+			<7480 6097 5401 5177 5064 5046 5042>,
+			<7441 6092 5400 5176 5065 5046 5042>,
+			<7405 6089 5400 5176 5066 5047 5043>,
+			<7374 6088 5401 5176 5067 5047 5044>,
+			<7350 6088 5403 5176 5067 5047 5044>,
+			<7329 6090 5407 5176 5068 5047 5044>,
+			<7314 6094 5413 5177 5068 5047 5044>,
+			<7323 6102 5416 5178 5069 5047 5044>,
+			<7367 6117 5418 5182 5071 5048 5044>,
+			<7391 6129 5422 5187 5073 5049 5045>,
+			<7291 6135 5450 5195 5075 5050 5045>,
+			<7156 6139 5483 5204 5078 5051 5046>,
+			<7138 6123 5488 5211 5081 5052 5047>,
+			<7142 6059 5490 5218 5085 5054 5048>,
+			<7144 6027 5490 5226 5089 5056 5050>,
+			<7141 6030 5484 5243 5097 5060 5052>,
+			<7136 6034 5472 5259 5107 5066 5055>,
+			<7138 6032 5457 5253 5118 5075 5062>,
+			<7150 6027 5435 5225 5131 5088 5073>,
+			<7165 6025 5421 5201 5133 5093 5078>,
+			<7194 6031 5414 5182 5104 5074 5065>,
+			<7230 6042 5409 5169 5075 5052 5048>,
+			<7265 6061 5410 5167 5071 5048 5044>,
+			<7301 6095 5412 5166 5069 5047 5043>,
+			<7340 6132 5415 5166 5069 5046 5042>,
+			<7383 6169 5421 5168 5070 5047 5042>,
+			<7430 6210 5431 5171 5071 5047 5042>,
+			<7476 6254 5444 5175 5073 5048 5043>,
+			<7523 6302 5464 5178 5075 5049 5043>,
+			<7575 6354 5486 5181 5078 5050 5044>,
+			<7633 6411 5511 5183 5081 5052 5046>,
+			<7696 6471 5539 5185 5083 5055 5048>,
+			<7764 6535 5569 5192 5084 5056 5050>,
+			<7836 6602 5603 5205 5084 5056 5053>,
+			<7911 6677 5640 5216 5084 5056 5053>,
+			<7991 6759 5681 5225 5083 5053 5049>,
+			<8076 6849 5727 5234 5083 5051 5046>,
+			<8172 6948 5778 5244 5084 5052 5047>,
+			<8278 7058 5835 5257 5087 5055 5050>,
+			<8396 7178 5899 5273 5091 5057 5052>,
+			<8531 7313 5971 5295 5095 5058 5052>,
+			<8689 7461 6060 5322 5099 5058 5052>,
+			<8881 7625 6170 5355 5104 5056 5049>,
+			<9142 7801 6295 5404 5112 5059 5048>,
+			<9395 7952 6438 5465 5127 5066 5057>,
+			<9966 8083 6542 5513 5135 5074 5067>,
+			<10874 8233 6666 5574 5150 5086 5075>,
+			<12099 8404 6813 5646 5166 5090 5080>,
+			<13825 8597 6972 5725 5172 5084 5066>,
+			<16318 8831 7159 5819 5184 5085 5065>,
+			<20019 9655 7408 5955 5214 5093 5070>,
+			<25895 11356 7725 6149 5262 5110 5083>,
+			<35348 14260 8288 6430 5374 5157 5109>,
+			<35348 14260 8288 6430 5374 5157 5109>,
+			<35348 14260 8288 6430 5374 5157 5109>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/qg-batterydata-mlp356477-2800mah.dtsi b/arch/arm64/boot/dts/qcom/qg-batterydata-mlp356477-2800mah.dtsi
new file mode 100644
index 0000000..f418fa0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qg-batterydata-mlp356477-2800mah.dtsi
@@ -0,0 +1,1050 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+qcom,mlp356477_2800mah {
+	/* mlp356477_2800mah_averaged_MasterSlave_Aug14th2017 */
+	qcom,max-voltage-uv = <4400000>;
+	qcom,fg-cc-cv-threshold-mv = <4390>;
+	qcom,fastchg-current-ma = <4200>;
+	qcom,batt-id-kohm = <82>;
+	qcom,battery-beta = <4250>;
+	qcom,battery-therm-kohm = <32>;
+	qcom,battery-type =
+		"mlp356477_2800mah_averaged_MasterSlave_Aug14th2017";
+	qcom,qg-batt-profile-ver = <100>;
+
+	qcom,jeita-fcc-ranges = <0   150   560000
+				 151 450  4200000
+				 451 550  2380000>;
+	qcom,jeita-fv-ranges =  <0   150  4150000
+				 151 450  4400000
+				 451 550  4150000>;
+
+	qcom,fcc1-temp-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-data = <2715 2788 2861 2898 2908>;
+	};
+
+	qcom,fcc2-temp-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-data = <2846 2860 2868 2865 2865>;
+	};
+
+	qcom,pc-temp-v1-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <43494 43682 43812 43865 43879>,
+			<43243 43420 43582 43645 43659>,
+			<42984 43174 43350 43418 43434>,
+			<42737 42940 43115 43191 43208>,
+			<42506 42710 42878 42958 42978>,
+			<42287 42479 42641 42722 42746>,
+			<42087 42250 42407 42489 42514>,
+			<41903 42027 42175 42255 42281>,
+			<41709 41807 41948 42023 42050>,
+			<41489 41592 41723 41794 41822>,
+			<41265 41381 41502 41568 41596>,
+			<41069 41176 41286 41348 41374>,
+			<40898 40982 41074 41131 41155>,
+			<40720 40799 40871 40921 40942>,
+			<40501 40613 40673 40716 40735>,
+			<40269 40405 40482 40518 40534>,
+			<40088 40193 40295 40329 40343>,
+			<39955 40022 40116 40148 40162>,
+			<39834 39894 39952 39975 39988>,
+			<39708 39765 39807 39818 39827>,
+			<39583 39577 39645 39659 39667>,
+			<39447 39345 39420 39461 39475>,
+			<39277 39148 39173 39221 39239>,
+			<39089 38991 38991 39014 39028>,
+			<38930 38860 38851 38860 38868>,
+			<38794 38758 38733 38728 38732>,
+			<38683 38676 38628 38611 38612>,
+			<38607 38602 38535 38507 38505>,
+			<38548 38529 38451 38414 38409>,
+			<38501 38462 38373 38327 38317>,
+			<38466 38407 38305 38251 38234>,
+			<38437 38360 38245 38182 38160>,
+			<38405 38317 38193 38121 38092>,
+			<38366 38277 38147 38067 38030>,
+			<38329 38240 38109 38022 37980>,
+			<38300 38203 38069 37977 37929>,
+			<38273 38170 38027 37921 37863>,
+			<38236 38130 37980 37857 37784>,
+			<38162 38057 37912 37781 37700>,
+			<38062 37946 37816 37690 37609>,
+			<37947 37830 37704 37585 37507>,
+			<37801 37713 37578 37463 37382>,
+			<37644 37575 37436 37322 37239>,
+			<37473 37394 37270 37162 37082>,
+			<37320 37251 37129 37032 36959>,
+			<37220 37161 37058 36960 36899>,
+			<37185 37129 37033 36942 36880>,
+			<37156 37103 37014 36927 36865>,
+			<37120 37070 36988 36902 36835>,
+			<37014 36957 36885 36755 36652>,
+			<36682 36593 36544 36398 36287>,
+			<36204 36109 36077 35921 35807>,
+			<35597 35486 35476 35307 35181>,
+			<34771 34630 34656 34460 34321>,
+			<33460 33262 33379 33128 32955>,
+			<30000 30000 30000 30000 30000>;
+	};
+
+	qcom,pc-temp-v2-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <43850 43830 43805 43740 43725>,
+			<43429 43514 43528 43481 43467>,
+			<43064 43219 43264 43228 43216>,
+			<42767 42948 43012 42983 42973>,
+			<42526 42700 42773 42744 42738>,
+			<42296 42458 42537 42509 42505>,
+			<42059 42213 42303 42277 42272>,
+			<41822 41972 42071 42047 42041>,
+			<41571 41739 41843 41820 41814>,
+			<41298 41515 41619 41595 41589>,
+			<41069 41297 41398 41374 41368>,
+			<40928 41088 41181 41158 41151>,
+			<40808 40884 40967 40946 40938>,
+			<40611 40677 40763 40742 40734>,
+			<40284 40461 40566 40541 40534>,
+			<39989 40259 40373 40348 40342>,
+			<39811 40087 40180 40164 40158>,
+			<39662 39920 39993 39985 39980>,
+			<39459 39722 39821 39814 39808>,
+			<39184 39492 39664 39651 39646>,
+			<38924 39264 39483 39469 39466>,
+			<38721 39048 39237 39230 39230>,
+			<38546 38846 38982 38986 38989>,
+			<38403 38678 38799 38809 38813>,
+			<38282 38535 38654 38669 38674>,
+			<38189 38406 38530 38547 38552>,
+			<38125 38286 38419 38438 38442>,
+			<38075 38179 38320 38341 38343>,
+			<38030 38090 38229 38250 38250>,
+			<37992 38012 38144 38166 38164>,
+			<37955 37949 38066 38089 38086>,
+			<37916 37900 37993 38019 38016>,
+			<37875 37857 37925 37953 37949>,
+			<37832 37817 37860 37884 37875>,
+			<37788 37781 37801 37812 37795>,
+			<37738 37740 37738 37728 37702>,
+			<37680 37688 37671 37625 37587>,
+			<37613 37625 37600 37519 37469>,
+			<37537 37552 37525 37430 37374>,
+			<37448 37465 37446 37352 37292>,
+			<37349 37363 37353 37263 37200>,
+			<37237 37238 37238 37151 37088>,
+			<37114 37101 37106 37022 36960>,
+			<36989 36957 36952 36870 36813>,
+			<36875 36859 36862 36807 36758>,
+			<36792 36792 36828 36785 36734>,
+			<36754 36762 36812 36769 36719>,
+			<36707 36710 36780 36736 36687>,
+			<36633 36613 36721 36656 36581>,
+			<36472 36411 36517 36379 36276>,
+			<36149 36031 36113 35946 35829>,
+			<35650 35485 35584 35386 35258>,
+			<34964 34771 34884 34643 34500>,
+			<34007 33739 33902 33598 33440>,
+			<32474 32144 32393 32025 31829>,
+			<28051 26513 28737 27554 26991>;
+	};
+
+	qcom,pc-temp-z1-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <14442 13243 12339 11979 11839>,
+			<14411 13218 12328 11916 11773>,
+			<14392 13199 12294 11893 11756>,
+			<14384 13180 12273 11879 11745>,
+			<14381 13174 12263 11870 11738>,
+			<14377 13179 12257 11863 11735>,
+			<14369 13182 12253 11858 11731>,
+			<14358 13175 12250 11851 11726>,
+			<14349 13158 12248 11847 11722>,
+			<14339 13146 12242 11845 11720>,
+			<14332 13143 12237 11845 11719>,
+			<14327 13144 12237 11844 11718>,
+			<14321 13142 12238 11840 11716>,
+			<14313 13135 12234 11837 11715>,
+			<14306 13128 12222 11835 11714>,
+			<14299 13120 12215 11834 11714>,
+			<14293 13113 12211 11833 11713>,
+			<14293 13111 12203 11830 11714>,
+			<14297 13119 12202 11828 11715>,
+			<14304 13129 12210 11831 11716>,
+			<14312 13133 12215 11837 11718>,
+			<14318 13130 12221 11841 11721>,
+			<14319 13125 12230 11843 11726>,
+			<14320 13135 12234 11846 11730>,
+			<14324 13151 12236 11852 11734>,
+			<14340 13158 12238 11860 11737>,
+			<14358 13165 12247 11865 11741>,
+			<14373 13167 12258 11870 11747>,
+			<14389 13165 12260 11873 11752>,
+			<14394 13167 12258 11877 11757>,
+			<14373 13169 12256 11880 11760>,
+			<14334 13168 12253 11886 11764>,
+			<14321 13167 12247 11892 11768>,
+			<14348 13170 12248 11897 11772>,
+			<14378 13177 12260 11901 11778>,
+			<14371 13182 12271 11905 11783>,
+			<14343 13188 12277 11910 11788>,
+			<14331 13194 12283 11917 11792>,
+			<14346 13205 12290 11924 11797>,
+			<14369 13219 12300 11931 11803>,
+			<14389 13228 12307 11937 11809>,
+			<14412 13237 12311 11941 11815>,
+			<14410 13245 12315 11945 11820>,
+			<14367 13259 12315 11949 11823>,
+			<14429 13239 12311 11954 11824>,
+			<14440 13243 12333 11959 11830>,
+			<14452 13241 12320 11961 11828>,
+			<14443 13243 12329 11964 11831>,
+			<14484 13241 12332 11968 11836>,
+			<14448 13263 12343 11977 11845>,
+			<14473 13293 12346 11988 11856>,
+			<14501 13300 12357 12000 11864>,
+			<14521 13333 12374 12015 11879>,
+			<14603 13373 12420 12034 11897>,
+			<14603 13373 12420 12034 11897>,
+			<14603 13373 12420 12034 11897>;
+	};
+
+	qcom,pc-temp-z2-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <9070 11213 10264 10349 10299>,
+			<9403 10211 10276 10386 10313>,
+			<9826 10116 10342 10430 10322>,
+			<9983 10114 10362 10447 10350>,
+			<9978 10115 10368 10437 10342>,
+			<9967 10120 10372 10407 10282>,
+			<9846 10126 10371 10393 10237>,
+			<9534 10132 10368 10388 10217>,
+			<9372 10137 10365 10382 10206>,
+			<9574 10141 10365 10378 10208>,
+			<9873 10143 10365 10386 10216>,
+			<9940 10145 10357 10384 10231>,
+			<9908 10147 10346 10370 10273>,
+			<9890 10148 10344 10357 10310>,
+			<9864 10149 10352 10353 10325>,
+			<9749 10147 10354 10353 10336>,
+			<9714 10144 10347 10355 10342>,
+			<10069 10146 10343 10360 10343>,
+			<10530 10156 10344 10366 10344>,
+			<10637 10166 10343 10378 10353>,
+			<10631 10154 10344 10396 10363>,
+			<10605 10119 10374 10405 10360>,
+			<10392 10103 10415 10412 10326>,
+			<10061 10118 10414 10414 10294>,
+			<9958 10135 10371 10402 10266>,
+			<9962 10132 10339 10387 10241>,
+			<9968 10117 10335 10377 10241>,
+			<9971 10107 10337 10360 10253>,
+			<9975 10109 10342 10353 10270>,
+			<9977 10112 10351 10373 10299>,
+			<9855 10116 10359 10397 10330>,
+			<9628 10123 10362 10398 10343>,
+			<9563 10131 10365 10389 10349>,
+			<9597 10143 10370 10392 10366>,
+			<9647 10159 10379 10443 10415>,
+			<9714 10166 10389 10499 10464>,
+			<9809 10169 10397 10520 10486>,
+			<9844 10172 10405 10533 10511>,
+			<9756 10186 10432 10548 10531>,
+			<9631 10212 10505 10586 10563>,
+			<9541 10225 10551 10621 10587>,
+			<9445 10161 10538 10637 10540>,
+			<9378 10144 10527 10646 10468>,
+			<9335 10322 10539 10611 10495>,
+			<9269 13378 10554 10627 10491>,
+			<9218 14361 10475 10629 10534>,
+			<9220 14794 10469 10642 10588>,
+			<9212 15070 10496 10651 10586>,
+			<9188 13785 10469 10739 10647>,
+			<9170 13219 10622 10694 10458>,
+			<9151 12652 10655 10557 10325>,
+			<9135 12236 10610 10495 10272>,
+			<9116 11644 10496 10432 10195>,
+			<9081 11027 10456 10300 10139>,
+			<9081 11027 10456 10300 10139>,
+			<9081 11027 10456 10300 10139>;
+	};
+
+	qcom,pc-temp-z3-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <19308 19258 19367 19369 19345>,
+			<19567 19611 19463 19395 19370>,
+			<19850 19705 19512 19411 19381>,
+			<19967 19740 19520 19416 19385>,
+			<19987 19749 19515 19414 19384>,
+			<19996 19735 19507 19405 19379>,
+			<19860 19713 19499 19400 19373>,
+			<19484 19698 19492 19395 19369>,
+			<19288 19687 19483 19391 19365>,
+			<19508 19679 19473 19388 19362>,
+			<19829 19673 19467 19382 19358>,
+			<19858 19667 19463 19378 19357>,
+			<19678 19660 19461 19372 19355>,
+			<19567 19648 19461 19369 19353>,
+			<19627 19641 19463 19369 19353>,
+			<19647 19646 19465 19368 19355>,
+			<19577 19654 19458 19367 19355>,
+			<19415 19653 19447 19366 19345>,
+			<19268 19631 19443 19365 19337>,
+			<19258 19613 19443 19365 19337>,
+			<19258 19623 19446 19366 19337>,
+			<19260 19652 19459 19374 19342>,
+			<19450 19665 19480 19393 19364>,
+			<19797 19666 19494 19403 19379>,
+			<19919 19667 19506 19402 19379>,
+			<19924 19671 19511 19400 19378>,
+			<19927 19681 19507 19400 19374>,
+			<19922 19686 19499 19400 19366>,
+			<19906 19684 19492 19399 19360>,
+			<19891 19680 19487 19397 19359>,
+			<19798 19673 19482 19393 19359>,
+			<19639 19661 19476 19390 19359>,
+			<19579 19650 19470 19386 19357>,
+			<19566 19644 19465 19382 19355>,
+			<19553 19639 19460 19380 19352>,
+			<19468 19636 19457 19378 19348>,
+			<19316 19630 19455 19375 19346>,
+			<19261 19624 19453 19373 19344>,
+			<19262 19618 19450 19371 19343>,
+			<19263 19609 19443 19369 19345>,
+			<19264 19576 19437 19368 19347>,
+			<19267 19367 19435 19368 19350>,
+			<19269 19261 19432 19367 19353>,
+			<19270 19260 19421 19365 19353>,
+			<19274 19257 19413 19361 19354>,
+			<19278 19257 19368 19354 19332>,
+			<19278 19257 19367 19346 19332>,
+			<19279 19257 19362 19331 19323>,
+			<19282 19257 19368 19326 19327>,
+			<19284 19257 19354 19338 19350>,
+			<19287 19257 19361 19346 19348>,
+			<19290 19257 19368 19356 19347>,
+			<19295 19257 19370 19353 19356>,
+			<19308 19258 19392 19382 19373>,
+			<19308 19258 19392 19382 19373>,
+			<19308 19258 19392 19382 19373>;
+	};
+
+	qcom,pc-temp-z4-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <16598 15992 15337 14972 14879>,
+			<16815 16035 15386 15059 14940>,
+			<16561 15923 15277 14982 14899>,
+			<16283 15657 15173 14901 14842>,
+			<15982 15436 15082 14879 14824>,
+			<15774 15304 15020 14868 14816>,
+			<15800 15207 14988 14856 14809>,
+			<15941 15154 14966 14843 14802>,
+			<16005 15119 14946 14830 14794>,
+			<15750 15094 14928 14818 14785>,
+			<15383 15076 14912 14807 14775>,
+			<15316 15063 14897 14797 14766>,
+			<15433 15048 14884 14788 14757>,
+			<15501 15033 14874 14778 14748>,
+			<15463 15025 14866 14769 14737>,
+			<15509 15037 14860 14760 14725>,
+			<15596 15057 14852 14751 14718>,
+			<15677 15056 14841 14742 14715>,
+			<15729 15002 14835 14738 14712>,
+			<15708 14951 14832 14736 14709>,
+			<15684 15017 14833 14735 14707>,
+			<15650 15207 14923 14756 14718>,
+			<15508 15302 15068 14837 14777>,
+			<15298 15313 15091 14879 14814>,
+			<15235 15319 15040 14870 14809>,
+			<15282 15294 14989 14855 14800>,
+			<15330 15200 14962 14841 14793>,
+			<15320 15131 14943 14826 14787>,
+			<15270 15105 14932 14814 14780>,
+			<15232 15088 14926 14805 14771>,
+			<15276 15076 14923 14798 14761>,
+			<15373 15065 14921 14794 14754>,
+			<15397 15057 14920 14791 14747>,
+			<15385 15051 14919 14789 14742>,
+			<15376 15043 14916 14787 14738>,
+			<15430 15036 14914 14786 14736>,
+			<15544 15016 14915 14794 14745>,
+			<15577 14998 14918 14811 14767>,
+			<15550 14991 14917 14816 14774>,
+			<15520 14987 14909 14811 14768>,
+			<15502 14998 14896 14803 14760>,
+			<15491 15139 14873 14788 14752>,
+			<15475 15211 14850 14774 14747>,
+			<15445 15195 14842 14774 14750>,
+			<15345 15130 14813 14764 14741>,
+			<15318 15079 14802 14736 14721>,
+			<15308 15066 14777 14720 14700>,
+			<15301 15057 14757 14705 14684>,
+			<15285 15045 14739 14698 14668>,
+			<15274 15053 14775 14717 14688>,
+			<15294 15076 14782 14719 14696>,
+			<15311 15080 14778 14712 14701>,
+			<15326 15091 14779 14719 14701>,
+			<15354 15108 14768 14706 14703>,
+			<15354 15108 14768 14706 14703>,
+			<15354 15108 14768 14706 14703>;
+	};
+
+	qcom,pc-temp-z5-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <10764 10957 12110 13794 13670>,
+			<11745 12925 13686 14768 14977>,
+			<12716 14010 14746 16056 16445>,
+			<13404 14718 15521 16744 17361>,
+			<13905 15321 16180 16789 17415>,
+			<14200 15933 16545 16568 17166>,
+			<13611 16455 16653 16420 16940>,
+			<11869 16730 16710 16364 16838>,
+			<10978 16895 16699 16401 16763>,
+			<12521 17062 16594 16402 16659>,
+			<14783 17315 16549 16292 16587>,
+			<15011 17507 16656 16178 16634>,
+			<13819 17490 16845 16003 16770>,
+			<13134 17527 17100 15977 16943>,
+			<13823 17638 17538 16159 17435>,
+			<14192 17626 17786 16425 18421>,
+			<13660 17482 17557 16723 18632>,
+			<12194 17384 17254 17131 17493>,
+			<10877 17447 17366 17305 16542>,
+			<10795 17704 18253 17609 16717>,
+			<10808 18910 18937 18108 17070>,
+			<10857 21136 18167 17900 17037>,
+			<13850 21892 16713 16569 16529>,
+			<19285 19957 16394 15708 16174>,
+			<21102 17736 16736 15560 16006>,
+			<20977 17560 17186 15557 15832>,
+			<20752 18050 17734 15845 15773>,
+			<20272 18693 18431 16567 15708>,
+			<19413 19705 19132 17289 15707>,
+			<18772 20743 19927 17959 16182>,
+			<17386 21034 20581 18611 16967>,
+			<15327 21059 21018 19179 17620>,
+			<14631 21034 21355 19699 18403>,
+			<14512 21133 21507 20256 19056>,
+			<14338 21373 21604 21000 19675>,
+			<13329 21460 21643 21494 20064>,
+			<11563 21322 21601 20994 19488>,
+			<10927 21163 21493 19730 18023>,
+			<10937 21134 21270 19156 17559>,
+			<10948 21040 20651 18991 17865>,
+			<10942 20318 20135 18929 18319>,
+			<10912 14582 19994 18903 18925>,
+			<10885 11608 19761 18788 19444>,
+			<10861 11587 18126 17802 18686>,
+			<10871 11314 17978 17266 18426>,
+			<10857 11130 15054 17271 15914>,
+			<10841 11088 15214 17078 16658>,
+			<10831 11067 15184 16484 17071>,
+			<10841 11046 15966 16365 19357>,
+			<10877 11142 14378 15551 19427>,
+			<10922 11156 14140 15626 17699>,
+			<10887 11109 14272 16679 16814>,
+			<10848 11069 14202 15606 17668>,
+			<10790 10995 15166 19180 19716>,
+			<10790 10995 15166 19180 19716>,
+			<10790 10995 15166 19180 19716>;
+	};
+
+	qcom,pc-temp-z6-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <17029 15901 15123 14807 14723>,
+			<17156 16022 15165 14844 14750>,
+			<17081 15990 15131 14815 14734>,
+			<16977 15851 15090 14780 14711>,
+			<16818 15720 15039 14766 14700>,
+			<16645 15630 15000 14756 14693>,
+			<16486 15560 14978 14746 14686>,
+			<16331 15519 14962 14737 14680>,
+			<16255 15490 14945 14728 14674>,
+			<16244 15468 14929 14720 14668>,
+			<16238 15452 14916 14712 14662>,
+			<16217 15438 14905 14704 14656>,
+			<16172 15422 14897 14697 14651>,
+			<16139 15401 14891 14691 14646>,
+			<16146 15390 14887 14686 14642>,
+			<16166 15395 14883 14681 14638>,
+			<16163 15403 14876 14677 14633>,
+			<16120 15402 14866 14672 14627>,
+			<16076 15372 14862 14670 14622>,
+			<16063 15345 14862 14670 14621>,
+			<16057 15380 14865 14671 14621>,
+			<16055 15480 14915 14684 14629>,
+			<16092 15533 14991 14732 14668>,
+			<16168 15543 15006 14757 14692>,
+			<16218 15549 14992 14753 14691>,
+			<16251 15541 14976 14746 14687>,
+			<16270 15511 14964 14741 14683>,
+			<16266 15488 14954 14735 14676>,
+			<16246 15479 14948 14730 14671>,
+			<16227 15473 14944 14726 14666>,
+			<16204 15467 14942 14722 14662>,
+			<16176 15459 14941 14719 14659>,
+			<16164 15454 14939 14716 14657>,
+			<16159 15453 14938 14715 14654>,
+			<16154 15453 14937 14714 14651>,
+			<16145 15453 14936 14714 14649>,
+			<16133 15450 14939 14717 14652>,
+			<16130 15447 14943 14725 14662>,
+			<16133 15449 14943 14727 14665>,
+			<16139 15454 14940 14725 14664>,
+			<16147 15454 14936 14723 14663>,
+			<16161 15429 14929 14718 14662>,
+			<16171 15417 14922 14712 14662>,
+			<16178 15424 14918 14713 14664>,
+			<16162 15408 14909 14708 14663>,
+			<16165 15399 14883 14694 14643>,
+			<16168 15398 14875 14684 14633>,
+			<16172 15401 14867 14670 14622>,
+			<16179 15405 14866 14665 14618>,
+			<16193 15425 14881 14682 14641>,
+			<16228 15451 14892 14690 14645>,
+			<16262 15468 14902 14695 14650>,
+			<16300 15497 14912 14700 14657>,
+			<16361 15535 14930 14716 14672>,
+			<16361 15535 14930 14716 14672>,
+			<16361 15535 14930 14716 14672>;
+	};
+
+	qcom,pc-temp-y1-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <6704 6050 5566 5322 5235>,
+			<6701 6050 5560 5320 5234>,
+			<6693 6051 5554 5318 5233>,
+			<6684 6051 5548 5316 5231>,
+			<6676 6052 5543 5313 5230>,
+			<6673 6053 5540 5311 5228>,
+			<6667 6054 5539 5308 5225>,
+			<6659 6054 5538 5305 5222>,
+			<6663 6055 5536 5302 5222>,
+			<6693 6056 5529 5299 5222>,
+			<6717 6055 5525 5298 5222>,
+			<6716 6050 5525 5297 5220>,
+			<6707 6044 5526 5296 5217>,
+			<6706 6044 5528 5295 5216>,
+			<6707 6049 5533 5293 5217>,
+			<6709 6052 5536 5291 5217>,
+			<6705 6053 5534 5290 5219>,
+			<6699 6055 5532 5288 5221>,
+			<6700 6057 5532 5289 5221>,
+			<6708 6062 5531 5290 5220>,
+			<6715 6065 5531 5292 5219>,
+			<6712 6067 5532 5294 5220>,
+			<6706 6071 5532 5296 5222>,
+			<6703 6071 5532 5297 5223>,
+			<6702 6070 5532 5298 5225>,
+			<6702 6069 5532 5299 5227>,
+			<6700 6068 5535 5301 5229>,
+			<6699 6065 5539 5305 5232>,
+			<6697 6062 5540 5309 5236>,
+			<6691 6059 5541 5311 5240>,
+			<6688 6059 5542 5314 5243>,
+			<6691 6063 5546 5317 5244>,
+			<6695 6069 5550 5320 5245>,
+			<6693 6072 5553 5324 5247>,
+			<6677 6077 5556 5329 5251>,
+			<6667 6080 5558 5333 5255>,
+			<6679 6081 5563 5336 5258>,
+			<6697 6082 5568 5339 5261>,
+			<6698 6085 5570 5342 5263>,
+			<6684 6094 5571 5348 5265>,
+			<6675 6101 5572 5352 5268>,
+			<6691 6098 5581 5353 5271>,
+			<6707 6096 5586 5356 5275>,
+			<6704 6102 5586 5363 5282>,
+			<6708 6104 5593 5368 5284>,
+			<6725 6098 5595 5370 5288>,
+			<6724 6114 5601 5370 5288>,
+			<6743 6089 5598 5376 5290>,
+			<6750 6086 5605 5374 5291>,
+			<6722 6104 5609 5381 5293>,
+			<6738 6105 5608 5384 5292>,
+			<6759 6112 5624 5392 5304>,
+			<6766 6128 5643 5400 5313>,
+			<6779 6149 5656 5417 5324>,
+			<6779 6149 5656 5417 5324>,
+			<6779 6149 5656 5417 5324>;
+	};
+
+	qcom,pc-temp-y2-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <9643 10639 11070 11121 11086>,
+			<9643 10662 11056 11097 11058>,
+			<9643 10675 11037 11063 11029>,
+			<9871 10680 11014 11027 11001>,
+			<10190 10680 10988 10997 10976>,
+			<10325 10677 10959 10981 10958>,
+			<10308 10664 10918 10973 10946>,
+			<10282 10644 10881 10967 10935>,
+			<10301 10632 10875 10959 10916>,
+			<10440 10623 10874 10933 10882>,
+			<10534 10619 10874 10919 10864>,
+			<10489 10626 10869 10936 10874>,
+			<10417 10643 10861 10961 10888>,
+			<10413 10676 10856 10952 10885>,
+			<10487 10748 10851 10897 10860>,
+			<10553 10801 10851 10866 10840>,
+			<10580 10826 10885 10876 10837>,
+			<10597 10843 10946 10896 10845>,
+			<10521 10842 11018 10943 10884>,
+			<10042 10822 11115 11060 10984>,
+			<9696 10809 11159 11120 11034>,
+			<9682 10815 11129 11098 11013>,
+			<9676 10826 11091 11071 10987>,
+			<9675 10835 11085 11079 11009>,
+			<9676 10846 11088 11121 11106>,
+			<9676 10848 11093 11154 11162>,
+			<9675 10684 11108 11176 11166>,
+			<9671 10460 11130 11199 11168>,
+			<9668 10652 11152 11224 11182>,
+			<9665 11565 11178 11263 11214>,
+			<9662 12069 11192 11286 11238>,
+			<9660 11796 11199 11310 11257>,
+			<9659 11319 11203 11338 11277>,
+			<9657 10963 11202 11344 11307>,
+			<9656 10643 11198 11320 11345>,
+			<9655 10423 11189 11299 11359>,
+			<9654 10140 11148 11294 11325>,
+			<9653 9828 11108 11301 11280>,
+			<9653 9733 11099 11301 11271>,
+			<9653 9707 11096 11290 11278>,
+			<9652 9692 11071 11287 11277>,
+			<9652 9681 10975 11329 11250>,
+			<9652 9674 10939 11356 11231>,
+			<9652 9668 10913 11303 11229>,
+			<9652 9664 10802 11253 11135>,
+			<9652 9663 10839 11180 11044>,
+			<9652 9661 10832 11146 11009>,
+			<9652 9660 10811 11105 10962>,
+			<9651 9659 10794 11061 10965>,
+			<9651 9658 10764 11053 10938>,
+			<9651 9658 10711 10981 10871>,
+			<9651 9656 10651 10927 10829>,
+			<9651 9654 10594 10851 10747>,
+			<9651 9654 10531 10798 10659>,
+			<9651 9654 10531 10798 10659>,
+			<9651 9654 10531 10798 10659>;
+	};
+
+	qcom,pc-temp-y3-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <13677 13390 13309 13301 13279>,
+			<13657 13393 13309 13294 13279>,
+			<13634 13397 13311 13289 13279>,
+			<13612 13400 13312 13285 13279>,
+			<13596 13403 13314 13283 13279>,
+			<13590 13406 13315 13282 13279>,
+			<13594 13408 13315 13283 13280>,
+			<13600 13410 13316 13286 13281>,
+			<13594 13412 13317 13287 13282>,
+			<13548 13416 13319 13287 13282>,
+			<13515 13419 13321 13287 13282>,
+			<13513 13421 13322 13289 13282>,
+			<13512 13423 13323 13291 13282>,
+			<13509 13422 13325 13291 13283>,
+			<13504 13414 13328 13291 13284>,
+			<13497 13407 13329 13291 13286>,
+			<13488 13401 13328 13292 13287>,
+			<13478 13395 13325 13294 13288>,
+			<13470 13387 13324 13297 13290>,
+			<13465 13376 13323 13301 13294>,
+			<13458 13367 13322 13303 13296>,
+			<13428 13360 13315 13297 13290>,
+			<13384 13354 13306 13287 13281>,
+			<13362 13349 13303 13283 13278>,
+			<13349 13346 13300 13281 13277>,
+			<13344 13341 13299 13280 13277>,
+			<13351 13308 13299 13280 13277>,
+			<13369 13266 13299 13282 13277>,
+			<13391 13259 13298 13282 13277>,
+			<13422 13259 13299 13283 13277>,
+			<13460 13258 13299 13283 13277>,
+			<13503 13258 13298 13283 13277>,
+			<13554 13259 13298 13283 13277>,
+			<13615 13263 13298 13283 13277>,
+			<13690 13285 13299 13283 13278>,
+			<13777 13302 13299 13283 13278>,
+			<13879 13294 13296 13281 13277>,
+			<13996 13281 13292 13279 13276>,
+			<14118 13282 13292 13278 13276>,
+			<14247 13299 13292 13277 13277>,
+			<14377 13319 13293 13277 13277>,
+			<14502 13343 13295 13277 13278>,
+			<14624 13368 13298 13277 13278>,
+			<14737 13402 13303 13278 13276>,
+			<14824 13470 13304 13280 13278>,
+			<14801 13476 13307 13284 13280>,
+			<14824 13517 13316 13291 13286>,
+			<14890 13560 13319 13292 13287>,
+			<14961 13607 13332 13295 13287>,
+			<15021 13665 13332 13292 13286>,
+			<15095 13703 13333 13294 13286>,
+			<15215 13779 13341 13296 13289>,
+			<15382 13934 13350 13299 13292>,
+			<15571 14143 13370 13308 13299>,
+			<15571 14143 13370 13308 13299>,
+			<15571 14143 13370 13308 13299>;
+	};
+
+	qcom,pc-temp-y4-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <17305 16798 16610 16483 16470>,
+			<17330 16862 16610 16486 16469>,
+			<17378 16934 16609 16489 16468>,
+			<17433 17001 16608 16491 16467>,
+			<17479 17051 16607 16493 16467>,
+			<17501 17070 16605 16493 16466>,
+			<17503 17059 16603 16493 16466>,
+			<17504 17041 16601 16492 16466>,
+			<17511 17030 16599 16493 16466>,
+			<17550 17023 16599 16497 16470>,
+			<17608 17020 16599 16500 16473>,
+			<17742 17034 16602 16502 16478>,
+			<17902 17062 16609 16506 16483>,
+			<17876 17086 16619 16512 16487>,
+			<17547 17110 16638 16523 16492>,
+			<17320 17134 16659 16535 16498>,
+			<17344 17161 16679 16546 16506>,
+			<17386 17183 16703 16560 16518>,
+			<17370 17170 16748 16586 16537>,
+			<17216 17080 16821 16630 16569>,
+			<17060 16974 16852 16651 16585>,
+			<16974 16865 16754 16602 16552>,
+			<16908 16761 16616 16529 16502>,
+			<16873 16703 16567 16502 16483>,
+			<16851 16662 16543 16489 16473>,
+			<16841 16647 16535 16485 16469>,
+			<16841 16681 16535 16485 16470>,
+			<16842 16727 16535 16487 16471>,
+			<16843 16732 16537 16489 16474>,
+			<16844 16721 16543 16497 16482>,
+			<16845 16716 16549 16507 16491>,
+			<16852 16721 16554 16521 16504>,
+			<16866 16730 16558 16535 16515>,
+			<16879 16732 16556 16540 16518>,
+			<16893 16714 16549 16540 16515>,
+			<16906 16704 16540 16534 16509>,
+			<16920 16735 16528 16505 16492>,
+			<16932 16784 16517 16477 16475>,
+			<16941 16805 16517 16476 16471>,
+			<16947 16815 16522 16479 16469>,
+			<16950 16818 16530 16481 16469>,
+			<16948 16818 16544 16482 16469>,
+			<16945 16817 16555 16481 16467>,
+			<16947 16815 16561 16471 16454>,
+			<16965 16826 16575 16477 16456>,
+			<16961 16849 16584 16493 16477>,
+			<16977 16893 16606 16503 16495>,
+			<17046 16954 16635 16528 16531>,
+			<17107 17025 16679 16557 16532>,
+			<17131 17054 16682 16515 16493>,
+			<17101 17038 16673 16527 16498>,
+			<17060 17051 16712 16548 16514>,
+			<17063 17124 16764 16588 16554>,
+			<17135 17255 16879 16727 16719>,
+			<17135 17255 16879 16727 16719>,
+			<17135 17255 16879 16727 16719>;
+	};
+
+	qcom,pc-temp-y5-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <8712 14223 14774 19943 16308>,
+			<8888 14349 15148 18667 15835>,
+			<10562 14526 15365 17009 15457>,
+			<12204 14713 15466 15353 15176>,
+			<13579 14867 15489 14086 14997>,
+			<14452 14948 15472 13593 14920>,
+			<14948 14973 15335 13800 15003>,
+			<15270 14986 15151 14123 15144>,
+			<15028 14986 15098 14118 15087>,
+			<13370 14973 15056 13826 14716>,
+			<12246 14930 14978 13664 14315>,
+			<13353 14287 14743 13788 13961>,
+			<15163 13386 14398 13870 13634>,
+			<15495 13334 14078 13643 13482>,
+			<15197 13853 13740 13191 13549>,
+			<14993 14346 13497 12887 13638>,
+			<15443 14672 13207 12793 13546>,
+			<16191 15006 12923 12796 13423>,
+			<16138 15417 13004 13001 13548>,
+			<14708 15994 13654 13569 14033>,
+			<13284 16419 14434 14193 14440>,
+			<12599 16670 15491 14905 14826>,
+			<12068 16832 16433 15541 15160>,
+			<11544 16827 16644 15650 15196>,
+			<10962 16682 16591 15306 15346>,
+			<10655 16390 16622 15048 15474>,
+			<10648 14341 16597 15293 15494>,
+			<10645 11728 16540 15744 15472>,
+			<10665 11156 16578 15865 15229>,
+			<10802 11032 16695 15749 14663>,
+			<10946 10959 16756 15607 14352>,
+			<11017 10901 16831 15502 14290>,
+			<11076 10865 16959 15400 14311>,
+			<11177 11054 17363 15705 14665>,
+			<11367 12196 18097 16573 15740>,
+			<11520 13011 18310 16919 16424>,
+			<11584 12496 17269 16620 16376>,
+			<11627 11602 15914 16091 16215>,
+			<11630 11486 15213 15448 16327>,
+			<11595 11681 14700 14692 16543>,
+			<11570 11787 14330 14365 16550>,
+			<11579 11797 14105 14243 16259>,
+			<11596 11778 14219 14209 16346>,
+			<11509 11647 14611 15058 16893>,
+			<11331 11779 14198 14882 16382>,
+			<11388 11508 14156 14882 14589>,
+			<11488 11654 14603 16012 16142>,
+			<11493 11662 14001 15040 14960>,
+			<11613 11939 14918 15399 14828>,
+			<11747 12726 15439 17093 17327>,
+			<11665 12655 15981 17753 17255>,
+			<11585 12280 16288 17881 17960>,
+			<11459 12118 16141 17436 18200>,
+			<11818 11932 16090 17352 17825>,
+			<11818 11932 16090 17352 17825>,
+			<11818 11932 16090 17352 17825>;
+	};
+
+	qcom,pc-temp-y6-lut {
+		qcom,lut-col-legend = <0 10 25 40 50>;
+		qcom,lut-row-legend = <10000 9800 9600 9400 9200>,
+			<9000 8800 8600 8400 8200>,
+			<8000 7800 7600 7400 7200>,
+			<7000 6800 6600 6400 6200>,
+			<6000 5800 5600 5400 5200>,
+			<5000 4800 4600 4400 4200>,
+			<4000 3800 3600 3400 3200>,
+			<3000 2800 2600 2400 2200>,
+			<2000 1800 1600 1400 1200>,
+			<1000 900 800 700 600>,
+			<500 400 300 200 100>,
+			<0>;
+		qcom,lut-data = <6132 5538 5158 5055 5027>,
+			<6176 5550 5158 5053 5026>,
+			<6205 5557 5158 5050 5025>,
+			<6223 5561 5157 5048 5025>,
+			<6232 5562 5156 5046 5025>,
+			<6234 5562 5154 5046 5025>,
+			<6227 5555 5152 5046 5025>,
+			<6211 5540 5150 5047 5026>,
+			<6191 5531 5149 5047 5027>,
+			<6161 5522 5149 5048 5028>,
+			<6144 5519 5149 5049 5029>,
+			<6170 5520 5150 5051 5030>,
+			<6214 5522 5151 5053 5031>,
+			<6207 5523 5154 5055 5033>,
+			<6119 5523 5160 5058 5035>,
+			<6058 5522 5167 5061 5038>,
+			<6060 5524 5172 5065 5041>,
+			<6065 5527 5177 5070 5045>,
+			<6054 5521 5188 5079 5052>,
+			<5986 5487 5208 5095 5064>,
+			<5923 5449 5216 5102 5070>,
+			<5892 5413 5184 5083 5056>,
+			<5871 5381 5138 5056 5035>,
+			<5868 5365 5122 5045 5028>,
+			<5872 5355 5114 5040 5024>,
+			<5878 5349 5111 5038 5023>,
+			<5895 5343 5112 5039 5023>,
+			<5926 5339 5113 5040 5024>,
+			<5960 5339 5115 5042 5026>,
+			<5999 5342 5118 5045 5028>,
+			<6044 5346 5121 5048 5031>,
+			<6096 5354 5124 5053 5034>,
+			<6156 5367 5126 5057 5038>,
+			<6222 5383 5127 5059 5039>,
+			<6297 5405 5127 5060 5039>,
+			<6380 5430 5127 5058 5038>,
+			<6470 5458 5124 5049 5032>,
+			<6568 5491 5120 5041 5027>,
+			<6667 5530 5121 5040 5027>,
+			<6768 5579 5127 5041 5027>,
+			<6867 5632 5133 5042 5028>,
+			<6963 5689 5144 5044 5028>,
+			<7053 5751 5155 5044 5028>,
+			<7135 5817 5167 5043 5024>,
+			<7206 5905 5181 5046 5026>,
+			<7192 5921 5188 5056 5034>,
+			<7214 5976 5205 5063 5044>,
+			<7280 6034 5219 5072 5055>,
+			<7350 6096 5248 5083 5055>,
+			<7405 6155 5252 5069 5043>,
+			<7454 6196 5257 5074 5046>,
+			<7535 6282 5285 5084 5053>,
+			<7666 6442 5320 5100 5069>,
+			<7846 6646 5385 5148 5123>,
+			<7846 6646 5385 5148 5123>,
+			<7846 6646 5385 5148 5123>;
+	};
+
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-mtp.dts b/arch/arm64/boot/dts/qcom/sdm450-mtp.dts
index 040b4ba..5744390 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-mtp.dts
@@ -24,3 +24,21 @@
 	qcom,board-id = <8 0>;
 	qcom,pmic-id = <0x010016 0x010011 0x0 0x0>;
 };
+
+/{
+	mtp_batterydata: qcom,battery-data {
+		qcom,batt-id-range-pct = <15>;
+		#include "batterydata-itech-3000mah.dtsi"
+		#include "batterydata-ascent-3450mAh.dtsi"
+	};
+};
+
+&qpnp_fg {
+	qcom,battery-data = <&mtp_batterydata>;
+};
+
+&qpnp_smbcharger {
+	qcom,battery-data = <&mtp_batterydata>;
+	qcom,chg-led-sw-controls;
+	qcom,chg-led-support;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi b/arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi
index 413612d..423fab6 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi
@@ -26,3 +26,21 @@
 	qcom,ps-hold-hard-reset-disable;
 	qcom,ps-hold-shutdown-disable;
 };
+
+&usb3 {
+	extcon = <&pmi632_charger>;
+	vbus_dwc3-supply = <&smb5_vbus>;
+};
+
+/{
+	mtp_batterydata: qcom,battery-data {
+		qcom,batt-id-range-pct = <15>;
+		#include "qg-batterydata-ascent-3450mah.dtsi"
+		#include "qg-batterydata-mlp356477-2800mah.dtsi"
+	};
+};
+
+&pmi632_qg {
+	qcom,battery-data = <&mtp_batterydata>;
+	qcom,rbat-conn-mohm = <20>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts
index 700e950..eb6a692 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "sdm450.dtsi"
+#include "pmi8937.dtsi"
+#include "msm8953-pmi8937.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM450 + PMI8937 SOC";
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts
index f50d177..cfdd4e9 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "sdm450.dtsi"
+#include "pmi8940.dtsi"
+#include "msm8953-pmi8940.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM450 + PMI8940 SOC";
diff --git a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi
index 5226e74..9e2981a 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi
@@ -12,6 +12,7 @@
  */
 
 #include "msm8953-qrd.dtsi"
+#include "msm8953-mdss-panels.dtsi"
 
 &qusb_phy {
 	qcom,qusb-phy-init-seq = <0x78 0x80
@@ -31,3 +32,78 @@
 	status = "disabled";
 };
 
+&tlmm {
+	pmx_mdss {
+		mdss_dsi_active: mdss_dsi_active {
+			mux {
+				pins = "gpio61";
+			};
+			config {
+				pins = "gpio61";
+			};
+		};
+		mdss_dsi_suspend: mdss_dsi_suspend {
+			mux {
+				pins = "gpio61";
+			};
+			config {
+				pins = "gpio61";
+			};
+		};
+	};
+};
+
+&dsi_panel_pwr_supply {
+	qcom,panel-supply-entry@2 {
+		reg = <2>;
+		qcom,supply-name = "lab";
+		qcom,supply-min-voltage = <4600000>;
+		qcom,supply-max-voltage = <6000000>;
+		qcom,supply-enable-load = <100000>;
+		qcom,supply-disable-load = <100>;
+	};
+
+	qcom,panel-supply-entry@3 {
+		reg = <3>;
+		qcom,supply-name = "ibb";
+		qcom,supply-min-voltage = <4600000>;
+		qcom,supply-max-voltage = <6000000>;
+		qcom,supply-enable-load = <100000>;
+		qcom,supply-disable-load = <100>;
+		qcom,supply-post-on-sleep = <10>;
+	};
+};
+
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi {
+	hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+	lab-supply = <&lcdb_ldo_vreg>;
+	ibb-supply = <&lcdb_ncp_vreg>;
+	/delete-property/ vdd-supply;
+
+	qcom,dsi-pref-prim-pan = <&dsi_hx8399c_truly_vid>;
+	qcom,platform-bklight-en-gpio = <&pm8953_gpios 4 0>;
+	pinctrl-names = "mdss_default", "mdss_sleep";
+	pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+	pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+	qcom,platform-te-gpio = <&tlmm 24 0>;
+	qcom,platform-reset-gpio = <&tlmm 61 0>;
+};
+
+&mdss_dsi1 {
+	status = "disabled";
+};
+
+&dsi_hx8399c_truly_vid {
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";
+	qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>;
+	qcom,mdss-dsi-bl-pmic-bank-select = <0>;
+	qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>;
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450.dts b/arch/arm64/boot/dts/qcom/sdm450.dts
index b829b81..6cdf897 100644
--- a/arch/arm64/boot/dts/qcom/sdm450.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "sdm450.dtsi"
+#include "pmi8950.dtsi"
+#include "msm8953-pmi8950.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM450 + PMI8950 SOC";
diff --git a/arch/arm64/boot/dts/qcom/sdm632.dtsi b/arch/arm64/boot/dts/qcom/sdm632.dtsi
index 5100f28..80e6749 100644
--- a/arch/arm64/boot/dts/qcom/sdm632.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm632.dtsi
@@ -21,6 +21,10 @@
 	qcom,msm-name = "SDM632";
 };
 
+&clock_gcc_mdss {
+	compatible = "qcom,gcc-mdss-sdm632";
+};
+
 &clock_gcc {
 	compatible = "qcom,gcc-sdm632";
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm670-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm670-audio.dtsi
index faaf644..73c7be2 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-audio.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-audio.dtsi
@@ -19,10 +19,10 @@
 };
 
 &soc {
-	audio_load_mod {
-		compatible = "qcom,audio-load-mod";
-		audio_test_mod {
-			compatible = "qcom,audio-test-mod";
+	qcom,msm-audio-apr {
+		compatible = "qcom,msm-audio-apr";
+		msm_audio_apr_dummy {
+			compatible = "qcom,msm-audio-apr-dummy";
 		};
 	};
 
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi
index 5bf8df7..c54b8db 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -186,7 +186,8 @@
 		reg-names = "phys_addr_base", "offset_addr";
 	};
 
-	qcom,rpmh-master-stats {
-		compatible = "qcom,rpmh-master-stats";
+	qcom,rpmh-master-stats@b221200 {
+		compatible = "qcom,rpmh-master-stats-v1";
+		reg = <0xb221200 0x60>;
 	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
index a3f7b8e..48deca6 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
@@ -489,6 +489,29 @@
 		ibb-supply = <&lcdb_ncp_vreg>;
 	};
 
+	ext_dsi_bridge_display: qcom,dsi-display@17 {
+		compatible = "qcom,dsi-display";
+		label = "ext_dsi_bridge_display";
+		qcom,display-type = "primary";
+
+		qcom,dsi-ctrl = <&mdss_dsi0>;
+		qcom,dsi-phy = <&mdss_dsi_phy0>;
+		clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+		       <&mdss_dsi0_pll PCLK_MUX_0_CLK>;
+		clock-names = "src_byte_clk", "src_pixel_clk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				ext_dsi_out: endpoint {
+				};
+			};
+		};
+	};
+
 	sde_wb: qcom,wb-display@0 {
 		compatible = "qcom,wb-display";
 		cell-index = <0>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi
index f6fa948..9903d19 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -138,7 +138,8 @@
 			 0x254 /* QUSB2PHY_TEST1 */
 			 0x198 /* PLL_BIAS_CONTROL_2 */
 			 0x228 /* QUSB2PHY_SQ_CTRL1 */
-			 0x22c>; /* QUSB2PHY_SQ_CTRL2 */
+			 0x22c /* QUSB2PHY_SQ_CTRL2 */
+			 0x27c>; /* QUSB2PHY_DEBUG_CTRL1 */
 
 		qcom,qusb-phy-init-seq =
 			/* <value reg_offset> */
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi
index ee10cfc..929239a 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -140,7 +140,8 @@
 		reg-names = "phys_addr_base", "offset_addr";
 	};
 
-	qcom,rpmh-master-stats {
-		compatible = "qcom,rpmh-master-stats";
+	qcom,rpmh-master-stats@b221200 {
+		compatible = "qcom,rpmh-master-stats-v1";
+		reg = <0xb221200 0x60>;
 	};
 };
diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig
index 7d7cbcf..2b01389 100644
--- a/arch/arm64/configs/msm8953-perf_defconfig
+++ b/arch/arm64/configs/msm8953-perf_defconfig
@@ -324,8 +324,10 @@
 CONFIG_QPNP_FG=y
 CONFIG_SMB135X_CHARGER=y
 CONFIG_SMB1351_USB_CHARGER=y
+CONFIG_QPNP_SMB5=y
 CONFIG_QPNP_SMBCHARGER=y
 CONFIG_QPNP_TYPEC=y
+CONFIG_QPNP_QG=y
 CONFIG_MSM_APM=y
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_THERMAL=y
@@ -463,6 +465,7 @@
 CONFIG_USB_CONFIGFS_UEVENT=y
 CONFIG_USB_CONFIGFS_F_HID=y
 CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_CDEV=y
 CONFIG_USB_CONFIGFS_F_QDSS=y
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
@@ -536,6 +539,9 @@
 CONFIG_QTI_RPM_STATS_LOG=y
 CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
 CONFIG_MEM_SHARE_QMI_SERVICE=y
+CONFIG_WCNSS_CORE=y
+CONFIG_WCNSS_CORE_PRONTO=y
+CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y
 CONFIG_QCOM_DEVFREQ_DEVBW=y
 CONFIG_SPDM_SCM=y
 CONFIG_DEVFREQ_SPDM=y
diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig
index c9d7ee2..f95beaa 100644
--- a/arch/arm64/configs/msm8953_defconfig
+++ b/arch/arm64/configs/msm8953_defconfig
@@ -334,8 +334,10 @@
 CONFIG_QPNP_FG=y
 CONFIG_SMB135X_CHARGER=y
 CONFIG_SMB1351_USB_CHARGER=y
+CONFIG_QPNP_SMB5=y
 CONFIG_QPNP_SMBCHARGER=y
 CONFIG_QPNP_TYPEC=y
+CONFIG_QPNP_QG=y
 CONFIG_MSM_APM=y
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_THERMAL=y
@@ -474,6 +476,7 @@
 CONFIG_USB_CONFIGFS_UEVENT=y
 CONFIG_USB_CONFIGFS_F_HID=y
 CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_CDEV=y
 CONFIG_USB_CONFIGFS_F_QDSS=y
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
diff --git a/arch/arm64/configs/sdm670-perf_defconfig b/arch/arm64/configs/sdm670-perf_defconfig
index 8aa1e7d..83b0d66 100644
--- a/arch/arm64/configs/sdm670-perf_defconfig
+++ b/arch/arm64/configs/sdm670-perf_defconfig
@@ -440,7 +440,6 @@
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
 CONFIG_MMC_PARANOID_SD_INIT=y
-CONFIG_MMC_CLKGATE=y
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
 CONFIG_MMC_TEST=y
diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig
index 667377f..0e8ef8f 100644
--- a/arch/arm64/configs/sdm670_defconfig
+++ b/arch/arm64/configs/sdm670_defconfig
@@ -384,6 +384,7 @@
 CONFIG_DRM=y
 CONFIG_DRM_SDE_EVTLOG_DEBUG=y
 CONFIG_DRM_SDE_RSC=y
+CONFIG_DRM_LT_LT9611=y
 CONFIG_FB_VIRTUAL=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
@@ -446,7 +447,6 @@
 CONFIG_MMC_PERF_PROFILING=y
 CONFIG_MMC_RING_BUFFER=y
 CONFIG_MMC_PARANOID_SD_INIT=y
-CONFIG_MMC_CLKGATE=y
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
 CONFIG_MMC_TEST=y
@@ -524,6 +524,7 @@
 CONFIG_MSM_GLADIATOR_ERP=y
 CONFIG_QCOM_EUD=y
 CONFIG_QCOM_WATCHDOG_V2=y
+CONFIG_QCOM_WDOG_IPI_ENABLE=y
 CONFIG_QPNP_PBS=y
 CONFIG_QCOM_MEMORY_DUMP_V2=y
 CONFIG_QCOM_MINIDUMP=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index 01687f5..af1dd30 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -524,6 +524,7 @@
 CONFIG_MSM_GLADIATOR_HANG_DETECT=y
 CONFIG_QCOM_EUD=y
 CONFIG_QCOM_WATCHDOG_V2=y
+CONFIG_QCOM_WDOG_IPI_ENABLE=y
 CONFIG_QCOM_MEMORY_DUMP_V2=y
 CONFIG_QCOM_BUS_SCALING=y
 CONFIG_QCOM_BUS_CONFIG_RPMH=y
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index e5ca5ab..a6cabf7 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -2391,8 +2391,8 @@
 	if (err)
 		goto bail;
 	mutex_lock(&fl->fl_map_mutex);
-	if (!fastrpc_mmap_find(fl, ud->fd, ud->va, ud->len, 0, 0, &map)) {
-		pr_err("mapping not found to unamp %x va %llx %x\n",
+	if (fastrpc_mmap_find(fl, ud->fd, ud->va, ud->len, 0, 0, &map)) {
+		pr_err("adsprpc: mapping not found to unmap %d va %llx %x\n",
 			ud->fd, (unsigned long long)ud->va,
 			(unsigned int)ud->len);
 		err = -1;
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 23cf293..a469eb9 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -1163,18 +1163,31 @@
 	struct list_head *start, *temp;
 	struct diag_dci_client_tbl *entry = NULL;
 
-	length = *(uint16_t *)(buf + 1); /* total length of event series */
-	if (length == 0) {
-		pr_err("diag: Incoming dci event length is invalid\n");
+	if (!buf) {
+		pr_err("diag: In %s buffer is NULL\n", __func__);
 		return;
 	}
 	/*
-	 * Move directly to the start of the event series. 1 byte for
-	 * event code and 2 bytes for the length field.
+	 * 1 byte for event code and 2 bytes for the length field.
 	 * The length field indicates the total length removing the cmd_code
 	 * and the length field. The event parsing in that case should happen
 	 * till the end.
 	 */
+	if (len < 3) {
+		pr_err("diag: In %s invalid len: %d\n", __func__, len);
+		return;
+	}
+	length = *(uint16_t *)(buf + 1); /* total length of event series */
+	if ((length == 0) || (len != (length + 3))) {
+		pr_err("diag: Incoming dci event length: %d is invalid\n",
+			length);
+		return;
+	}
+	/*
+	 * Move directly to the start of the event series.
+	 * The event parsing should happen from start of event
+	 * series till the end.
+	 */
 	temp_len = 3;
 	while (temp_len < length) {
 		event_id_packet = *(uint16_t *)(buf + temp_len);
@@ -1191,30 +1204,60 @@
 			 * necessary.
 			 */
 			timestamp_len = 8;
-			memcpy(timestamp, buf + temp_len + 2, timestamp_len);
+			if ((temp_len + timestamp_len + 2) <= len)
+				memcpy(timestamp, buf + temp_len + 2,
+					timestamp_len);
+			else {
+				pr_err("diag: Invalid length in %s, len: %d, temp_len: %d",
+						__func__, len, temp_len);
+				return;
+			}
 		}
 		/* 13th and 14th bit represent the payload length */
 		if (((event_id_packet & 0x6000) >> 13) == 3) {
 			payload_len_field = 1;
-			payload_len = *(uint8_t *)
+			if ((temp_len + timestamp_len + 3) <= len) {
+				payload_len = *(uint8_t *)
 					(buf + temp_len + 2 + timestamp_len);
-			if (payload_len < (MAX_EVENT_SIZE - 13)) {
-				/* copy the payload length and the payload */
+			} else {
+				pr_err("diag: Invalid length in %s, len: %d, temp_len: %d",
+						__func__, len, temp_len);
+				return;
+			}
+			if ((payload_len < (MAX_EVENT_SIZE - 13)) &&
+			((temp_len + timestamp_len + payload_len + 3) <= len)) {
+				/*
+				 * Copy the payload length and the payload
+				 * after skipping temp_len bytes for already
+				 * parsed packet, timestamp_len for timestamp
+				 * buffer, 2 bytes for event_id_packet.
+				 */
 				memcpy(event_data + 12, buf + temp_len + 2 +
 							timestamp_len, 1);
 				memcpy(event_data + 13, buf + temp_len + 2 +
 					timestamp_len + 1, payload_len);
 			} else {
-				pr_err("diag: event > %d, payload_len = %d\n",
-					(MAX_EVENT_SIZE - 13), payload_len);
+				pr_err("diag: event > %d, payload_len = %d, temp_len = %d\n",
+				(MAX_EVENT_SIZE - 13), payload_len, temp_len);
 				return;
 			}
 		} else {
 			payload_len_field = 0;
 			payload_len = (event_id_packet & 0x6000) >> 13;
-			/* copy the payload */
-			memcpy(event_data + 12, buf + temp_len + 2 +
+			/*
+			 * Copy the payload after skipping temp_len bytes
+			 * for already parsed packet, timestamp_len for
+			 * timestamp buffer, 2 bytes for event_id_packet.
+			 */
+			if ((payload_len < (MAX_EVENT_SIZE - 12)) &&
+			((temp_len + timestamp_len + payload_len + 2) <= len))
+				memcpy(event_data + 12, buf + temp_len + 2 +
 						timestamp_len, payload_len);
+			else {
+				pr_err("diag: event > %d, payload_len = %d, temp_len = %d\n",
+				(MAX_EVENT_SIZE - 12), payload_len, temp_len);
+				return;
+			}
 		}
 
 		/* Before copying the data to userspace, check if we are still
@@ -1340,19 +1383,19 @@
 		pr_err("diag: In %s buffer is NULL\n", __func__);
 		return;
 	}
-
-	/* The first six bytes for the incoming log packet contains
-	 * Command code (2), the length of the packet (2) and the length
-	 * of the log (2)
+	/*
+	 * The first eight bytes for the incoming log packet contains
+	 * Command code (2), the length of the packet (2), the length
+	 * of the log (2) and log code (2)
 	 */
-	log_code = *(uint16_t *)(buf + 6);
-	read_bytes += sizeof(uint16_t) + 6;
-	if (read_bytes > len) {
-		pr_err("diag: Invalid length in %s, len: %d, read: %d",
-						__func__, len, read_bytes);
+	if (len < 8) {
+		pr_err("diag: In %s invalid len: %d\n", __func__, len);
 		return;
 	}
 
+	log_code = *(uint16_t *)(buf + 6);
+	read_bytes += sizeof(uint16_t) + 6;
+
 	/* parse through log mask table of each client and check mask */
 	mutex_lock(&driver->dci_mutex);
 	list_for_each_safe(start, temp, &driver->dci_client_list) {
@@ -1379,6 +1422,10 @@
 		pr_err("diag: In %s buffer is NULL\n", __func__);
 		return;
 	}
+	if (len < (EXT_HDR_LEN + sizeof(uint8_t))) {
+		pr_err("diag: In %s invalid len: %d\n", __func__, len);
+		return;
+	}
 
 	version = *(uint8_t *)buf + 1;
 	if (version < EXT_HDR_VERSION)  {
@@ -1390,10 +1437,6 @@
 	pkt = buf + EXT_HDR_LEN;
 	pkt_cmd_code = *(uint8_t *)pkt;
 	len -= EXT_HDR_LEN;
-	if (len < 0) {
-		pr_err("diag: %s, Invalid length len: %d\n", __func__, len);
-		return;
-	}
 
 	switch (pkt_cmd_code) {
 	case LOG_CMD_CODE:
diff --git a/drivers/clk/msm/Makefile b/drivers/clk/msm/Makefile
index d264e79..74c8055 100644
--- a/drivers/clk/msm/Makefile
+++ b/drivers/clk/msm/Makefile
@@ -16,6 +16,9 @@
 obj-$(CONFIG_ARCH_MSM8953)	+= clock-gcc-8953.o
 obj-$(CONFIG_ARCH_MSM8953)	+= clock-cpu-8953.o
 obj-$(CONFIG_ARCH_MSM8953)	+= clock-rcgwr.o
+obj-$(CONFIG_ARCH_MSM8937)	+= clock-gcc-8952.o
+obj-$(CONFIG_ARCH_MSM8937)	+= clock-cpu-8939.o
+obj-$(CONFIG_ARCH_MSM8937)	+= clock-rcgwr.o
 endif
 
 obj-y               += mdss/
diff --git a/drivers/clk/msm/clock-cpu-8939.c b/drivers/clk/msm/clock-cpu-8939.c
new file mode 100644
index 0000000..68ea9a1
--- /dev/null
+++ b/drivers/clk/msm/clock-cpu-8939.c
@@ -0,0 +1,992 @@
+/*
+ * Copyright (c) 2014-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/pm_qos.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of.h>
+#include <linux/clk/msm-clock-generic.h>
+#include <linux/suspend.h>
+#include <linux/of_platform.h>
+#include <linux/pm_opp.h>
+#include <soc/qcom/clock-local2.h>
+#include <soc/qcom/pm.h>
+
+#include "clock.h"
+#include <dt-bindings/clock/msm-cpu-clocks-8939.h>
+
+DEFINE_VDD_REGS_INIT(vdd_cpu_bc, 1);
+DEFINE_VDD_REGS_INIT(vdd_cpu_lc, 1);
+DEFINE_VDD_REGS_INIT(vdd_cpu_cci, 1);
+
+enum {
+	A53SS_MUX_BC,
+	A53SS_MUX_LC,
+	A53SS_MUX_CCI,
+	A53SS_MUX_NUM,
+};
+
+static const char * const mux_names[] = { "c1", "c0", "cci"};
+
+struct cpu_clk_8939 {
+	u32 cpu_reg_mask;
+	cpumask_t cpumask;
+	bool hw_low_power_ctrl;
+	struct pm_qos_request req;
+	struct clk c;
+	struct latency_level latency_lvl;
+	s32 cpu_latency_no_l2_pc_us;
+};
+
+static struct mux_div_clk a53ssmux_bc = {
+	.ops = &rcg_mux_div_ops,
+	.safe_freq = 400000000,
+	.data = {
+		.max_div = 32,
+		.min_div = 2,
+		.is_half_divider = true,
+	},
+	.c = {
+		.dbg_name = "a53ssmux_bc",
+		.ops = &clk_ops_mux_div_clk,
+		CLK_INIT(a53ssmux_bc.c),
+	},
+	.parents = (struct clk_src[8]) {},
+	.div_mask = BM(4, 0),
+	.src_mask = BM(10, 8) >> 8,
+	.src_shift = 8,
+};
+
+static struct mux_div_clk a53ssmux_lc = {
+	.ops = &rcg_mux_div_ops,
+	.safe_freq = 200000000,
+	.data = {
+		.max_div = 32,
+		.min_div = 2,
+		.is_half_divider = true,
+	},
+	.c = {
+		.dbg_name = "a53ssmux_lc",
+		.ops = &clk_ops_mux_div_clk,
+		CLK_INIT(a53ssmux_lc.c),
+	},
+	.parents = (struct clk_src[8]) {},
+	.div_mask = BM(4, 0),
+	.src_mask = BM(10, 8) >> 8,
+	.src_shift = 8,
+};
+
+static struct mux_div_clk a53ssmux_cci = {
+	.ops = &rcg_mux_div_ops,
+	.safe_freq = 200000000,
+	.data = {
+		.max_div = 32,
+		.min_div = 2,
+		.is_half_divider = true,
+	},
+	.c = {
+		.dbg_name = "a53ssmux_cci",
+		.ops = &clk_ops_mux_div_clk,
+		CLK_INIT(a53ssmux_cci.c),
+	},
+	.parents = (struct clk_src[8]) {},
+	.div_mask = BM(4, 0),
+	.src_mask = BM(10, 8) >> 8,
+	.src_shift = 8,
+};
+
+static void do_nothing(void *unused) { }
+
+static inline struct cpu_clk_8939 *to_cpu_clk_8939(struct clk *c)
+{
+	return container_of(c, struct cpu_clk_8939, c);
+}
+
+static enum handoff cpu_clk_8939_handoff(struct clk *c)
+{
+	c->rate = clk_get_rate(c->parent);
+	return HANDOFF_DISABLED_CLK;
+}
+
+static long cpu_clk_8939_round_rate(struct clk *c, unsigned long rate)
+{
+	return clk_round_rate(c->parent, rate);
+}
+
+static int cpu_clk_8939_set_rate(struct clk *c, unsigned long rate)
+{
+	int ret = 0;
+	struct cpu_clk_8939 *cpuclk = to_cpu_clk_8939(c);
+	bool hw_low_power_ctrl = cpuclk->hw_low_power_ctrl;
+
+	if (hw_low_power_ctrl) {
+		memset(&cpuclk->req, 0, sizeof(cpuclk->req));
+		cpumask_copy(&cpuclk->req.cpus_affine,
+				(const struct cpumask *)&cpuclk->cpumask);
+		cpuclk->req.type = PM_QOS_REQ_AFFINE_CORES;
+		pm_qos_add_request(&cpuclk->req, PM_QOS_CPU_DMA_LATENCY,
+				cpuclk->cpu_latency_no_l2_pc_us - 1);
+		smp_call_function_any(&cpuclk->cpumask, do_nothing,
+				NULL, 1);
+	}
+
+	ret = clk_set_rate(c->parent, rate);
+
+	if (hw_low_power_ctrl)
+		pm_qos_remove_request(&cpuclk->req);
+
+	return ret;
+}
+
+static struct clk_ops clk_ops_cpu = {
+	.set_rate = cpu_clk_8939_set_rate,
+	.round_rate = cpu_clk_8939_round_rate,
+	.handoff = cpu_clk_8939_handoff,
+};
+
+static struct cpu_clk_8939 a53_bc_clk = {
+	.cpu_reg_mask = 0x3,
+	.latency_lvl = {
+		.affinity_level = LPM_AFF_LVL_L2,
+		.reset_level = LPM_RESET_LVL_GDHS,
+		.level_name = "perf",
+	},
+	.cpu_latency_no_l2_pc_us = 300,
+	.c = {
+		.parent = &a53ssmux_bc.c,
+		.ops = &clk_ops_cpu,
+		.vdd_class = &vdd_cpu_bc,
+		.dbg_name = "a53_bc_clk",
+		CLK_INIT(a53_bc_clk.c),
+	},
+};
+
+static struct cpu_clk_8939 a53_lc_clk = {
+	.cpu_reg_mask = 0x103,
+	.latency_lvl = {
+		.affinity_level = LPM_AFF_LVL_L2,
+		.reset_level = LPM_RESET_LVL_GDHS,
+		.level_name = "pwr",
+	},
+	.cpu_latency_no_l2_pc_us = 300,
+	.c = {
+		.parent = &a53ssmux_lc.c,
+		.ops = &clk_ops_cpu,
+		.vdd_class = &vdd_cpu_lc,
+		.dbg_name = "a53_lc_clk",
+		CLK_INIT(a53_lc_clk.c),
+	},
+};
+
+static struct cpu_clk_8939 cci_clk = {
+	.c = {
+		.parent = &a53ssmux_cci.c,
+		.ops = &clk_ops_cpu,
+		.vdd_class = &vdd_cpu_cci,
+		.dbg_name = "cci_clk",
+		CLK_INIT(cci_clk.c),
+	},
+};
+
+static struct clk_lookup cpu_clocks_8939[] = {
+	CLK_LIST(a53ssmux_lc),
+	CLK_LIST(a53ssmux_bc),
+	CLK_LIST(a53ssmux_cci),
+	CLK_LIST(a53_bc_clk),
+	CLK_LIST(a53_lc_clk),
+	CLK_LIST(cci_clk),
+};
+
+static struct clk_lookup cpu_clocks_8939_single_cluster[] = {
+	CLK_LIST(a53ssmux_bc),
+	CLK_LIST(a53_bc_clk),
+};
+
+
+static struct mux_div_clk *a53ssmux[] = {&a53ssmux_bc,
+						&a53ssmux_lc, &a53ssmux_cci};
+
+static struct cpu_clk_8939 *cpuclk[] = { &a53_bc_clk, &a53_lc_clk, &cci_clk};
+
+static struct clk *logical_cpu_to_clk(int cpu)
+{
+	struct device_node *cpu_node = of_get_cpu_node(cpu, NULL);
+	u32 reg;
+
+	/* CPU 0/1/2/3 --> a53_bc_clk and mask = 0x103
+	 * CPU 4/5/6/7 --> a53_lc_clk and mask = 0x3
+	 */
+	if (cpu_node && !of_property_read_u32(cpu_node, "reg", &reg)) {
+		if ((reg | a53_bc_clk.cpu_reg_mask) == a53_bc_clk.cpu_reg_mask)
+			return &a53_lc_clk.c;
+		if ((reg | a53_lc_clk.cpu_reg_mask) == a53_lc_clk.cpu_reg_mask)
+			return &a53_bc_clk.c;
+	}
+
+	return NULL;
+}
+
+static int of_get_fmax_vdd_class(struct platform_device *pdev, struct clk *c,
+								char *prop_name)
+{
+	struct device_node *of = pdev->dev.of_node;
+	int prop_len, i;
+	struct clk_vdd_class *vdd = c->vdd_class;
+	u32 *array;
+
+	if (!of_find_property(of, prop_name, &prop_len)) {
+		dev_err(&pdev->dev, "missing %s\n", prop_name);
+		return -EINVAL;
+	}
+
+	prop_len /= sizeof(u32);
+	if (prop_len % 2) {
+		dev_err(&pdev->dev, "bad length %d\n", prop_len);
+		return -EINVAL;
+	}
+
+	prop_len /= 2;
+	vdd->level_votes = devm_kzalloc(&pdev->dev,
+				prop_len * sizeof(*vdd->level_votes),
+					GFP_KERNEL);
+	if (!vdd->level_votes)
+		return -ENOMEM;
+
+	vdd->vdd_uv = devm_kzalloc(&pdev->dev, prop_len * sizeof(int),
+					GFP_KERNEL);
+	if (!vdd->vdd_uv)
+		return -ENOMEM;
+
+	c->fmax = devm_kzalloc(&pdev->dev, prop_len * sizeof(unsigned long),
+					GFP_KERNEL);
+	if (!c->fmax)
+		return -ENOMEM;
+
+	array = devm_kzalloc(&pdev->dev,
+			prop_len * sizeof(u32) * 2, GFP_KERNEL);
+	if (!array)
+		return -ENOMEM;
+
+	of_property_read_u32_array(of, prop_name, array, prop_len * 2);
+	for (i = 0; i < prop_len; i++) {
+		c->fmax[i] = array[2 * i];
+		vdd->vdd_uv[i] = array[2 * i + 1];
+	}
+
+	devm_kfree(&pdev->dev, array);
+	vdd->num_levels = prop_len;
+	vdd->cur_level = prop_len;
+	vdd->use_max_uV = true;
+	c->num_fmax = prop_len;
+	return 0;
+}
+
+static void get_speed_bin(struct platform_device *pdev, int *bin,
+								int *version)
+{
+	struct resource *res;
+	void __iomem *base, *base1, *base2;
+	u32 pte_efuse, pte_efuse1, pte_efuse2;
+
+	*bin = 0;
+	*version = 0;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse");
+	if (!res) {
+		dev_info(&pdev->dev,
+			 "No speed/PVS binning available. Defaulting to 0!\n");
+		return;
+	}
+
+	base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!base) {
+		dev_warn(&pdev->dev,
+			 "Unable to read efuse data. Defaulting to 0!\n");
+		return;
+	}
+
+	pte_efuse = readl_relaxed(base);
+	devm_iounmap(&pdev->dev, base);
+
+	*bin = (pte_efuse >> 2) & 0x7;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse1");
+	if (!res) {
+		dev_info(&pdev->dev,
+			 "No PVS version available. Defaulting to 0!\n");
+		goto out;
+	}
+
+	base1 = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!base1) {
+		dev_warn(&pdev->dev,
+			 "Unable to read efuse1 data. Defaulting to 0!\n");
+		goto out;
+	}
+
+	pte_efuse1 = readl_relaxed(base1);
+	devm_iounmap(&pdev->dev, base1);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse2");
+	if (!res) {
+		dev_info(&pdev->dev,
+			 "No PVS version available. Defaulting to 0!\n");
+		goto out;
+	}
+
+	base2 = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!base2) {
+		dev_warn(&pdev->dev,
+			 "Unable to read efuse2 data. Defaulting to 0!\n");
+		goto out;
+	}
+
+	pte_efuse2 = readl_relaxed(base2);
+	devm_iounmap(&pdev->dev, base2);
+
+	*version = ((pte_efuse1 >> 29 & 0x1) | ((pte_efuse2 >> 18 & 0x3) << 1));
+
+out:
+	dev_info(&pdev->dev, "Speed bin: %d PVS Version: %d\n", *bin,
+								*version);
+}
+
+static int of_get_clk_src(struct platform_device *pdev,
+				struct clk_src *parents, int mux_id)
+{
+	struct device_node *of = pdev->dev.of_node;
+	int mux_parents, i, j, index;
+	struct clk *c;
+	char clk_name[] = "clk-xxx-x";
+
+	mux_parents = of_property_count_strings(of, "clock-names");
+	if (mux_parents <= 0) {
+		dev_err(&pdev->dev, "missing clock-names\n");
+		return -EINVAL;
+	}
+	j = 0;
+
+	for (i = 0; i < 8; i++) {
+		snprintf(clk_name, ARRAY_SIZE(clk_name), "clk-%s-%d",
+							mux_names[mux_id], i);
+		index = of_property_match_string(of, "clock-names", clk_name);
+		if (index < 0)
+			continue;
+
+		parents[j].sel = i;
+		parents[j].src = c = devm_clk_get(&pdev->dev, clk_name);
+		if (IS_ERR(c)) {
+			if (c != ERR_PTR(-EPROBE_DEFER))
+				dev_err(&pdev->dev, "clk_get: %s\n fail",
+						clk_name);
+			return PTR_ERR(c);
+		}
+		j++;
+	}
+
+	return j;
+}
+
+static int cpu_parse_devicetree(struct platform_device *pdev, int mux_id)
+{
+	struct resource *res;
+	int rc;
+	char rcg_name[] = "apcs-xxx-rcg-base";
+	char vdd_name[] = "vdd-xxx";
+	struct regulator *regulator;
+
+	snprintf(rcg_name, ARRAY_SIZE(rcg_name), "apcs-%s-rcg-base",
+						mux_names[mux_id]);
+	res = platform_get_resource_byname(pdev,
+					IORESOURCE_MEM, rcg_name);
+	if (!res) {
+		dev_err(&pdev->dev, "missing %s\n", rcg_name);
+		return -EINVAL;
+	}
+	a53ssmux[mux_id]->base = devm_ioremap(&pdev->dev, res->start,
+							resource_size(res));
+	if (!a53ssmux[mux_id]->base) {
+		dev_err(&pdev->dev, "ioremap failed for %s\n", rcg_name);
+		return -ENOMEM;
+	}
+
+	snprintf(vdd_name, ARRAY_SIZE(vdd_name), "vdd-%s", mux_names[mux_id]);
+	regulator = devm_regulator_get(&pdev->dev, vdd_name);
+	if (IS_ERR(regulator)) {
+		if (PTR_ERR(regulator) != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "unable to get regulator\n");
+		return PTR_ERR(regulator);
+	}
+	cpuclk[mux_id]->c.vdd_class->regulator[0] = regulator;
+
+	rc = of_get_clk_src(pdev, a53ssmux[mux_id]->parents, mux_id);
+	if (rc < 0)
+		return rc;
+
+	a53ssmux[mux_id]->num_parents = rc;
+
+	return 0;
+}
+
+static long corner_to_voltage(unsigned long corner, struct device *dev)
+{
+	struct dev_pm_opp *oppl;
+	long uv;
+
+	rcu_read_lock();
+	oppl = dev_pm_opp_find_freq_exact(dev, corner, true);
+	rcu_read_unlock();
+	if (IS_ERR_OR_NULL(oppl))
+		return -EINVAL;
+
+	rcu_read_lock();
+	uv = dev_pm_opp_get_voltage(oppl);
+	rcu_read_unlock();
+
+	return uv;
+}
+
+
+static int add_opp(struct clk *c, struct device *cpudev, struct device *vregdev,
+			unsigned long max_rate)
+{
+	unsigned long rate = 0;
+	int level;
+	long ret, uv, corner;
+	bool use_voltages = false;
+	struct dev_pm_opp *oppl;
+	int j = 1;
+
+	rcu_read_lock();
+	/* Check if the regulator driver has already populated OPP tables */
+	oppl = dev_pm_opp_find_freq_exact(vregdev, 2, true);
+	rcu_read_unlock();
+	if (!IS_ERR_OR_NULL(oppl))
+		use_voltages = true;
+
+	while (1) {
+		rate = c->fmax[j++];
+		level = find_vdd_level(c, rate);
+		if (level <= 0) {
+			pr_warn("clock-cpu: no uv for %lu.\n", rate);
+			return -EINVAL;
+		}
+		uv = corner = c->vdd_class->vdd_uv[level];
+		/*
+		 * If corner to voltage mapping is available, populate the OPP
+		 * table with the voltages rather than corners.
+		 */
+		if (use_voltages) {
+			uv = corner_to_voltage(corner, vregdev);
+			if (uv < 0) {
+				pr_warn("clock-cpu: no uv for corner %lu\n",
+					 corner);
+				return uv;
+			}
+			ret = dev_pm_opp_add(cpudev, rate, uv);
+			if (ret) {
+				pr_warn("clock-cpu: couldn't add OPP for %lu\n",
+					 rate);
+				return ret;
+			}
+
+		} else {
+			/*
+			 * Populate both CPU and regulator devices with the
+			 * freq-to-corner OPP table to maintain backward
+			 * compatibility.
+			 */
+			ret = dev_pm_opp_add(cpudev, rate, corner);
+			if (ret) {
+				pr_warn("clock-cpu: couldn't add OPP for %lu\n",
+					rate);
+				return ret;
+			}
+			ret = dev_pm_opp_add(vregdev, rate, corner);
+			if (ret) {
+				pr_warn("clock-cpu: couldn't add OPP for %lu\n",
+					rate);
+				return ret;
+			}
+		}
+		if (rate >= max_rate)
+			break;
+	}
+
+	return 0;
+}
+
+static void print_opp_table(int a53_c0_cpu, int a53_c1_cpu, bool single_cluster)
+{
+	struct dev_pm_opp *oppfmax, *oppfmin;
+	unsigned long apc0_fmax, apc1_fmax, apc0_fmin, apc1_fmin;
+
+	if (!single_cluster) {
+		apc0_fmax = a53_lc_clk.c.fmax[a53_lc_clk.c.num_fmax - 1];
+		apc0_fmin = a53_lc_clk.c.fmax[1];
+	}
+	apc1_fmax = a53_bc_clk.c.fmax[a53_bc_clk.c.num_fmax - 1];
+	apc1_fmin = a53_bc_clk.c.fmax[1];
+
+	rcu_read_lock();
+	if (!single_cluster) {
+		oppfmax = dev_pm_opp_find_freq_exact(get_cpu_device(a53_c0_cpu),
+						apc0_fmax, true);
+		oppfmin = dev_pm_opp_find_freq_exact(get_cpu_device(a53_c0_cpu),
+						apc0_fmin, true);
+		/*
+		 * One time information during boot. Important to know that this
+		 * looks sane since it can eventually make its way to the
+		 * scheduler.
+		 */
+		pr_info("clock_cpu: a53_c0: OPP voltage for %lu: %ld\n",
+			apc0_fmin, dev_pm_opp_get_voltage(oppfmin));
+		pr_info("clock_cpu: a53_c0: OPP voltage for %lu: %ld\n",
+			apc0_fmax, dev_pm_opp_get_voltage(oppfmax));
+	}
+	oppfmax = dev_pm_opp_find_freq_exact(get_cpu_device(a53_c1_cpu),
+						apc1_fmax, true);
+	oppfmin = dev_pm_opp_find_freq_exact(get_cpu_device(a53_c1_cpu),
+						apc1_fmin, true);
+	pr_info("clock_cpu: a53_c1: OPP voltage for %lu: %lu\n", apc1_fmin,
+		dev_pm_opp_get_voltage(oppfmin));
+	pr_info("clock_cpu: a53_c1: OPP voltage for %lu: %lu\n", apc1_fmax,
+		dev_pm_opp_get_voltage(oppfmax));
+	rcu_read_unlock();
+}
+
+static void populate_opp_table(struct platform_device *pdev,
+					bool single_cluster)
+{
+	struct platform_device *apc0_dev = 0, *apc1_dev;
+	struct device_node *apc0_node = NULL, *apc1_node;
+	unsigned long apc0_fmax = 0, apc1_fmax = 0;
+	int cpu, a53_c0_cpu = 0, a53_c1_cpu = 0;
+
+	if (!single_cluster)
+		apc0_node = of_parse_phandle(pdev->dev.of_node,
+						"vdd-c0-supply", 0);
+	apc1_node = of_parse_phandle(pdev->dev.of_node, "vdd-c1-supply", 0);
+	if (!apc0_node && !single_cluster) {
+		pr_err("can't find the apc0 dt node.\n");
+		return;
+	}
+	if (!apc1_node) {
+		pr_err("can't find the apc1 dt node.\n");
+		return;
+	}
+	if (!single_cluster)
+		apc0_dev = of_find_device_by_node(apc0_node);
+
+	apc1_dev = of_find_device_by_node(apc1_node);
+	if (!apc1_dev && !single_cluster) {
+		pr_err("can't find the apc0 device node.\n");
+		return;
+	}
+	if (!apc1_dev) {
+		pr_err("can't find the apc1 device node.\n");
+		return;
+	}
+
+	if (!single_cluster)
+		apc0_fmax = a53_lc_clk.c.fmax[a53_lc_clk.c.num_fmax - 1];
+
+	apc1_fmax = a53_bc_clk.c.fmax[a53_bc_clk.c.num_fmax - 1];
+
+	for_each_possible_cpu(cpu) {
+		pr_debug("the CPU number is : %d\n", cpu);
+		if (cpu/4 == 0) {
+			a53_c1_cpu = cpu;
+			WARN(add_opp(&a53_bc_clk.c, get_cpu_device(cpu),
+				     &apc1_dev->dev, apc1_fmax),
+				     "Failed to add OPP levels for A53 big cluster\n");
+		} else if (cpu/4 == 1 && !single_cluster) {
+			a53_c0_cpu = cpu;
+			WARN(add_opp(&a53_lc_clk.c, get_cpu_device(cpu),
+				     &apc0_dev->dev, apc0_fmax),
+				     "Failed to add OPP levels for A53 little cluster\n");
+		}
+	}
+
+	/* One time print during bootup */
+	pr_info("clock-cpu-8939: OPP tables populated (cpu %d and %d)",
+		a53_c0_cpu, a53_c1_cpu);
+
+	print_opp_table(a53_c0_cpu, a53_c1_cpu, single_cluster);
+
+}
+
+static void config_pll(int mux_id)
+{
+	unsigned long rate, aux_rate;
+	struct clk *aux_clk, *main_pll;
+
+	aux_clk = a53ssmux[mux_id]->parents[0].src;
+	main_pll = a53ssmux[mux_id]->parents[1].src;
+
+	aux_rate = clk_get_rate(aux_clk);
+	rate = clk_get_rate(&a53ssmux[mux_id]->c);
+	clk_set_rate(&a53ssmux[mux_id]->c, aux_rate);
+	clk_set_rate(main_pll, clk_round_rate(main_pll, 1));
+	clk_set_rate(&a53ssmux[mux_id]->c, rate);
+
+}
+
+static int clock_8939_pm_event(struct notifier_block *this,
+				unsigned long event, void *ptr)
+{
+	switch (event) {
+	case PM_POST_HIBERNATION:
+	case PM_POST_SUSPEND:
+		clk_unprepare(&a53_lc_clk.c);
+		clk_unprepare(&a53_bc_clk.c);
+		clk_unprepare(&cci_clk.c);
+		break;
+	case PM_HIBERNATION_PREPARE:
+	case PM_SUSPEND_PREPARE:
+		clk_prepare(&a53_lc_clk.c);
+		clk_prepare(&a53_bc_clk.c);
+		clk_prepare(&cci_clk.c);
+		break;
+	default:
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static int clock_8939_pm_event_single_cluster(struct notifier_block *this,
+						unsigned long event, void *ptr)
+{
+	switch (event) {
+	case PM_POST_HIBERNATION:
+	case PM_POST_SUSPEND:
+		clk_unprepare(&a53_bc_clk.c);
+		break;
+	case PM_HIBERNATION_PREPARE:
+	case PM_SUSPEND_PREPARE:
+		clk_prepare(&a53_bc_clk.c);
+		break;
+	default:
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block clock_8939_pm_notifier = {
+	.notifier_call = clock_8939_pm_event,
+};
+
+static struct notifier_block clock_8939_pm_notifier_single_cluster = {
+	.notifier_call = clock_8939_pm_event_single_cluster,
+};
+
+/**
+ * clock_panic_callback() - panic notification callback function.
+ *		This function is invoked when a kernel panic occurs.
+ * @nfb:	Notifier block pointer
+ * @event:	Value passed unmodified to notifier function
+ * @data:	Pointer passed unmodified to notifier function
+ *
+ * Return: NOTIFY_OK
+ */
+static int clock_panic_callback(struct notifier_block *nfb,
+					unsigned long event, void *data)
+{
+	bool single_cluster = 0;
+	unsigned long rate;
+	struct device_node *ofnode = of_find_compatible_node(NULL, NULL,
+							"qcom,cpu-clock-8939");
+	if (!ofnode)
+		ofnode = of_find_compatible_node(NULL, NULL,
+						"qcom,cpu-clock-8917");
+	if (ofnode)
+		single_cluster = of_property_read_bool(ofnode,
+							"qcom,num-cluster");
+
+	rate  = (a53_bc_clk.c.count) ? a53_bc_clk.c.rate : 0;
+	pr_err("%s frequency: %10lu Hz\n", a53_bc_clk.c.dbg_name, rate);
+
+	if (!single_cluster) {
+		rate  = (a53_lc_clk.c.count) ? a53_lc_clk.c.rate : 0;
+		pr_err("%s frequency: %10lu Hz\n", a53_lc_clk.c.dbg_name, rate);
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block clock_panic_notifier = {
+	.notifier_call = clock_panic_callback,
+	.priority = 1,
+};
+
+static int clock_a53_probe(struct platform_device *pdev)
+{
+	int speed_bin, version, rc, cpu, mux_id, rate;
+	char prop_name[] = "qcom,speedX-bin-vX-XXX";
+	int mux_num;
+	bool single_cluster;
+
+	single_cluster = of_property_read_bool(pdev->dev.of_node,
+						"qcom,num-cluster");
+
+	get_speed_bin(pdev, &speed_bin, &version);
+
+	mux_num = single_cluster ? A53SS_MUX_LC:A53SS_MUX_NUM;
+
+	for (mux_id = 0; mux_id < mux_num; mux_id++) {
+		rc = cpu_parse_devicetree(pdev, mux_id);
+		if (rc)
+			return rc;
+
+		snprintf(prop_name, ARRAY_SIZE(prop_name),
+					"qcom,speed%d-bin-v%d-%s",
+					speed_bin, version, mux_names[mux_id]);
+
+		rc = of_get_fmax_vdd_class(pdev, &cpuclk[mux_id]->c,
+								prop_name);
+		if (rc) {
+			/* Fall back to most conservative PVS table */
+			dev_err(&pdev->dev, "Unable to load voltage plan %s!\n",
+								prop_name);
+
+			snprintf(prop_name, ARRAY_SIZE(prop_name),
+				"qcom,speed0-bin-v0-%s", mux_names[mux_id]);
+			rc = of_get_fmax_vdd_class(pdev, &cpuclk[mux_id]->c,
+								prop_name);
+			if (rc) {
+				dev_err(&pdev->dev,
+					"Unable to load safe voltage plan\n");
+				return rc;
+			}
+			dev_info(&pdev->dev, "Safe voltage plan loaded.\n");
+		}
+	}
+	if (single_cluster)
+		rc = of_msm_clock_register(pdev->dev.of_node,
+				cpu_clocks_8939_single_cluster,
+				ARRAY_SIZE(cpu_clocks_8939_single_cluster));
+	else
+		rc = of_msm_clock_register(pdev->dev.of_node,
+				cpu_clocks_8939, ARRAY_SIZE(cpu_clocks_8939));
+
+	if (rc) {
+		dev_err(&pdev->dev, "msm_clock_register failed\n");
+		return rc;
+	}
+
+	if (!single_cluster) {
+		rate = clk_get_rate(&cci_clk.c);
+		clk_set_rate(&cci_clk.c, rate);
+	}
+
+	for (mux_id = 0; mux_id < mux_num; mux_id++) {
+		/* Force a PLL reconfiguration */
+		config_pll(mux_id);
+	}
+
+	/*
+	 * We don't want the CPU clocks to be turned off at late init
+	 * if CPUFREQ or HOTPLUG configs are disabled. So, bump up the
+	 * refcount of these clocks. Any cpufreq/hotplug manager can assume
+	 * that the clocks have already been prepared and enabled by the time
+	 * they take over.
+	 */
+	get_online_cpus();
+	for_each_online_cpu(cpu) {
+		WARN(clk_prepare_enable(&cpuclk[cpu/4]->c),
+				"Unable to turn on CPU clock");
+		if (!single_cluster)
+			clk_prepare_enable(&cci_clk.c);
+	}
+	put_online_cpus();
+
+	for_each_possible_cpu(cpu) {
+		if (logical_cpu_to_clk(cpu) == &a53_bc_clk.c)
+			cpumask_set_cpu(cpu, &a53_bc_clk.cpumask);
+		if (logical_cpu_to_clk(cpu) == &a53_lc_clk.c)
+			cpumask_set_cpu(cpu, &a53_lc_clk.cpumask);
+	}
+
+	a53_lc_clk.hw_low_power_ctrl = true;
+	a53_bc_clk.hw_low_power_ctrl = true;
+
+	if (single_cluster)
+		register_pm_notifier(&clock_8939_pm_notifier_single_cluster);
+	else
+		register_pm_notifier(&clock_8939_pm_notifier);
+
+	populate_opp_table(pdev, single_cluster);
+
+	atomic_notifier_chain_register(&panic_notifier_list,
+						&clock_panic_notifier);
+
+	return 0;
+}
+
+static const struct of_device_id clock_a53_match_table[] = {
+	{.compatible = "qcom,cpu-clock-8939"},
+	{.compatible = "qcom,cpu-clock-8917"},
+	{}
+};
+
+static struct platform_driver clock_a53_driver = {
+	.probe = clock_a53_probe,
+	.driver = {
+		.name = "cpu-clock-8939",
+		.of_match_table = clock_a53_match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init clock_a53_init(void)
+{
+	return platform_driver_register(&clock_a53_driver);
+}
+arch_initcall(clock_a53_init);
+
+static int __init clock_cpu_lpm_get_latency(void)
+{
+	bool single_cluster;
+	int rc = 0;
+	struct device_node *ofnode = of_find_compatible_node(NULL, NULL,
+					"qcom,cpu-clock-8939");
+
+	if (!ofnode)
+		ofnode = of_find_compatible_node(NULL, NULL,
+					"qcom,cpu-clock-gold");
+
+	if (!ofnode)
+		return 0;
+
+	single_cluster = of_property_read_bool(ofnode,
+					"qcom,num-cluster");
+
+	rc = lpm_get_latency(&a53_bc_clk.latency_lvl,
+			&a53_bc_clk.cpu_latency_no_l2_pc_us);
+	if (rc < 0)
+		pr_err("Failed to get the L2 PC value for perf\n");
+
+	if (!single_cluster) {
+		rc = lpm_get_latency(&a53_lc_clk.latency_lvl,
+				&a53_lc_clk.cpu_latency_no_l2_pc_us);
+		if (rc < 0)
+			pr_err("Failed to get the L2 PC value for pwr\n");
+
+		pr_debug("Latency for pwr/perf cluster %d : %d\n",
+			a53_lc_clk.cpu_latency_no_l2_pc_us,
+			a53_bc_clk.cpu_latency_no_l2_pc_us);
+	} else {
+		pr_debug("Latency for perf cluster %d\n",
+			a53_bc_clk.cpu_latency_no_l2_pc_us);
+	}
+
+	return rc;
+}
+late_initcall(clock_cpu_lpm_get_latency);
+
+#define APCS_C0_PLL			0xb116000
+#define C0_PLL_MODE			0x0
+#define C0_PLL_L_VAL			0x4
+#define C0_PLL_M_VAL			0x8
+#define C0_PLL_N_VAL			0xC
+#define C0_PLL_USER_CTL			0x10
+#define C0_PLL_CONFIG_CTL		0x14
+
+#define APCS_ALIAS0_CMD_RCGR		0xb111050
+#define APCS_ALIAS0_CFG_OFF		0x4
+#define APCS_ALIAS0_CORE_CBCR_OFF	0x8
+#define SRC_SEL				0x4
+#define SRC_DIV				0x3
+
+static void __init configure_enable_sr2_pll(void __iomem *base)
+{
+	/* Disable Mode */
+	writel_relaxed(0x0, base + C0_PLL_MODE);
+
+	/* Configure L/M/N values */
+	writel_relaxed(0x34, base + C0_PLL_L_VAL);
+	writel_relaxed(0x0,  base + C0_PLL_M_VAL);
+	writel_relaxed(0x1,  base + C0_PLL_N_VAL);
+
+	/* Configure USER_CTL and CONFIG_CTL value */
+	writel_relaxed(0x0100000f, base + C0_PLL_USER_CTL);
+	writel_relaxed(0x4c015765, base + C0_PLL_CONFIG_CTL);
+
+	/* Enable PLL now */
+	writel_relaxed(0x2, base + C0_PLL_MODE);
+	udelay(2);
+	writel_relaxed(0x6, base + C0_PLL_MODE);
+	udelay(50);
+	writel_relaxed(0x7, base + C0_PLL_MODE);
+	/* Ensure that the writes go through before enabling
+	 * PLL
+	 */
+	mb();
+}
+
+static int __init cpu_clock_a53_init_little(void)
+{
+	void __iomem  *base;
+	int regval = 0, count;
+	struct device_node *ofnode = of_find_compatible_node(NULL, NULL,
+							"qcom,cpu-clock-8939");
+	if (!ofnode)
+		return 0;
+
+	base = ioremap_nocache(APCS_C0_PLL, SZ_32);
+	configure_enable_sr2_pll(base);
+	iounmap(base);
+
+	base = ioremap_nocache(APCS_ALIAS0_CMD_RCGR, SZ_8);
+	regval = readl_relaxed(base);
+	/* Source GPLL0 and 1/2 the rate of GPLL0 */
+	regval = (SRC_SEL << 8) | SRC_DIV; /* 0x403 */
+	writel_relaxed(regval, base + APCS_ALIAS0_CFG_OFF);
+	/* Make sure src sel and src div is set before update bit */
+	mb();
+
+	/* update bit */
+	regval = readl_relaxed(base);
+	regval |= BIT(0);
+	writel_relaxed(regval, base);
+
+	/* Wait for update to take effect */
+	for (count = 500; count > 0; count--) {
+		if (!(readl_relaxed(base)) & BIT(0))
+			break;
+		udelay(1);
+	}
+
+	/* Enable the branch */
+	regval =  readl_relaxed(base + APCS_ALIAS0_CORE_CBCR_OFF);
+	regval |= BIT(0);
+	writel_relaxed(regval, base + APCS_ALIAS0_CORE_CBCR_OFF);
+	/* Branch enable should be complete */
+	mb();
+	iounmap(base);
+
+	pr_info("A53 Power clocks configured\n");
+
+	return 0;
+}
+early_initcall(cpu_clock_a53_init_little);
diff --git a/drivers/clk/msm/clock-gcc-8952.c b/drivers/clk/msm/clock-gcc-8952.c
new file mode 100644
index 0000000..7da217c
--- /dev/null
+++ b/drivers/clk/msm/clock-gcc-8952.c
@@ -0,0 +1,4867 @@
+/*
+ * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <soc/qcom/clock-local2.h>
+#include <soc/qcom/clock-pll.h>
+#include <soc/qcom/clock-alpha-pll.h>
+#include <soc/qcom/clock-voter.h>
+#include <soc/qcom/rpm-smd.h>
+#include <soc/qcom/clock-rpm.h>
+
+#include <linux/clk/msm-clock-generic.h>
+#include <linux/regulator/rpm-smd-regulator.h>
+
+#include <dt-bindings/clock/msm-clocks-8952.h>
+#include <dt-bindings/clock/msm-clocks-hwio-8952.h>
+
+#include "clock.h"
+#include "reset.h"
+
+enum {
+	GCC_BASE,
+	APCS_C1_PLL_BASE,
+	APCS_C0_PLL_BASE,
+	APCS_CCI_PLL_BASE,
+	N_BASES,
+};
+
+static void __iomem *virt_bases[N_BASES];
+#define GCC_REG_BASE(x) (void __iomem *)(virt_bases[GCC_BASE] + (x))
+
+static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
+
+/* SMD clocks */
+DEFINE_CLK_RPM_SMD_BRANCH(xo_clk_src, xo_a_clk_src, RPM_MISC_CLK_TYPE,
+				CXO_CLK_SRC_ID, 19200000);
+DEFINE_CLK_RPM_SMD(pnoc_clk, pnoc_a_clk, RPM_BUS_CLK_TYPE, PNOC_CLK_ID, NULL);
+DEFINE_CLK_RPM_SMD(bimc_clk, bimc_a_clk, RPM_MEM_CLK_TYPE, BIMC_CLK_ID, NULL);
+DEFINE_CLK_RPM_SMD(bimc_gpu_clk, bimc_gpu_a_clk, RPM_MEM_CLK_TYPE,
+						BIMC_GPU_CLK_ID, NULL);
+DEFINE_CLK_RPM_SMD(snoc_clk, snoc_a_clk, RPM_BUS_CLK_TYPE, SNOC_CLK_ID, NULL);
+DEFINE_CLK_RPM_SMD(sysmmnoc_clk, sysmmnoc_a_clk, RPM_BUS_CLK_TYPE,
+						SYSMMNOC_CLK_ID, NULL);
+DEFINE_CLK_RPM_SMD(ipa_clk, ipa_a_clk, RPM_IPA_CLK_TYPE, IPA_CLK_ID, NULL);
+DEFINE_CLK_RPM_SMD_QDSS(qdss_clk, qdss_a_clk, RPM_MISC_CLK_TYPE, QDSS_CLK_ID);
+
+/* SMD_XO_BUFFER */
+DEFINE_CLK_RPM_SMD_XO_BUFFER(bb_clk1, bb_clk1_a, BB_CLK1_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(bb_clk2, bb_clk2_a, BB_CLK2_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(rf_clk2, rf_clk2_a, RF_CLK2_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(div_clk2, div_clk2_a, DIV_CLK2_ID);
+
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(bb_clk1_pin, bb_clk1_a_pin, BB_CLK1_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(bb_clk2_pin, bb_clk2_a_pin, BB_CLK2_ID);
+
+/* Voter clocks */
+static DEFINE_CLK_VOTER(pnoc_msmbus_clk, &pnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_clk, &snoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(sysmmnoc_msmbus_clk,  &sysmmnoc_clk.c,  LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_msmbus_clk, &bimc_clk.c, LONG_MAX);
+
+static DEFINE_CLK_VOTER(pnoc_msmbus_a_clk, &pnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_a_clk, &snoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(sysmmnoc_msmbus_a_clk,  &sysmmnoc_a_clk.c,  LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_msmbus_a_clk, &bimc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pnoc_keepalive_a_clk, &pnoc_a_clk.c, LONG_MAX);
+
+static DEFINE_CLK_VOTER(pnoc_usb_a_clk, &pnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_usb_a_clk, &snoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_usb_a_clk, &bimc_a_clk.c, LONG_MAX);
+
+static DEFINE_CLK_VOTER(pnoc_usb_clk, &pnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_usb_clk, &snoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_usb_clk, &bimc_clk.c, LONG_MAX);
+
+static DEFINE_CLK_VOTER(snoc_wcnss_a_clk, &snoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_wcnss_a_clk, &bimc_a_clk.c, LONG_MAX);
+
+/* Branch Voter clocks */
+static DEFINE_CLK_BRANCH_VOTER(xo_gcc, &xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_otg_clk, &xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_lpm_clk, &xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_pil_pronto_clk, &xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_pil_mss_clk, &xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_wlan_clk, &xo_clk_src.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_pil_lpass_clk, &xo_clk_src.c);
+
+DEFINE_CLK_DUMMY(wcnss_m_clk, 0);
+
+enum vdd_sr2_pll_levels {
+	VDD_SR2_PLL_OFF,
+	VDD_SR2_PLL_SVS,
+	VDD_SR2_PLL_NOM,
+	VDD_SR2_PLL_TUR,
+	VDD_SR2_PLL_SUPER_TUR,
+	VDD_SR2_PLL_NUM,
+};
+
+static int vdd_sr2_levels[] = {
+	0,	 RPM_REGULATOR_LEVEL_NONE,	/* VDD_SR2_PLL_OFF */
+	1800000, RPM_REGULATOR_LEVEL_SVS,	/* VDD_SR2_PLL_SVS */
+	1800000, RPM_REGULATOR_LEVEL_NOM,	/* VDD_SR2_PLL_NOM */
+	1800000, RPM_REGULATOR_LEVEL_TURBO,	/* VDD_SR2_PLL_TUR */
+	1800000, RPM_REGULATOR_LEVEL_BINNING,	/* VDD_SR2_PLL_SUPER_TUR */
+};
+
+static DEFINE_VDD_REGULATORS(vdd_sr2_pll, VDD_SR2_PLL_NUM, 2,
+				vdd_sr2_levels, NULL);
+
+enum vdd_hf_pll_levels {
+	VDD_HF_PLL_OFF,
+	VDD_HF_PLL_SVS,
+	VDD_HF_PLL_NOM,
+	VDD_HF_PLL_TUR,
+	VDD_HF_PLL_SUPER_TUR,
+	VDD_HF_PLL_NUM,
+};
+
+static int vdd_hf_levels[] = {
+	0,	 RPM_REGULATOR_LEVEL_NONE,	/* VDD_HF_PLL_OFF */
+	1800000, RPM_REGULATOR_LEVEL_SVS,	/* VDD_HF_PLL_SVS */
+	1800000, RPM_REGULATOR_LEVEL_NOM,	/* VDD_HF_PLL_NOM */
+	1800000, RPM_REGULATOR_LEVEL_TURBO,	/* VDD_HF_PLL_TUR */
+	1800000, RPM_REGULATOR_LEVEL_BINNING,	/* VDD_HF_PLL_SUPER_TUR */
+};
+static DEFINE_VDD_REGULATORS(vdd_hf_pll, VDD_HF_PLL_NUM, 2,
+				vdd_hf_levels, NULL);
+
+static struct pll_freq_tbl apcs_cci_pll_freq[] = {
+	F_APCS_PLL(307200000, 16, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(600000000, 31, 0x1, 0x4, 0x0, 0x0, 0x0),
+};
+
+static struct pll_clk a53ss_cci_pll = {
+	.mode_reg = (void __iomem *)APCS_CCI_PLL_MODE,
+	.l_reg = (void __iomem *)APCS_CCI_PLL_L_VAL,
+	.m_reg = (void __iomem *)APCS_CCI_PLL_M_VAL,
+	.n_reg = (void __iomem *)APCS_CCI_PLL_N_VAL,
+	.config_reg = (void __iomem *)APCS_CCI_PLL_USER_CTL,
+	.status_reg = (void __iomem *)APCS_CCI_PLL_STATUS,
+	.freq_tbl = apcs_cci_pll_freq,
+	.masks = {
+		.vco_mask = BM(29, 28),
+		.pre_div_mask = BIT(12),
+		.post_div_mask = BM(9, 8),
+		.mn_en_mask = BIT(24),
+		.main_output_mask = BIT(0),
+	},
+	.base = &virt_bases[APCS_CCI_PLL_BASE],
+	.spm_ctrl = {
+		.offset = 0x40,
+		.event_bit = 0x0,
+	},
+	.c = {
+		.parent = &xo_a_clk_src.c,
+		.dbg_name = "a53ss_cci_pll",
+		.ops = &clk_ops_sr2_pll,
+		.vdd_class = &vdd_sr2_pll,
+		.fmax = (unsigned long [VDD_SR2_PLL_NUM]) {
+			[VDD_SR2_PLL_SVS] = 1000000000,
+			[VDD_SR2_PLL_NOM] = 1900000000,
+		},
+		.num_fmax = VDD_SR2_PLL_NUM,
+		CLK_INIT(a53ss_cci_pll.c),
+	},
+};
+
+static struct pll_freq_tbl apcs_c0_pll_freq[] = {
+	F_APCS_PLL( 249600000,  13, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 307200000,  16, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 345600000,  18, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 384000000,  20, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 460800000,  24, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 499200000,  26, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 518400000,  27, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 768000000,  40, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 806400000,  42, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 844800000,  44, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 883200000,  46, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 902400000,  47, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 921600000,  48, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 998400000,  52, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1094400000,  57, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1209600000,  63, 0x0, 0x1, 0x0, 0x0, 0x0),
+};
+
+static struct pll_clk a53ss_c0_pll = {
+	.mode_reg = (void __iomem *)APCS_C0_PLL_MODE,
+	.l_reg = (void __iomem *)APCS_C0_PLL_L_VAL,
+	.m_reg = (void __iomem *)APCS_C0_PLL_M_VAL,
+	.n_reg = (void __iomem *)APCS_C0_PLL_N_VAL,
+	.config_reg = (void __iomem *)APCS_C0_PLL_USER_CTL,
+	.status_reg = (void __iomem *)APCS_C0_PLL_STATUS,
+	.freq_tbl = apcs_c0_pll_freq,
+	.masks = {
+		.vco_mask = BM(29, 28),
+		.pre_div_mask = BIT(12),
+		.post_div_mask = BM(9, 8),
+		.mn_en_mask = BIT(24),
+		.main_output_mask = BIT(0),
+	},
+	.base = &virt_bases[APCS_C0_PLL_BASE],
+	.spm_ctrl = {
+		.offset = 0x50,
+		.event_bit = 0x4,
+	},
+	.c = {
+		.parent = &xo_a_clk_src.c,
+		.dbg_name = "a53ss_c0_pll",
+		.ops = &clk_ops_sr2_pll,
+		.vdd_class = &vdd_sr2_pll,
+		.fmax = (unsigned long [VDD_SR2_PLL_NUM]) {
+			[VDD_SR2_PLL_SVS] = 1000000000,
+			[VDD_SR2_PLL_NOM] = 1900000000,
+		},
+		.num_fmax = VDD_SR2_PLL_NUM,
+		CLK_INIT(a53ss_c0_pll.c),
+	},
+};
+
+static struct pll_freq_tbl apcs_c1_pll_freq[] = {
+	F_APCS_PLL( 345600000, 18, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 422400000, 22, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 499200000, 26, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 652800000, 34, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 729600000, 38, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 806400000, 42, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 844800000, 44, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 883200000, 46, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 960000000, 50, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 998400000, 52, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1036800000, 54, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1094400000, 57, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1113600000, 58, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1190400000, 62, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1209600000, 63, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1248000000, 65, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1267200000, 66, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1344000000, 70, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1401000000, 73, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1420800000, 74, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1440000000, 75, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1459200000, 76, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1497600000, 78, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1516800000, 79, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1536000000, 80, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1651200000, 86, 0x0, 0x1, 0x0, 0x0, 0x0),
+};
+
+static struct pll_clk a53ss_c1_pll = {
+	.mode_reg = (void __iomem *)APCS_C1_PLL_MODE,
+	.l_reg = (void __iomem *)APCS_C1_PLL_L_VAL,
+	.m_reg = (void __iomem *)APCS_C1_PLL_M_VAL,
+	.n_reg = (void __iomem *)APCS_C1_PLL_N_VAL,
+	.config_reg = (void __iomem *)APCS_C1_PLL_USER_CTL,
+	.status_reg = (void __iomem *)APCS_C1_PLL_STATUS,
+	.freq_tbl = apcs_c1_pll_freq,
+	.masks = {
+		.vco_mask = BM(29, 28),
+		.pre_div_mask = BIT(12),
+		.post_div_mask = BM(9, 8),
+		.mn_en_mask = BIT(24),
+		.main_output_mask = BIT(0),
+	},
+	.base = &virt_bases[APCS_C1_PLL_BASE],
+	.spm_ctrl = {
+		.offset = 0x50,
+		.event_bit = 0x4,
+	},
+	.c = {
+		.parent = &xo_a_clk_src.c,
+		.dbg_name = "a53ss_c1_pll",
+		.ops = &clk_ops_sr2_pll,
+		.vdd_class = &vdd_hf_pll,
+		.fmax = (unsigned long [VDD_HF_PLL_NUM]) {
+			[VDD_HF_PLL_SVS] = 1000000000,
+			[VDD_HF_PLL_NOM] = 2000000000,
+		},
+		.num_fmax = VDD_HF_PLL_NUM,
+		CLK_INIT(a53ss_c1_pll.c),
+	},
+};
+
+static struct pll_vote_clk gpll0_sleep_clk_src = {
+	.en_reg = (void __iomem *)APCS_CLOCK_SLEEP_ENA_VOTE,
+	.en_mask = BIT(23),
+	.status_reg = (void __iomem *)GPLL0_MODE,
+	.status_mask = BIT(30),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &xo_clk_src.c,
+		.rate = 800000000,
+		.dbg_name = "gpll0_sleep_clk_src",
+		.ops = &clk_ops_pll_sleep_vote,
+		CLK_INIT(gpll0_sleep_clk_src.c),
+	},
+};
+
+static unsigned int soft_vote_gpll0;
+
+/* PLL_ACTIVE_FLAG bit of GCC_GPLL0_MODE register
+ * gets set from PLL voting FSM.It indicates when
+ * FSM has enabled the PLL and PLL should be locked.
+ */
+static struct pll_vote_clk gpll0_clk_src_8952 = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)GPLL0_STATUS,
+	.status_mask = BIT(17),
+	.soft_vote = &soft_vote_gpll0,
+	.soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &xo_clk_src.c,
+		.rate = 800000000,
+		.dbg_name = "gpll0_clk_src_8952",
+		.ops = &clk_ops_pll_acpu_vote,
+		CLK_INIT(gpll0_clk_src_8952.c),
+	},
+};
+
+static struct pll_vote_clk gpll0_clk_src_8937 = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)GPLL0_MODE,
+	.status_mask = BIT(30),
+	.soft_vote = &soft_vote_gpll0,
+	.soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &gpll0_sleep_clk_src.c,
+		.rate = 800000000,
+		.dbg_name = "gpll0_clk_src_8937",
+		.ops = &clk_ops_pll_acpu_vote,
+		CLK_INIT(gpll0_clk_src_8937.c),
+	},
+};
+
+DEFINE_EXT_CLK(gpll0_clk_src, NULL);
+DEFINE_EXT_CLK(gpll0_ao_clk_src, NULL);
+DEFINE_EXT_CLK(gpll0_out_aux_clk_src, &gpll0_clk_src.c);
+DEFINE_EXT_CLK(gpll0_out_main_clk_src, &gpll0_clk_src.c);
+DEFINE_EXT_CLK(ext_pclk0_clk_src, NULL);
+DEFINE_EXT_CLK(ext_byte0_clk_src, NULL);
+DEFINE_EXT_CLK(ext_pclk1_clk_src, NULL);
+DEFINE_EXT_CLK(ext_byte1_clk_src, NULL);
+
+/* Don't vote for xo if using this clock to allow xo shutdown */
+static struct pll_vote_clk gpll0_ao_clk_src_8952 = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)GPLL0_STATUS,
+	.status_mask = BIT(17),
+	.soft_vote = &soft_vote_gpll0,
+	.soft_vote_mask = PLL_SOFT_VOTE_ACPU,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &xo_a_clk_src.c,
+		.rate = 800000000,
+		.dbg_name = "gpll0_ao_clk_src_8952",
+		.ops = &clk_ops_pll_acpu_vote,
+		CLK_INIT(gpll0_ao_clk_src_8952.c),
+	},
+};
+
+static struct pll_vote_clk gpll0_ao_clk_src_8937 = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)GPLL0_MODE,
+	.status_mask = BIT(30),
+	.soft_vote = &soft_vote_gpll0,
+	.soft_vote_mask = PLL_SOFT_VOTE_ACPU,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &xo_a_clk_src.c,
+		.rate = 800000000,
+		.dbg_name = "gpll0_ao_clk_src_8937",
+		.ops = &clk_ops_pll_acpu_vote,
+		CLK_INIT(gpll0_ao_clk_src_8937.c),
+	},
+};
+
+static struct pll_vote_clk gpll6_clk_src = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(7),
+	.status_reg = (void __iomem *)GPLL6_STATUS,
+	.status_mask = BIT(17),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &xo_clk_src.c,
+		.rate = 1080000000,
+		.dbg_name = "gpll6_clk_src",
+		.ops = &clk_ops_pll_vote,
+		CLK_INIT(gpll6_clk_src.c),
+	},
+};
+
+DEFINE_EXT_CLK(gpll6_aux_clk_src, &gpll6_clk_src.c);
+DEFINE_EXT_CLK(gpll6_out_main_clk_src, &gpll6_clk_src.c);
+
+static struct alpha_pll_masks pll_masks_p = {
+	.lock_mask = BIT(31),
+	.active_mask = BIT(30),
+	.vco_mask = BM(21, 20) >> 20,
+	.vco_shift = 20,
+	.alpha_en_mask = BIT(24),
+	.output_mask = 0xf,
+	.update_mask = BIT(22),
+	.post_div_mask = BM(11, 8),
+	.test_ctl_lo_mask = BM(31, 0),
+	.test_ctl_hi_mask = BM(31, 0),
+};
+
+/* Slewing plls won't allow to change vco_sel.
+ * Hence will have only one vco table entry
+ */
+static struct alpha_pll_vco_tbl p_vco[] = {
+	VCO(0,  700000000, 1400000000),
+};
+
+/* Slewing plls won't allow to change vco_sel.
+ * Hence will have only one vco table entry
+ */
+static struct alpha_pll_vco_tbl p_vco_8937[] = {
+	VCO(1,  525000000, 1066000000),
+};
+
+static struct alpha_pll_clk gpll3_clk_src = {
+	.masks = &pll_masks_p,
+	.base = &virt_bases[GCC_BASE],
+	.offset = GPLL3_MODE,
+	.vco_tbl = p_vco,
+	.num_vco = ARRAY_SIZE(p_vco),
+	.enable_config = 1,
+	/*
+	 * gpll3 is dedicated to oxili and has a fuse implementation for
+	 * post divider to limit frequency. HW with fuse blown has a divider
+	 * value set to 2. So lets stick to divide by 2 in software to avoid
+	 * conflicts.
+	 */
+	.post_div_config = 1 << 8,
+	.slew = true,
+	.config_ctl_val = 0x4001055b,
+	.test_ctl_hi_val = 0x40000600,
+	.c = {
+		.rate = 1050000000,
+		.parent = &xo_clk_src.c,
+		.dbg_name = "gpll3_clk_src",
+		.ops = &clk_ops_dyna_alpha_pll,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 1400000000),
+		CLK_INIT(gpll3_clk_src.c),
+	},
+};
+
+static struct pll_vote_clk gpll4_clk_src = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(5),
+	.status_reg = (void __iomem *)GPLL4_MODE,
+	.status_mask = BIT(30),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.rate =  1152000000,
+		.parent = &xo_clk_src.c,
+		.dbg_name = "gpll4_clk_src",
+		.ops = &clk_ops_pll_vote,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 1400000000),
+		CLK_INIT(gpll4_clk_src.c),
+	},
+};
+DEFINE_EXT_CLK(gpll4_out_clk_src, &gpll4_clk_src.c);
+
+static struct clk_freq_tbl ftbl_gcc_camss_top_ahb_clk[] = {
+	F( 40000000,	gpll0,	10,	1,	2),
+	F( 61540000,	gpll0,	13,	0,	0),
+	F( 80000000,	gpll0,	10,	0,	0),
+	F_END
+};
+
+static struct rcg_clk camss_top_ahb_clk_src = {
+	.cmd_rcgr_reg =  CAMSS_TOP_AHB_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_camss_top_ahb_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "camss_top_ahb_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP3(LOWER, 40000000, LOW, 61540000,
+				  NOMINAL, 80000000),
+		CLK_INIT(camss_top_ahb_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_apss_ahb_clk[] = {
+	F( 19200000,	xo_a,	1,	0,	0),
+	F( 50000000,	gpll0,	16,	0,	0),
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 133330000,	gpll0,	6,	0,	0),
+	F_END
+};
+
+static struct rcg_clk apss_ahb_clk_src = {
+	.cmd_rcgr_reg = APSS_AHB_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_apss_ahb_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "apss_ahb_clk_src",
+		.ops = &clk_ops_rcg,
+		CLK_INIT(apss_ahb_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_csi0_2_clk[] = {
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 160000000,	gpll0,	5,	0,	0),
+	F( 200000000,	gpll0,	4,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_csi0_2_clk_8937[] = {
+	F( 100000000,          gpll0,    8,    0,     0),
+	F( 160000000,          gpll0,    5,    0,     0),
+	F( 200000000,          gpll0,    4,    0,     0),
+	F( 266670000,          gpll0,    3,    0,     0),
+	F_END
+};
+
+
+static struct rcg_clk csi0_clk_src = {
+	.cmd_rcgr_reg = CSI0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_camss_csi0_2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "csi0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOWER, 100000000, LOW, 160000000,
+				  NOMINAL, 200000000),
+		CLK_INIT(csi0_clk_src.c),
+	},
+};
+
+static struct rcg_clk csi1_clk_src = {
+	.cmd_rcgr_reg = CSI1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_camss_csi0_2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "csi1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOWER, 100000000, LOW, 160000000,
+				  NOMINAL, 200000000),
+		CLK_INIT(csi1_clk_src.c),
+	},
+};
+
+static struct rcg_clk csi2_clk_src = {
+	.cmd_rcgr_reg = CSI2_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_camss_csi0_2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "csi2_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOWER, 100000000, LOW, 160000000,
+				  NOMINAL, 200000000),
+		CLK_INIT(csi2_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_venus0_vcodec0_clk[] = {
+	F( 133330000,	gpll0,	6,	0,	0),
+	F( 180000000,	gpll6,	6,	0,	0),
+	F( 228570000,	gpll0,	3.5,	0,	0),
+	F( 266670000,	gpll0,	3,	0,	0),
+	F( 308570000,	gpll6,	3.5,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_venus0_vcodec0_clk_8937[] = {
+	F( 166150000,          gpll6,  6.5,    0,     0),
+	F( 240000000,          gpll6,  4.5,    0,     0),
+	F( 308570000,          gpll6,  3.5,    0,     0),
+	F( 320000000,          gpll0,  2.5,    0,     0),
+	F( 360000000,          gpll6,    3,    0,     0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_venus0_vcodec0_clk_8917[] = {
+	F( 160000000,          gpll0,    5,    0,     0),
+	F( 200000000,          gpll0,    4,    0,     0),
+	F( 270000000,          gpll6,    4,    0,     0),
+	F( 308570000,          gpll6,  3.5,    0,     0),
+	F( 329140000,          gpll4_out,  3.5,    0,     0),
+	F( 360000000,          gpll6,    3,    0,     0),
+	F_END
+};
+
+static struct rcg_clk vcodec0_clk_src = {
+	.cmd_rcgr_reg =  VCODEC0_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_venus0_vcodec0_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "vcodec0_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP5(LOWER, 133330000, LOW, 180000000,
+				  NOMINAL, 228570000, NOM_PLUS, 266670000,
+				  HIGH, 308570000),
+		CLK_INIT(vcodec0_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_vfe0_1_clk[] = {
+	F( 50000000,	gpll0,	16,	0,	0),
+	F( 80000000,	gpll0,	10,	0,	0),
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 133330000,	gpll0,	6,	0,	0),
+	F( 160000000,	gpll0,	5,	0,	0),
+	F( 177780000,	gpll0,	4.5,	0,	0),
+	F( 200000000,	gpll0,	4,	0,	0),
+	F( 266670000,	gpll0,	3,	0,	0),
+	F( 308570000,	gpll6,	3.5,	0,	0),
+	F( 320000000,	gpll0,	2.5,	0,	0),
+	F( 360000000,	gpll6,	3,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_vfe0_1_clk_8937[] = {
+	F(  50000000,          gpll0,   16,    0,     0),
+	F(  80000000,          gpll0,   10,    0,     0),
+	F( 100000000,          gpll0,    8,    0,     0),
+	F( 133333333,          gpll0,    6,    0,     0),
+	F( 160000000,          gpll0,    5,    0,     0),
+	F( 177780000,          gpll0,  4.5,    0,     0),
+	F( 200000000,          gpll0,    4,    0,     0),
+	F( 266670000,          gpll0,    3,    0,     0),
+	F( 308570000,          gpll6,  3.5,    0,     0),
+	F( 320000000,          gpll0,  2.5,    0,     0),
+	F( 360000000,          gpll6,    3,    0,     0),
+	F( 400000000,          gpll0,    2,    0,     0),
+	F( 432000000,          gpll6,  2.5,    0,     0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_vfe0_1_clk_8917[] = {
+	F(  50000000,          gpll0,   16,    0,     0),
+	F(  80000000,          gpll0,   10,    0,     0),
+	F( 100000000,          gpll0,    8,    0,     0),
+	F( 133333333,          gpll0,    6,    0,     0),
+	F( 160000000,          gpll0,    5,    0,     0),
+	F( 177780000,          gpll0,  4.5,    0,     0),
+	F( 200000000,          gpll0,    4,    0,     0),
+	F( 266670000,          gpll0,    3,    0,     0),
+	F( 308570000,          gpll6,  3.5,    0,     0),
+	F( 320000000,          gpll0,  2.5,    0,     0),
+	F( 329140000,          gpll4_out,  3.5,    0,     0),
+	F( 360000000,          gpll6,    3,    0,     0),
+	F_END
+};
+
+static struct rcg_clk vfe0_clk_src = {
+	.cmd_rcgr_reg = VFE0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_camss_vfe0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "vfe0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP5(LOWER, 133330000, LOW, 266670000,
+				  NOMINAL, 308570000, NOM_PLUS, 320000000,
+				  HIGH, 360000000),
+		CLK_INIT(vfe0_clk_src.c),
+	},
+};
+
+static struct rcg_clk vfe1_clk_src = {
+	.cmd_rcgr_reg = VFE1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_camss_vfe0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "vfe1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP5(LOWER, 133330000, LOW, 266670000,
+				  NOMINAL, 308570000, NOM_PLUS, 320000000,
+				  HIGH, 360000000),
+		CLK_INIT(vfe1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_oxili_gfx3d_clk[] = {
+	F_SLEW( 19200000,  FIXED_CLK_SRC, xo,		1,	0,	0),
+	F_SLEW( 50000000,  FIXED_CLK_SRC, gpll0,	16,	0,	0),
+	F_SLEW( 80000000,  FIXED_CLK_SRC, gpll0,	10,	0,	0),
+	F_SLEW( 100000000, FIXED_CLK_SRC, gpll0,	8,	0,	0),
+	F_SLEW( 160000000, FIXED_CLK_SRC, gpll0,	5,	0,	0),
+	F_SLEW( 200000000, FIXED_CLK_SRC, gpll0,	4,	0,	0),
+	F_SLEW( 228570000, FIXED_CLK_SRC, gpll0,	3.5,	0,	0),
+	F_SLEW( 240000000, FIXED_CLK_SRC, gpll6_aux,	4.5,	0,	0),
+	F_SLEW( 266670000, FIXED_CLK_SRC, gpll0,	3,	0,	0),
+	F_SLEW( 400000000, FIXED_CLK_SRC, gpll0,	2,	0,	0),
+	F_SLEW( 465000000, 930000000,	  gpll3,	1,	0,	0),
+	F_SLEW( 500000000, 1000000000,	  gpll3,	1,	0,	0),
+	F_SLEW( 550000000, 1100000000,	  gpll3,	1,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_oxili_gfx3d_clk_8937[] = {
+	F_SLEW( 19200000,  FIXED_CLK_SRC, xo,		1,	0,	0),
+	F_SLEW( 50000000,  FIXED_CLK_SRC, gpll0,	16,	0,	0),
+	F_SLEW( 80000000,  FIXED_CLK_SRC, gpll0,	10,	0,	0),
+	F_SLEW( 100000000, FIXED_CLK_SRC, gpll0,	8,	0,	0),
+	F_SLEW( 160000000, FIXED_CLK_SRC, gpll0,	5,	0,	0),
+	F_SLEW( 200000000, FIXED_CLK_SRC, gpll0,	4,	0,	0),
+	F_SLEW( 216000000, FIXED_CLK_SRC, gpll6_aux,	5,	0,	0),
+	F_SLEW( 228570000, FIXED_CLK_SRC, gpll0,	3.5,	0,	0),
+	F_SLEW( 240000000, FIXED_CLK_SRC, gpll6_aux,	4.5,	0,	0),
+	F_SLEW( 266670000, FIXED_CLK_SRC, gpll0,	3,	0,	0),
+	F_SLEW( 300000000, 600000000,	  gpll3,	1,	0,      0),
+	F_SLEW( 320000000, FIXED_CLK_SRC, gpll0,	2.5,	0,	0),
+	F_SLEW( 375000000, 750000000,	  gpll3,	1,	0,	0),
+	F_SLEW( 400000000, FIXED_CLK_SRC, gpll0,	2,	0,	0),
+	F_SLEW( 450000000, 900000000,	  gpll3,	1,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_oxili_gfx3d_clk_8937_475MHz[] = {
+	F_SLEW( 19200000,  FIXED_CLK_SRC, xo,		1,	0,	0),
+	F_SLEW( 50000000,  FIXED_CLK_SRC, gpll0,	16,	0,	0),
+	F_SLEW( 80000000,  FIXED_CLK_SRC, gpll0,	10,	0,	0),
+	F_SLEW( 100000000, FIXED_CLK_SRC, gpll0,	8,	0,	0),
+	F_SLEW( 160000000, FIXED_CLK_SRC, gpll0,	5,	0,	0),
+	F_SLEW( 200000000, FIXED_CLK_SRC, gpll0,	4,	0,	0),
+	F_SLEW( 216000000, FIXED_CLK_SRC, gpll6_aux,	5,	0,	0),
+	F_SLEW( 228570000, FIXED_CLK_SRC, gpll0,	3.5,	0,	0),
+	F_SLEW( 240000000, FIXED_CLK_SRC, gpll6_aux,	4.5,	0,	0),
+	F_SLEW( 266670000, FIXED_CLK_SRC, gpll0,	3,	0,	0),
+	F_SLEW( 300000000, 600000000,	  gpll3,	1,	0,	0),
+	F_SLEW( 320000000, FIXED_CLK_SRC, gpll0,	2.5,	0,	0),
+	F_SLEW( 375000000, 750000000,	  gpll3,	1,	0,	0),
+	F_SLEW( 400000000, FIXED_CLK_SRC, gpll0,	2,	0,	0),
+	F_SLEW( 450000000, 900000000,	  gpll3,	1,	0,	0),
+	F_SLEW( 475000000, 950000000,	  gpll3,	1,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_oxili_gfx3d_clk_8940_500MHz[] = {
+	F_SLEW( 19200000,  FIXED_CLK_SRC, xo,		1,	0,	0),
+	F_SLEW( 50000000,  FIXED_CLK_SRC, gpll0,	16,	0,	0),
+	F_SLEW( 80000000,  FIXED_CLK_SRC, gpll0,	10,	0,	0),
+	F_SLEW( 100000000, FIXED_CLK_SRC, gpll0,	8,	0,	0),
+	F_SLEW( 160000000, FIXED_CLK_SRC, gpll0,	5,	0,	0),
+	F_SLEW( 200000000, FIXED_CLK_SRC, gpll0,	4,	0,	0),
+	F_SLEW( 216000000, FIXED_CLK_SRC, gpll6_aux,	5,	0,	0),
+	F_SLEW( 228570000, FIXED_CLK_SRC, gpll0,	3.5,	0,	0),
+	F_SLEW( 240000000, FIXED_CLK_SRC, gpll6_aux,	4.5,	0,	0),
+	F_SLEW( 266670000, FIXED_CLK_SRC, gpll0,	3,	0,	0),
+	F_SLEW( 300000000, 600000000,	  gpll3,	1,	0,	0),
+	F_SLEW( 320000000, FIXED_CLK_SRC, gpll0,	2.5,	0,	0),
+	F_SLEW( 375000000, 750000000,	  gpll3,	1,	0,	0),
+	F_SLEW( 400000000, FIXED_CLK_SRC, gpll0,	2,	0,	0),
+	F_SLEW( 450000000, 900000000,	  gpll3,	1,	0,	0),
+	F_SLEW( 475000000, 950000000,	  gpll3,	1,	0,	0),
+	F_SLEW( 500000000, 1000000000,	  gpll3,	1,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_oxili_gfx3d_clk_8917[] = {
+	F_SLEW( 19200000,  FIXED_CLK_SRC, xo,		1,	0,	0),
+	F_SLEW( 50000000,  FIXED_CLK_SRC, gpll0,	16,	0,	0),
+	F_SLEW( 80000000,  FIXED_CLK_SRC, gpll0,	10,	0,	0),
+	F_SLEW( 100000000, FIXED_CLK_SRC, gpll0,	8,	0,	0),
+	F_SLEW( 160000000, FIXED_CLK_SRC, gpll0,	5,	0,	0),
+	F_SLEW( 200000000, FIXED_CLK_SRC, gpll0,	4,	0,	0),
+	F_SLEW( 228570000, FIXED_CLK_SRC, gpll0,	3.5,	0,	0),
+	F_SLEW( 240000000, FIXED_CLK_SRC, gpll6_aux,	4.5,	0,	0),
+	F_SLEW( 266670000, FIXED_CLK_SRC, gpll0,	3,	0,	0),
+	F_SLEW( 270000000, FIXED_CLK_SRC, gpll6_aux,	4,	0,	0),
+	F_SLEW( 320000000, FIXED_CLK_SRC, gpll0,	2.5,	0,	0),
+	F_SLEW( 400000000, FIXED_CLK_SRC, gpll0,	2,	0,	0),
+	F_SLEW( 484800000, 969600000,	  gpll3,	1,	0,	0),
+	F_SLEW( 523200000, 1046400000,	  gpll3,	1,	0,	0),
+	F_SLEW( 550000000, 1100000000,	  gpll3,	1,	0,	0),
+	F_SLEW( 598000000, 1196000000,	  gpll3,	1,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_oxili_gfx3d_clk_8917_650MHz[] = {
+	F_SLEW( 19200000,  FIXED_CLK_SRC, xo,		1,	0,	0),
+	F_SLEW( 50000000,  FIXED_CLK_SRC, gpll0,	16,	0,	0),
+	F_SLEW( 80000000,  FIXED_CLK_SRC, gpll0,	10,	0,	0),
+	F_SLEW( 100000000, FIXED_CLK_SRC, gpll0,	8,	0,	0),
+	F_SLEW( 160000000, FIXED_CLK_SRC, gpll0,	5,	0,	0),
+	F_SLEW( 200000000, FIXED_CLK_SRC, gpll0,	4,	0,	0),
+	F_SLEW( 228570000, FIXED_CLK_SRC, gpll0,	3.5,	0,	0),
+	F_SLEW( 240000000, FIXED_CLK_SRC, gpll6_aux,	4.5,	0,	0),
+	F_SLEW( 266670000, FIXED_CLK_SRC, gpll0,	3,	0,	0),
+	F_SLEW( 270000000, FIXED_CLK_SRC, gpll6_aux,	4,	0,	0),
+	F_SLEW( 320000000, FIXED_CLK_SRC, gpll0,	2.5,	0,	0),
+	F_SLEW( 400000000, FIXED_CLK_SRC, gpll0,	2,	0,	0),
+	F_SLEW( 484800000, 969600000,	  gpll3,	1,	0,	0),
+	F_SLEW( 523200000, 1046400000,	  gpll3,	1,	0,	0),
+	F_SLEW( 550000000, 1100000000,	  gpll3,	1,	0,	0),
+	F_SLEW( 598000000, 1196000000,	  gpll3,	1,	0,	0),
+	F_SLEW( 650000000, 1300000000,	  gpll3,	1,	0,	0),
+	F_END
+};
+
+static struct  rcg_clk gfx3d_clk_src = {
+	.cmd_rcgr_reg = GFX3D_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_oxili_gfx3d_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gfx3d_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP5(LOWER, 240000000, LOW, 400000000,
+				  NOMINAL, 465000000, NOM_PLUS, 500000000,
+				  HIGH, 550000000),
+		CLK_INIT(gfx3d_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_2_qup1_4_i2c_apps_clk[] = {
+	F( 19200000,	xo,	1,	0,	0),
+	F( 50000000,	gpll0,	16,	0,	0),
+	F_END
+};
+
+static struct rcg_clk blsp1_qup1_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP1_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup1_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp1_qup1_i2c_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk[] = {
+	F( 960000,	xo,	10,	1,	2),
+	F( 4800000,	xo,	4,	0,	0),
+	F( 9600000,	xo,	2,	0,	0),
+	F( 16000000,	gpll0,	10,	1,	5),
+	F( 19200000,	xo,	1,	0,	0),
+	F( 25000000,	gpll0,	16,	1,	2),
+	F( 50000000,	gpll0,	16,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk_8917[] = {
+	F( 960000,	xo,	10,	1,	2),
+	F( 4800000,	xo,	4,	0,	0),
+	F( 9600000,	xo,	2,	0,	0),
+	F( 16000000,	gpll0,	10,	1,	5),
+	F( 19200000,	xo,	1,	0,	0),
+	F( 25000000,	gpll0,	16,	1,	2),
+	F( 40000000,	gpll0,	10,	1,	2),
+	F( 50000000,	gpll0,	16,	0,	0),
+	F_END
+};
+
+static struct rcg_clk blsp1_qup1_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_QUP1_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup1_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup1_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup2_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP2_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup2_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp1_qup2_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup2_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_QUP2_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup2_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup2_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup3_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP3_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup3_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp1_qup3_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup3_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_QUP3_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup3_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup3_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup4_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP4_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup4_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp1_qup4_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup4_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_QUP4_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup4_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup4_spi_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_2_uart1_2_apps_clk[] = {
+	F( 3686400,	gpll0,	1,	72,	15625),
+	F( 7372800,	gpll0,	1,	144,	15625),
+	F( 14745600,	gpll0,	1,	288,	15625),
+	F( 16000000,	gpll0,	10,	1,	5),
+	F( 19200000,	xo,	1,	0,	0),
+	F( 24000000,	gpll0,	1,	3,	100),
+	F( 25000000,	gpll0,	16,	1,	2),
+	F( 32000000,	gpll0,	1,	1,	25),
+	F( 40000000,	gpll0,	1,	1,	20),
+	F( 46400000,	gpll0,	1,	29,	500),
+	F( 48000000,	gpll0,	1,	3,	50),
+	F( 51200000,	gpll0,	1,	8,	125),
+	F( 56000000,	gpll0,	1,	7,	100),
+	F( 58982400,	gpll0,	1,	1152,	15625),
+	F( 60000000,	gpll0,	1,	3,	40),
+	F( 64000000,	gpll0,  1,	2,	25),
+	F_END
+};
+
+static struct rcg_clk blsp1_uart1_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_UART1_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_2_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart1_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 32000000, NOMINAL, 64000000),
+		CLK_INIT(blsp1_uart1_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart2_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_UART2_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_2_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart2_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 32000000, NOMINAL, 64000000),
+		CLK_INIT(blsp1_uart2_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup1_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP1_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup1_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp2_qup1_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup1_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP2_QUP1_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup1_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp2_qup1_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup2_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP2_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup2_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp2_qup2_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup2_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP2_QUP2_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup2_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp2_qup2_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup3_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP3_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup3_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp2_qup3_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup3_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP2_QUP3_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup3_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp2_qup3_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup4_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP4_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup4_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 50000000),
+		CLK_INIT(blsp2_qup4_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup4_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP2_QUP4_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup4_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp2_qup4_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_uart1_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP2_UART1_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_2_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_uart1_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 32000000, NOMINAL, 64000000),
+		CLK_INIT(blsp2_uart1_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_uart2_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP2_UART2_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_2_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_uart2_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 32000000, NOMINAL, 64000000),
+		CLK_INIT(blsp2_uart2_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_cci_clk[] = {
+	F( 19200000,	xo,		1,	0,	0),
+	F( 37500000,	gpll0_out_aux,	1,	3,	64),
+	F_END
+};
+
+static struct rcg_clk cci_clk_src = {
+	.cmd_rcgr_reg =  CCI_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_camss_cci_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "cci_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 19200000, LOW, 37500000),
+		CLK_INIT(cci_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_cpp_clk[] = {
+	F( 133330000,	gpll0,	6,	0,	0),
+	F( 180000000,	gpll6,	6,	0,	0),
+	F( 266670000,	gpll0,	3,	0,	0),
+	F( 308570000,	gpll6,	3.5,	0,	0),
+	F( 320000000,	gpll0,	2.5,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_cpp_clk_8937[] = {
+	F( 133333333,          gpll0,    6,    0,     0),
+	F( 160000000,          gpll0,    5,    0,     0),
+	F( 200000000,          gpll0,    4,    0,     0),
+	F( 266666667,          gpll0,    3,    0,     0),
+	F( 308570000,          gpll6,  3.5,    0,     0),
+	F( 320000000,          gpll0,  2.5,    0,     0),
+	F( 360000000,          gpll6,    3,    0,     0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_cpp_clk_8917[] = {
+	F( 133330000,          gpll0,    6,    0,     0),
+	F( 160000000,          gpll0,    5,    0,     0),
+	F( 266670000,          gpll0,    3,    0,     0),
+	F( 308570000,          gpll6,  3.5,    0,     0),
+	F( 320000000,          gpll0,  2.5,    0,     0),
+	F( 360000000,          gpll6,    3,    0,     0),
+	F_END
+};
+
+static struct rcg_clk cpp_clk_src = {
+	.cmd_rcgr_reg = CPP_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_camss_cpp_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "cpp_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP5(LOWER, 133330000, LOW, 180000000,
+				  NOMINAL, 266670000, NOM_PLUS, 308570000,
+				  HIGH, 320000000),
+		CLK_INIT(cpp_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_gp0_1_clk[] = {
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 160000000,	gpll0,	5,	0,	0),
+	F( 200000000,	gpll0,	4,	0,	0),
+	F_END
+};
+
+static struct rcg_clk camss_gp0_clk_src = {
+	.cmd_rcgr_reg =  MM_GP0_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_camss_gp0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "camss_gp0_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP3(LOWER, 100000000, LOW, 160000000,
+				  NOMINAL, 200000000),
+		CLK_INIT(camss_gp0_clk_src.c),
+	},
+};
+
+static struct rcg_clk camss_gp1_clk_src = {
+	.cmd_rcgr_reg =  MM_GP1_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_camss_gp0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "camss_gp1_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP3(LOWER, 100000000, LOW, 160000000,
+				  NOMINAL, 200000000),
+		CLK_INIT(camss_gp1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_jpeg0_clk[] = {
+	F( 133330000,	gpll0,	6,	0,	0),
+	F( 266670000,	gpll0,	3,	0,	0),
+	F( 320000000,	gpll0,	2.5,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_jpeg0_clk_8937[] = {
+	F( 133333333,          gpll0,    6,    0,     0),
+	F( 200000000,          gpll0,    4,    0,     0),
+	F( 266666667,          gpll0,    3,    0,     0),
+	F( 308570000,          gpll6,  3.5,    0,     0),
+	F( 320000000,          gpll0,  2.5,    0,     0),
+	F_END
+};
+
+static struct rcg_clk jpeg0_clk_src = {
+	.cmd_rcgr_reg = JPEG0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_camss_jpeg0_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "jpeg0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOWER, 133330000, NOMINAL, 266670000,
+				  HIGH, 320000000),
+		CLK_INIT(jpeg0_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_mclk0_2_clk[] = {
+	F( 19200000,	xo,	1,	0,	0),
+	F( 24000000,	gpll6,	1,	1,	45),
+	F( 66670000,	gpll0,	12,	0,	0),
+	F_END
+};
+
+static struct rcg_clk mclk0_clk_src = {
+	.cmd_rcgr_reg =  MCLK0_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_camss_mclk0_2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "mclk0_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOWER, 66670000),
+		CLK_INIT(mclk0_clk_src.c),
+	},
+};
+
+static struct rcg_clk mclk1_clk_src = {
+	.cmd_rcgr_reg =  MCLK1_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_camss_mclk0_2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "mclk1_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOWER, 66670000),
+		CLK_INIT(mclk1_clk_src.c),
+	},
+};
+
+static struct rcg_clk mclk2_clk_src = {
+	.cmd_rcgr_reg =  MCLK2_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_camss_mclk0_2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "mclk2_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOWER, 66670000),
+		CLK_INIT(mclk2_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_csi0_1phytimer_clk[] = {
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 160000000,	gpll0,	5,	0,	0),
+	F( 200000000,	gpll0,	4,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_camss_csi0_1phytimer_clk_8917[] = {
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 160000000,	gpll0,	5,	0,	0),
+	F( 200000000,	gpll0,	4,	0,	0),
+	F( 266670000,	gpll0,	3,	0,	0),
+	F_END
+};
+
+static struct rcg_clk csi0phytimer_clk_src = {
+	.cmd_rcgr_reg = CSI0PHYTIMER_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_camss_csi0_1phytimer_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "csi0phytimer_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOWER, 100000000, LOW, 160000000,
+				  NOMINAL, 200000000),
+		CLK_INIT(csi0phytimer_clk_src.c),
+	},
+};
+
+static struct rcg_clk csi1phytimer_clk_src = {
+	.cmd_rcgr_reg = CSI1PHYTIMER_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_camss_csi0_1phytimer_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "csi1phytimer_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOWER, 100000000, LOW, 160000000,
+				  NOMINAL, 200000000),
+		CLK_INIT(csi1phytimer_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_crypto_clk[] = {
+	F( 50000000,	gpll0,	16,	0,	0),
+	F( 80000000,	gpll0,	10,	0,	0),
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 160000000,	gpll0,	5,	0,	0),
+	F_END
+};
+
+static struct rcg_clk crypto_clk_src = {
+	.cmd_rcgr_reg = CRYPTO_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_crypto_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "crypto_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOWER, 80000000, NOMINAL, 160000000),
+		CLK_INIT(crypto_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_gp1_3_clk[] = {
+	F( 19200000,	xo,	1,	0,	0),
+	F_END
+};
+
+static struct rcg_clk gp1_clk_src = {
+	.cmd_rcgr_reg =  GP1_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_gp1_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gp1_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOWER, 19200000),
+		CLK_INIT(gp1_clk_src.c),
+	},
+};
+
+static struct rcg_clk gp2_clk_src = {
+	.cmd_rcgr_reg =  GP2_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_gp1_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gp2_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOW, 19200000),
+		CLK_INIT(gp2_clk_src.c),
+	},
+};
+
+static struct rcg_clk gp3_clk_src = {
+	.cmd_rcgr_reg =  GP3_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_gp1_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gp3_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOW, 19200000),
+		CLK_INIT(gp3_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_byte0_clk[] = {
+	{
+		.div_src_val = BVAL(10, 8, dsi0_phypll_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &ext_byte0_clk_src.c,
+		.freq_hz = 0,
+	},
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_byte0_clk_8937[] = {
+	{
+		.div_src_val = BVAL(10, 8, xo_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &xo_clk_src.c,
+		.freq_hz = 0,
+	},
+	{
+		.div_src_val = BVAL(10, 8, dsi0_0phypll_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &ext_byte0_clk_src.c,
+		.freq_hz = 0,
+	},
+	{
+		.div_src_val = BVAL(10, 8, dsi1_0phypll_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &ext_byte1_clk_src.c,
+		.freq_hz = 0,
+	},
+	F_END
+};
+
+static struct rcg_clk byte0_clk_src = {
+	.cmd_rcgr_reg = BYTE0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.current_freq = ftbl_gcc_mdss_byte0_clk,
+	.freq_tbl = ftbl_gcc_mdss_byte0_clk,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "byte0_clk_src",
+		.ops = &clk_ops_byte_multiparent,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		VDD_DIG_FMAX_MAP2(LOWER, 120000000, NOMINAL, 187500000),
+		CLK_INIT(byte0_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_byte1_clk[] = {
+	{
+		.div_src_val = BVAL(10, 8, xo_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &xo_clk_src.c,
+		.freq_hz = 0,
+	},
+	{
+		.div_src_val = BVAL(10, 8, dsi1_1phypll_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &ext_byte1_clk_src.c,
+		.freq_hz = 0,
+	},
+	{
+		.div_src_val = BVAL(10, 8, dsi0_1phypll_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &ext_byte0_clk_src.c,
+		.freq_hz = 0,
+	},
+	F_END
+};
+
+static struct rcg_clk byte1_clk_src = {
+		.cmd_rcgr_reg = BYTE1_CMD_RCGR,
+		.set_rate = set_rate_hid,
+		.current_freq = ftbl_gcc_mdss_byte1_clk,
+		.freq_tbl = ftbl_gcc_mdss_byte1_clk,
+		.base = &virt_bases[GCC_BASE],
+		.c = {
+			.dbg_name = "byte1_clk_src",
+			.ops = &clk_ops_byte_multiparent,
+			.flags = CLKFLAG_NO_RATE_CACHE,
+			VDD_DIG_FMAX_MAP2(LOWER, 125000000, NOMINAL, 187500000),
+			CLK_INIT(byte1_clk_src.c),
+		},
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_esc0_clk[] = {
+	F( 19200000,	xo,	1,	0,	0),
+	F_END
+};
+
+static struct rcg_clk esc0_clk_src = {
+	.cmd_rcgr_reg = ESC0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_mdss_esc0_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "esc0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 19200000),
+		CLK_INIT(esc0_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_esc1_clk_src[] = {
+	F(  19200000,             xo,    1,    0,     0),
+	F_END
+};
+
+static struct rcg_clk esc1_clk_src = {
+	.cmd_rcgr_reg = ESC1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_esc1_clk_src,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "esc1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 19200000),
+		CLK_INIT(esc1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_mdp_clk[] = {
+	F( 50000000,	gpll0,	16,	0,	0),
+	F( 80000000,	gpll0,	10,	0,	0),
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 145450000,	gpll0,	5.5,	0,	0),
+	F( 160000000,	gpll0,	5,	0,	0),
+	F( 177780000,	gpll0,	4.5,	0,	0),
+	F( 200000000,	gpll0,	4,	0,	0),
+	F( 266670000,	gpll0,	3,	0,	0),
+	F( 320000000,	gpll0,	2.5,	0,	0),
+	F_END
+};
+
+static struct rcg_clk mdp_clk_src = {
+	.cmd_rcgr_reg = MDP_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_mdss_mdp_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "mdp_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOWER, 160000000, NOMINAL, 266670000,
+				  HIGH, 320000000),
+		CLK_INIT(mdp_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_pclk0_clk[] = {
+	{
+		.div_src_val = BVAL(10, 8, dsi0_phypll_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &ext_pclk0_clk_src.c,
+		.freq_hz = 0,
+	},
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_pclk0_clk_8937[] = {
+	{
+		.div_src_val = BVAL(10, 8, xo_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &xo_clk_src.c,
+		.freq_hz = 0,
+	},
+	{
+		.div_src_val = BVAL(10, 8, dsi0_0phypll_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &ext_pclk0_clk_src.c,
+		.freq_hz = 0,
+	},
+	{
+		.div_src_val = BVAL(10, 8, dsi1_0phypll_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &ext_pclk1_clk_src.c,
+		.freq_hz = 0,
+	},
+	F_END
+};
+
+static struct rcg_clk pclk0_clk_src = {
+	.cmd_rcgr_reg =  PCLK0_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.current_freq = ftbl_gcc_mdss_pclk0_clk,
+	.freq_tbl = ftbl_gcc_mdss_pclk0_clk,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "pclk0_clk_src",
+		.ops = &clk_ops_pixel_multiparent,
+		VDD_DIG_FMAX_MAP2(LOWER, 160000000, NOMINAL, 250000000),
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(pclk0_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_pclk1_clk[] = {
+	{
+		.div_src_val = BVAL(10, 8, xo_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &xo_clk_src.c,
+		.freq_hz = 0,
+	},
+	{
+		.div_src_val = BVAL(10, 8, dsi1_1phypll_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &ext_pclk1_clk_src.c,
+		.freq_hz = 0,
+	},
+	{
+		.div_src_val = BVAL(10, 8, dsi0_1phypll_source_val)
+					| BVAL(4, 0, 0),
+		.src_clk = &ext_pclk0_clk_src.c,
+		.freq_hz = 0,
+	},
+	F_END
+};
+
+static struct rcg_clk pclk1_clk_src = {
+	.cmd_rcgr_reg = PCLK1_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.current_freq = ftbl_gcc_mdss_pclk1_clk,
+	.freq_tbl = ftbl_gcc_mdss_pclk1_clk,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "pclk1_clk_src",
+		.ops = &clk_ops_pixel_multiparent,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		VDD_DIG_FMAX_MAP2(LOWER, 166670000, NOMINAL, 250000000),
+		CLK_INIT(pclk1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_mdss_vsync_clk[] = {
+	F( 19200000,	xo,	1,	0,	0),
+	F_END
+};
+
+static struct rcg_clk vsync_clk_src = {
+	.cmd_rcgr_reg = VSYNC_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_mdss_vsync_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "vsync_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 19200000),
+		CLK_INIT(vsync_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_pdm2_clk[] = {
+	F( 64000000,	gpll0,	12.5,	0,	0),
+	F_END
+};
+
+static struct rcg_clk pdm2_clk_src = {
+	.cmd_rcgr_reg = PDM2_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_pdm2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "pdm2_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOWER, 64000000),
+		CLK_INIT(pdm2_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_sdcc1_apps_clk[] = {
+	F( 144000,	xo,	16,	3,	25),
+	F( 400000,	xo,	12,	1,	4),
+	F( 20000000,	gpll0,	10,	1,	4),
+	F( 25000000,	gpll0,	16,	1,	2),
+	F( 50000000,	gpll0,	16,	0,	0),
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 177770000,	gpll0,	4.5,	0,	0),
+	F( 192000000,	gpll4,	6,	0,	0),
+	F( 200000000,	gpll0,	4,	0,	0),
+	F( 384000000,	gpll4,	3,	0,	0),
+	F_END
+};
+
+static struct rcg_clk sdcc1_apps_clk_src = {
+	.cmd_rcgr_reg =  SDCC1_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_sdcc1_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc1_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 50000000, NOMINAL, 384000000),
+		CLK_INIT(sdcc1_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_sdcc1_ice_core_clk[] = {
+	F( 100000000,	gpll0_out_main,	8,	0,	0),
+	F( 200000000,	gpll0_out_main,	4,	0,	0),
+	F_END
+};
+
+static struct rcg_clk sdcc1_ice_core_clk_src = {
+	.cmd_rcgr_reg =  SDCC1_ICE_CORE_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_sdcc1_ice_core_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc1_ice_core_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 100000000, NOMINAL, 200000000),
+		CLK_INIT(sdcc1_ice_core_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_sdcc2_apps_clk[] = {
+	F( 144000,	xo,	16,	3,	25),
+	F( 400000,	xo,	12,	1,	4),
+	F( 20000000,	gpll0,	10,	1,	4),
+	F( 25000000,	gpll0,	16,	1,	2),
+	F( 50000000,	gpll0,	16,	0,	0),
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 177770000,	gpll0,	4.5,	0,	0),
+	F( 200000000,	gpll0,	4,	0,	0),
+	F_END
+};
+
+static struct rcg_clk sdcc2_apps_clk_src = {
+	.cmd_rcgr_reg =  SDCC2_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_sdcc2_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc2_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOWER, 100000000, NOMINAL, 200000000),
+		CLK_INIT(sdcc2_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_fs_ic_clk[] = {
+	F( 60000000,	gpll6_out_main,	9,	1,	2),
+	F_END
+};
+
+static struct rcg_clk usb_fs_ic_clk_src = {
+	.cmd_rcgr_reg =  USB_FS_IC_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_usb_fs_ic_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_fs_ic_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOWER, 60000000),
+		CLK_INIT(usb_fs_ic_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_fs_system_clk[] = {
+	F( 64000000,	gpll0_out_aux,	12.5,	0,	0),
+	F_END
+};
+
+static struct rcg_clk usb_fs_system_clk_src = {
+	.cmd_rcgr_reg =  USB_FS_SYSTEM_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_usb_fs_system_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_fs_system_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOWER, 64000000),
+		CLK_INIT(usb_fs_system_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hs_system_clk[] = {
+	F( 57140000,	gpll0,	14,	0,	0),
+	F( 100000000,	gpll0,	8,	0,	0),
+	F( 133330000,	gpll0,	6,	0,	0),
+	F( 177780000,	gpll0,	4.5,	0,	0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hs_system_clk_8917[] = {
+	F( 80000000,	gpll0,	 10,	0,	0),
+	F( 100000000,	gpll0,	  8,	0,	0),
+	F( 133330000,	gpll0,	  6,	0,	0),
+	F( 177780000,	gpll0,	4.5,	0,	0),
+	F_END
+};
+
+static struct rcg_clk usb_hs_system_clk_src = {
+	.cmd_rcgr_reg = USB_HS_SYSTEM_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb_hs_system_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_hs_system_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOWER, 57140000, NOMINAL, 133330000,
+				  HIGH, 177780000),
+		CLK_INIT(usb_hs_system_clk_src.c),
+	},
+};
+
+static struct branch_clk gcc_bimc_gpu_clk = {
+	.cbcr_reg = BIMC_GPU_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_bimc_gpu_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_bimc_gpu_clk.c),
+	},
+};
+
+static struct branch_clk gcc_dcc_clk = {
+	.cbcr_reg = DCC_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_dcc_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_dcc_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_blsp1_ahb_clk = {
+	.cbcr_reg = BLSP1_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(10),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_blsp1_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup1_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP1_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup1_i2c_apps_clk",
+		.parent = &blsp1_qup1_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup1_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup1_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP1_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup1_spi_apps_clk",
+		.parent = &blsp1_qup1_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup1_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup2_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP2_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup2_i2c_apps_clk",
+		.parent = &blsp1_qup2_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup2_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup2_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP2_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup2_spi_apps_clk",
+		.parent = &blsp1_qup2_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup2_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup3_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP3_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup3_i2c_apps_clk",
+		.parent = &blsp1_qup3_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup3_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup3_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP3_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup3_spi_apps_clk",
+		.parent = &blsp1_qup3_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup3_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup4_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP4_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup4_i2c_apps_clk",
+		.parent = &blsp1_qup4_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup4_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup4_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP4_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup4_spi_apps_clk",
+		.parent = &blsp1_qup4_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup4_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart1_apps_clk = {
+	.cbcr_reg = BLSP1_UART1_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart1_apps_clk",
+		.parent = &blsp1_uart1_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart1_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart2_apps_clk = {
+	.cbcr_reg = BLSP1_UART2_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart2_apps_clk",
+		.parent = &blsp1_uart2_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart2_apps_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_blsp2_ahb_clk = {
+	.cbcr_reg = BLSP2_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(20),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_blsp2_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup1_i2c_apps_clk = {
+	.cbcr_reg = BLSP2_QUP1_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup1_i2c_apps_clk",
+		.parent = &blsp2_qup1_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup1_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup1_spi_apps_clk = {
+	.cbcr_reg = BLSP2_QUP1_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup1_spi_apps_clk",
+		.parent = &blsp2_qup1_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup1_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup2_i2c_apps_clk = {
+	.cbcr_reg = BLSP2_QUP2_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup2_i2c_apps_clk",
+		.parent = &blsp2_qup2_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup2_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup2_spi_apps_clk = {
+	.cbcr_reg = BLSP2_QUP2_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup2_spi_apps_clk",
+		.parent = &blsp2_qup2_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup2_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup3_i2c_apps_clk = {
+	.cbcr_reg = BLSP2_QUP3_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup3_i2c_apps_clk",
+		.parent = &blsp2_qup3_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup3_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup3_spi_apps_clk = {
+	.cbcr_reg = BLSP2_QUP3_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup3_spi_apps_clk",
+		.parent = &blsp2_qup3_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup3_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup4_i2c_apps_clk = {
+	.cbcr_reg = BLSP2_QUP4_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup4_i2c_apps_clk",
+		.parent = &blsp2_qup4_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup4_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup4_spi_apps_clk = {
+	.cbcr_reg = BLSP2_QUP4_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup4_spi_apps_clk",
+		.parent = &blsp2_qup4_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup4_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_uart1_apps_clk = {
+	.cbcr_reg = BLSP2_UART1_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_uart1_apps_clk",
+		.parent = &blsp2_uart1_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_uart1_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_uart2_apps_clk = {
+	.cbcr_reg = BLSP2_UART2_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_uart2_apps_clk",
+		.parent = &blsp2_uart2_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_uart2_apps_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_boot_rom_ahb_clk = {
+	.cbcr_reg = BOOT_ROM_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(7),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_boot_rom_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_boot_rom_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_cci_ahb_clk = {
+	.cbcr_reg = CAMSS_CCI_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_cci_ahb_clk",
+		.parent = &camss_top_ahb_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_cci_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_cci_clk = {
+	.cbcr_reg = CAMSS_CCI_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_cci_clk",
+		.parent = &cci_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_cci_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_cpp_ahb_clk = {
+	.cbcr_reg = CAMSS_CPP_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_cpp_ahb_clk",
+		.parent = &camss_top_ahb_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_cpp_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_cpp_axi_clk = {
+	.cbcr_reg = CAMSS_CPP_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_cpp_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_cpp_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_cpp_clk = {
+	.cbcr_reg = CAMSS_CPP_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_cpp_clk",
+		.parent = &cpp_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_cpp_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi0_ahb_clk = {
+	.cbcr_reg = CAMSS_CSI0_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi0_ahb_clk",
+		.parent = &camss_top_ahb_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi0_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi0_clk = {
+	.cbcr_reg = CAMSS_CSI0_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi0_clk",
+		.parent = &csi0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi0phy_clk = {
+	.cbcr_reg = CAMSS_CSI0PHY_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi0phy_clk",
+		.parent = &csi0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi0phy_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi0pix_clk = {
+	.cbcr_reg = CAMSS_CSI0PIX_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi0pix_clk",
+		.parent = &csi0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi0pix_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi0rdi_clk = {
+	.cbcr_reg = CAMSS_CSI0RDI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi0rdi_clk",
+		.parent = &csi0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi0rdi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi1_ahb_clk = {
+	.cbcr_reg = CAMSS_CSI1_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi1_ahb_clk",
+		.parent = &camss_top_ahb_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi1_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi1_clk = {
+	.cbcr_reg = CAMSS_CSI1_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi1_clk",
+		.parent = &csi1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi1phy_clk = {
+	.cbcr_reg = CAMSS_CSI1PHY_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi1phy_clk",
+		.parent = &csi1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi1phy_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi1pix_clk = {
+	.cbcr_reg = CAMSS_CSI1PIX_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi1pix_clk",
+		.parent = &csi1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi1pix_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi1rdi_clk = {
+	.cbcr_reg = CAMSS_CSI1RDI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi1rdi_clk",
+		.parent = &csi1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi1rdi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi2_ahb_clk = {
+	.cbcr_reg = CAMSS_CSI2_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi2_ahb_clk",
+		.parent = &camss_top_ahb_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi2_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi2_clk = {
+	.cbcr_reg = CAMSS_CSI2_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi2_clk",
+		.parent = &csi2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi2_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi2phy_clk = {
+	.cbcr_reg = CAMSS_CSI2PHY_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi2phy_clk",
+		.parent = &csi2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi2phy_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi2pix_clk = {
+	.cbcr_reg = CAMSS_CSI2PIX_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi2pix_clk",
+		.parent = &csi2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi2pix_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi2rdi_clk = {
+	.cbcr_reg = CAMSS_CSI2RDI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi2rdi_clk",
+		.parent = &csi2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi2rdi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi_vfe0_clk = {
+	.cbcr_reg = CAMSS_CSI_VFE0_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi_vfe0_clk",
+		.parent = &vfe0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi_vfe0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi_vfe1_clk = {
+	.cbcr_reg = CAMSS_CSI_VFE1_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi_vfe1_clk",
+		.parent = &vfe1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi_vfe1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_gp0_clk = {
+	.cbcr_reg = CAMSS_GP0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_gp0_clk",
+		.parent = &camss_gp0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_gp0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_gp1_clk = {
+	.cbcr_reg = CAMSS_GP1_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_gp1_clk",
+		.parent = &camss_gp1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_gp1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_ispif_ahb_clk = {
+	.cbcr_reg = CAMSS_ISPIF_AHB_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_ispif_ahb_clk",
+		.parent = &camss_top_ahb_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_ispif_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_jpeg0_clk = {
+	.cbcr_reg = CAMSS_JPEG0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_jpeg0_clk",
+		.parent = &jpeg0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_jpeg0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_jpeg_ahb_clk = {
+	.cbcr_reg = CAMSS_JPEG_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_jpeg_ahb_clk",
+		.parent = &camss_top_ahb_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_jpeg_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_jpeg_axi_clk = {
+	.cbcr_reg = CAMSS_JPEG_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_jpeg_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_jpeg_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_mclk0_clk = {
+	.cbcr_reg = CAMSS_MCLK0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_mclk0_clk",
+		.parent = &mclk0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_mclk0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_mclk1_clk = {
+	.cbcr_reg = CAMSS_MCLK1_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_mclk1_clk",
+		.parent = &mclk1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_mclk1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_mclk2_clk = {
+	.cbcr_reg = CAMSS_MCLK2_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_mclk2_clk",
+		.parent = &mclk2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_mclk2_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_micro_ahb_clk = {
+	.cbcr_reg = CAMSS_MICRO_AHB_CBCR,
+	.bcr_reg =  CAMSS_MICRO_BCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_micro_ahb_clk",
+		.parent = &camss_top_ahb_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_micro_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi0phytimer_clk = {
+	.cbcr_reg = CAMSS_CSI0PHYTIMER_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi0phytimer_clk",
+		.parent = &csi0phytimer_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi0phytimer_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_csi1phytimer_clk = {
+	.cbcr_reg = CAMSS_CSI1PHYTIMER_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_csi1phytimer_clk",
+		.parent = &csi1phytimer_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_csi1phytimer_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_ahb_clk = {
+	.cbcr_reg = CAMSS_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_top_ahb_clk = {
+	.cbcr_reg = CAMSS_TOP_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_top_ahb_clk",
+		.parent = &camss_top_ahb_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_top_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_vfe0_clk = {
+	.cbcr_reg = CAMSS_VFE0_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_vfe0_clk",
+		.parent = &vfe0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_vfe0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_vfe_ahb_clk = {
+	.cbcr_reg = CAMSS_VFE_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_vfe_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_vfe_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_vfe_axi_clk = {
+	.cbcr_reg = CAMSS_VFE_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_vfe_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_vfe_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_vfe1_ahb_clk = {
+	.cbcr_reg = CAMSS_VFE1_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_vfe1_ahb_clk",
+		.parent = &camss_top_ahb_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_vfe1_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_vfe1_axi_clk = {
+	.cbcr_reg = CAMSS_VFE1_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_vfe1_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_vfe1_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_camss_vfe1_clk = {
+	.cbcr_reg = CAMSS_VFE1_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_camss_vfe1_clk",
+		.parent = &vfe1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_camss_vfe1_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_crypto_ahb_clk = {
+	.cbcr_reg = CRYPTO_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(0),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_crypto_ahb_clk",
+		.parent = &crypto_clk_src.c,
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_crypto_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_crypto_axi_clk = {
+	.cbcr_reg = CRYPTO_AXI_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(1),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_crypto_axi_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_crypto_axi_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_crypto_clk = {
+	.cbcr_reg = CRYPTO_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(2),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_crypto_clk",
+		.parent = &crypto_clk_src.c,
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_crypto_clk.c),
+	},
+};
+
+static struct gate_clk gcc_oxili_gmem_clk = {
+	.en_reg = OXILI_GMEM_CBCR,
+	.en_mask = BIT(0),
+	.delay_us = 50,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_oxili_gmem_clk",
+		.parent = &gfx3d_clk_src.c,
+		.ops = &clk_ops_gate,
+		CLK_INIT(gcc_oxili_gmem_clk.c),
+	},
+};
+
+static struct branch_clk gcc_gp1_clk = {
+	.cbcr_reg = GP1_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_gp1_clk",
+		.parent = &gp1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_gp1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_gp2_clk = {
+	.cbcr_reg = GP2_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_gp2_clk",
+		.parent = &gp2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_gp2_clk.c),
+	},
+};
+
+static struct branch_clk gcc_gp3_clk = {
+	.cbcr_reg = GP3_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_gp3_clk",
+		.parent = &gp3_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_gp3_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mdss_ahb_clk = {
+	.cbcr_reg = MDSS_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdss_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mdss_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mdss_axi_clk = {
+	.cbcr_reg = MDSS_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdss_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mdss_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mdss_byte0_clk = {
+	.cbcr_reg = MDSS_BYTE0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdss_byte0_clk",
+		.parent = &byte0_clk_src.c,
+		.ops = &clk_ops_branch,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(gcc_mdss_byte0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mdss_byte1_clk = {
+	.cbcr_reg = MDSS_BYTE1_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdss_byte1_clk",
+		.parent = &byte1_clk_src.c,
+		.ops = &clk_ops_branch,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(gcc_mdss_byte1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mdss_esc0_clk = {
+	.cbcr_reg = MDSS_ESC0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdss_esc0_clk",
+		.parent = &esc0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mdss_esc0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mdss_esc1_clk = {
+	.cbcr_reg = MDSS_ESC1_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdss_esc1_clk",
+		.parent = &esc1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mdss_esc1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mdss_mdp_clk = {
+	.cbcr_reg = MDSS_MDP_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdss_mdp_clk",
+		.parent = &mdp_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mdss_mdp_clk.c),
+	},
+};
+
+static DEFINE_CLK_VOTER(mdss_mdp_vote_clk, &gcc_mdss_mdp_clk.c, 0);
+static DEFINE_CLK_VOTER(mdss_rotator_vote_clk, &gcc_mdss_mdp_clk.c, 0);
+
+static struct branch_clk gcc_mdss_pclk0_clk = {
+	.cbcr_reg = MDSS_PCLK0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdss_pclk0_clk",
+		.parent = &pclk0_clk_src.c,
+		.ops = &clk_ops_branch,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(gcc_mdss_pclk0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mdss_pclk1_clk = {
+	.cbcr_reg = MDSS_PCLK1_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdss_pclk1_clk",
+		.parent = &pclk1_clk_src.c,
+		.ops = &clk_ops_branch,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(gcc_mdss_pclk1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mdss_vsync_clk = {
+	.cbcr_reg = MDSS_VSYNC_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdss_vsync_clk",
+		.parent = &vsync_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mdss_vsync_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mss_cfg_ahb_clk = {
+	.cbcr_reg = MSS_CFG_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mss_cfg_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mss_cfg_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mss_q6_bimc_axi_clk = {
+	.cbcr_reg = MSS_Q6_BIMC_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mss_q6_bimc_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mss_q6_bimc_axi_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_apss_tcu_clk;
+static struct branch_clk gcc_bimc_gfx_clk = {
+	.cbcr_reg = BIMC_GFX_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_bimc_gfx_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_bimc_gfx_clk.c),
+		.depends = &gcc_apss_tcu_clk.c,
+	},
+};
+
+static struct branch_clk gcc_oxili_ahb_clk = {
+	.cbcr_reg = OXILI_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_oxili_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_oxili_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_oxili_gfx3d_clk = {
+	.cbcr_reg = OXILI_GFX3D_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_oxili_gfx3d_clk",
+		.parent = &gfx3d_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_oxili_gfx3d_clk.c),
+	},
+};
+
+static struct branch_clk gcc_oxili_timer_clk = {
+	.cbcr_reg = OXILI_TIMER_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_oxili_timer_clk",
+		.parent = &xo_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_oxili_timer_clk.c),
+	},
+};
+
+static struct branch_clk gcc_oxili_aon_clk = {
+	.cbcr_reg = OXILI_AON_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_oxili_aon_clk",
+		.parent = &gfx3d_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_oxili_aon_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pdm2_clk = {
+	.cbcr_reg = PDM2_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pdm2_clk",
+		.parent = &pdm2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pdm2_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pdm_ahb_clk = {
+	.cbcr_reg = PDM_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pdm_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pdm_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_prng_ahb_clk = {
+	.cbcr_reg = PRNG_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(8),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_prng_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_prng_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_qdss_dap_clk = {
+	.cbcr_reg = QDSS_DAP_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(21),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_qdss_dap_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_qdss_dap_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc1_ahb_clk = {
+	.cbcr_reg = SDCC1_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc1_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc1_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc1_apps_clk = {
+	.cbcr_reg = SDCC1_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc1_apps_clk",
+		.parent = &sdcc1_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc1_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc1_ice_core_clk = {
+	.cbcr_reg = SDCC1_ICE_CORE_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc1_ice_core_clk",
+		.parent = &sdcc1_ice_core_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc1_ice_core_clk.c),
+	}
+};
+
+static struct branch_clk gcc_sdcc2_ahb_clk = {
+	.cbcr_reg = SDCC2_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc2_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc2_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc2_apps_clk = {
+	.cbcr_reg = SDCC2_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc2_apps_clk",
+		.parent = &sdcc2_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc2_apps_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_cpp_tbu_clk = {
+	.cbcr_reg = CPP_TBU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(14),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_cpp_tbu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_cpp_tbu_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_gfx_tbu_clk = {
+	.cbcr_reg = GFX_TBU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(3),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_gfx_tbu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_gfx_tbu_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_gfx_tcu_clk = {
+	.cbcr_reg = GFX_TCU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(2),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_gfx_tcu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_gfx_tcu_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_apss_tcu_clk = {
+	.cbcr_reg = APSS_TCU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(1),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_apss_tcu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_apss_tcu_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_gtcu_ahb_clk = {
+	.cbcr_reg = GTCU_AHB_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(13),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_gtcu_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_gtcu_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_ipa_tbu_clk = {
+	.cbcr_reg = IPA_TBU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(16),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_ipa_tbu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_ipa_tbu_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_jpeg_tbu_clk = {
+	.cbcr_reg = JPEG_TBU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(10),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_jpeg_tbu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_jpeg_tbu_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_mdp_tbu_clk = {
+	.cbcr_reg = MDP_TBU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(4),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mdp_tbu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_mdp_tbu_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_smmu_cfg_clk = {
+	.cbcr_reg = SMMU_CFG_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(12),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_smmu_cfg_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_smmu_cfg_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_venus_tbu_clk = {
+	.cbcr_reg = VENUS_TBU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(5),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_venus_tbu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_venus_tbu_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_vfe1_tbu_clk = {
+	.cbcr_reg = VFE1_TBU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(17),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_vfe1_tbu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_vfe1_tbu_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_vfe_tbu_clk = {
+	.cbcr_reg = VFE_TBU_CBCR,
+	.vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(9),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_vfe_tbu_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_vfe_tbu_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb2a_phy_sleep_clk = {
+	.cbcr_reg = USB2A_PHY_SLEEP_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb2a_phy_sleep_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb2a_phy_sleep_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hs_phy_cfg_ahb_clk = {
+	.cbcr_reg = USB_HS_PHY_CFG_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hs_phy_cfg_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hs_phy_cfg_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_fs_ahb_clk = {
+	.cbcr_reg = USB_FS_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_fs_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_fs_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_fs_ic_clk = {
+	.cbcr_reg = USB_FS_IC_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_fs_ic_clk",
+		.parent = &usb_fs_ic_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_fs_ic_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_fs_system_clk = {
+	.cbcr_reg = USB_FS_SYSTEM_CBCR,
+	.bcr_reg  = USB_FS_BCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_fs_system_clk",
+		.parent = &usb_fs_system_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_fs_system_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hs_ahb_clk = {
+	.cbcr_reg = USB_HS_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hs_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hs_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hs_system_clk = {
+	.cbcr_reg = USB_HS_SYSTEM_CBCR,
+	.bcr_reg = USB_HS_BCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hs_system_clk",
+		.parent = &usb_hs_system_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hs_system_clk.c),
+	},
+};
+
+static struct reset_clk gcc_usb2_hs_phy_only_clk = {
+	.reset_reg = USB2_HS_PHY_ONLY_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb2_hs_phy_only_clk",
+		.ops = &clk_ops_rst,
+		CLK_INIT(gcc_usb2_hs_phy_only_clk.c),
+	},
+};
+
+static struct reset_clk gcc_qusb2_phy_clk = {
+	.reset_reg = QUSB2_PHY_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_qusb2_phy_clk",
+		.ops = &clk_ops_rst,
+		CLK_INIT(gcc_qusb2_phy_clk.c),
+	},
+};
+
+static struct branch_clk gcc_venus0_ahb_clk = {
+	.cbcr_reg = VENUS0_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_venus0_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_venus0_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_venus0_axi_clk = {
+	.cbcr_reg = VENUS0_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_venus0_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_venus0_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_venus0_core0_vcodec0_clk = {
+	.cbcr_reg = VENUS0_CORE0_VCODEC0_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_venus0_core0_vcodec0_clk",
+		.parent = &vcodec0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_venus0_core0_vcodec0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_venus0_core1_vcodec0_clk = {
+	.cbcr_reg = VENUS0_CORE1_VCODEC0_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_venus0_core1_vcodec0_clk",
+		.parent = &vcodec0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_venus0_core1_vcodec0_clk.c),
+	},
+};
+
+static struct branch_clk gcc_venus0_vcodec0_clk = {
+	.cbcr_reg = VENUS0_VCODEC0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_venus0_vcodec0_clk",
+		.parent = &vcodec0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_venus0_vcodec0_clk.c),
+	},
+};
+
+static struct clk_ops clk_ops_debug_mux;
+
+static void __iomem *meas_base;
+
+static struct measure_clk apc0_m_clk = {
+	.c = {
+		.ops = &clk_ops_empty,
+		.dbg_name = "apc0_m_clk",
+		CLK_INIT(apc0_m_clk.c),
+	},
+};
+
+static struct measure_clk apc1_m_clk = {
+	.c = {
+		.ops = &clk_ops_empty,
+		.dbg_name = "apc1_m_clk",
+		CLK_INIT(apc1_m_clk.c),
+	},
+};
+
+static struct measure_clk cci_m_clk = {
+	.c = {
+		.ops = &clk_ops_empty,
+		.dbg_name = "cci_m_clk",
+		CLK_INIT(cci_m_clk.c),
+	},
+};
+
+static struct mux_clk apss_debug_ter_mux = {
+	.ops = &mux_reg_ops,
+	.mask = 0x3,
+	.shift = 8,
+	MUX_SRC_LIST(
+		{&apc0_m_clk.c, 0},
+		{&apc1_m_clk.c, 1},
+		{&cci_m_clk.c, 2},
+	),
+	.base = &meas_base,
+	.c = {
+		.dbg_name = "apss_debug_ter_mux",
+		.ops = &clk_ops_gen_mux,
+		CLK_INIT(apss_debug_ter_mux.c),
+	},
+};
+
+static struct mux_clk apss_debug_sec_mux = {
+	.ops = &mux_reg_ops,
+	.mask = 0x7,
+	.shift = 12,
+	MUX_SRC_LIST(
+		{&apss_debug_ter_mux.c, 0},
+	),
+	MUX_REC_SRC_LIST(
+		&apss_debug_ter_mux.c,
+	),
+	.base = &meas_base,
+	.c = {
+		.dbg_name = "apss_debug_sec_mux",
+		.ops = &clk_ops_gen_mux,
+		CLK_INIT(apss_debug_sec_mux.c),
+	},
+};
+
+static struct mux_clk apss_debug_pri_mux = {
+	.ops = &mux_reg_ops,
+	.mask = 0x3,
+	.shift = 16,
+	MUX_SRC_LIST(
+		{&apss_debug_sec_mux.c, 0},
+	),
+	MUX_REC_SRC_LIST(
+		&apss_debug_sec_mux.c,
+	),
+	.base = &meas_base,
+	.c = {
+		.dbg_name = "apss_debug_pri_mux",
+		.ops = &clk_ops_gen_mux,
+		CLK_INIT(apss_debug_pri_mux.c),
+	},
+};
+
+static struct measure_clk_data debug_mux_priv = {
+	.cxo = &xo_clk_src.c,
+	.plltest_reg = GCC_PLLTEST_PAD_CFG,
+	.plltest_val = 0x51A00,
+	.xo_div4_cbcr = GCC_XO_DIV4_CBCR,
+	.ctl_reg = CLOCK_FRQ_MEASURE_CTL,
+	.status_reg = CLOCK_FRQ_MEASURE_STATUS,
+	.base = &virt_bases[GCC_BASE],
+};
+
+static struct mux_clk gcc_debug_mux = {
+	.priv = &debug_mux_priv,
+	.ops = &mux_reg_ops,
+	.offset = GCC_DEBUG_CLK_CTL,
+	.mask = 0x1FF,
+	.en_offset = GCC_DEBUG_CLK_CTL,
+	.en_mask = BIT(16),
+	.base = &virt_bases[GCC_BASE],
+	MUX_REC_SRC_LIST(
+		&apss_debug_pri_mux.c,
+	),
+	MUX_SRC_LIST(
+		{ &apss_debug_pri_mux.c, 0x016A},
+		{ &snoc_clk.c,  0x0000 },
+		{ &sysmmnoc_clk.c,  0x0001 },
+		{ &pnoc_clk.c, 0x0008 },
+		{ &bimc_clk.c,  0x0154 },
+		{ &gcc_gp1_clk.c, 0x0010 },
+		{ &gcc_gp2_clk.c, 0x0011 },
+		{ &gcc_gp3_clk.c, 0x0012 },
+		{ &gcc_bimc_gfx_clk.c, 0x002d },
+		{ &gcc_mss_cfg_ahb_clk.c, 0x0030 },
+		{ &gcc_mss_q6_bimc_axi_clk.c, 0x0031 },
+		{ &gcc_apss_tcu_clk.c, 0x0050 },
+		{ &gcc_mdp_tbu_clk.c, 0x0051 },
+		{ &gcc_gfx_tbu_clk.c, 0x0052 },
+		{ &gcc_gfx_tcu_clk.c, 0x0053 },
+		{ &gcc_venus_tbu_clk.c, 0x0054 },
+		{ &gcc_gtcu_ahb_clk.c, 0x0058 },
+		{ &gcc_vfe_tbu_clk.c, 0x005a },
+		{ &gcc_smmu_cfg_clk.c, 0x005b },
+		{ &gcc_jpeg_tbu_clk.c, 0x005c },
+		{ &gcc_usb_hs_system_clk.c, 0x0060 },
+		{ &gcc_usb_hs_ahb_clk.c, 0x0061 },
+		{ &gcc_usb2a_phy_sleep_clk.c, 0x0063 },
+		{ &gcc_usb_hs_phy_cfg_ahb_clk.c, 0x0064 },
+		{ &gcc_sdcc1_apps_clk.c, 0x0068 },
+		{ &gcc_sdcc1_ahb_clk.c, 0x0069 },
+		{ &gcc_sdcc1_ice_core_clk.c, 0x006a },
+		{ &gcc_sdcc2_apps_clk.c, 0x0070 },
+		{ &gcc_sdcc2_ahb_clk.c, 0x0071 },
+		{ &gcc_blsp1_ahb_clk.c, 0x0088 },
+		{ &gcc_blsp1_qup1_spi_apps_clk.c, 0x008a },
+		{ &gcc_blsp1_qup1_i2c_apps_clk.c, 0x008b },
+		{ &gcc_blsp1_uart1_apps_clk.c, 0x008c },
+		{ &gcc_blsp1_qup2_spi_apps_clk.c, 0x008e },
+		{ &gcc_blsp1_qup2_i2c_apps_clk.c, 0x0090 },
+		{ &gcc_blsp1_uart2_apps_clk.c, 0x0091 },
+		{ &gcc_blsp1_qup3_spi_apps_clk.c, 0x0093 },
+		{ &gcc_blsp1_qup3_i2c_apps_clk.c, 0x0094 },
+		{ &gcc_blsp1_qup4_spi_apps_clk.c, 0x0095 },
+		{ &gcc_blsp1_qup4_i2c_apps_clk.c, 0x0096 },
+		{ &gcc_blsp2_ahb_clk.c, 0x0098 },
+		{ &gcc_blsp2_qup1_spi_apps_clk.c, 0x009a },
+		{ &gcc_blsp2_qup1_i2c_apps_clk.c, 0x009b },
+		{ &gcc_blsp2_uart1_apps_clk.c, 0x009c },
+		{ &gcc_blsp2_qup2_spi_apps_clk.c, 0x009e },
+		{ &gcc_blsp2_qup2_i2c_apps_clk.c, 0x00a0 },
+		{ &gcc_blsp2_uart2_apps_clk.c, 0x00a1 },
+		{ &gcc_blsp2_qup3_spi_apps_clk.c, 0x00a3 },
+		{ &gcc_blsp2_qup3_i2c_apps_clk.c, 0x00a4 },
+		{ &gcc_blsp2_qup4_spi_apps_clk.c, 0x00a5 },
+		{ &gcc_blsp2_qup4_i2c_apps_clk.c, 0x00a6 },
+		{ &gcc_camss_ahb_clk.c, 0x00a8 },
+		{ &gcc_camss_top_ahb_clk.c, 0x00a9 },
+		{ &gcc_camss_micro_ahb_clk.c, 0x00aa },
+		{ &gcc_camss_gp0_clk.c, 0x00ab },
+		{ &gcc_camss_gp1_clk.c, 0x00ac },
+		{ &gcc_camss_mclk0_clk.c, 0x00ad },
+		{ &gcc_camss_mclk1_clk.c, 0x00ae },
+		{ &gcc_camss_cci_clk.c, 0x00af },
+		{ &gcc_camss_cci_ahb_clk.c, 0x00b0 },
+		{ &gcc_camss_csi0phytimer_clk.c, 0x00b1 },
+		{ &gcc_camss_csi1phytimer_clk.c, 0x00b2 },
+		{ &gcc_camss_jpeg0_clk.c, 0x00b3 },
+		{ &gcc_camss_jpeg_ahb_clk.c, 0x00b4 },
+		{ &gcc_camss_jpeg_axi_clk.c, 0x00b5 },
+		{ &gcc_camss_vfe0_clk.c, 0x00b8 },
+		{ &gcc_camss_cpp_clk.c, 0x00b9 },
+		{ &gcc_camss_cpp_ahb_clk.c, 0x00ba },
+		{ &gcc_camss_vfe_ahb_clk.c, 0x00bb },
+		{ &gcc_camss_vfe_axi_clk.c, 0x00bc },
+		{ &gcc_camss_csi_vfe0_clk.c, 0x00bf },
+		{ &gcc_camss_csi0_clk.c, 0x00c0 },
+		{ &gcc_camss_csi0_ahb_clk.c, 0x00c1 },
+		{ &gcc_camss_csi0phy_clk.c, 0x00c2 },
+		{ &gcc_camss_csi0rdi_clk.c, 0x00c3 },
+		{ &gcc_camss_csi0pix_clk.c, 0x00c4 },
+		{ &gcc_camss_csi1_clk.c, 0x00c5 },
+		{ &gcc_camss_csi1_ahb_clk.c, 0x00c6 },
+		{ &gcc_camss_csi1phy_clk.c, 0x00c7 },
+		{ &gcc_pdm_ahb_clk.c, 0x00d0 },
+		{ &gcc_pdm2_clk.c, 0x00d2 },
+		{ &gcc_prng_ahb_clk.c, 0x00d8 },
+		{ &gcc_camss_csi1rdi_clk.c, 0x00e0 },
+		{ &gcc_camss_csi1pix_clk.c, 0x00e1 },
+		{ &gcc_camss_ispif_ahb_clk.c, 0x00e2 },
+		{ &gcc_camss_csi2_clk.c, 0x00e3 },
+		{ &gcc_camss_csi2_ahb_clk.c, 0x00e4 },
+		{ &gcc_camss_csi2phy_clk.c, 0x00e5 },
+		{ &gcc_camss_csi2rdi_clk.c, 0x00e6 },
+		{ &gcc_camss_csi2pix_clk.c, 0x00e7 },
+		{ &gcc_cpp_tbu_clk.c, 0x00e9 },
+		{ &gcc_boot_rom_ahb_clk.c, 0x00f8 },
+		{ &gcc_usb_fs_ahb_clk.c, 0x00f1 },
+		{ &gcc_usb_fs_ic_clk.c, 0x00f4 },
+		{ &gcc_crypto_clk.c, 0x0138 },
+		{ &gcc_crypto_axi_clk.c, 0x0139 },
+		{ &gcc_crypto_ahb_clk.c, 0x013a },
+		{ &gcc_bimc_gpu_clk.c, 0x0157 },
+		{ &gcc_ipa_tbu_clk.c, 0x0198 },
+		{ &gcc_vfe1_tbu_clk.c, 0x0199 },
+		{ &gcc_camss_csi_vfe1_clk.c, 0x01a0 },
+		{ &gcc_camss_vfe1_clk.c, 0x01a1 },
+		{ &gcc_camss_vfe1_ahb_clk.c, 0x01a2 },
+		{ &gcc_camss_vfe1_axi_clk.c, 0x01a3 },
+		{ &gcc_venus0_core0_vcodec0_clk.c, 0x01b8 },
+		{ &gcc_venus0_core1_vcodec0_clk.c, 0x01b9 },
+		{ &gcc_camss_mclk2_clk.c, 0x01bd },
+		{ &gcc_oxili_timer_clk.c, 0x01e9 },
+		{ &gcc_oxili_gfx3d_clk.c, 0x01ea },
+		{ &gcc_oxili_ahb_clk.c, 0x01eb },
+		{ &gcc_oxili_gmem_clk.c, 0x01f0 },
+		{ &gcc_venus0_vcodec0_clk.c, 0x01f1 },
+		{ &gcc_venus0_axi_clk.c, 0x01f2 },
+		{ &gcc_venus0_ahb_clk.c, 0x01f3 },
+		{ &gcc_mdss_ahb_clk.c, 0x01f6 },
+		{ &gcc_mdss_axi_clk.c, 0x01f7 },
+		{ &gcc_mdss_pclk0_clk.c, 0x01f8 },
+		{ &gcc_mdss_mdp_clk.c, 0x01f9 },
+		{ &gcc_mdss_vsync_clk.c, 0x01fb },
+		{ &gcc_mdss_byte0_clk.c, 0x01fc },
+		{ &gcc_mdss_esc0_clk.c, 0x01fd },
+		{ &wcnss_m_clk.c, 0x0ec },
+	),
+	.c = {
+		.dbg_name = "gcc_debug_mux",
+		.ops = &clk_ops_debug_mux,
+		.flags = CLKFLAG_NO_RATE_CACHE | CLKFLAG_MEASURE,
+		CLK_INIT(gcc_debug_mux.c),
+	},
+};
+
+static struct mux_clk gcc_debug_mux_8937 = {
+	.priv = &debug_mux_priv,
+	.ops = &mux_reg_ops,
+	.offset = GCC_DEBUG_CLK_CTL,
+	.mask = 0x1FF,
+	.en_offset = GCC_DEBUG_CLK_CTL,
+	.en_mask = BIT(16),
+	.base = &virt_bases[GCC_BASE],
+	MUX_REC_SRC_LIST(
+		&apss_debug_pri_mux.c,
+	),
+	MUX_SRC_LIST(
+		{ &apss_debug_pri_mux.c, 0x016A},
+		{ &snoc_clk.c,  0x0000 },
+		{ &sysmmnoc_clk.c,  0x0001 },
+		{ &pnoc_clk.c, 0x0008 },
+		{ &bimc_clk.c,  0x015A },
+		{ &ipa_clk.c, 0x1B0 },
+		{ &gcc_gp1_clk.c, 0x0010 },
+		{ &gcc_gp2_clk.c, 0x0011 },
+		{ &gcc_gp3_clk.c, 0x0012 },
+		{ &gcc_bimc_gfx_clk.c, 0x002d },
+		{ &gcc_mss_cfg_ahb_clk.c, 0x0030 },
+		{ &gcc_mss_q6_bimc_axi_clk.c, 0x0031 },
+		{ &gcc_qdss_dap_clk.c, 0x0049 },
+		{ &gcc_apss_tcu_clk.c, 0x0050 },
+		{ &gcc_mdp_tbu_clk.c, 0x0051 },
+		{ &gcc_gfx_tbu_clk.c, 0x0052 },
+		{ &gcc_gfx_tcu_clk.c, 0x0053 },
+		{ &gcc_venus_tbu_clk.c, 0x0054 },
+		{ &gcc_gtcu_ahb_clk.c, 0x0058 },
+		{ &gcc_vfe_tbu_clk.c, 0x005a },
+		{ &gcc_smmu_cfg_clk.c, 0x005b },
+		{ &gcc_jpeg_tbu_clk.c, 0x005c },
+		{ &gcc_usb_hs_system_clk.c, 0x0060 },
+		{ &gcc_usb_hs_ahb_clk.c, 0x0061 },
+		{ &gcc_usb2a_phy_sleep_clk.c, 0x0063 },
+		{ &gcc_usb_hs_phy_cfg_ahb_clk.c, 0x0064 },
+		{ &gcc_sdcc1_apps_clk.c, 0x0068 },
+		{ &gcc_sdcc1_ahb_clk.c, 0x0069 },
+		{ &gcc_sdcc1_ice_core_clk.c, 0x006a },
+		{ &gcc_sdcc2_apps_clk.c, 0x0070 },
+		{ &gcc_sdcc2_ahb_clk.c, 0x0071 },
+		{ &gcc_blsp1_ahb_clk.c, 0x0088 },
+		{ &gcc_blsp1_qup1_spi_apps_clk.c, 0x008a },
+		{ &gcc_blsp1_qup1_i2c_apps_clk.c, 0x008b },
+		{ &gcc_blsp1_uart1_apps_clk.c, 0x008c },
+		{ &gcc_blsp1_qup2_spi_apps_clk.c, 0x008e },
+		{ &gcc_blsp1_qup2_i2c_apps_clk.c, 0x0090 },
+		{ &gcc_blsp1_uart2_apps_clk.c, 0x0091 },
+		{ &gcc_blsp1_qup3_spi_apps_clk.c, 0x0093 },
+		{ &gcc_blsp1_qup3_i2c_apps_clk.c, 0x0094 },
+		{ &gcc_blsp1_qup4_spi_apps_clk.c, 0x0095 },
+		{ &gcc_blsp1_qup4_i2c_apps_clk.c, 0x0096 },
+		{ &gcc_blsp2_ahb_clk.c, 0x0098 },
+		{ &gcc_blsp2_qup1_spi_apps_clk.c, 0x009a },
+		{ &gcc_blsp2_qup1_i2c_apps_clk.c, 0x009b },
+		{ &gcc_blsp2_uart1_apps_clk.c, 0x009c },
+		{ &gcc_blsp2_qup2_spi_apps_clk.c, 0x009e },
+		{ &gcc_blsp2_qup2_i2c_apps_clk.c, 0x00a0 },
+		{ &gcc_blsp2_uart2_apps_clk.c, 0x00a1 },
+		{ &gcc_blsp2_qup3_spi_apps_clk.c, 0x00a3 },
+		{ &gcc_blsp2_qup3_i2c_apps_clk.c, 0x00a4 },
+		{ &gcc_blsp2_qup4_spi_apps_clk.c, 0x00a5 },
+		{ &gcc_blsp2_qup4_i2c_apps_clk.c, 0x00a6 },
+		{ &gcc_camss_ahb_clk.c, 0x00a8 },
+		{ &gcc_camss_top_ahb_clk.c, 0x00a9 },
+		{ &gcc_camss_micro_ahb_clk.c, 0x00aa },
+		{ &gcc_camss_gp0_clk.c, 0x00ab },
+		{ &gcc_camss_gp1_clk.c, 0x00ac },
+		{ &gcc_camss_mclk0_clk.c, 0x00ad },
+		{ &gcc_camss_mclk1_clk.c, 0x00ae },
+		{ &gcc_camss_cci_clk.c, 0x00af },
+		{ &gcc_camss_cci_ahb_clk.c, 0x00b0 },
+		{ &gcc_camss_csi0phytimer_clk.c, 0x00b1 },
+		{ &gcc_camss_csi1phytimer_clk.c, 0x00b2 },
+		{ &gcc_camss_jpeg0_clk.c, 0x00b3 },
+		{ &gcc_camss_jpeg_ahb_clk.c, 0x00b4 },
+		{ &gcc_camss_jpeg_axi_clk.c, 0x00b5 },
+		{ &gcc_camss_vfe0_clk.c, 0x00b8 },
+		{ &gcc_camss_cpp_clk.c, 0x00b9 },
+		{ &gcc_camss_cpp_ahb_clk.c, 0x00ba },
+		{ &gcc_camss_vfe_ahb_clk.c, 0x00bb },
+		{ &gcc_camss_vfe_axi_clk.c, 0x00bc },
+		{ &gcc_camss_csi_vfe0_clk.c, 0x00bf },
+		{ &gcc_camss_csi0_clk.c, 0x00c0 },
+		{ &gcc_camss_csi0_ahb_clk.c, 0x00c1 },
+		{ &gcc_camss_csi0phy_clk.c, 0x00c2 },
+		{ &gcc_camss_csi0rdi_clk.c, 0x00c3 },
+		{ &gcc_camss_csi0pix_clk.c, 0x00c4 },
+		{ &gcc_camss_csi1_clk.c, 0x00c5 },
+		{ &gcc_camss_csi1_ahb_clk.c, 0x00c6 },
+		{ &gcc_camss_csi1phy_clk.c, 0x00c7 },
+		{ &gcc_pdm_ahb_clk.c, 0x00d0 },
+		{ &gcc_pdm2_clk.c, 0x00d2 },
+		{ &gcc_prng_ahb_clk.c, 0x00d8 },
+		{ &gcc_camss_csi1rdi_clk.c, 0x00e0 },
+		{ &gcc_camss_csi1pix_clk.c, 0x00e1 },
+		{ &gcc_camss_ispif_ahb_clk.c, 0x00e2 },
+		{ &gcc_camss_csi2_clk.c, 0x00e3 },
+		{ &gcc_camss_csi2_ahb_clk.c, 0x00e4 },
+		{ &gcc_camss_csi2phy_clk.c, 0x00e5 },
+		{ &gcc_camss_csi2rdi_clk.c, 0x00e6 },
+		{ &gcc_camss_csi2pix_clk.c, 0x00e7 },
+		{ &gcc_cpp_tbu_clk.c, 0x00e9 },
+		{ &gcc_boot_rom_ahb_clk.c, 0x00f8 },
+		{ &gcc_crypto_clk.c, 0x0138 },
+		{ &gcc_crypto_axi_clk.c, 0x0139 },
+		{ &gcc_crypto_ahb_clk.c, 0x013a },
+		{ &gcc_bimc_gpu_clk.c, 0x0157 },
+		{ &gcc_ipa_tbu_clk.c, 0x0198 },
+		{ &gcc_vfe1_tbu_clk.c, 0x0199 },
+		{ &gcc_camss_csi_vfe1_clk.c, 0x01a0 },
+		{ &gcc_camss_vfe1_clk.c, 0x01a1 },
+		{ &gcc_camss_vfe1_ahb_clk.c, 0x01a2 },
+		{ &gcc_camss_vfe1_axi_clk.c, 0x01a3 },
+		{ &gcc_camss_cpp_axi_clk.c, 0x01a4 },
+		{ &gcc_venus0_core0_vcodec0_clk.c, 0x01b8 },
+		{ &gcc_dcc_clk.c, 0x01b9 },
+		{ &gcc_camss_mclk2_clk.c, 0x01bd },
+		{ &gcc_oxili_timer_clk.c, 0x01e9 },
+		{ &gcc_oxili_gfx3d_clk.c, 0x01ea },
+		{ &gcc_oxili_aon_clk.c, 0x00ee },
+		{ &gcc_oxili_ahb_clk.c, 0x01eb },
+		{ &gcc_venus0_vcodec0_clk.c, 0x01f1 },
+		{ &gcc_venus0_axi_clk.c, 0x01f2 },
+		{ &gcc_venus0_ahb_clk.c, 0x01f3 },
+		{ &gcc_mdss_ahb_clk.c, 0x01f6 },
+		{ &gcc_mdss_axi_clk.c, 0x01f7 },
+		{ &gcc_mdss_pclk0_clk.c, 0x01f8 },
+		{ &gcc_mdss_pclk1_clk.c, 0x01e3 },
+		{ &gcc_mdss_mdp_clk.c, 0x01f9 },
+		{ &gcc_mdss_vsync_clk.c, 0x01fb },
+		{ &gcc_mdss_byte0_clk.c, 0x01fc },
+		{ &gcc_mdss_byte1_clk.c, 0x01e4 },
+		{ &gcc_mdss_esc0_clk.c, 0x01fd },
+		{ &gcc_mdss_esc1_clk.c, 0x01e5 },
+		{ &wcnss_m_clk.c, 0x0ec },
+	),
+	.c = {
+		.dbg_name = "gcc_debug_mux_8937",
+		.ops = &clk_ops_debug_mux,
+		.flags = CLKFLAG_NO_RATE_CACHE | CLKFLAG_MEASURE,
+		CLK_INIT(gcc_debug_mux_8937.c),
+	},
+};
+
+/* Clock lookup */
+static struct clk_lookup msm_clocks_lookup_common[] = {
+	/* RPM clocks */
+	CLK_LIST(xo_clk_src),
+	CLK_LIST(xo_a_clk_src),
+	CLK_LIST(xo_otg_clk),
+	CLK_LIST(xo_lpm_clk),
+	CLK_LIST(xo_pil_mss_clk),
+	CLK_LIST(xo_pil_pronto_clk),
+	CLK_LIST(xo_wlan_clk),
+	CLK_LIST(xo_pil_lpass_clk),
+
+	CLK_LIST(sysmmnoc_msmbus_clk),
+	CLK_LIST(snoc_msmbus_clk),
+	CLK_LIST(snoc_msmbus_a_clk),
+	CLK_LIST(sysmmnoc_msmbus_a_clk),
+	CLK_LIST(pnoc_msmbus_clk),
+	CLK_LIST(pnoc_msmbus_a_clk),
+	CLK_LIST(bimc_msmbus_clk),
+	CLK_LIST(bimc_msmbus_a_clk),
+	CLK_LIST(pnoc_keepalive_a_clk),
+
+	CLK_LIST(pnoc_usb_a_clk),
+	CLK_LIST(snoc_usb_a_clk),
+	CLK_LIST(bimc_usb_a_clk),
+	CLK_LIST(pnoc_usb_clk),
+	CLK_LIST(snoc_usb_clk),
+	CLK_LIST(bimc_usb_clk),
+
+	CLK_LIST(snoc_wcnss_a_clk),
+	CLK_LIST(bimc_wcnss_a_clk),
+
+	CLK_LIST(qdss_clk),
+	CLK_LIST(qdss_a_clk),
+
+	CLK_LIST(snoc_clk),
+	CLK_LIST(sysmmnoc_clk),
+	CLK_LIST(pnoc_clk),
+	CLK_LIST(bimc_clk),
+	CLK_LIST(snoc_a_clk),
+	CLK_LIST(sysmmnoc_a_clk),
+	CLK_LIST(pnoc_a_clk),
+	CLK_LIST(bimc_a_clk),
+
+	CLK_LIST(bb_clk1),
+	CLK_LIST(bb_clk1_a),
+	CLK_LIST(bb_clk2),
+	CLK_LIST(bb_clk2_a),
+	CLK_LIST(rf_clk2),
+	CLK_LIST(rf_clk2_a),
+	CLK_LIST(div_clk2),
+	CLK_LIST(div_clk2_a),
+
+	CLK_LIST(bb_clk1_pin),
+	CLK_LIST(bb_clk1_a_pin),
+	CLK_LIST(bb_clk2_pin),
+	CLK_LIST(bb_clk2_a_pin),
+
+	CLK_LIST(gpll0_clk_src),
+	CLK_LIST(gpll0_ao_clk_src),
+	CLK_LIST(gpll6_clk_src),
+	CLK_LIST(gpll4_clk_src),
+	CLK_LIST(gpll3_clk_src),
+	CLK_LIST(a53ss_c1_pll),
+	CLK_LIST(gcc_blsp1_ahb_clk),
+	CLK_LIST(gcc_blsp2_ahb_clk),
+	CLK_LIST(gcc_boot_rom_ahb_clk),
+	CLK_LIST(gcc_crypto_ahb_clk),
+	CLK_LIST(gcc_crypto_axi_clk),
+	CLK_LIST(gcc_crypto_clk),
+	CLK_LIST(gcc_prng_ahb_clk),
+	CLK_LIST(gcc_cpp_tbu_clk),
+	CLK_LIST(gcc_apss_tcu_clk),
+	CLK_LIST(gcc_jpeg_tbu_clk),
+	CLK_LIST(gcc_mdp_tbu_clk),
+	CLK_LIST(gcc_smmu_cfg_clk),
+	CLK_LIST(gcc_venus_tbu_clk),
+	CLK_LIST(gcc_vfe1_tbu_clk),
+	CLK_LIST(gcc_vfe_tbu_clk),
+	CLK_LIST(camss_top_ahb_clk_src),
+	CLK_LIST(apss_ahb_clk_src),
+	CLK_LIST(csi0_clk_src),
+	CLK_LIST(csi1_clk_src),
+	CLK_LIST(csi2_clk_src),
+	CLK_LIST(vcodec0_clk_src),
+	CLK_LIST(vfe0_clk_src),
+	CLK_LIST(vfe1_clk_src),
+	CLK_LIST(gfx3d_clk_src),
+	CLK_LIST(blsp1_qup2_i2c_apps_clk_src),
+	CLK_LIST(blsp1_qup2_spi_apps_clk_src),
+	CLK_LIST(blsp1_qup3_i2c_apps_clk_src),
+	CLK_LIST(blsp1_qup3_spi_apps_clk_src),
+	CLK_LIST(blsp1_qup4_i2c_apps_clk_src),
+	CLK_LIST(blsp1_qup4_spi_apps_clk_src),
+	CLK_LIST(blsp1_uart1_apps_clk_src),
+	CLK_LIST(blsp1_uart2_apps_clk_src),
+	CLK_LIST(blsp2_qup1_i2c_apps_clk_src),
+	CLK_LIST(blsp2_qup1_spi_apps_clk_src),
+	CLK_LIST(blsp2_qup2_i2c_apps_clk_src),
+	CLK_LIST(blsp2_qup2_spi_apps_clk_src),
+	CLK_LIST(blsp2_qup3_i2c_apps_clk_src),
+	CLK_LIST(blsp2_qup3_spi_apps_clk_src),
+	CLK_LIST(blsp2_uart1_apps_clk_src),
+	CLK_LIST(blsp2_uart2_apps_clk_src),
+	CLK_LIST(cci_clk_src),
+	CLK_LIST(cpp_clk_src),
+	CLK_LIST(camss_gp0_clk_src),
+	CLK_LIST(camss_gp1_clk_src),
+	CLK_LIST(jpeg0_clk_src),
+	CLK_LIST(mclk0_clk_src),
+	CLK_LIST(mclk1_clk_src),
+	CLK_LIST(mclk2_clk_src),
+	CLK_LIST(csi0phytimer_clk_src),
+	CLK_LIST(csi1phytimer_clk_src),
+	CLK_LIST(crypto_clk_src),
+	CLK_LIST(gp1_clk_src),
+	CLK_LIST(gp2_clk_src),
+	CLK_LIST(gp3_clk_src),
+	CLK_LIST(esc0_clk_src),
+	CLK_LIST(mdp_clk_src),
+	CLK_LIST(vsync_clk_src),
+	CLK_LIST(pdm2_clk_src),
+	CLK_LIST(sdcc1_apps_clk_src),
+	CLK_LIST(sdcc1_ice_core_clk_src),
+	CLK_LIST(sdcc2_apps_clk_src),
+	CLK_LIST(usb_hs_system_clk_src),
+	CLK_LIST(gcc_bimc_gpu_clk),
+	CLK_LIST(gcc_blsp1_qup2_i2c_apps_clk),
+	CLK_LIST(gcc_blsp1_qup2_spi_apps_clk),
+	CLK_LIST(gcc_blsp1_qup3_i2c_apps_clk),
+	CLK_LIST(gcc_blsp1_qup3_spi_apps_clk),
+	CLK_LIST(gcc_blsp1_qup4_i2c_apps_clk),
+	CLK_LIST(gcc_blsp1_qup4_spi_apps_clk),
+	CLK_LIST(gcc_blsp1_uart1_apps_clk),
+	CLK_LIST(gcc_blsp1_uart2_apps_clk),
+	CLK_LIST(gcc_blsp2_qup1_i2c_apps_clk),
+	CLK_LIST(gcc_blsp2_qup1_spi_apps_clk),
+	CLK_LIST(gcc_blsp2_qup2_i2c_apps_clk),
+	CLK_LIST(gcc_blsp2_qup2_spi_apps_clk),
+	CLK_LIST(gcc_blsp2_qup3_i2c_apps_clk),
+	CLK_LIST(gcc_blsp2_qup3_spi_apps_clk),
+	CLK_LIST(gcc_blsp2_uart1_apps_clk),
+	CLK_LIST(gcc_blsp2_uart2_apps_clk),
+	CLK_LIST(gcc_camss_cci_ahb_clk),
+	CLK_LIST(gcc_camss_cci_clk),
+	CLK_LIST(gcc_camss_cpp_ahb_clk),
+	CLK_LIST(gcc_camss_cpp_axi_clk),
+	CLK_LIST(gcc_camss_cpp_clk),
+	CLK_LIST(gcc_camss_csi0_ahb_clk),
+	CLK_LIST(gcc_camss_csi0_clk),
+	CLK_LIST(gcc_camss_csi0phy_clk),
+	CLK_LIST(gcc_camss_csi0pix_clk),
+	CLK_LIST(gcc_camss_csi0rdi_clk),
+	CLK_LIST(gcc_camss_csi1_ahb_clk),
+	CLK_LIST(gcc_camss_csi1_clk),
+	CLK_LIST(gcc_camss_csi1phy_clk),
+	CLK_LIST(gcc_camss_csi1pix_clk),
+	CLK_LIST(gcc_camss_csi1rdi_clk),
+	CLK_LIST(gcc_camss_csi2_ahb_clk),
+	CLK_LIST(gcc_camss_csi2_clk),
+	CLK_LIST(gcc_camss_csi2phy_clk),
+	CLK_LIST(gcc_camss_csi2pix_clk),
+	CLK_LIST(gcc_camss_csi2rdi_clk),
+	CLK_LIST(gcc_camss_csi_vfe0_clk),
+	CLK_LIST(gcc_camss_csi_vfe1_clk),
+	CLK_LIST(gcc_camss_gp0_clk),
+	CLK_LIST(gcc_camss_gp1_clk),
+	CLK_LIST(gcc_camss_ispif_ahb_clk),
+	CLK_LIST(gcc_camss_jpeg0_clk),
+	CLK_LIST(gcc_camss_jpeg_ahb_clk),
+	CLK_LIST(gcc_camss_jpeg_axi_clk),
+	CLK_LIST(gcc_camss_mclk0_clk),
+	CLK_LIST(gcc_camss_mclk1_clk),
+	CLK_LIST(gcc_camss_mclk2_clk),
+	CLK_LIST(gcc_camss_micro_ahb_clk),
+	CLK_LIST(gcc_camss_csi0phytimer_clk),
+	CLK_LIST(gcc_camss_csi1phytimer_clk),
+	CLK_LIST(gcc_camss_ahb_clk),
+	CLK_LIST(gcc_camss_top_ahb_clk),
+	CLK_LIST(gcc_camss_vfe0_clk),
+	CLK_LIST(gcc_camss_vfe_ahb_clk),
+	CLK_LIST(gcc_camss_vfe_axi_clk),
+	CLK_LIST(gcc_camss_vfe1_ahb_clk),
+	CLK_LIST(gcc_camss_vfe1_axi_clk),
+	CLK_LIST(gcc_camss_vfe1_clk),
+	CLK_LIST(gcc_gp1_clk),
+	CLK_LIST(gcc_gp2_clk),
+	CLK_LIST(gcc_gp3_clk),
+	CLK_LIST(gcc_mdss_ahb_clk),
+	CLK_LIST(gcc_mdss_axi_clk),
+	CLK_LIST(gcc_mdss_esc0_clk),
+	CLK_LIST(gcc_mdss_mdp_clk),
+	CLK_LIST(gcc_mdss_vsync_clk),
+	CLK_LIST(gcc_mss_cfg_ahb_clk),
+	CLK_LIST(gcc_mss_q6_bimc_axi_clk),
+	CLK_LIST(gcc_bimc_gfx_clk),
+	CLK_LIST(gcc_oxili_ahb_clk),
+	CLK_LIST(gcc_oxili_gfx3d_clk),
+	CLK_LIST(gcc_pdm2_clk),
+	CLK_LIST(gcc_pdm_ahb_clk),
+	CLK_LIST(gcc_sdcc1_ahb_clk),
+	CLK_LIST(gcc_sdcc1_apps_clk),
+	CLK_LIST(gcc_sdcc1_ice_core_clk),
+	CLK_LIST(gcc_sdcc2_ahb_clk),
+	CLK_LIST(gcc_sdcc2_apps_clk),
+	CLK_LIST(gcc_usb2a_phy_sleep_clk),
+	CLK_LIST(gcc_usb_hs_phy_cfg_ahb_clk),
+	CLK_LIST(gcc_usb_hs_ahb_clk),
+	CLK_LIST(gcc_usb_hs_system_clk),
+	CLK_LIST(gcc_venus0_ahb_clk),
+	CLK_LIST(gcc_venus0_axi_clk),
+	CLK_LIST(gcc_venus0_core0_vcodec0_clk),
+	CLK_LIST(gcc_venus0_vcodec0_clk),
+
+	/* Reset clks */
+	CLK_LIST(gcc_usb2_hs_phy_only_clk),
+	CLK_LIST(gcc_qusb2_phy_clk),
+
+	/* WCNSS Debug */
+	CLK_LIST(wcnss_m_clk),
+};
+
+static struct clk_lookup msm_clocks_lookup_8952[] = {
+	CLK_LIST(a53ss_c0_pll),
+	CLK_LIST(a53ss_cci_pll),
+	CLK_LIST(ipa_clk),
+	CLK_LIST(ipa_a_clk),
+	CLK_LIST(gpll0_clk_src_8952),
+	CLK_LIST(gpll0_ao_clk_src_8952),
+	CLK_LIST(gcc_oxili_gmem_clk),
+	CLK_LIST(usb_fs_ic_clk_src),
+	CLK_LIST(gcc_usb_fs_ic_clk),
+	CLK_LIST(usb_fs_system_clk_src),
+	CLK_LIST(gcc_usb_fs_system_clk),
+	CLK_LIST(gcc_gfx_tcu_clk),
+	CLK_LIST(gcc_gfx_tbu_clk),
+	CLK_LIST(gcc_gtcu_ahb_clk),
+	CLK_LIST(gcc_ipa_tbu_clk),
+	CLK_LIST(gcc_usb_fs_ahb_clk),
+	CLK_LIST(gcc_venus0_core1_vcodec0_clk),
+	CLK_LIST(blsp1_qup1_i2c_apps_clk_src),
+	CLK_LIST(blsp1_qup1_spi_apps_clk_src),
+	CLK_LIST(gcc_blsp1_qup1_i2c_apps_clk),
+	CLK_LIST(gcc_blsp1_qup1_spi_apps_clk),
+	CLK_LIST(blsp2_qup4_i2c_apps_clk_src),
+	CLK_LIST(blsp2_qup4_spi_apps_clk_src),
+	CLK_LIST(gcc_blsp2_qup4_i2c_apps_clk),
+	CLK_LIST(gcc_blsp2_qup4_spi_apps_clk),
+	CLK_LIST(gcc_oxili_timer_clk),
+};
+
+static struct clk_lookup msm_clocks_lookup_8937[] = {
+	CLK_LIST(gpll0_clk_src_8937),
+	CLK_LIST(gpll0_ao_clk_src_8937),
+	CLK_LIST(gpll0_sleep_clk_src),
+	CLK_LIST(a53ss_c0_pll),
+	CLK_LIST(esc1_clk_src),
+	CLK_LIST(gcc_mdss_esc1_clk),
+	CLK_LIST(gcc_dcc_clk),
+	CLK_LIST(gcc_oxili_aon_clk),
+	CLK_LIST(gcc_qdss_dap_clk),
+	CLK_LIST(blsp1_qup1_i2c_apps_clk_src),
+	CLK_LIST(blsp1_qup1_spi_apps_clk_src),
+	CLK_LIST(gcc_blsp1_qup1_i2c_apps_clk),
+	CLK_LIST(gcc_blsp1_qup1_spi_apps_clk),
+	CLK_LIST(blsp2_qup4_i2c_apps_clk_src),
+	CLK_LIST(blsp2_qup4_spi_apps_clk_src),
+	CLK_LIST(gcc_blsp2_qup4_i2c_apps_clk),
+	CLK_LIST(gcc_blsp2_qup4_spi_apps_clk),
+	CLK_LIST(gcc_oxili_timer_clk),
+};
+
+static struct clk_lookup msm_clocks_lookup_8917[] = {
+	CLK_LIST(gpll0_clk_src_8937),
+	CLK_LIST(gpll0_ao_clk_src_8937),
+	CLK_LIST(gpll0_sleep_clk_src),
+	CLK_LIST(bimc_gpu_clk),
+	CLK_LIST(bimc_gpu_a_clk),
+	CLK_LIST(gcc_dcc_clk),
+	CLK_LIST(gcc_qdss_dap_clk),
+	CLK_LIST(gcc_gfx_tcu_clk),
+	CLK_LIST(gcc_gfx_tbu_clk),
+	CLK_LIST(gcc_gtcu_ahb_clk),
+};
+
+static struct clk_lookup msm_clocks_lookup_8920[] = {
+	CLK_LIST(gpll0_clk_src_8937),
+	CLK_LIST(gpll0_ao_clk_src_8937),
+	CLK_LIST(gpll0_sleep_clk_src),
+	CLK_LIST(bimc_gpu_clk),
+	CLK_LIST(bimc_gpu_a_clk),
+	CLK_LIST(gcc_dcc_clk),
+	CLK_LIST(gcc_qdss_dap_clk),
+	CLK_LIST(gcc_gfx_tcu_clk),
+	CLK_LIST(gcc_gfx_tbu_clk),
+	CLK_LIST(gcc_gtcu_ahb_clk),
+	CLK_LIST(ipa_clk),
+	CLK_LIST(ipa_a_clk),
+	CLK_LIST(gcc_ipa_tbu_clk),
+};
+
+static struct clk_lookup msm_clocks_lookup_8940[] = {
+	CLK_LIST(gpll0_clk_src_8937),
+	CLK_LIST(gpll0_ao_clk_src_8937),
+	CLK_LIST(gpll0_sleep_clk_src),
+	CLK_LIST(a53ss_c0_pll),
+	CLK_LIST(esc1_clk_src),
+	CLK_LIST(gcc_mdss_esc1_clk),
+	CLK_LIST(gcc_dcc_clk),
+	CLK_LIST(gcc_oxili_aon_clk),
+	CLK_LIST(gcc_qdss_dap_clk),
+	CLK_LIST(blsp1_qup1_i2c_apps_clk_src),
+	CLK_LIST(blsp1_qup1_spi_apps_clk_src),
+	CLK_LIST(gcc_blsp1_qup1_i2c_apps_clk),
+	CLK_LIST(gcc_blsp1_qup1_spi_apps_clk),
+	CLK_LIST(blsp2_qup4_i2c_apps_clk_src),
+	CLK_LIST(blsp2_qup4_spi_apps_clk_src),
+	CLK_LIST(gcc_blsp2_qup4_i2c_apps_clk),
+	CLK_LIST(gcc_blsp2_qup4_spi_apps_clk),
+	CLK_LIST(gcc_oxili_timer_clk),
+	CLK_LIST(ipa_clk),
+	CLK_LIST(ipa_a_clk),
+	CLK_LIST(gcc_ipa_tbu_clk),
+};
+
+/* Please note that the order of reg-names is important */
+static int get_mmio_addr(struct platform_device *pdev, u32 nbases)
+{
+	int i, count;
+	const char *str;
+	struct resource *res;
+	struct device *dev = &pdev->dev;
+
+	count = of_property_count_strings(dev->of_node, "reg-names");
+	if (count < nbases) {
+		dev_err(dev, "missing reg-names property, expected %d strings\n",
+				nbases);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < nbases; i++) {
+		of_property_read_string_index(dev->of_node, "reg-names", i,
+						&str);
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, str);
+		if (!res) {
+			dev_err(dev, "Unable to retrieve register base.\n");
+			return -ENOMEM;
+		}
+
+		virt_bases[i] = devm_ioremap(dev, res->start,
+							resource_size(res));
+		if (!virt_bases[i]) {
+			dev_err(dev, "Failed to map in CC registers.\n");
+			return -ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
+static const struct msm_reset_map gcc_8952_resets[] = {
+	[GCC_CAMSS_MICRO_BCR] = {0x56008},
+	[GCC_USB_FS_BCR] = {0x3F000},
+	[GCC_USB_HS_BCR] = {0x41000},
+	[GCC_USB2_HS_PHY_ONLY_BCR] = {0x41034},
+	[GCC_QUSB2_PHY_BCR] = {0x4103C},
+};
+
+static void override_for_8917(int speed_bin)
+{
+	gpll3_clk_src.c.rate = 930000000;
+
+	OVERRIDE_FMAX3(csi0,
+		LOWER, 100000000, LOW, 200000000, NOMINAL, 266670000);
+	/* Frequency Table same as 8937 */
+	OVERRIDE_FTABLE(csi0, ftbl_gcc_camss_csi0_2_clk, 8937);
+	OVERRIDE_FMAX3(csi1,
+		LOWER, 100000000, LOW, 200000000, NOMINAL, 266670000);
+	/* Frequency Table same as 8937 */
+	OVERRIDE_FTABLE(csi1, ftbl_gcc_camss_csi0_2_clk, 8937);
+	OVERRIDE_FMAX3(csi2,
+		LOWER, 100000000, LOW, 200000000, NOMINAL, 266670000);
+	/* Frequency Table same as 8937 */
+	OVERRIDE_FTABLE(csi2, ftbl_gcc_camss_csi0_2_clk, 8937);
+
+	OVERRIDE_FMAX5(vfe0,
+		LOWER, 160000000, LOW, 266670000, NOMINAL, 320000000,
+		NOM_PLUS, 329140000, HIGH, 360000000);
+	OVERRIDE_FTABLE(vfe0, ftbl_gcc_camss_vfe0_1_clk, 8917);
+	OVERRIDE_FMAX5(vfe1,
+		LOWER, 160000000, LOW, 266670000, NOMINAL, 320000000,
+		NOM_PLUS, 329140000, HIGH, 360000000);
+	OVERRIDE_FTABLE(vfe1, ftbl_gcc_camss_vfe0_1_clk, 8917);
+	OVERRIDE_FTABLE(vcodec0, ftbl_gcc_venus0_vcodec0_clk, 8917);
+	OVERRIDE_FMAX5(vcodec0,
+		LOWER, 200000000, LOW, 270000000, NOMINAL, 308570000,
+		NOM_PLUS, 329140000, HIGH, 360000000);
+	OVERRIDE_FMAX4(cpp,
+		LOWER, 160000000, LOW, 266670000, NOMINAL, 320000000,
+		NOM_PLUS, 360000000);
+	OVERRIDE_FTABLE(cpp, ftbl_gcc_camss_cpp_clk, 8917);
+	OVERRIDE_FMAX5(jpeg0,
+		LOWER, 133330000, LOW, 200000000, NOMINAL, 266670000,
+		NOM_PLUS, 308570000, HIGH, 320000000);
+	/* Frequency Table same as 8937 */
+	OVERRIDE_FTABLE(jpeg0, ftbl_gcc_camss_jpeg0_clk, 8937);
+
+	if (speed_bin) {
+		OVERRIDE_FMAX5(gfx3d,
+			LOWER, 270000000, LOW, 400000000, NOMINAL, 484800000,
+			NOM_PLUS, 523200000, HIGH, 650000000);
+		OVERRIDE_FTABLE(gfx3d, ftbl_gcc_oxili_gfx3d_clk, 8917_650MHz);
+	} else {
+		OVERRIDE_FMAX5(gfx3d,
+			LOWER, 270000000, LOW, 400000000, NOMINAL, 484800000,
+			NOM_PLUS, 523200000, HIGH, 598000000);
+		OVERRIDE_FTABLE(gfx3d, ftbl_gcc_oxili_gfx3d_clk, 8917);
+	}
+
+	OVERRIDE_FMAX1(cci, LOWER, 37500000);
+
+	OVERRIDE_FTABLE(csi0phytimer, ftbl_gcc_camss_csi0_1phytimer_clk, 8917);
+	OVERRIDE_FMAX3(csi0phytimer, LOWER, 100000000, LOW, 200000000,
+			NOMINAL, 266670000);
+	OVERRIDE_FTABLE(csi1phytimer, ftbl_gcc_camss_csi0_1phytimer_clk, 8917);
+	OVERRIDE_FMAX3(csi1phytimer, LOWER, 100000000, LOW, 200000000,
+			NOMINAL, 266670000);
+	OVERRIDE_FMAX2(gp1, LOWER, 100000000, NOMINAL, 200000000);
+	OVERRIDE_FMAX2(gp2, LOWER, 100000000, NOMINAL, 200000000);
+	OVERRIDE_FMAX2(gp3, LOWER, 100000000, NOMINAL, 200000000);
+
+	OVERRIDE_FMAX2(byte0, LOWER, 125000000, NOMINAL, 187500000);
+	/* Frequency Table same as 8937 */
+	OVERRIDE_FTABLE(byte0, ftbl_gcc_mdss_byte0_clk, 8937);
+	byte0_clk_src.current_freq = ftbl_gcc_mdss_pclk0_clk_8937;
+
+	OVERRIDE_FMAX2(pclk0, LOWER, 166670000, NOMINAL, 250000000);
+	/* Frequency Table same as 8937 */
+	OVERRIDE_FTABLE(pclk0, ftbl_gcc_mdss_pclk0_clk, 8937);
+	pclk0_clk_src.current_freq = ftbl_gcc_mdss_pclk0_clk_8937;
+
+	OVERRIDE_FMAX2(sdcc1_apps, LOWER, 200000000, NOMINAL, 400000000);
+	OVERRIDE_FTABLE(usb_hs_system, ftbl_gcc_usb_hs_system_clk, 8917);
+	OVERRIDE_FMAX3(usb_hs_system, LOWER, 800000000, NOMINAL, 133333000,
+			HIGH, 177780000);
+}
+
+static void override_for_8937(int speed_bin)
+{
+	gpll3_clk_src.c.rate = 900000000;
+	gpll3_clk_src.vco_tbl = p_vco_8937;
+	gpll3_clk_src.num_vco = ARRAY_SIZE(p_vco_8937);
+	OVERRIDE_FMAX2(gpll3, LOW, 800000000, NOMINAL, 1066000000);
+
+	OVERRIDE_FMAX1(cci, LOWER, 37500000);
+	OVERRIDE_FMAX3(csi0,
+		LOWER, 100000000, LOW, 200000000, NOMINAL, 266670000);
+	OVERRIDE_FTABLE(csi0, ftbl_gcc_camss_csi0_2_clk, 8937);
+	OVERRIDE_FMAX3(csi1,
+		LOWER, 100000000, LOW, 200000000, NOMINAL, 266670000);
+	OVERRIDE_FTABLE(csi1, ftbl_gcc_camss_csi0_2_clk, 8937);
+	OVERRIDE_FMAX3(csi2,
+		LOWER, 100000000, LOW, 200000000, NOMINAL, 266670000);
+	OVERRIDE_FTABLE(csi2, ftbl_gcc_camss_csi0_2_clk, 8937);
+	OVERRIDE_FMAX4(vfe0,
+		LOWER, 160000000, LOW, 308570000, NOMINAL, 400000000,
+		NOM_PLUS, 432000000);
+	OVERRIDE_FTABLE(vfe0, ftbl_gcc_camss_vfe0_1_clk, 8937);
+	OVERRIDE_FMAX4(vfe1,
+		LOWER, 160000000, LOW, 308570000, NOMINAL, 400000000,
+		NOM_PLUS, 432000000);
+	OVERRIDE_FTABLE(vfe1, ftbl_gcc_camss_vfe0_1_clk, 8937);
+
+	if (speed_bin) {
+		OVERRIDE_FMAX6(gfx3d,
+			LOWER, 216000000, LOW, 300000000,
+			NOMINAL, 375000000, NOM_PLUS, 400000000,
+			HIGH, 450000000, SUPER_TUR, 475000000);
+		OVERRIDE_FTABLE(gfx3d, ftbl_gcc_oxili_gfx3d_clk, 8937_475MHz);
+	} else {
+		OVERRIDE_FMAX5(gfx3d,
+			LOWER, 216000000, LOW, 300000000,
+			NOMINAL, 375000000, NOM_PLUS, 400000000,
+			HIGH, 450000000);
+		OVERRIDE_FTABLE(gfx3d, ftbl_gcc_oxili_gfx3d_clk, 8937);
+	}
+
+	OVERRIDE_FMAX5(cpp,
+		LOWER, 160000000, LOW, 266670000, NOMINAL, 320000000,
+		NOM_PLUS, 342860000, HIGH, 360000000);
+	OVERRIDE_FTABLE(cpp, ftbl_gcc_camss_cpp_clk, 8937);
+	OVERRIDE_FMAX5(jpeg0,
+		LOWER, 133330000, LOW, 200000000, NOMINAL, 266670000,
+		NOM_PLUS, 308570000, HIGH, 320000000);
+	OVERRIDE_FTABLE(jpeg0, ftbl_gcc_camss_jpeg0_clk, 8937);
+	OVERRIDE_FMAX2(csi0phytimer, LOWER, 100000000, LOW, 200000000);
+	OVERRIDE_FMAX2(csi1phytimer, LOWER, 100000000, LOW, 200000000);
+	OVERRIDE_FMAX2(gp1, LOWER, 100000000, NOMINAL, 200000000);
+	OVERRIDE_FMAX2(gp2, LOWER, 100000000, NOMINAL, 200000000);
+	OVERRIDE_FMAX2(gp3, LOWER, 100000000, NOMINAL, 200000000);
+	OVERRIDE_FMAX2(byte0, LOWER, 125000000, NOMINAL, 187500000);
+	OVERRIDE_FTABLE(byte0, ftbl_gcc_mdss_byte0_clk, 8937);
+	OVERRIDE_FMAX2(byte1, LOWER, 125000000, NOMINAL, 187500000);
+	byte0_clk_src.current_freq = ftbl_gcc_mdss_byte0_clk_8937;
+	OVERRIDE_FMAX2(pclk0, LOWER, 166670000, NOMINAL, 250000000);
+	OVERRIDE_FTABLE(pclk0, ftbl_gcc_mdss_pclk0_clk, 8937);
+	OVERRIDE_FMAX2(pclk1, LOWER, 166670000, NOMINAL, 250000000);
+	pclk0_clk_src.current_freq = ftbl_gcc_mdss_pclk0_clk_8937;
+	OVERRIDE_FTABLE(vcodec0, ftbl_gcc_venus0_vcodec0_clk, 8937);
+	OVERRIDE_FMAX5(vcodec0,
+		LOWER, 166150000, LOW, 240000000, NOMINAL, 308570000,
+		NOM_PLUS, 320000000, HIGH, 360000000);
+	OVERRIDE_FMAX2(sdcc1_apps, LOWER, 100000000,
+		NOMINAL, 400000000);
+}
+
+static void get_speed_bin(struct platform_device *pdev, int *bin)
+{
+	struct resource *res;
+	void __iomem *base;
+	u32 config_efuse;
+
+	*bin = 0;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse");
+	if (!res) {
+		dev_info(&pdev->dev,
+			"No GPU speed binning available. Defaulting to 0.\n");
+		return;
+	}
+
+	base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!base) {
+		dev_warn(&pdev->dev,
+			"Unable to ioremap efuse reg address. Defaulting to 0.\n");
+		return;
+	}
+
+	config_efuse = readl_relaxed(base);
+	devm_iounmap(&pdev->dev, base);
+	*bin = (config_efuse >> 31) & 0x1;
+
+	dev_info(&pdev->dev, "GPU speed bin: %d\n", *bin);
+}
+
+static int msm_gcc_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	int ret;
+	int speed_bin;
+	u32 regval, nbases = N_BASES;
+	bool compat_bin = false;
+	bool compat_bin2 = false;
+	bool compat_bin3 = false;
+	bool compat_bin4 = false;
+
+	compat_bin = of_device_is_compatible(pdev->dev.of_node,
+						"qcom,gcc-8937");
+
+	compat_bin2 = of_device_is_compatible(pdev->dev.of_node,
+						"qcom,gcc-8917");
+
+	compat_bin3 = of_device_is_compatible(pdev->dev.of_node,
+						"qcom,gcc-8940");
+
+	compat_bin4 = of_device_is_compatible(pdev->dev.of_node,
+						"qcom,gcc-8920");
+
+	ret = vote_bimc(&bimc_clk, INT_MAX);
+	if (ret < 0)
+		return ret;
+
+	if (compat_bin2 || compat_bin4)
+		nbases = APCS_C0_PLL_BASE;
+
+	ret = get_mmio_addr(pdev, nbases);
+	if (ret)
+		return ret;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cc_base");
+	if (!res) {
+		dev_err(&pdev->dev, "Register base not defined\n");
+		return -ENOMEM;
+	}
+
+	virt_bases[GCC_BASE] = devm_ioremap(&pdev->dev, res->start,
+							resource_size(res));
+	if (!virt_bases[GCC_BASE]) {
+		dev_err(&pdev->dev, "Failed to ioremap CC registers\n");
+		return -ENOMEM;
+	}
+
+	vdd_dig.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_dig");
+	if (IS_ERR(vdd_dig.regulator[0])) {
+		if (!(PTR_ERR(vdd_dig.regulator[0]) == -EPROBE_DEFER))
+			dev_err(&pdev->dev,
+					"Unable to get vdd_dig regulator!!!\n");
+		return PTR_ERR(vdd_dig.regulator[0]);
+	}
+
+	if (!compat_bin2 && !compat_bin4) {
+		vdd_sr2_pll.regulator[0] = devm_regulator_get(&pdev->dev,
+							"vdd_sr2_pll");
+		if (IS_ERR(vdd_sr2_pll.regulator[0])) {
+			if (PTR_ERR(vdd_sr2_pll.regulator[0]) != -EPROBE_DEFER)
+				dev_err(&pdev->dev,
+				"Unable to get vdd_sr2_pll regulator!!!\n");
+			return PTR_ERR(vdd_sr2_pll.regulator[0]);
+		}
+
+		vdd_sr2_pll.regulator[1] = devm_regulator_get(&pdev->dev,
+							"vdd_sr2_dig");
+		if (IS_ERR(vdd_sr2_pll.regulator[1])) {
+			if (PTR_ERR(vdd_sr2_pll.regulator[1]) != -EPROBE_DEFER)
+				dev_err(&pdev->dev,
+				"Unable to get vdd_sr2_dig regulator!!!\n");
+			return PTR_ERR(vdd_sr2_pll.regulator[1]);
+		}
+	}
+
+	vdd_hf_pll.regulator[0] = devm_regulator_get(&pdev->dev,
+							"vdd_hf_pll");
+	if (IS_ERR(vdd_hf_pll.regulator[0])) {
+		if (PTR_ERR(vdd_hf_pll.regulator[0]) != -EPROBE_DEFER)
+			dev_err(&pdev->dev,
+				"Unable to get vdd_sr2_pll regulator!!!\n");
+		return PTR_ERR(vdd_hf_pll.regulator[0]);
+	}
+
+	vdd_hf_pll.regulator[1] = devm_regulator_get(&pdev->dev,
+							"vdd_hf_dig");
+	if (IS_ERR(vdd_hf_pll.regulator[1])) {
+		if (PTR_ERR(vdd_hf_pll.regulator[1]) != -EPROBE_DEFER)
+			dev_err(&pdev->dev,
+				"Unable to get vdd_hf_dig regulator!!!\n");
+		return PTR_ERR(vdd_hf_pll.regulator[1]);
+	}
+
+	/* Vote for GPLL0 to turn on. Needed by acpuclock. */
+	regval = readl_relaxed(GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
+	regval |= BIT(0);
+	writel_relaxed(regval, GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
+
+	if (compat_bin || compat_bin3) {
+		gpll0_clk_src.c.parent = &gpll0_clk_src_8937.c;
+		gpll0_ao_clk_src.c.parent = &gpll0_ao_clk_src_8937.c;
+		/* Oxili Ocmem in GX rail: OXILI_GMEM_CLAMP_IO */
+		regval = readl_relaxed(GCC_REG_BASE(GX_DOMAIN_MISC));
+		regval &= ~BIT(0);
+		writel_relaxed(regval, GCC_REG_BASE(GX_DOMAIN_MISC));
+		get_speed_bin(pdev, &speed_bin);
+		override_for_8937(speed_bin);
+
+		if (compat_bin3) {
+			if (speed_bin) {
+				gfx3d_clk_src.freq_tbl =
+					ftbl_gcc_oxili_gfx3d_clk_8940_500MHz;
+				gfx3d_clk_src.c.fmax[VDD_DIG_SUPER_TUR] =
+								500000000;
+			} else {
+				gfx3d_clk_src.freq_tbl =
+					ftbl_gcc_oxili_gfx3d_clk_8937_475MHz;
+				gfx3d_clk_src.c.fmax[VDD_DIG_SUPER_TUR] =
+								475000000;
+			}
+		}
+	} else if (compat_bin2 || compat_bin4) {
+		gpll0_clk_src.c.parent = &gpll0_clk_src_8937.c;
+		gpll0_ao_clk_src.c.parent = &gpll0_ao_clk_src_8937.c;
+		vdd_dig.num_levels = VDD_DIG_NUM_8917;
+		vdd_dig.cur_level = VDD_DIG_NUM_8917;
+		vdd_hf_pll.num_levels = VDD_HF_PLL_NUM_8917;
+		vdd_hf_pll.cur_level = VDD_HF_PLL_NUM_8917;
+		get_speed_bin(pdev, &speed_bin);
+		override_for_8917(speed_bin);
+
+		if (compat_bin2) {
+			blsp1_qup2_spi_apps_clk_src.freq_tbl =
+				ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk_8917;
+			blsp1_qup3_spi_apps_clk_src.freq_tbl =
+				ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk_8917;
+			blsp1_qup4_spi_apps_clk_src.freq_tbl =
+				ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk_8917;
+			blsp2_qup1_spi_apps_clk_src.freq_tbl =
+				ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk_8917;
+			blsp2_qup2_spi_apps_clk_src.freq_tbl =
+				ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk_8917;
+			blsp2_qup3_spi_apps_clk_src.freq_tbl =
+				ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk_8917;
+		}
+	} else {
+		gpll0_clk_src.c.parent = &gpll0_clk_src_8952.c;
+		gpll0_ao_clk_src.c.parent = &gpll0_ao_clk_src_8952.c;
+	}
+
+	ret = of_msm_clock_register(pdev->dev.of_node,
+				msm_clocks_lookup_common,
+				ARRAY_SIZE(msm_clocks_lookup_common));
+	if (ret)
+		return ret;
+
+	if (compat_bin)
+		ret = of_msm_clock_register(pdev->dev.of_node,
+					msm_clocks_lookup_8937,
+					ARRAY_SIZE(msm_clocks_lookup_8937));
+	else if (compat_bin2)
+		ret = of_msm_clock_register(pdev->dev.of_node,
+					msm_clocks_lookup_8917,
+					ARRAY_SIZE(msm_clocks_lookup_8917));
+	else if (compat_bin3)
+		ret = of_msm_clock_register(pdev->dev.of_node,
+					msm_clocks_lookup_8940,
+					ARRAY_SIZE(msm_clocks_lookup_8940));
+	else if (compat_bin4)
+		ret = of_msm_clock_register(pdev->dev.of_node,
+					msm_clocks_lookup_8920,
+					ARRAY_SIZE(msm_clocks_lookup_8920));
+	else
+		ret = of_msm_clock_register(pdev->dev.of_node,
+					msm_clocks_lookup_8952,
+					ARRAY_SIZE(msm_clocks_lookup_8952));
+	if (ret)
+		return ret;
+
+	ret = enable_rpm_scaling();
+	if (ret)
+		return ret;
+
+	clk_set_rate(&apss_ahb_clk_src.c, 19200000);
+	clk_prepare_enable(&apss_ahb_clk_src.c);
+
+	/*
+	 *  Hold an active set vote for PCNOC AHB source. Sleep set vote is 0.
+	 */
+	clk_set_rate(&pnoc_keepalive_a_clk.c, 19200000);
+	clk_prepare_enable(&pnoc_keepalive_a_clk.c);
+
+	clk_prepare_enable(&xo_a_clk_src.c);
+	clk_prepare_enable(&gcc_blsp1_ahb_clk.c);
+	clk_prepare_enable(&gcc_blsp2_ahb_clk.c);
+	clk_prepare_enable(&gcc_blsp1_uart2_apps_clk.c);
+	clk_prepare_enable(&gcc_blsp1_uart1_apps_clk.c);
+	clk_prepare_enable(&gcc_bimc_gpu_clk.c);
+	clk_prepare_enable(&sysmmnoc_msmbus_a_clk.c);
+	clk_prepare_enable(&sysmmnoc_a_clk.c);
+
+	if (!compat_bin && !compat_bin3) {
+		/* Configure Sleep and Wakeup cycles for GMEM clock */
+		regval = readl_relaxed(GCC_REG_BASE(OXILI_GMEM_CBCR));
+		regval ^= 0xFF0;
+		regval |= CLKFLAG_WAKEUP_CYCLES << 8;
+		regval |= CLKFLAG_SLEEP_CYCLES << 4;
+		writel_relaxed(regval, GCC_REG_BASE(OXILI_GMEM_CBCR));
+	} else {
+		/* Configure Sleep and Wakeup cycles for OXILI clock */
+		regval = readl_relaxed(GCC_REG_BASE(OXILI_GFX3D_CBCR));
+		regval &= ~0xF0;
+		regval |= CLKFLAG_SLEEP_CYCLES << 4;
+		writel_relaxed(regval, GCC_REG_BASE(OXILI_GFX3D_CBCR));
+	}
+
+	ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+	if (ret)
+		return ret;
+
+	msm_reset_controller_register(pdev, gcc_8952_resets,
+			ARRAY_SIZE(gcc_8952_resets), virt_bases[GCC_BASE]);
+
+	dev_info(&pdev->dev, "Registered GCC clocks\n");
+
+	return 0;
+}
+
+static const struct of_device_id msm_clock_gcc_match_table[] = {
+	{ .compatible = "qcom,gcc-8952" },
+	{ .compatible = "qcom,gcc-8937" },
+	{ .compatible = "qcom,gcc-8917" },
+	{ .compatible = "qcom,gcc-8940" },
+	{ .compatible = "qcom,gcc-8920" },
+	{}
+};
+
+static struct platform_driver msm_clock_gcc_driver = {
+	.probe = msm_gcc_probe,
+	.driver = {
+		.name = "qcom,gcc-8952",
+		.of_match_table = msm_clock_gcc_match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int msm_gcc_spm_probe(struct platform_device *pdev)
+{
+	struct resource *res = NULL;
+	bool compat_bin = false;
+
+	compat_bin = of_device_is_compatible(pdev->dev.of_node,
+					"qcom,spm-8952");
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "spm_c0_base");
+	if (!res) {
+		dev_err(&pdev->dev, "SPM register base not defined for c0\n");
+		return -ENOMEM;
+	}
+
+	a53ss_c0_pll.spm_ctrl.spm_base = devm_ioremap(&pdev->dev, res->start,
+						resource_size(res));
+	if (!a53ss_c0_pll.spm_ctrl.spm_base) {
+		dev_err(&pdev->dev, "Failed to ioremap c0 spm registers\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "spm_c1_base");
+	if (!res) {
+		dev_err(&pdev->dev, "SPM register base not defined for c1\n");
+		return -ENOMEM;
+	}
+
+	a53ss_c1_pll.spm_ctrl.spm_base = devm_ioremap(&pdev->dev, res->start,
+						resource_size(res));
+	if (!a53ss_c1_pll.spm_ctrl.spm_base) {
+		dev_err(&pdev->dev, "Failed to ioremap c1 spm registers\n");
+		return -ENOMEM;
+	}
+
+	if (compat_bin) {
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						"spm_cci_base");
+		if (!res) {
+			dev_err(&pdev->dev, "SPM register base not defined for cci\n");
+			return -ENOMEM;
+		}
+
+		a53ss_cci_pll.spm_ctrl.spm_base = devm_ioremap(&pdev->dev,
+						res->start, resource_size(res));
+		if (!a53ss_cci_pll.spm_ctrl.spm_base) {
+			dev_err(&pdev->dev, "Failed to ioremap cci spm registers\n");
+			return -ENOMEM;
+		}
+	}
+
+	dev_info(&pdev->dev, "Registered GCC SPM clocks\n");
+
+	return 0;
+}
+
+static const struct of_device_id msm_clock_spm_match_table[] = {
+	{ .compatible = "qcom,gcc-spm-8952" },
+	{ .compatible = "qcom,gcc-spm-8937" },
+	{}
+};
+
+static struct platform_driver msm_clock_spm_driver = {
+	.probe = msm_gcc_spm_probe,
+	.driver = {
+		.name = "qcom,gcc-spm-8952",
+		.of_match_table = msm_clock_spm_match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_gcc_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&msm_clock_gcc_driver);
+	if (!ret)
+		ret = platform_driver_register(&msm_clock_spm_driver);
+
+	return ret;
+}
+
+static struct clk_lookup msm_clocks_measure[] = {
+	CLK_LOOKUP_OF("measure", gcc_debug_mux, "debug"),
+	CLK_LIST(apss_debug_pri_mux),
+	CLK_LIST(apc0_m_clk),
+	CLK_LIST(apc1_m_clk),
+	CLK_LIST(cci_m_clk),
+};
+
+static struct clk_lookup msm_clocks_measure_8937[] = {
+	CLK_LOOKUP_OF("measure", gcc_debug_mux_8937, "debug"),
+	CLK_LIST(apss_debug_pri_mux),
+	CLK_LIST(apc0_m_clk),
+	CLK_LIST(apc1_m_clk),
+	CLK_LIST(cci_m_clk),
+};
+
+static int msm_clock_debug_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct resource *res;
+	bool compat_bin = false, compat_bin2 = false;
+	bool compat_bin3 = false;
+	bool compat_bin4 = false;
+
+	compat_bin = of_device_is_compatible(pdev->dev.of_node,
+					"qcom,cc-debug-8937");
+
+	compat_bin2 = of_device_is_compatible(pdev->dev.of_node,
+					"qcom,cc-debug-8917");
+
+	compat_bin3 = of_device_is_compatible(pdev->dev.of_node,
+					"qcom,cc-debug-8940");
+
+	compat_bin4 = of_device_is_compatible(pdev->dev.of_node,
+					"qcom,cc-debug-8920");
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "meas");
+	if (!res) {
+		dev_err(&pdev->dev, "GLB clock diag base not defined.\n");
+		return -EINVAL;
+	}
+
+	meas_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!meas_base) {
+		dev_err(&pdev->dev, "Unable to map GLB clock diag base.\n");
+		return -ENOMEM;
+	}
+
+	clk_ops_debug_mux = clk_ops_gen_mux;
+	clk_ops_debug_mux.get_rate = measure_get_rate;
+
+	if (compat_bin2)
+		gcc_debug_mux_8937.post_div = 0x3;
+
+	if (!compat_bin && !compat_bin2 && !compat_bin3 && !compat_bin4)
+		ret =  of_msm_clock_register(pdev->dev.of_node,
+			msm_clocks_measure, ARRAY_SIZE(msm_clocks_measure));
+	else
+		ret =  of_msm_clock_register(pdev->dev.of_node,
+				msm_clocks_measure_8937,
+				ARRAY_SIZE(msm_clocks_measure_8937));
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to register debug Mux\n");
+		return ret;
+	}
+
+	dev_info(&pdev->dev, "Registered Debug Mux successfully\n");
+	return ret;
+}
+
+static const struct of_device_id msm_clock_debug_match_table[] = {
+	{ .compatible = "qcom,cc-debug-8952" },
+	{ .compatible = "qcom,cc-debug-8937" },
+	{ .compatible = "qcom,cc-debug-8917" },
+	{ .compatible = "qcom,cc-debug-8940" },
+	{ .compatible = "qcom,cc-debug-8920" },
+	{}
+};
+
+static struct platform_driver msm_clock_debug_driver = {
+	.probe = msm_clock_debug_probe,
+	.driver = {
+		.name = "qcom,cc-debug-8952",
+		.of_match_table = msm_clock_debug_match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_clock_debug_init(void)
+{
+	return platform_driver_register(&msm_clock_debug_driver);
+}
+
+/* MDSS DSI_PHY_PLL */
+static struct clk_lookup msm_clocks_gcc_mdss_common[] = {
+	CLK_LIST(ext_pclk0_clk_src),
+	CLK_LIST(ext_byte0_clk_src),
+	CLK_LIST(byte0_clk_src),
+	CLK_LIST(pclk0_clk_src),
+	CLK_LIST(gcc_mdss_pclk0_clk),
+	CLK_LIST(gcc_mdss_byte0_clk),
+	CLK_LIST(mdss_mdp_vote_clk),
+	CLK_LIST(mdss_rotator_vote_clk),
+};
+
+static struct clk_lookup msm_clocks_gcc_mdss_8937[] = {
+	CLK_LIST(ext_pclk1_clk_src),
+	CLK_LIST(ext_byte1_clk_src),
+	CLK_LIST(byte1_clk_src),
+	CLK_LIST(pclk1_clk_src),
+	CLK_LIST(gcc_mdss_pclk1_clk),
+	CLK_LIST(gcc_mdss_byte1_clk),
+};
+
+static int msm_gcc_mdss_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct clk *curr_p;
+	bool compat_bin = false;
+
+	compat_bin = of_device_is_compatible(pdev->dev.of_node,
+				"qcom,gcc-mdss-8937");
+	if (!compat_bin)
+		compat_bin = of_device_is_compatible(pdev->dev.of_node,
+				"qcom,gcc-mdss-8940");
+
+	curr_p = ext_pclk0_clk_src.c.parent = devm_clk_get(&pdev->dev,
+								"pclk0_src");
+	if (IS_ERR(curr_p)) {
+		dev_err(&pdev->dev, "Failed to get pclk0 source.\n");
+		return PTR_ERR(curr_p);
+	}
+
+	curr_p = ext_byte0_clk_src.c.parent = devm_clk_get(&pdev->dev,
+								"byte0_src");
+	if (IS_ERR(curr_p)) {
+		dev_err(&pdev->dev, "Failed to get byte source.\n");
+		ret = PTR_ERR(curr_p);
+		goto byte0_fail;
+	}
+
+	ext_pclk0_clk_src.c.flags = CLKFLAG_NO_RATE_CACHE;
+	ext_byte0_clk_src.c.flags = CLKFLAG_NO_RATE_CACHE;
+
+	if (compat_bin) {
+		curr_p = ext_pclk1_clk_src.c.parent = devm_clk_get(&pdev->dev,
+									"pclk1_src");
+		if (IS_ERR(curr_p)) {
+			dev_err(&pdev->dev, "Failed to get pclk1 source.\n");
+			ret = PTR_ERR(curr_p);
+			goto fail;
+		}
+
+		curr_p = ext_byte1_clk_src.c.parent = devm_clk_get(&pdev->dev,
+									"byte1_src");
+		if (IS_ERR(curr_p)) {
+			dev_err(&pdev->dev, "Failed to get byte1 source.\n");
+			ret = PTR_ERR(curr_p);
+			goto byte1_fail;
+		}
+
+		ext_pclk1_clk_src.c.flags = CLKFLAG_NO_RATE_CACHE;
+		ext_byte1_clk_src.c.flags = CLKFLAG_NO_RATE_CACHE;
+	}
+
+	ret = of_msm_clock_register(pdev->dev.of_node,
+			msm_clocks_gcc_mdss_common,
+			ARRAY_SIZE(msm_clocks_gcc_mdss_common));
+	if (ret)
+		goto fail;
+
+	if (compat_bin) {
+		ret = of_msm_clock_register(pdev->dev.of_node,
+		msm_clocks_gcc_mdss_8937,
+		ARRAY_SIZE(msm_clocks_gcc_mdss_8937));
+		if (ret)
+			goto fail_8937;
+	}
+
+	dev_info(&pdev->dev, "Registered GCC MDSS clocks.\n");
+
+	return ret;
+fail_8937:
+	devm_clk_put(&pdev->dev, ext_byte1_clk_src.c.parent);
+byte1_fail:
+	devm_clk_put(&pdev->dev, ext_pclk1_clk_src.c.parent);
+fail:
+	devm_clk_put(&pdev->dev, ext_byte0_clk_src.c.parent);
+byte0_fail:
+	devm_clk_put(&pdev->dev, ext_pclk0_clk_src.c.parent);
+	return ret;
+
+}
+
+static const struct of_device_id msm_clock_mdss_match_table[] = {
+	{ .compatible = "qcom,gcc-mdss-8952" },
+	{ .compatible = "qcom,gcc-mdss-8937" },
+	{ .compatible = "qcom,gcc-mdss-8917" },
+	{ .compatible = "qcom,gcc-mdss-8940" },
+	{ .compatible = "qcom,gcc-mdss-8920" },
+	{}
+};
+
+static struct platform_driver msm_clock_gcc_mdss_driver = {
+	.probe = msm_gcc_mdss_probe,
+	.driver = {
+		.name = "gcc-mdss-8952",
+		.of_match_table = msm_clock_mdss_match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_gcc_mdss_init(void)
+{
+	return platform_driver_register(&msm_clock_gcc_mdss_driver);
+}
+arch_initcall(msm_gcc_init);
+fs_initcall_sync(msm_gcc_mdss_init);
+late_initcall(msm_clock_debug_init);
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 10e12e7..688c776 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -74,6 +74,15 @@
 	---help---
 	  Toshiba TC358767 eDP bridge chip driver.
 
+config DRM_LT_LT9611
+	bool "LT LT9611 DSI/HDMI Bridge"
+	depends on OF
+	select DRM_KMS_HELPER
+	select REGMAP_I2C
+	select DRM_MIPI_DSI
+	help
+	  Support for the LT Devices LT9611 DSI to HDMI encoder.
+
 source "drivers/gpu/drm/bridge/analogix/Kconfig"
 
 source "drivers/gpu/drm/bridge/adv7511/Kconfig"
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index cdf3a3c..68cf605 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -10,3 +10,4 @@
 obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o
 obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/
 obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/
+obj-$(CONFIG_DRM_LT_LT9611) += lt9611.o
diff --git a/drivers/gpu/drm/bridge/lt9611.c b/drivers/gpu/drm/bridge/lt9611.c
new file mode 100644
index 0000000..4327e93
--- /dev/null
+++ b/drivers/gpu/drm/bridge/lt9611.c
@@ -0,0 +1,2180 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/of_gpio.h>
+#include <linux/of_graph.h>
+#include <linux/of_irq.h>
+#include <linux/regulator/consumer.h>
+#include <linux/hdmi.h>
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_mipi_dsi.h>
+
+
+#define CFG_HPD_INTERRUPTS BIT(0)
+#define CFG_EDID_INTERRUPTS BIT(1)
+#define CFG_CEC_INTERRUPTS BIT(2)
+#define CFG_VID_CHK_INTERRUPTS BIT(3)
+
+#define EDID_SEG_SIZE 256
+
+struct lt9611_reg_cfg {
+	u8 reg;
+	u8 val;
+	int sleep_in_ms;
+};
+
+struct lt9611_vreg {
+	struct regulator *vreg; /* vreg handle */
+	char vreg_name[32];
+	int min_voltage;
+	int max_voltage;
+	int enable_load;
+	int disable_load;
+	int pre_on_sleep;
+	int post_on_sleep;
+	int pre_off_sleep;
+	int post_off_sleep;
+};
+
+struct lt9611_video_cfg {
+	u32 h_active;
+	u32 h_front_porch;
+	u32 h_pulse_width;
+	u32 h_back_porch;
+	bool h_polarity;
+	u32 v_active;
+	u32 v_front_porch;
+	u32 v_pulse_width;
+	u32 v_back_porch;
+	bool v_polarity;
+	u32 pclk_khz;
+	bool interlaced;
+	u32 vic;
+	enum hdmi_picture_aspect ar;
+	u32 num_of_lanes;
+	u32 num_of_intfs;
+	u8 scaninfo;
+};
+
+struct lt9611 {
+	struct device *dev;
+	struct drm_bridge bridge;
+
+	struct device_node *host_node;
+	struct mipi_dsi_device *dsi;
+
+	u8 i2c_addr;
+	int irq;
+	bool ac_mode;
+
+	u32 irq_gpio;
+	u32 reset_gpio;
+	u32 hdmi_ps_gpio;
+	u32 hdmi_en_gpio;
+
+	unsigned int num_vreg;
+	struct lt9611_vreg *vreg_config;
+
+	struct i2c_client *i2c_client;
+
+	enum drm_connector_status status;
+	bool power_on;
+
+	/* get display modes from device tree */
+	bool non_pluggable;
+	u32 num_of_modes;
+	struct list_head mode_list;
+
+	struct drm_display_mode curr_mode;
+	struct lt9611_video_cfg video_cfg;
+
+	u8 edid_buf[EDID_SEG_SIZE];
+	bool hdmi_mode;
+};
+
+static struct lt9611_reg_cfg lt9611_init_setup[] = {
+	/* LT9611_System_Init */
+	{0xFF, 0x81, 0},
+	{0x01, 0x18, 0}, /* sel xtal clock */
+
+	/* timer for frequency meter */
+	{0xff, 0x82, 0},
+	{0x1b, 0x69, 0}, /*timer 2*/
+	{0x1c, 0x78, 0},
+	{0xcb, 0x69, 0}, /*timer 1 */
+	{0xcc, 0x78, 0},
+
+	/* irq init */
+	{0xff, 0x82, 0},
+	{0x51, 0x01, 0},
+	{0x58, 0x0a, 0}, /* hpd irq */
+	{0x59, 0x80, 0}, /* hpd debounce width */
+	{0x9e, 0xf7, 0}, /* video check irq */
+
+	/* power consumption for work */
+	{0xff, 0x80, 0},
+	{0x04, 0xf0, 0},
+	{0x06, 0xf0, 0},
+	{0x0a, 0x80, 0},
+	{0x0b, 0x40, 0},
+	{0x0d, 0xef, 0},
+	{0x11, 0xfa, 0},
+};
+
+struct lt9611_timing_info {
+	u16 xres;
+	u16 yres;
+	u8 bpp;
+	u8 fps;
+	u8 lanes;
+	u8 intfs;
+};
+
+static struct lt9611_timing_info lt9611_supp_timing_cfg[] = {
+	{3840, 2160, 24, 30, 4, 2}, /* 3840x2160 24bit 30Hz 4Lane 2ports */
+	{1920, 1080, 24, 60, 4, 1}, /* 1080P 24bit 60Hz 4lane 1port */
+	{1920, 1080, 24, 30, 3, 1}, /* 1080P 24bit 30Hz 3lane 1port */
+	{1920, 1080, 24, 24, 3, 1},
+	{720, 480, 24, 60, 2, 1},
+	{720, 576, 24, 50, 2, 1},
+	{640, 480, 24, 60, 2, 1},
+	{0xffff, 0xffff, 0xff, 0xff, 0xff},
+};
+
+static struct lt9611 *bridge_to_lt9611(struct drm_bridge *bridge)
+{
+	return container_of(bridge, struct lt9611, bridge);
+}
+
+static struct lt9611 *connector_to_lt9611(struct drm_connector *connector)
+{
+	WARN_ON(!connector->private);
+
+	return bridge_to_lt9611(connector->private);
+}
+
+static int lt9611_write(struct lt9611 *pdata, u8 reg, u8 val)
+{
+	struct i2c_client *client = pdata->i2c_client;
+	u8 buf[2] = {reg, val};
+	struct i2c_msg msg = {
+		.addr = client->addr,
+		.flags = 0,
+		.len = 2,
+		.buf = buf,
+	};
+
+	if (i2c_transfer(client->adapter, &msg, 1) < 1) {
+		pr_err("i2c write failed\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int lt9611_read(struct lt9611 *pdata, u8 reg, char *buf, u32 size)
+{
+	struct i2c_client *client = pdata->i2c_client;
+	struct i2c_msg msg[2] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = 1,
+			.buf = &reg,
+		},
+		{
+			.addr = client->addr,
+			.flags = I2C_M_RD,
+			.len = size,
+			.buf = buf,
+		}
+	};
+
+	if (i2c_transfer(client->adapter, msg, 2) != 2) {
+		pr_err("i2c read failed\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int lt9611_write_array(struct lt9611 *pdata,
+	struct lt9611_reg_cfg *cfg, int size)
+{
+	int ret = 0;
+	int i;
+
+	size = size / sizeof(struct lt9611_reg_cfg);
+	for (i = 0; i < size; i++) {
+		ret = lt9611_write(pdata, cfg[i].reg, cfg[i].val);
+
+		if (ret != 0) {
+			pr_err("reg writes failed. Last write %02X to %02X\n",
+				cfg[i].val, cfg[i].reg);
+			goto w_regs_fail;
+		}
+
+		if (cfg[i].sleep_in_ms)
+			msleep(cfg[i].sleep_in_ms);
+	}
+
+w_regs_fail:
+	if (ret != 0)
+		pr_err("exiting with ret = %d after %d writes\n", ret, i);
+
+	return ret;
+}
+
+static int lt9611_parse_dt_modes(struct device_node *np,
+					struct list_head *head,
+					u32 *num_of_modes)
+{
+	int rc = 0;
+	struct drm_display_mode *mode;
+	u32 mode_count = 0;
+	struct device_node *node = NULL;
+	struct device_node *root_node = NULL;
+	u32 h_front_porch, h_pulse_width, h_back_porch;
+	u32 v_front_porch, v_pulse_width, v_back_porch;
+	bool h_active_high, v_active_high;
+	u32 flags = 0;
+
+	root_node = of_get_child_by_name(np, "lt,customize-modes");
+	if (!root_node) {
+		root_node = of_parse_phandle(np, "lt,customize-modes", 0);
+		if (!root_node) {
+			pr_info("No entry present for lt,customize-modes");
+			goto end;
+		}
+	}
+
+	for_each_child_of_node(root_node, node) {
+		rc = 0;
+		mode = kzalloc(sizeof(*mode), GFP_KERNEL);
+		if (!mode) {
+			pr_err("Out of memory\n");
+			rc =  -ENOMEM;
+			continue;
+		}
+
+		rc = of_property_read_u32(node, "lt,mode-h-active",
+						&mode->hdisplay);
+		if (rc) {
+			pr_err("failed to read h-active, rc=%d\n", rc);
+			goto fail;
+		}
+
+		rc = of_property_read_u32(node, "lt,mode-h-front-porch",
+						&h_front_porch);
+		if (rc) {
+			pr_err("failed to read h-front-porch, rc=%d\n", rc);
+			goto fail;
+		}
+
+		rc = of_property_read_u32(node, "lt,mode-h-pulse-width",
+						&h_pulse_width);
+		if (rc) {
+			pr_err("failed to read h-pulse-width, rc=%d\n", rc);
+			goto fail;
+		}
+
+		rc = of_property_read_u32(node, "lt,mode-h-back-porch",
+						&h_back_porch);
+		if (rc) {
+			pr_err("failed to read h-back-porch, rc=%d\n", rc);
+			goto fail;
+		}
+
+		h_active_high = of_property_read_bool(node,
+						"lt,mode-h-active-high");
+
+		rc = of_property_read_u32(node, "lt,mode-v-active",
+						&mode->vdisplay);
+		if (rc) {
+			pr_err("failed to read v-active, rc=%d\n", rc);
+			goto fail;
+		}
+
+		rc = of_property_read_u32(node, "lt,mode-v-front-porch",
+						&v_front_porch);
+		if (rc) {
+			pr_err("failed to read v-front-porch, rc=%d\n", rc);
+			goto fail;
+		}
+
+		rc = of_property_read_u32(node, "lt,mode-v-pulse-width",
+						&v_pulse_width);
+		if (rc) {
+			pr_err("failed to read v-pulse-width, rc=%d\n", rc);
+			goto fail;
+		}
+
+		rc = of_property_read_u32(node, "lt,mode-v-back-porch",
+						&v_back_porch);
+		if (rc) {
+			pr_err("failed to read v-back-porch, rc=%d\n", rc);
+			goto fail;
+		}
+
+		v_active_high = of_property_read_bool(node,
+						"lt,mode-v-active-high");
+
+		rc = of_property_read_u32(node, "lt,mode-refresh-rate",
+						&mode->vrefresh);
+		if (rc) {
+			pr_err("failed to read refresh-rate, rc=%d\n", rc);
+			goto fail;
+		}
+
+		rc = of_property_read_u32(node, "lt,mode-clock-in-khz",
+						&mode->clock);
+		if (rc) {
+			pr_err("failed to read clock, rc=%d\n", rc);
+			goto fail;
+		}
+
+		mode->hsync_start = mode->hdisplay + h_front_porch;
+		mode->hsync_end = mode->hsync_start + h_pulse_width;
+		mode->htotal = mode->hsync_end + h_back_porch;
+		mode->vsync_start = mode->vdisplay + v_front_porch;
+		mode->vsync_end = mode->vsync_start + v_pulse_width;
+		mode->vtotal = mode->vsync_end + v_back_porch;
+		if (h_active_high)
+			flags |= DRM_MODE_FLAG_PHSYNC;
+		else
+			flags |= DRM_MODE_FLAG_NHSYNC;
+		if (v_active_high)
+			flags |= DRM_MODE_FLAG_PVSYNC;
+		else
+			flags |= DRM_MODE_FLAG_NVSYNC;
+		mode->flags = flags;
+
+		if (!rc) {
+			mode_count++;
+			list_add_tail(&mode->head, head);
+		}
+
+		drm_mode_set_name(mode);
+
+		pr_debug("mode[%s] h[%d,%d,%d,%d] v[%d,%d,%d,%d] %d %x %dkHZ\n",
+			mode->name, mode->hdisplay, mode->hsync_start,
+			mode->hsync_end, mode->htotal, mode->vdisplay,
+			mode->vsync_start, mode->vsync_end, mode->vtotal,
+			mode->vrefresh, mode->flags, mode->clock);
+fail:
+		if (rc) {
+			kfree(mode);
+			continue;
+		}
+	}
+
+	if (num_of_modes)
+		*num_of_modes = mode_count;
+
+end:
+	return rc;
+}
+
+
+static int lt9611_parse_dt(struct device *dev,
+	struct lt9611 *pdata)
+{
+	struct device_node *np = dev->of_node;
+	struct device_node *end_node;
+	int ret = 0;
+
+	end_node = of_graph_get_endpoint_by_regs(dev->of_node, 0, 0);
+	if (!end_node) {
+		pr_err("remote endpoint not found\n");
+		return -ENODEV;
+	}
+
+	pdata->host_node = of_graph_get_remote_port_parent(end_node);
+	of_node_put(end_node);
+	if (!pdata->host_node) {
+		pr_err("remote node not found\n");
+		return -ENODEV;
+	}
+	of_node_put(pdata->host_node);
+
+	pdata->irq_gpio =
+		of_get_named_gpio(np, "lt,irq-gpio", 0);
+	if (!gpio_is_valid(pdata->irq_gpio)) {
+		pr_err("irq gpio not specified\n");
+		ret = -EINVAL;
+	}
+	pr_debug("irq_gpio=%d\n", pdata->irq_gpio);
+
+	pdata->reset_gpio =
+		of_get_named_gpio(np, "lt,reset-gpio", 0);
+	if (!gpio_is_valid(pdata->reset_gpio)) {
+		pr_err("reset gpio not specified\n");
+		ret = -EINVAL;
+	}
+	pr_debug("reset_gpio=%d\n", pdata->reset_gpio);
+
+	pdata->hdmi_ps_gpio =
+		of_get_named_gpio(np, "lt,hdmi-ps-gpio", 0);
+	if (!gpio_is_valid(pdata->hdmi_ps_gpio))
+		pr_debug("hdmi ps gpio not specified\n");
+	else
+		pr_debug("hdmi_ps_gpio=%d\n", pdata->hdmi_ps_gpio);
+
+	pdata->hdmi_en_gpio =
+		of_get_named_gpio(np, "lt,hdmi-en-gpio", 0);
+	if (!gpio_is_valid(pdata->hdmi_en_gpio))
+		pr_debug("hdmi en gpio not specified\n");
+	else
+		pr_debug("hdmi_en_gpio=%d\n", pdata->hdmi_en_gpio);
+
+	pdata->ac_mode = of_property_read_bool(np, "lt,ac-mode");
+	pr_debug("ac_mode=%d\n", pdata->ac_mode);
+
+	pdata->non_pluggable = of_property_read_bool(np, "lt,non-pluggable");
+	pr_debug("non_pluggable = %d\n", pdata->non_pluggable);
+	if (pdata->non_pluggable) {
+		INIT_LIST_HEAD(&pdata->mode_list);
+		ret = lt9611_parse_dt_modes(np,
+			&pdata->mode_list, &pdata->num_of_modes);
+	}
+
+	return ret;
+}
+
+static int lt9611_gpio_configure(struct lt9611 *pdata, bool on)
+{
+	int ret = 0;
+
+	if (on) {
+		ret = gpio_request(pdata->reset_gpio,
+			"lt9611-reset-gpio");
+		if (ret) {
+			pr_err("lt9611 reset gpio request failed\n");
+			goto error;
+		}
+
+		ret = gpio_direction_output(pdata->reset_gpio, 0);
+		if (ret) {
+			pr_err("lt9611 reset gpio direction failed\n");
+			goto reset_error;
+		}
+
+		if (gpio_is_valid(pdata->hdmi_en_gpio)) {
+			ret = gpio_request(pdata->hdmi_en_gpio,
+					"lt9611-hdmi-en-gpio");
+			if (ret) {
+				pr_err("lt9611 hdmi en gpio request failed\n");
+				goto reset_error;
+			}
+
+			ret = gpio_direction_output(pdata->hdmi_en_gpio, 1);
+			if (ret) {
+				pr_err("lt9611 hdmi en gpio direction failed\n");
+				goto hdmi_en_error;
+			}
+		}
+
+		if (gpio_is_valid(pdata->hdmi_ps_gpio)) {
+			ret = gpio_request(pdata->hdmi_ps_gpio,
+				"lt9611-hdmi-ps-gpio");
+			if (ret) {
+				pr_err("lt9611 hdmi ps gpio request failed\n");
+				goto hdmi_en_error;
+			}
+
+			ret = gpio_direction_input(pdata->hdmi_ps_gpio);
+			if (ret) {
+				pr_err("lt9611 hdmi ps gpio direction failed\n");
+				goto hdmi_ps_error;
+			}
+		}
+
+		ret = gpio_request(pdata->irq_gpio, "lt9611-irq-gpio");
+		if (ret) {
+			pr_err("lt9611 irq gpio request failed\n");
+			goto hdmi_ps_error;
+		}
+
+		ret = gpio_direction_input(pdata->irq_gpio);
+		if (ret) {
+			pr_err("lt9611 irq gpio direction failed\n");
+			goto irq_error;
+		}
+	} else {
+		gpio_free(pdata->irq_gpio);
+		if (gpio_is_valid(pdata->hdmi_ps_gpio))
+			gpio_free(pdata->hdmi_ps_gpio);
+		if (gpio_is_valid(pdata->hdmi_en_gpio))
+			gpio_free(pdata->hdmi_en_gpio);
+		gpio_free(pdata->reset_gpio);
+	}
+
+	return ret;
+
+
+irq_error:
+	gpio_free(pdata->irq_gpio);
+hdmi_ps_error:
+	if (gpio_is_valid(pdata->hdmi_ps_gpio))
+		gpio_free(pdata->hdmi_ps_gpio);
+hdmi_en_error:
+	if (gpio_is_valid(pdata->hdmi_en_gpio))
+		gpio_free(pdata->hdmi_en_gpio);
+reset_error:
+	gpio_free(pdata->reset_gpio);
+error:
+	return ret;
+}
+
+static int lt9611_read_device_rev(struct lt9611 *pdata)
+{
+	u8 rev = 0;
+	int ret = 0;
+
+	lt9611_write(pdata, 0xff, 0x80);
+	lt9611_write(pdata, 0xee, 0x01);
+
+	ret = lt9611_read(pdata, 0x02, &rev, 1);
+
+	if (ret == 0)
+		pr_info("LT9611 revsion: 0x%x\n", rev);
+
+	return ret;
+}
+
+static int lt9611_mipi_input_analog(struct lt9611 *pdata,
+		struct lt9611_video_cfg *cfg)
+{
+	struct lt9611_reg_cfg reg_cfg[] = {
+		{0xff, 0x81, 0},
+		{0x06, 0x40, 0}, /*port A rx current*/
+		{0x0a, 0xfe, 0}, /*port A ldo voltage set*/
+		{0x0b, 0xbf, 0}, /*enable port A lprx*/
+		{0x11, 0x40, 0}, /*port B rx current*/
+		{0x15, 0xfe, 0}, /*port B ldo voltage set*/
+		{0x16, 0xbf, 0}, /*enable port B lprx*/
+
+		{0x1c, 0x03, 0}, /*PortA clk lane no-LP mode*/
+		{0x20, 0x03, 0}, /*PortB clk lane with-LP mode*/
+	};
+
+	if (!pdata || !cfg) {
+		pr_err("invalid input\n");
+		return -EINVAL;
+	}
+
+	lt9611_write_array(pdata, reg_cfg, sizeof(reg_cfg));
+
+	return 0;
+}
+
+static int lt9611_mipi_input_digital(struct lt9611 *pdata,
+	struct lt9611_video_cfg *cfg)
+{
+	u8 lanes = 0;
+	u8 ports = 0;
+	struct lt9611_reg_cfg reg_cfg[] = {
+		{0xff, 0x82, 0},
+		{0x4f, 0x80, 0},
+		{0x50, 0x10, 0},
+		{0xff, 0x83, 0},
+
+		{0x02, 0x0a, 0},
+		{0x06, 0x0a, 0},
+	};
+
+	if (!pdata || !cfg) {
+		pr_err("invalid input\n");
+		return -EINVAL;
+	}
+
+	lanes = cfg->num_of_lanes;
+	ports = cfg->num_of_intfs;
+
+	lt9611_write(pdata, 0xff, 0x83);
+	if (lanes == 4)
+		lt9611_write(pdata, 0x00, 0x00);
+	else if (lanes < 4)
+		lt9611_write(pdata, 0x00, lanes);
+	else {
+		pr_err("invalid lane count\n");
+		return -EINVAL;
+	}
+
+	if (ports == 1)
+		lt9611_write(pdata, 0x0a, 0x00);
+	else if (ports == 2)
+		lt9611_write(pdata, 0x0a, 0x03);
+	else {
+		pr_err("invalid port count\n");
+		return -EINVAL;
+	}
+
+	lt9611_write_array(pdata, reg_cfg, sizeof(reg_cfg));
+
+	return 0;
+}
+
+static void lt9611_mipi_video_setup(struct lt9611 *pdata,
+	struct lt9611_video_cfg *cfg)
+{
+	u32 h_total, h_act, hpw, hfp, hss;
+	u32 v_total, v_act, vpw, vfp, vss;
+
+	if (!pdata || !cfg) {
+		pr_err("invalid input\n");
+		return;
+	}
+
+	h_total = cfg->h_active + cfg->h_front_porch +
+	      cfg->h_pulse_width + cfg->h_back_porch;
+	v_total = cfg->v_active + cfg->v_front_porch +
+	      cfg->v_pulse_width + cfg->v_back_porch;
+
+	h_act = cfg->h_active;
+	hpw = cfg->h_pulse_width;
+	hfp = cfg->h_front_porch;
+	hss = cfg->h_pulse_width + cfg->h_back_porch;
+
+	v_act = cfg->v_active;
+	vpw = cfg->v_pulse_width;
+	vfp = cfg->v_front_porch;
+	vss = cfg->v_pulse_width + cfg->v_back_porch;
+
+	pr_debug("h_total=%d, h_active=%d, hfp=%d, hpw=%d, hbp=%d\n",
+		h_total, cfg->h_active, cfg->h_front_porch,
+		cfg->h_pulse_width, cfg->h_back_porch);
+
+	pr_debug("v_total=%d, v_active=%d, vfp=%d, vpw=%d, vbp=%d\n",
+		v_total, cfg->v_active, cfg->v_front_porch,
+		cfg->v_pulse_width, cfg->v_back_porch);
+
+	lt9611_write(pdata, 0xff, 0x83);
+
+	lt9611_write(pdata, 0x0d, (u8)(v_total / 256));
+	lt9611_write(pdata, 0x0e, (u8)(v_total % 256));
+
+	lt9611_write(pdata, 0x0f, (u8)(v_act / 256));
+	lt9611_write(pdata, 0x10, (u8)(v_act % 256));
+
+	lt9611_write(pdata, 0x11, (u8)(h_total / 256));
+	lt9611_write(pdata, 0x12, (u8)(h_total % 256));
+
+	lt9611_write(pdata, 0x13, (u8)(h_act / 256));
+	lt9611_write(pdata, 0x14, (u8)(h_act % 256));
+
+	lt9611_write(pdata, 0x15, (u8)(vpw % 256));
+	lt9611_write(pdata, 0x16, (u8)(hpw % 256));
+
+	lt9611_write(pdata, 0x17, (u8)(vfp % 256));
+
+	lt9611_write(pdata, 0x18, (u8)(vss % 256));
+
+	lt9611_write(pdata, 0x19, (u8)(hfp % 256));
+
+	lt9611_write(pdata, 0x1a, (u8)(hss / 256));
+	lt9611_write(pdata, 0x1b, (u8)(hss % 256));
+}
+
+static int lt9611_pcr_setup(struct lt9611 *pdata,
+		struct lt9611_video_cfg *cfg)
+{
+	u32 h_act = 0;
+	struct lt9611_reg_cfg reg_cfg[] = {
+		{0xff, 0x83, 0},
+
+		{0x2d, 0x38, 0}, /* up_lmt */
+		{0x2e, 0x00, 0},
+		{0x31, 0x10, 0}, /* low lmt */
+		{0x32, 0x00, 0},
+
+		{0xff, 0x80, 0},
+		{0x11, 0x5a, 0}, /* pcr reset */
+		{0x11, 0xfa, 0},
+	};
+
+	if (!pdata || !cfg) {
+		pr_err("invalid input\n");
+		return -EINVAL;
+	}
+
+	h_act = cfg->h_active;
+
+	if (h_act == 1920) {
+		lt9611_write(pdata, 0xff, 0x83);
+		lt9611_write(pdata, 0x48, 0x00);
+		lt9611_write(pdata, 0x49, 0x81);
+
+		lt9611_write(pdata, 0x4a, 0x10);
+		lt9611_write(pdata, 0x1d, 0x10);
+		lt9611_write(pdata, 0x21, 0x41);
+		lt9611_write(pdata, 0x22, 0x40);
+		lt9611_write(pdata, 0x24, 0x11);
+		lt9611_write(pdata, 0x25, 0x30);
+		lt9611_write(pdata, 0x26, 0x37);
+		lt9611_write(pdata, 0x2a, 0x02);
+	} else if (h_act == 3840) {
+		lt9611_write(pdata, 0xff, 0x83);
+		lt9611_write(pdata, 0x0b, 0x03);
+		lt9611_write(pdata, 0x0c, 0xd0);
+		lt9611_write(pdata, 0x48, 0x03);
+		lt9611_write(pdata, 0x49, 0xd0);
+
+		lt9611_write(pdata, 0x4a, 0x01);
+		lt9611_write(pdata, 0x1d, 0x10);
+		lt9611_write(pdata, 0x21, 0x41);
+		lt9611_write(pdata, 0x22, 0x40);
+		lt9611_write(pdata, 0x24, 0x70);
+		lt9611_write(pdata, 0x25, 0x50);
+		lt9611_write(pdata, 0x26, 0x37);
+		lt9611_write(pdata, 0x2a, 0x03);
+	} else if (h_act == 640) {
+		lt9611_write(pdata, 0xff, 0x83);
+		lt9611_write(pdata, 0x0b, 0x01);
+		lt9611_write(pdata, 0x0c, 0x20);
+		lt9611_write(pdata, 0x48, 0x00);
+		lt9611_write(pdata, 0x49, 0x81);
+
+		lt9611_write(pdata, 0x4a, 0x10);
+		lt9611_write(pdata, 0x1d, 0x10);
+		lt9611_write(pdata, 0x21, 0x41);
+		lt9611_write(pdata, 0x22, 0x40);
+		lt9611_write(pdata, 0x24, 0x11);
+		lt9611_write(pdata, 0x25, 0x30);
+		lt9611_write(pdata, 0x26, 0x13);
+		lt9611_write(pdata, 0x2a, 0x03);
+	}
+
+	lt9611_write_array(pdata, reg_cfg, sizeof(reg_cfg));
+
+	return 0;
+}
+
+static int lt9611_pll_setup(struct lt9611 *pdata,
+		struct lt9611_video_cfg *cfg)
+{
+	u32 pclk = 0;
+	struct lt9611_reg_cfg reg_cfg[] = {
+		/* txpll init */
+		{0xff, 0x81, 0},
+		{0x23, 0x40, 0},
+		{0x24, 0x64, 0},
+		{0x25, 0x80, 0},
+		{0x26, 0x55, 0},
+		{0x2c, 0x37, 0},
+		{0x2f, 0x01, 0},
+		{0x26, 0x55, 0},
+		{0x27, 0x66, 0},
+		{0x28, 0x88, 0},
+	};
+
+	if (!pdata || !cfg) {
+		pr_err("invalid input\n");
+		return -EINVAL;
+	}
+
+	pclk = cfg->pclk_khz;
+
+	lt9611_write_array(pdata, reg_cfg, sizeof(reg_cfg));
+
+	if (pclk > 150000)
+		lt9611_write(pdata, 0x2d, 0x88);
+	else if (pclk > 70000)
+		lt9611_write(pdata, 0x2d, 0x99);
+	else
+		lt9611_write(pdata, 0x2d, 0xaa);
+
+	lt9611_write(pdata, 0xff, 0x82);
+	pclk = pclk / 2;
+	lt9611_write(pdata, 0xe3, pclk/65536); /* pclk[19:16] */
+	pclk = pclk % 65536;
+	lt9611_write(pdata, 0xe4, pclk/256);   /* pclk[15:8]  */
+	lt9611_write(pdata, 0xe5, pclk%256);   /* pclk[7:0]   */
+
+	lt9611_write(pdata, 0xde, 0x20);
+	lt9611_write(pdata, 0xde, 0xe0);
+
+	lt9611_write(pdata, 0xff, 0x80);
+	lt9611_write(pdata, 0x16, 0xf1);
+	lt9611_write(pdata, 0x16, 0xf3);
+
+	return 0;
+}
+
+static int lt9611_video_check(struct lt9611 *pdata)
+{
+	int ret = 0;
+	u32 v_total, v_act, h_act_a, h_act_b, h_total_sysclk;
+	u8 temp = 0;
+
+	if (!pdata) {
+		pr_err("invalid input\n");
+		return -EINVAL;
+	}
+
+	/* top module video check */
+	lt9611_write(pdata, 0xff, 0x82);
+
+	/* v_act */
+	ret = lt9611_read(pdata, 0x82, &temp, 1);
+	if (ret)
+		goto end;
+
+	v_act = temp << 8;
+	ret = lt9611_read(pdata, 0x83, &temp, 1);
+	if (ret)
+		goto end;
+	v_act = v_act + temp;
+
+	/* v_total */
+	ret = lt9611_read(pdata, 0x6c, &temp, 1);
+	if (ret)
+		goto end;
+	v_total = temp << 8;
+	ret = lt9611_read(pdata, 0x6d, &temp, 1);
+	if (ret)
+		goto end;
+	v_total = v_total + temp;
+
+	/* h_total_sysclk */
+	ret = lt9611_read(pdata, 0x86, &temp, 1);
+	if (ret)
+		goto end;
+	h_total_sysclk = temp << 8;
+	ret = lt9611_read(pdata, 0x87, &temp, 1);
+	if (ret)
+		goto end;
+	h_total_sysclk = h_total_sysclk + temp;
+
+	/* h_act_a */
+	lt9611_write(pdata, 0xff, 0x83);
+	ret = lt9611_read(pdata, 0x82, &temp, 1);
+	if (ret)
+		goto end;
+	h_act_a = temp << 8;
+	ret = lt9611_read(pdata, 0x83, &temp, 1);
+	if (ret)
+		goto end;
+	h_act_a = (h_act_a + temp)/3;
+
+	/* h_act_b */
+	lt9611_write(pdata, 0xff, 0x83);
+	ret = lt9611_read(pdata, 0x86, &temp, 1);
+	if (ret)
+		goto end;
+	h_act_b = temp << 8;
+	ret = lt9611_read(pdata, 0x87, &temp, 1);
+	if (ret)
+		goto end;
+	h_act_b = (h_act_b + temp)/3;
+
+	pr_info("video check: h_act_a=%d, h_act_b=%d, v_act=%d, v_total=%d, h_total_sysclk=%d\n",
+		h_act_a, h_act_b, v_act, v_total, h_total_sysclk);
+
+	return 0;
+
+end:
+	pr_err("read video check error\n");
+	return ret;
+}
+
+static int lt9611_hdmi_tx_digital(struct lt9611 *pdata,
+		struct lt9611_video_cfg *cfg)
+{
+	int ret = -EINVAL;
+	u32 checksum, vic;
+
+	if (!pdata || !cfg) {
+		pr_err("invalid input\n");
+		return ret;
+	}
+
+	vic = cfg->vic;
+	checksum = 0x46 - vic;
+
+	lt9611_write(pdata, 0xff, 0x84);
+	lt9611_write(pdata, 0x43, checksum);
+	lt9611_write(pdata, 0x44, 0x84);
+	lt9611_write(pdata, 0x47, vic);
+
+	lt9611_write(pdata, 0xff, 0x82);
+	lt9611_write(pdata, 0xd6, 0x8c);
+	lt9611_write(pdata, 0xd7, 0x04);
+
+	return ret;
+}
+
+static int lt9611_hdmi_tx_phy(struct lt9611 *pdata,
+		struct lt9611_video_cfg *cfg)
+{
+	int ret = -EINVAL;
+	struct lt9611_reg_cfg reg_cfg[] = {
+		{0xff, 0x81, 0},
+		{0x30, 0x6a, 0},
+		{0x31, 0x44, 0}, /* HDMI DC mode */
+		{0x32, 0x4a, 0},
+		{0x33, 0x0b, 0},
+		{0x34, 0x00, 0},
+		{0x35, 0x00, 0},
+		{0x36, 0x00, 0},
+		{0x37, 0x44, 0},
+		{0x3f, 0x0f, 0},
+		{0x40, 0xa0, 0},
+		{0x41, 0xa0, 0},
+		{0x42, 0xa0, 0},
+		{0x43, 0xa0, 0},
+		{0x44, 0x0a, 0},
+	};
+
+	if (!pdata || !cfg) {
+		pr_err("invalid input\n");
+		return ret;
+	}
+
+	/* HDMI AC mode */
+	if (pdata->ac_mode)
+		reg_cfg[2].val = 0x73;
+
+	lt9611_write_array(pdata, reg_cfg, sizeof(reg_cfg));
+
+	return ret;
+}
+
+static void lt9611_hdmi_output_enable(struct lt9611 *pdata)
+{
+	lt9611_write(pdata, 0xff, 0x81);
+	lt9611_write(pdata, 0x30, 0xea);
+}
+
+static void lt9611_hdmi_output_disable(struct lt9611 *pdata)
+{
+	lt9611_write(pdata, 0xff, 0x81);
+	lt9611_write(pdata, 0x30, 0x6a);
+}
+
+static irqreturn_t lt9611_irq_thread_handler(int irq, void *dev_id)
+{
+	struct lt9611 *pdata = dev_id;
+	u8 irq_flag0 = 0;
+	u8 irq_flag3 = 0;
+
+	lt9611_write(pdata, 0xff, 0x82);
+	lt9611_read(pdata, 0x0f, &irq_flag3, 1);
+	lt9611_read(pdata, 0x0c, &irq_flag0, 1);
+
+	 /* hpd changed low */
+	if (irq_flag3 & 0x80) {
+		pr_info("hdmi cable disconnected\n");
+
+		lt9611_write(pdata, 0xff, 0x82); /* irq 3 clear flag */
+		lt9611_write(pdata, 0x07, 0xbf);
+		lt9611_write(pdata, 0x07, 0x3f);
+	}
+	 /* hpd changed high */
+	if (irq_flag3 & 0x40) {
+		pr_info("hdmi cable connected\n");
+
+		lt9611_write(pdata, 0xff, 0x82); /* irq 3 clear flag */
+		lt9611_write(pdata, 0x07, 0x7f);
+		lt9611_write(pdata, 0x07, 0x3f);
+	}
+
+	/* video input changed */
+	if (irq_flag0 & 0x01) {
+		pr_info("video input changed\n");
+		lt9611_write(pdata, 0xff, 0x82); /* irq 0 clear flag */
+		lt9611_write(pdata, 0x9e, 0xff);
+		lt9611_write(pdata, 0x9e, 0xf7);
+		lt9611_write(pdata, 0x04, 0xff);
+		lt9611_write(pdata, 0x04, 0xfe);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int lt9611_enable_interrupts(struct lt9611 *pdata, int interrupts)
+{
+	int ret = 0;
+	u8 reg_val = 0;
+	u8 init_reg_val;
+
+	if (!pdata) {
+		pr_err("invalid input\n");
+		goto end;
+	}
+
+	if (interrupts & CFG_VID_CHK_INTERRUPTS) {
+		lt9611_write(pdata, 0xff, 0x82);
+		lt9611_read(pdata, 0x00, &reg_val, 1);
+
+		if (reg_val & 0x01) {
+			init_reg_val = reg_val & 0xfe;
+			pr_debug("enabling video check interrupts\n");
+			lt9611_write(pdata, 0x00, init_reg_val);
+		}
+		lt9611_write(pdata, 0x04, 0xff); /* clear */
+		lt9611_write(pdata, 0x04, 0xfe);
+	}
+
+	if (interrupts & CFG_HPD_INTERRUPTS) {
+		lt9611_write(pdata, 0xff, 0x82);
+		lt9611_read(pdata, 0x03, &reg_val, 1);
+
+		if (reg_val & 0xc0) { //reg_val | 0xc0???
+			init_reg_val = reg_val & 0x3f;
+			pr_debug("enabling hpd interrupts\n");
+			lt9611_write(pdata, 0x03, init_reg_val);
+		}
+
+		lt9611_write(pdata, 0x07, 0xff); //clear
+		lt9611_write(pdata, 0x07, 0x3f);
+	}
+
+end:
+	return ret;
+}
+
+static void lt9611_pcr_mk_debug(struct lt9611 *pdata)
+{
+	u8 m = 0, k1 = 0, k2 = 0, k3 = 0;
+
+	lt9611_write(pdata, 0xff, 0x83);
+	lt9611_read(pdata, 0xb4, &m, 1);
+	lt9611_read(pdata, 0xb5, &k1, 1);
+	lt9611_read(pdata, 0xb6, &k2, 1);
+	lt9611_read(pdata, 0xb7, &k3, 1);
+
+	pr_info("pcr mk:0x%x 0x%x 0x%x 0x%x\n",
+			m, k1, k2, k3);
+}
+
+static void lt9611_sleep_setup(struct lt9611 *pdata)
+{
+	struct lt9611_reg_cfg sleep_setup[] = {
+		{0xff, 0x80, 0}, //register I2C addr
+		{0x24, 0x76, 0},
+		{0x23, 0x01, 0},
+		{0xff, 0x81, 0}, //set addr pin as output
+		{0x57, 0x03, 0},
+		{0x49, 0x0b, 0},
+		{0xff, 0x81, 0}, //anlog power down
+		{0x51, 0x30, 0}, //disable IRQ
+		{0x02, 0x48, 0}, //MIPI Rx power down
+		{0x23, 0x80, 0},
+		{0x30, 0x00, 0},
+		{0x00, 0x01, 0}, //bandgap power down
+		{0x01, 0x00, 0}, //system clk power down
+	};
+
+	pr_err("sleep\n");
+
+	lt9611_write_array(pdata, sleep_setup, sizeof(sleep_setup));
+}
+
+static int lt9611_power_on(struct lt9611 *pdata, bool on)
+{
+	int ret = 0;
+
+	pr_debug("power_on: on=%d\n", on);
+
+	if (on && !pdata->power_on) {
+		lt9611_write_array(pdata, lt9611_init_setup,
+			sizeof(lt9611_init_setup));
+
+		ret = lt9611_enable_interrupts(pdata, CFG_HPD_INTERRUPTS);
+		if (ret) {
+			pr_err("Failed to enable HPD intr %d\n", ret);
+			return ret;
+		}
+		pdata->power_on = true;
+	} else if (!on) {
+		lt9611_write(pdata, 0xff, 0x81);
+		lt9611_write(pdata, 0x30, 0x6a);
+
+		pdata->power_on = false;
+	}
+
+	return ret;
+}
+
+static int lt9611_video_on(struct lt9611 *pdata, bool on)
+{
+	int ret = 0;
+	struct lt9611_video_cfg *cfg = &pdata->video_cfg;
+
+	pr_debug("on=%d\n", on);
+
+	if (on) {
+		lt9611_mipi_input_analog(pdata, cfg);
+		lt9611_mipi_input_digital(pdata, cfg);
+		lt9611_pll_setup(pdata, cfg);
+		lt9611_mipi_video_setup(pdata, cfg);
+		lt9611_pcr_setup(pdata, cfg);
+		lt9611_hdmi_tx_digital(pdata, cfg);
+		lt9611_hdmi_tx_phy(pdata, cfg);
+
+		msleep(500);
+
+		lt9611_video_check(pdata);
+		lt9611_hdmi_output_enable(pdata);
+	} else {
+		lt9611_hdmi_output_disable(pdata);
+	}
+
+	return ret;
+}
+
+static void lt9611_mipi_byte_clk_debug(struct lt9611 *pdata)
+{
+	u8 reg_val = 0;
+	u32 byte_clk;
+
+	/* port A byte clk meter */
+	lt9611_write(pdata, 0xff, 0x82);
+	lt9611_write(pdata, 0xc7, 0x03); /* port A */
+	msleep(50);
+	lt9611_read(pdata, 0xcd, &reg_val, 1);
+
+	if ((reg_val & 0x60) == 0x60) {
+		byte_clk =  (reg_val & 0x0f) * 65536;
+		lt9611_read(pdata, 0xce, &reg_val, 1);
+		byte_clk = byte_clk + reg_val * 256;
+		lt9611_read(pdata, 0xcf, &reg_val, 1);
+		byte_clk = byte_clk + reg_val;
+
+		pr_info("port A byte clk = %d khz,\n", byte_clk);
+	} else
+		pr_info("port A byte clk unstable\n");
+
+	/* port B byte clk meter */
+	lt9611_write(pdata, 0xff, 0x82);
+	lt9611_write(pdata, 0xc7, 0x04); /* port B */
+	msleep(50);
+	lt9611_read(pdata, 0xcd, &reg_val, 1);
+
+	if ((reg_val & 0x60) == 0x60) {
+		byte_clk =  (reg_val & 0x0f) * 65536;
+		lt9611_read(pdata, 0xce, &reg_val, 1);
+		byte_clk = byte_clk + reg_val * 256;
+		lt9611_read(pdata, 0xcf, &reg_val, 1);
+		byte_clk = byte_clk + reg_val;
+
+		pr_info("port B byte clk = %d khz,\n", byte_clk);
+	} else
+		pr_info("port B byte clk unstable\n");
+}
+
+static void lt9611_reset(struct lt9611 *pdata)
+{
+	gpio_set_value(pdata->reset_gpio, 1);
+	msleep(20);
+	gpio_set_value(pdata->reset_gpio, 0);
+	msleep(20);
+	gpio_set_value(pdata->reset_gpio, 1);
+	msleep(20);
+}
+
+static void lt9611_assert_5v(struct lt9611 *pdata)
+{
+	if (gpio_is_valid(pdata->hdmi_en_gpio)) {
+		gpio_set_value(pdata->hdmi_en_gpio, 1);
+		msleep(20);
+	}
+}
+
+static int lt9611_config_vreg(struct device *dev,
+	struct lt9611_vreg *in_vreg, int num_vreg, bool config)
+{
+	int i = 0, rc = 0;
+	struct lt9611_vreg *curr_vreg = NULL;
+
+	if (!in_vreg || !num_vreg)
+		return rc;
+
+	if (config) {
+		for (i = 0; i < num_vreg; i++) {
+			curr_vreg = &in_vreg[i];
+			curr_vreg->vreg = regulator_get(dev,
+					curr_vreg->vreg_name);
+			rc = PTR_RET(curr_vreg->vreg);
+			if (rc) {
+				pr_err("%s get failed. rc=%d\n",
+						curr_vreg->vreg_name, rc);
+				curr_vreg->vreg = NULL;
+				goto vreg_get_fail;
+			}
+
+			rc = regulator_set_voltage(
+					curr_vreg->vreg,
+					curr_vreg->min_voltage,
+					curr_vreg->max_voltage);
+			if (rc < 0) {
+				pr_err("%s set vltg fail\n",
+						curr_vreg->vreg_name);
+				goto vreg_set_voltage_fail;
+			}
+		}
+	} else {
+		for (i = num_vreg-1; i >= 0; i--) {
+			curr_vreg = &in_vreg[i];
+			if (curr_vreg->vreg) {
+				regulator_set_voltage(curr_vreg->vreg,
+						0, curr_vreg->max_voltage);
+
+				regulator_put(curr_vreg->vreg);
+				curr_vreg->vreg = NULL;
+			}
+		}
+	}
+	return 0;
+
+vreg_unconfig:
+	regulator_set_load(curr_vreg->vreg, 0);
+
+vreg_set_voltage_fail:
+	regulator_put(curr_vreg->vreg);
+	curr_vreg->vreg = NULL;
+
+vreg_get_fail:
+	for (i--; i >= 0; i--) {
+		curr_vreg = &in_vreg[i];
+		goto vreg_unconfig;
+	}
+	return rc;
+}
+
+static int lt9611_get_dt_supply(struct device *dev,
+		struct lt9611 *pdata)
+{
+	int i = 0, rc = 0;
+	u32 tmp = 0;
+	struct device_node *of_node = NULL, *supply_root_node = NULL;
+	struct device_node *supply_node = NULL;
+
+	if (!dev || !pdata) {
+		pr_err("invalid input param dev:%pK pdata:%pK\n", dev, pdata);
+		return -EINVAL;
+	}
+
+	of_node = dev->of_node;
+
+	pdata->num_vreg = 0;
+	supply_root_node = of_get_child_by_name(of_node,
+			"lt,supply-entries");
+	if (!supply_root_node) {
+		pr_info("no supply entry present\n");
+		return 0;
+	}
+
+	pdata->num_vreg = of_get_available_child_count(supply_root_node);
+	if (pdata->num_vreg == 0) {
+		pr_info("no vreg present\n");
+		return 0;
+	}
+
+	pr_debug("vreg found. count=%d\n", pdata->num_vreg);
+	pdata->vreg_config = devm_kzalloc(dev, sizeof(struct lt9611_vreg) *
+			pdata->num_vreg, GFP_KERNEL);
+	if (!pdata->vreg_config)
+		return -ENOMEM;
+
+	for_each_available_child_of_node(supply_root_node, supply_node) {
+		const char *st = NULL;
+
+		rc = of_property_read_string(supply_node,
+				"lt,supply-name", &st);
+		if (rc) {
+			pr_err("error reading name. rc=%d\n", rc);
+			goto error;
+		}
+
+		strlcpy(pdata->vreg_config[i].vreg_name, st,
+				sizeof(pdata->vreg_config[i].vreg_name));
+
+		rc = of_property_read_u32(supply_node,
+				"lt,supply-min-voltage", &tmp);
+		if (rc) {
+			pr_err("error reading min volt. rc=%d\n", rc);
+			goto error;
+		}
+		pdata->vreg_config[i].min_voltage = tmp;
+
+		rc = of_property_read_u32(supply_node,
+				"lt,supply-max-voltage", &tmp);
+		if (rc) {
+			pr_err("error reading max volt. rc=%d\n", rc);
+			goto error;
+		}
+		pdata->vreg_config[i].max_voltage = tmp;
+
+		rc = of_property_read_u32(supply_node,
+				"lt,supply-enable-load", &tmp);
+		if (rc)
+			pr_debug("no supply enable load value. rc=%d\n", rc);
+
+		pdata->vreg_config[i].enable_load = (!rc ? tmp : 0);
+
+		rc = of_property_read_u32(supply_node,
+				"lt,supply-disable-load", &tmp);
+		if (rc)
+			pr_debug("no supply disable load value. rc=%d\n", rc);
+
+		pdata->vreg_config[i].disable_load = (!rc ? tmp : 0);
+
+		rc = of_property_read_u32(supply_node,
+				"lt,supply-pre-on-sleep", &tmp);
+		if (rc)
+			pr_debug("no supply pre on sleep value. rc=%d\n", rc);
+
+		pdata->vreg_config[i].pre_on_sleep = (!rc ? tmp : 0);
+
+		rc = of_property_read_u32(supply_node,
+				"lt,supply-pre-off-sleep", &tmp);
+		if (rc)
+			pr_debug("no supply pre off sleep value. rc=%d\n", rc);
+
+		pdata->vreg_config[i].pre_off_sleep = (!rc ? tmp : 0);
+
+		rc = of_property_read_u32(supply_node,
+				"lt,supply-post-on-sleep", &tmp);
+		if (rc)
+			pr_debug("no supply post on sleep value. rc=%d\n", rc);
+
+		pdata->vreg_config[i].post_on_sleep = (!rc ? tmp : 0);
+
+		rc = of_property_read_u32(supply_node,
+				"lt,supply-post-off-sleep", &tmp);
+		if (rc)
+			pr_debug("no supply post off sleep value. rc=%d\n", rc);
+
+		pdata->vreg_config[i].post_off_sleep = (!rc ? tmp : 0);
+
+		pr_debug("%s min=%d, max=%d, enable=%d, disable=%d, preonsleep=%d, postonsleep=%d, preoffsleep=%d, postoffsleep=%d\n",
+				pdata->vreg_config[i].vreg_name,
+				pdata->vreg_config[i].min_voltage,
+				pdata->vreg_config[i].max_voltage,
+				pdata->vreg_config[i].enable_load,
+				pdata->vreg_config[i].disable_load,
+				pdata->vreg_config[i].pre_on_sleep,
+				pdata->vreg_config[i].post_on_sleep,
+				pdata->vreg_config[i].pre_off_sleep,
+				pdata->vreg_config[i].post_off_sleep);
+		++i;
+
+		rc = 0;
+	}
+
+	rc = lt9611_config_vreg(dev,
+			pdata->vreg_config, pdata->num_vreg, true);
+	if (rc)
+		goto error;
+
+	return rc;
+
+error:
+	if (pdata->vreg_config) {
+		devm_kfree(dev, pdata->vreg_config);
+		pdata->vreg_config = NULL;
+		pdata->num_vreg = 0;
+	}
+
+	return rc;
+}
+
+static void lt9611_put_dt_supply(struct device *dev,
+		struct lt9611 *pdata)
+{
+	if (!dev || !pdata) {
+		pr_err("invalid input param dev:%pK pdata:%pK\n", dev, pdata);
+		return;
+	}
+
+	lt9611_config_vreg(dev,
+			pdata->vreg_config, pdata->num_vreg, false);
+
+	if (pdata->vreg_config) {
+		devm_kfree(dev, pdata->vreg_config);
+		pdata->vreg_config = NULL;
+	}
+	pdata->num_vreg = 0;
+}
+
+static int lt9611_enable_vreg(struct lt9611 *pdata, int enable)
+{
+	int i = 0, rc = 0;
+	bool need_sleep;
+	struct lt9611_vreg *in_vreg = pdata->vreg_config;
+	int num_vreg = pdata->num_vreg;
+
+	if (enable) {
+		for (i = 0; i < num_vreg; i++) {
+			rc = PTR_RET(in_vreg[i].vreg);
+			if (rc) {
+				pr_err("%s regulator error. rc=%d\n",
+						in_vreg[i].vreg_name, rc);
+				goto vreg_set_opt_mode_fail;
+			}
+			need_sleep = !regulator_is_enabled(in_vreg[i].vreg);
+			if (in_vreg[i].pre_on_sleep && need_sleep)
+				usleep_range(in_vreg[i].pre_on_sleep * 1000,
+						in_vreg[i].pre_on_sleep * 1000);
+			rc = regulator_set_load(in_vreg[i].vreg,
+					in_vreg[i].enable_load);
+			if (rc < 0) {
+				pr_err("%s set opt m fail\n",
+						in_vreg[i].vreg_name);
+				goto vreg_set_opt_mode_fail;
+			}
+			rc = regulator_enable(in_vreg[i].vreg);
+			if (in_vreg[i].post_on_sleep && need_sleep)
+				usleep_range(in_vreg[i].post_on_sleep * 1000,
+					in_vreg[i].post_on_sleep * 1000);
+			if (rc < 0) {
+				pr_err("%s enable failed\n",
+						in_vreg[i].vreg_name);
+				goto disable_vreg;
+			}
+		}
+	} else {
+		for (i = num_vreg-1; i >= 0; i--) {
+			if (in_vreg[i].pre_off_sleep)
+				usleep_range(in_vreg[i].pre_off_sleep * 1000,
+					in_vreg[i].pre_off_sleep * 1000);
+			regulator_set_load(in_vreg[i].vreg,
+					in_vreg[i].disable_load);
+			regulator_disable(in_vreg[i].vreg);
+			if (in_vreg[i].post_off_sleep)
+				usleep_range(in_vreg[i].post_off_sleep * 1000,
+					in_vreg[i].post_off_sleep * 1000);
+		}
+	}
+	return rc;
+
+disable_vreg:
+	regulator_set_load(in_vreg[i].vreg, in_vreg[i].disable_load);
+
+vreg_set_opt_mode_fail:
+	for (i--; i >= 0; i--) {
+		if (in_vreg[i].pre_off_sleep)
+			usleep_range(in_vreg[i].pre_off_sleep * 1000,
+					in_vreg[i].pre_off_sleep * 1000);
+		regulator_set_load(in_vreg[i].vreg,
+				in_vreg[i].disable_load);
+		regulator_disable(in_vreg[i].vreg);
+		if (in_vreg[i].post_off_sleep)
+			usleep_range(in_vreg[i].post_off_sleep * 1000,
+					in_vreg[i].post_off_sleep * 1000);
+	}
+
+	return rc;
+}
+
+static struct lt9611_timing_info *lt9611_get_supported_timing(
+		struct drm_display_mode *mode) {
+	int i = 0;
+
+	while (lt9611_supp_timing_cfg[i].xres != 0xffff) {
+		if (lt9611_supp_timing_cfg[i].xres == mode->hdisplay &&
+			lt9611_supp_timing_cfg[i].yres == mode->vdisplay &&
+			lt9611_supp_timing_cfg[i].fps ==
+					drm_mode_vrefresh(mode)) {
+			return &lt9611_supp_timing_cfg[i];
+		}
+		i++;
+	}
+
+	return NULL;
+}
+
+/* TODO: intf/lane number needs info from both DSI host and client */
+static int lt9611_get_intf_num(struct lt9611 *pdata,
+	struct drm_display_mode *mode)
+{
+	int num_of_intfs = 0;
+	struct lt9611_timing_info *timing =
+			lt9611_get_supported_timing(mode);
+
+	if (timing)
+		num_of_intfs = timing->intfs;
+	else {
+		pr_err("interface number not defined by bridge chip\n");
+		num_of_intfs = 0;
+	}
+
+	return num_of_intfs;
+}
+
+static int lt9611_get_lane_num(struct lt9611 *pdata,
+	struct drm_display_mode *mode)
+{
+	int num_of_lanes = 0;
+	struct lt9611_timing_info *timing =
+				lt9611_get_supported_timing(mode);
+
+	if (timing)
+		num_of_lanes = timing->lanes;
+	else {
+		pr_err("lane number not defined by bridge chip\n");
+		num_of_lanes = 0;
+	}
+
+	return num_of_lanes;
+}
+
+static void lt9611_get_video_cfg(struct lt9611 *pdata,
+	struct drm_display_mode *mode,
+	struct lt9611_video_cfg *video_cfg)
+{
+	int rc = 0;
+	struct hdmi_avi_infoframe avi_frame;
+
+	memset(&avi_frame, 0, sizeof(avi_frame));
+
+	video_cfg->h_active = mode->hdisplay;
+	video_cfg->v_active = mode->vdisplay;
+	video_cfg->h_front_porch = mode->hsync_start - mode->hdisplay;
+	video_cfg->v_front_porch = mode->vsync_start - mode->vdisplay;
+	video_cfg->h_back_porch = mode->htotal - mode->hsync_end;
+	video_cfg->v_back_porch = mode->vtotal - mode->vsync_end;
+	video_cfg->h_pulse_width = mode->hsync_end - mode->hsync_start;
+	video_cfg->v_pulse_width = mode->vsync_end - mode->vsync_start;
+	video_cfg->pclk_khz = mode->clock;
+
+	video_cfg->h_polarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
+	video_cfg->v_polarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
+
+	video_cfg->num_of_lanes = lt9611_get_lane_num(pdata, mode);
+	video_cfg->num_of_intfs = lt9611_get_intf_num(pdata, mode);
+
+	pr_debug("video=h[%d,%d,%d,%d] v[%d,%d,%d,%d] pclk=%d lane=%d intf=%d\n",
+		video_cfg->h_active, video_cfg->h_front_porch,
+		video_cfg->h_pulse_width, video_cfg->h_back_porch,
+		video_cfg->v_active, video_cfg->v_front_porch,
+		video_cfg->v_pulse_width, video_cfg->v_back_porch,
+		video_cfg->pclk_khz, video_cfg->num_of_lanes,
+		video_cfg->num_of_intfs);
+
+	rc = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame, mode);
+	if (rc) {
+		pr_err("get avi frame failed ret=%d\n", rc);
+	} else {
+		video_cfg->scaninfo = avi_frame.scan_mode;
+		video_cfg->ar = avi_frame.picture_aspect;
+		video_cfg->vic = avi_frame.video_code;
+		pr_debug("scaninfo=%d ar=%d vic=%d\n",
+			video_cfg->scaninfo, video_cfg->ar, video_cfg->vic);
+	}
+}
+
+/* connector funcs */
+static enum drm_connector_status
+lt9611_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct lt9611 *pdata = connector_to_lt9611(connector);
+
+	if (!pdata->non_pluggable) {
+		u8 reg_val = 0;
+		int connected = 0;
+
+		lt9611_write(pdata, 0xff, 0x82);
+		lt9611_read(pdata, 0x5e, &reg_val, 1);
+		connected  = (reg_val & BIT(2));
+		pr_debug("connected = %x\n", connected);
+
+		pdata->status = connected ?  connector_status_connected :
+					connector_status_disconnected;
+	} else
+		pdata->status = connector_status_connected;
+
+	return pdata->status;
+}
+
+static int lt9611_read_edid(struct lt9611 *pdata)
+{
+	int ret = 0;
+	u8 i, j;
+	u8 temp = 0;
+
+	if (!pdata) {
+		pr_err("invalid input\n");
+		return -EINVAL;
+	}
+
+	memset(pdata->edid_buf, 0, EDID_SEG_SIZE);
+
+	lt9611_write(pdata, 0xff, 0x85);
+	lt9611_write(pdata, 0x03, 0xc9);
+	lt9611_write(pdata, 0x04, 0xa0); /* 0xA0 is EDID device address */
+	lt9611_write(pdata, 0x05, 0x00); /* 0x00 is EDID offset address */
+	lt9611_write(pdata, 0x06, 0x20); /* length for read */
+	lt9611_write(pdata, 0x14, 0x7f);
+
+	for (i = 0 ; i < 8 ; i++) {
+		lt9611_write(pdata, 0x05, i * 32); /* offset address */
+		lt9611_write(pdata, 0x07, 0x36);
+		lt9611_write(pdata, 0x07, 0x31);
+		lt9611_write(pdata, 0x07, 0x37);
+		usleep_range(5000, 10000);
+
+		lt9611_read(pdata, 0x40, &temp, 1);
+
+		if (temp & 0x02) {  /*KEY_DDC_ACCS_DONE=1*/
+			for (j = 0; j < 32; j++) {
+				lt9611_read(pdata, 0x83,
+					&(pdata->edid_buf[i*32+j]), 1);
+			}
+		} else if (temp & 0x50) { /* DDC No Ack or Abitration lost */
+			pr_err("read edid failed: no ack\n");
+			ret = -EIO;
+			goto end;
+		} else {
+			pr_err("read edid failed: access not done\n");
+			ret = -EIO;
+			goto end;
+		}
+	}
+
+	pr_debug("read edid succeeded, checksum = 0x%x\n",
+		pdata->edid_buf[255]);
+
+end:
+	lt9611_write(pdata, 0x07, 0x1f);
+	return ret;
+}
+
+/* TODO: add support for more extenstion blocks */
+static int lt9611_get_edid_block(void *data, u8 *buf, unsigned int block,
+				  size_t len)
+{
+	struct lt9611 *pdata = data;
+	int ret = 0;
+
+	pr_debug("get edid block: block=%d, len=%d\n", block, (int)len);
+
+	if (len > 128)
+		return -EINVAL;
+
+	/* support up to 1 extension block */
+	if (block > 1)
+		return -EINVAL;
+
+	if (block == 0) {
+		/* always read 2 edid blocks once */
+		ret = lt9611_read_edid(pdata);
+		if (ret) {
+			pr_err("edid read failed\n");
+			return ret;
+		}
+	}
+
+	if (block % 2 == 0)
+		memcpy(buf, pdata->edid_buf, len);
+	else
+		memcpy(buf, pdata->edid_buf + 128, len);
+
+	return 0;
+}
+
+static int lt9611_connector_get_modes(struct drm_connector *connector)
+{
+	struct lt9611 *pdata = connector_to_lt9611(connector);
+	struct drm_display_mode *mode, *m;
+	unsigned int count = 0;
+
+	pr_debug("get modes\n");
+
+	if (pdata->non_pluggable) {
+		list_for_each_entry(mode, &pdata->mode_list, head) {
+			m = drm_mode_duplicate(connector->dev, mode);
+			if (!m) {
+				pr_err("failed to add hdmi mode %dx%d\n",
+					mode->hdisplay, mode->vdisplay);
+				break;
+			}
+			drm_mode_probed_add(connector, m);
+		}
+		count = pdata->num_of_modes;
+	} else {
+		struct edid *edid;
+
+		if (!pdata->power_on)
+			lt9611_power_on(pdata, true);
+		edid = drm_do_get_edid(connector, lt9611_get_edid_block, pdata);
+
+		drm_mode_connector_update_edid_property(connector, edid);
+		count = drm_add_edid_modes(connector, edid);
+
+		pdata->hdmi_mode = drm_detect_hdmi_monitor(edid);
+		pr_debug("hdmi_mode = %d\n", pdata->hdmi_mode);
+
+		/* TODO: this should not be hard coded */
+		drm_set_preferred_mode(connector, 1920, 1080);
+
+		kfree(edid);
+	}
+
+	return count;
+}
+
+static enum drm_mode_status lt9611_connector_mode_valid(
+	struct drm_connector *connector, struct drm_display_mode *mode)
+{
+	struct lt9611_timing_info *timing =
+			lt9611_get_supported_timing(mode);
+
+	return timing ? MODE_OK : MODE_BAD;
+}
+
+/* bridge funcs */
+static void lt9611_bridge_enable(struct drm_bridge *bridge)
+{
+	struct lt9611 *pdata = bridge_to_lt9611(bridge);
+
+	pr_debug("bridge enable\n");
+
+	if (lt9611_power_on(pdata, true)) {
+		pr_err("power on failed\n");
+		return;
+	}
+
+	if (lt9611_video_on(pdata, true)) {
+		pr_err("video on failed\n");
+		return;
+	}
+}
+
+static void lt9611_bridge_disable(struct drm_bridge *bridge)
+{
+	struct lt9611 *pdata = bridge_to_lt9611(bridge);
+
+	pr_debug("bridge disable\n");
+
+	if (lt9611_video_on(pdata, false)) {
+		pr_err("video on failed\n");
+		return;
+	}
+
+	if (lt9611_power_on(pdata, false)) {
+		pr_err("power on failed\n");
+		return;
+	}
+}
+
+static void lt9611_bridge_mode_set(struct drm_bridge *bridge,
+				    struct drm_display_mode *mode,
+				    struct drm_display_mode *adj_mode)
+{
+	struct lt9611 *pdata = bridge_to_lt9611(bridge);
+	struct lt9611_video_cfg *video_cfg = &pdata->video_cfg;
+	int ret = 0;
+
+	pr_debug("bridge mode_set: hdisplay=%d, vdisplay=%d, vrefresh=%d, clock=%d\n",
+		adj_mode->hdisplay, adj_mode->vdisplay,
+		adj_mode->vrefresh, adj_mode->clock);
+
+	drm_mode_copy(&pdata->curr_mode, adj_mode);
+
+	memset(video_cfg, 0, sizeof(struct lt9611_video_cfg));
+	lt9611_get_video_cfg(pdata, adj_mode, video_cfg);
+
+	/* TODO: update intf number of host */
+	if (video_cfg->num_of_lanes != pdata->dsi->lanes) {
+		mipi_dsi_detach(pdata->dsi);
+		pdata->dsi->lanes = video_cfg->num_of_lanes;
+		ret = mipi_dsi_attach(pdata->dsi);
+		if (ret)
+			pr_err("failed to change host lanes\n");
+	}
+}
+
+static int lt9611_bridge_attach(struct drm_bridge *bridge)
+{
+	struct mipi_dsi_host *host;
+	struct mipi_dsi_device *dsi;
+	struct lt9611 *pdata = bridge_to_lt9611(bridge);
+	int ret;
+	const struct mipi_dsi_device_info info = { .type = "lt9611",
+						   .channel = 0,
+						   .node = NULL,
+						 };
+
+	pr_debug("bridge attach\n");
+
+	if (!bridge->encoder) {
+		DRM_ERROR("Parent encoder object not found");
+		return -ENODEV;
+	}
+
+	host = of_find_mipi_dsi_host_by_node(pdata->host_node);
+	if (!host) {
+		pr_err("failed to find dsi host\n");
+		return -EPROBE_DEFER;
+	}
+
+	dsi = mipi_dsi_device_register_full(host, &info);
+	if (IS_ERR(dsi)) {
+		pr_err("failed to create dsi device\n");
+		ret = PTR_ERR(dsi);
+		goto err_dsi_device;
+	}
+
+	dsi->lanes = 4;
+	dsi->format = MIPI_DSI_FMT_RGB888;
+	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+			  MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO_BLLP |
+			  MIPI_DSI_MODE_VIDEO_EOF_BLLP;
+
+	ret = mipi_dsi_attach(dsi);
+	if (ret < 0) {
+		pr_err("failed to attach dsi to host\n");
+		goto err_dsi_attach;
+	}
+
+	pdata->dsi = dsi;
+
+	return 0;
+
+err_dsi_attach:
+	mipi_dsi_device_unregister(dsi);
+err_dsi_device:
+	return ret;
+}
+
+static void lt9611_bridge_pre_enable(struct drm_bridge *bridge)
+{
+	struct lt9611 *pdata = bridge_to_lt9611(bridge);
+
+	pr_debug("bridge pre_enable\n");
+
+	lt9611_reset(pdata);
+
+	lt9611_write(pdata, 0xff, 0x80);
+	lt9611_write(pdata, 0xee, 0x01);
+}
+
+static bool lt9611_bridge_mode_fixup(struct drm_bridge *bridge,
+				  const struct drm_display_mode *mode,
+				  struct drm_display_mode *adjusted_mode)
+{
+	pr_debug("bridge mode_fixup\n");
+
+	return true;
+}
+
+static void lt9611_bridge_post_disable(struct drm_bridge *bridge)
+{
+	struct lt9611 *pdata = bridge_to_lt9611(bridge);
+
+	pr_debug("bridge post_disable\n");
+
+	lt9611_sleep_setup(pdata);
+}
+
+static struct drm_connector_funcs override_funcs;
+static struct drm_connector_helper_funcs override_helper_private;
+
+static int lt9611_bridge_connector_init(struct drm_bridge *bridge,
+	struct drm_connector *connector)
+{
+	pr_debug("bridge connector_init\n");
+
+	if (connector->encoder != bridge->encoder) {
+		pr_err("bridge and connector need attach to the same encoder\n");
+		return -EINVAL;
+	}
+
+	connector->private = bridge;
+
+	/*
+	 * Make a copy of drm_connector_funcs and drm_connector_helper_funcs. To
+	 * make sure other KMS components won't be broken. For example, if other
+	 * connectors share the implementation for ->funs, overwriting this will
+	 * break other connectors.
+	 */
+	override_funcs = *connector->funcs;
+	override_funcs.detect = lt9611_connector_detect;
+	connector->funcs = &override_funcs;
+
+	override_helper_private = *connector->helper_private;
+	override_helper_private.get_modes = lt9611_connector_get_modes;
+	override_helper_private.mode_valid = lt9611_connector_mode_valid;
+	connector->helper_private = &override_helper_private;
+
+	return 0;
+}
+
+static const struct drm_bridge_funcs lt9611_bridge_funcs = {
+	.attach = lt9611_bridge_attach,
+	.mode_fixup   = lt9611_bridge_mode_fixup,
+	.pre_enable   = lt9611_bridge_pre_enable,
+	.enable = lt9611_bridge_enable,
+	.disable = lt9611_bridge_disable,
+	.post_disable = lt9611_bridge_post_disable,
+	.mode_set = lt9611_bridge_mode_set,
+	.connector_init = lt9611_bridge_connector_init,
+};
+
+/* sysfs */
+static int lt9611_dump_debug_info(struct lt9611 *pdata)
+{
+	if (!pdata->power_on) {
+		pr_err("device is not power on\n");
+		return -EINVAL;
+	}
+
+	lt9611_video_check(pdata);
+
+	lt9611_pcr_mk_debug(pdata);
+
+	lt9611_mipi_byte_clk_debug(pdata);
+
+	return 0;
+}
+
+static ssize_t lt9611_dump_info_wta_attr(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf,
+				  size_t count)
+{
+	struct lt9611 *pdata = dev_get_drvdata(dev);
+
+	if (!pdata) {
+		pr_err("pdata is NULL\n");
+		return -EINVAL;
+	}
+
+	lt9611_dump_debug_info(pdata);
+
+	return count;
+}
+
+static DEVICE_ATTR(dump_info, 0200, NULL, lt9611_dump_info_wta_attr);
+
+static struct attribute *lt9611_sysfs_attrs[] = {
+	&dev_attr_dump_info.attr,
+	NULL,
+};
+
+static struct attribute_group lt9611_sysfs_attr_grp = {
+	.attrs = lt9611_sysfs_attrs,
+};
+
+static int lt9611_sysfs_init(struct device *dev)
+{
+	int rc = 0;
+
+	if (!dev) {
+		pr_err("%s: Invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = sysfs_create_group(&dev->kobj, &lt9611_sysfs_attr_grp);
+	if (rc)
+		pr_err("%s: sysfs group creation failed %d\n", __func__, rc);
+
+	return rc;
+}
+
+static void lt9611_sysfs_remove(struct device *dev)
+{
+	if (!dev) {
+		pr_err("%s: Invalid params\n", __func__);
+		return;
+	}
+
+	sysfs_remove_group(&dev->kobj, &lt9611_sysfs_attr_grp);
+}
+
+static int lt9611_probe(struct i2c_client *client,
+	 const struct i2c_device_id *id)
+{
+	struct lt9611 *pdata;
+	int ret = 0;
+
+	if (!client || !client->dev.of_node) {
+		pr_err("invalid input\n");
+		return -EINVAL;
+	}
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_err("device doesn't support I2C\n");
+		return -ENODEV;
+	}
+
+	pdata = devm_kzalloc(&client->dev,
+		sizeof(struct lt9611), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	ret = lt9611_parse_dt(&client->dev, pdata);
+	if (ret) {
+		pr_err("failed to parse device tree\n");
+		goto err_dt_parse;
+	}
+
+	ret = lt9611_get_dt_supply(&client->dev, pdata);
+	if (ret) {
+		pr_err("failed to get dt supply\n");
+		goto err_dt_parse;
+	}
+
+	pdata->dev = &client->dev;
+	pdata->i2c_client = client;
+	pr_debug("I2C address is %x\n", client->addr);
+
+	ret = lt9611_gpio_configure(pdata, true);
+	if (ret) {
+		pr_err("failed to configure GPIOs\n");
+		goto err_dt_supply;
+	}
+
+	lt9611_assert_5v(pdata);
+
+	ret = lt9611_enable_vreg(pdata, true);
+	if (ret) {
+		pr_err("failed to enable vreg\n");
+		goto err_dt_supply;
+	}
+
+	lt9611_reset(pdata);
+
+	ret = lt9611_read_device_rev(pdata);
+	if (ret) {
+		pr_err("failed to read chip rev\n");
+		goto err_i2c_prog;
+	}
+
+	pdata->irq = gpio_to_irq(pdata->irq_gpio);
+	ret = request_threaded_irq(pdata->irq, NULL, lt9611_irq_thread_handler,
+		IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "lt9611", pdata);
+	if (ret) {
+		pr_err("failed to request irq\n");
+		goto err_i2c_prog;
+	}
+
+	i2c_set_clientdata(client, pdata);
+	dev_set_drvdata(&client->dev, pdata);
+
+	ret = lt9611_sysfs_init(&client->dev);
+	if (ret) {
+		pr_err("sysfs init failed\n");
+		goto err_sysfs_init;
+	}
+
+	pdata->bridge.funcs = &lt9611_bridge_funcs;
+	pdata->bridge.of_node = client->dev.of_node;
+
+	drm_bridge_add(&pdata->bridge);
+
+	return ret;
+
+err_sysfs_init:
+	disable_irq(pdata->irq);
+	free_irq(pdata->irq, pdata);
+err_i2c_prog:
+	lt9611_gpio_configure(pdata, false);
+err_dt_supply:
+	lt9611_put_dt_supply(&client->dev, pdata);
+err_dt_parse:
+	devm_kfree(&client->dev, pdata);
+	return ret;
+}
+
+static int lt9611_remove(struct i2c_client *client)
+{
+	int ret = -EINVAL;
+	struct lt9611 *pdata = i2c_get_clientdata(client);
+	struct drm_display_mode *mode, *n;
+
+	if (!pdata)
+		goto end;
+
+	mipi_dsi_detach(pdata->dsi);
+	mipi_dsi_device_unregister(pdata->dsi);
+
+	drm_bridge_remove(&pdata->bridge);
+
+	lt9611_sysfs_remove(&client->dev);
+
+	disable_irq(pdata->irq);
+	free_irq(pdata->irq, pdata);
+
+	ret = lt9611_gpio_configure(pdata, false);
+
+	lt9611_put_dt_supply(&client->dev, pdata);
+
+	if (pdata->non_pluggable) {
+		list_for_each_entry_safe(mode, n, &pdata->mode_list, head) {
+			list_del(&mode->head);
+			kfree(mode);
+		}
+	}
+
+	devm_kfree(&client->dev, pdata);
+
+end:
+	return ret;
+}
+
+
+static struct i2c_device_id lt9611_id[] = {
+	{ "lt,lt9611", 0},
+	{}
+};
+
+static const struct of_device_id lt9611_match_table[] = {
+	{.compatible = "lt,lt9611"},
+	{}
+};
+MODULE_DEVICE_TABLE(of, lt9611_match_table);
+
+static struct i2c_driver lt9611_driver = {
+	.driver = {
+		.name = "lt9611",
+		.owner = THIS_MODULE,
+		.of_match_table = lt9611_match_table,
+	},
+	.probe = lt9611_probe,
+	.remove = lt9611_remove,
+	.id_table = lt9611_id,
+};
+
+static int __init lt9611_init(void)
+{
+	return i2c_add_driver(&lt9611_driver);
+}
+
+static void __exit lt9611_exit(void)
+{
+	i2c_del_driver(&lt9611_driver);
+}
+
+module_init(lt9611_init);
+module_exit(lt9611_exit);
+
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index c1a670d..d5437d0 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -668,6 +668,27 @@
 		}
 	}
 
+	/**
+	 * Since pp interrupt is heavy weight, try to queue the work
+	 * into a dedicated worker thread, so that they dont interrupt
+	 * other important events.
+	 */
+	kthread_init_worker(&priv->pp_event_worker);
+	priv->pp_event_thread = kthread_run(kthread_worker_fn,
+			&priv->pp_event_worker, "pp_event");
+
+	ret = sched_setscheduler(priv->pp_event_thread,
+						SCHED_FIFO, &param);
+	if (ret)
+		pr_warn("pp_event thread priority update failed: %d\n",
+								ret);
+
+	if (IS_ERR(priv->pp_event_thread)) {
+		dev_err(dev, "failed to create pp_event kthread\n");
+		priv->pp_event_thread = NULL;
+		goto fail;
+	}
+
 	ret = drm_vblank_init(ddev, priv->num_crtcs);
 	if (ret < 0) {
 		dev_err(dev, "failed to initialize vblank\n");
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index cc09256..17a41d5 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
  *
@@ -578,6 +578,9 @@
 	struct msm_drm_thread disp_thread[MAX_CRTCS];
 	struct msm_drm_thread event_thread[MAX_CRTCS];
 
+	struct task_struct *pp_event_thread;
+	struct kthread_worker pp_event_worker;
+
 	unsigned int num_encoders;
 	struct drm_encoder *encoders[MAX_ENCODERS];
 
diff --git a/drivers/gpu/drm/msm/sde/sde_color_processing.c b/drivers/gpu/drm/msm/sde/sde_color_processing.c
index 3e084d5..8d7d292 100644
--- a/drivers/gpu/drm/msm/sde/sde_color_processing.c
+++ b/drivers/gpu/drm/msm/sde/sde_color_processing.c
@@ -1573,7 +1573,8 @@
 {
 	struct sde_crtc *crtc = arg;
 
-	sde_crtc_event_queue(&crtc->base, sde_cp_notify_ad_event, NULL);
+	sde_crtc_event_queue(&crtc->base, sde_cp_notify_ad_event,
+							NULL, true);
 }
 
 static void sde_cp_notify_ad_event(struct drm_crtc *crtc_drm, void *arg)
@@ -1834,7 +1835,8 @@
 	}
 
 	/* notify histogram event */
-	sde_crtc_event_queue(crtc_drm, sde_cp_notify_hist_event, NULL);
+	sde_crtc_event_queue(crtc_drm, sde_cp_notify_hist_event,
+							NULL, true);
 }
 
 static void sde_cp_notify_hist_event(struct drm_crtc *crtc_drm, void *arg)
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 8d2f115..8c1599e 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -5927,7 +5927,8 @@
 }
 
 int sde_crtc_event_queue(struct drm_crtc *crtc,
-		void (*func)(struct drm_crtc *crtc, void *usr), void *usr)
+		void (*func)(struct drm_crtc *crtc, void *usr),
+		void *usr, bool color_processing_event)
 {
 	unsigned long irq_flags;
 	struct sde_crtc *sde_crtc;
@@ -5966,7 +5967,11 @@
 
 	/* queue new event request */
 	kthread_init_work(&event->kt_work, _sde_crtc_event_cb);
-	kthread_queue_work(&priv->event_thread[crtc_id].worker,
+	if (color_processing_event)
+		kthread_queue_work(&priv->pp_event_worker,
+			&event->kt_work);
+	else
+		kthread_queue_work(&priv->event_thread[crtc_id].worker,
 			&event->kt_work);
 
 	return 0;
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index 78f15ec..21ce3db 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -664,10 +664,12 @@
  * @crtc: Pointer to drm crtc structure
  * @func: Pointer to callback function
  * @usr: Pointer to user data to be passed to callback
+ * @color_processing_event: True if color processing event
  * Returns: Zero on success
  */
 int sde_crtc_event_queue(struct drm_crtc *crtc,
-		void (*func)(struct drm_crtc *crtc, void *usr), void *usr);
+		void (*func)(struct drm_crtc *crtc, void *usr),
+		void *usr, bool color_processing_event);
 
 /**
  * sde_crtc_res_add - add given resource to resource pool in crtc state
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 9a878fb..86b3986 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -565,6 +565,8 @@
 		return -EBUSY;
 	}
 
+	memset(&time, 0x0, sizeof(time));
+
 	dispatcher->inflight++;
 	dispatch_q->inflight++;
 
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 5168d9e..1faad93 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -120,13 +120,60 @@
 
 }
 
+static void adreno_profile_submit_time(struct adreno_submit_time *time)
+{
+	struct kgsl_drawobj *drawobj;
+	struct kgsl_drawobj_cmd *cmdobj;
+	struct kgsl_mem_entry *entry;
+
+	if (time == NULL)
+		return;
+
+	drawobj = time->drawobj;
+
+	if (drawobj == NULL)
+		return;
+
+	cmdobj = CMDOBJ(drawobj);
+	entry = cmdobj->profiling_buf_entry;
+
+	if (entry) {
+		struct kgsl_drawobj_profiling_buffer *profile_buffer;
+
+		profile_buffer = kgsl_gpuaddr_to_vaddr(&entry->memdesc,
+					cmdobj->profiling_buffer_gpuaddr);
+
+		if (profile_buffer == NULL)
+			return;
+
+		/* Return kernel clock time to the the client if requested */
+		if (drawobj->flags & KGSL_DRAWOBJ_PROFILING_KTIME) {
+			uint64_t secs = time->ktime;
+
+			profile_buffer->wall_clock_ns =
+				do_div(secs, NSEC_PER_SEC);
+			profile_buffer->wall_clock_s = secs;
+		} else {
+			profile_buffer->wall_clock_s = time->utime.tv_sec;
+			profile_buffer->wall_clock_ns = time->utime.tv_nsec;
+		}
+
+		profile_buffer->gpu_ticks_queued = time->ticks;
+
+		kgsl_memdesc_unmap(&entry->memdesc);
+	}
+}
+
 void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb,
 		struct adreno_submit_time *time)
 {
 	struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb);
 
-	if (time != NULL)
+	if (time != NULL) {
 		adreno_get_submit_time(adreno_dev, rb, time);
+		/* Put the timevalues in the profiling buffer */
+		adreno_profile_submit_time(time);
+	}
 
 	adreno_ringbuffer_wptr(adreno_dev, rb);
 }
@@ -261,7 +308,8 @@
 {
 	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
 	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
-	int i, status;
+	int i;
+	int status = -ENOMEM;
 
 	if (!adreno_is_a3xx(adreno_dev)) {
 		status = kgsl_allocate_global(device, &device->scratch,
@@ -774,16 +822,12 @@
 	int flags = KGSL_CMD_FLAGS_NONE;
 	int ret;
 	struct adreno_ringbuffer *rb;
-	struct kgsl_drawobj_profiling_buffer *profile_buffer = NULL;
 	unsigned int dwords = 0;
 	struct adreno_submit_time local;
-	struct kgsl_mem_entry *entry = cmdobj->profiling_buf_entry;
 	struct adreno_firmware *fw = ADRENO_FW(adreno_dev, ADRENO_FW_SQE);
 	bool set_ib1list_marker = false;
 
-	if (entry)
-		profile_buffer = kgsl_gpuaddr_to_vaddr(&entry->memdesc,
-					cmdobj->profiling_buffer_gpuaddr);
+	memset(&local, 0x0, sizeof(local));
 
 	context = drawobj->context;
 	drawctxt = ADRENO_CONTEXT(context);
@@ -855,7 +899,8 @@
 	dwords += (numibs * 30);
 
 	if (drawobj->flags & KGSL_DRAWOBJ_PROFILING &&
-		!adreno_is_a3xx(adreno_dev) && profile_buffer) {
+		!adreno_is_a3xx(adreno_dev) &&
+		(cmdobj->profiling_buf_entry != NULL)) {
 		user_profiling = true;
 		dwords += 6;
 
@@ -875,6 +920,8 @@
 
 		if (time == NULL)
 			time = &local;
+
+		time->drawobj = drawobj;
 	}
 
 	if (test_bit(CMDOBJ_PROFILE, &cmdobj->priv)) {
@@ -1027,35 +1074,9 @@
 	if (!ret) {
 		set_bit(KGSL_CONTEXT_PRIV_SUBMITTED, &context->priv);
 		cmdobj->global_ts = drawctxt->internal_timestamp;
-
-		/* Put the timevalues in the profiling buffer */
-		if (user_profiling) {
-			/*
-			 * Return kernel clock time to the the client
-			 * if requested
-			 */
-			if (drawobj->flags & KGSL_DRAWOBJ_PROFILING_KTIME) {
-				uint64_t secs = time->ktime;
-
-				profile_buffer->wall_clock_ns =
-					do_div(secs, NSEC_PER_SEC);
-				profile_buffer->wall_clock_s = secs;
-			} else {
-				profile_buffer->wall_clock_s =
-					time->utime.tv_sec;
-				profile_buffer->wall_clock_ns =
-					time->utime.tv_nsec;
-			}
-			profile_buffer->gpu_ticks_queued = time->ticks;
-		}
 	}
 
 done:
-	/* Corresponding unmap to the memdesc map of profile_buffer */
-	if (entry)
-		kgsl_memdesc_unmap(&entry->memdesc);
-
-
 	trace_kgsl_issueibcmds(device, context->id, numibs, drawobj->timestamp,
 			drawobj->flags, ret, drawctxt->type);
 
diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h
index 1dfdb5b..a4dc901 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -43,11 +43,13 @@
  * @ticks: GPU ticks at submit time (from the 19.2Mhz timer)
  * @ktime: local clock time (in nanoseconds)
  * @utime: Wall clock time
+ * @drawobj: the object that we want to profile
  */
 struct adreno_submit_time {
 	uint64_t ticks;
 	u64 ktime;
 	struct timespec utime;
+	struct kgsl_drawobj *drawobj;
 };
 
 /**
diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c
index f3f9a1a..abb695d 100644
--- a/drivers/leds/leds-qpnp-flash-v2.c
+++ b/drivers/leds/leds-qpnp-flash-v2.c
@@ -171,6 +171,7 @@
 };
 
 enum flash_led_type {
+	FLASH_LED_TYPE_UNKNOWN,
 	FLASH_LED_TYPE_FLASH,
 	FLASH_LED_TYPE_TORCH,
 };
@@ -204,13 +205,13 @@
 	int				prev_current_ma;
 	u8				duration;
 	u8				id;
-	u8				type;
 	u8				ires_idx;
 	u8				default_ires_idx;
 	u8				hdrm_val;
 	u8				current_reg_val;
 	u8				strobe_ctrl;
 	u8				strobe_sel;
+	enum flash_led_type		type;
 	bool				led_on;
 };
 
@@ -225,6 +226,7 @@
 	int				led_mask;
 	bool				regulator_on;
 	bool				enabled;
+	bool				symmetry_en;
 };
 
 /*
@@ -1091,6 +1093,71 @@
 	return 0;
 }
 
+static int qpnp_flash_led_symmetry_config(struct flash_switch_data *snode)
+{
+	struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev);
+	int i, total_curr_ma = 0, num_leds = 0, prgm_current_ma;
+	enum flash_led_type type = FLASH_LED_TYPE_UNKNOWN;
+
+	for (i = 0; i < led->num_fnodes; i++) {
+		if (snode->led_mask & BIT(led->fnode[i].id)) {
+			if (led->fnode[i].type == FLASH_LED_TYPE_FLASH &&
+				led->fnode[i].led_on)
+				type = FLASH_LED_TYPE_FLASH;
+
+			if (led->fnode[i].type == FLASH_LED_TYPE_TORCH &&
+				led->fnode[i].led_on)
+				type = FLASH_LED_TYPE_TORCH;
+		}
+	}
+
+	if (type == FLASH_LED_TYPE_UNKNOWN) {
+		pr_err("Incorrect type possibly because of no active LEDs\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < led->num_fnodes; i++) {
+		if ((snode->led_mask & BIT(led->fnode[i].id)) &&
+			(led->fnode[i].type == type)) {
+			total_curr_ma += led->fnode[i].current_ma;
+			num_leds++;
+		}
+	}
+
+	if (num_leds > 0 && total_curr_ma > 0) {
+		prgm_current_ma = total_curr_ma / num_leds;
+	} else {
+		pr_err("Incorrect configuration, num_leds: %d total_curr_ma: %d\n",
+			num_leds, total_curr_ma);
+		return -EINVAL;
+	}
+
+	if (prgm_current_ma == 0) {
+		pr_warn("prgm_curr_ma cannot be 0\n");
+		return 0;
+	}
+
+	pr_debug("num_leds: %d total: %d prgm_curr_ma: %d\n", num_leds,
+		total_curr_ma, prgm_current_ma);
+
+	for (i = 0; i < led->num_fnodes; i++) {
+		if (snode->led_mask & BIT(led->fnode[i].id) &&
+			led->fnode[i].current_ma != prgm_current_ma &&
+			led->fnode[i].type == type) {
+			qpnp_flash_led_node_set(&led->fnode[i],
+				prgm_current_ma);
+			pr_debug("%s LED %d current: %d code: %d ires_ua: %d\n",
+				(type == FLASH_LED_TYPE_FLASH) ?
+					"flash" : "torch",
+				led->fnode[i].id, prgm_current_ma,
+				led->fnode[i].current_reg_val,
+				led->fnode[i].ires_ua);
+		}
+	}
+
+	return 0;
+}
+
 static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
 {
 	struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev);
@@ -1109,6 +1176,15 @@
 	}
 
 	/* Iterate over all active leds for this switch node */
+	if (snode->symmetry_en) {
+		rc = qpnp_flash_led_symmetry_config(snode);
+		if (rc < 0) {
+			pr_err("Failed to configure current symmetrically, rc=%d\n",
+				rc);
+			return rc;
+		}
+	}
+
 	val = 0;
 	for (i = 0; i < led->num_fnodes; i++)
 		if (led->fnode[i].led_on &&
@@ -1707,6 +1783,8 @@
 		return rc;
 	}
 
+	snode->symmetry_en = of_property_read_bool(node, "qcom,symmetry-en");
+
 	if (snode->led_mask < 1 || snode->led_mask > 7) {
 		pr_err("Invalid value for led-mask\n");
 		return -EINVAL;
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 5ed9b72..0abc7a3 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -1916,7 +1916,11 @@
 			err = PTR_ERR(buf);
 		}
 	} else {
-		val = *buf;
+		/*
+		 * 30 bits from bit offset 0 would be read.
+		 * We're interested in bits 28:29
+		 */
+		val = (*buf >> 28) & 0x3;
 		kfree(buf);
 	}
 
diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c
index e20ddba..bf498f9 100644
--- a/drivers/platform/msm/ipa/ipa_api.c
+++ b/drivers/platform/msm/ipa/ipa_api.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -3230,6 +3230,18 @@
 	return ret;
 }
 
+/**
+ * ipa_pm_is_used() - Returns if IPA PM framework is used
+ */
+bool ipa_pm_is_used(void)
+{
+	bool ret;
+
+	IPA_API_DISPATCH_RETURN(ipa_pm_is_used);
+
+	return ret;
+}
+
 static const struct dev_pm_ops ipa_pm_ops = {
 	.suspend_noirq = ipa_ap_suspend,
 	.resume_noirq = ipa_ap_resume,
diff --git a/drivers/platform/msm/ipa/ipa_api.h b/drivers/platform/msm/ipa/ipa_api.h
index f3e62b8..79d0c70 100644
--- a/drivers/platform/msm/ipa/ipa_api.h
+++ b/drivers/platform/msm/ipa/ipa_api.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -421,6 +421,8 @@
 	int (*ipa_get_smmu_params)(struct ipa_smmu_in_params *in,
 		struct ipa_smmu_out_params *out);
 	int (*ipa_is_vlan_mode)(enum ipa_vlan_ifaces iface, bool *res);
+
+	bool (*ipa_pm_is_used)(void);
 };
 
 #ifdef CONFIG_IPA
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c
index 52ffa52..78d1c96 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c
@@ -3925,7 +3925,6 @@
 	ipa_ctx->skip_uc_pipe_reset = resource_p->skip_uc_pipe_reset;
 	ipa_ctx->use_dma_zone = resource_p->use_dma_zone;
 	ipa_ctx->tethered_flow_control = resource_p->tethered_flow_control;
-	ipa_ctx->use_ipa_pm = resource_p->use_ipa_pm;
 
 	/* Setting up IPA RX Polling Timeout Seconds */
 	ipa_rx_timeout_min_max_calc(&ipa_ctx->ipa_rx_min_timeout_usec,
@@ -4451,20 +4450,12 @@
 	return result;
 }
 
-bool ipa_pm_is_used(void)
-{
-	return (ipa_ctx) ? ipa_ctx->use_ipa_pm : false;
-}
-
 static int get_ipa_dts_configuration(struct platform_device *pdev,
 		struct ipa_plat_drv_res *ipa_drv_res)
 {
 	int result;
 	struct resource *resource;
 
-	ipa_drv_res->use_ipa_pm = of_property_read_bool(pdev->dev.of_node,
-		"qcom,use-ipa-pm");
-	IPADBG("use_ipa_pm=%d\n", ipa_drv_res->use_ipa_pm);
 	/* initialize ipa_res */
 	ipa_drv_res->ipa_pipe_mem_start_ofst = IPA_PIPE_MEM_START_OFST;
 	ipa_drv_res->ipa_pipe_mem_size = IPA_PIPE_MEM_SIZE;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
index ec4942f..91017a5 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1206,7 +1206,6 @@
 	int num_ipa_cne_evt_req;
 	struct mutex ipa_cne_evt_lock;
 	bool ipa_uc_monitor_holb;
-	bool use_ipa_pm;
 };
 
 /**
@@ -1263,7 +1262,6 @@
 	u32 ipa_rx_polling_sleep_msec;
 	u32 ipa_polling_iteration;
 	bool ipa_uc_monitor_holb;
-	bool use_ipa_pm;
 };
 
 struct ipa_mem_partition {
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
index e06f6cf..27120c8 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
@@ -4984,6 +4984,11 @@
 	ipa_ctx->tag_process_before_gating = val;
 }
 
+static bool ipa2_pm_is_used(void)
+{
+	return false;
+}
+
 int ipa2_bind_api_controller(enum ipa_hw_type ipa_hw_type,
 	struct ipa_api_controller *api_ctrl)
 {
@@ -5159,6 +5164,7 @@
 	api_ctrl->ipa_disconn_wdi3_pipes = ipa2_disconn_wdi3_pipes;
 	api_ctrl->ipa_enable_wdi3_pipes = ipa2_enable_wdi3_pipes;
 	api_ctrl->ipa_disable_wdi3_pipes = ipa2_disable_wdi3_pipes;
+	api_ctrl->ipa_pm_is_used = ipa2_pm_is_used;
 
 	return 0;
 }
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index da3b399..0dd0b7b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -5381,11 +5381,6 @@
 	return result;
 }
 
-bool ipa_pm_is_used(void)
-{
-	return (ipa3_ctx) ? ipa3_ctx->use_ipa_pm : false;
-}
-
 static int get_ipa_dts_pm_info(struct platform_device *pdev,
 	struct ipa3_plat_drv_res *ipa_drv_res)
 {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index 9974b87..32e9891 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -4336,6 +4336,11 @@
 	return 0;
 }
 
+static bool ipa3_pm_is_used(void)
+{
+	return (ipa3_ctx) ? ipa3_ctx->use_ipa_pm : false;
+}
+
 int ipa3_bind_api_controller(enum ipa_hw_type ipa_hw_type,
 	struct ipa_api_controller *api_ctrl)
 {
@@ -4523,6 +4528,7 @@
 	api_ctrl->ipa_tz_unlock_reg = ipa3_tz_unlock_reg;
 	api_ctrl->ipa_get_smmu_params = ipa3_get_smmu_params;
 	api_ctrl->ipa_is_vlan_mode = ipa3_is_vlan_mode;
+	api_ctrl->ipa_pm_is_used = ipa3_pm_is_used;
 
 	return 0;
 }
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index 93692fa..f4a36a3 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -324,6 +324,9 @@
 	POWER_SUPPLY_ATTR(parallel_fcc_max),
 	POWER_SUPPLY_ATTR(min_icl),
 	POWER_SUPPLY_ATTR(moisture_detected),
+	POWER_SUPPLY_ATTR(batt_profile_version),
+	POWER_SUPPLY_ATTR(batt_full_current),
+	POWER_SUPPLY_ATTR(recharge_soc),
 	/* Local extensions of type int64_t */
 	POWER_SUPPLY_ATTR(charge_counter_ext),
 	/* Properties of type `const char *' */
diff --git a/drivers/power/supply/qcom/Kconfig b/drivers/power/supply/qcom/Kconfig
index c8e731a..e653475 100644
--- a/drivers/power/supply/qcom/Kconfig
+++ b/drivers/power/supply/qcom/Kconfig
@@ -115,4 +115,13 @@
 	  USB power-delivery. The driver adds support to report these type-C
 	  parameters via the power-supply framework.
 
+config QPNP_QG
+	bool "QPNP Qgauge driver"
+	depends on MFD_SPMI_PMIC
+	help
+	  Say Y here to enable the Qualcomm Technologies, Inc. QGauge driver
+	  which uses the periodic sampling of the battery voltage and current
+	  to determine the battery state-of-charge (SOC) and supports other
+	  battery management features.
+
 endmenu
diff --git a/drivers/power/supply/qcom/Makefile b/drivers/power/supply/qcom/Makefile
index 870a67e..6c7fc78 100644
--- a/drivers/power/supply/qcom/Makefile
+++ b/drivers/power/supply/qcom/Makefile
@@ -6,6 +6,7 @@
 obj-$(CONFIG_SMB1351_USB_CHARGER) += smb1351-charger.o pmic-voter.o battery.o
 obj-$(CONFIG_QPNP_SMB2)		+= step-chg-jeita.o battery.o qpnp-smb2.o smb-lib.o pmic-voter.o storm-watch.o
 obj-$(CONFIG_SMB138X_CHARGER)	+= step-chg-jeita.o smb138x-charger.o smb-lib.o pmic-voter.o storm-watch.o battery.o
+obj-$(CONFIG_QPNP_QG)		+= qpnp-qg.o pmic-voter.o qg-util.o qg-soc.o qg-sdam.o qg-battery-profile.o qg-profile-lib.o
 obj-$(CONFIG_QPNP_QNOVO)	+= qpnp-qnovo.o battery.o
 obj-$(CONFIG_QPNP_TYPEC)	+= qpnp-typec.o
 obj-$(CONFIG_QPNP_SMB5)		+= step-chg-jeita.o battery.o qpnp-smb5.o smb5-lib.o pmic-voter.o storm-watch.o
diff --git a/drivers/power/supply/qcom/qg-battery-profile.c b/drivers/power/supply/qcom/qg-battery-profile.c
new file mode 100644
index 0000000..b86c7f5
--- /dev/null
+++ b/drivers/power/supply/qcom/qg-battery-profile.c
@@ -0,0 +1,503 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)	"QG-K: %s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/fcntl.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <uapi/linux/qg-profile.h>
+#include "qg-profile-lib.h"
+#include "qg-defs.h"
+
+struct qg_battery_data {
+	/* battery-data class node */
+	dev_t				dev_no;
+	struct class			*battery_class;
+	struct device			*battery_device;
+	struct cdev			battery_cdev;
+
+	/* profile */
+	struct device_node		*profile_node;
+	struct profile_table_data	profile[TABLE_MAX];
+};
+
+struct tables {
+	int table_index;
+	char *table_name;
+};
+
+static struct tables table[] = {
+	{TABLE_SOC_OCV1, "qcom,pc-temp-v1-lut"},
+	{TABLE_SOC_OCV2, "qcom,pc-temp-v2-lut"},
+	{TABLE_FCC1, "qcom,fcc1-temp-lut"},
+	{TABLE_FCC2, "qcom,fcc2-temp-lut"},
+	{TABLE_Z1, "qcom,pc-temp-z1-lut"},
+	{TABLE_Z2, "qcom,pc-temp-z2-lut"},
+	{TABLE_Z3, "qcom,pc-temp-z3-lut"},
+	{TABLE_Z4, "qcom,pc-temp-z4-lut"},
+	{TABLE_Z5, "qcom,pc-temp-z5-lut"},
+	{TABLE_Z6, "qcom,pc-temp-z6-lut"},
+	{TABLE_Y1, "qcom,pc-temp-y1-lut"},
+	{TABLE_Y2, "qcom,pc-temp-y2-lut"},
+	{TABLE_Y3, "qcom,pc-temp-y3-lut"},
+	{TABLE_Y4, "qcom,pc-temp-y4-lut"},
+	{TABLE_Y5, "qcom,pc-temp-y5-lut"},
+	{TABLE_Y6, "qcom,pc-temp-y6-lut"},
+};
+
+static struct qg_battery_data *the_battery;
+
+static int qg_battery_data_open(struct inode *inode, struct file *file)
+{
+	struct qg_battery_data *battery = container_of(inode->i_cdev,
+				struct qg_battery_data, battery_cdev);
+
+	file->private_data = battery;
+
+	return 0;
+}
+
+static long qg_battery_data_ioctl(struct file *file, unsigned int cmd,
+						unsigned long arg)
+{
+	struct qg_battery_data *battery = file->private_data;
+	struct battery_params __user *bp_user =
+				(struct battery_params __user *)arg;
+	struct battery_params bp;
+	int rc = 0, soc, ocv_uv, fcc_mah, var, slope;
+
+	if (!battery->profile_node) {
+		pr_err("Battery data not set!\n");
+		return -EINVAL;
+	}
+
+	if (!bp_user) {
+		pr_err("Invalid battery-params user pointer\n");
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&bp, bp_user, sizeof(bp))) {
+		pr_err("Failed in copy_from_user\n");
+		return -EFAULT;
+	}
+
+	switch (cmd) {
+	case BPIOCXSOC:
+		if (bp.table_index != TABLE_SOC_OCV1 &&
+				bp.table_index != TABLE_SOC_OCV2) {
+			pr_err("Invalid table index %d for SOC-OCV lookup\n",
+					bp.table_index);
+			rc = -EINVAL;
+		} else {
+			/* OCV is passed as deci-uV  - 10^-4 V */
+			soc = interpolate_soc(&battery->profile[bp.table_index],
+					bp.batt_temp, UV_TO_DECIUV(bp.ocv_uv));
+			soc = CAP(QG_MIN_SOC, QG_MAX_SOC, soc);
+			rc = put_user(soc, &bp_user->soc);
+			if (rc < 0) {
+				pr_err("BPIOCXSOC: Failed rc=%d\n", rc);
+				goto ret_err;
+			}
+			pr_debug("BPIOCXSOC: lut=%s ocv=%d batt_temp=%d soc=%d\n",
+					battery->profile[bp.table_index].name,
+					bp.ocv_uv, bp.batt_temp, soc);
+		}
+		break;
+	case BPIOCXOCV:
+		if (bp.table_index != TABLE_SOC_OCV1 &&
+				bp.table_index != TABLE_SOC_OCV2) {
+			pr_err("Invalid table index %d for SOC-OCV lookup\n",
+					bp.table_index);
+			rc = -EINVAL;
+		} else {
+			ocv_uv = interpolate_var(
+					&battery->profile[bp.table_index],
+					bp.batt_temp, bp.soc);
+			ocv_uv = DECIUV_TO_UV(ocv_uv);
+			ocv_uv = CAP(QG_MIN_OCV_UV, QG_MAX_OCV_UV, ocv_uv);
+			rc = put_user(ocv_uv, &bp_user->ocv_uv);
+			if (rc < 0) {
+				pr_err("BPIOCXOCV: Failed rc=%d\n", rc);
+				goto ret_err;
+			}
+			pr_debug("BPIOCXOCV: lut=%s ocv=%d batt_temp=%d soc=%d\n",
+					battery->profile[bp.table_index].name,
+					ocv_uv, bp.batt_temp, bp.soc);
+		}
+		break;
+	case BPIOCXFCC:
+		if (bp.table_index != TABLE_FCC1 &&
+				bp.table_index != TABLE_FCC2) {
+			pr_err("Invalid table index %d for FCC lookup\n",
+					bp.table_index);
+			rc = -EINVAL;
+		} else {
+			fcc_mah = interpolate_single_row_lut(
+					&battery->profile[bp.table_index],
+					bp.batt_temp, DEGC_SCALE);
+			fcc_mah = CAP(QG_MIN_FCC_MAH, QG_MAX_FCC_MAH, fcc_mah);
+			rc = put_user(fcc_mah, &bp_user->fcc_mah);
+			if (rc) {
+				pr_err("BPIOCXFCC: Failed rc=%d\n", rc);
+				goto ret_err;
+			}
+			pr_debug("BPIOCXFCC: lut=%s batt_temp=%d fcc_mah=%d\n",
+					battery->profile[bp.table_index].name,
+					bp.batt_temp, fcc_mah);
+		}
+		break;
+	case BPIOCXVAR:
+		if (bp.table_index < TABLE_Z1 || bp.table_index > TABLE_MAX) {
+			pr_err("Invalid table index %d for VAR lookup\n",
+					bp.table_index);
+			rc = -EINVAL;
+		} else {
+			var = interpolate_var(&battery->profile[bp.table_index],
+					bp.batt_temp, bp.soc);
+			var = CAP(QG_MIN_VAR, QG_MAX_VAR, var);
+			rc = put_user(var, &bp_user->var);
+			if (rc < 0) {
+				pr_err("BPIOCXVAR: Failed rc=%d\n", rc);
+				goto ret_err;
+			}
+			pr_debug("BPIOCXVAR: lut=%s var=%d batt_temp=%d soc=%d\n",
+					battery->profile[bp.table_index].name,
+					var, bp.batt_temp, bp.soc);
+		}
+		break;
+	case BPIOCXSLOPE:
+		if (bp.table_index != TABLE_SOC_OCV1 &&
+				bp.table_index != TABLE_SOC_OCV2) {
+			pr_err("Invalid table index %d for Slope lookup\n",
+					bp.table_index);
+			rc = -EINVAL;
+		} else {
+			slope = interpolate_slope(
+					&battery->profile[bp.table_index],
+					bp.batt_temp, bp.soc);
+			slope = CAP(QG_MIN_SLOPE, QG_MAX_SLOPE, slope);
+			rc = put_user(slope, &bp_user->slope);
+			if (rc) {
+				pr_err("BPIOCXSLOPE: Failed rc=%d\n", rc);
+				goto ret_err;
+			}
+			pr_debug("BPIOCXSLOPE: lut=%s soc=%d batt_temp=%d slope=%d\n",
+					battery->profile[bp.table_index].name,
+					bp.soc, bp.batt_temp, slope);
+		}
+		break;
+	default:
+		pr_err("IOCTL %d not supported\n", cmd);
+		rc = -EINVAL;
+	}
+ret_err:
+	return rc;
+}
+
+static int qg_battery_data_release(struct inode *inode, struct file *file)
+{
+	pr_debug("battery_data device closed\n");
+
+	return 0;
+}
+
+static const struct file_operations qg_battery_data_fops = {
+	.owner = THIS_MODULE,
+	.open = qg_battery_data_open,
+	.unlocked_ioctl = qg_battery_data_ioctl,
+	.compat_ioctl = qg_battery_data_ioctl,
+	.release = qg_battery_data_release,
+};
+
+static int get_length(struct device_node *node,
+			int *length, char *prop_name, bool ignore_null)
+{
+	struct property *prop;
+
+	prop = of_find_property(node, prop_name, NULL);
+	if (!prop) {
+		if (ignore_null) {
+			*length = 1;
+			return 0;
+		}
+		pr_err("Failed to find %s property\n", prop_name);
+		return -ENODATA;
+	} else if (!prop->value) {
+		pr_err("Failed to find value for %s property\n", prop_name);
+		return -ENODATA;
+	}
+
+	*length = prop->length / sizeof(u32);
+
+	return 0;
+}
+
+static int qg_parse_battery_profile(struct qg_battery_data *battery)
+{
+	int i, j, k, rows = 0, cols = 0, lut_length = 0, rc = 0;
+	struct device_node *node;
+	struct property *prop;
+	const __be32 *data;
+
+	for (i = 0; i < TABLE_MAX; i++) {
+		node = of_find_node_by_name(battery->profile_node,
+						table[i].table_name);
+		if (!node) {
+			pr_err("%s table not found\n", table[i].table_name);
+			rc = -ENODEV;
+			goto cleanup;
+		}
+
+		rc = get_length(node, &cols, "qcom,lut-col-legend", false);
+		if (rc < 0) {
+			pr_err("Failed to get col-length for %s table rc=%d\n",
+				table[i].table_name, rc);
+			goto cleanup;
+		}
+
+		rc = get_length(node, &rows, "qcom,lut-row-legend", true);
+		if (rc < 0) {
+			pr_err("Failed to get row-length for %s table rc=%d\n",
+				table[i].table_name, rc);
+			goto cleanup;
+		}
+
+		rc = get_length(node, &lut_length, "qcom,lut-data", false);
+		if (rc < 0) {
+			pr_err("Failed to get lut-length for %s table rc=%d\n",
+				table[i].table_name, rc);
+			goto cleanup;
+		}
+
+		if (lut_length != cols * rows) {
+			pr_err("Invalid lut-length for %s table\n",
+					table[i].table_name);
+			rc = -EINVAL;
+			goto cleanup;
+		}
+
+		battery->profile[i].name = kzalloc(strlen(table[i].table_name)
+						+ 1, GFP_KERNEL);
+		if (!battery->profile[i].name) {
+			rc = -ENOMEM;
+			goto cleanup;
+		}
+
+		strlcpy(battery->profile[i].name, table[i].table_name,
+						strlen(table[i].table_name));
+		battery->profile[i].rows = rows;
+		battery->profile[i].cols = cols;
+
+		if (rows != 1) {
+			battery->profile[i].row_entries = kcalloc(rows,
+				sizeof(*battery->profile[i].row_entries),
+				GFP_KERNEL);
+			if (!battery->profile[i].row_entries) {
+				rc = -ENOMEM;
+				goto cleanup;
+			}
+		}
+
+		battery->profile[i].col_entries = kcalloc(cols,
+				sizeof(*battery->profile[i].col_entries),
+				GFP_KERNEL);
+		if (!battery->profile[i].col_entries) {
+			rc = -ENOMEM;
+			goto cleanup;
+		}
+
+		battery->profile[i].data = kcalloc(rows,
+				sizeof(*battery->profile[i].data), GFP_KERNEL);
+		if (!battery->profile[i].data) {
+			rc = -ENOMEM;
+			goto cleanup;
+		}
+
+		for (j = 0; j < rows; j++) {
+			battery->profile[i].data[j] = kcalloc(cols,
+				sizeof(**battery->profile[i].data),
+				GFP_KERNEL);
+			if (!battery->profile[i].data[j]) {
+				rc = -ENOMEM;
+				goto cleanup;
+			}
+		}
+
+		/* read profile data */
+		rc = of_property_read_u32_array(node, "qcom,lut-col-legend",
+					battery->profile[i].col_entries, cols);
+		if (rc < 0) {
+			pr_err("Failed to read cols values for table %s rc=%d\n",
+					table[i].table_name, rc);
+			goto cleanup;
+		}
+
+		if (rows != 1) {
+			rc = of_property_read_u32_array(node,
+					"qcom,lut-row-legend",
+					battery->profile[i].row_entries, rows);
+			if (rc < 0) {
+				pr_err("Failed to read row values for table %s rc=%d\n",
+						table[i].table_name, rc);
+				goto cleanup;
+			}
+		}
+
+		prop = of_find_property(node, "qcom,lut-data", NULL);
+		if (!prop) {
+			pr_err("Failed to find lut-data\n");
+			rc = -EINVAL;
+			goto cleanup;
+		}
+		data = prop->value;
+		for (j = 0; j < rows; j++) {
+			for (k = 0; k < cols; k++)
+				battery->profile[i].data[j][k] =
+						be32_to_cpup(data++);
+		}
+
+		pr_debug("Profile table %s parsed rows=%d cols=%d\n",
+			battery->profile[i].name, battery->profile[i].rows,
+			battery->profile[i].cols);
+	}
+
+	return 0;
+
+cleanup:
+	for (; i >= 0; i++) {
+		kfree(battery->profile[i].name);
+		kfree(battery->profile[i].row_entries);
+		kfree(battery->profile[i].col_entries);
+		for (j = 0; j < battery->profile[i].rows; j++) {
+			if (battery->profile[i].data)
+				kfree(battery->profile[i].data[j]);
+		}
+		kfree(battery->profile[i].data);
+	}
+	return rc;
+}
+
+int lookup_soc_ocv(u32 *soc, u32 ocv_uv, int batt_temp, bool charging)
+{
+	u8 table_index = charging ? TABLE_SOC_OCV1 : TABLE_SOC_OCV2;
+
+	if (!the_battery || !the_battery->profile) {
+		pr_err("Battery profile not loaded\n");
+		return -ENODEV;
+	}
+
+	*soc = interpolate_soc(&the_battery->profile[table_index],
+				batt_temp, UV_TO_DECIUV(ocv_uv));
+
+	*soc = CAP(0, 100, DIV_ROUND_CLOSEST(*soc, 100));
+
+	return 0;
+}
+
+int qg_batterydata_init(struct device_node *profile_node)
+{
+	int rc = 0;
+	struct qg_battery_data *battery;
+
+	battery = kzalloc(sizeof(*battery), GFP_KERNEL);
+	if (!battery)
+		return -ENOMEM;
+
+	battery->profile_node = profile_node;
+
+	/* char device to access battery-profile data */
+	rc = alloc_chrdev_region(&battery->dev_no, 0, 1, "qg_battery");
+	if (rc < 0) {
+		pr_err("Failed to allocate chrdev rc=%d\n", rc);
+		goto free_battery;
+	}
+
+	cdev_init(&battery->battery_cdev, &qg_battery_data_fops);
+	rc = cdev_add(&battery->battery_cdev, battery->dev_no, 1);
+	if (rc) {
+		pr_err("Failed to add battery_cdev rc=%d\n", rc);
+		goto unregister_chrdev;
+	}
+
+	battery->battery_class = class_create(THIS_MODULE, "qg_battery");
+	if (IS_ERR_OR_NULL(battery->battery_class)) {
+		pr_err("Failed to create qg-battery class\n");
+		rc = -ENODEV;
+		goto delete_cdev;
+	}
+
+	battery->battery_device = device_create(battery->battery_class,
+					NULL, battery->dev_no,
+					NULL, "qg_battery");
+	if (IS_ERR_OR_NULL(battery->battery_device)) {
+		pr_err("Failed to create battery_device device\n");
+		rc = -ENODEV;
+		goto delete_cdev;
+	}
+
+	/* parse the battery profile */
+	rc = qg_parse_battery_profile(battery);
+	if (rc < 0) {
+		pr_err("Failed to parse battery profile rc=%d\n", rc);
+		goto destroy_device;
+	}
+
+	the_battery = battery;
+
+	pr_info("QG Battery-profile loaded, '/dev/qg_battery' created!\n");
+
+	return 0;
+
+destroy_device:
+	device_destroy(battery->battery_class, battery->dev_no);
+delete_cdev:
+	cdev_del(&battery->battery_cdev);
+unregister_chrdev:
+	unregister_chrdev_region(battery->dev_no, 1);
+free_battery:
+	kfree(battery);
+	return rc;
+}
+
+void qg_batterydata_exit(void)
+{
+	int i, j;
+
+	if (the_battery) {
+		/* unregister the device node */
+		device_destroy(the_battery->battery_class, the_battery->dev_no);
+		cdev_del(&the_battery->battery_cdev);
+		unregister_chrdev_region(the_battery->dev_no, 1);
+
+		/* delete all the battery profile memory */
+		for (i = 0; i < TABLE_MAX; i++) {
+			kfree(the_battery->profile[i].name);
+			kfree(the_battery->profile[i].row_entries);
+			kfree(the_battery->profile[i].col_entries);
+			for (j = 0; j < the_battery->profile[i].rows; j++) {
+				if (the_battery->profile[i].data)
+					kfree(the_battery->profile[i].data[j]);
+			}
+			kfree(the_battery->profile[i].data);
+		}
+	}
+
+	kfree(the_battery);
+	the_battery = NULL;
+}
diff --git a/drivers/power/supply/qcom/qg-battery-profile.h b/drivers/power/supply/qcom/qg-battery-profile.h
new file mode 100644
index 0000000..143a4f2
--- /dev/null
+++ b/drivers/power/supply/qcom/qg-battery-profile.h
@@ -0,0 +1,19 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __QG_BATTERY_PROFILE_H__
+#define __QG_BATTERY_PROFILE_H__
+
+int qg_batterydata_init(struct device_node *node);
+void qg_batterydata_exit(void);
+int lookup_soc_ocv(u32 *soc, u32 ocv_uv, int batt_temp, bool charging);
+
+#endif /* __QG_BATTERY_PROFILE_H__ */
diff --git a/drivers/power/supply/qcom/qg-core.h b/drivers/power/supply/qcom/qg-core.h
new file mode 100644
index 0000000..aadef7f
--- /dev/null
+++ b/drivers/power/supply/qcom/qg-core.h
@@ -0,0 +1,143 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __QG_CORE_H__
+#define __QG_CORE_H__
+
+struct qg_batt_props {
+	const char		*batt_type_str;
+	int			float_volt_uv;
+	int			vbatt_full_mv;
+	int			fastchg_curr_ma;
+	int			qg_profile_version;
+};
+
+struct qg_irq_info {
+	const char		*name;
+	const irq_handler_t	handler;
+	const bool		wake;
+	int			irq;
+};
+
+struct qg_dt {
+	int			vbatt_empty_mv;
+	int			vbatt_low_mv;
+	int			vbatt_cutoff_mv;
+	int			iterm_ma;
+	int			s2_fifo_length;
+	int			s2_vbat_low_fifo_length;
+	int			s2_acc_length;
+	int			s2_acc_intvl_ms;
+	int			ocv_timer_expiry_min;
+	int			ocv_tol_threshold_uv;
+	int			s3_entry_fifo_length;
+	int			s3_entry_ibat_ua;
+	int			s3_exit_ibat_ua;
+	int			delta_soc;
+	int			rbat_conn_mohm;
+};
+
+struct qpnp_qg {
+	struct device		*dev;
+	struct pmic_revid_data	*pmic_rev_id;
+	struct regmap		*regmap;
+	struct qpnp_vadc_chip	*vadc_dev;
+	struct power_supply	*qg_psy;
+	struct class		*qg_class;
+	struct device		*qg_device;
+	struct cdev		qg_cdev;
+	dev_t			dev_no;
+	struct work_struct	udata_work;
+	struct work_struct	scale_soc_work;
+	struct work_struct	qg_status_change_work;
+	struct notifier_block	nb;
+	struct mutex		bus_lock;
+	struct mutex		data_lock;
+	struct mutex		soc_lock;
+	wait_queue_head_t	qg_wait_q;
+	struct votable		*awake_votable;
+	struct votable		*vbatt_irq_disable_votable;
+	struct votable		*fifo_irq_disable_votable;
+	struct votable		*good_ocv_irq_disable_votable;
+	u32			qg_base;
+
+	/* local data variables */
+	u32			batt_id_ohm;
+	struct qg_kernel_data	kdata;
+	struct qg_user_data	udata;
+	struct power_supply	*batt_psy;
+	struct power_supply	*usb_psy;
+	struct power_supply	*parallel_psy;
+
+	/* status variable */
+	u32			*debug_mask;
+	bool			profile_loaded;
+	bool			battery_missing;
+	bool			data_ready;
+	bool			suspend_data;
+	bool			vbat_low;
+	bool			charge_done;
+	bool			parallel_enabled;
+	bool			usb_present;
+	int			charge_status;
+	int			charge_type;
+	int			next_wakeup_ms;
+	u32			wa_flags;
+	ktime_t			last_user_update_time;
+	ktime_t			last_fifo_update_time;
+
+	/* soc params */
+	int			catch_up_soc;
+	int			msoc;
+	int			pon_soc;
+	struct alarm		alarm_timer;
+	u32			sdam_data[SDAM_MAX];
+
+	/* DT */
+	struct qg_dt		dt;
+	struct qg_batt_props	bp;
+};
+
+enum ocv_type {
+	PON_OCV,
+	GOOD_OCV,
+};
+
+enum debug_mask {
+	QG_DEBUG_PON		= BIT(0),
+	QG_DEBUG_PROFILE	= BIT(1),
+	QG_DEBUG_DEVICE		= BIT(2),
+	QG_DEBUG_STATUS		= BIT(3),
+	QG_DEBUG_FIFO		= BIT(4),
+	QG_DEBUG_IRQ		= BIT(5),
+	QG_DEBUG_SOC		= BIT(6),
+	QG_DEBUG_PM		= BIT(7),
+	QG_DEBUG_BUS_READ	= BIT(8),
+	QG_DEBUG_BUS_WRITE	= BIT(9),
+};
+
+enum qg_irq {
+	QG_BATT_MISSING_IRQ,
+	QG_VBATT_LOW_IRQ,
+	QG_VBATT_EMPTY_IRQ,
+	QG_FIFO_UPDATE_DONE_IRQ,
+	QG_GOOD_OCV_IRQ,
+	QG_FSM_STAT_CHG_IRQ,
+	QG_EVENT_IRQ,
+	QG_MAX_IRQ,
+};
+
+enum qg_wa_flags {
+	QG_VBAT_LOW_WA = BIT(0),
+};
+
+
+#endif /* __QG_CORE_H__ */
diff --git a/drivers/power/supply/qcom/qg-defs.h b/drivers/power/supply/qcom/qg-defs.h
new file mode 100644
index 0000000..bbbc7ee
--- /dev/null
+++ b/drivers/power/supply/qcom/qg-defs.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QG_DEFS_H__
+#define __QG_DEFS_H__
+
+#define qg_dbg(chip, reason, fmt, ...)			\
+	do {							\
+		if (*chip->debug_mask & (reason))		\
+			pr_info(fmt, ##__VA_ARGS__);	\
+		else						\
+			pr_debug(fmt, ##__VA_ARGS__);	\
+	} while (0)
+
+#define is_between(left, right, value) \
+		(((left) >= (right) && (left) >= (value) \
+			&& (value) >= (right)) \
+		|| ((left) <= (right) && (left) <= (value) \
+			&& (value) <= (right)))
+
+#define UDATA_READY_VOTER		"UDATA_READY_VOTER"
+#define FIFO_DONE_VOTER			"FIFO_DONE_VOTER"
+#define FIFO_RT_DONE_VOTER		"FIFO_RT_DONE_VOTER"
+#define SUSPEND_DATA_VOTER		"SUSPEND_DATA_VOTER"
+#define GOOD_OCV_VOTER			"GOOD_OCV_VOTER"
+#define PROFILE_IRQ_DISABLE		"NO_PROFILE_IRQ_DISABLE"
+#define QG_INIT_STATE_IRQ_DISABLE	"QG_INIT_STATE_IRQ_DISABLE"
+
+#define V_RAW_TO_UV(V_RAW)		div_u64(194637ULL * (u64)V_RAW, 1000)
+#define I_RAW_TO_UA(I_RAW)		div_s64(152588LL * (s64)I_RAW, 1000)
+
+#define DEGC_SCALE			10
+#define UV_TO_DECIUV(a)			(a / 100)
+#define DECIUV_TO_UV(a)			(a * 100)
+
+#define CAP(min, max, value)			\
+		((min > value) ? min : ((value > max) ? max : value))
+
+#endif /* __QG_DEFS_H__ */
diff --git a/drivers/power/supply/qcom/qg-profile-lib.c b/drivers/power/supply/qcom/qg-profile-lib.c
new file mode 100644
index 0000000..2af997e
--- /dev/null
+++ b/drivers/power/supply/qcom/qg-profile-lib.c
@@ -0,0 +1,311 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include "qg-profile-lib.h"
+#include "qg-defs.h"
+
+static int linear_interpolate(int y0, int x0, int y1, int x1, int x)
+{
+	if (y0 == y1 || x == x0)
+		return y0;
+	if (x1 == x0 || x == x1)
+		return y1;
+
+	return y0 + ((y1 - y0) * (x - x0) / (x1 - x0));
+}
+
+int interpolate_single_row_lut(struct profile_table_data *lut,
+						int x, int scale)
+{
+	int i, result;
+	int cols = lut->cols;
+
+	if (x < lut->col_entries[0] * scale) {
+		pr_debug("x %d less than known range return y = %d lut = %s\n",
+					x, lut->data[0][0], lut->name);
+		return lut->data[0][0];
+	}
+
+	if (x > lut->col_entries[cols-1] * scale) {
+		pr_debug("x %d more than known range return y = %d lut = %s\n",
+					x, lut->data[0][cols-1], lut->name);
+		return lut->data[0][cols-1];
+	}
+
+	for (i = 0; i < cols; i++) {
+		if (x <= lut->col_entries[i] * scale)
+			break;
+	}
+
+	if (x == lut->col_entries[i] * scale) {
+		result = lut->data[0][i];
+	} else {
+		result = linear_interpolate(
+			lut->data[0][i-1],
+			lut->col_entries[i-1] * scale,
+			lut->data[0][i],
+			lut->col_entries[i] * scale,
+			x);
+	}
+
+	return result;
+}
+
+int interpolate_soc(struct profile_table_data *lut,
+				int batt_temp, int ocv)
+{
+	int i, j, soc_high, soc_low, soc;
+	int rows = lut->rows;
+	int cols = lut->cols;
+
+	if (batt_temp < lut->col_entries[0] * DEGC_SCALE) {
+		pr_debug("batt_temp %d < known temp range\n", batt_temp);
+		batt_temp = lut->col_entries[0] * DEGC_SCALE;
+	}
+
+	if (batt_temp > lut->col_entries[cols - 1] * DEGC_SCALE) {
+		pr_debug("batt_temp %d > known temp range\n", batt_temp);
+		batt_temp = lut->col_entries[cols - 1] * DEGC_SCALE;
+	}
+
+	for (j = 0; j < cols; j++)
+		if (batt_temp <= lut->col_entries[j] * DEGC_SCALE)
+			break;
+
+	if (batt_temp == lut->col_entries[j] * DEGC_SCALE) {
+		/* found an exact match for temp in the table */
+		if (ocv >= lut->data[0][j])
+			return lut->row_entries[0];
+		if (ocv <= lut->data[rows - 1][j])
+			return lut->row_entries[rows - 1];
+		for (i = 0; i < rows; i++) {
+			if (ocv >= lut->data[i][j]) {
+				if (ocv == lut->data[i][j])
+					return lut->row_entries[i];
+				soc = linear_interpolate(
+					lut->row_entries[i],
+					lut->data[i][j],
+					lut->row_entries[i - 1],
+					lut->data[i - 1][j],
+					ocv);
+				return soc;
+			}
+		}
+	}
+
+	/* batt_temp is within temperature for column j-1 and j */
+	if (ocv >= lut->data[0][j])
+		return lut->row_entries[0];
+	if (ocv <= lut->data[rows - 1][j - 1])
+		return lut->row_entries[rows - 1];
+
+	soc_low = soc_high = 0;
+	for (i = 0; i < rows-1; i++) {
+		if (soc_high == 0 && is_between(lut->data[i][j],
+				lut->data[i+1][j], ocv)) {
+			soc_high = linear_interpolate(
+				lut->row_entries[i],
+				lut->data[i][j],
+				lut->row_entries[i + 1],
+				lut->data[i+1][j],
+				ocv);
+		}
+
+		if (soc_low == 0 && is_between(lut->data[i][j-1],
+				lut->data[i+1][j-1], ocv)) {
+			soc_low = linear_interpolate(
+				lut->row_entries[i],
+				lut->data[i][j-1],
+				lut->row_entries[i + 1],
+				lut->data[i+1][j-1],
+				ocv);
+		}
+
+		if (soc_high && soc_low) {
+			soc = linear_interpolate(
+				soc_low,
+				lut->col_entries[j-1] * DEGC_SCALE,
+				soc_high,
+				lut->col_entries[j] * DEGC_SCALE,
+				batt_temp);
+			return soc;
+		}
+	}
+
+	if (soc_high)
+		return soc_high;
+
+	if (soc_low)
+		return soc_low;
+
+	pr_debug("%d ocv wasn't found for temp %d in the LUT %s returning 100%%\n",
+						ocv, batt_temp, lut->name);
+	return 10000;
+}
+
+int interpolate_var(struct profile_table_data *lut,
+				int batt_temp, int soc)
+{
+	int i, var1, var2, var, rows, cols;
+	int row1 = 0;
+	int row2 = 0;
+
+	rows = lut->rows;
+	cols = lut->cols;
+	if (soc > lut->row_entries[0]) {
+		pr_debug("soc %d greater than known soc ranges for %s lut\n",
+							soc, lut->name);
+		row1 = 0;
+		row2 = 0;
+	} else if (soc < lut->row_entries[rows - 1]) {
+		pr_debug("soc %d less than known soc ranges for %s lut\n",
+							soc, lut->name);
+		row1 = rows - 1;
+		row2 = rows - 1;
+	} else {
+		for (i = 0; i < rows; i++) {
+			if (soc == lut->row_entries[i]) {
+				row1 = i;
+				row2 = i;
+				break;
+			}
+			if (soc > lut->row_entries[i]) {
+				row1 = i - 1;
+				row2 = i;
+				break;
+			}
+		}
+	}
+
+	if (batt_temp < lut->col_entries[0] * DEGC_SCALE)
+		batt_temp = lut->col_entries[0] * DEGC_SCALE;
+	if (batt_temp > lut->col_entries[cols - 1] * DEGC_SCALE)
+		batt_temp = lut->col_entries[cols - 1] * DEGC_SCALE;
+
+	for (i = 0; i < cols; i++)
+		if (batt_temp <= lut->col_entries[i] * DEGC_SCALE)
+			break;
+
+	if (batt_temp == lut->col_entries[i] * DEGC_SCALE) {
+		var = linear_interpolate(
+				lut->data[row1][i],
+				lut->row_entries[row1],
+				lut->data[row2][i],
+				lut->row_entries[row2],
+				soc);
+		return var;
+	}
+
+	var1 = linear_interpolate(
+				lut->data[row1][i - 1],
+				lut->col_entries[i - 1] * DEGC_SCALE,
+				lut->data[row1][i],
+				lut->col_entries[i] * DEGC_SCALE,
+				batt_temp);
+
+	var2 = linear_interpolate(
+				lut->data[row2][i - 1],
+				lut->col_entries[i - 1] * DEGC_SCALE,
+				lut->data[row2][i],
+				lut->col_entries[i] * DEGC_SCALE,
+				batt_temp);
+
+	var = linear_interpolate(
+				var1,
+				lut->row_entries[row1],
+				var2,
+				lut->row_entries[row2],
+				soc);
+
+	return var;
+}
+
+int interpolate_slope(struct profile_table_data *lut,
+					int batt_temp, int soc)
+{
+	int i, ocvrow1, ocvrow2, rows, cols;
+	int row1 = 0;
+	int row2 = 0;
+	int slope;
+
+	rows = lut->rows;
+	cols = lut->cols;
+	if (soc >= lut->row_entries[0]) {
+		pr_debug("soc %d >= max soc range - use the slope at soc=%d for lut %s\n",
+					soc, lut->row_entries[0], lut->name);
+		row1 = 0;
+		row2 = 1;
+	} else if (soc <= lut->row_entries[rows - 1]) {
+		pr_debug("soc %d is <= min soc range - use the slope at soc=%d for lut %s\n",
+				soc, lut->row_entries[rows - 1], lut->name);
+		row1 = rows - 2;
+		row2 = rows - 1;
+	} else {
+		for (i = 0; i < rows; i++) {
+			if (soc >= lut->row_entries[i]) {
+				row1 = i - 1;
+				row2 = i;
+				break;
+			}
+		}
+	}
+
+	if (batt_temp < lut->col_entries[0] * DEGC_SCALE)
+		batt_temp = lut->col_entries[0] * DEGC_SCALE;
+	if (batt_temp > lut->col_entries[cols - 1] * DEGC_SCALE)
+		batt_temp = lut->col_entries[cols - 1] * DEGC_SCALE;
+
+	for (i = 0; i < cols; i++) {
+		if (batt_temp <= lut->col_entries[i] * DEGC_SCALE)
+			break;
+	}
+
+	if (batt_temp == lut->col_entries[i] * DEGC_SCALE) {
+		slope = (lut->data[row1][i] - lut->data[row2][i]);
+		if (slope <= 0) {
+			pr_warn_ratelimited("Slope=%d for soc=%d, using 1\n",
+							slope, soc);
+			slope = 1;
+		}
+		slope *= 10000;
+		slope /= (lut->row_entries[row1] -
+			lut->row_entries[row2]);
+		return slope;
+	}
+	ocvrow1 = linear_interpolate(
+			lut->data[row1][i - 1],
+			lut->col_entries[i - 1] * DEGC_SCALE,
+			lut->data[row1][i],
+			lut->col_entries[i] * DEGC_SCALE,
+			batt_temp);
+
+	ocvrow2 = linear_interpolate(
+			lut->data[row2][i - 1],
+			lut->col_entries[i - 1] * DEGC_SCALE,
+			lut->data[row2][i],
+			lut->col_entries[i] * DEGC_SCALE,
+			batt_temp);
+
+	slope = (ocvrow1 - ocvrow2);
+	if (slope <= 0) {
+		pr_warn_ratelimited("Slope=%d for soc=%d, using 1\n",
+							slope, soc);
+		slope = 1;
+	}
+	slope *= 10000;
+	slope /= (lut->row_entries[row1] - lut->row_entries[row2]);
+
+	return slope;
+}
diff --git a/drivers/power/supply/qcom/qg-profile-lib.h b/drivers/power/supply/qcom/qg-profile-lib.h
new file mode 100644
index 0000000..eb7263d
--- /dev/null
+++ b/drivers/power/supply/qcom/qg-profile-lib.h
@@ -0,0 +1,34 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QG_PROFILE_LIB_H__
+#define __QG_PROFILE_LIB_H__
+
+struct profile_table_data {
+	char		*name;
+	int		rows;
+	int		cols;
+	int		*row_entries;
+	int		*col_entries;
+	int		**data;
+};
+
+int interpolate_single_row_lut(struct profile_table_data *lut,
+						int x, int scale);
+int interpolate_soc(struct profile_table_data *lut,
+				int batt_temp, int ocv);
+int interpolate_var(struct profile_table_data *lut,
+				int batt_temp, int soc);
+int interpolate_slope(struct profile_table_data *lut,
+				int batt_temp, int soc);
+
+#endif /*__QG_PROFILE_LIB_H__ */
diff --git a/drivers/power/supply/qcom/qg-reg.h b/drivers/power/supply/qcom/qg-reg.h
new file mode 100644
index 0000000..1f42a8c
--- /dev/null
+++ b/drivers/power/supply/qcom/qg-reg.h
@@ -0,0 +1,89 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QG_REG_H__
+#define __QG_REG_H__
+
+#define PERPH_TYPE_REG				0x04
+#define QG_TYPE					0x0D
+
+#define QG_STATUS1_REG				0x08
+#define BATTERY_PRESENT_BIT			BIT(0)
+
+#define QG_STATUS2_REG				0x09
+#define GOOD_OCV_BIT				BIT(1)
+
+#define QG_STATUS3_REG				0x0A
+#define COUNT_FIFO_RT_MASK			GENMASK(3, 0)
+
+#define QG_INT_RT_STS_REG			0x10
+#define FIFO_UPDATE_DONE_RT_STS_BIT		BIT(3)
+#define VBAT_LOW_INT_RT_STS_BIT			BIT(1)
+
+#define QG_INT_LATCHED_STS_REG			0x18
+#define FIFO_UPDATE_DONE_INT_LAT_STS_BIT	BIT(3)
+
+#define QG_DATA_CTL1_REG			0x41
+#define MASTER_HOLD_OR_CLR_BIT			BIT(0)
+
+#define QG_MODE_CTL1_REG			0x43
+#define PARALLEL_IBAT_SENSE_EN_BIT		BIT(7)
+
+#define QG_VBAT_EMPTY_THRESHOLD_REG		0x4B
+#define QG_VBAT_LOW_THRESHOLD_REG		0x4C
+
+#define QG_S2_NORMAL_MEAS_CTL2_REG		0x51
+#define FIFO_LENGTH_MASK			GENMASK(5, 3)
+#define FIFO_LENGTH_SHIFT			3
+#define NUM_OF_ACCUM_MASK			GENMASK(2, 0)
+
+#define QG_S2_NORMAL_MEAS_CTL3_REG		0x52
+
+#define QG_S3_SLEEP_OCV_MEAS_CTL4_REG		0x59
+#define S3_SLEEP_OCV_TIMER_MASK			GENMASK(2, 0)
+
+#define QG_S3_SLEEP_OCV_TREND_CTL2_REG		0x5C
+#define TREND_TOL_MASK				GENMASK(5, 0)
+
+#define QG_S3_SLEEP_OCV_IBAT_CTL1_REG		0x5D
+#define SLEEP_IBAT_QUALIFIED_LENGTH_MASK	GENMASK(2, 0)
+
+#define QG_S3_ENTRY_IBAT_THRESHOLD_REG		0x5E
+#define QG_S3_EXIT_IBAT_THRESHOLD_REG		0x5F
+
+#define QG_S7_PON_OCV_V_DATA0_REG		0x70
+#define QG_S7_PON_OCV_I_DATA0_REG		0x72
+#define QG_S3_GOOD_OCV_V_DATA0_REG		0x74
+#define QG_S3_GOOD_OCV_I_DATA0_REG		0x76
+
+#define QG_V_ACCUM_DATA0_RT_REG			0x88
+#define QG_I_ACCUM_DATA0_RT_REG			0x8B
+#define QG_ACCUM_CNT_RT_REG			0x8E
+
+#define QG_V_FIFO0_DATA0_REG			0x90
+#define QG_I_FIFO0_DATA0_REG			0xA0
+
+#define QG_SOC_MONOTONIC_REG			0xBF
+
+#define QG_LAST_ADC_V_DATA0_REG			0xC0
+#define QG_LAST_ADC_I_DATA0_REG			0xC2
+
+/* SDAM offsets */
+#define QG_SDAM_VALID_OFFSET			0x46
+#define QG_SDAM_SOC_OFFSET			0x47
+#define QG_SDAM_TEMP_OFFSET			0x48
+#define QG_SDAM_RBAT_OFFSET			0x4A
+#define QG_SDAM_OCV_OFFSET			0x4C
+#define QG_SDAM_IBAT_OFFSET			0x50
+#define QG_SDAM_TIME_OFFSET			0x54
+
+#endif
diff --git a/drivers/power/supply/qcom/qg-sdam.c b/drivers/power/supply/qcom/qg-sdam.c
new file mode 100644
index 0000000..65bebab
--- /dev/null
+++ b/drivers/power/supply/qcom/qg-sdam.c
@@ -0,0 +1,219 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)	"QG-K: %s: " fmt, __func__
+
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include "qg-sdam.h"
+#include "qg-reg.h"
+
+static struct qg_sdam *the_chip;
+
+struct qg_sdam_info {
+	char		*name;
+	u32		offset;
+	u32		length;
+};
+
+static struct qg_sdam_info sdam_info[] = {
+	[SDAM_VALID] = {
+		.name	= "VALID",
+		.offset = QG_SDAM_VALID_OFFSET,
+		.length = 1,
+	},
+	[SDAM_SOC] = {
+		.name	= "SOC",
+		.offset = QG_SDAM_SOC_OFFSET,
+		.length = 1,
+	},
+	[SDAM_TEMP] = {
+		.name	= "BATT_TEMP",
+		.offset = QG_SDAM_TEMP_OFFSET,
+		.length = 2,
+	},
+	[SDAM_RBAT_MOHM] = {
+		.name	= "RBAT_MOHM",
+		.offset = QG_SDAM_RBAT_OFFSET,
+		.length = 2,
+	},
+	[SDAM_OCV_UV] = {
+		.name	= "OCV_UV",
+		.offset = QG_SDAM_OCV_OFFSET,
+		.length = 4,
+	},
+	[SDAM_IBAT_UA] = {
+		.name	= "IBAT_UA",
+		.offset = QG_SDAM_IBAT_OFFSET,
+		.length = 4,
+	},
+	[SDAM_TIME_SEC] = {
+		.name	= "TIME_SEC",
+		.offset = QG_SDAM_TIME_OFFSET,
+		.length = 4,
+	},
+};
+
+int qg_sdam_write(u8 param, u32 data)
+{
+	int rc;
+	struct qg_sdam *chip = the_chip;
+	u32 offset;
+	size_t length;
+
+	if (!chip) {
+		pr_err("Invalid sdam-chip pointer\n");
+		return -EINVAL;
+	}
+
+	if (param >= SDAM_MAX) {
+		pr_err("Invalid SDAM param %d\n", param);
+		return -EINVAL;
+	}
+
+	offset = chip->sdam_base + sdam_info[param].offset;
+	length = sdam_info[param].length;
+	rc = regmap_bulk_write(chip->regmap, offset, (u8 *)&data, length);
+	if (rc < 0)
+		pr_err("Failed to write offset=%0x4x param=%d value=%d\n",
+					offset, param, data);
+	else
+		pr_debug("QG SDAM write param=%s value=%d\n",
+					sdam_info[param].name, data);
+
+	return rc;
+}
+
+int qg_sdam_read(u8 param, u32 *data)
+{
+	int rc;
+	struct qg_sdam *chip = the_chip;
+	u32 offset;
+	size_t length;
+
+	if (!chip) {
+		pr_err("Invalid sdam-chip pointer\n");
+		return -EINVAL;
+	}
+
+	if (param >= SDAM_MAX) {
+		pr_err("Invalid SDAM param %d\n", param);
+		return -EINVAL;
+	}
+
+	offset = chip->sdam_base + sdam_info[param].offset;
+	length = sdam_info[param].length;
+	rc = regmap_raw_read(chip->regmap, offset, (u8 *)data, length);
+	if (rc < 0)
+		pr_err("Failed to read offset=%0x4x param=%d\n",
+					offset, param);
+	else
+		pr_debug("QG SDAM read param=%s value=%d\n",
+				sdam_info[param].name, *data);
+
+	return rc;
+}
+
+int qg_sdam_read_all(u32 *sdam_data)
+{
+	int i, rc;
+	struct qg_sdam *chip = the_chip;
+
+	if (!chip) {
+		pr_err("Invalid sdam-chip pointer\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < SDAM_MAX; i++) {
+		rc = qg_sdam_read(i, &sdam_data[i]);
+		if (rc < 0) {
+			pr_err("Failed to read SDAM param=%s rc=%d\n",
+					sdam_info[i].name, rc);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+int qg_sdam_write_all(u32 *sdam_data)
+{
+	int i, rc;
+	struct qg_sdam *chip = the_chip;
+
+	if (!chip) {
+		pr_err("Invalid sdam-chip pointer\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < SDAM_MAX; i++) {
+		rc = qg_sdam_write(i, sdam_data[i]);
+		if (rc < 0) {
+			pr_err("Failed to write SDAM param=%s rc=%d\n",
+					sdam_info[i].name, rc);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+int qg_sdam_init(struct device *dev)
+{
+	int rc;
+	u32 base = 0, type = 0;
+	struct qg_sdam *chip;
+	struct device_node *child, *node = dev->of_node;
+
+	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+	if (!chip)
+		return 0;
+
+	chip->regmap = dev_get_regmap(dev->parent, NULL);
+	if (!chip->regmap) {
+		pr_err("Parent regmap is unavailable\n");
+		return -ENXIO;
+	}
+
+	/* get the SDAM base address */
+	for_each_available_child_of_node(node, child) {
+		rc = of_property_read_u32(child, "reg", &base);
+		if (rc < 0) {
+			pr_err("Failed to read base address rc=%d\n", rc);
+			return rc;
+		}
+
+		rc = regmap_read(chip->regmap, base + PERPH_TYPE_REG, &type);
+		if (rc < 0) {
+			pr_err("Failed to read type rc=%d\n", rc);
+			return rc;
+		}
+
+		switch (type) {
+		case SDAM_TYPE:
+			chip->sdam_base = base;
+			break;
+		default:
+			break;
+		}
+	}
+	if (!chip->sdam_base) {
+		pr_err("QG SDAM node not defined\n");
+		return -EINVAL;
+	}
+
+	the_chip = chip;
+
+	return 0;
+}
diff --git a/drivers/power/supply/qcom/qg-sdam.h b/drivers/power/supply/qcom/qg-sdam.h
new file mode 100644
index 0000000..a75ead9
--- /dev/null
+++ b/drivers/power/supply/qcom/qg-sdam.h
@@ -0,0 +1,40 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QG_SDAM_H__
+#define __QG_SDAM_H__
+
+#define SDAM_TYPE			0x2E
+
+enum qg_sdam_param {
+	SDAM_VALID,
+	SDAM_SOC,
+	SDAM_TEMP,
+	SDAM_RBAT_MOHM,
+	SDAM_OCV_UV,
+	SDAM_IBAT_UA,
+	SDAM_TIME_SEC,
+	SDAM_MAX,
+};
+
+struct qg_sdam {
+	struct regmap		*regmap;
+	u16			sdam_base;
+};
+
+int qg_sdam_init(struct device *dev);
+int qg_sdam_write(u8 param, u32 data);
+int qg_sdam_read(u8 param, u32 *data);
+int qg_sdam_write_all(u32 *sdam_data);
+int qg_sdam_read_all(u32 *sdam_data);
+
+#endif
diff --git a/drivers/power/supply/qcom/qg-soc.c b/drivers/power/supply/qcom/qg-soc.c
new file mode 100644
index 0000000..4fdd258
--- /dev/null
+++ b/drivers/power/supply/qcom/qg-soc.c
@@ -0,0 +1,226 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)	"QG-K: %s: " fmt, __func__
+
+#include <linux/alarmtimer.h>
+#include <linux/power_supply.h>
+#include <uapi/linux/qg.h>
+#include "qg-sdam.h"
+#include "qg-core.h"
+#include "qg-reg.h"
+#include "qg-util.h"
+#include "qg-defs.h"
+
+#define DEFAULT_UPDATE_TIME_MS			64000
+#define SOC_SCALE_HYST_MS			2000
+static void get_next_update_time(struct qpnp_qg *chip, int *time_ms)
+{
+	int rc = 0, full_time_ms = 0, rt_time_ms = 0;
+
+	*time_ms = DEFAULT_UPDATE_TIME_MS;
+
+	rc = get_fifo_done_time(chip, false, &full_time_ms);
+	if (rc < 0)
+		return;
+
+	rc = get_fifo_done_time(chip, true, &rt_time_ms);
+	if (rc < 0)
+		return;
+
+	*time_ms = full_time_ms - rt_time_ms;
+
+	if (*time_ms < 0)
+		*time_ms = 0;
+
+	qg_dbg(chip, QG_DEBUG_SOC, "SOC scale next-update-time %d secs\n",
+					*time_ms / 1000);
+}
+
+static bool is_scaling_required(struct qpnp_qg *chip)
+{
+	if ((abs(chip->catch_up_soc - chip->msoc) < chip->dt.delta_soc) &&
+		chip->catch_up_soc != 0 && chip->catch_up_soc != 100)
+		return false;
+
+	if (chip->catch_up_soc == chip->msoc)
+		/* SOC has not changed */
+		return false;
+
+
+	if (chip->catch_up_soc > chip->msoc && !is_usb_present(chip))
+		/* USB is not present and SOC has increased */
+		return false;
+
+	return true;
+}
+
+static void update_msoc(struct qpnp_qg *chip)
+{
+	int rc;
+
+	if (chip->catch_up_soc > chip->msoc) {
+		/* SOC increased */
+		if (is_usb_present(chip)) /* Increment if USB is present */
+			chip->msoc += chip->dt.delta_soc;
+	} else {
+		/* SOC dropped */
+		chip->msoc -= chip->dt.delta_soc;
+	}
+	chip->msoc = CAP(0, 100, chip->msoc);
+
+	/* update the SOC register */
+	rc = qg_write_monotonic_soc(chip, chip->msoc);
+	if (rc < 0)
+		pr_err("Failed to update MSOC register rc=%d\n", rc);
+
+	/* update SDAM with the new MSOC */
+	rc = qg_sdam_write(SDAM_SOC, chip->msoc);
+	if (rc < 0)
+		pr_err("Failed to update SDAM with MSOC rc=%d\n", rc);
+
+	qg_dbg(chip, QG_DEBUG_SOC,
+		"SOC scale: Update msoc=%d catch_up_soc=%d delta_soc=%d\n",
+		chip->msoc, chip->catch_up_soc, chip->dt.delta_soc);
+}
+
+static void scale_soc_stop(struct qpnp_qg *chip)
+{
+	chip->next_wakeup_ms = 0;
+	alarm_cancel(&chip->alarm_timer);
+
+	qg_dbg(chip, QG_DEBUG_SOC,
+			"SOC scale stopped: msoc=%d catch_up_soc=%d\n",
+			chip->msoc, chip->catch_up_soc);
+}
+
+static void scale_soc_work(struct work_struct *work)
+{
+	struct qpnp_qg *chip = container_of(work,
+			struct qpnp_qg, scale_soc_work);
+
+	mutex_lock(&chip->soc_lock);
+
+	if (!is_scaling_required(chip)) {
+		scale_soc_stop(chip);
+		goto done;
+	}
+
+	update_msoc(chip);
+
+	if (is_scaling_required(chip)) {
+		alarm_start_relative(&chip->alarm_timer,
+				ms_to_ktime(chip->next_wakeup_ms));
+	} else {
+		scale_soc_stop(chip);
+		goto done_psy;
+	}
+
+	qg_dbg(chip, QG_DEBUG_SOC,
+		"SOC scale: Work msoc=%d catch_up_soc=%d delta_soc=%d next_wakeup=%d sec\n",
+			chip->msoc, chip->catch_up_soc, chip->dt.delta_soc,
+			chip->next_wakeup_ms / 1000);
+
+done_psy:
+	power_supply_changed(chip->qg_psy);
+done:
+	pm_relax(chip->dev);
+	mutex_unlock(&chip->soc_lock);
+}
+
+static enum alarmtimer_restart
+	qpnp_msoc_timer(struct alarm *alarm, ktime_t now)
+{
+	struct qpnp_qg *chip = container_of(alarm,
+				struct qpnp_qg, alarm_timer);
+
+	/* timer callback runs in atomic context, cannot use voter */
+	pm_stay_awake(chip->dev);
+	schedule_work(&chip->scale_soc_work);
+
+	return ALARMTIMER_NORESTART;
+}
+
+int qg_scale_soc(struct qpnp_qg *chip, bool force_soc)
+{
+	int soc_points = 0;
+	int rc = 0, time_ms = 0;
+
+	mutex_lock(&chip->soc_lock);
+
+	qg_dbg(chip, QG_DEBUG_SOC,
+			"SOC scale: Start msoc=%d catch_up_soc=%d delta_soc=%d\n",
+			chip->msoc, chip->catch_up_soc, chip->dt.delta_soc);
+
+	if (force_soc) {
+		chip->msoc = chip->catch_up_soc;
+		rc = qg_write_monotonic_soc(chip, chip->msoc);
+		if (rc < 0)
+			pr_err("Failed to update MSOC register rc=%d\n", rc);
+
+		qg_dbg(chip, QG_DEBUG_SOC,
+			"SOC scale: Forced msoc=%d\n", chip->msoc);
+		goto done_psy;
+	}
+
+	if (!is_scaling_required(chip)) {
+		scale_soc_stop(chip);
+		goto done;
+	}
+
+	update_msoc(chip);
+
+	if (is_scaling_required(chip)) {
+		get_next_update_time(chip, &time_ms);
+		soc_points = abs(chip->msoc - chip->catch_up_soc)
+					/ chip->dt.delta_soc;
+		chip->next_wakeup_ms = (time_ms / (soc_points + 1))
+					- SOC_SCALE_HYST_MS;
+		if (chip->next_wakeup_ms < 0)
+			chip->next_wakeup_ms = 1; /* wake up immediately */
+		alarm_start_relative(&chip->alarm_timer,
+					ms_to_ktime(chip->next_wakeup_ms));
+	} else {
+		scale_soc_stop(chip);
+		goto done_psy;
+	}
+
+	qg_dbg(chip, QG_DEBUG_SOC,
+		"SOC scale: msoc=%d catch_up_soc=%d delta_soc=%d soc_points=%d next_wakeup=%d sec\n",
+			chip->msoc, chip->catch_up_soc,	chip->dt.delta_soc,
+			soc_points, chip->next_wakeup_ms / 1000);
+
+done_psy:
+	power_supply_changed(chip->qg_psy);
+done:
+	mutex_unlock(&chip->soc_lock);
+	return rc;
+}
+
+int qg_soc_init(struct qpnp_qg *chip)
+{
+	if (alarmtimer_get_rtcdev()) {
+		alarm_init(&chip->alarm_timer, ALARM_BOOTTIME,
+			qpnp_msoc_timer);
+	} else {
+		pr_err("Failed to get soc alarm-timer\n");
+		return -EINVAL;
+	}
+	INIT_WORK(&chip->scale_soc_work, scale_soc_work);
+
+	return 0;
+}
+
+void qg_soc_exit(struct qpnp_qg *chip)
+{
+	alarm_cancel(&chip->alarm_timer);
+}
diff --git a/drivers/power/supply/qcom/qg-soc.h b/drivers/power/supply/qcom/qg-soc.h
new file mode 100644
index 0000000..3b4eb60
--- /dev/null
+++ b/drivers/power/supply/qcom/qg-soc.h
@@ -0,0 +1,20 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QG_SOC_H__
+#define __QG_SOC_H__
+
+int qg_scale_soc(struct qpnp_qg *chip, bool force_soc);
+int qg_soc_init(struct qpnp_qg *chip);
+void qg_soc_exit(struct qpnp_qg *chip);
+
+#endif /* __QG_SOC_H__ */
diff --git a/drivers/power/supply/qcom/qg-util.c b/drivers/power/supply/qcom/qg-util.c
new file mode 100644
index 0000000..44e5048
--- /dev/null
+++ b/drivers/power/supply/qcom/qg-util.c
@@ -0,0 +1,291 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/alarmtimer.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+#include <uapi/linux/qg.h>
+#include "qg-sdam.h"
+#include "qg-core.h"
+#include "qg-reg.h"
+#include "qg-defs.h"
+
+static inline bool is_sticky_register(u32 addr)
+{
+	if ((addr & 0xFF) == QG_STATUS2_REG)
+		return true;
+
+	return false;
+}
+
+int qg_read(struct qpnp_qg *chip, u32 addr, u8 *val, int len)
+{
+	int rc, i;
+	u32 dummy = 0;
+
+	if (is_sticky_register(addr)) {
+		rc = regmap_write(chip->regmap, addr, dummy);
+		if (rc < 0) {
+			pr_err("Failed regmap_write for %04x rc=%d\n",
+						addr, rc);
+			return rc;
+		}
+	}
+
+	rc = regmap_bulk_read(chip->regmap, addr, val, len);
+	if (rc < 0) {
+		pr_err("Failed regmap_read for address %04x rc=%d\n", addr, rc);
+		return rc;
+	}
+
+	if (*chip->debug_mask & QG_DEBUG_BUS_READ) {
+		pr_info("length %d addr=%04x\n", len, addr);
+		for (i = 0; i < len; i++)
+			pr_info("val[%d]: %02x\n", i, val[i]);
+	}
+
+	return 0;
+}
+
+int qg_write(struct qpnp_qg *chip, u32 addr, u8 *val, int len)
+{
+	int rc, i;
+
+	mutex_lock(&chip->bus_lock);
+
+	if (len > 1)
+		rc = regmap_bulk_write(chip->regmap, addr, val, len);
+	else
+		rc = regmap_write(chip->regmap, addr, *val);
+
+	if (rc < 0) {
+		pr_err("Failed regmap_write for address %04x rc=%d\n",
+				addr, rc);
+		goto out;
+	}
+
+	if (*chip->debug_mask & QG_DEBUG_BUS_WRITE) {
+		pr_info("length %d addr=%04x\n", len, addr);
+		for (i = 0; i < len; i++)
+			pr_info("val[%d]: %02x\n", i, val[i]);
+	}
+out:
+	mutex_unlock(&chip->bus_lock);
+	return rc;
+}
+
+int qg_masked_write(struct qpnp_qg *chip, int addr, u32 mask, u32 val)
+{
+	int rc;
+
+	mutex_lock(&chip->bus_lock);
+
+	rc = regmap_update_bits(chip->regmap, addr, mask, val);
+	if (rc < 0) {
+		pr_err("Failed regmap_update_bits for address %04x rc=%d\n",
+				addr, rc);
+		goto out;
+	}
+
+	if (*chip->debug_mask & QG_DEBUG_BUS_WRITE)
+		pr_info("addr=%04x mask: %02x val: %02x\n", addr, mask, val);
+
+out:
+	mutex_unlock(&chip->bus_lock);
+	return rc;
+}
+
+int get_fifo_length(struct qpnp_qg *chip, u32 *fifo_length, bool rt)
+{
+	int rc;
+	u8 reg = 0;
+	u32 addr;
+
+	addr = rt ? QG_STATUS3_REG : QG_S2_NORMAL_MEAS_CTL2_REG;
+	rc = qg_read(chip, chip->qg_base + addr, &reg, 1);
+	if (rc < 0) {
+		pr_err("Failed to read FIFO length rc=%d\n", rc);
+		return rc;
+	}
+
+	if (rt) {
+		*fifo_length &= COUNT_FIFO_RT_MASK;
+	} else {
+		*fifo_length = (reg & FIFO_LENGTH_MASK) >> FIFO_LENGTH_SHIFT;
+		*fifo_length += 1;
+	}
+
+	return rc;
+}
+
+int get_sample_count(struct qpnp_qg *chip, u32 *sample_count)
+{
+	int rc;
+	u8 reg = 0;
+
+	rc = qg_read(chip, chip->qg_base + QG_S2_NORMAL_MEAS_CTL2_REG,
+					&reg, 1);
+	if (rc < 0) {
+		pr_err("Failed to read FIFO sample count rc=%d\n", rc);
+		return rc;
+	}
+
+	*sample_count = 1 << ((reg & NUM_OF_ACCUM_MASK) + 1);
+
+	return rc;
+}
+
+int get_sample_interval(struct qpnp_qg *chip, u32 *sample_interval)
+{
+	int rc;
+	u8 reg = 0;
+
+	rc = qg_read(chip, chip->qg_base + QG_S2_NORMAL_MEAS_CTL3_REG,
+					&reg, 1);
+	if (rc < 0) {
+		pr_err("Failed to read FIFO sample interval rc=%d\n", rc);
+		return rc;
+	}
+
+	*sample_interval = reg * 10;
+
+	return rc;
+}
+
+int get_rtc_time(unsigned long *rtc_time)
+{
+	struct rtc_time tm;
+	struct rtc_device *rtc;
+	int rc;
+
+	rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+	if (rtc == NULL) {
+		pr_err("Failed to open rtc device (%s)\n",
+				CONFIG_RTC_HCTOSYS_DEVICE);
+		return -EINVAL;
+	}
+
+	rc = rtc_read_time(rtc, &tm);
+	if (rc) {
+		pr_err("Failed to read rtc time (%s) : %d\n",
+				CONFIG_RTC_HCTOSYS_DEVICE, rc);
+		goto close_time;
+	}
+
+	rc = rtc_valid_tm(&tm);
+	if (rc) {
+		pr_err("Invalid RTC time (%s): %d\n",
+				CONFIG_RTC_HCTOSYS_DEVICE, rc);
+		goto close_time;
+	}
+	rtc_tm_to_time(&tm, rtc_time);
+
+close_time:
+	rtc_class_close(rtc);
+	return rc;
+}
+
+int get_fifo_done_time(struct qpnp_qg *chip, bool rt, int *time_ms)
+{
+	int rc, length = 0;
+	u32 sample_count = 0, sample_interval = 0, acc_count = 0;
+
+	rc = get_fifo_length(chip, &length, rt ? true : false);
+	if (rc < 0)
+		return rc;
+
+	rc = get_sample_count(chip, &sample_count);
+	if (rc < 0)
+		return rc;
+
+	rc = get_sample_interval(chip, &sample_interval);
+	if (rc < 0)
+		return rc;
+
+	*time_ms = length * sample_count * sample_interval;
+
+	if (rt) {
+		rc = qg_read(chip, chip->qg_base + QG_ACCUM_CNT_RT_REG,
+					(u8 *)&acc_count, 1);
+		if (rc < 0)
+			return rc;
+
+		*time_ms += ((sample_count - acc_count) * sample_interval);
+	}
+
+	return 0;
+}
+
+static bool is_usb_available(struct qpnp_qg *chip)
+{
+	if (chip->usb_psy)
+		return true;
+
+	chip->usb_psy = power_supply_get_by_name("usb");
+	if (!chip->usb_psy)
+		return false;
+
+	return true;
+}
+
+bool is_usb_present(struct qpnp_qg *chip)
+{
+	union power_supply_propval pval = {0, };
+
+	if (is_usb_available(chip))
+		power_supply_get_property(chip->usb_psy,
+			POWER_SUPPLY_PROP_PRESENT, &pval);
+
+	return pval.intval ? true : false;
+}
+
+static bool is_parallel_available(struct qpnp_qg *chip)
+{
+	if (chip->parallel_psy)
+		return true;
+
+	chip->parallel_psy = power_supply_get_by_name("parallel");
+	if (!chip->parallel_psy)
+		return false;
+
+	return true;
+}
+
+bool is_parallel_enabled(struct qpnp_qg *chip)
+{
+	union power_supply_propval pval = {0, };
+
+	if (is_parallel_available(chip)) {
+		power_supply_get_property(chip->parallel_psy,
+			POWER_SUPPLY_PROP_CHARGING_ENABLED, &pval);
+	}
+
+	return pval.intval ? true : false;
+}
+
+int qg_write_monotonic_soc(struct qpnp_qg *chip, int msoc)
+{
+	u8 reg = 0;
+	int rc;
+
+	reg = (msoc * 255) / 100;
+	rc = qg_write(chip, chip->qg_base + QG_SOC_MONOTONIC_REG,
+				&reg, 1);
+	if (rc < 0)
+		pr_err("Failed to update QG_SOC_MONOTINIC reg rc=%d\n", rc);
+
+	return rc;
+}
diff --git a/drivers/power/supply/qcom/qg-util.h b/drivers/power/supply/qcom/qg-util.h
new file mode 100644
index 0000000..a3664e1
--- /dev/null
+++ b/drivers/power/supply/qcom/qg-util.h
@@ -0,0 +1,27 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __QG_UTIL_H__
+#define __QG_UTIL_H__
+
+int qg_read(struct qpnp_qg *chip, u32 addr, u8 *val, int len);
+int qg_write(struct qpnp_qg *chip, u32 addr, u8 *val, int len);
+int qg_masked_write(struct qpnp_qg *chip, int addr, u32 mask, u32 val);
+int get_fifo_length(struct qpnp_qg *chip, u32 *fifo_length, bool rt);
+int get_sample_count(struct qpnp_qg *chip, u32 *sample_count);
+int get_sample_interval(struct qpnp_qg *chip, u32 *sample_interval);
+int get_fifo_done_time(struct qpnp_qg *chip, bool rt, int *time_ms);
+int get_rtc_time(unsigned long *rtc_time);
+bool is_usb_present(struct qpnp_qg *chip);
+bool is_parallel_enabled(struct qpnp_qg *chip);
+int qg_write_monotonic_soc(struct qpnp_qg *chip, int msoc);
+
+#endif
diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c
new file mode 100644
index 0000000..55cb5ef
--- /dev/null
+++ b/drivers/power/supply/qcom/qpnp-qg.c
@@ -0,0 +1,2376 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)	"QG-K: %s: " fmt, __func__
+
+#include <linux/alarmtimer.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/ktime.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_batterydata.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+#include <linux/uaccess.h>
+#include <linux/pmic-voter.h>
+#include <linux/qpnp/qpnp-adc.h>
+#include <uapi/linux/qg.h>
+#include "qg-sdam.h"
+#include "qg-core.h"
+#include "qg-reg.h"
+#include "qg-util.h"
+#include "qg-soc.h"
+#include "qg-battery-profile.h"
+#include "qg-defs.h"
+
+static int qg_debug_mask;
+module_param_named(
+	debug_mask, qg_debug_mask, int, 0600
+);
+
+static int qg_get_battery_temp(struct qpnp_qg *chip, int *batt_temp);
+
+static bool is_battery_present(struct qpnp_qg *chip)
+{
+	u8 reg = 0;
+	int rc;
+
+	rc = qg_read(chip, chip->qg_base + QG_STATUS1_REG, &reg, 1);
+	if (rc < 0)
+		pr_err("Failed to read battery presence, rc=%d\n", rc);
+
+	return !!(reg & BATTERY_PRESENT_BIT);
+}
+
+#define DEBUG_BATT_ID_LOW	6000
+#define DEBUG_BATT_ID_HIGH	8500
+static bool is_debug_batt_id(struct qpnp_qg *chip)
+{
+	if (is_between(DEBUG_BATT_ID_LOW, DEBUG_BATT_ID_HIGH,
+					chip->batt_id_ohm))
+		return true;
+
+	return false;
+}
+
+static int qg_read_ocv(struct qpnp_qg *chip, u32 *ocv_uv, u8 type)
+{
+	int rc, addr;
+	u64 temp = 0;
+
+	switch (type) {
+	case GOOD_OCV:
+		addr = QG_S3_GOOD_OCV_V_DATA0_REG;
+		break;
+	case PON_OCV:
+		addr = QG_S7_PON_OCV_V_DATA0_REG;
+		break;
+	default:
+		pr_err("Invalid OCV type %d\n", type);
+		return -EINVAL;
+	}
+
+	rc = qg_read(chip, chip->qg_base + addr, (u8 *)&temp, 2);
+	if (rc < 0) {
+		pr_err("Failed to read ocv, rc=%d\n", rc);
+		return rc;
+	}
+
+	*ocv_uv = V_RAW_TO_UV(temp);
+
+	pr_debug("%s: OCV=%duV\n",
+		type == GOOD_OCV ? "GOOD_OCV" : "PON_OCV", *ocv_uv);
+
+	return rc;
+}
+
+static int qg_update_fifo_length(struct qpnp_qg *chip, u8 length)
+{
+	int rc;
+
+	if (!length || length > 8) {
+		pr_err("Invalid FIFO length %d\n", length);
+		return -EINVAL;
+	}
+
+	rc = qg_masked_write(chip, chip->qg_base + QG_S2_NORMAL_MEAS_CTL2_REG,
+			FIFO_LENGTH_MASK, (length - 1) << FIFO_LENGTH_SHIFT);
+	if (rc < 0)
+		pr_err("Failed to write S2 FIFO length, rc=%d\n", rc);
+
+	return rc;
+}
+
+static int qg_master_hold(struct qpnp_qg *chip, bool hold)
+{
+	int rc;
+
+	/* clear the master */
+	rc = qg_masked_write(chip, chip->qg_base + QG_DATA_CTL1_REG,
+					MASTER_HOLD_OR_CLR_BIT, 0);
+	if (rc < 0)
+		return rc;
+
+	if (hold) {
+		/* 0 -> 1, hold the master */
+		rc = qg_masked_write(chip, chip->qg_base + QG_DATA_CTL1_REG,
+					MASTER_HOLD_OR_CLR_BIT,
+					MASTER_HOLD_OR_CLR_BIT);
+		if (rc < 0)
+			return rc;
+	}
+
+	qg_dbg(chip, QG_DEBUG_STATUS, "Master hold = %d\n", hold);
+
+	return rc;
+}
+
+static void qg_notify_charger(struct qpnp_qg *chip)
+{
+	union power_supply_propval prop = {0, };
+	int rc;
+
+	if (!chip->batt_psy)
+		return;
+
+	if (is_debug_batt_id(chip)) {
+		prop.intval = 1;
+		power_supply_set_property(chip->batt_psy,
+			POWER_SUPPLY_PROP_DEBUG_BATTERY, &prop);
+		return;
+	}
+
+	if (!chip->profile_loaded)
+		return;
+
+	prop.intval = chip->bp.float_volt_uv;
+	rc = power_supply_set_property(chip->batt_psy,
+			POWER_SUPPLY_PROP_VOLTAGE_MAX, &prop);
+	if (rc < 0) {
+		pr_err("Failed to set voltage_max property on batt_psy, rc=%d\n",
+			rc);
+		return;
+	}
+
+	prop.intval = chip->bp.fastchg_curr_ma * 1000;
+	rc = power_supply_set_property(chip->batt_psy,
+			POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &prop);
+	if (rc < 0) {
+		pr_err("Failed to set constant_charge_current_max property on batt_psy, rc=%d\n",
+			rc);
+		return;
+	}
+
+	pr_debug("Notified charger on float voltage and FCC\n");
+}
+
+static bool is_batt_available(struct qpnp_qg *chip)
+{
+	if (chip->batt_psy)
+		return true;
+
+	chip->batt_psy = power_supply_get_by_name("battery");
+	if (!chip->batt_psy)
+		return false;
+
+	/* batt_psy is initialized, set the fcc and fv */
+	qg_notify_charger(chip);
+
+	return true;
+}
+
+static int qg_update_sdam_params(struct qpnp_qg *chip)
+{
+	int rc, batt_temp = 0, i;
+	unsigned long rtc_sec = 0;
+
+	rc = get_rtc_time(&rtc_sec);
+	if (rc < 0)
+		pr_err("Failed to get RTC time, rc=%d\n", rc);
+	else
+		chip->sdam_data[SDAM_TIME_SEC] = rtc_sec;
+
+	rc = qg_get_battery_temp(chip, &batt_temp);
+	if (rc < 0)
+		pr_err("Failed to get battery-temp, rc = %d\n", rc);
+	else
+		chip->sdam_data[SDAM_TEMP] = (u32)batt_temp;
+
+	rc = qg_sdam_write_all(chip->sdam_data);
+	if (rc < 0)
+		pr_err("Failed to write to SDAM rc=%d\n", rc);
+
+	for (i = 0; i < SDAM_MAX; i++)
+		qg_dbg(chip, QG_DEBUG_STATUS, "SDAM write param %d value=%d\n",
+					i, chip->sdam_data[i]);
+
+	return rc;
+}
+
+static int qg_process_fifo(struct qpnp_qg *chip, u32 fifo_length)
+{
+	int rc = 0, i, j = 0, temp;
+	u8 v_fifo[MAX_FIFO_LENGTH * 2], i_fifo[MAX_FIFO_LENGTH * 2];
+	u32 sample_interval = 0, sample_count = 0, fifo_v = 0, fifo_i = 0;
+
+	if (!fifo_length) {
+		pr_debug("No FIFO data\n");
+		return 0;
+	}
+
+	qg_dbg(chip, QG_DEBUG_FIFO, "FIFO length=%d\n", fifo_length);
+
+	rc = get_sample_interval(chip, &sample_interval);
+	if (rc < 0) {
+		pr_err("Failed to get FIFO sample interval, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = get_sample_count(chip, &sample_count);
+	if (rc < 0) {
+		pr_err("Failed to get FIFO sample count, rc=%d\n", rc);
+		return rc;
+	}
+
+	for (i = 0; i < fifo_length * 2; i = i + 2, j++) {
+		rc = qg_read(chip, chip->qg_base + QG_V_FIFO0_DATA0_REG + i,
+					&v_fifo[i], 2);
+		if (rc < 0) {
+			pr_err("Failed to read QG_V_FIFO, rc=%d\n", rc);
+			return rc;
+		}
+		rc = qg_read(chip, chip->qg_base + QG_I_FIFO0_DATA0_REG + i,
+					&i_fifo[i], 2);
+		if (rc < 0) {
+			pr_err("Failed to read QG_I_FIFO, rc=%d\n", rc);
+			return rc;
+		}
+
+		fifo_v = v_fifo[i] | (v_fifo[i + 1] << 8);
+		fifo_i = i_fifo[i] | (i_fifo[i + 1] << 8);
+
+		temp = sign_extend32(fifo_i, 15);
+
+		chip->kdata.fifo[j].v = V_RAW_TO_UV(fifo_v);
+		chip->kdata.fifo[j].i = I_RAW_TO_UA(temp);
+		chip->kdata.fifo[j].interval = sample_interval;
+		chip->kdata.fifo[j].count = sample_count;
+
+		qg_dbg(chip, QG_DEBUG_FIFO, "FIFO %d raw_v=%d uV=%d raw_i=%d uA=%d interval=%d count=%d\n",
+					j, fifo_v,
+					chip->kdata.fifo[j].v,
+					fifo_i,
+					(int)chip->kdata.fifo[j].i,
+					chip->kdata.fifo[j].interval,
+					chip->kdata.fifo[j].count);
+	}
+
+	chip->kdata.fifo_length = fifo_length;
+
+	return rc;
+}
+
+static int qg_process_accumulator(struct qpnp_qg *chip)
+{
+	int rc, sample_interval = 0;
+	u8 count, index = chip->kdata.fifo_length;
+	u64 acc_v = 0, acc_i = 0;
+	s64 temp = 0;
+
+	rc = qg_read(chip, chip->qg_base + QG_ACCUM_CNT_RT_REG,
+			&count, 1);
+	if (rc < 0) {
+		pr_err("Failed to read ACC count, rc=%d\n", rc);
+		return rc;
+	}
+
+	if (!count) {
+		pr_debug("No ACCUMULATOR data!\n");
+		return 0;
+	}
+
+	rc = get_sample_interval(chip, &sample_interval);
+	if (rc < 0) {
+		pr_err("Failed to get ACC sample interval, rc=%d\n", rc);
+		return 0;
+	}
+
+	rc = qg_read(chip, chip->qg_base + QG_V_ACCUM_DATA0_RT_REG,
+			(u8 *)&acc_v, 3);
+	if (rc < 0) {
+		pr_err("Failed to read ACC RT V data, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qg_read(chip, chip->qg_base + QG_I_ACCUM_DATA0_RT_REG,
+			(u8 *)&acc_i, 3);
+	if (rc < 0) {
+		pr_err("Failed to read ACC RT I data, rc=%d\n", rc);
+		return rc;
+	}
+
+	temp = sign_extend64(acc_i, 23);
+
+	chip->kdata.fifo[index].v = V_RAW_TO_UV(div_u64(acc_v, count));
+	chip->kdata.fifo[index].i = I_RAW_TO_UA(div_s64(temp, count));
+	chip->kdata.fifo[index].interval = sample_interval;
+	chip->kdata.fifo[index].count = count;
+	chip->kdata.fifo_length++;
+
+	qg_dbg(chip, QG_DEBUG_FIFO, "ACC v_avg=%duV i_avg=%duA interval=%d count=%d\n",
+			chip->kdata.fifo[index].v,
+			(int)chip->kdata.fifo[index].i,
+			chip->kdata.fifo[index].interval,
+			chip->kdata.fifo[index].count);
+
+	return rc;
+}
+
+static int qg_process_rt_fifo(struct qpnp_qg *chip)
+{
+	int rc;
+	u32 fifo_length = 0;
+
+	/* Get the real-time FIFO length */
+	rc = get_fifo_length(chip, &fifo_length, true);
+	if (rc < 0) {
+		pr_err("Failed to read RT FIFO length, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qg_process_fifo(chip, fifo_length);
+	if (rc < 0) {
+		pr_err("Failed to process FIFO data, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qg_process_accumulator(chip);
+	if (rc < 0) {
+		pr_err("Failed to process ACC data, rc=%d\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+#define VBAT_LOW_HYST_UV		50000 /* 50mV */
+static int qg_vbat_low_wa(struct qpnp_qg *chip)
+{
+	int rc, i;
+	u32 vbat_low_uv = chip->dt.vbatt_low_mv * 1000 + VBAT_LOW_HYST_UV;
+
+	if (!(chip->wa_flags & QG_VBAT_LOW_WA) || !chip->vbat_low)
+		return 0;
+
+	/*
+	 * PMI632 1.0 does not generate a falling VBAT_LOW IRQ.
+	 * To exit from VBAT_LOW config, check if any of the FIFO
+	 * averages is > vbat_low threshold and reconfigure the
+	 * FIFO length to normal.
+	 */
+	for (i = 0; i < chip->kdata.fifo_length; i++) {
+		if (chip->kdata.fifo[i].v > vbat_low_uv) {
+			rc = qg_master_hold(chip, true);
+			if (rc < 0) {
+				pr_err("Failed to hold master, rc=%d\n", rc);
+				goto done;
+			}
+			rc = qg_update_fifo_length(chip,
+					chip->dt.s2_fifo_length);
+			if (rc < 0)
+				goto done;
+
+			rc = qg_master_hold(chip, false);
+			if (rc < 0) {
+				pr_err("Failed to release master, rc=%d\n", rc);
+				goto done;
+			}
+			/* FIFOs restarted */
+			chip->last_fifo_update_time = ktime_get();
+
+			chip->vbat_low = false;
+			pr_info("Exit VBAT_LOW vbat_avg=%duV vbat_low=%duV updated fifo_length=%d\n",
+					chip->kdata.fifo[i].v, vbat_low_uv,
+					chip->dt.s2_fifo_length);
+			break;
+		}
+	}
+
+	return 0;
+
+done:
+	qg_master_hold(chip, false);
+	return rc;
+}
+
+#define MIN_FIFO_FULL_TIME_MS			12000
+static int process_rt_fifo_data(struct qpnp_qg *chip,
+				bool vbat_low, bool update_smb)
+{
+	int rc = 0;
+	ktime_t now = ktime_get();
+	s64 time_delta;
+
+	/*
+	 * Reject the FIFO read event if there are back-to-back requests
+	 * This is done to gaurantee that there is always a minimum FIFO
+	 * data to be processed, ignore this if vbat_low is set.
+	 */
+	time_delta = ktime_ms_delta(now, chip->last_user_update_time);
+
+	qg_dbg(chip, QG_DEBUG_FIFO, "time_delta=%lld ms vbat_low=%d\n",
+				time_delta, vbat_low);
+
+	if (time_delta > MIN_FIFO_FULL_TIME_MS || vbat_low || update_smb) {
+		rc = qg_master_hold(chip, true);
+		if (rc < 0) {
+			pr_err("Failed to hold master, rc=%d\n", rc);
+			goto done;
+		}
+
+		rc = qg_process_rt_fifo(chip);
+		if (rc < 0) {
+			pr_err("Failed to process FIFO real-time, rc=%d\n", rc);
+			goto done;
+		}
+
+		if (vbat_low) {
+			/* change FIFO length */
+			rc = qg_update_fifo_length(chip,
+					chip->dt.s2_vbat_low_fifo_length);
+			if (rc < 0)
+				goto done;
+
+			qg_dbg(chip, QG_DEBUG_STATUS,
+				"FIFO length updated to %d vbat_low=%d\n",
+					chip->dt.s2_vbat_low_fifo_length,
+					vbat_low);
+		}
+
+		if (update_smb) {
+			rc = qg_masked_write(chip, chip->qg_base +
+				QG_MODE_CTL1_REG, PARALLEL_IBAT_SENSE_EN_BIT,
+				chip->parallel_enabled ?
+					PARALLEL_IBAT_SENSE_EN_BIT : 0);
+			if (rc < 0) {
+				pr_err("Failed to update SMB_EN, rc=%d\n", rc);
+				goto done;
+			}
+			qg_dbg(chip, QG_DEBUG_STATUS, "Parallel SENSE %d\n",
+						chip->parallel_enabled);
+		}
+
+		rc = qg_master_hold(chip, false);
+		if (rc < 0) {
+			pr_err("Failed to release master, rc=%d\n", rc);
+			goto done;
+		}
+		/* FIFOs restarted */
+		chip->last_fifo_update_time = ktime_get();
+
+		/* signal the read thread */
+		chip->data_ready = true;
+		wake_up_interruptible(&chip->qg_wait_q);
+		chip->last_user_update_time = now;
+
+		/* vote to stay awake until userspace reads data */
+		vote(chip->awake_votable, FIFO_RT_DONE_VOTER, true, 0);
+	} else {
+		qg_dbg(chip, QG_DEBUG_FIFO, "FIFO processing too early time_delta=%lld\n",
+							time_delta);
+	}
+done:
+	qg_master_hold(chip, false);
+	return rc;
+}
+
+static void process_udata_work(struct work_struct *work)
+{
+	struct qpnp_qg *chip = container_of(work,
+			struct qpnp_qg, udata_work);
+	int rc;
+
+	if (chip->udata.param[QG_SOC].valid) {
+		qg_dbg(chip, QG_DEBUG_SOC, "udata SOC=%d last SOC=%d\n",
+			chip->udata.param[QG_SOC].data, chip->catch_up_soc);
+
+		/* Only scale if SOC has changed */
+		if (chip->catch_up_soc != chip->udata.param[QG_SOC].data) {
+			chip->catch_up_soc = chip->udata.param[QG_SOC].data;
+			qg_scale_soc(chip, false);
+		}
+
+		/* update parameters to SDAM */
+		chip->sdam_data[SDAM_SOC] =
+				chip->udata.param[QG_SOC].data;
+		chip->sdam_data[SDAM_OCV_UV] =
+				chip->udata.param[QG_OCV_UV].data;
+		chip->sdam_data[SDAM_RBAT_MOHM] =
+				chip->udata.param[QG_RBAT_MOHM].data;
+		chip->sdam_data[SDAM_VALID] = 1;
+
+		rc = qg_update_sdam_params(chip);
+		if (rc < 0)
+			pr_err("Failed to update SDAM params, rc=%d\n", rc);
+	}
+
+	vote(chip->awake_votable, UDATA_READY_VOTER, false, 0);
+}
+
+static irqreturn_t qg_default_irq_handler(int irq, void *data)
+{
+	struct qpnp_qg *chip = data;
+
+	qg_dbg(chip, QG_DEBUG_IRQ, "IRQ triggered\n");
+
+	return IRQ_HANDLED;
+}
+
+#define MAX_FIFO_DELTA_PERCENT		10
+static irqreturn_t qg_fifo_update_done_handler(int irq, void *data)
+{
+	ktime_t now = ktime_get();
+	int rc, hw_delta_ms = 0, margin_ms = 0;
+	u32 fifo_length = 0;
+	s64 time_delta_ms = 0;
+	struct qpnp_qg *chip = data;
+
+	time_delta_ms = ktime_ms_delta(now, chip->last_fifo_update_time);
+	chip->last_fifo_update_time = now;
+
+	qg_dbg(chip, QG_DEBUG_IRQ, "IRQ triggered\n");
+	mutex_lock(&chip->data_lock);
+
+	rc = get_fifo_length(chip, &fifo_length, false);
+	if (rc < 0) {
+		pr_err("Failed to get FIFO length, rc=%d\n", rc);
+		goto done;
+	}
+
+	rc = qg_process_fifo(chip, fifo_length);
+	if (rc < 0) {
+		pr_err("Failed to process QG FIFO, rc=%d\n", rc);
+		goto done;
+	}
+
+	rc = qg_vbat_low_wa(chip);
+	if (rc < 0) {
+		pr_err("Failed to apply VBAT LOW WA, rc=%d\n", rc);
+		goto done;
+	}
+
+	rc = get_fifo_done_time(chip, false, &hw_delta_ms);
+	if (rc < 0)
+		hw_delta_ms = 0;
+	else
+		margin_ms = (hw_delta_ms * MAX_FIFO_DELTA_PERCENT) / 100;
+
+	if (abs(hw_delta_ms - time_delta_ms) < margin_ms) {
+		chip->kdata.param[QG_FIFO_TIME_DELTA].data = time_delta_ms;
+		chip->kdata.param[QG_FIFO_TIME_DELTA].valid = true;
+		qg_dbg(chip, QG_DEBUG_FIFO, "FIFO_done time_delta_ms=%lld\n",
+							time_delta_ms);
+	}
+
+	/* signal the read thread */
+	chip->data_ready = true;
+	wake_up_interruptible(&chip->qg_wait_q);
+
+	/* vote to stay awake until userspace reads data */
+	vote(chip->awake_votable, FIFO_DONE_VOTER, true, 0);
+
+done:
+	mutex_unlock(&chip->data_lock);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t qg_vbat_low_handler(int irq, void *data)
+{
+	int rc;
+	struct qpnp_qg *chip = data;
+	u8 status = 0;
+
+	qg_dbg(chip, QG_DEBUG_IRQ, "IRQ triggered\n");
+	mutex_lock(&chip->data_lock);
+
+	rc = qg_read(chip, chip->qg_base + QG_INT_RT_STS_REG, &status, 1);
+	if (rc < 0) {
+		pr_err("Failed to read RT status, rc=%d\n", rc);
+		goto done;
+	}
+	chip->vbat_low = !!(status & VBAT_LOW_INT_RT_STS_BIT);
+
+	rc = process_rt_fifo_data(chip, chip->vbat_low, false);
+	if (rc < 0)
+		pr_err("Failed to process RT FIFO data, rc=%d\n", rc);
+
+	qg_dbg(chip, QG_DEBUG_IRQ, "VBAT_LOW = %d\n", chip->vbat_low);
+done:
+	mutex_unlock(&chip->data_lock);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t qg_vbat_empty_handler(int irq, void *data)
+{
+	struct qpnp_qg *chip = data;
+	u32 ocv_uv = 0;
+
+	qg_dbg(chip, QG_DEBUG_IRQ, "IRQ triggered\n");
+	pr_warn("VBATT EMPTY SOC = 0\n");
+
+	chip->catch_up_soc = 0;
+	qg_scale_soc(chip, true);
+
+	qg_sdam_read(SDAM_OCV_UV, &ocv_uv);
+	chip->sdam_data[SDAM_SOC] = 0;
+	chip->sdam_data[SDAM_OCV_UV] = ocv_uv;
+	chip->sdam_data[SDAM_VALID] = 1;
+
+	qg_update_sdam_params(chip);
+
+	if (chip->qg_psy)
+		power_supply_changed(chip->qg_psy);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t qg_good_ocv_handler(int irq, void *data)
+{
+	int rc;
+	u32 ocv_uv;
+	struct qpnp_qg *chip = data;
+
+	qg_dbg(chip, QG_DEBUG_IRQ, "IRQ triggered\n");
+
+	mutex_lock(&chip->data_lock);
+
+	rc = qg_read_ocv(chip, &ocv_uv, GOOD_OCV);
+	if (rc < 0) {
+		pr_err("Failed to read good_ocv, rc=%d\n", rc);
+		goto done;
+	}
+
+	chip->kdata.param[QG_GOOD_OCV_UV].data = ocv_uv;
+	chip->kdata.param[QG_GOOD_OCV_UV].valid = true;
+
+	vote(chip->awake_votable, GOOD_OCV_VOTER, true, 0);
+
+	/* signal the readd thread */
+	chip->data_ready = true;
+	wake_up_interruptible(&chip->qg_wait_q);
+done:
+	mutex_unlock(&chip->data_lock);
+	return IRQ_HANDLED;
+}
+
+static struct qg_irq_info qg_irqs[] = {
+	[QG_BATT_MISSING_IRQ] = {
+		.name		= "qg-batt-missing",
+		.handler	= qg_default_irq_handler,
+	},
+	[QG_VBATT_LOW_IRQ] = {
+		.name		= "qg-vbat-low",
+		.handler	= qg_vbat_low_handler,
+		.wake		= true,
+	},
+	[QG_VBATT_EMPTY_IRQ] = {
+		.name		= "qg-vbat-empty",
+		.handler	= qg_vbat_empty_handler,
+		.wake		= true,
+	},
+	[QG_FIFO_UPDATE_DONE_IRQ] = {
+		.name		= "qg-fifo-done",
+		.handler	= qg_fifo_update_done_handler,
+		.wake		= true,
+	},
+	[QG_GOOD_OCV_IRQ] = {
+		.name		= "qg-good-ocv",
+		.handler	= qg_good_ocv_handler,
+		.wake		= true,
+	},
+	[QG_FSM_STAT_CHG_IRQ] = {
+		.name		= "qg-fsm-state-chg",
+		.handler	= qg_default_irq_handler,
+	},
+	[QG_EVENT_IRQ] = {
+		.name		= "qg-event",
+		.handler	= qg_default_irq_handler,
+	},
+};
+
+static int qg_awake_cb(struct votable *votable, void *data, int awake,
+			const char *client)
+{
+	struct qpnp_qg *chip = data;
+
+	if (awake)
+		pm_stay_awake(chip->dev);
+	else
+		pm_relax(chip->dev);
+
+	pr_debug("client: %s awake: %d\n", client, awake);
+	return 0;
+}
+
+static int qg_fifo_irq_disable_cb(struct votable *votable, void *data,
+				int disable, const char *client)
+{
+	if (disable) {
+		if (qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].wake)
+			disable_irq_wake(
+				qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].irq);
+		if (qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].irq)
+			disable_irq_nosync(
+				qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].irq);
+	} else {
+		if (qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].irq)
+			enable_irq(qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].irq);
+		if (qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].wake)
+			enable_irq_wake(
+				qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].irq);
+	}
+
+	return 0;
+}
+
+static int qg_vbatt_irq_disable_cb(struct votable *votable, void *data,
+				int disable, const char *client)
+{
+	if (disable) {
+		if (qg_irqs[QG_VBATT_LOW_IRQ].wake)
+			disable_irq_wake(qg_irqs[QG_VBATT_LOW_IRQ].irq);
+		if (qg_irqs[QG_VBATT_EMPTY_IRQ].wake)
+			disable_irq_wake(qg_irqs[QG_VBATT_EMPTY_IRQ].irq);
+		if (qg_irqs[QG_VBATT_LOW_IRQ].irq)
+			disable_irq_nosync(qg_irqs[QG_VBATT_LOW_IRQ].irq);
+		if (qg_irqs[QG_VBATT_EMPTY_IRQ].irq)
+			disable_irq_nosync(qg_irqs[QG_VBATT_EMPTY_IRQ].irq);
+	} else {
+		if (qg_irqs[QG_VBATT_LOW_IRQ].irq)
+			enable_irq(qg_irqs[QG_VBATT_LOW_IRQ].irq);
+		if (qg_irqs[QG_VBATT_EMPTY_IRQ].irq)
+			enable_irq(qg_irqs[QG_VBATT_EMPTY_IRQ].irq);
+		if (qg_irqs[QG_VBATT_LOW_IRQ].wake)
+			enable_irq_wake(qg_irqs[QG_VBATT_LOW_IRQ].irq);
+		if (qg_irqs[QG_VBATT_EMPTY_IRQ].wake)
+			enable_irq_wake(qg_irqs[QG_VBATT_EMPTY_IRQ].irq);
+	}
+
+	return 0;
+}
+
+static int qg_good_ocv_irq_disable_cb(struct votable *votable, void *data,
+				int disable, const char *client)
+{
+	if (disable) {
+		if (qg_irqs[QG_GOOD_OCV_IRQ].wake)
+			disable_irq_wake(qg_irqs[QG_GOOD_OCV_IRQ].irq);
+		if (qg_irqs[QG_GOOD_OCV_IRQ].irq)
+			disable_irq_nosync(qg_irqs[QG_GOOD_OCV_IRQ].irq);
+	} else {
+		if (qg_irqs[QG_GOOD_OCV_IRQ].irq)
+			enable_irq(qg_irqs[QG_GOOD_OCV_IRQ].irq);
+		if (qg_irqs[QG_GOOD_OCV_IRQ].wake)
+			enable_irq_wake(qg_irqs[QG_GOOD_OCV_IRQ].irq);
+	}
+
+	return 0;
+}
+
+#define DEFAULT_BATT_TYPE	"Unknown Battery"
+#define MISSING_BATT_TYPE	"Missing Battery"
+#define DEBUG_BATT_TYPE		"Debug Board"
+static const char *qg_get_battery_type(struct qpnp_qg *chip)
+{
+	if (chip->battery_missing)
+		return MISSING_BATT_TYPE;
+
+	if (is_debug_batt_id(chip))
+		return DEBUG_BATT_TYPE;
+
+	if (chip->bp.batt_type_str) {
+		if (chip->profile_loaded)
+			return chip->bp.batt_type_str;
+	}
+
+	return DEFAULT_BATT_TYPE;
+}
+
+static int qg_get_battery_current(struct qpnp_qg *chip, int *ibat_ua)
+{
+	int rc = 0, last_ibat = 0;
+
+	if (chip->battery_missing) {
+		*ibat_ua = 0;
+		return 0;
+	}
+
+	rc = qg_read(chip, chip->qg_base + QG_LAST_ADC_I_DATA0_REG,
+				(u8 *)&last_ibat, 2);
+	if (rc < 0) {
+		pr_err("Failed to read LAST_ADV_I reg, rc=%d\n", rc);
+		return rc;
+	}
+
+	last_ibat = sign_extend32(last_ibat, 15);
+	*ibat_ua = I_RAW_TO_UA(last_ibat);
+
+	return rc;
+}
+
+static int qg_get_battery_voltage(struct qpnp_qg *chip, int *vbat_uv)
+{
+	int rc = 0;
+	u64 last_vbat = 0;
+
+	if (chip->battery_missing) {
+		*vbat_uv = 3700000;
+		return 0;
+	}
+
+	rc = qg_read(chip, chip->qg_base + QG_LAST_ADC_V_DATA0_REG,
+				(u8 *)&last_vbat, 2);
+	if (rc < 0) {
+		pr_err("Failed to read LAST_ADV_V reg, rc=%d\n", rc);
+		return rc;
+	}
+
+	*vbat_uv = V_RAW_TO_UV(last_vbat);
+
+	return rc;
+}
+
+#define DEBUG_BATT_SOC		67
+#define BATT_MISSING_SOC	50
+#define EMPTY_SOC		0
+static int qg_get_battery_capacity(struct qpnp_qg *chip, int *soc)
+{
+	if (is_debug_batt_id(chip)) {
+		*soc = DEBUG_BATT_SOC;
+		return 0;
+	}
+
+	if (chip->battery_missing || !chip->profile_loaded) {
+		*soc = BATT_MISSING_SOC;
+		return 0;
+	}
+
+	*soc = chip->msoc;
+
+	return 0;
+}
+
+static int qg_get_battery_temp(struct qpnp_qg *chip, int *temp)
+{
+	int rc = 0;
+	struct qpnp_vadc_result result;
+
+	if (chip->battery_missing) {
+		*temp = 250;
+		return 0;
+	}
+
+	rc = qpnp_vadc_read(chip->vadc_dev, VADC_BAT_THERM_PU2, &result);
+	if (rc) {
+		pr_err("Failed reading adc channel=%d, rc=%d\n",
+					VADC_BAT_THERM_PU2, rc);
+		return rc;
+	}
+	pr_debug("batt_temp = %lld meas = 0x%llx\n",
+			result.physical, result.measurement);
+
+	*temp = (int)result.physical;
+
+	return rc;
+}
+
+static int qg_psy_set_property(struct power_supply *psy,
+			       enum power_supply_property psp,
+			       const union power_supply_propval *pval)
+{
+	return 0;
+}
+
+static int qg_psy_get_property(struct power_supply *psy,
+			       enum power_supply_property psp,
+			       union power_supply_propval *pval)
+{
+	struct qpnp_qg *chip = power_supply_get_drvdata(psy);
+	int rc = 0;
+
+	pval->intval = 0;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CAPACITY:
+		rc = qg_get_battery_capacity(chip, &pval->intval);
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		rc = qg_get_battery_voltage(chip, &pval->intval);
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		rc = qg_get_battery_current(chip, &pval->intval);
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
+		rc = qg_sdam_read(SDAM_OCV_UV, &pval->intval);
+		break;
+	case POWER_SUPPLY_PROP_TEMP:
+		rc = qg_get_battery_temp(chip, &pval->intval);
+		break;
+	case POWER_SUPPLY_PROP_RESISTANCE_ID:
+		pval->intval = chip->batt_id_ohm;
+		break;
+	case POWER_SUPPLY_PROP_DEBUG_BATTERY:
+		pval->intval = is_debug_batt_id(chip);
+		break;
+	case POWER_SUPPLY_PROP_RESISTANCE:
+		rc = qg_sdam_read(SDAM_RBAT_MOHM, &pval->intval);
+		if (!rc)
+			pval->intval *= 1000;
+		break;
+	case POWER_SUPPLY_PROP_RESISTANCE_CAPACITIVE:
+		pval->intval = chip->dt.rbat_conn_mohm;
+		break;
+	case POWER_SUPPLY_PROP_BATTERY_TYPE:
+		pval->strval = qg_get_battery_type(chip);
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
+		pval->intval = chip->dt.vbatt_cutoff_mv * 1000;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+		pval->intval = chip->bp.float_volt_uv;
+		break;
+	case POWER_SUPPLY_PROP_BATT_FULL_CURRENT:
+		pval->intval = chip->dt.iterm_ma * 1000;
+		break;
+	case POWER_SUPPLY_PROP_BATT_PROFILE_VERSION:
+		pval->intval = chip->bp.qg_profile_version;
+		break;
+	default:
+		pr_debug("Unsupported property %d\n", psp);
+		break;
+	}
+
+	return rc;
+}
+
+static int qg_property_is_writeable(struct power_supply *psy,
+				enum power_supply_property psp)
+{
+	return 0;
+}
+
+static enum power_supply_property qg_psy_props[] = {
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_TEMP,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_VOLTAGE_OCV,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_RESISTANCE,
+	POWER_SUPPLY_PROP_RESISTANCE_ID,
+	POWER_SUPPLY_PROP_RESISTANCE_CAPACITIVE,
+	POWER_SUPPLY_PROP_DEBUG_BATTERY,
+	POWER_SUPPLY_PROP_BATTERY_TYPE,
+	POWER_SUPPLY_PROP_VOLTAGE_MIN,
+	POWER_SUPPLY_PROP_VOLTAGE_MAX,
+	POWER_SUPPLY_PROP_BATT_FULL_CURRENT,
+	POWER_SUPPLY_PROP_BATT_PROFILE_VERSION,
+};
+
+static const struct power_supply_desc qg_psy_desc = {
+	.name = "bms",
+	.type = POWER_SUPPLY_TYPE_BMS,
+	.properties = qg_psy_props,
+	.num_properties = ARRAY_SIZE(qg_psy_props),
+	.get_property = qg_psy_get_property,
+	.set_property = qg_psy_set_property,
+	.property_is_writeable = qg_property_is_writeable,
+};
+
+static int qg_charge_full_update(struct qpnp_qg *chip)
+{
+
+	vote(chip->good_ocv_irq_disable_votable,
+		QG_INIT_STATE_IRQ_DISABLE, !chip->charge_done, 0);
+
+	/* TODO: add hold-soc-at-full logic */
+	return 0;
+}
+
+static int qg_parallel_status_update(struct qpnp_qg *chip)
+{
+	int rc;
+	bool parallel_enabled = is_parallel_enabled(chip);
+
+	if (parallel_enabled == chip->parallel_enabled)
+		return 0;
+
+	chip->parallel_enabled = parallel_enabled;
+	qg_dbg(chip, QG_DEBUG_STATUS,
+		"Parallel status changed Enabled=%d\n", parallel_enabled);
+
+	mutex_lock(&chip->data_lock);
+
+	rc = process_rt_fifo_data(chip, false, true);
+	if (rc < 0)
+		pr_err("Failed to process RT FIFO data, rc=%d\n", rc);
+
+	mutex_unlock(&chip->data_lock);
+
+	return 0;
+}
+
+static int qg_usb_status_update(struct qpnp_qg *chip)
+{
+	bool usb_present = is_usb_present(chip);
+
+	if (chip->usb_present != usb_present) {
+		qg_dbg(chip, QG_DEBUG_STATUS,
+			"USB status changed Present=%d\n",
+							usb_present);
+		qg_scale_soc(chip, false);
+	}
+
+	chip->usb_present = usb_present;
+
+	return 0;
+}
+
+static void qg_status_change_work(struct work_struct *work)
+{
+	struct qpnp_qg *chip = container_of(work,
+			struct qpnp_qg, qg_status_change_work);
+	union power_supply_propval prop = {0, };
+	int rc = 0;
+
+	if (!is_batt_available(chip)) {
+		pr_debug("batt-psy not available\n");
+		goto out;
+	}
+
+	rc = power_supply_get_property(chip->batt_psy,
+			POWER_SUPPLY_PROP_STATUS, &prop);
+	if (rc < 0)
+		pr_err("Failed to get charger status, rc=%d\n", rc);
+	else
+		chip->charge_status = prop.intval;
+
+	rc = power_supply_get_property(chip->batt_psy,
+			POWER_SUPPLY_PROP_CHARGE_DONE, &prop);
+	if (rc < 0)
+		pr_err("Failed to get charge done status, rc=%d\n", rc);
+	else
+		chip->charge_done = prop.intval;
+
+	rc = qg_parallel_status_update(chip);
+	if (rc < 0)
+		pr_err("Failed to update parallel-status, rc=%d\n", rc);
+
+	rc = qg_usb_status_update(chip);
+	if (rc < 0)
+		pr_err("Failed to update usb status, rc=%d\n", rc);
+
+	rc = qg_charge_full_update(chip);
+	if (rc < 0)
+		pr_err("Failed in charge_full_update, rc=%d\n", rc);
+out:
+	pm_relax(chip->dev);
+}
+
+static int qg_notifier_cb(struct notifier_block *nb,
+			unsigned long event, void *data)
+{
+	struct power_supply *psy = data;
+	struct qpnp_qg *chip = container_of(nb, struct qpnp_qg, nb);
+
+	if (event != PSY_EVENT_PROP_CHANGED)
+		return NOTIFY_OK;
+
+	if (work_pending(&chip->qg_status_change_work))
+		return NOTIFY_OK;
+
+	if ((strcmp(psy->desc->name, "battery") == 0)
+		|| (strcmp(psy->desc->name, "parallel") == 0)
+		|| (strcmp(psy->desc->name, "usb") == 0)) {
+		/*
+		 * We cannot vote for awake votable here as that takes
+		 * a mutex lock and this is executed in an atomic context.
+		 */
+		pm_stay_awake(chip->dev);
+		schedule_work(&chip->qg_status_change_work);
+	}
+
+	return NOTIFY_OK;
+}
+
+static int qg_init_psy(struct qpnp_qg *chip)
+{
+	struct power_supply_config qg_psy_cfg;
+	int rc;
+
+	qg_psy_cfg.drv_data = chip;
+	qg_psy_cfg.of_node = NULL;
+	qg_psy_cfg.supplied_to = NULL;
+	qg_psy_cfg.num_supplicants = 0;
+	chip->qg_psy = devm_power_supply_register(chip->dev,
+				&qg_psy_desc, &qg_psy_cfg);
+	if (IS_ERR_OR_NULL(chip->qg_psy)) {
+		pr_err("Failed to register qg_psy rc = %ld\n",
+				PTR_ERR(chip->qg_psy));
+		return -ENODEV;
+	}
+
+	chip->nb.notifier_call = qg_notifier_cb;
+	rc = power_supply_reg_notifier(&chip->nb);
+	if (rc < 0)
+		pr_err("Failed register psy notifier rc = %d\n", rc);
+
+	return rc;
+}
+
+static ssize_t qg_device_read(struct file *file, char __user *buf, size_t count,
+			  loff_t *ppos)
+{
+	int rc;
+	struct qpnp_qg *chip = file->private_data;
+	unsigned long data_size = sizeof(chip->kdata);
+
+	/* non-blocking access, return */
+	if (!chip->data_ready && (file->f_flags & O_NONBLOCK))
+		return -EAGAIN;
+
+	/* blocking access wait on data_ready */
+	if (!(file->f_flags & O_NONBLOCK)) {
+		rc = wait_event_interruptible(chip->qg_wait_q,
+					chip->data_ready);
+		if (rc < 0) {
+			pr_debug("Failed wait! rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	mutex_lock(&chip->data_lock);
+
+	if (!chip->data_ready) {
+		pr_debug("No Data, false wakeup\n");
+		rc = -EFAULT;
+		goto fail_read;
+	}
+
+	if (copy_to_user(buf, &chip->kdata, data_size)) {
+		pr_err("Failed in copy_to_user\n");
+		rc = -EFAULT;
+		goto fail_read;
+	}
+	chip->data_ready = false;
+
+	/* clear data */
+	memset(&chip->kdata, 0, sizeof(chip->kdata));
+
+	/* release all wake sources */
+	vote(chip->awake_votable, GOOD_OCV_VOTER, false, 0);
+	vote(chip->awake_votable, FIFO_DONE_VOTER, false, 0);
+	vote(chip->awake_votable, FIFO_RT_DONE_VOTER, false, 0);
+	vote(chip->awake_votable, SUSPEND_DATA_VOTER, false, 0);
+
+	qg_dbg(chip, QG_DEBUG_DEVICE,
+			"QG device read complete Size=%ld\n", data_size);
+
+	mutex_unlock(&chip->data_lock);
+
+	return data_size;
+
+fail_read:
+	mutex_unlock(&chip->data_lock);
+	return rc;
+}
+
+static ssize_t qg_device_write(struct file *file, const char __user *buf,
+			size_t count, loff_t *ppos)
+{
+	int rc = -EINVAL;
+	struct qpnp_qg *chip = file->private_data;
+	unsigned long data_size = sizeof(chip->udata);
+
+	mutex_lock(&chip->data_lock);
+	if (count == 0) {
+		pr_err("No data!\n");
+		goto fail;
+	}
+
+	if (count != 0 && count < data_size) {
+		pr_err("Invalid datasize %zu expected %zu\n", count, data_size);
+		goto fail;
+	}
+
+	if (copy_from_user(&chip->udata, buf, data_size)) {
+		pr_err("Failed in copy_from_user\n");
+		rc = -EFAULT;
+		goto fail;
+	}
+
+	rc = data_size;
+	vote(chip->awake_votable, UDATA_READY_VOTER, true, 0);
+	schedule_work(&chip->udata_work);
+	qg_dbg(chip, QG_DEBUG_DEVICE, "QG write complete size=%d\n", rc);
+fail:
+	mutex_unlock(&chip->data_lock);
+	return rc;
+}
+
+static unsigned int qg_device_poll(struct file *file, poll_table *wait)
+{
+	struct qpnp_qg *chip = file->private_data;
+	unsigned int mask;
+
+	poll_wait(file, &chip->qg_wait_q, wait);
+
+	if (chip->data_ready)
+		mask = POLLIN | POLLRDNORM;
+	else
+		mask = POLLERR;
+
+	return mask;
+}
+
+static int qg_device_open(struct inode *inode, struct file *file)
+{
+	struct qpnp_qg *chip = container_of(inode->i_cdev,
+				struct qpnp_qg, qg_cdev);
+
+	file->private_data = chip;
+	qg_dbg(chip, QG_DEBUG_DEVICE, "QG device opened!\n");
+
+	return 0;
+}
+
+static const struct file_operations qg_fops = {
+	.owner		= THIS_MODULE,
+	.open		= qg_device_open,
+	.read		= qg_device_read,
+	.write		= qg_device_write,
+	.poll		= qg_device_poll,
+};
+
+static int qg_register_device(struct qpnp_qg *chip)
+{
+	int rc;
+
+	rc = alloc_chrdev_region(&chip->dev_no, 0, 1, "qg");
+	if (rc < 0) {
+		pr_err("Failed to allocate chardev rc=%d\n", rc);
+		return rc;
+	}
+
+	cdev_init(&chip->qg_cdev, &qg_fops);
+	rc = cdev_add(&chip->qg_cdev, chip->dev_no, 1);
+	if (rc < 0) {
+		pr_err("Failed to cdev_add rc=%d\n", rc);
+		goto unregister_chrdev;
+	}
+
+	chip->qg_class = class_create(THIS_MODULE, "qg");
+	if (IS_ERR_OR_NULL(chip->qg_class)) {
+		pr_err("Failed to create qg class\n");
+		rc = -EINVAL;
+		goto delete_cdev;
+	}
+	chip->qg_device = device_create(chip->qg_class, NULL, chip->dev_no,
+					NULL, "qg");
+	if (IS_ERR(chip->qg_device)) {
+		pr_err("Failed to create qg_device\n");
+		rc = -EINVAL;
+		goto destroy_class;
+	}
+
+	qg_dbg(chip, QG_DEBUG_DEVICE, "'/dev/qg' successfully created\n");
+
+	return 0;
+
+destroy_class:
+	class_destroy(chip->qg_class);
+delete_cdev:
+	cdev_del(&chip->qg_cdev);
+unregister_chrdev:
+	unregister_chrdev_region(chip->dev_no, 1);
+	return rc;
+}
+
+#define BID_RPULL_OHM		100000
+#define BID_VREF_MV		1875
+static int get_batt_id_ohm(struct qpnp_qg *chip, u32 *batt_id_ohm)
+{
+	int rc, batt_id_mv;
+	int64_t denom;
+	struct qpnp_vadc_result result;
+
+	/* Read battery-id */
+	rc = qpnp_vadc_read(chip->vadc_dev, VADC_BAT_ID_PU2, &result);
+	if (rc) {
+		pr_err("Failed to read BATT_ID over vadc, rc=%d\n", rc);
+		return rc;
+	}
+
+	batt_id_mv = result.physical / 1000;
+	if (batt_id_mv == 0) {
+		pr_debug("batt_id_mv = 0 from ADC\n");
+		return 0;
+	}
+
+	denom = div64_s64(BID_VREF_MV * 1000, batt_id_mv) - 1000;
+	if (denom <= 0) {
+		/* batt id connector might be open, return 0 kohms */
+		return 0;
+	}
+
+	*batt_id_ohm = div64_u64(BID_RPULL_OHM * 1000 + denom / 2, denom);
+
+	qg_dbg(chip, QG_DEBUG_PROFILE, "batt_id_mv=%d, batt_id_ohm=%d\n",
+					batt_id_mv, *batt_id_ohm);
+
+	return 0;
+}
+
+static int qg_load_battery_profile(struct qpnp_qg *chip)
+{
+	struct device_node *node = chip->dev->of_node;
+	struct device_node *batt_node, *profile_node;
+	int rc;
+
+	batt_node = of_find_node_by_name(node, "qcom,battery-data");
+	if (!batt_node) {
+		pr_err("Batterydata not available\n");
+		return -ENXIO;
+	}
+
+	profile_node = of_batterydata_get_best_profile(batt_node,
+				chip->batt_id_ohm / 1000, NULL);
+	if (IS_ERR(profile_node)) {
+		rc = PTR_ERR(profile_node);
+		pr_err("Failed to detect valid QG battery profile %d\n", rc);
+		return rc;
+	}
+
+	rc = of_property_read_string(profile_node, "qcom,battery-type",
+				&chip->bp.batt_type_str);
+	if (rc < 0) {
+		pr_err("Failed to detect battery type rc:%d\n", rc);
+		return rc;
+	}
+
+	rc = qg_batterydata_init(profile_node);
+	if (rc < 0) {
+		pr_err("Failed to initialize battery-profile rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = of_property_read_u32(profile_node, "qcom,max-voltage-uv",
+				&chip->bp.float_volt_uv);
+	if (rc < 0) {
+		pr_err("Failed to read battery float-voltage rc:%d\n", rc);
+		chip->bp.float_volt_uv = -EINVAL;
+	}
+
+	rc = of_property_read_u32(profile_node, "qcom,fastchg-current-ma",
+				&chip->bp.fastchg_curr_ma);
+	if (rc < 0) {
+		pr_err("Failed to read battery fastcharge current rc:%d\n", rc);
+		chip->bp.fastchg_curr_ma = -EINVAL;
+	}
+
+	rc = of_property_read_u32(profile_node, "qcom,qg-batt-profile-ver",
+				&chip->bp.qg_profile_version);
+	if (rc < 0) {
+		pr_err("Failed to read QG profile version rc:%d\n", rc);
+		chip->bp.qg_profile_version = -EINVAL;
+	}
+
+	qg_dbg(chip, QG_DEBUG_PROFILE, "profile=%s FV=%duV FCC=%dma\n",
+			chip->bp.batt_type_str, chip->bp.float_volt_uv,
+			chip->bp.fastchg_curr_ma);
+
+	return 0;
+}
+
+static int qg_setup_battery(struct qpnp_qg *chip)
+{
+	int rc;
+
+	if (!is_battery_present(chip)) {
+		qg_dbg(chip, QG_DEBUG_PROFILE, "Battery Missing!\n");
+		chip->battery_missing = true;
+		chip->profile_loaded = false;
+	} else {
+		/* battery present */
+		rc = get_batt_id_ohm(chip, &chip->batt_id_ohm);
+		if (rc < 0) {
+			pr_err("Failed to detect batt_id rc=%d\n", rc);
+			chip->profile_loaded = false;
+		} else {
+			rc = qg_load_battery_profile(chip);
+			if (rc < 0)
+				pr_err("Failed to load battery-profile rc=%d\n",
+								rc);
+			else
+				chip->profile_loaded = true;
+		}
+	}
+
+	qg_dbg(chip, QG_DEBUG_PROFILE, "battery_missing=%d batt_id_ohm=%d Ohm profile_loaded=%d profile=%s\n",
+			chip->battery_missing, chip->batt_id_ohm,
+			chip->profile_loaded, chip->bp.batt_type_str);
+
+	return 0;
+}
+
+static int qg_determine_pon_soc(struct qpnp_qg *chip)
+{
+	u8 status;
+	int rc, batt_temp = 0;
+	bool use_pon_ocv = false;
+	unsigned long rtc_sec = 0;
+	u32 ocv_uv = 0, soc = 0, shutdown[SDAM_MAX] = {0};
+
+	if (!chip->profile_loaded) {
+		qg_dbg(chip, QG_DEBUG_PON, "No Profile, skipping PON soc\n");
+		return 0;
+	}
+
+	rc = qg_get_battery_temp(chip, &batt_temp);
+	if (rc) {
+		pr_err("Failed to read BATT_TEMP at PON rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qg_read(chip, chip->qg_base + QG_STATUS2_REG,
+					&status, 1);
+	if (rc < 0) {
+		pr_err("Failed to read status2 register rc=%d\n", rc);
+		return rc;
+	}
+
+	if (status & GOOD_OCV_BIT) {
+		qg_dbg(chip, QG_DEBUG_PON, "Using GOOD_OCV @ PON\n");
+		rc = qg_read_ocv(chip, &ocv_uv, GOOD_OCV);
+		if (rc < 0) {
+			pr_err("Failed to read good_ocv rc=%d\n", rc);
+			use_pon_ocv = true;
+		} else {
+			rc = lookup_soc_ocv(&soc, ocv_uv, batt_temp, false);
+			if (rc < 0) {
+				pr_err("Failed to lookup SOC (GOOD_OCV) @ PON rc=%d\n",
+					rc);
+				use_pon_ocv = true;
+			}
+		}
+	} else {
+		rc = get_rtc_time(&rtc_sec);
+		if (rc < 0) {
+			pr_err("Failed to read RTC time rc=%d\n", rc);
+			use_pon_ocv = true;
+			goto done;
+		}
+
+		rc = qg_sdam_read_all(shutdown);
+		if (rc < 0) {
+			pr_err("Failed to read shutdown params rc=%d\n", rc);
+			use_pon_ocv = true;
+			goto done;
+		}
+		qg_dbg(chip, QG_DEBUG_PON, "Shutdown: SOC=%d OCV=%duV time=%dsecs, time_now=%ldsecs\n",
+				shutdown[SDAM_SOC],
+				shutdown[SDAM_OCV_UV],
+				shutdown[SDAM_TIME_SEC],
+				rtc_sec);
+		/*
+		 * Use the shutdown SOC if
+		 * 1. The device was powered off for < 180 seconds
+		 * 2. SDAM read is a success & SDAM data is valid
+		 */
+		use_pon_ocv = true;
+		if (!rc && shutdown[SDAM_VALID] &&
+			((rtc_sec - shutdown[SDAM_TIME_SEC]) < 180)) {
+			use_pon_ocv = false;
+			ocv_uv = shutdown[SDAM_OCV_UV];
+			soc = shutdown[SDAM_SOC];
+			qg_dbg(chip, QG_DEBUG_PON, "Using SHUTDOWN_SOC @ PON\n");
+		}
+	}
+done:
+	/*
+	 * Use PON OCV if
+	 * OCV_UV is not set or shutdown SOC is invalid.
+	 */
+	if (use_pon_ocv || !ocv_uv || !rtc_sec) {
+		qg_dbg(chip, QG_DEBUG_PON, "Using PON_OCV @ PON\n");
+		rc = qg_read_ocv(chip, &ocv_uv, PON_OCV);
+		if (rc < 0) {
+			pr_err("Failed to read HW PON ocv rc=%d\n", rc);
+			return rc;
+		}
+		rc = lookup_soc_ocv(&soc, ocv_uv, batt_temp, false);
+		if (rc < 0) {
+			pr_err("Failed to lookup SOC @ PON rc=%d\n", rc);
+			soc = 50;
+		}
+	}
+
+	chip->pon_soc = chip->catch_up_soc = chip->msoc = soc;
+	chip->kdata.param[QG_PON_OCV_UV].data = ocv_uv;
+	chip->kdata.param[QG_PON_OCV_UV].valid = true;
+
+	/* write back to SDAM */
+	chip->sdam_data[SDAM_SOC] = soc;
+	chip->sdam_data[SDAM_OCV_UV] = ocv_uv;
+	chip->sdam_data[SDAM_VALID] = 1;
+
+	rc = qg_write_monotonic_soc(chip, chip->msoc);
+	if (rc < 0)
+		pr_err("Failed to update MSOC register rc=%d\n", rc);
+
+	rc = qg_update_sdam_params(chip);
+	if (rc < 0)
+		pr_err("Failed to update sdam params rc=%d\n", rc);
+
+	pr_info("use_pon_ocv=%d good_ocv=%d ocv_uv=%duV temp=%d soc=%d\n",
+			use_pon_ocv, !!(status & GOOD_OCV_BIT),
+			ocv_uv, batt_temp, chip->msoc);
+
+	return 0;
+}
+
+static int qg_set_wa_flags(struct qpnp_qg *chip)
+{
+	switch (chip->pmic_rev_id->pmic_subtype) {
+	case PMI632_SUBTYPE:
+		if (chip->pmic_rev_id->rev4 == PMI632_V1P0_REV4)
+			chip->wa_flags |= QG_VBAT_LOW_WA;
+		break;
+	default:
+		pr_err("Unsupported PMIC subtype %d\n",
+			chip->pmic_rev_id->pmic_subtype);
+		return -EINVAL;
+	}
+
+	qg_dbg(chip, QG_DEBUG_PON, "wa_flags = %x\n", chip->wa_flags);
+
+	return 0;
+}
+
+static int qg_hw_init(struct qpnp_qg *chip)
+{
+	int rc, temp;
+	u8 reg;
+
+	rc = qg_set_wa_flags(chip);
+	if (rc < 0) {
+		pr_err("Failed to update PMIC type flags, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qg_master_hold(chip, true);
+	if (rc < 0) {
+		pr_err("Failed to hold master, rc=%d\n", rc);
+		goto done_fifo;
+	}
+
+	rc = qg_process_rt_fifo(chip);
+	if (rc < 0) {
+		pr_err("Failed to process FIFO real-time, rc=%d\n", rc);
+		goto done_fifo;
+	}
+
+	/* update the changed S2 fifo DT parameters */
+	if (chip->dt.s2_fifo_length > 0) {
+		rc = qg_update_fifo_length(chip, chip->dt.s2_fifo_length);
+		if (rc < 0)
+			goto done_fifo;
+	}
+
+	if (chip->dt.s2_acc_length > 0) {
+		reg = ilog2(chip->dt.s2_acc_length) - 1;
+		rc = qg_masked_write(chip, chip->qg_base +
+				QG_S2_NORMAL_MEAS_CTL2_REG,
+				NUM_OF_ACCUM_MASK, reg);
+		if (rc < 0) {
+			pr_err("Failed to write S2 ACC length, rc=%d\n", rc);
+			goto done_fifo;
+		}
+	}
+
+	if (chip->dt.s2_acc_intvl_ms > 0) {
+		reg = chip->dt.s2_acc_intvl_ms / 10;
+		rc = qg_write(chip, chip->qg_base +
+				QG_S2_NORMAL_MEAS_CTL3_REG,
+				&reg, 1);
+		if (rc < 0) {
+			pr_err("Failed to write S2 ACC intrvl, rc=%d\n", rc);
+			goto done_fifo;
+		}
+	}
+
+	/* signal the read thread */
+	chip->data_ready = true;
+	wake_up_interruptible(&chip->qg_wait_q);
+
+done_fifo:
+	rc = qg_master_hold(chip, false);
+	if (rc < 0) {
+		pr_err("Failed to release master, rc=%d\n", rc);
+		return rc;
+	}
+	chip->last_fifo_update_time = ktime_get();
+
+	if (chip->dt.ocv_timer_expiry_min != -EINVAL) {
+		if (chip->dt.ocv_timer_expiry_min < 2)
+			chip->dt.ocv_timer_expiry_min = 2;
+		else if (chip->dt.ocv_timer_expiry_min > 30)
+			chip->dt.ocv_timer_expiry_min = 30;
+
+		reg = (chip->dt.ocv_timer_expiry_min - 2) / 4;
+		rc = qg_masked_write(chip,
+			chip->qg_base + QG_S3_SLEEP_OCV_MEAS_CTL4_REG,
+			SLEEP_IBAT_QUALIFIED_LENGTH_MASK, reg);
+		if (rc < 0) {
+			pr_err("Failed to write OCV timer, rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	if (chip->dt.ocv_tol_threshold_uv != -EINVAL) {
+		if (chip->dt.ocv_tol_threshold_uv < 0)
+			chip->dt.ocv_tol_threshold_uv = 0;
+		else if (chip->dt.ocv_tol_threshold_uv > 12262)
+			chip->dt.ocv_tol_threshold_uv = 12262;
+
+		reg = chip->dt.ocv_tol_threshold_uv / 195;
+		rc = qg_masked_write(chip,
+			chip->qg_base + QG_S3_SLEEP_OCV_TREND_CTL2_REG,
+			TREND_TOL_MASK, reg);
+		if (rc < 0) {
+			pr_err("Failed to write OCV tol-thresh, rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	if (chip->dt.s3_entry_fifo_length != -EINVAL) {
+		if (chip->dt.s3_entry_fifo_length < 1)
+			chip->dt.s3_entry_fifo_length = 1;
+		else if (chip->dt.s3_entry_fifo_length > 8)
+			chip->dt.s3_entry_fifo_length = 8;
+
+		reg = chip->dt.s3_entry_fifo_length - 1;
+		rc = qg_masked_write(chip,
+			chip->qg_base + QG_S3_SLEEP_OCV_IBAT_CTL1_REG,
+			SLEEP_IBAT_QUALIFIED_LENGTH_MASK, reg);
+		if (rc < 0) {
+			pr_err("Failed to write S3-entry fifo-length, rc=%d\n",
+							rc);
+			return rc;
+		}
+	}
+
+	if (chip->dt.s3_entry_ibat_ua != -EINVAL) {
+		if (chip->dt.s3_entry_ibat_ua < 0)
+			chip->dt.s3_entry_ibat_ua = 0;
+		else if (chip->dt.s3_entry_ibat_ua > 155550)
+			chip->dt.s3_entry_ibat_ua = 155550;
+
+		reg = chip->dt.s3_entry_ibat_ua / 610;
+		rc = qg_write(chip, chip->qg_base +
+				QG_S3_ENTRY_IBAT_THRESHOLD_REG,
+				&reg, 1);
+		if (rc < 0) {
+			pr_err("Failed to write S3-entry ibat-uA, rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	if (chip->dt.s3_exit_ibat_ua != -EINVAL) {
+		if (chip->dt.s3_exit_ibat_ua < 0)
+			chip->dt.s3_exit_ibat_ua = 0;
+		else if (chip->dt.s3_exit_ibat_ua > 155550)
+			chip->dt.s3_exit_ibat_ua = 155550;
+
+		rc = qg_read(chip, chip->qg_base +
+				QG_S3_ENTRY_IBAT_THRESHOLD_REG,
+				&reg, 1);
+		if (rc < 0) {
+			pr_err("Failed to read S3-entry ibat-uA, rc=%d", rc);
+			return rc;
+		}
+		temp = reg * 610;
+		if (chip->dt.s3_exit_ibat_ua < temp)
+			chip->dt.s3_exit_ibat_ua = temp;
+		else
+			chip->dt.s3_exit_ibat_ua -= temp;
+
+		reg = chip->dt.s3_exit_ibat_ua / 610;
+		rc = qg_write(chip,
+			chip->qg_base + QG_S3_EXIT_IBAT_THRESHOLD_REG,
+			&reg, 1);
+		if (rc < 0) {
+			pr_err("Failed to write S3-entry ibat-uA, rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	/* vbat low */
+	if (chip->dt.vbatt_low_mv < 0)
+		chip->dt.vbatt_low_mv = 0;
+	else if (chip->dt.vbatt_low_mv > 12750)
+		chip->dt.vbatt_low_mv = 12750;
+
+	reg = chip->dt.vbatt_low_mv / 50;
+	rc = qg_write(chip, chip->qg_base + QG_VBAT_LOW_THRESHOLD_REG,
+					&reg, 1);
+	if (rc < 0) {
+		pr_err("Failed to write vbat-low, rc=%d\n", rc);
+		return rc;
+	}
+
+	/* vbat empty */
+	if (chip->dt.vbatt_empty_mv < 0)
+		chip->dt.vbatt_empty_mv = 0;
+	else if (chip->dt.vbatt_empty_mv > 12750)
+		chip->dt.vbatt_empty_mv = 12750;
+
+	reg = chip->dt.vbatt_empty_mv / 50;
+	rc = qg_write(chip, chip->qg_base + QG_VBAT_EMPTY_THRESHOLD_REG,
+					&reg, 1);
+	if (rc < 0) {
+		pr_err("Failed to write vbat-empty, rc=%d\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int qg_post_init(struct qpnp_qg *chip)
+{
+	/* disable all IRQs if profile is not loaded */
+	if (!chip->profile_loaded) {
+		vote(chip->vbatt_irq_disable_votable,
+				PROFILE_IRQ_DISABLE, true, 0);
+		vote(chip->fifo_irq_disable_votable,
+				PROFILE_IRQ_DISABLE, true, 0);
+		vote(chip->good_ocv_irq_disable_votable,
+				PROFILE_IRQ_DISABLE, true, 0);
+	} else {
+		/* disable GOOD_OCV IRQ at init */
+		vote(chip->good_ocv_irq_disable_votable,
+				QG_INIT_STATE_IRQ_DISABLE, true, 0);
+	}
+
+	return 0;
+}
+
+static int qg_get_irq_index_byname(const char *irq_name)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(qg_irqs); i++) {
+		if (strcmp(qg_irqs[i].name, irq_name) == 0)
+			return i;
+	}
+
+	return -ENOENT;
+}
+
+static int qg_request_interrupt(struct qpnp_qg *chip,
+		struct device_node *node, const char *irq_name)
+{
+	int rc, irq, irq_index;
+
+	irq = of_irq_get_byname(node, irq_name);
+	if (irq < 0) {
+		pr_err("Failed to get irq %s byname\n", irq_name);
+		return irq;
+	}
+
+	irq_index = qg_get_irq_index_byname(irq_name);
+	if (irq_index < 0) {
+		pr_err("%s is not a defined irq\n", irq_name);
+		return irq_index;
+	}
+
+	if (!qg_irqs[irq_index].handler)
+		return 0;
+
+	rc = devm_request_threaded_irq(chip->dev, irq, NULL,
+				qg_irqs[irq_index].handler,
+				IRQF_ONESHOT, irq_name, chip);
+	if (rc < 0) {
+		pr_err("Failed to request irq %d\n", irq);
+		return rc;
+	}
+
+	qg_irqs[irq_index].irq = irq;
+	if (qg_irqs[irq_index].wake)
+		enable_irq_wake(irq);
+
+	qg_dbg(chip, QG_DEBUG_PON, "IRQ %s registered wakeable=%d\n",
+			qg_irqs[irq_index].name, qg_irqs[irq_index].wake);
+
+	return 0;
+}
+
+static int qg_request_irqs(struct qpnp_qg *chip)
+{
+	struct device_node *node = chip->dev->of_node;
+	struct device_node *child;
+	const char *name;
+	struct property *prop;
+	int rc = 0;
+
+	for_each_available_child_of_node(node, child) {
+		of_property_for_each_string(child, "interrupt-names",
+					    prop, name) {
+			rc = qg_request_interrupt(chip, child, name);
+			if (rc < 0)
+				return rc;
+		}
+	}
+
+
+	return 0;
+}
+
+#define DEFAULT_VBATT_EMPTY_MV		3200
+#define DEFAULT_VBATT_CUTOFF_MV		3400
+#define DEFAULT_VBATT_LOW_MV		3500
+#define DEFAULT_ITERM_MA		100
+#define DEFAULT_S2_FIFO_LENGTH		5
+#define DEFAULT_S2_VBAT_LOW_LENGTH	2
+#define DEFAULT_S2_ACC_LENGTH		128
+#define DEFAULT_S2_ACC_INTVL_MS		100
+#define DEFAULT_DELTA_SOC		1
+static int qg_parse_dt(struct qpnp_qg *chip)
+{
+	int rc = 0;
+	struct device_node *revid_node, *child, *node = chip->dev->of_node;
+	u32 base, temp;
+	u8 type;
+
+	if (!node)  {
+		pr_err("Failed to find device-tree node\n");
+		return -ENXIO;
+	}
+
+	revid_node = of_parse_phandle(node, "qcom,pmic-revid", 0);
+	if (!revid_node) {
+		pr_err("Missing qcom,pmic-revid property - driver failed\n");
+		return -EINVAL;
+	}
+
+	chip->pmic_rev_id = get_revid_data(revid_node);
+	of_node_put(revid_node);
+	if (IS_ERR_OR_NULL(chip->pmic_rev_id)) {
+		pr_err("Failed to get pmic_revid, rc=%ld\n",
+			PTR_ERR(chip->pmic_rev_id));
+		/*
+		 * the revid peripheral must be registered, any failure
+		 * here only indicates that the rev-id module has not
+		 * probed yet.
+		 */
+		return -EPROBE_DEFER;
+	}
+
+	qg_dbg(chip, QG_DEBUG_PON, "PMIC subtype %d Digital major %d\n",
+		chip->pmic_rev_id->pmic_subtype, chip->pmic_rev_id->rev4);
+
+	for_each_available_child_of_node(node, child) {
+		rc = of_property_read_u32(child, "reg", &base);
+		if (rc < 0) {
+			pr_err("Failed to read base address, rc=%d\n", rc);
+			return rc;
+		}
+
+		rc = qg_read(chip, base + PERPH_TYPE_REG, &type, 1);
+		if (rc < 0) {
+			pr_err("Failed to read type, rc=%d\n", rc);
+			return rc;
+		}
+
+		switch (type) {
+		case QG_TYPE:
+			chip->qg_base = base;
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (!chip->qg_base) {
+		pr_err("QG device node missing\n");
+		return -EINVAL;
+	}
+
+	/* S2 state params */
+	rc = of_property_read_u32(node, "qcom,s2-fifo-length", &temp);
+	if (rc < 0)
+		chip->dt.s2_fifo_length = DEFAULT_S2_FIFO_LENGTH;
+	else
+		chip->dt.s2_fifo_length = temp;
+
+	rc = of_property_read_u32(node, "qcom,s2-vbat-low-fifo-length", &temp);
+	if (rc < 0)
+		chip->dt.s2_vbat_low_fifo_length = DEFAULT_S2_VBAT_LOW_LENGTH;
+	else
+		chip->dt.s2_vbat_low_fifo_length = temp;
+
+	rc = of_property_read_u32(node, "qcom,s2-acc-length", &temp);
+	if (rc < 0)
+		chip->dt.s2_acc_length = DEFAULT_S2_ACC_LENGTH;
+	else
+		chip->dt.s2_acc_length = temp;
+
+	rc = of_property_read_u32(node, "qcom,s2-acc-interval-ms", &temp);
+	if (rc < 0)
+		chip->dt.s2_acc_intvl_ms = DEFAULT_S2_ACC_INTVL_MS;
+	else
+		chip->dt.s2_acc_intvl_ms = temp;
+
+	qg_dbg(chip, QG_DEBUG_PON, "DT: S2 FIFO length=%d low_vbat_length=%d acc_length=%d acc_interval=%d\n",
+		chip->dt.s2_fifo_length, chip->dt.s2_vbat_low_fifo_length,
+		chip->dt.s2_acc_length, chip->dt.s2_acc_intvl_ms);
+
+	/* OCV params */
+	rc = of_property_read_u32(node, "qcom,ocv-timer-expiry-min", &temp);
+	if (rc < 0)
+		chip->dt.ocv_timer_expiry_min = -EINVAL;
+	else
+		chip->dt.ocv_timer_expiry_min = temp;
+
+	rc = of_property_read_u32(node, "qcom,ocv-tol-threshold-uv", &temp);
+	if (rc < 0)
+		chip->dt.ocv_tol_threshold_uv = -EINVAL;
+	else
+		chip->dt.ocv_tol_threshold_uv = temp;
+
+	qg_dbg(chip, QG_DEBUG_PON, "DT: OCV timer_expiry =%dmin ocv_tol_threshold=%duV\n",
+		chip->dt.ocv_timer_expiry_min, chip->dt.ocv_tol_threshold_uv);
+
+	/* S3 sleep configuration */
+	rc = of_property_read_u32(node, "qcom,s3-entry-fifo-length", &temp);
+	if (rc < 0)
+		chip->dt.s3_entry_fifo_length = -EINVAL;
+	else
+		chip->dt.s3_entry_fifo_length = temp;
+
+	rc = of_property_read_u32(node, "qcom,s3-entry-ibat-ua", &temp);
+	if (rc < 0)
+		chip->dt.s3_entry_ibat_ua = -EINVAL;
+	else
+		chip->dt.s3_entry_ibat_ua = temp;
+
+	rc = of_property_read_u32(node, "qcom,s3-entry-ibat-ua", &temp);
+	if (rc < 0)
+		chip->dt.s3_exit_ibat_ua = -EINVAL;
+	else
+		chip->dt.s3_exit_ibat_ua = temp;
+
+	/* VBAT thresholds */
+	rc = of_property_read_u32(node, "qcom,vbatt-empty-mv", &temp);
+	if (rc < 0)
+		chip->dt.vbatt_empty_mv = DEFAULT_VBATT_EMPTY_MV;
+	else
+		chip->dt.vbatt_empty_mv = temp;
+
+	rc = of_property_read_u32(node, "qcom,vbatt-low-mv", &temp);
+	if (rc < 0)
+		chip->dt.vbatt_low_mv = DEFAULT_VBATT_LOW_MV;
+	else
+		chip->dt.vbatt_low_mv = temp;
+
+	rc = of_property_read_u32(node, "qcom,vbatt-cutoff-mv", &temp);
+	if (rc < 0)
+		chip->dt.vbatt_cutoff_mv = DEFAULT_VBATT_CUTOFF_MV;
+	else
+		chip->dt.vbatt_cutoff_mv = temp;
+
+	/* IBAT thresholds */
+	rc = of_property_read_u32(node, "qcom,qg-iterm-ma", &temp);
+	if (rc < 0)
+		chip->dt.iterm_ma = DEFAULT_ITERM_MA;
+	else
+		chip->dt.iterm_ma = temp;
+
+	rc = of_property_read_u32(node, "qcom,delta-soc", &temp);
+	if (rc < 0)
+		chip->dt.delta_soc = DEFAULT_DELTA_SOC;
+	else
+		chip->dt.delta_soc = temp;
+
+	rc = of_property_read_u32(node, "qcom,rbat-conn-mohm", &temp);
+	if (rc < 0)
+		chip->dt.rbat_conn_mohm = 0;
+	else
+		chip->dt.rbat_conn_mohm = temp;
+
+	qg_dbg(chip, QG_DEBUG_PON, "DT: vbatt_empty_mv=%dmV vbatt_low_mv=%dmV delta_soc=%d\n",
+			chip->dt.vbatt_empty_mv, chip->dt.vbatt_low_mv,
+			chip->dt.delta_soc);
+
+	return 0;
+}
+
+static int process_suspend(struct qpnp_qg *chip)
+{
+	int rc;
+	u32 fifo_rt_length = 0, sleep_fifo_length = 0;
+
+	/* ignore any suspend processing if we are charging */
+	if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
+		qg_dbg(chip, QG_DEBUG_PM, "Charging @ suspend - ignore processing\n");
+		return 0;
+	}
+
+	rc = get_fifo_length(chip, &fifo_rt_length, true);
+	if (rc < 0) {
+		pr_err("Failed to read FIFO RT count, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qg_read(chip, chip->qg_base + QG_S3_SLEEP_OCV_IBAT_CTL1_REG,
+			(u8 *)&sleep_fifo_length, 1);
+	if (rc < 0) {
+		pr_err("Failed to read sleep FIFO count, rc=%d\n", rc);
+		return rc;
+	}
+	sleep_fifo_length &= SLEEP_IBAT_QUALIFIED_LENGTH_MASK;
+	/*
+	 * If the real-time FIFO count is greater than
+	 * the the #fifo to enter sleep, save the FIFO data
+	 * and reset the fifo count.
+	 */
+	if (fifo_rt_length >= (chip->dt.s2_fifo_length - sleep_fifo_length)) {
+		rc = qg_master_hold(chip, true);
+		if (rc < 0) {
+			pr_err("Failed to hold master, rc=%d\n", rc);
+			return rc;
+		}
+
+		rc = qg_process_rt_fifo(chip);
+		if (rc < 0) {
+			pr_err("Failed to process FIFO real-time, rc=%d\n", rc);
+			qg_master_hold(chip, false);
+			return rc;
+		}
+
+		rc = qg_master_hold(chip, false);
+		if (rc < 0) {
+			pr_err("Failed to release master, rc=%d\n", rc);
+			return rc;
+		}
+		/* FIFOs restarted */
+		chip->last_fifo_update_time = ktime_get();
+
+		chip->suspend_data = true;
+	}
+
+	qg_dbg(chip, QG_DEBUG_PM, "FIFO rt_length=%d sleep_fifo_length=%d default_s2_count=%d suspend_data=%d\n",
+			fifo_rt_length, sleep_fifo_length,
+			chip->dt.s2_fifo_length, chip->suspend_data);
+
+	return rc;
+}
+
+static int process_resume(struct qpnp_qg *chip)
+{
+	int rc, batt_temp = 0;
+	u8 status2 = 0, rt_status = 0;
+	u32 ocv_uv = 0, soc = 0;
+
+	rc = qg_read(chip, chip->qg_base + QG_STATUS2_REG, &status2, 1);
+	if (rc < 0) {
+		pr_err("Failed to read status2 register, rc=%d\n", rc);
+		return rc;
+	}
+
+	if (status2 & GOOD_OCV_BIT) {
+		rc = qg_read_ocv(chip, &ocv_uv, GOOD_OCV);
+		if (rc < 0) {
+			pr_err("Failed to read good_ocv, rc=%d\n", rc);
+			return rc;
+		}
+		rc = qg_get_battery_temp(chip, &batt_temp);
+		if (rc < 0) {
+			pr_err("Failed to read BATT_TEMP, rc=%d\n", rc);
+			return rc;
+		}
+
+		chip->kdata.param[QG_GOOD_OCV_UV].data = ocv_uv;
+		chip->kdata.param[QG_GOOD_OCV_UV].valid = true;
+		chip->suspend_data = false;
+		rc = lookup_soc_ocv(&soc, ocv_uv, batt_temp, false);
+		if (rc < 0) {
+			pr_err("Failed to lookup OCV, rc=%d\n", rc);
+			return rc;
+		}
+		chip->catch_up_soc = soc;
+		/* update the SOC immediately */
+		qg_scale_soc(chip, true);
+
+		qg_dbg(chip, QG_DEBUG_PM, "GOOD OCV @ resume good_ocv=%d uV soc=%d\n",
+				ocv_uv, soc);
+	}
+	/*
+	 * If the wakeup was not because of FIFO_DONE
+	 * send the pending data collected during suspend.
+	 */
+	rc = qg_read(chip, chip->qg_base + QG_INT_LATCHED_STS_REG,
+						&rt_status, 1);
+	if (rc < 0) {
+		pr_err("Failed to read latched status register, rc=%d\n", rc);
+		return rc;
+	}
+	rt_status &= FIFO_UPDATE_DONE_INT_LAT_STS_BIT;
+
+	if (!rt_status && chip->suspend_data) {
+		vote(chip->awake_votable, SUSPEND_DATA_VOTER, true, 0);
+		/* signal the read thread */
+		chip->data_ready = true;
+		wake_up_interruptible(&chip->qg_wait_q);
+	}
+
+	qg_dbg(chip, QG_DEBUG_PM, "fifo_done rt_status=%d suspend_data=%d data_ready=%d\n",
+			!!rt_status, chip->suspend_data, chip->data_ready);
+
+	chip->suspend_data = false;
+
+	return rc;
+}
+
+static int qpnp_qg_suspend_noirq(struct device *dev)
+{
+	int rc;
+	struct qpnp_qg *chip = dev_get_drvdata(dev);
+
+	mutex_lock(&chip->data_lock);
+
+	rc = process_suspend(chip);
+	if (rc < 0)
+		pr_err("Failed to process QG suspend, rc=%d\n", rc);
+
+	mutex_unlock(&chip->data_lock);
+
+	return 0;
+}
+
+static int qpnp_qg_resume_noirq(struct device *dev)
+{
+	int rc;
+	struct qpnp_qg *chip = dev_get_drvdata(dev);
+
+	mutex_lock(&chip->data_lock);
+
+	rc = process_resume(chip);
+	if (rc < 0)
+		pr_err("Failed to process QG resume, rc=%d\n", rc);
+
+	mutex_unlock(&chip->data_lock);
+
+	return 0;
+}
+
+static const struct dev_pm_ops qpnp_qg_pm_ops = {
+	.suspend_noirq	= qpnp_qg_suspend_noirq,
+	.resume_noirq	= qpnp_qg_resume_noirq,
+};
+
+static int qpnp_qg_probe(struct platform_device *pdev)
+{
+	int rc = 0, soc = 0;
+	struct qpnp_qg *chip;
+
+	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	chip->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!chip->regmap) {
+		pr_err("Parent regmap is unavailable\n");
+		return -ENXIO;
+	}
+
+	/* VADC for BID */
+	chip->vadc_dev = qpnp_get_vadc(&pdev->dev, "qg");
+	if (IS_ERR(chip->vadc_dev)) {
+		rc = PTR_ERR(chip->vadc_dev);
+		if (rc != -EPROBE_DEFER)
+			pr_err("Failed to find VADC node, rc=%d\n", rc);
+
+		return rc;
+	}
+
+	chip->dev = &pdev->dev;
+	chip->debug_mask = &qg_debug_mask;
+	platform_set_drvdata(pdev, chip);
+	INIT_WORK(&chip->udata_work, process_udata_work);
+	INIT_WORK(&chip->qg_status_change_work, qg_status_change_work);
+	mutex_init(&chip->bus_lock);
+	mutex_init(&chip->soc_lock);
+	mutex_init(&chip->data_lock);
+	init_waitqueue_head(&chip->qg_wait_q);
+
+	rc = qg_parse_dt(chip);
+	if (rc < 0) {
+		pr_err("Failed to parse DT, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qg_hw_init(chip);
+	if (rc < 0) {
+		pr_err("Failed to hw_init, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qg_setup_battery(chip);
+	if (rc < 0) {
+		pr_err("Failed to setup battery, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qg_register_device(chip);
+	if (rc < 0) {
+		pr_err("Failed to register QG char device, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qg_sdam_init(chip->dev);
+	if (rc < 0) {
+		pr_err("Failed to initialize QG SDAM, rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qg_soc_init(chip);
+	if (rc < 0) {
+		pr_err("Failed to initialize SOC scaling init rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qg_determine_pon_soc(chip);
+	if (rc < 0) {
+		pr_err("Failed to determine initial state, rc=%d\n", rc);
+		goto fail_device;
+	}
+
+	chip->awake_votable = create_votable("QG_WS", VOTE_SET_ANY,
+					 qg_awake_cb, chip);
+	if (IS_ERR(chip->awake_votable)) {
+		rc = PTR_ERR(chip->awake_votable);
+		chip->awake_votable = NULL;
+		goto fail_device;
+	}
+
+	chip->vbatt_irq_disable_votable = create_votable("QG_VBATT_IRQ_DISABLE",
+				VOTE_SET_ANY, qg_vbatt_irq_disable_cb, chip);
+	if (IS_ERR(chip->vbatt_irq_disable_votable)) {
+		rc = PTR_ERR(chip->vbatt_irq_disable_votable);
+		chip->vbatt_irq_disable_votable = NULL;
+		goto fail_device;
+	}
+
+	chip->fifo_irq_disable_votable = create_votable("QG_FIFO_IRQ_DISABLE",
+				VOTE_SET_ANY, qg_fifo_irq_disable_cb, chip);
+	if (IS_ERR(chip->fifo_irq_disable_votable)) {
+		rc = PTR_ERR(chip->fifo_irq_disable_votable);
+		chip->fifo_irq_disable_votable = NULL;
+		goto fail_device;
+	}
+
+	chip->good_ocv_irq_disable_votable =
+			create_votable("QG_GOOD_IRQ_DISABLE",
+			VOTE_SET_ANY, qg_good_ocv_irq_disable_cb, chip);
+	if (IS_ERR(chip->good_ocv_irq_disable_votable)) {
+		rc = PTR_ERR(chip->good_ocv_irq_disable_votable);
+		chip->good_ocv_irq_disable_votable = NULL;
+		goto fail_device;
+	}
+
+	rc = qg_init_psy(chip);
+	if (rc < 0) {
+		pr_err("Failed to initialize QG psy, rc=%d\n", rc);
+		goto fail_votable;
+	}
+
+	rc = qg_request_irqs(chip);
+	if (rc < 0) {
+		pr_err("Failed to register QG interrupts, rc=%d\n", rc);
+		goto fail_votable;
+	}
+
+	rc = qg_post_init(chip);
+	if (rc < 0) {
+		pr_err("Failed in qg_post_init rc=%d\n", rc);
+		goto fail_votable;
+	}
+
+	qg_get_battery_capacity(chip, &soc);
+	pr_info("QG initialized! battery_profile=%s SOC=%d\n",
+				qg_get_battery_type(chip), soc);
+
+	return rc;
+
+fail_votable:
+	destroy_votable(chip->awake_votable);
+fail_device:
+	device_destroy(chip->qg_class, chip->dev_no);
+	cdev_del(&chip->qg_cdev);
+	unregister_chrdev_region(chip->dev_no, 1);
+	return rc;
+}
+
+static int qpnp_qg_remove(struct platform_device *pdev)
+{
+	struct qpnp_qg *chip = platform_get_drvdata(pdev);
+
+	qg_batterydata_exit();
+	qg_soc_exit(chip);
+
+	cancel_work_sync(&chip->udata_work);
+	cancel_work_sync(&chip->qg_status_change_work);
+	device_destroy(chip->qg_class, chip->dev_no);
+	cdev_del(&chip->qg_cdev);
+	unregister_chrdev_region(chip->dev_no, 1);
+	mutex_destroy(&chip->bus_lock);
+	mutex_destroy(&chip->data_lock);
+	mutex_destroy(&chip->soc_lock);
+	if (chip->awake_votable)
+		destroy_votable(chip->awake_votable);
+
+	return 0;
+}
+
+static const struct of_device_id match_table[] = {
+	{ .compatible = "qcom,qpnp-qg", },
+	{ },
+};
+
+static struct platform_driver qpnp_qg_driver = {
+	.driver		= {
+		.name		= "qcom,qpnp-qg",
+		.owner		= THIS_MODULE,
+		.of_match_table	= match_table,
+		.pm		= &qpnp_qg_pm_ops,
+	},
+	.probe		= qpnp_qg_probe,
+	.remove		= qpnp_qg_remove,
+};
+module_platform_driver(qpnp_qg_driver);
+
+MODULE_DESCRIPTION("QPNP QG Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c
index 3903a4b..b07efdf 100644
--- a/drivers/power/supply/qcom/qpnp-smb5.c
+++ b/drivers/power/supply/qcom/qpnp-smb5.c
@@ -370,6 +370,7 @@
 	POWER_SUPPLY_PROP_PD_VOLTAGE_MIN,
 	POWER_SUPPLY_PROP_SDP_CURRENT_MAX,
 	POWER_SUPPLY_PROP_CONNECTOR_TYPE,
+	POWER_SUPPLY_PROP_VOLTAGE_MAX,
 };
 
 static int smb5_usb_get_prop(struct power_supply *psy,
diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c
index 4fc60a1..dbadd95 100644
--- a/drivers/power/supply/qcom/smb5-lib.c
+++ b/drivers/power/supply/qcom/smb5-lib.c
@@ -1569,6 +1569,18 @@
 	return rc;
 }
 
+static int smblib_force_vbus_voltage(struct smb_charger *chg, u8 val)
+{
+	int rc;
+
+	rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, val, val);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
+				rc);
+
+	return rc;
+}
+
 int smblib_dp_dm(struct smb_charger *chg, int val)
 {
 	int target_icl_ua, rc = 0;
@@ -1619,6 +1631,21 @@
 		smblib_dbg(chg, PR_PARALLEL, "ICL DOWN ICL=%d reduction=%d\n",
 				target_icl_ua, chg->usb_icl_delta_ua);
 		break;
+	case POWER_SUPPLY_DP_DM_FORCE_5V:
+		rc = smblib_force_vbus_voltage(chg, FORCE_5V_BIT);
+		if (rc < 0)
+			pr_err("Failed to force 5V\n");
+		break;
+	case POWER_SUPPLY_DP_DM_FORCE_9V:
+		rc = smblib_force_vbus_voltage(chg, FORCE_9V_BIT);
+		if (rc < 0)
+			pr_err("Failed to force 9V\n");
+		break;
+	case POWER_SUPPLY_DP_DM_FORCE_12V:
+		rc = smblib_force_vbus_voltage(chg, FORCE_12V_BIT);
+		if (rc < 0)
+			pr_err("Failed to force 12V\n");
+		break;
 	case POWER_SUPPLY_DP_DM_ICL_UP:
 	default:
 		break;
@@ -1745,8 +1772,13 @@
 {
 	switch (chg->real_charger_type) {
 	case POWER_SUPPLY_TYPE_USB_HVDCP:
+	case POWER_SUPPLY_TYPE_USB_HVDCP_3:
 	case POWER_SUPPLY_TYPE_USB_PD:
-		val->intval = MICRO_12V;
+		if (chg->smb_version == PMI632_SUBTYPE)
+			val->intval = MICRO_9V;
+		else
+			val->intval = MICRO_12V;
+		break;
 	default:
 		val->intval = MICRO_5V;
 		break;
diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h
index dfc303e..9a418c8 100644
--- a/drivers/power/supply/qcom/smb5-reg.h
+++ b/drivers/power/supply/qcom/smb5-reg.h
@@ -178,6 +178,8 @@
 #define APSD_RERUN_BIT				BIT(0)
 
 #define CMD_HVDCP_2_REG				(USBIN_BASE + 0x43)
+#define FORCE_12V_BIT				BIT(5)
+#define FORCE_9V_BIT				BIT(4)
 #define FORCE_5V_BIT				BIT(3)
 #define SINGLE_DECREMENT_BIT			BIT(1)
 #define SINGLE_INCREMENT_BIT			BIT(0)
diff --git a/drivers/regulator/msm_gfx_ldo.c b/drivers/regulator/msm_gfx_ldo.c
index 2800607..115a9b7 100644
--- a/drivers/regulator/msm_gfx_ldo.c
+++ b/drivers/regulator/msm_gfx_ldo.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -773,12 +773,34 @@
 	return ldo_vreg->vreg_enabled;
 }
 
+/**
+ * msm_gfx_ldo_list_corner_voltage() - return the ldo voltage mapped to
+ *			the specified voltage corner
+ * @rdev:		Regulator device pointer for the msm_gfx_ldo
+ * @corner:		Voltage corner
+ *
+ * Return: voltage value in microvolts or -EINVAL if the corner is out of range
+ */
+static int msm_gfx_ldo_list_corner_voltage(struct regulator_dev *rdev,
+		int corner)
+{
+	struct msm_gfx_ldo *ldo_vreg  = rdev_get_drvdata(rdev);
+
+	corner -= MIN_CORNER_OFFSET;
+
+	if (corner >= 0 && corner < ldo_vreg->num_corners)
+		return ldo_vreg->open_loop_volt[corner];
+	else
+		return -EINVAL;
+}
+
 static struct regulator_ops msm_gfx_ldo_corner_ops = {
-	.enable		= msm_gfx_ldo_corner_enable,
-	.disable	= msm_gfx_ldo_disable,
-	.is_enabled	= msm_gfx_ldo_is_enabled,
-	.set_voltage	= msm_gfx_ldo_set_corner,
-	.get_voltage	= msm_gfx_ldo_get_corner,
+	.enable			= msm_gfx_ldo_corner_enable,
+	.disable		= msm_gfx_ldo_disable,
+	.is_enabled		= msm_gfx_ldo_is_enabled,
+	.set_voltage		= msm_gfx_ldo_set_corner,
+	.get_voltage		= msm_gfx_ldo_get_corner,
+	.list_corner_voltage	= msm_gfx_ldo_list_corner_voltage,
 };
 
 static int msm_gfx_ldo_get_bypass(struct regulator_dev *rdev,
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index c3b2ca8..770f056 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -250,6 +250,17 @@
 	  deadlocks. It does not run during the bootup process, so it will
 	  not catch any early lockups.
 
+config QCOM_WDOG_IPI_ENABLE
+	bool "Qcom WDT pet optimization"
+	depends on QCOM_WATCHDOG_V2
+	default n
+	help
+	  When this option is enabled, watchdog sends IPI to cores in low power
+	  mode also. For power optimizations, by default watchdog don't ping
+	  cores in low power mode at pettime.
+
+	  To track CPUs health on LPM, or on debug builds enable it.
+
 config QPNP_PBS
 	tristate "PBS trigger support for QPNP PMIC"
 	depends on SPMI
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 0255761..c882403 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -65,9 +65,9 @@
 obj-$(CONFIG_ICNSS) += icnss.o wlan_firmware_service_v01.o
 
 obj-$(CONFIG_MEM_SHARE_QMI_SERVICE)		+= memshare/
+obj-$(CONFIG_MSM_PIL)   +=      peripheral-loader.o
 obj-$(CONFIG_MSM_PIL_SSR_GENERIC) += subsys-pil-tz.o
 obj-$(CONFIG_MSM_PIL_MSS_QDSP6V5) += pil-q6v5.o pil-msa.o pil-q6v5-mss.o
-obj-$(CONFIG_MSM_PIL)   +=      peripheral-loader.o
 
 obj-$(CONFIG_MSM_PERFORMANCE) += msm_performance.o
 
diff --git a/drivers/soc/qcom/ipc_router_glink_xprt.c b/drivers/soc/qcom/ipc_router_glink_xprt.c
index ada7d5e..c93e0e1 100644
--- a/drivers/soc/qcom/ipc_router_glink_xprt.c
+++ b/drivers/soc/qcom/ipc_router_glink_xprt.c
@@ -44,6 +44,7 @@
 #define MIN_FRAG_SZ (IPC_ROUTER_HDR_SIZE + sizeof(union rr_control_msg))
 #define IPC_RTR_XPRT_NAME_LEN (2 * GLINK_NAME_SIZE)
 #define PIL_SUBSYSTEM_NAME_LEN 32
+#define IPC_RTR_WS_NAME_LEN ((2 * GLINK_NAME_SIZE) + 4)
 
 #define MAX_NUM_LO_INTENTS 5
 #define MAX_NUM_MD_INTENTS 3
@@ -60,6 +61,7 @@
  * @transport: Physical Transport Name as identified by Glink.
  * @pil_edge: Edge name understood by PIL.
  * @ipc_rtr_xprt_name: XPRT Name to be registered with IPC Router.
+ * @notify_rx_ws_name: Name of wakesource used in notify rx path.
  * @xprt: IPC Router XPRT structure to contain XPRT specific info.
  * @ch_hndl: Opaque Channel handle returned by GLink.
  * @xprt_wq: Workqueue to queue read & other XPRT related works.
@@ -80,9 +82,11 @@
 	char transport[GLINK_NAME_SIZE];
 	char pil_edge[PIL_SUBSYSTEM_NAME_LEN];
 	char ipc_rtr_xprt_name[IPC_RTR_XPRT_NAME_LEN];
+	char notify_rx_ws_name[IPC_RTR_WS_NAME_LEN];
 	struct msm_ipc_router_xprt xprt;
 	void *ch_hndl;
 	struct workqueue_struct *xprt_wq;
+	struct wakeup_source notify_rxv_ws;
 	struct rw_semaphore ss_reset_rwlock;
 	int ss_reset;
 	void *pil;
@@ -380,6 +384,7 @@
 	glink_rx_done(glink_xprtp->ch_hndl, rx_work->iovec, reuse_intent);
 	kfree(rx_work);
 	up_read(&glink_xprtp->ss_reset_rwlock);
+	__pm_relax(&glink_xprtp->notify_rxv_ws);
 }
 
 static void glink_xprt_open_event(struct work_struct *work)
@@ -494,6 +499,8 @@
 	rx_work->iovec_size = size;
 	rx_work->vbuf_provider = vbuf_provider;
 	rx_work->pbuf_provider = pbuf_provider;
+	if (!glink_xprtp->dynamic_wakeup_source)
+		__pm_stay_awake(&glink_xprtp->notify_rxv_ws);
 	INIT_WORK(&rx_work->work, glink_xprt_read_data);
 	queue_work(glink_xprtp->xprt_wq, &rx_work->work);
 }
@@ -762,7 +769,10 @@
 		kfree(glink_xprtp);
 		return -EFAULT;
 	}
-
+	scnprintf(glink_xprtp->notify_rx_ws_name, IPC_RTR_WS_NAME_LEN,
+			"%s_%s_rx", glink_xprtp->ch_name, glink_xprtp->edge);
+	wakeup_source_init(&glink_xprtp->notify_rxv_ws,
+				glink_xprtp->notify_rx_ws_name);
 	mutex_lock(&glink_xprt_list_lock_lha1);
 	list_add(&glink_xprtp->list, &glink_xprt_list);
 	mutex_unlock(&glink_xprt_list_lock_lha1);
diff --git a/drivers/soc/qcom/rpmh_master_stat.c b/drivers/soc/qcom/rpmh_master_stat.c
index 2c379a0..bc665fd 100644
--- a/drivers/soc/qcom/rpmh_master_stat.c
+++ b/drivers/soc/qcom/rpmh_master_stat.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -13,21 +13,25 @@
 
 #define pr_fmt(fmt) "%s: " fmt, KBUILD_MODNAME
 
-#include <linux/debugfs.h>
-#include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/init.h>
-#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/uaccess.h>
 #include <soc/qcom/smem.h>
+#include "rpmh_master_stat.h"
+
+#define UNIT_DIST 0x14
+#define REG_VALID 0x0
+#define REG_DATA_LO 0x4
+#define REG_DATA_HI 0x8
+
+#define GET_ADDR(REG, UNIT_NO) (REG + (UNIT_DIST * UNIT_NO))
 
 enum master_smem_id {
 	MPSS = 605,
@@ -48,6 +52,14 @@
 	PID_DISPLAY = PID_APSS,
 };
 
+enum profile_data {
+	POWER_DOWN_START,
+	POWER_UP_END,
+	POWER_DOWN_END,
+	POWER_UP_START,
+	NUM_UNIT,
+};
+
 struct msm_rpmh_master_data {
 	char *master_name;
 	enum master_smem_id smem_id;
@@ -66,16 +78,24 @@
 struct msm_rpmh_master_stats {
 	uint32_t version_id;
 	uint32_t counts;
-	uint64_t last_entered_at;
-	uint64_t last_exited_at;
+	uint64_t last_entered;
+	uint64_t last_exited;
 	uint64_t accumulated_duration;
 };
 
+struct msm_rpmh_profile_unit {
+	uint64_t value;
+	uint64_t valid;
+};
+
 struct rpmh_master_stats_prv_data {
 	struct kobj_attribute ka;
 	struct kobject *kobj;
 };
 
+static struct msm_rpmh_master_stats apss_master_stats;
+static void __iomem *rpmh_unit_base;
+
 static DEFINE_MUTEX(rpmh_stats_mutex);
 
 static ssize_t msm_rpmh_master_stats_print_data(char *prvbuf, ssize_t length,
@@ -88,7 +108,7 @@
 			"\tSleep Last Exited At:0x%llx\n"
 			"\tSleep Accumulated Duration:0x%llx\n\n",
 			name, record->version_id, record->counts,
-			record->last_entered_at, record->last_exited_at,
+			record->last_entered, record->last_exited,
 			record->accumulated_duration);
 }
 
@@ -100,13 +120,16 @@
 	unsigned int size = 0;
 	struct msm_rpmh_master_stats *record = NULL;
 
-	/*
-	 * Read SMEM data written by masters
-	 */
-
 	mutex_lock(&rpmh_stats_mutex);
 
-	for (i = 0, length = 0; i < ARRAY_SIZE(rpmh_masters); i++) {
+	/* First Read APSS master stats */
+
+	length = msm_rpmh_master_stats_print_data(buf, PAGE_SIZE,
+						&apss_master_stats, "APSS");
+
+	/* Read SMEM data written by other masters */
+
+	for (i = 0; i < ARRAY_SIZE(rpmh_masters); i++) {
 		record = (struct msm_rpmh_master_stats *) smem_get_entry(
 					rpmh_masters[i].smem_id, &size,
 					rpmh_masters[i].pid, 0);
@@ -122,30 +145,66 @@
 	return length;
 }
 
+static inline void msm_rpmh_apss_master_stats_update(
+				struct msm_rpmh_profile_unit *profile_unit)
+{
+	apss_master_stats.counts++;
+	apss_master_stats.last_entered = profile_unit[POWER_DOWN_END].value;
+	apss_master_stats.last_exited = profile_unit[POWER_UP_START].value;
+	apss_master_stats.accumulated_duration +=
+					(apss_master_stats.last_exited
+					- apss_master_stats.last_entered);
+}
+
+void msm_rpmh_master_stats_update(void)
+{
+	int i;
+	struct msm_rpmh_profile_unit profile_unit[NUM_UNIT];
+
+	if (!rpmh_unit_base)
+		return;
+
+	for (i = POWER_DOWN_END; i < NUM_UNIT; i++) {
+		profile_unit[i].valid = readl_relaxed(rpmh_unit_base +
+						GET_ADDR(REG_VALID, i));
+
+		/*
+		 * Do not update APSS stats if valid bit is not set.
+		 * It means APSS did not execute cx-off sequence.
+		 * This can be due to fall through at some point.
+		 */
+
+		if (!(profile_unit[i].valid & BIT(REG_VALID)))
+			return;
+
+		profile_unit[i].value = readl_relaxed(rpmh_unit_base +
+						GET_ADDR(REG_DATA_LO, i));
+		profile_unit[i].value |= ((uint64_t)
+					readl_relaxed(rpmh_unit_base +
+					GET_ADDR(REG_DATA_HI, i)) << 32);
+	}
+	msm_rpmh_apss_master_stats_update(profile_unit);
+}
+EXPORT_SYMBOL(msm_rpmh_master_stats_update);
+
 static int msm_rpmh_master_stats_probe(struct platform_device *pdev)
 {
 	struct rpmh_master_stats_prv_data *prvdata = NULL;
 	struct kobject *rpmh_master_stats_kobj = NULL;
-	int ret = 0;
+	int ret = -ENOMEM;
 
 	if (!pdev)
 		return -EINVAL;
 
-	prvdata = kzalloc(sizeof(struct rpmh_master_stats_prv_data),
-							GFP_KERNEL);
-	if (!prvdata) {
-		ret = -ENOMEM;
-		goto fail;
-	}
+	prvdata = devm_kzalloc(&pdev->dev, sizeof(*prvdata), GFP_KERNEL);
+	if (!prvdata)
+		return ret;
 
 	rpmh_master_stats_kobj = kobject_create_and_add(
 					"rpmh_stats",
 					power_kobj);
-	if (!rpmh_master_stats_kobj) {
-		ret = -ENOMEM;
-		kfree(prvdata);
-		goto fail;
-	}
+	if (!rpmh_master_stats_kobj)
+		return ret;
 
 	prvdata->kobj = rpmh_master_stats_kobj;
 
@@ -158,14 +217,24 @@
 	ret = sysfs_create_file(prvdata->kobj, &prvdata->ka.attr);
 	if (ret) {
 		pr_err("sysfs_create_file failed\n");
-		kobject_put(prvdata->kobj);
-		kfree(prvdata);
-		goto fail;
+		goto fail_sysfs;
 	}
 
-	platform_set_drvdata(pdev, prvdata);
+	rpmh_unit_base = of_iomap(pdev->dev.of_node, 0);
+	if (!rpmh_unit_base) {
+		pr_err("Failed to get rpmh_unit_base\n");
+		ret = -ENOMEM;
+		goto fail_iomap;
+	}
 
-fail:
+	apss_master_stats.version_id = 0x1;
+	platform_set_drvdata(pdev, prvdata);
+	return ret;
+
+fail_iomap:
+	sysfs_remove_file(prvdata->kobj, &prvdata->ka.attr);
+fail_sysfs:
+	kobject_put(prvdata->kobj);
 	return ret;
 }
 
@@ -181,14 +250,14 @@
 
 	sysfs_remove_file(prvdata->kobj, &prvdata->ka.attr);
 	kobject_put(prvdata->kobj);
-	kfree(prvdata);
 	platform_set_drvdata(pdev, NULL);
+	iounmap(rpmh_unit_base);
 
 	return 0;
 }
 
 static const struct of_device_id rpmh_master_table[] = {
-	{.compatible = "qcom,rpmh-master-stats"},
+	{.compatible = "qcom,rpmh-master-stats-v1"},
 	{},
 };
 
@@ -197,24 +266,11 @@
 	.remove = msm_rpmh_master_stats_remove,
 	.driver = {
 		.name = "msm_rpmh_master_stats",
-		.owner = THIS_MODULE,
 		.of_match_table = rpmh_master_table,
 	},
 };
 
-static int __init msm_rpmh_master_stats_init(void)
-{
-	return platform_driver_register(&msm_rpmh_master_stats_driver);
-}
-
-static void __exit msm_rpmh_master_stats_exit(void)
-{
-	platform_driver_unregister(&msm_rpmh_master_stats_driver);
-}
-
-module_init(msm_rpmh_master_stats_init);
-module_exit(msm_rpmh_master_stats_exit);
-
+module_platform_driver(msm_rpmh_master_stats_driver);
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("MSM RPMH Master Statistics driver");
 MODULE_ALIAS("platform:msm_rpmh_master_stat_log");
diff --git a/drivers/soc/qcom/rpmh_master_stat.h b/drivers/soc/qcom/rpmh_master_stat.h
new file mode 100644
index 0000000..c3fe7dc
--- /dev/null
+++ b/drivers/soc/qcom/rpmh_master_stat.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#if defined(CONFIG_QTI_RPMH_API) && defined(CONFIG_QTI_RPM_STATS_LOG)
+
+void msm_rpmh_master_stats_update(void);
+
+#else
+
+static inline void msm_rpmh_master_stats_update(void) {}
+
+#endif
diff --git a/drivers/soc/qcom/system_pm.c b/drivers/soc/qcom/system_pm.c
index 480a33c..30b73db 100644
--- a/drivers/soc/qcom/system_pm.c
+++ b/drivers/soc/qcom/system_pm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -19,6 +19,7 @@
 #include <soc/qcom/system_pm.h>
 
 #include <clocksource/arm_arch_timer.h>
+#include "rpmh_master_stat.h"
 
 #define PDC_TIME_VALID_SHIFT	31
 #define PDC_TIME_UPPER_MASK	0xFFFFFF
@@ -76,6 +77,7 @@
  */
 void system_sleep_exit(void)
 {
+	msm_rpmh_master_stats_update();
 }
 EXPORT_SYMBOL(system_sleep_exit);
 
diff --git a/drivers/soc/qcom/watchdog_v2.c b/drivers/soc/qcom/watchdog_v2.c
index 6d58d6b..8040d6d 100644
--- a/drivers/soc/qcom/watchdog_v2.c
+++ b/drivers/soc/qcom/watchdog_v2.c
@@ -112,12 +112,22 @@
 module_param(WDT_HZ, long, 0);
 
 /*
+ * Watchdog ipi optimization:
+ * Does not ping cores in low power mode at pet time to save power.
+ * This feature is enabled by default.
+ *
  * On the kernel command line specify
- * watchdog_v2.ipi_opt_en=1 to enable the watchdog ipi ping
- * optimization. By default it is turned off
+ * watchdog_v2.ipi_en=1 to disable this optimization.
+ * Or, can be turned off, by enabling CONFIG_QCOM_WDOG_IPI_ENABLE.
  */
-static int ipi_opt_en;
-module_param(ipi_opt_en, int, 0);
+#ifdef CONFIG_QCOM_WDOG_IPI_ENABLE
+#define IPI_CORES_IN_LPM 1
+#else
+#define IPI_CORES_IN_LPM 0
+#endif
+
+static int ipi_en = IPI_CORES_IN_LPM;
+module_param(ipi_en, int, 0444);
 
 static void dump_cpu_alive_mask(struct msm_watchdog_data *wdog_dd)
 {
@@ -463,7 +473,7 @@
 	struct msm_watchdog_data *wdog_dd =
 			(struct msm_watchdog_data *)platform_get_drvdata(pdev);
 
-	if (ipi_opt_en)
+	if (!ipi_en)
 		cpu_pm_unregister_notifier(&wdog_cpu_pm_nb);
 
 	mutex_lock(&wdog_dd->disable_lock);
@@ -709,7 +719,7 @@
 
 	if (wdog_dd->irq_ppi)
 		enable_percpu_irq(wdog_dd->bark_irq, 0);
-	if (ipi_opt_en)
+	if (!ipi_en)
 		cpu_pm_register_notifier(&wdog_cpu_pm_nb);
 	dev_info(wdog_dd->dev, "MSM Watchdog Initialized\n");
 }
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index 83b46d4..a1602e4 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -510,17 +510,36 @@
 		if (test_task_flag(tsk, TIF_MM_RELEASED))
 			continue;
 
-		if (time_before_eq(jiffies, lowmem_deathpending_timeout)) {
-			if (test_task_lmk_waiting(tsk)) {
-				rcu_read_unlock();
-				mutex_unlock(&scan_mutex);
-				return 0;
-			}
-		}
+		if (oom_reaper) {
+			p = find_lock_task_mm(tsk);
+			if (!p)
+				continue;
 
-		p = find_lock_task_mm(tsk);
-		if (!p)
-			continue;
+			if (test_bit(MMF_OOM_VICTIM, &p->mm->flags)) {
+				if (test_bit(MMF_OOM_SKIP, &p->mm->flags)) {
+					task_unlock(p);
+					continue;
+				} else if (time_before_eq(jiffies,
+						lowmem_deathpending_timeout)) {
+					task_unlock(p);
+					rcu_read_unlock();
+					mutex_unlock(&scan_mutex);
+					return 0;
+				}
+			}
+		} else {
+			if (time_before_eq(jiffies,
+					   lowmem_deathpending_timeout))
+				if (test_task_lmk_waiting(tsk)) {
+					rcu_read_unlock();
+					mutex_unlock(&scan_mutex);
+					return 0;
+				}
+
+			p = find_lock_task_mm(tsk);
+			if (!p)
+				continue;
+		}
 
 		oom_score_adj = p->signal->oom_score_adj;
 		if (oom_score_adj < min_score_adj) {
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 27bf54b..1259654 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -58,4 +58,4 @@
 obj-$(CONFIG_MTK_THERMAL)	+= mtk_thermal.o
 obj-$(CONFIG_GENERIC_ADC_THERMAL)	+= thermal-generic-adc.o
 obj-$(CONFIG_THERMAL_QPNP_ADC_TM)	+= qpnp-adc-tm.o
-obj-$(CONFIG_THERMAL_TSENS)	+= msm-tsens.o tsens2xxx.o tsens-dbg.o tsens-mtc.o
+obj-$(CONFIG_THERMAL_TSENS)	+= msm-tsens.o tsens2xxx.o tsens-dbg.o tsens-mtc.o tsens1xxx.o
diff --git a/drivers/thermal/msm-tsens.c b/drivers/thermal/msm-tsens.c
index fe0a7c7..c137d3d 100644
--- a/drivers/thermal/msm-tsens.c
+++ b/drivers/thermal/msm-tsens.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -49,6 +49,11 @@
 	return tmdev->ops->hw_init(tmdev);
 }
 
+static int tsens_calib(struct tsens_device *tmdev)
+{
+	return tmdev->ops->calibrate(tmdev);
+}
+
 static int tsens_register_interrupts(struct tsens_device *tmdev)
 {
 	if (tmdev->ops->interrupts_reg)
@@ -82,6 +87,9 @@
 	{	.compatible = "qcom,tsens24xx",
 		.data = &data_tsens24xx,
 	},
+	{	.compatible = "qcom,msm8937-tsens",
+		.data = &data_tsens14xx,
+	},
 	{}
 };
 MODULE_DEVICE_TABLE(of, tsens_table);
@@ -97,6 +105,7 @@
 	struct device_node *of_node = pdev->dev.of_node;
 	const struct of_device_id *id;
 	const struct tsens_data *data;
+	int rc = 0;
 	struct resource *res_tsens_mem;
 
 	if (!of_match_node(tsens_table, of_node)) {
@@ -150,7 +159,27 @@
 		return PTR_ERR(tmdev->tsens_tm_addr);
 	}
 
-	return 0;
+	/* TSENS eeprom register region */
+	res_tsens_mem = platform_get_resource_byname(pdev,
+				IORESOURCE_MEM, "tsens_eeprom_physical");
+	if (!res_tsens_mem) {
+		pr_debug("Could not get tsens physical address resource\n");
+	} else {
+		tmdev->tsens_calib_addr = devm_ioremap_resource(&pdev->dev,
+								res_tsens_mem);
+		if (IS_ERR(tmdev->tsens_calib_addr)) {
+			dev_err(&pdev->dev, "Failed to IO map TSENS EEPROM registers.\n");
+			rc = PTR_ERR(tmdev->tsens_calib_addr);
+		}  else {
+			rc = tsens_calib(tmdev);
+			if (rc) {
+				pr_err("Error initializing TSENS controller\n");
+				return rc;
+			}
+		}
+	}
+
+	return rc;
 }
 
 static int tsens_thermal_zone_register(struct tsens_device *tmdev)
diff --git a/drivers/thermal/tsens.h b/drivers/thermal/tsens.h
index ae4741d..885b15c 100644
--- a/drivers/thermal/tsens.h
+++ b/drivers/thermal/tsens.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -23,10 +23,15 @@
 
 #define DEBUG_SIZE				10
 #define TSENS_MAX_SENSORS			16
+#define TSENS_1x_MAX_SENSORS			11
 #define TSENS_CONTROLLER_ID(n)			(n)
 #define TSENS_CTRL_ADDR(n)			(n)
 #define TSENS_TM_SN_STATUS(n)			((n) + 0xa0)
 
+#define ONE_PT_CALIB		0x1
+#define ONE_PT_CALIB2		0x2
+#define TWO_PT_CALIB		0x3
+
 enum tsens_dbg_type {
 	TSENS_DBG_POLL,
 	TSENS_DBG_LOG_TEMP_READS,
@@ -70,6 +75,8 @@
 	int				high_temp;
 	int				low_temp;
 	int				crit_temp;
+	int				high_adc_code;
+	int				low_adc_code;
 };
 
 struct tsens_sensor {
@@ -79,6 +86,8 @@
 	u32				id;
 	const char			*sensor_name;
 	struct tsens_context		thr_state;
+	int				offset;
+	int				slope;
 };
 
 /**
@@ -93,6 +102,7 @@
 	int (*interrupts_reg)(struct tsens_device *);
 	int (*dbg)(struct tsens_device *, u32, u32, int *);
 	int (*sensor_en)(struct tsens_device *, u32);
+	int (*calibrate)(struct tsens_device *);
 };
 
 struct tsens_irqs {
@@ -116,14 +126,15 @@
 	bool				wd_bark;
 	u32				wd_bark_mask;
 	bool				mtc;
+	bool				valid_status_check;
 };
 
 struct tsens_mtc_sysfs {
-	uint32_t	zone_log;
+	u32			zone_log;
 	int			zone_mtc;
 	int			th1;
 	int			th2;
-	uint32_t	zone_hist;
+	u32			zone_hist;
 };
 
 struct tsens_device {
@@ -134,6 +145,7 @@
 	struct regmap_field		*status_field;
 	void __iomem			*tsens_srot_addr;
 	void __iomem			*tsens_tm_addr;
+	void __iomem			*tsens_calib_addr;
 	const struct tsens_ops		*ops;
 	struct tsens_dbg_context	tsens_dbg;
 	spinlock_t			tsens_crit_lock;
@@ -144,6 +156,7 @@
 };
 
 extern const struct tsens_data data_tsens2xxx, data_tsens23xx, data_tsens24xx;
+extern const struct tsens_data data_tsens14xx;
 extern struct list_head tsens_device_list;
 
 #endif /* __QCOM_TSENS_H__ */
diff --git a/drivers/thermal/tsens1xxx.c b/drivers/thermal/tsens1xxx.c
new file mode 100644
index 0000000..e2fad32
--- /dev/null
+++ b/drivers/thermal/tsens1xxx.c
@@ -0,0 +1,654 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/vmalloc.h>
+#include "tsens.h"
+#include "thermal_core.h"
+
+#define TSENS_DRIVER_NAME			"msm-tsens"
+
+#define TSENS_UPPER_LOWER_INTERRUPT_CTRL(n)		(n)
+#define TSENS_INTERRUPT_EN		BIT(0)
+
+#define TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(n)	((n) + 0x04)
+#define TSENS_UPPER_STATUS_CLR		BIT(21)
+#define TSENS_LOWER_STATUS_CLR		BIT(20)
+#define TSENS_UPPER_THRESHOLD_MASK	0xffc00
+#define TSENS_LOWER_THRESHOLD_MASK	0x3ff
+#define TSENS_UPPER_THRESHOLD_SHIFT	10
+
+#define TSENS_S0_STATUS_ADDR(n)		((n) + 0x30)
+#define TSENS_SN_ADDR_OFFSET		0x4
+#define TSENS_SN_STATUS_TEMP_MASK	0x3ff
+#define TSENS_SN_STATUS_LOWER_STATUS	BIT(11)
+#define TSENS_SN_STATUS_UPPER_STATUS	BIT(12)
+#define TSENS_STATUS_ADDR_OFFSET			2
+
+#define TSENS_TRDY_MASK			BIT(0)
+
+#define TSENS_SN_STATUS_ADDR(n)	((n) + 0x44)
+#define TSENS_SN_STATUS_VALID		BIT(14)
+#define TSENS_SN_STATUS_VALID_MASK	0x4000
+#define TSENS_TRDY_ADDR(n)		((n) + 0x84)
+
+#define TSENS_CTRL_ADDR(n)		(n)
+#define TSENS_EN				BIT(0)
+#define TSENS_CTRL_SENSOR_EN_MASK(n)		((n >> 3) & 0x7ff)
+#define TSENS_TRDY_RDY_MIN_TIME		2000
+#define TSENS_TRDY_RDY_MAX_TIME		2100
+#define TSENS_THRESHOLD_MAX_CODE	0x3ff
+#define TSENS_THRESHOLD_MIN_CODE	0x0
+
+/* eeprom layout data for 8937 */
+#define BASE0_MASK	0x000000ff
+#define BASE1_MASK	0xff000000
+#define BASE1_SHIFT	24
+
+#define S0_P1_MASK		0x000001f8
+#define S1_P1_MASK		0x001f8000
+#define S2_P1_MASK_0_4		0xf8000000
+#define S2_P1_MASK_5		0x00000001
+#define S3_P1_MASK		0x00001f80
+#define S4_P1_MASK		0x01f80000
+#define S5_P1_MASK		0x00003f00
+#define S6_P1_MASK		0x03f00000
+#define S7_P1_MASK		0x0000003f
+#define S8_P1_MASK		0x0003f000
+#define S9_P1_MASK		0x0000003f
+#define S10_P1_MASK		0x0003f000
+
+#define S0_P2_MASK		0x00007e00
+#define S1_P2_MASK		0x07e00000
+#define S2_P2_MASK		0x0000007e
+#define S3_P2_MASK		0x0007e000
+#define S4_P2_MASK		0x7e000000
+#define S5_P2_MASK		0x000fc000
+#define S6_P2_MASK		0xfc000000
+#define S7_P2_MASK		0x00000fc0
+#define S8_P2_MASK		0x00fc0000
+#define S9_P2_MASK		0x00000fc0
+#define S10_P2_MASK		0x00fc0000
+
+#define S0_P1_SHIFT     3
+#define S1_P1_SHIFT     15
+#define S2_P1_SHIFT_0_4 27
+#define S2_P1_SHIFT_5   5
+#define S3_P1_SHIFT     7
+#define S4_P1_SHIFT     19
+#define S5_P1_SHIFT     8
+#define S6_P1_SHIFT     20
+#define S8_P1_SHIFT     12
+#define S10_P1_SHIFT    12
+
+#define S0_P2_SHIFT     9
+#define S1_P2_SHIFT     21
+#define S2_P2_SHIFT     1
+#define S3_P2_SHIFT     13
+#define S4_P2_SHIFT     25
+#define S5_P2_SHIFT     14
+#define S6_P2_SHIFT     26
+#define S7_P2_SHIFT     6
+#define S8_P2_SHIFT     18
+#define S9_P2_SHIFT     6
+#define S10_P2_SHIFT    18
+
+#define CAL_SEL_MASK	0x00000007
+
+#define CAL_DEGC_PT1		30
+#define CAL_DEGC_PT2		120
+#define SLOPE_FACTOR		1000
+#define SLOPE_DEFAULT		3200
+
+/*
+ * Use this function on devices where slope and offset calculations
+ * depend on calibration data read from qfprom. On others the slope
+ * and offset values are derived from tz->tzp->slope and tz->tzp->offset
+ * resp.
+ */
+static void compute_intercept_slope(struct tsens_device *tmdev, u32 *p1,
+			     u32 *p2, u32 mode)
+{
+	int i;
+	int num, den;
+
+	for (i = 0; i < TSENS_1x_MAX_SENSORS; i++) {
+		pr_debug(
+			"sensor%d - data_point1:%#x data_point2:%#x\n",
+			i, p1[i], p2[i]);
+
+		tmdev->sensor[i].slope = SLOPE_DEFAULT;
+		if (mode == TWO_PT_CALIB) {
+			/*
+			 * slope (m) = adc_code2 - adc_code1 (y2 - y1)/
+			 *	temp_120_degc - temp_30_degc (x2 - x1)
+			 */
+			num = p2[i] - p1[i];
+			num *= SLOPE_FACTOR;
+			den = CAL_DEGC_PT2 - CAL_DEGC_PT1;
+			tmdev->sensor[i].slope = num / den;
+		}
+
+		tmdev->sensor[i].offset = (p1[i] * SLOPE_FACTOR) -
+				(CAL_DEGC_PT1 *
+				tmdev->sensor[i].slope);
+		pr_debug("offset:%d\n", tmdev->sensor[i].offset);
+	}
+}
+
+static int code_to_degc(u32 adc_code, const struct tsens_sensor *sensor)
+{
+	int degc, num, den;
+
+	num = (adc_code * SLOPE_FACTOR) - sensor->offset;
+	den = sensor->slope;
+
+	if (num > 0)
+		degc = num + (den / 2);
+	else if (num < 0)
+		degc = num - (den / 2);
+	else
+		degc = num;
+
+	degc /= den;
+
+	return degc;
+}
+
+static int degc_to_code(int degc, const struct tsens_sensor *sensor)
+{
+	int code = ((degc * sensor->slope)
+		+ sensor->offset)/SLOPE_FACTOR;
+
+	if (code > TSENS_THRESHOLD_MAX_CODE)
+		code = TSENS_THRESHOLD_MAX_CODE;
+	else if (code < TSENS_THRESHOLD_MIN_CODE)
+		code = TSENS_THRESHOLD_MIN_CODE;
+	pr_debug("raw_code:0x%x, degc:%d\n",
+			code, degc);
+	return code;
+}
+
+static int calibrate_8937(struct tsens_device *tmdev)
+{
+	int base0 = 0, base1 = 0, i;
+	u32 p1[TSENS_1x_MAX_SENSORS], p2[TSENS_1x_MAX_SENSORS];
+	int mode = 0, tmp = 0;
+	u32 qfprom_cdata[5] = {0, 0, 0, 0, 0};
+
+	qfprom_cdata[0] = readl_relaxed(tmdev->tsens_calib_addr + 0x1D8);
+	qfprom_cdata[1] = readl_relaxed(tmdev->tsens_calib_addr + 0x1DC);
+	qfprom_cdata[2] = readl_relaxed(tmdev->tsens_calib_addr + 0x210);
+	qfprom_cdata[3] = readl_relaxed(tmdev->tsens_calib_addr + 0x214);
+	qfprom_cdata[4] = readl_relaxed(tmdev->tsens_calib_addr + 0x230);
+
+	mode = (qfprom_cdata[2] & CAL_SEL_MASK);
+	pr_debug("calibration mode is %d\n", mode);
+
+	switch (mode) {
+	case TWO_PT_CALIB:
+		base1 = (qfprom_cdata[1] & BASE1_MASK) >> BASE1_SHIFT;
+		p2[0] = (qfprom_cdata[2] & S0_P2_MASK) >> S0_P2_SHIFT;
+		p2[1] = (qfprom_cdata[2] & S1_P2_MASK) >> S1_P2_SHIFT;
+		p2[2] = (qfprom_cdata[3] & S2_P2_MASK) >> S2_P2_SHIFT;
+		p2[3] = (qfprom_cdata[3] & S3_P2_MASK) >> S3_P2_SHIFT;
+		p2[4] = (qfprom_cdata[3] & S4_P2_MASK) >> S4_P2_SHIFT;
+		p2[5] = (qfprom_cdata[0] & S5_P2_MASK) >> S5_P2_SHIFT;
+		p2[6] = (qfprom_cdata[0] & S6_P2_MASK) >> S6_P2_SHIFT;
+		p2[7] = (qfprom_cdata[1] & S7_P2_MASK) >> S7_P2_SHIFT;
+		p2[8] = (qfprom_cdata[1] & S8_P2_MASK) >> S8_P2_SHIFT;
+		p2[9] = (qfprom_cdata[4] & S9_P2_MASK) >> S9_P2_SHIFT;
+		p2[10] = (qfprom_cdata[4] & S10_P2_MASK) >> S10_P2_SHIFT;
+
+		for (i = 0; i < TSENS_1x_MAX_SENSORS; i++)
+			p2[i] = ((base1 + p2[i]) << 2);
+		/* Fall through */
+	case ONE_PT_CALIB2:
+		base0 = (qfprom_cdata[0] & BASE0_MASK);
+		p1[0] = (qfprom_cdata[2] & S0_P1_MASK) >> S0_P1_SHIFT;
+		p1[1] = (qfprom_cdata[2] & S1_P1_MASK) >> S1_P1_SHIFT;
+		p1[2] = (qfprom_cdata[2] & S2_P1_MASK_0_4) >> S2_P1_SHIFT_0_4;
+		tmp = (qfprom_cdata[3] & S2_P1_MASK_5) << S2_P1_SHIFT_5;
+		p1[2] |= tmp;
+		p1[3] = (qfprom_cdata[3] & S3_P1_MASK) >> S3_P1_SHIFT;
+		p1[4] = (qfprom_cdata[3] & S4_P1_MASK) >> S4_P1_SHIFT;
+		p1[5] = (qfprom_cdata[0] & S5_P1_MASK) >> S5_P1_SHIFT;
+		p1[6] = (qfprom_cdata[0] & S6_P1_MASK) >> S6_P1_SHIFT;
+		p1[7] = (qfprom_cdata[1] & S7_P1_MASK);
+		p1[8] = (qfprom_cdata[1] & S8_P1_MASK) >> S8_P1_SHIFT;
+		p1[9] = (qfprom_cdata[4] & S9_P1_MASK);
+		p1[10] = (qfprom_cdata[4] & S10_P1_MASK) >> S10_P1_SHIFT;
+
+		for (i = 0; i < TSENS_1x_MAX_SENSORS; i++)
+			p1[i] = (((base0) + p1[i]) << 2);
+		break;
+	default:
+		for (i = 0; i < TSENS_1x_MAX_SENSORS; i++) {
+			p1[i] = 500;
+			p2[i] = 780;
+		}
+		break;
+	}
+
+	compute_intercept_slope(tmdev, p1, p2, mode);
+
+	return 0;
+}
+
+static int tsens1xxx_get_temp(struct tsens_sensor *sensor, int *temp)
+{
+	struct tsens_device *tmdev = NULL;
+	unsigned int code;
+	void __iomem *sensor_addr;
+	void __iomem *trdy_addr;
+	int last_temp = 0, last_temp2 = 0, last_temp3 = 0;
+	bool last_temp_valid = false, last_temp2_valid = false;
+	bool last_temp3_valid = false;
+
+	if (!sensor)
+		return -EINVAL;
+
+	tmdev = sensor->tmdev;
+
+	trdy_addr = TSENS_TRDY_ADDR(tmdev->tsens_tm_addr);
+	sensor_addr = TSENS_SN_STATUS_ADDR(tmdev->tsens_tm_addr);
+
+	code = readl_relaxed(sensor_addr +
+			(sensor->hw_id << TSENS_STATUS_ADDR_OFFSET));
+	last_temp = code & TSENS_SN_STATUS_TEMP_MASK;
+
+	if (tmdev->ctrl_data->valid_status_check) {
+		if (code & TSENS_SN_STATUS_VALID)
+			last_temp_valid = true;
+		else {
+			code = readl_relaxed(sensor_addr +
+				(sensor->hw_id << TSENS_STATUS_ADDR_OFFSET));
+			last_temp2 = code & TSENS_SN_STATUS_TEMP_MASK;
+			if (code & TSENS_SN_STATUS_VALID) {
+				last_temp = last_temp2;
+				last_temp2_valid = true;
+			} else {
+				code = readl_relaxed(sensor_addr +
+					(sensor->hw_id <<
+					TSENS_STATUS_ADDR_OFFSET));
+				last_temp3 = code & TSENS_SN_STATUS_TEMP_MASK;
+				if (code & TSENS_SN_STATUS_VALID) {
+					last_temp = last_temp3;
+					last_temp3_valid = true;
+				}
+			}
+		}
+	}
+
+	if ((tmdev->ctrl_data->valid_status_check) &&
+		(!last_temp_valid && !last_temp2_valid && !last_temp3_valid)) {
+		if (last_temp == last_temp2)
+			last_temp = last_temp2;
+		else if (last_temp2 == last_temp3)
+			last_temp = last_temp3;
+	}
+
+	*temp = code_to_degc(last_temp, sensor);
+
+	return 0;
+}
+
+static int tsens_tz_activate_trip_type(struct tsens_sensor *tm_sensor,
+			int trip, enum thermal_device_mode mode)
+{
+	struct tsens_device *tmdev = NULL;
+	unsigned int reg_cntl, code, hi_code, lo_code, mask;
+
+	/* clear the interrupt and unmask */
+	if (!tm_sensor || trip < 0)
+		return -EINVAL;
+
+	tmdev = tm_sensor->tmdev;
+	if (!tmdev)
+		return -EINVAL;
+
+	lo_code = TSENS_THRESHOLD_MIN_CODE;
+	hi_code = TSENS_THRESHOLD_MAX_CODE;
+
+	reg_cntl = readl_relaxed((TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+					(tmdev->tsens_tm_addr) +
+					(tm_sensor->hw_id *
+					TSENS_SN_ADDR_OFFSET)));
+
+	switch (trip) {
+	case THERMAL_TRIP_CONFIGURABLE_HI:
+		tmdev->sensor[tm_sensor->hw_id].thr_state.high_th_state = mode;
+
+		code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
+					>> TSENS_UPPER_THRESHOLD_SHIFT;
+		mask = TSENS_UPPER_STATUS_CLR;
+
+		if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
+			lo_code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
+		break;
+	case THERMAL_TRIP_CONFIGURABLE_LOW:
+		tmdev->sensor[tm_sensor->hw_id].thr_state.low_th_state = mode;
+
+		code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
+		mask = TSENS_LOWER_STATUS_CLR;
+
+		if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
+			hi_code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
+					>> TSENS_UPPER_THRESHOLD_SHIFT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (mode == THERMAL_DEVICE_DISABLED)
+		writel_relaxed(reg_cntl | mask,
+		(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(tmdev->tsens_tm_addr) +
+			(tm_sensor->hw_id * TSENS_SN_ADDR_OFFSET)));
+	else
+		writel_relaxed(reg_cntl & ~mask,
+		(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(tmdev->tsens_tm_addr) +
+		(tm_sensor->hw_id * TSENS_SN_ADDR_OFFSET)));
+	/* Enable the thresholds */
+	mb();
+
+	return 0;
+}
+
+static int tsens1xxx_set_trip_temp(struct tsens_sensor *tm_sensor,
+						int low_temp, int high_temp)
+{
+	unsigned int reg_cntl;
+	unsigned long flags;
+	struct tsens_device *tmdev = NULL;
+	int high_code, low_code, rc = 0;
+
+	if (!tm_sensor)
+		return -EINVAL;
+
+	tmdev = tm_sensor->tmdev;
+	if (!tmdev)
+		return -EINVAL;
+
+	spin_lock_irqsave(&tmdev->tsens_upp_low_lock, flags);
+
+	if (high_temp != INT_MAX) {
+		high_code = degc_to_code(high_temp, tm_sensor);
+		tmdev->sensor[tm_sensor->hw_id].thr_state.high_adc_code =
+							high_code;
+		tmdev->sensor[tm_sensor->hw_id].thr_state.high_temp =
+							high_temp;
+
+		reg_cntl = readl_relaxed(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+					(tmdev->tsens_tm_addr) +
+					(tm_sensor->hw_id *
+					 TSENS_SN_ADDR_OFFSET));
+
+		high_code <<= TSENS_UPPER_THRESHOLD_SHIFT;
+		reg_cntl &= ~TSENS_UPPER_THRESHOLD_MASK;
+		writel_relaxed(reg_cntl | high_code,
+				(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+					(tmdev->tsens_tm_addr) +
+					(tm_sensor->hw_id *
+					TSENS_SN_ADDR_OFFSET)));
+	}
+
+	if (low_temp != INT_MIN) {
+		low_code = degc_to_code(low_temp, tm_sensor);
+		tmdev->sensor[tm_sensor->hw_id].thr_state.low_adc_code =
+							low_code;
+		tmdev->sensor[tm_sensor->hw_id].thr_state.low_temp =
+							low_temp;
+
+		reg_cntl = readl_relaxed(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+					(tmdev->tsens_tm_addr) +
+					(tm_sensor->hw_id *
+					TSENS_SN_ADDR_OFFSET));
+
+		reg_cntl &= ~TSENS_LOWER_THRESHOLD_MASK;
+		writel_relaxed(reg_cntl | low_code,
+				(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+					(tmdev->tsens_tm_addr) +
+					(tm_sensor->hw_id *
+					TSENS_SN_ADDR_OFFSET)));
+	}
+	/* Set trip temperature thresholds */
+	mb();
+
+	if (high_temp != INT_MAX) {
+		rc = tsens_tz_activate_trip_type(tm_sensor,
+				THERMAL_TRIP_CONFIGURABLE_HI,
+				THERMAL_DEVICE_ENABLED);
+		if (rc) {
+			pr_err("trip high enable error :%d\n", rc);
+			goto fail;
+		}
+	} else {
+		rc = tsens_tz_activate_trip_type(tm_sensor,
+				THERMAL_TRIP_CONFIGURABLE_HI,
+				THERMAL_DEVICE_DISABLED);
+		if (rc) {
+			pr_err("trip high disable error :%d\n", rc);
+			goto fail;
+		}
+	}
+
+	if (low_temp != INT_MIN) {
+		rc = tsens_tz_activate_trip_type(tm_sensor,
+				THERMAL_TRIP_CONFIGURABLE_LOW,
+				THERMAL_DEVICE_ENABLED);
+		if (rc) {
+			pr_err("trip low enable activation error :%d\n", rc);
+			goto fail;
+		}
+	} else {
+		rc = tsens_tz_activate_trip_type(tm_sensor,
+				THERMAL_TRIP_CONFIGURABLE_LOW,
+				THERMAL_DEVICE_DISABLED);
+		if (rc) {
+			pr_err("trip low disable error :%d\n", rc);
+			goto fail;
+		}
+	}
+
+fail:
+	spin_unlock_irqrestore(&tmdev->tsens_upp_low_lock, flags);
+	return rc;
+}
+
+static irqreturn_t tsens_irq_thread(int irq, void *data)
+{
+	struct tsens_device *tm = data;
+	unsigned int i, status, threshold, temp, th_temp;
+	unsigned long flags;
+	void __iomem *sensor_status_addr;
+	void __iomem *sensor_status_ctrl_addr;
+	u32 rc = 0, addr_offset;
+
+	sensor_status_addr = TSENS_SN_STATUS_ADDR(tm->tsens_tm_addr);
+	sensor_status_ctrl_addr =
+		TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(tm->tsens_tm_addr);
+
+	for (i = 0; i < TSENS_1x_MAX_SENSORS; i++) {
+		bool upper_thr = false, lower_thr = false;
+
+		if (IS_ERR(tm->sensor[i].tzd))
+			continue;
+
+		rc = tsens1xxx_get_temp(&tm->sensor[i], &temp);
+		if (rc) {
+			pr_debug("Error:%d reading temp sensor:%d\n", rc, i);
+			continue;
+		}
+
+		spin_lock_irqsave(&tm->tsens_upp_low_lock, flags);
+
+		addr_offset = tm->sensor[i].hw_id *
+						TSENS_SN_ADDR_OFFSET;
+		status = readl_relaxed(sensor_status_addr + addr_offset);
+		threshold = readl_relaxed(sensor_status_ctrl_addr +
+								addr_offset);
+
+		if (status & TSENS_SN_STATUS_UPPER_STATUS) {
+			writel_relaxed(threshold | TSENS_UPPER_STATUS_CLR,
+				TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(
+					tm->tsens_tm_addr + addr_offset));
+			th_temp = code_to_degc((threshold &
+					TSENS_UPPER_THRESHOLD_MASK) >>
+					TSENS_UPPER_THRESHOLD_SHIFT,
+					tm->sensor);
+			if (th_temp > temp) {
+				pr_debug("Re-arm high threshold\n");
+				rc = tsens_tz_activate_trip_type(
+						&tm->sensor[i],
+						THERMAL_TRIP_CONFIGURABLE_HI,
+						THERMAL_DEVICE_ENABLED);
+				if (rc)
+					pr_err("high rearm failed");
+			} else {
+				upper_thr = true;
+				tm->sensor[i].thr_state.high_th_state =
+					THERMAL_DEVICE_DISABLED;
+			}
+		}
+
+		if (status & TSENS_SN_STATUS_LOWER_STATUS) {
+			writel_relaxed(threshold | TSENS_LOWER_STATUS_CLR,
+				TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(
+					tm->tsens_tm_addr + addr_offset));
+			th_temp = code_to_degc((threshold &
+					TSENS_LOWER_THRESHOLD_MASK),
+					tm->sensor);
+			if (th_temp < temp) {
+				pr_debug("Re-arm Low threshold\n");
+				rc = tsens_tz_activate_trip_type(
+						&tm->sensor[i],
+						THERMAL_TRIP_CONFIGURABLE_LOW,
+						THERMAL_DEVICE_ENABLED);
+				if (rc)
+					pr_err("low rearm failed");
+			} else {
+				lower_thr = true;
+				tm->sensor[i].thr_state.low_th_state =
+					THERMAL_DEVICE_DISABLED;
+			}
+		}
+		spin_unlock_irqrestore(&tm->tsens_upp_low_lock, flags);
+
+		if (upper_thr || lower_thr) {
+			pr_debug("sensor:%d trigger temp (%d degC)\n",
+				tm->sensor[i].hw_id,
+				code_to_degc((status &
+				TSENS_SN_STATUS_TEMP_MASK),
+				tm->sensor));
+			of_thermal_handle_trip(tm->sensor[i].tzd);
+		}
+	}
+
+	/* Disable monitoring sensor trip threshold for triggered sensor */
+	mb();
+
+	return IRQ_HANDLED;
+}
+
+static int tsens1xxx_hw_sensor_en(struct tsens_device *tmdev,
+					u32 sensor_id)
+{
+	void __iomem *srot_addr;
+	unsigned int srot_val, sensor_en;
+
+	srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_srot_addr + 0x4);
+	srot_val = readl_relaxed(srot_addr);
+	srot_val = TSENS_CTRL_SENSOR_EN_MASK(srot_val);
+
+	sensor_en = ((1 << sensor_id) & srot_val);
+
+	return sensor_en;
+}
+
+static int tsens1xxx_hw_init(struct tsens_device *tmdev)
+{
+	void __iomem *srot_addr;
+	unsigned int srot_val;
+
+	srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_srot_addr + 0x4);
+	srot_val = readl_relaxed(srot_addr);
+	if (!(srot_val & TSENS_EN)) {
+		pr_err("TSENS device is not enabled\n");
+		return -ENODEV;
+	}
+
+	writel_relaxed(TSENS_INTERRUPT_EN,
+			TSENS_UPPER_LOWER_INTERRUPT_CTRL(tmdev->tsens_tm_addr));
+
+	spin_lock_init(&tmdev->tsens_upp_low_lock);
+
+	return 0;
+}
+
+static const struct tsens_irqs tsens1xxx_irqs[] = {
+	{ "tsens-upper-lower", tsens_irq_thread},
+};
+
+static int tsens1xxx_register_interrupts(struct tsens_device *tmdev)
+{
+	struct platform_device *pdev;
+	int i, rc;
+
+	if (!tmdev)
+		return -EINVAL;
+
+	pdev = tmdev->pdev;
+
+	for (i = 0; i < ARRAY_SIZE(tsens1xxx_irqs); i++) {
+		int irq;
+
+		irq = platform_get_irq_byname(pdev, tsens1xxx_irqs[i].name);
+		if (irq < 0) {
+			dev_err(&pdev->dev, "failed to get irq %s\n",
+					tsens1xxx_irqs[i].name);
+			return irq;
+		}
+
+		rc = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+				tsens1xxx_irqs[i].handler,
+				IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+				tsens1xxx_irqs[i].name, tmdev);
+		if (rc) {
+			dev_err(&pdev->dev, "failed to get irq %s\n",
+					tsens1xxx_irqs[i].name);
+			return rc;
+		}
+		enable_irq_wake(irq);
+	}
+
+	return 0;
+}
+
+static const struct tsens_ops ops_tsens1xxx = {
+	.hw_init		= tsens1xxx_hw_init,
+	.get_temp		= tsens1xxx_get_temp,
+	.set_trips		= tsens1xxx_set_trip_temp,
+	.interrupts_reg		= tsens1xxx_register_interrupts,
+	.sensor_en		= tsens1xxx_hw_sensor_en,
+	.calibrate		= calibrate_8937,
+};
+
+const struct tsens_data data_tsens14xx = {
+	.ops			= &ops_tsens1xxx,
+	.valid_status_check	= true,
+	.mtc			= true,
+};
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 89bf6b7..a91dceb0 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -3518,6 +3518,7 @@
 	mdwc->no_vbus_vote_type_c = of_property_read_bool(node,
 					"qcom,no-vbus-vote-with-type-C");
 
+	mutex_init(&mdwc->suspend_resume_mutex);
 	/* Mark type-C as true by default */
 	mdwc->type_c = true;
 
@@ -3543,7 +3544,6 @@
 	if (ret)
 		goto put_psy;
 
-	mutex_init(&mdwc->suspend_resume_mutex);
 	/* Update initial VBUS/ID state from extcon */
 	if (mdwc->extcon_vbus && extcon_get_state(mdwc->extcon_vbus,
 							EXTCON_USB))
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 0fec59c..0390c72 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -36,7 +36,7 @@
 	 SSUSB_GADGET_VBUS_DRAW : CONFIG_USB_GADGET_VBUS_DRAW)
 
 /* disable LPM by default */
-static bool disable_l1_for_hs = true;
+static bool disable_l1_for_hs;
 module_param(disable_l1_for_hs, bool, 0644);
 MODULE_PARM_DESC(disable_l1_for_hs,
 	"Disable support for L1 LPM for HS devices");
diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c
index 4bdfadf..41aa62d 100644
--- a/drivers/usb/gadget/function/f_gsi.c
+++ b/drivers/usb/gadget/function/f_gsi.c
@@ -1655,11 +1655,10 @@
 
 	buf = (rndis_init_msg_type *)req->buf;
 	if (buf->MessageType == RNDIS_MSG_INIT) {
-		gsi->d_port.in_aggr_size = min_t(u32, gsi->d_port.in_aggr_size,
-						gsi->params->dl_max_xfer_size);
-		log_event_dbg("RNDIS host dl_aggr_size:%d in_aggr_size:%d\n",
-				gsi->params->dl_max_xfer_size,
-				gsi->d_port.in_aggr_size);
+		/* honor host dl aggr size */
+		gsi->d_port.in_aggr_size = gsi->params->dl_max_xfer_size;
+		log_event_dbg("RNDIS host dl_aggr_size:%d\n",
+				gsi->params->dl_max_xfer_size);
 	}
 }
 
@@ -2565,7 +2564,7 @@
 		info.out_epname = "gsi-epout";
 		info.in_req_buf_len = GSI_IN_BUFF_SIZE;
 		gsi->d_port.in_aggr_size = GSI_IN_RNDIS_AGGR_SIZE;
-		info.in_req_num_buf = GSI_NUM_IN_BUFFERS;
+		info.in_req_num_buf = GSI_NUM_IN_RNDIS_BUFFERS;
 		gsi->d_port.out_aggr_size = GSI_OUT_AGGR_SIZE;
 		info.out_req_buf_len = GSI_OUT_AGGR_SIZE;
 		info.out_req_num_buf = GSI_NUM_OUT_BUFFERS;
diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h
index 58a7706..71bea5e 100644
--- a/drivers/usb/gadget/function/f_gsi.h
+++ b/drivers/usb/gadget/function/f_gsi.h
@@ -34,13 +34,13 @@
 #define GSI_MAX_CTRL_PKT_SIZE 4096
 #define GSI_CTRL_DTR (1 << 0)
 
-
+#define GSI_NUM_IN_RNDIS_BUFFERS 50
 #define GSI_NUM_IN_BUFFERS 15
 #define GSI_IN_BUFF_SIZE 2048
 #define GSI_NUM_OUT_BUFFERS 14
 #define GSI_OUT_AGGR_SIZE 24576
 
-#define GSI_IN_RNDIS_AGGR_SIZE 9216
+#define GSI_IN_RNDIS_AGGR_SIZE 16384
 #define GSI_IN_MBIM_AGGR_SIZE 16384
 #define GSI_IN_RMNET_AGGR_SIZE 16384
 #define GSI_ECM_AGGR_SIZE 2048
diff --git a/drivers/usb/gadget/function/u_bam_dmux.c b/drivers/usb/gadget/function/u_bam_dmux.c
new file mode 100644
index 0000000..2ad184a
--- /dev/null
+++ b/drivers/usb/gadget/function/u_bam_dmux.c
@@ -0,0 +1,2645 @@
+/* Copyright (c) 2011-2018, Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/termios.h>
+#include <soc/qcom/smd.h>
+#include <linux/netdevice.h>
+#include <linux/debugfs.h>
+#include <linux/bitops.h>
+#include <linux/termios.h>
+
+#include <soc/qcom/bam_dmux.h>
+
+#include <linux/usb/msm_hsusb.h>
+#include <linux/usb/usb_ctrl_qti.h>
+#include <linux/usb_bam.h>
+
+#include "usb_gadget_xport.h"
+#include "u_rmnet.h"
+
+#define BAM_N_PORTS	 2
+#define BAM2BAM_N_PORTS	 4
+
+static struct workqueue_struct *gbam_wq;
+static int n_bam_ports;
+static int n_bam2bam_ports;
+static unsigned int n_tx_req_queued;
+
+static unsigned int bam_ch_ids[BAM_N_PORTS] = {
+	BAM_DMUX_USB_RMNET_0,
+	BAM_DMUX_USB_DPL
+};
+
+static char bam_ch_names[BAM_N_PORTS][BAM_DMUX_CH_NAME_MAX_LEN];
+
+static const enum ipa_client_type usb_prod[BAM2BAM_N_PORTS] = {
+	IPA_CLIENT_USB_PROD, IPA_CLIENT_USB2_PROD,
+	IPA_CLIENT_USB3_PROD, IPA_CLIENT_USB4_PROD
+};
+static const enum ipa_client_type usb_cons[BAM2BAM_N_PORTS] = {
+	IPA_CLIENT_USB_CONS, IPA_CLIENT_USB2_CONS,
+	IPA_CLIENT_USB3_CONS, IPA_CLIENT_USB4_CONS
+};
+
+#define BAM_PENDING_PKTS_LIMIT			220
+#define BAM_MUX_TX_PKT_DROP_THRESHOLD		1000
+#define BAM_MUX_RX_PKT_FCTRL_EN_TSHOLD		500
+#define BAM_MUX_RX_PKT_FCTRL_DIS_TSHOLD		300
+#define BAM_MUX_RX_PKT_FLOW_CTRL_SUPPORT	1
+
+#define BAM_MUX_HDR				8
+
+#define BAM_MUX_RX_Q_SIZE			128
+#define BAM_MUX_TX_Q_SIZE			200
+#define BAM_MUX_RX_REQ_SIZE			2048   /* Must be 1KB aligned */
+
+#define DL_INTR_THRESHOLD			20
+#define BAM_PENDING_BYTES_LIMIT			(50 * BAM_MUX_RX_REQ_SIZE)
+#define BAM_PENDING_BYTES_FCTRL_EN_TSHOLD	(BAM_PENDING_BYTES_LIMIT / 3)
+
+/* Extra buffer size to allocate for tx */
+#define EXTRA_ALLOCATION_SIZE_U_BAM	128
+
+static unsigned int bam_pending_pkts_limit = BAM_PENDING_PKTS_LIMIT;
+module_param(bam_pending_pkts_limit, uint, 0644);
+
+static unsigned int bam_pending_bytes_limit = BAM_PENDING_BYTES_LIMIT;
+module_param(bam_pending_bytes_limit, uint, 0644);
+
+static unsigned int bam_pending_bytes_fctrl_en_thold =
+					BAM_PENDING_BYTES_FCTRL_EN_TSHOLD;
+module_param(bam_pending_bytes_fctrl_en_thold, uint, 0644);
+
+static unsigned int bam_mux_tx_pkt_drop_thld = BAM_MUX_TX_PKT_DROP_THRESHOLD;
+module_param(bam_mux_tx_pkt_drop_thld, uint, 0644);
+
+static unsigned int bam_mux_rx_fctrl_en_thld = BAM_MUX_RX_PKT_FCTRL_EN_TSHOLD;
+module_param(bam_mux_rx_fctrl_en_thld, uint, 0644);
+
+static unsigned int bam_mux_rx_fctrl_support = BAM_MUX_RX_PKT_FLOW_CTRL_SUPPORT;
+module_param(bam_mux_rx_fctrl_support, uint, 0644);
+
+static unsigned int bam_mux_rx_fctrl_dis_thld = BAM_MUX_RX_PKT_FCTRL_DIS_TSHOLD;
+module_param(bam_mux_rx_fctrl_dis_thld, uint, 0644);
+
+static unsigned int bam_mux_tx_q_size = BAM_MUX_TX_Q_SIZE;
+module_param(bam_mux_tx_q_size, uint, 0644);
+
+static unsigned int bam_mux_rx_q_size = BAM_MUX_RX_Q_SIZE;
+module_param(bam_mux_rx_q_size, uint, 0644);
+
+static unsigned long bam_mux_rx_req_size = BAM_MUX_RX_REQ_SIZE;
+module_param(bam_mux_rx_req_size, ulong, 0444);
+
+static unsigned int dl_intr_threshold = DL_INTR_THRESHOLD;
+module_param(dl_intr_threshold, uint, 0644);
+
+#define BAM_CH_OPENED			BIT(0)
+#define BAM_CH_READY			BIT(1)
+#define BAM_CH_WRITE_INPROGRESS		BIT(2)
+
+enum u_bam_event_type {
+	U_BAM_DISCONNECT_E = 0,
+	U_BAM_CONNECT_E,
+	U_BAM_SUSPEND_E,
+	U_BAM_RESUME_E
+};
+
+struct sys2ipa_sw {
+	void		*teth_priv;
+	ipa_notify_cb	teth_cb;
+};
+
+struct bam_ch_info {
+	unsigned long		flags;
+	unsigned int		id;
+
+	struct list_head        tx_idle;
+	struct sk_buff_head	tx_skb_q;
+
+	struct list_head        rx_idle;
+	struct sk_buff_head	rx_skb_q;
+	struct sk_buff_head	rx_skb_idle;
+
+	struct gbam_port	*port;
+	struct work_struct	write_tobam_w;
+	struct work_struct	write_tohost_w;
+
+	struct usb_request	*rx_req;
+	struct usb_request	*tx_req;
+	bool			tx_req_dequeued;
+	bool			rx_req_dequeued;
+
+	u32			src_pipe_idx;
+	u32			dst_pipe_idx;
+	u8			src_connection_idx;
+	u8			dst_connection_idx;
+	enum usb_ctrl		usb_bam_type;
+
+	enum transport_type trans;
+	struct usb_bam_connect_ipa_params ipa_params;
+
+	/* added to support sys to ipa sw UL path */
+	struct sys2ipa_sw	ul_params;
+	enum usb_bam_pipe_type	src_pipe_type;
+	enum usb_bam_pipe_type	dst_pipe_type;
+
+	/* stats */
+	unsigned int		pending_pkts_with_bam;
+	unsigned int		pending_bytes_with_bam;
+	unsigned int		tohost_drp_cnt;
+	unsigned int		tomodem_drp_cnt;
+	unsigned int		tx_len;
+	unsigned int		rx_len;
+	unsigned long		to_modem;
+	unsigned long		to_host;
+	unsigned int		rx_flow_control_disable;
+	unsigned int		rx_flow_control_enable;
+	unsigned int		rx_flow_control_triggered;
+	unsigned int		max_num_pkts_pending_with_bam;
+	unsigned int		max_bytes_pending_with_bam;
+	unsigned int		delayed_bam_mux_write_done;
+	unsigned long		skb_expand_cnt;
+};
+
+struct gbam_port {
+	bool			is_connected;
+	enum u_bam_event_type	last_event;
+	unsigned int		port_num;
+	spinlock_t		port_lock_ul;
+	spinlock_t		port_lock_dl;
+	spinlock_t		port_lock;
+
+	struct grmnet		*port_usb;
+	struct usb_gadget	*gadget;
+
+	struct bam_ch_info	data_ch;
+
+	struct work_struct	connect_w;
+	struct work_struct	disconnect_w;
+	struct work_struct	suspend_w;
+	struct work_struct	resume_w;
+};
+
+static struct bam_portmaster {
+	struct gbam_port *port;
+	struct platform_driver pdrv;
+} bam_ports[BAM_N_PORTS];
+
+struct  u_bam_data_connect_info {
+	u32 usb_bam_pipe_idx;
+	u32 peer_pipe_idx;
+	unsigned long usb_bam_handle;
+};
+
+struct gbam_port *bam2bam_ports[BAM2BAM_N_PORTS];
+static void gbam_start_rx(struct gbam_port *port);
+static void gbam_start_endless_rx(struct gbam_port *port);
+static void gbam_start_endless_tx(struct gbam_port *port);
+static void gbam_notify(void *p, int event, unsigned long data);
+static void gbam_data_write_tobam(struct work_struct *w);
+
+/*---------------misc functions---------------- */
+static void gbam_free_requests(struct usb_ep *ep, struct list_head *head)
+{
+	struct usb_request	*req;
+
+	while (!list_empty(head)) {
+		req = list_entry(head->next, struct usb_request, list);
+		list_del(&req->list);
+		usb_ep_free_request(ep, req);
+	}
+}
+
+static int gbam_alloc_requests(struct usb_ep *ep, struct list_head *head,
+		int num,
+		void (*cb)(struct usb_ep *ep, struct usb_request *),
+		gfp_t flags)
+{
+	int i;
+	struct usb_request *req;
+
+	pr_debug("%s: ep:%pK head:%pK num:%d cb:%pK", __func__,
+			ep, head, num, cb);
+
+	for (i = 0; i < num; i++) {
+		req = usb_ep_alloc_request(ep, flags);
+		if (!req) {
+			pr_debug("%s: req allocated:%d\n", __func__, i);
+			return list_empty(head) ? -ENOMEM : 0;
+		}
+		req->complete = cb;
+		list_add(&req->list, head);
+	}
+
+	return 0;
+}
+
+static inline dma_addr_t gbam_get_dma_from_skb(struct sk_buff *skb)
+{
+	return *((dma_addr_t *)(skb->cb));
+}
+
+/* This function should be called with port_lock_ul lock held */
+static struct sk_buff *gbam_alloc_skb_from_pool(struct gbam_port *port)
+{
+	struct bam_ch_info *d;
+	struct sk_buff *skb;
+	dma_addr_t      skb_buf_dma_addr;
+	struct usb_gadget *gadget;
+
+	if (!port)
+		return NULL;
+
+	d = &port->data_ch;
+	if (!d)
+		return NULL;
+
+	if (d->rx_skb_idle.qlen == 0) {
+		/*
+		 * In case skb idle pool is empty, we allow to allocate more
+		 * skbs so we dynamically enlarge the pool size when needed.
+		 * Therefore, in steady state this dynamic allocation will
+		 * stop when the pool will arrive to its optimal size.
+		 */
+		pr_debug("%s: allocate skb\n", __func__);
+		skb = alloc_skb(bam_mux_rx_req_size + BAM_MUX_HDR, GFP_ATOMIC);
+
+		if (!skb)
+			goto alloc_exit;
+
+		skb_reserve(skb, BAM_MUX_HDR);
+
+		if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
+
+			gadget = port->port_usb->gadget;
+
+			skb_buf_dma_addr =
+				dma_map_single(&gadget->dev, skb->data,
+					bam_mux_rx_req_size, DMA_BIDIRECTIONAL);
+
+			if (dma_mapping_error(&gadget->dev, skb_buf_dma_addr)) {
+				pr_err("%s: Could not DMA map SKB buffer\n",
+					__func__);
+				skb_buf_dma_addr = DMA_ERROR_CODE;
+			}
+		} else {
+			skb_buf_dma_addr = DMA_ERROR_CODE;
+		}
+
+
+		memcpy(skb->cb, &skb_buf_dma_addr,
+			sizeof(skb_buf_dma_addr));
+
+	} else {
+		pr_debug("%s: pull skb from pool\n", __func__);
+		skb = __skb_dequeue(&d->rx_skb_idle);
+		if (skb_headroom(skb) < BAM_MUX_HDR)
+			skb_reserve(skb, BAM_MUX_HDR);
+	}
+
+alloc_exit:
+	return skb;
+}
+
+/* This function should be called with port_lock_ul lock held */
+static void gbam_free_skb_to_pool(struct gbam_port *port, struct sk_buff *skb)
+{
+	struct bam_ch_info *d;
+
+	if (!port)
+		return;
+	d = &port->data_ch;
+
+	skb->len = 0;
+	skb_reset_tail_pointer(skb);
+	__skb_queue_tail(&d->rx_skb_idle, skb);
+}
+
+static void gbam_free_rx_skb_idle_list(struct gbam_port *port)
+{
+	struct bam_ch_info *d;
+	struct sk_buff *skb;
+	dma_addr_t dma_addr;
+	struct usb_gadget *gadget = NULL;
+
+	if (!port)
+		return;
+	d = &port->data_ch;
+
+	gadget = port->port_usb->gadget;
+
+	while (d->rx_skb_idle.qlen > 0) {
+		skb = __skb_dequeue(&d->rx_skb_idle);
+		dma_addr = gbam_get_dma_from_skb(skb);
+
+		if (gadget && dma_addr != DMA_ERROR_CODE) {
+			dma_unmap_single(&gadget->dev, dma_addr,
+				bam_mux_rx_req_size, DMA_BIDIRECTIONAL);
+
+			dma_addr = DMA_ERROR_CODE;
+			memcpy(skb->cb, &dma_addr,
+				sizeof(dma_addr));
+		}
+		dev_kfree_skb_any(skb);
+	}
+}
+
+/*----- sys2bam towards the IPA --------------- */
+static void gbam_ipa_sys2bam_notify_cb(void *priv, enum ipa_dp_evt_type event,
+		unsigned long data)
+{
+	struct sys2ipa_sw	*ul = (struct sys2ipa_sw *)priv;
+	struct gbam_port	*port;
+	struct bam_ch_info	*d;
+
+	switch (event) {
+	case IPA_WRITE_DONE:
+		d = container_of(ul, struct bam_ch_info, ul_params);
+		port = container_of(d, struct gbam_port, data_ch);
+		/* call into bam_demux functionality that'll recycle the data */
+		gbam_notify(port, BAM_DMUX_WRITE_DONE, data);
+		break;
+	case IPA_RECEIVE:
+		/* call the callback given by tethering driver init function
+		 * (and was given to ipa_connect)
+		 */
+		if (ul->teth_cb)
+			ul->teth_cb(ul->teth_priv, event, data);
+		break;
+	default:
+		/* unexpected event */
+		pr_err("%s: unexpected event %d\n", __func__, event);
+		break;
+	}
+}
+
+
+/*--------------------------------------------- */
+
+/*------------data_path----------------------------*/
+static void gbam_write_data_tohost(struct gbam_port *port)
+{
+	unsigned long			flags;
+	struct bam_ch_info		*d = &port->data_ch;
+	struct sk_buff			*skb;
+	struct sk_buff			*new_skb;
+	int				ret;
+	int				tail_room = 0;
+	int				extra_alloc = 0;
+	struct usb_request		*req;
+	struct usb_ep			*ep;
+
+	spin_lock_irqsave(&port->port_lock_dl, flags);
+	if (!port->port_usb) {
+		spin_unlock_irqrestore(&port->port_lock_dl, flags);
+		return;
+	}
+
+	ep = port->port_usb->in;
+
+	while (!list_empty(&d->tx_idle)) {
+		skb = __skb_dequeue(&d->tx_skb_q);
+		if (!skb)
+			break;
+
+		/*
+		 * Some UDC requires allocation of some extra bytes for
+		 * TX buffer due to hardware requirement. Check if extra
+		 * bytes are already there, otherwise allocate new buffer
+		 * with extra bytes and do memcpy.
+		 */
+		if (port->gadget->extra_buf_alloc)
+			extra_alloc = EXTRA_ALLOCATION_SIZE_U_BAM;
+		tail_room = skb_tailroom(skb);
+		if (tail_room < extra_alloc) {
+			pr_debug("%s: tail_room  %d less than %d\n", __func__,
+					tail_room, extra_alloc);
+			new_skb = skb_copy_expand(skb, 0, extra_alloc -
+					tail_room, GFP_ATOMIC);
+			if (!new_skb) {
+				pr_err("skb_copy_expand failed\n");
+				break;
+			}
+			dev_kfree_skb_any(skb);
+			skb = new_skb;
+			d->skb_expand_cnt++;
+		}
+
+		req = list_first_entry(&d->tx_idle,
+				struct usb_request,
+				list);
+		req->context = skb;
+		req->buf = skb->data;
+		req->length = skb->len;
+		n_tx_req_queued++;
+		if (n_tx_req_queued == dl_intr_threshold) {
+			req->no_interrupt = 0;
+			n_tx_req_queued = 0;
+		} else {
+			req->no_interrupt = 1;
+		}
+
+		/* Send ZLP in case packet length is multiple of maxpacksize */
+		req->zero = 1;
+
+		list_del(&req->list);
+
+		spin_unlock(&port->port_lock_dl);
+		ret = usb_ep_queue(ep, req, GFP_ATOMIC);
+		spin_lock(&port->port_lock_dl);
+		if (ret) {
+			pr_err_ratelimited("%s: usb epIn failed with %d\n",
+					 __func__, ret);
+			list_add(&req->list, &d->tx_idle);
+			dev_kfree_skb_any(skb);
+			break;
+		}
+		d->to_host++;
+	}
+	spin_unlock_irqrestore(&port->port_lock_dl, flags);
+}
+
+static void gbam_write_data_tohost_w(struct work_struct *w)
+{
+	struct bam_ch_info	*d;
+	struct gbam_port	*port;
+
+	d = container_of(w, struct bam_ch_info, write_tohost_w);
+	port = d->port;
+
+	gbam_write_data_tohost(port);
+}
+
+void gbam_data_recv_cb(void *p, struct sk_buff *skb)
+{
+	struct gbam_port	*port = p;
+	struct bam_ch_info	*d = &port->data_ch;
+	unsigned long		flags;
+
+	if (!skb)
+		return;
+
+	pr_debug("%s: p:%pK#%d d:%pK skb_len:%d\n", __func__,
+			port, port->port_num, d, skb->len);
+
+	spin_lock_irqsave(&port->port_lock_dl, flags);
+	if (!port->port_usb) {
+		spin_unlock_irqrestore(&port->port_lock_dl, flags);
+		dev_kfree_skb_any(skb);
+		return;
+	}
+
+	if (d->tx_skb_q.qlen > bam_mux_tx_pkt_drop_thld) {
+		d->tohost_drp_cnt++;
+		if (printk_ratelimited())
+			pr_err("%s: tx pkt dropped: tx_drop_cnt:%u\n",
+					__func__, d->tohost_drp_cnt);
+		spin_unlock_irqrestore(&port->port_lock_dl, flags);
+		dev_kfree_skb_any(skb);
+		return;
+	}
+
+	__skb_queue_tail(&d->tx_skb_q, skb);
+	spin_unlock_irqrestore(&port->port_lock_dl, flags);
+
+	gbam_write_data_tohost(port);
+}
+
+void gbam_data_write_done(void *p, struct sk_buff *skb)
+{
+	struct gbam_port	*port = p;
+	struct bam_ch_info	*d = &port->data_ch;
+	unsigned long		flags;
+
+	if (!skb)
+		return;
+
+	spin_lock_irqsave(&port->port_lock_ul, flags);
+
+	d->pending_pkts_with_bam--;
+	d->pending_bytes_with_bam -= skb->len;
+	gbam_free_skb_to_pool(port, skb);
+
+	pr_debug("%s:port:%pK d:%pK tom:%lu ppkt:%u pbytes:%u pno:%d\n",
+		       __func__, port, d, d->to_modem, d->pending_pkts_with_bam,
+		       d->pending_bytes_with_bam, port->port_num);
+
+	spin_unlock_irqrestore(&port->port_lock_ul, flags);
+
+	/*
+	 * If BAM doesn't have much pending data then push new data from here:
+	 * write_complete notify only to avoid any underruns due to wq latency
+	 */
+	if (d->pending_bytes_with_bam <= bam_pending_bytes_fctrl_en_thold) {
+		gbam_data_write_tobam(&d->write_tobam_w);
+	} else {
+		d->delayed_bam_mux_write_done++;
+		queue_work(gbam_wq, &d->write_tobam_w);
+	}
+}
+
+/* This function should be called with port_lock_ul spinlock acquired */
+static bool gbam_ul_bam_limit_reached(struct bam_ch_info *data_ch)
+{
+	unsigned int	curr_pending_pkts = data_ch->pending_pkts_with_bam;
+	unsigned int	curr_pending_bytes = data_ch->pending_bytes_with_bam;
+	struct sk_buff	*skb;
+
+	if (curr_pending_pkts >= bam_pending_pkts_limit)
+		return true;
+
+	/* check if next skb length doesn't exceed pending_bytes_limit */
+	skb = skb_peek(&data_ch->rx_skb_q);
+	if (!skb)
+		return false;
+
+	if ((curr_pending_bytes + skb->len) > bam_pending_bytes_limit)
+		return true;
+	else
+		return false;
+}
+
+static void gbam_data_write_tobam(struct work_struct *w)
+{
+	struct gbam_port	*port;
+	struct bam_ch_info	*d;
+	struct sk_buff		*skb;
+	unsigned long		flags;
+	int			ret;
+	int			qlen;
+
+	d = container_of(w, struct bam_ch_info, write_tobam_w);
+	port = d->port;
+
+	spin_lock_irqsave(&port->port_lock_ul, flags);
+	if (!port->port_usb) {
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
+		return;
+	}
+	/* Bail out if already in progress */
+	if (test_bit(BAM_CH_WRITE_INPROGRESS, &d->flags)) {
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
+		return;
+	}
+
+	set_bit(BAM_CH_WRITE_INPROGRESS, &d->flags);
+
+	while (!gbam_ul_bam_limit_reached(d) &&
+			(d->trans != USB_GADGET_XPORT_BAM2BAM_IPA ||
+			usb_bam_get_prod_granted(d->usb_bam_type,
+					d->dst_connection_idx))) {
+		skb =  __skb_dequeue(&d->rx_skb_q);
+		if (!skb)
+			break;
+
+		d->pending_pkts_with_bam++;
+		d->pending_bytes_with_bam += skb->len;
+		d->to_modem++;
+
+		pr_debug("%s: port:%pK d:%pK tom:%lu ppkts:%u pbytes:%u pno:%d\n",
+				__func__, port, d,
+				d->to_modem, d->pending_pkts_with_bam,
+				d->pending_bytes_with_bam, port->port_num);
+
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
+		if (d->src_pipe_type == USB_BAM_PIPE_SYS2BAM) {
+			dma_addr_t         skb_dma_addr;
+			struct ipa_tx_meta ipa_meta = {0x0};
+
+			skb_dma_addr = gbam_get_dma_from_skb(skb);
+			if (skb_dma_addr != DMA_ERROR_CODE) {
+				ipa_meta.dma_address = skb_dma_addr;
+				ipa_meta.dma_address_valid = true;
+			}
+
+			ret = ipa_tx_dp(usb_prod[port->port_num],
+				skb,
+				&ipa_meta);
+		} else {
+			ret = msm_bam_dmux_write(d->id, skb);
+		}
+
+		spin_lock_irqsave(&port->port_lock_ul, flags);
+		if (ret) {
+			pr_debug("%s: write error:%d\n", __func__, ret);
+			d->pending_pkts_with_bam--;
+			d->pending_bytes_with_bam -= skb->len;
+			d->to_modem--;
+			d->tomodem_drp_cnt++;
+			gbam_free_skb_to_pool(port, skb);
+			break;
+		}
+		if (d->pending_pkts_with_bam > d->max_num_pkts_pending_with_bam)
+			d->max_num_pkts_pending_with_bam =
+					d->pending_pkts_with_bam;
+		if (d->pending_bytes_with_bam > d->max_bytes_pending_with_bam)
+			d->max_bytes_pending_with_bam =
+					d->pending_bytes_with_bam;
+	}
+
+	qlen = d->rx_skb_q.qlen;
+
+	clear_bit(BAM_CH_WRITE_INPROGRESS, &d->flags);
+	spin_unlock_irqrestore(&port->port_lock_ul, flags);
+
+	if (qlen < bam_mux_rx_fctrl_dis_thld) {
+		if (d->rx_flow_control_triggered) {
+			d->rx_flow_control_disable++;
+			d->rx_flow_control_triggered = 0;
+		}
+		gbam_start_rx(port);
+	}
+}
+/*-------------------------------------------------------------*/
+
+static void gbam_epin_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct gbam_port	*port = ep->driver_data;
+	struct bam_ch_info	*d;
+	struct sk_buff		*skb = req->context;
+	int			status = req->status;
+
+	switch (status) {
+	case 0:
+		/* successful completion */
+		break;
+	case -ECONNRESET:
+	case -ESHUTDOWN:
+		/* connection gone */
+		dev_kfree_skb_any(skb);
+		usb_ep_free_request(ep, req);
+		return;
+	default:
+		pr_err("%s: data tx ep error %d\n",
+				__func__, status);
+		break;
+	}
+
+	dev_kfree_skb_any(skb);
+
+	if (!port)
+		return;
+
+	spin_lock(&port->port_lock_dl);
+	d = &port->data_ch;
+	list_add_tail(&req->list, &d->tx_idle);
+	spin_unlock(&port->port_lock_dl);
+
+	queue_work(gbam_wq, &d->write_tohost_w);
+}
+
+static void
+gbam_epout_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct gbam_port	*port = ep->driver_data;
+	struct bam_ch_info	*d = &port->data_ch;
+	struct sk_buff		*skb = req->context;
+	int			status = req->status;
+	int			queue = 0;
+
+	switch (status) {
+	case 0:
+		skb_put(skb, req->actual);
+		queue = 1;
+		break;
+	case -ECONNRESET:
+	case -ESHUTDOWN:
+		/* cable disconnection */
+		spin_lock(&port->port_lock_ul);
+		gbam_free_skb_to_pool(port, skb);
+		spin_unlock(&port->port_lock_ul);
+		req->buf = 0;
+		usb_ep_free_request(ep, req);
+		return;
+	default:
+		if (printk_ratelimited())
+			pr_err("%s: %s response error %d, %d/%d\n",
+				__func__, ep->name, status,
+				req->actual, req->length);
+		spin_lock(&port->port_lock_ul);
+		gbam_free_skb_to_pool(port, skb);
+		spin_unlock(&port->port_lock_ul);
+		break;
+	}
+
+	spin_lock(&port->port_lock_ul);
+
+	if (queue) {
+		__skb_queue_tail(&d->rx_skb_q, skb);
+		if ((d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) &&
+			!usb_bam_get_prod_granted(d->usb_bam_type,
+					d->dst_connection_idx)) {
+			list_add_tail(&req->list, &d->rx_idle);
+			spin_unlock(&port->port_lock_ul);
+			return;
+		}
+
+		queue_work(gbam_wq, &d->write_tobam_w);
+	}
+
+	/* TODO: Handle flow control gracefully by having
+	 * having call back mechanism from bam driver
+	 */
+	if (bam_mux_rx_fctrl_support &&
+		d->rx_skb_q.qlen >= bam_mux_rx_fctrl_en_thld) {
+		if (!d->rx_flow_control_triggered) {
+			d->rx_flow_control_triggered = 1;
+			d->rx_flow_control_enable++;
+		}
+		list_add_tail(&req->list, &d->rx_idle);
+		spin_unlock(&port->port_lock_ul);
+		return;
+	}
+
+	skb = gbam_alloc_skb_from_pool(port);
+	if (!skb) {
+		list_add_tail(&req->list, &d->rx_idle);
+		spin_unlock(&port->port_lock_ul);
+		return;
+	}
+	spin_unlock(&port->port_lock_ul);
+
+	req->buf = skb->data;
+	req->dma = gbam_get_dma_from_skb(skb);
+	req->length = bam_mux_rx_req_size;
+
+	if (req->dma != DMA_ERROR_CODE)
+		req->dma_pre_mapped = true;
+	else
+		req->dma_pre_mapped = false;
+
+	req->context = skb;
+
+	status = usb_ep_queue(ep, req, GFP_ATOMIC);
+	if (status) {
+		spin_lock(&port->port_lock_ul);
+		gbam_free_skb_to_pool(port, skb);
+		spin_unlock(&port->port_lock_ul);
+
+		if (printk_ratelimited())
+			pr_err("%s: data rx enqueue err %d\n",
+					__func__, status);
+
+		spin_lock(&port->port_lock_ul);
+		list_add_tail(&req->list, &d->rx_idle);
+		spin_unlock(&port->port_lock_ul);
+	}
+}
+
+static void gbam_endless_rx_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	int status = req->status;
+
+	pr_debug("%s status: %d\n", __func__, status);
+}
+
+static void gbam_endless_tx_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	int status = req->status;
+
+	pr_debug("%s status: %d\n", __func__, status);
+}
+
+static void gbam_start_rx(struct gbam_port *port)
+{
+	struct usb_request		*req;
+	struct bam_ch_info		*d;
+	struct usb_ep			*ep;
+	unsigned long			flags;
+	int				ret;
+	struct sk_buff			*skb;
+
+	spin_lock_irqsave(&port->port_lock_ul, flags);
+	if (!port->port_usb || !port->port_usb->out) {
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
+		return;
+	}
+
+	d = &port->data_ch;
+	ep = port->port_usb->out;
+
+	while (port->port_usb && !list_empty(&d->rx_idle)) {
+
+		if (bam_mux_rx_fctrl_support &&
+			d->rx_skb_q.qlen >= bam_mux_rx_fctrl_en_thld)
+			break;
+
+		req = list_first_entry(&d->rx_idle, struct usb_request, list);
+
+		skb = gbam_alloc_skb_from_pool(port);
+		if (!skb)
+			break;
+
+		list_del(&req->list);
+		req->buf = skb->data;
+		req->dma = gbam_get_dma_from_skb(skb);
+		req->length = bam_mux_rx_req_size;
+
+		if (req->dma != DMA_ERROR_CODE)
+			req->dma_pre_mapped = true;
+		else
+			req->dma_pre_mapped = false;
+
+		req->context = skb;
+
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
+		ret = usb_ep_queue(ep, req, GFP_ATOMIC);
+		spin_lock_irqsave(&port->port_lock_ul, flags);
+		if (ret) {
+			gbam_free_skb_to_pool(port, skb);
+
+			if (printk_ratelimited())
+				pr_err("%s: rx queue failed %d\n",
+							__func__, ret);
+
+			if (port->port_usb)
+				list_add(&req->list, &d->rx_idle);
+			else
+				usb_ep_free_request(ep, req);
+			break;
+		}
+	}
+
+	spin_unlock_irqrestore(&port->port_lock_ul, flags);
+}
+
+static void gbam_start_endless_rx(struct gbam_port *port)
+{
+	struct bam_ch_info *d = &port->data_ch;
+	int status;
+	struct usb_ep *ep;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->port_lock_ul, flags);
+	if (!port->port_usb || !d->rx_req) {
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
+		pr_err("%s: port->port_usb is NULL", __func__);
+		return;
+	}
+
+	ep = port->port_usb->out;
+	spin_unlock_irqrestore(&port->port_lock_ul, flags);
+	pr_debug("%s: enqueue\n", __func__);
+	status = usb_ep_queue(ep, d->rx_req, GFP_ATOMIC);
+	if (status)
+		pr_err("%s: error enqueuing transfer, %d\n", __func__, status);
+}
+
+static void gbam_start_endless_tx(struct gbam_port *port)
+{
+	struct bam_ch_info *d = &port->data_ch;
+	int status;
+	struct usb_ep *ep;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->port_lock_dl, flags);
+	if (!port->port_usb || !d->tx_req) {
+		spin_unlock_irqrestore(&port->port_lock_dl, flags);
+		pr_err("%s: port->port_usb is NULL", __func__);
+		return;
+	}
+
+	ep = port->port_usb->in;
+	spin_unlock_irqrestore(&port->port_lock_dl, flags);
+	pr_debug("%s: enqueue\n", __func__);
+	status = usb_ep_queue(ep, d->tx_req, GFP_ATOMIC);
+	if (status)
+		pr_err("%s: error enqueuing transfer, %d\n", __func__, status);
+}
+
+static void gbam_stop_endless_rx(struct gbam_port *port)
+{
+	struct bam_ch_info *d = &port->data_ch;
+	int status;
+	unsigned long flags;
+	struct usb_ep *ep;
+
+	spin_lock_irqsave(&port->port_lock_ul, flags);
+	if (!port->port_usb) {
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
+		pr_err("%s: port->port_usb is NULL", __func__);
+		return;
+	}
+
+	ep = port->port_usb->out;
+	d->rx_req_dequeued = true;
+	spin_unlock_irqrestore(&port->port_lock_ul, flags);
+	pr_debug("%s: dequeue\n", __func__);
+	status = usb_ep_dequeue(ep, d->rx_req);
+	if (status)
+		pr_err("%s: error dequeuing transfer, %d\n", __func__, status);
+}
+
+static void gbam_stop_endless_tx(struct gbam_port *port)
+{
+	struct bam_ch_info *d = &port->data_ch;
+	int status;
+	unsigned long flags;
+	struct usb_ep *ep;
+
+	spin_lock_irqsave(&port->port_lock_dl, flags);
+	if (!port->port_usb) {
+		spin_unlock_irqrestore(&port->port_lock_dl, flags);
+		pr_err("%s: port->port_usb is NULL", __func__);
+		return;
+	}
+
+	ep = port->port_usb->in;
+	d->tx_req_dequeued = true;
+	spin_unlock_irqrestore(&port->port_lock_dl, flags);
+	pr_debug("%s: dequeue\n", __func__);
+	status = usb_ep_dequeue(ep, d->tx_req);
+	if (status)
+		pr_err("%s: error dequeuing transfer, %d\n", __func__, status);
+}
+
+
+/*
+ * This function configured data fifo based on index passed to get bam2bam
+ * configuration.
+ */
+static void configure_data_fifo(enum usb_ctrl bam_type, u8 idx,
+		struct usb_ep *ep, enum usb_bam_pipe_type pipe_type)
+{
+	struct u_bam_data_connect_info bam_info;
+	struct sps_mem_buffer data_fifo = {0};
+
+	if (pipe_type == USB_BAM_PIPE_BAM2BAM) {
+		get_bam2bam_connection_info(bam_type, idx,
+				&bam_info.usb_bam_pipe_idx,
+				NULL, &data_fifo, NULL);
+
+		msm_data_fifo_config(ep,
+				data_fifo.phys_base,
+				data_fifo.size,
+				bam_info.usb_bam_pipe_idx);
+	}
+}
+
+
+static void gbam_start(void *param, enum usb_bam_pipe_dir dir)
+{
+	struct gbam_port *port = param;
+	struct usb_gadget *gadget = NULL;
+	struct bam_ch_info *d;
+	unsigned long flags;
+
+	if (port == NULL) {
+		pr_err("%s: port is NULL\n", __func__);
+		return;
+	}
+
+	spin_lock_irqsave(&port->port_lock, flags);
+	if (port->port_usb == NULL) {
+		pr_err("%s: port_usb is NULL, disconnected\n", __func__);
+		spin_unlock_irqrestore(&port->port_lock, flags);
+		return;
+	}
+
+	gadget = port->port_usb->gadget;
+	d = &port->data_ch;
+	spin_unlock_irqrestore(&port->port_lock, flags);
+
+	if (gadget == NULL) {
+		pr_err("%s: gadget is NULL\n", __func__);
+		return;
+	}
+
+	if (dir == USB_TO_PEER_PERIPHERAL) {
+		if (port->data_ch.src_pipe_type == USB_BAM_PIPE_BAM2BAM)
+			gbam_start_endless_rx(port);
+		else {
+			gbam_start_rx(port);
+			queue_work(gbam_wq, &d->write_tobam_w);
+		}
+	} else {
+		if (gadget_is_dwc3(gadget) &&
+		    msm_dwc3_reset_ep_after_lpm(gadget)) {
+			configure_data_fifo(d->usb_bam_type,
+				d->dst_connection_idx,
+				port->port_usb->in, d->dst_pipe_type);
+		}
+		gbam_start_endless_tx(port);
+	}
+}
+
+static void gbam_stop(void *param, enum usb_bam_pipe_dir dir)
+{
+	struct gbam_port *port = param;
+
+	if (dir == USB_TO_PEER_PERIPHERAL) {
+		/*
+		 * Only handling BAM2BAM, as there is no equivalent to
+		 * gbam_stop_endless_rx() for the SYS2BAM use case
+		 */
+		if (port->data_ch.src_pipe_type == USB_BAM_PIPE_BAM2BAM)
+			gbam_stop_endless_rx(port);
+	} else {
+		gbam_stop_endless_tx(port);
+	}
+}
+
+static int _gbam_start_io(struct gbam_port *port, bool in)
+{
+	unsigned long		flags;
+	int			ret = 0;
+	struct usb_ep		*ep;
+	struct list_head	*idle;
+	unsigned int		queue_size;
+	spinlock_t		*spinlock;
+	void		(*ep_complete)(struct usb_ep *, struct usb_request *);
+
+	if (in)
+		spinlock = &port->port_lock_dl;
+	else
+		spinlock = &port->port_lock_ul;
+
+	spin_lock_irqsave(spinlock, flags);
+	if (!port->port_usb) {
+		spin_unlock_irqrestore(spinlock, flags);
+		return -EBUSY;
+	}
+
+	if (in) {
+		ep = port->port_usb->in;
+		idle = &port->data_ch.tx_idle;
+		queue_size = bam_mux_tx_q_size;
+		ep_complete = gbam_epin_complete;
+	} else {
+		ep = port->port_usb->out;
+		if (!ep)
+			goto out;
+		idle = &port->data_ch.rx_idle;
+		queue_size = bam_mux_rx_q_size;
+		ep_complete = gbam_epout_complete;
+	}
+
+	ret = gbam_alloc_requests(ep, idle, queue_size, ep_complete,
+			GFP_ATOMIC);
+out:
+	spin_unlock_irqrestore(spinlock, flags);
+	if (ret)
+		pr_err("%s: allocation failed\n", __func__);
+
+	return ret;
+}
+
+static void gbam_start_io(struct gbam_port *port)
+{
+	unsigned long		flags;
+
+	pr_debug("%s: port:%pK\n", __func__, port);
+
+	if (_gbam_start_io(port, true))
+		return;
+
+	if (_gbam_start_io(port, false)) {
+		spin_lock_irqsave(&port->port_lock_dl, flags);
+		if (port->port_usb)
+			gbam_free_requests(port->port_usb->in,
+				&port->data_ch.tx_idle);
+		spin_unlock_irqrestore(&port->port_lock_dl, flags);
+		return;
+	}
+
+	/* queue out requests */
+	gbam_start_rx(port);
+}
+
+static void gbam_notify(void *p, int event, unsigned long data)
+{
+	struct gbam_port	*port = p;
+	struct bam_ch_info *d;
+	struct sk_buff *skb;
+
+	if (port == NULL)
+		pr_err("BAM DMUX notifying after channel close\n");
+
+	switch (event) {
+	case BAM_DMUX_RECEIVE:
+		skb = (struct sk_buff *)data;
+		if (port)
+			gbam_data_recv_cb(p, skb);
+		else
+			dev_kfree_skb_any(skb);
+		break;
+	case BAM_DMUX_WRITE_DONE:
+		skb = (struct sk_buff *)data;
+		if (port)
+			gbam_data_write_done(p, skb);
+		else
+			dev_kfree_skb_any(skb);
+		break;
+	case BAM_DMUX_TRANSMIT_SIZE:
+		d = &port->data_ch;
+		if (test_bit(BAM_CH_OPENED, &d->flags))
+			pr_warn("%s, BAM channel opened already", __func__);
+		bam_mux_rx_req_size = data;
+		pr_debug("%s rx_req_size: %lu", __func__, bam_mux_rx_req_size);
+		break;
+	}
+}
+
+static void gbam_free_rx_buffers(struct gbam_port *port)
+{
+	struct sk_buff		*skb;
+	unsigned long		flags;
+	struct bam_ch_info	*d;
+
+	spin_lock_irqsave(&port->port_lock_ul, flags);
+
+	if (!port->port_usb || !port->port_usb->out)
+		goto free_rx_buf_out;
+
+	d = &port->data_ch;
+	gbam_free_requests(port->port_usb->out, &d->rx_idle);
+
+	while ((skb = __skb_dequeue(&d->rx_skb_q)))
+		dev_kfree_skb_any(skb);
+
+	gbam_free_rx_skb_idle_list(port);
+
+free_rx_buf_out:
+	spin_unlock_irqrestore(&port->port_lock_ul, flags);
+}
+
+static void gbam_free_tx_buffers(struct gbam_port *port)
+{
+	struct sk_buff		*skb;
+	unsigned long		flags;
+	struct bam_ch_info	*d;
+
+	spin_lock_irqsave(&port->port_lock_dl, flags);
+
+	if (!port->port_usb)
+		goto free_tx_buf_out;
+
+	d = &port->data_ch;
+	gbam_free_requests(port->port_usb->in, &d->tx_idle);
+
+	while ((skb = __skb_dequeue(&d->tx_skb_q)))
+		dev_kfree_skb_any(skb);
+
+free_tx_buf_out:
+	spin_unlock_irqrestore(&port->port_lock_dl, flags);
+}
+
+static void gbam_free_buffers(struct gbam_port *port)
+{
+	gbam_free_rx_buffers(port);
+	gbam_free_tx_buffers(port);
+}
+
+static void gbam_disconnect_work(struct work_struct *w)
+{
+	struct gbam_port *port =
+			container_of(w, struct gbam_port, disconnect_w);
+	struct bam_ch_info *d = &port->data_ch;
+
+	if (!test_bit(BAM_CH_OPENED, &d->flags)) {
+		pr_err("%s: Bam channel is not opened\n", __func__);
+		goto exit;
+	}
+
+	msm_bam_dmux_close(d->id);
+	clear_bit(BAM_CH_OPENED, &d->flags);
+exit:
+	return;
+}
+
+static void gbam2bam_disconnect_work(struct work_struct *w)
+{
+	struct gbam_port *port =
+			container_of(w, struct gbam_port, disconnect_w);
+	struct bam_ch_info *d;
+	int ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->port_lock, flags);
+
+	if (!port->is_connected) {
+		pr_debug("%s: Port already disconnected. Bailing out.\n",
+			__func__);
+		spin_unlock_irqrestore(&port->port_lock, flags);
+		return;
+	}
+
+	port->is_connected = false;
+	d = &port->data_ch;
+
+	/*
+	 * Unlock the port here and not at the end of this work,
+	 * because we do not want to activate usb_bam, ipa and
+	 * tethe bridge logic in atomic context and wait uneeded time.
+	 * Either way other works will not fire until end of this work
+	 * and event functions (as bam_data_connect) will not influance
+	 * while lower layers connect pipes, etc.
+	 */
+	spin_unlock_irqrestore(&port->port_lock, flags);
+
+	if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
+		ret = usb_bam_disconnect_ipa(d->usb_bam_type, &d->ipa_params);
+		if (ret)
+			pr_err("%s: usb_bam_disconnect_ipa failed: err:%d\n",
+				__func__, ret);
+		usb_bam_free_fifos(d->usb_bam_type, d->src_connection_idx);
+		usb_bam_free_fifos(d->usb_bam_type, d->dst_connection_idx);
+		teth_bridge_disconnect(d->ipa_params.src_client);
+		/*
+		 * Decrement usage count which was incremented upon cable
+		 * connect or cable disconnect in suspended state
+		 */
+		usb_gadget_autopm_put_async(port->gadget);
+	}
+}
+
+static void gbam_connect_work(struct work_struct *w)
+{
+	struct gbam_port *port = container_of(w, struct gbam_port, connect_w);
+	struct bam_ch_info *d = &port->data_ch;
+	int ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->port_lock_ul, flags);
+	spin_lock(&port->port_lock_dl);
+	if (!port->port_usb) {
+		spin_unlock(&port->port_lock_dl);
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
+		return;
+	}
+	spin_unlock(&port->port_lock_dl);
+	spin_unlock_irqrestore(&port->port_lock_ul, flags);
+
+	if (!test_bit(BAM_CH_READY, &d->flags)) {
+		pr_err("%s: Bam channel is not ready\n", __func__);
+		return;
+	}
+
+	ret = msm_bam_dmux_open(d->id, port, gbam_notify);
+	if (ret) {
+		pr_err("%s: unable open bam ch:%d err:%d\n",
+				__func__, d->id, ret);
+		return;
+	}
+
+	set_bit(BAM_CH_OPENED, &d->flags);
+
+	gbam_start_io(port);
+
+	pr_debug("%s: done\n", __func__);
+}
+
+static void gbam2bam_connect_work(struct work_struct *w)
+{
+	struct gbam_port *port = container_of(w, struct gbam_port, connect_w);
+	struct usb_gadget *gadget = NULL;
+	struct teth_bridge_connect_params connect_params;
+	struct teth_bridge_init_params teth_bridge_params;
+	struct bam_ch_info *d;
+	u32 sps_params;
+	int ret;
+	unsigned long flags, flags_ul;
+
+	spin_lock_irqsave(&port->port_lock, flags);
+
+	if (port->last_event == U_BAM_DISCONNECT_E) {
+		pr_debug("%s: Port is about to disconnected. Bailing out.\n",
+			__func__);
+		spin_unlock_irqrestore(&port->port_lock, flags);
+		return;
+	}
+
+	if (port->is_connected) {
+		pr_debug("%s: Port already connected. Bail out.\n",
+			__func__);
+		spin_unlock_irqrestore(&port->port_lock, flags);
+		return;
+	}
+	port->is_connected = true;
+
+	spin_lock_irqsave(&port->port_lock_ul, flags_ul);
+	spin_lock(&port->port_lock_dl);
+	if (!port->port_usb) {
+		pr_debug("%s: usb cable is disconnected, exiting\n", __func__);
+		spin_unlock(&port->port_lock_dl);
+		spin_unlock_irqrestore(&port->port_lock_ul, flags_ul);
+		spin_unlock_irqrestore(&port->port_lock, flags);
+		return;
+	}
+
+	gadget = port->port_usb->gadget;
+	if (!gadget) {
+		spin_unlock(&port->port_lock_dl);
+		spin_unlock_irqrestore(&port->port_lock_ul, flags_ul);
+		spin_unlock_irqrestore(&port->port_lock, flags);
+		pr_err("%s: port_usb.gadget is NULL, exiting\n", __func__);
+		return;
+	}
+	d = &port->data_ch;
+
+	/*
+	 * Unlock the port here and not at the end of this work,
+	 * because we do not want to activate usb_bam, ipa and
+	 * tethe bridge logic in atomic context and wait uneeded time.
+	 * Either way other works will not fire until end of this work
+	 * and event functions (as bam_data_connect) will not influance
+	 * while lower layers connect pipes, etc.
+	 */
+	spin_unlock(&port->port_lock_dl);
+	spin_unlock_irqrestore(&port->port_lock_ul, flags_ul);
+
+	d->ipa_params.usb_connection_speed = gadget->speed;
+
+	/*
+	 * Invalidate prod and cons client handles from previous
+	 * disconnect.
+	 */
+	d->ipa_params.cons_clnt_hdl = -1;
+	d->ipa_params.prod_clnt_hdl = -1;
+
+	if (usb_bam_get_pipe_type(d->usb_bam_type, d->ipa_params.src_idx,
+			&d->src_pipe_type) ||
+		usb_bam_get_pipe_type(d->usb_bam_type, d->ipa_params.dst_idx,
+				&d->dst_pipe_type)) {
+		spin_unlock_irqrestore(&port->port_lock, flags);
+		pr_err("%s:usb_bam_get_pipe_type() failed\n", __func__);
+		return;
+	}
+	if (d->dst_pipe_type != USB_BAM_PIPE_BAM2BAM) {
+		spin_unlock_irqrestore(&port->port_lock, flags);
+		pr_err("%s: no software preparation for DL not using bam2bam\n",
+				__func__);
+		return;
+	}
+
+	spin_unlock_irqrestore(&port->port_lock, flags);
+	usb_bam_alloc_fifos(d->usb_bam_type, d->src_connection_idx);
+	usb_bam_alloc_fifos(d->usb_bam_type, d->dst_connection_idx);
+
+	spin_lock_irqsave(&port->port_lock, flags);
+	/* check if USB cable is disconnected or not */
+	if (!port || !port->port_usb) {
+		pr_debug("%s: cable is disconnected.\n",
+						 __func__);
+		spin_unlock_irqrestore(&port->port_lock,
+							flags);
+		goto free_fifos;
+	}
+	if (gadget_is_dwc3(gadget)) {
+		/* Configure for RX */
+		configure_data_fifo(d->usb_bam_type, d->src_connection_idx,
+				    port->port_usb->out, d->src_pipe_type);
+		sps_params = MSM_SPS_MODE | MSM_DISABLE_WB | MSM_PRODUCER |
+								d->src_pipe_idx;
+		d->rx_req->length = 32*1024;
+		d->rx_req->udc_priv = sps_params;
+		msm_ep_config(port->port_usb->out, d->rx_req);
+
+		/* Configure for TX */
+		configure_data_fifo(d->usb_bam_type, d->dst_connection_idx,
+				    port->port_usb->in, d->dst_pipe_type);
+		sps_params = MSM_SPS_MODE | MSM_DISABLE_WB | d->dst_pipe_idx;
+		d->tx_req->length = 32*1024;
+		d->tx_req->udc_priv = sps_params;
+		msm_ep_config(port->port_usb->in, d->tx_req);
+
+	} else {
+		/* Configure for RX */
+		get_bam2bam_connection_info(d->usb_bam_type,
+				d->src_connection_idx,
+				&d->src_pipe_idx,
+				NULL, NULL, NULL);
+		sps_params = (MSM_SPS_MODE | d->src_pipe_idx |
+				MSM_VENDOR_ID) & ~MSM_IS_FINITE_TRANSFER;
+		d->rx_req->udc_priv = sps_params;
+
+		/* Configure for TX */
+		get_bam2bam_connection_info(d->usb_bam_type,
+				d->dst_connection_idx,
+				&d->dst_pipe_idx,
+				NULL, NULL, NULL);
+		sps_params = (MSM_SPS_MODE | d->dst_pipe_idx |
+				MSM_VENDOR_ID) & ~MSM_IS_FINITE_TRANSFER;
+		d->tx_req->udc_priv = sps_params;
+
+	}
+
+	teth_bridge_params.client = d->ipa_params.src_client;
+	ret = teth_bridge_init(&teth_bridge_params);
+	if (ret) {
+		spin_unlock_irqrestore(&port->port_lock, flags);
+		pr_err("%s:teth_bridge_init() failed\n", __func__);
+		goto ep_unconfig;
+	}
+
+	/* Support for UL using system-to-IPA */
+	if (d->src_pipe_type == USB_BAM_PIPE_SYS2BAM) {
+		d->ul_params.teth_priv =
+			teth_bridge_params.private_data;
+		d->ul_params.teth_cb =
+			teth_bridge_params.usb_notify_cb;
+		d->ipa_params.notify = gbam_ipa_sys2bam_notify_cb;
+		d->ipa_params.priv = &d->ul_params;
+		d->ipa_params.reset_pipe_after_lpm = false;
+
+	} else {
+		d->ipa_params.notify =
+			teth_bridge_params.usb_notify_cb;
+		d->ipa_params.priv =
+			teth_bridge_params.private_data;
+		d->ipa_params.reset_pipe_after_lpm =
+			(gadget_is_dwc3(gadget) &&
+			 msm_dwc3_reset_ep_after_lpm(gadget));
+	}
+	d->ipa_params.ipa_ep_cfg.mode.mode = IPA_BASIC;
+	d->ipa_params.skip_ep_cfg = teth_bridge_params.skip_ep_cfg;
+	d->ipa_params.dir = USB_TO_PEER_PERIPHERAL;
+	spin_unlock_irqrestore(&port->port_lock, flags);
+	ret = usb_bam_connect_ipa(d->usb_bam_type, &d->ipa_params);
+	if (ret) {
+		pr_err("%s: usb_bam_connect_ipa failed: err:%d\n",
+			__func__, ret);
+		goto ep_unconfig;
+	}
+
+	spin_lock_irqsave(&port->port_lock, flags);
+	/* check if USB cable is disconnected or not */
+	if (port->last_event ==  U_BAM_DISCONNECT_E) {
+		spin_unlock_irqrestore(&port->port_lock, flags);
+		pr_debug("%s:%d: cable is disconnected.\n",
+						 __func__, __LINE__);
+		goto ep_unconfig;
+	}
+
+	/* Remove support for UL using system-to-IPA towards DL */
+	if (d->src_pipe_type == USB_BAM_PIPE_SYS2BAM) {
+		d->ipa_params.notify = d->ul_params.teth_cb;
+		d->ipa_params.priv = d->ul_params.teth_priv;
+	}
+	if (d->dst_pipe_type == USB_BAM_PIPE_BAM2BAM)
+		d->ipa_params.reset_pipe_after_lpm =
+			(gadget_is_dwc3(gadget) &&
+			 msm_dwc3_reset_ep_after_lpm(gadget));
+	else
+		d->ipa_params.reset_pipe_after_lpm = false;
+	d->ipa_params.dir = PEER_PERIPHERAL_TO_USB;
+	spin_unlock_irqrestore(&port->port_lock, flags);
+	ret = usb_bam_connect_ipa(d->usb_bam_type, &d->ipa_params);
+	if (ret) {
+		pr_err("%s: usb_bam_connect_ipa failed: err:%d\n",
+			__func__, ret);
+		goto ep_unconfig;
+	}
+
+	spin_lock_irqsave(&port->port_lock, flags);
+	/* check if USB cable is disconnected or not */
+	if (port->last_event ==  U_BAM_DISCONNECT_E) {
+		spin_unlock_irqrestore(&port->port_lock, flags);
+		pr_debug("%s:%d: cable is disconnected.\n",
+						 __func__, __LINE__);
+		goto ep_unconfig;
+	}
+
+	spin_unlock_irqrestore(&port->port_lock, flags);
+	gqti_ctrl_update_ipa_pipes(port->port_usb, port->port_num,
+					d->ipa_params.ipa_prod_ep_idx,
+					d->ipa_params.ipa_cons_ep_idx);
+
+	connect_params.ipa_usb_pipe_hdl = d->ipa_params.prod_clnt_hdl;
+	connect_params.usb_ipa_pipe_hdl = d->ipa_params.cons_clnt_hdl;
+	connect_params.tethering_mode = TETH_TETHERING_MODE_RMNET;
+	connect_params.client_type = d->ipa_params.src_client;
+	ret = teth_bridge_connect(&connect_params);
+	if (ret) {
+		pr_err("%s:teth_bridge_connect() failed\n", __func__);
+		goto ep_unconfig;
+	}
+
+	/* queue in & out requests */
+	if (d->src_pipe_type == USB_BAM_PIPE_BAM2BAM) {
+		gbam_start_endless_rx(port);
+	} else {
+		/* The use-case of UL (OUT) ports using sys2bam is based on
+		 * partial reuse of the system-to-bam_demux code. The following
+		 * lines perform the branching out of the standard bam2bam flow
+		 * on the USB side of the UL channel
+		 */
+		if (_gbam_start_io(port, false)) {
+			pr_err("%s: _gbam_start_io failed\n", __func__);
+			return;
+		}
+		gbam_start_rx(port);
+	}
+	gbam_start_endless_tx(port);
+
+	pr_debug("%s: done\n", __func__);
+	return;
+
+ep_unconfig:
+	if (gadget_is_dwc3(gadget)) {
+		spin_lock_irqsave(&port->port_lock, flags);
+		/* check if USB cable is disconnected or not */
+		if (port->port_usb) {
+			msm_ep_unconfig(port->port_usb->in);
+			msm_ep_unconfig(port->port_usb->out);
+		}
+		spin_unlock_irqrestore(&port->port_lock, flags);
+	}
+free_fifos:
+	usb_bam_free_fifos(d->usb_bam_type, d->src_connection_idx);
+	usb_bam_free_fifos(d->usb_bam_type, d->dst_connection_idx);
+
+}
+
+static int gbam_wake_cb(void *param)
+{
+	struct gbam_port	*port = (struct gbam_port *)param;
+	struct usb_gadget	*gadget;
+	unsigned long flags;
+	struct usb_function *func;
+	int ret;
+
+	spin_lock_irqsave(&port->port_lock, flags);
+	if (!port->port_usb) {
+		pr_debug("%s: usb cable is disconnected, exiting\n",
+				__func__);
+		spin_unlock_irqrestore(&port->port_lock, flags);
+		return -ENODEV;
+	}
+
+	gadget = port->port_usb->gadget;
+	func = port->port_usb->f;
+	spin_unlock_irqrestore(&port->port_lock, flags);
+
+	pr_debug("%s: woken up by peer\n", __func__);
+
+	if ((gadget->speed == USB_SPEED_SUPER) &&
+	    (func->func_is_suspended))
+		ret = usb_func_wakeup(func);
+	else
+		ret = usb_gadget_wakeup(gadget);
+
+	if ((ret == -EBUSY) || (ret == -EAGAIN))
+		pr_debug("Remote wakeup is delayed due to LPM exit\n");
+	else if (ret)
+		pr_err("Failed to wake up the USB core. ret=%d\n", ret);
+
+	return ret;
+}
+
+static void gbam2bam_suspend_work(struct work_struct *w)
+{
+	struct gbam_port *port = container_of(w, struct gbam_port, suspend_w);
+	struct bam_ch_info *d;
+	int ret;
+	unsigned long flags;
+
+	pr_debug("%s: suspend work started\n", __func__);
+
+	spin_lock_irqsave(&port->port_lock, flags);
+
+	if ((port->last_event == U_BAM_DISCONNECT_E) ||
+	    (port->last_event == U_BAM_RESUME_E)) {
+		pr_debug("%s: Port is about to disconnect/resume. Bail out\n",
+			__func__);
+		goto exit;
+	}
+
+	d = &port->data_ch;
+
+	ret = usb_bam_register_wake_cb(d->usb_bam_type, d->dst_connection_idx,
+					gbam_wake_cb, port);
+	if (ret) {
+		pr_err("%s(): Failed to register BAM wake callback.\n",
+			__func__);
+		goto exit;
+	}
+
+	if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
+		usb_bam_register_start_stop_cbs(d->usb_bam_type,
+			 d->dst_connection_idx, gbam_start, gbam_stop, port);
+
+		/*
+		 * release lock here because gbam_start() or
+		 * gbam_stop() called from usb_bam_suspend()
+		 * re-acquires port lock.
+		 */
+		spin_unlock_irqrestore(&port->port_lock, flags);
+		usb_bam_suspend(d->usb_bam_type, &d->ipa_params);
+		spin_lock_irqsave(&port->port_lock, flags);
+	}
+
+exit:
+	/*
+	 * Decrement usage count after IPA handshake is done to allow gadget
+	 * parent to go to lpm. This counter was incremented upon cable connect
+	 */
+	usb_gadget_autopm_put_async(port->gadget);
+
+	spin_unlock_irqrestore(&port->port_lock, flags);
+}
+
+static void gbam2bam_resume_work(struct work_struct *w)
+{
+	struct gbam_port *port = container_of(w, struct gbam_port, resume_w);
+	struct bam_ch_info *d;
+	struct usb_gadget *gadget = NULL;
+	int ret;
+	unsigned long flags;
+
+	pr_debug("%s: resume work started\n", __func__);
+
+	spin_lock_irqsave(&port->port_lock, flags);
+
+	if (port->last_event == U_BAM_DISCONNECT_E || !port->port_usb) {
+		pr_debug("%s: usb cable is disconnected, exiting\n",
+			__func__);
+		goto exit;
+	}
+
+	d = &port->data_ch;
+	gadget = port->port_usb->gadget;
+
+	ret = usb_bam_register_wake_cb(d->usb_bam_type, d->dst_connection_idx,
+					NULL, NULL);
+	if (ret) {
+		pr_err("%s(): Failed to register BAM wake callback.\n",
+			__func__);
+		goto exit;
+	}
+
+	if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
+		if (gadget_is_dwc3(gadget) &&
+		    msm_dwc3_reset_ep_after_lpm(gadget)) {
+			if (d->tx_req_dequeued) {
+				msm_ep_unconfig(port->port_usb->in);
+				configure_data_fifo(d->usb_bam_type,
+					d->dst_connection_idx,
+					port->port_usb->in, d->dst_pipe_type);
+			}
+			if (d->rx_req_dequeued) {
+				msm_ep_unconfig(port->port_usb->out);
+				configure_data_fifo(d->usb_bam_type,
+					d->src_connection_idx,
+					port->port_usb->out, d->src_pipe_type);
+			}
+
+			spin_unlock_irqrestore(&port->port_lock, flags);
+			if (d->tx_req_dequeued)
+				msm_dwc3_reset_dbm_ep(port->port_usb->in);
+			if (d->rx_req_dequeued)
+				msm_dwc3_reset_dbm_ep(port->port_usb->out);
+			spin_lock_irqsave(&port->port_lock, flags);
+			if (port->port_usb) {
+				if (d->tx_req_dequeued)
+					msm_ep_config(port->port_usb->in,
+							d->tx_req);
+				if (d->rx_req_dequeued)
+					msm_ep_config(port->port_usb->out,
+							d->rx_req);
+			}
+		}
+		d->tx_req_dequeued = false;
+		d->rx_req_dequeued = false;
+		usb_bam_resume(d->usb_bam_type, &d->ipa_params);
+	}
+
+exit:
+	spin_unlock_irqrestore(&port->port_lock, flags);
+}
+
+/* BAM data channel ready, allow attempt to open */
+static int gbam_data_ch_probe(struct platform_device *pdev)
+{
+	struct gbam_port	*port;
+	struct bam_ch_info	*d;
+	int			i;
+	unsigned long		flags;
+	bool			do_work = false;
+
+	pr_debug("%s: name:%s\n", __func__, pdev->name);
+
+	for (i = 0; i < n_bam_ports; i++) {
+		port = bam_ports[i].port;
+		d = &port->data_ch;
+
+		if (!strcmp(bam_ch_names[i], pdev->name)) {
+			set_bit(BAM_CH_READY, &d->flags);
+
+			/* if usb is online, try opening bam_ch */
+			spin_lock_irqsave(&port->port_lock_ul, flags);
+			spin_lock(&port->port_lock_dl);
+			if (port->port_usb)
+				do_work = true;
+			spin_unlock(&port->port_lock_dl);
+			spin_unlock_irqrestore(&port->port_lock_ul, flags);
+
+			if (do_work)
+				queue_work(gbam_wq, &port->connect_w);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/* BAM data channel went inactive, so close it */
+static int gbam_data_ch_remove(struct platform_device *pdev)
+{
+	struct gbam_port	*port;
+	struct bam_ch_info	*d;
+	struct usb_ep		*ep_in = NULL;
+	struct usb_ep		*ep_out = NULL;
+	unsigned long		flags;
+	int			i;
+
+	pr_debug("%s: name:%s\n", __func__, pdev->name);
+
+	for (i = 0; i < n_bam_ports; i++) {
+		if (!strcmp(bam_ch_names[i], pdev->name)) {
+			port = bam_ports[i].port;
+			d = &port->data_ch;
+
+			spin_lock_irqsave(&port->port_lock_ul, flags);
+			spin_lock(&port->port_lock_dl);
+			if (port->port_usb) {
+				ep_in = port->port_usb->in;
+				ep_out = port->port_usb->out;
+			}
+			spin_unlock(&port->port_lock_dl);
+			spin_unlock_irqrestore(&port->port_lock_ul, flags);
+
+			if (ep_in)
+				usb_ep_fifo_flush(ep_in);
+			if (ep_out)
+				usb_ep_fifo_flush(ep_out);
+
+			gbam_free_buffers(port);
+
+			msm_bam_dmux_close(d->id);
+
+			/* bam dmux will free all pending skbs */
+			d->pending_pkts_with_bam = 0;
+			d->pending_bytes_with_bam = 0;
+
+			clear_bit(BAM_CH_READY, &d->flags);
+			clear_bit(BAM_CH_OPENED, &d->flags);
+		}
+	}
+
+	return 0;
+}
+
+static void gbam_port_free(int portno)
+{
+	struct gbam_port *port = bam_ports[portno].port;
+	struct platform_driver *pdrv = &bam_ports[portno].pdrv;
+
+	if (port)
+		platform_driver_unregister(pdrv);
+
+	kfree(port);
+}
+
+static void gbam2bam_port_free(int portno)
+{
+	struct gbam_port *port = bam2bam_ports[portno];
+
+	kfree(port);
+}
+
+static int gbam_port_alloc(int portno)
+{
+	struct gbam_port	*port;
+	struct bam_ch_info	*d;
+	struct platform_driver	*pdrv;
+
+	port = kzalloc(sizeof(struct gbam_port), GFP_KERNEL);
+	if (!port)
+		return -ENOMEM;
+
+	port->port_num = portno;
+
+	/* port initialization */
+	port->is_connected = false;
+	spin_lock_init(&port->port_lock_ul);
+	spin_lock_init(&port->port_lock_dl);
+	spin_lock_init(&port->port_lock);
+	INIT_WORK(&port->connect_w, gbam_connect_work);
+	INIT_WORK(&port->disconnect_w, gbam_disconnect_work);
+
+	/* data ch */
+	d = &port->data_ch;
+	d->port = port;
+	INIT_LIST_HEAD(&d->tx_idle);
+	INIT_LIST_HEAD(&d->rx_idle);
+	INIT_WORK(&d->write_tobam_w, gbam_data_write_tobam);
+	INIT_WORK(&d->write_tohost_w, gbam_write_data_tohost_w);
+	skb_queue_head_init(&d->tx_skb_q);
+	skb_queue_head_init(&d->rx_skb_q);
+	skb_queue_head_init(&d->rx_skb_idle);
+	d->id = bam_ch_ids[portno];
+
+	bam_ports[portno].port = port;
+
+	scnprintf(bam_ch_names[portno], BAM_DMUX_CH_NAME_MAX_LEN,
+			"bam_dmux_ch_%d", bam_ch_ids[portno]);
+	pdrv = &bam_ports[portno].pdrv;
+	pdrv->probe = gbam_data_ch_probe;
+	pdrv->remove = gbam_data_ch_remove;
+	pdrv->driver.name = bam_ch_names[portno];
+	pdrv->driver.owner = THIS_MODULE;
+
+	platform_driver_register(pdrv);
+	pr_debug("%s: port:%pK portno:%d\n", __func__, port, portno);
+
+	return 0;
+}
+
+static int gbam2bam_port_alloc(int portno)
+{
+	struct gbam_port	*port;
+	struct bam_ch_info	*d;
+
+	port = kzalloc(sizeof(struct gbam_port), GFP_KERNEL);
+	if (!port)
+		return -ENOMEM;
+
+	port->port_num = portno;
+
+	/* port initialization */
+	port->is_connected = false;
+	spin_lock_init(&port->port_lock_ul);
+	spin_lock_init(&port->port_lock_dl);
+	spin_lock_init(&port->port_lock);
+
+	INIT_WORK(&port->connect_w, gbam2bam_connect_work);
+	INIT_WORK(&port->disconnect_w, gbam2bam_disconnect_work);
+	INIT_WORK(&port->suspend_w, gbam2bam_suspend_work);
+	INIT_WORK(&port->resume_w, gbam2bam_resume_work);
+
+	/* data ch */
+	d = &port->data_ch;
+	d->port = port;
+	d->ipa_params.src_client = usb_prod[portno];
+	d->ipa_params.dst_client = usb_cons[portno];
+	bam2bam_ports[portno] = port;
+
+	/* UL workaround requirements */
+	skb_queue_head_init(&d->rx_skb_q);
+	skb_queue_head_init(&d->rx_skb_idle);
+	INIT_LIST_HEAD(&d->rx_idle);
+	INIT_WORK(&d->write_tobam_w, gbam_data_write_tobam);
+
+	pr_debug("%s: port:%pK portno:%d\n", __func__, port, portno);
+
+	return 0;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+#define DEBUG_BUF_SIZE	1024
+static ssize_t gbam_read_stats(struct file *file, char __user *ubuf,
+		size_t count, loff_t *ppos)
+{
+	struct gbam_port	*port;
+	struct bam_ch_info	*d;
+	char			*buf;
+	unsigned long		flags;
+	int			ret;
+	int			i;
+	int			temp = 0;
+
+	buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	for (i = 0; i < n_bam_ports; i++) {
+		port = bam_ports[i].port;
+		if (!port)
+			continue;
+		spin_lock_irqsave(&port->port_lock_ul, flags);
+		spin_lock(&port->port_lock_dl);
+
+		d = &port->data_ch;
+
+		temp += scnprintf(buf + temp, DEBUG_BUF_SIZE - temp,
+				"#PORT:%d port:%pK data_ch:%pK#\n"
+				"dpkts_to_usbhost: %lu\n"
+				"dpkts_to_modem:  %lu\n"
+				"dpkts_pwith_bam: %u\n"
+				"dbytes_pwith_bam: %u\n"
+				"to_usbhost_dcnt:  %u\n"
+				"tomodem__dcnt:  %u\n"
+				"rx_flow_control_disable_count: %u\n"
+				"rx_flow_control_enable_count: %u\n"
+				"rx_flow_control_triggered: %u\n"
+				"max_num_pkts_pending_with_bam: %u\n"
+				"max_bytes_pending_with_bam: %u\n"
+				"delayed_bam_mux_write_done: %u\n"
+				"tx_buf_len:	 %u\n"
+				"rx_buf_len:	 %u\n"
+				"data_ch_open:   %d\n"
+				"data_ch_ready:  %d\n"
+				"skb_expand_cnt: %lu\n",
+				i, port, &port->data_ch,
+				d->to_host, d->to_modem,
+				d->pending_pkts_with_bam,
+				d->pending_bytes_with_bam,
+				d->tohost_drp_cnt, d->tomodem_drp_cnt,
+				d->rx_flow_control_disable,
+				d->rx_flow_control_enable,
+				d->rx_flow_control_triggered,
+				d->max_num_pkts_pending_with_bam,
+				d->max_bytes_pending_with_bam,
+				d->delayed_bam_mux_write_done,
+				d->tx_skb_q.qlen, d->rx_skb_q.qlen,
+				test_bit(BAM_CH_OPENED, &d->flags),
+				test_bit(BAM_CH_READY, &d->flags),
+				d->skb_expand_cnt);
+
+		spin_unlock(&port->port_lock_dl);
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
+	}
+
+	ret = simple_read_from_buffer(ubuf, count, ppos, buf, temp);
+
+	kfree(buf);
+
+	return ret;
+}
+
+static ssize_t gbam_reset_stats(struct file *file, const char __user *buf,
+				 size_t count, loff_t *ppos)
+{
+	struct gbam_port	*port;
+	struct bam_ch_info	*d;
+	int			i;
+	unsigned long		flags;
+
+	for (i = 0; i < n_bam_ports; i++) {
+		port = bam_ports[i].port;
+		if (!port)
+			continue;
+
+		spin_lock_irqsave(&port->port_lock_ul, flags);
+		spin_lock(&port->port_lock_dl);
+
+		d = &port->data_ch;
+
+		d->to_host = 0;
+		d->to_modem = 0;
+		d->pending_pkts_with_bam = 0;
+		d->pending_bytes_with_bam = 0;
+		d->tohost_drp_cnt = 0;
+		d->tomodem_drp_cnt = 0;
+		d->rx_flow_control_disable = 0;
+		d->rx_flow_control_enable = 0;
+		d->rx_flow_control_triggered = 0;
+		d->max_num_pkts_pending_with_bam = 0;
+		d->max_bytes_pending_with_bam = 0;
+		d->delayed_bam_mux_write_done = 0;
+		d->skb_expand_cnt = 0;
+
+		spin_unlock(&port->port_lock_dl);
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
+	}
+	return count;
+}
+
+const struct file_operations gbam_stats_ops = {
+	.read = gbam_read_stats,
+	.write = gbam_reset_stats,
+};
+
+static ssize_t gbam_rw_write(struct file *file, const char __user *ubuf,
+				size_t count, loff_t *ppos)
+{
+	struct gbam_port	*port = bam2bam_ports[0];
+	struct usb_function	*func;
+	struct usb_gadget	*gadget;
+	unsigned long		flags;
+
+	if (!port)
+		return -ENODEV;
+
+	spin_lock_irqsave(&port->port_lock, flags);
+	if (!port->port_usb) {
+		pr_debug("%s: usb cable is disconnected, exiting\n",
+				__func__);
+		spin_unlock_irqrestore(&port->port_lock, flags);
+		return -ENODEV;
+	}
+
+	gadget = port->port_usb->gadget;
+	func = port->port_usb->f;
+	spin_unlock_irqrestore(&port->port_lock, flags);
+
+	if ((gadget->speed == USB_SPEED_SUPER) && (func->func_is_suspended)) {
+		pr_debug("%s Initiating usb_func rwakeup\n", __func__);
+		usb_func_wakeup(func);
+	}
+
+	return count;
+}
+
+
+const struct file_operations debug_remote_wakeup_fops = {
+	.write = gbam_rw_write,
+};
+
+struct dentry *gbam_dent;
+static void gbam_debugfs_init(void)
+{
+	struct dentry *dfile;
+
+	if (gbam_dent)
+		return;
+
+	gbam_dent = debugfs_create_dir("usb_rmnet", 0);
+	if (!gbam_dent || IS_ERR(gbam_dent))
+		return;
+
+	debugfs_create_file("remote_wakeup", 0444, gbam_dent, 0,
+			&debug_remote_wakeup_fops);
+
+	dfile = debugfs_create_file("status", 0444, gbam_dent, 0,
+			&gbam_stats_ops);
+	if (!dfile || IS_ERR(dfile)) {
+		debugfs_remove(gbam_dent);
+		gbam_dent = NULL;
+		return;
+	}
+}
+static void gbam_debugfs_remove(void)
+{
+	debugfs_remove_recursive(gbam_dent);
+}
+#else
+static inline void gbam_debugfs_init(void) {}
+static inline void gbam_debugfs_remove(void) {}
+#endif
+
+void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans)
+{
+	struct gbam_port	*port;
+	unsigned long		flags, flags_ul, flags_dl;
+	struct bam_ch_info	*d;
+
+	pr_debug("%s: grmnet:%pK port#%d\n", __func__, gr, port_num);
+
+	if (trans == USB_GADGET_XPORT_BAM2BAM) {
+		pr_err("%s: invalid xport#%d\n", __func__, trans);
+		return;
+	}
+	if (trans == USB_GADGET_XPORT_BAM_DMUX &&
+		port_num >= n_bam_ports) {
+		pr_err("%s: invalid bam portno#%d\n",
+			   __func__, port_num);
+		return;
+	}
+
+	if ((trans == USB_GADGET_XPORT_BAM2BAM_IPA) &&
+				port_num >= n_bam2bam_ports) {
+		pr_err("%s: invalid bam2bam portno#%d\n",
+			   __func__, port_num);
+		return;
+	}
+
+	if (!gr) {
+		pr_err("%s: grmnet port is null\n", __func__);
+		return;
+	}
+	if (trans == USB_GADGET_XPORT_BAM_DMUX)
+		port = bam_ports[port_num].port;
+	else
+		port = bam2bam_ports[port_num];
+
+	if (!port) {
+		pr_err("%s: NULL port", __func__);
+		return;
+	}
+
+	spin_lock_irqsave(&port->port_lock, flags);
+
+	d = &port->data_ch;
+	/* Already disconnected due to suspend with remote wake disabled */
+	if (port->last_event == U_BAM_DISCONNECT_E) {
+		spin_unlock_irqrestore(&port->port_lock, flags);
+		return;
+	}
+	/*
+	 * Suspend with remote wakeup enabled. Increment usage
+	 * count when disconnect happens in suspended state.
+	 * Corresponding decrement happens in the end of this
+	 * function if IPA handshake is already done or it is done
+	 * in disconnect work after finishing IPA handshake.
+	 */
+	if (port->last_event == U_BAM_SUSPEND_E)
+		usb_gadget_autopm_get_noresume(port->gadget);
+
+	port->port_usb = gr;
+
+	if (trans == USB_GADGET_XPORT_BAM_DMUX)
+		gbam_free_buffers(port);
+	else if (trans == USB_GADGET_XPORT_BAM2BAM_IPA)
+		gbam_free_rx_buffers(port);
+
+	spin_lock_irqsave(&port->port_lock_ul, flags_ul);
+	spin_lock(&port->port_lock_dl);
+	port->port_usb = 0;
+	n_tx_req_queued = 0;
+	spin_unlock(&port->port_lock_dl);
+	spin_unlock_irqrestore(&port->port_lock_ul, flags_ul);
+
+	usb_ep_disable(gr->in);
+	if (trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
+		spin_lock_irqsave(&port->port_lock_dl, flags_dl);
+		if (d->tx_req) {
+			usb_ep_free_request(gr->in, d->tx_req);
+			d->tx_req = NULL;
+		}
+		spin_unlock_irqrestore(&port->port_lock_dl, flags_dl);
+	}
+	/* disable endpoints */
+	if (gr->out) {
+		usb_ep_disable(gr->out);
+		if (trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
+			spin_lock_irqsave(&port->port_lock_ul, flags_ul);
+			if (d->rx_req) {
+				usb_ep_free_request(gr->out, d->rx_req);
+				d->rx_req = NULL;
+			}
+			spin_unlock_irqrestore(&port->port_lock_ul, flags_ul);
+		}
+	}
+
+	/*
+	 * Set endless flag to false as USB Endpoint is already
+	 * disable.
+	 */
+	if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
+
+		if (d->dst_pipe_type == USB_BAM_PIPE_BAM2BAM)
+			gr->in->endless = false;
+
+		if (d->src_pipe_type == USB_BAM_PIPE_BAM2BAM && gr->out)
+			gr->out->endless = false;
+	}
+
+	gr->in->driver_data = NULL;
+	if (gr->out)
+		gr->out->driver_data = NULL;
+
+	port->last_event = U_BAM_DISCONNECT_E;
+	/* Disable usb irq for CI gadget. It will be enabled in
+	 * usb_bam_disconnect_pipe() after disconnecting all pipes
+	 * and USB BAM reset is done.
+	 */
+	if (!gadget_is_dwc3(port->gadget) &&
+			(trans == USB_GADGET_XPORT_BAM2BAM_IPA))
+		msm_usb_irq_disable(true);
+
+	queue_work(gbam_wq, &port->disconnect_w);
+
+	spin_unlock_irqrestore(&port->port_lock, flags);
+}
+
+int gbam_connect(struct grmnet *gr, u8 port_num,
+		enum transport_type trans, u8 src_connection_idx,
+		u8 dst_connection_idx)
+{
+	struct gbam_port	*port;
+	struct bam_ch_info	*d;
+	int			ret;
+	unsigned long		flags, flags_ul;
+
+	pr_debug("%s: grmnet:%pK port#%d\n", __func__, gr, port_num);
+
+	if (!gr) {
+		pr_err("%s: grmnet port is null\n", __func__);
+		return -ENODEV;
+	}
+
+	if (!gr->gadget) {
+		pr_err("%s: gadget handle not passed\n", __func__);
+		return -EINVAL;
+	}
+
+	if (trans == USB_GADGET_XPORT_BAM2BAM) {
+		pr_err("%s: invalid xport#%d\n", __func__, trans);
+		return -EINVAL;
+	}
+
+	if (trans == USB_GADGET_XPORT_BAM_DMUX && port_num >= n_bam_ports) {
+		pr_err("%s: invalid portno#%d\n", __func__, port_num);
+		return -ENODEV;
+	}
+
+	if ((trans == USB_GADGET_XPORT_BAM2BAM_IPA)
+			&& port_num >= n_bam2bam_ports) {
+		pr_err("%s: invalid portno#%d\n", __func__, port_num);
+		return -ENODEV;
+	}
+
+	if (trans == USB_GADGET_XPORT_BAM_DMUX)
+		port = bam_ports[port_num].port;
+	else
+		port = bam2bam_ports[port_num];
+
+	if (!port) {
+		pr_err("%s: NULL port", __func__);
+		return -ENODEV;
+	}
+
+	spin_lock_irqsave(&port->port_lock, flags);
+
+	d = &port->data_ch;
+	d->trans = trans;
+
+	spin_lock_irqsave(&port->port_lock_ul, flags_ul);
+	spin_lock(&port->port_lock_dl);
+	port->port_usb = gr;
+	port->gadget = port->port_usb->gadget;
+
+	if (trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
+		d->rx_req = usb_ep_alloc_request(port->port_usb->out,
+								GFP_ATOMIC);
+		if (!d->rx_req) {
+			pr_err("%s: RX request allocation failed\n", __func__);
+			d->rx_req = NULL;
+			spin_unlock(&port->port_lock_dl);
+			spin_unlock_irqrestore(&port->port_lock_ul, flags_ul);
+			spin_unlock_irqrestore(&port->port_lock, flags);
+			return -ENOMEM;
+		}
+
+		d->rx_req->context = port;
+		d->rx_req->complete = gbam_endless_rx_complete;
+		d->rx_req->length = 0;
+		d->rx_req->no_interrupt = 1;
+
+		d->tx_req = usb_ep_alloc_request(port->port_usb->in,
+								GFP_ATOMIC);
+		if (!d->tx_req) {
+			pr_err("%s: TX request allocation failed\n", __func__);
+			d->tx_req = NULL;
+			usb_ep_free_request(port->port_usb->out, d->rx_req);
+			d->rx_req = NULL;
+			spin_unlock(&port->port_lock_dl);
+			spin_unlock_irqrestore(&port->port_lock_ul, flags_ul);
+			spin_unlock_irqrestore(&port->port_lock, flags);
+			return -ENOMEM;
+		}
+
+		d->tx_req->context = port;
+		d->tx_req->complete = gbam_endless_tx_complete;
+		d->tx_req->length = 0;
+		d->tx_req->no_interrupt = 1;
+	}
+
+	if (d->trans == USB_GADGET_XPORT_BAM_DMUX) {
+		d->to_host = 0;
+		d->to_modem = 0;
+		d->pending_pkts_with_bam = 0;
+		d->pending_bytes_with_bam = 0;
+		d->tohost_drp_cnt = 0;
+		d->tomodem_drp_cnt = 0;
+		d->rx_flow_control_disable = 0;
+		d->rx_flow_control_enable = 0;
+		d->rx_flow_control_triggered = 0;
+		d->max_num_pkts_pending_with_bam = 0;
+		d->max_bytes_pending_with_bam = 0;
+		d->delayed_bam_mux_write_done = 0;
+	}
+
+	spin_unlock(&port->port_lock_dl);
+	spin_unlock_irqrestore(&port->port_lock_ul, flags_ul);
+
+	if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
+		d->src_connection_idx = src_connection_idx;
+		d->dst_connection_idx = dst_connection_idx;
+		d->usb_bam_type = usb_bam_get_bam_type(gr->gadget->name);
+		d->ipa_params.src_pipe = &(d->src_pipe_idx);
+		d->ipa_params.dst_pipe = &(d->dst_pipe_idx);
+		d->ipa_params.src_idx = src_connection_idx;
+		d->ipa_params.dst_idx = dst_connection_idx;
+
+		/*
+		 * Query pipe type using IPA src/dst index with
+		 * usbbam driver. It is being set either as
+		 * BAM2BAM or SYS2BAM.
+		 */
+		if (usb_bam_get_pipe_type(d->usb_bam_type,
+				d->ipa_params.src_idx, &d->src_pipe_type) ||
+		    usb_bam_get_pipe_type(d->usb_bam_type,
+				d->ipa_params.dst_idx, &d->dst_pipe_type)) {
+			pr_err("%s:usb_bam_get_pipe_type() failed\n",
+				__func__);
+			ret = -EINVAL;
+			usb_ep_free_request(port->port_usb->out, d->rx_req);
+			d->rx_req = NULL;
+			usb_ep_free_request(port->port_usb->in, d->tx_req);
+			d->tx_req = NULL;
+			goto exit;
+		}
+		/*
+		 * Check for pipe_type. If it is BAM2BAM, then it is required
+		 * to disable Xfer complete and Xfer not ready interrupts for
+		 * that particular endpoint. Hence it set endless flag based
+		 * it which is considered into UDC driver while enabling
+		 * USB Endpoint.
+		 */
+		if (d->dst_pipe_type == USB_BAM_PIPE_BAM2BAM)
+			port->port_usb->in->endless = true;
+
+		if (d->src_pipe_type == USB_BAM_PIPE_BAM2BAM)
+			port->port_usb->out->endless = true;
+	}
+
+	ret = usb_ep_enable(gr->in);
+	if (ret) {
+		pr_err("%s: usb_ep_enable failed eptype:IN ep:%pK",
+			__func__, gr->in);
+		usb_ep_free_request(port->port_usb->out, d->rx_req);
+		d->rx_req = NULL;
+		usb_ep_free_request(port->port_usb->in, d->tx_req);
+		d->tx_req = NULL;
+		if (d->dst_pipe_type == USB_BAM_PIPE_BAM2BAM)
+			port->port_usb->in->endless = false;
+
+		if (d->src_pipe_type == USB_BAM_PIPE_BAM2BAM)
+			port->port_usb->out->endless = false;
+		goto exit;
+	}
+	gr->in->driver_data = port;
+
+	/*
+	 * DPL traffic is routed through BAM-DMUX on some targets.
+	 * DPL function has only 1 IN endpoint. Add out endpoint
+	 * checks for BAM-DMUX transport.
+	 */
+	if (gr->out) {
+		ret = usb_ep_enable(gr->out);
+		if (ret) {
+			pr_err("%s: usb_ep_enable failed eptype:OUT ep:%pK",
+					__func__, gr->out);
+			gr->in->driver_data = 0;
+			usb_ep_disable(gr->in);
+			usb_ep_free_request(port->port_usb->out, d->rx_req);
+			d->rx_req = NULL;
+			usb_ep_free_request(port->port_usb->in, d->tx_req);
+			d->tx_req = NULL;
+			if (d->dst_pipe_type == USB_BAM_PIPE_BAM2BAM)
+				port->port_usb->in->endless = false;
+
+			if (d->src_pipe_type == USB_BAM_PIPE_BAM2BAM)
+				port->port_usb->out->endless = false;
+			goto exit;
+		}
+		gr->out->driver_data = port;
+	}
+
+	port->last_event = U_BAM_CONNECT_E;
+	/*
+	 * Increment usage count upon cable connect. Decrement after IPA
+	 * handshake is done in disconnect work (due to cable disconnect)
+	 * or in suspend work.
+	 */
+	if (trans == USB_GADGET_XPORT_BAM2BAM_IPA)
+		usb_gadget_autopm_get_noresume(port->gadget);
+	queue_work(gbam_wq, &port->connect_w);
+
+	ret = 0;
+exit:
+	spin_unlock_irqrestore(&port->port_lock, flags);
+	return ret;
+}
+
+void gbam_data_flush_workqueue(void)
+{
+	pr_debug("%s(): Flushing workqueue\n", __func__);
+	flush_workqueue(gbam_wq);
+}
+
+int gbam_setup(unsigned int no_bam_port)
+{
+	int	i;
+	int	ret;
+	int	bam_port_start = n_bam_ports;
+	int	total_bam_ports = bam_port_start + no_bam_port;
+
+	pr_debug("%s: requested BAM ports:%d\n", __func__, no_bam_port);
+
+	if (!no_bam_port || total_bam_ports > BAM_N_PORTS) {
+		pr_err("%s: Invalid num of ports count:%d\n",
+				__func__, no_bam_port);
+		return -EINVAL;
+	}
+
+	if (!gbam_wq) {
+		gbam_wq = alloc_workqueue("k_gbam", WQ_UNBOUND |
+					WQ_MEM_RECLAIM, 1);
+		if (!gbam_wq) {
+			pr_err("%s: Unable to create workqueue gbam_wq\n",
+					__func__);
+			return -ENOMEM;
+		}
+	}
+
+	for (i = bam_port_start; i < (bam_port_start + no_bam_port); i++) {
+		n_bam_ports++;
+		pr_debug("gbam_port_alloc called for %d\n", i);
+		ret = gbam_port_alloc(i);
+		if (ret) {
+			n_bam_ports--;
+			pr_err("%s: Unable to alloc port:%d\n", __func__, i);
+			goto free_bam_ports;
+		}
+	}
+
+	gbam_debugfs_init();
+
+	return bam_port_start;
+
+free_bam_ports:
+	for (i = 0; i < n_bam_ports; i++)
+		gbam_port_free(i);
+	destroy_workqueue(gbam_wq);
+
+	return ret;
+}
+
+int gbam2bam_setup(unsigned int no_bam2bam_port)
+{
+	int	i;
+	int	ret;
+	int	bam2bam_port_start = n_bam2bam_ports;
+	int	total_bam2bam_ports = bam2bam_port_start + no_bam2bam_port;
+
+	pr_debug("%s: requested BAM2BAM ports:%d\n", __func__, no_bam2bam_port);
+
+	if (!no_bam2bam_port || total_bam2bam_ports > BAM2BAM_N_PORTS) {
+		pr_err("%s: Invalid num of ports count:%d\n",
+				__func__, no_bam2bam_port);
+		return -EINVAL;
+	}
+
+	if (!gbam_wq) {
+		gbam_wq = alloc_workqueue("k_gbam", WQ_UNBOUND |
+					WQ_MEM_RECLAIM, 1);
+		if (!gbam_wq) {
+			pr_err("%s: Unable to create workqueue gbam_wq\n",
+					__func__);
+			return -ENOMEM;
+		}
+	}
+
+	for (i = bam2bam_port_start; i < (bam2bam_port_start +
+				no_bam2bam_port); i++) {
+		n_bam2bam_ports++;
+		ret = gbam2bam_port_alloc(i);
+		if (ret) {
+			n_bam2bam_ports--;
+			pr_err("%s: Unable to alloc port:%d\n", __func__, i);
+			goto free_bam2bam_ports;
+		}
+	}
+
+	gbam_debugfs_init();
+
+	return bam2bam_port_start;
+
+free_bam2bam_ports:
+	for (i = 0; i < n_bam2bam_ports; i++)
+		gbam2bam_port_free(i);
+	destroy_workqueue(gbam_wq);
+
+	return ret;
+}
+
+void gbam_cleanup(void)
+{
+	gbam_debugfs_remove();
+}
+
+void gbam_suspend(struct grmnet *gr, u8 port_num, enum transport_type trans)
+{
+	struct gbam_port	*port;
+	struct bam_ch_info *d;
+	unsigned long flags;
+
+	if (trans != USB_GADGET_XPORT_BAM2BAM_IPA)
+		return;
+
+	port = bam2bam_ports[port_num];
+
+	if (!port) {
+		pr_err("%s: NULL port", __func__);
+		return;
+	}
+
+	spin_lock_irqsave(&port->port_lock, flags);
+
+	d = &port->data_ch;
+
+	pr_debug("%s: suspended port %d\n", __func__, port_num);
+
+	port->last_event = U_BAM_SUSPEND_E;
+	queue_work(gbam_wq, &port->suspend_w);
+
+	spin_unlock_irqrestore(&port->port_lock, flags);
+}
+
+void gbam_resume(struct grmnet *gr, u8 port_num, enum transport_type trans)
+{
+	struct gbam_port	*port;
+	struct bam_ch_info *d;
+	unsigned long flags;
+
+	if (trans != USB_GADGET_XPORT_BAM2BAM_IPA)
+		return;
+
+	port = bam2bam_ports[port_num];
+
+	if (!port) {
+		pr_err("%s: NULL port", __func__);
+		return;
+	}
+
+	spin_lock_irqsave(&port->port_lock, flags);
+
+	d = &port->data_ch;
+
+	pr_debug("%s: resumed port %d\n", __func__, port_num);
+
+	port->last_event = U_BAM_RESUME_E;
+	/*
+	 * Increment usage count here to disallow gadget parent suspend.
+	 * This counter will decrement after IPA handshake is done in
+	 * disconnect work (due to cable disconnect) or in bam_disconnect
+	 * in suspended state.
+	 */
+	usb_gadget_autopm_get_noresume(port->gadget);
+	queue_work(gbam_wq, &port->resume_w);
+
+	spin_unlock_irqrestore(&port->port_lock, flags);
+}
+
+int gbam_mbim_connect(struct usb_gadget *g, struct usb_ep *in,
+			struct usb_ep *out)
+{
+	struct grmnet *gr;
+
+	gr = kzalloc(sizeof(*gr), GFP_ATOMIC);
+	if (!gr)
+		return -ENOMEM;
+	gr->in = in;
+	gr->out = out;
+	gr->gadget = g;
+
+	return gbam_connect(gr, 0, USB_GADGET_XPORT_BAM_DMUX, 0, 0);
+}
+
+void gbam_mbim_disconnect(void)
+{
+	struct gbam_port *port = bam_ports[0].port;
+	struct grmnet *gr = port->port_usb;
+
+	if (!gr) {
+		pr_err("%s: port_usb is NULL\n", __func__);
+		return;
+	}
+
+	gbam_disconnect(gr, 0, USB_GADGET_XPORT_BAM_DMUX);
+	kfree(gr);
+}
+
+int gbam_mbim_setup(void)
+{
+	int ret = 0;
+
+	/*
+	 * MBIM requires only 1 USB_GADGET_XPORT_BAM_DMUX
+	 * port. The port is always 0 and is shared
+	 * between RMNET and MBIM.
+	 */
+	if (!n_bam_ports)
+		ret = gbam_setup(1);
+
+	return ret;
+}
diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index 54220a5..d50510f 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -21,6 +21,8 @@
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
+#include <linux/if_arp.h>
+#include <linux/msm_rmnet.h>
 
 #include "u_ether.h"
 
@@ -89,6 +91,8 @@
 	struct work_struct	rx_work;
 
 	unsigned long		todo;
+	unsigned long		flags;
+	unsigned short		rx_needed_headroom;
 #define	WORK_RX_MEMORY		0
 
 	bool			zlp;
@@ -161,6 +165,25 @@
 	return 0;
 }
 
+static int ueth_change_mtu_ip(struct net_device *net, int new_mtu)
+{
+	struct eth_dev	*dev = netdev_priv(net);
+	unsigned long	flags;
+	int		status = 0;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	if (new_mtu <= 0)
+		status = -EINVAL;
+	else
+		net->mtu = new_mtu;
+
+	DBG(dev, "[%s] MTU change: old=%d new=%d\n", net->name,
+					net->mtu, new_mtu);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return status;
+}
+
 static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p)
 {
 	struct eth_dev *dev = netdev_priv(net);
@@ -900,15 +923,176 @@
 	return 18;
 }
 
+static int ether_ioctl(struct net_device *, struct ifreq *, int);
+
 static const struct net_device_ops eth_netdev_ops = {
 	.ndo_open		= eth_open,
 	.ndo_stop		= eth_stop,
 	.ndo_start_xmit		= eth_start_xmit,
+	.ndo_do_ioctl		= ether_ioctl,
 	.ndo_change_mtu		= ueth_change_mtu,
 	.ndo_set_mac_address 	= eth_mac_addr,
 	.ndo_validate_addr	= eth_validate_addr,
 };
 
+static const struct net_device_ops eth_netdev_ops_ip = {
+	.ndo_open		= eth_open,
+	.ndo_stop		= eth_stop,
+	.ndo_start_xmit		= eth_start_xmit,
+	.ndo_do_ioctl		= ether_ioctl,
+	.ndo_change_mtu		= ueth_change_mtu_ip,
+	.ndo_set_mac_address	= NULL,
+	.ndo_validate_addr	= NULL,
+};
+
+static int rmnet_ioctl_extended(struct net_device *dev, struct ifreq *ifr)
+{
+	struct rmnet_ioctl_extended_s ext_cmd;
+	struct eth_dev *eth_dev = netdev_priv(dev);
+	int rc = 0;
+
+	rc = copy_from_user(&ext_cmd, ifr->ifr_ifru.ifru_data,
+			    sizeof(struct rmnet_ioctl_extended_s));
+
+	if (rc) {
+		DBG(eth_dev, "%s(): copy_from_user() failed\n", __func__);
+		return rc;
+	}
+
+	switch (ext_cmd.extended_ioctl) {
+	case RMNET_IOCTL_GET_SUPPORTED_FEATURES:
+		ext_cmd.u.data = 0;
+		break;
+
+	case RMNET_IOCTL_SET_MRU:
+		if (netif_running(dev))
+			return -EBUSY;
+
+		/* 16K max */
+		if ((size_t)ext_cmd.u.data > 0x4000)
+			return -EINVAL;
+
+		if (eth_dev->port_usb) {
+			eth_dev->port_usb->is_fixed = true;
+			eth_dev->port_usb->fixed_out_len =
+				(size_t) ext_cmd.u.data;
+			DBG(eth_dev, "[%s] rmnet_ioctl(): SET MRU to %u\n",
+				dev->name, eth_dev->port_usb->fixed_out_len);
+		} else {
+			pr_err("[%s]: %s: SET MRU failed. Cable disconnected\n",
+				dev->name, __func__);
+			return -ENODEV;
+		}
+		break;
+
+	case RMNET_IOCTL_GET_MRU:
+		if (eth_dev->port_usb) {
+			ext_cmd.u.data = eth_dev->port_usb->is_fixed ?
+					eth_dev->port_usb->fixed_out_len :
+					dev->mtu;
+		} else {
+			pr_err("[%s]: %s: GET MRU failed. Cable disconnected\n",
+				dev->name, __func__);
+			return -ENODEV;
+		}
+		break;
+
+	case RMNET_IOCTL_GET_DRIVER_NAME:
+		strlcpy(ext_cmd.u.if_name, dev->name,
+			sizeof(ext_cmd.u.if_name));
+		break;
+
+	default:
+		break;
+	}
+
+	rc = copy_to_user(ifr->ifr_ifru.ifru_data, &ext_cmd,
+			  sizeof(struct rmnet_ioctl_extended_s));
+
+	if (rc)
+		DBG(eth_dev, "%s(): copy_to_user() failed\n", __func__);
+	return rc;
+}
+
+static int ether_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct eth_dev	*eth_dev = netdev_priv(dev);
+	void __user *addr = (void __user *) ifr->ifr_ifru.ifru_data;
+	int		prev_mtu = dev->mtu;
+	u32		state, old_opmode;
+	int		rc = -EFAULT;
+
+	old_opmode = eth_dev->flags;
+	/* Process IOCTL command */
+	switch (cmd) {
+	case RMNET_IOCTL_SET_LLP_ETHERNET:	/*Set Ethernet protocol*/
+		/* Perform Ethernet config only if in IP mode currently*/
+		if (test_bit(RMNET_MODE_LLP_IP, &eth_dev->flags)) {
+			ether_setup(dev);
+			dev->mtu = prev_mtu;
+			dev->netdev_ops = &eth_netdev_ops;
+			clear_bit(RMNET_MODE_LLP_IP, &eth_dev->flags);
+			set_bit(RMNET_MODE_LLP_ETH, &eth_dev->flags);
+			DBG(eth_dev, "[%s] ioctl(): set Ethernet proto mode\n",
+					dev->name);
+		}
+		if (test_bit(RMNET_MODE_LLP_ETH, &eth_dev->flags))
+			rc = 0;
+		break;
+
+	case RMNET_IOCTL_SET_LLP_IP:		/* Set RAWIP protocol*/
+		/* Perform IP config only if in Ethernet mode currently*/
+		if (test_bit(RMNET_MODE_LLP_ETH, &eth_dev->flags)) {
+			/* Undo config done in ether_setup() */
+			dev->header_ops = NULL;  /* No header */
+			dev->type = ARPHRD_RAWIP;
+			dev->hard_header_len = 0;
+			dev->mtu = prev_mtu;
+			dev->addr_len = 0;
+			dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST);
+			dev->netdev_ops = &eth_netdev_ops_ip;
+			clear_bit(RMNET_MODE_LLP_ETH, &eth_dev->flags);
+			set_bit(RMNET_MODE_LLP_IP, &eth_dev->flags);
+			DBG(eth_dev, "[%s] ioctl(): set IP protocol mode\n",
+					dev->name);
+		}
+		if (test_bit(RMNET_MODE_LLP_IP, &eth_dev->flags))
+			rc = 0;
+		break;
+
+	case RMNET_IOCTL_GET_LLP:	/* Get link protocol state */
+		state = eth_dev->flags & (RMNET_MODE_LLP_ETH
+						| RMNET_MODE_LLP_IP);
+		if (copy_to_user(addr, &state, sizeof(state)))
+			break;
+		rc = 0;
+		break;
+
+	case RMNET_IOCTL_SET_RX_HEADROOM:	/* Set RX headroom */
+		if (copy_from_user(&eth_dev->rx_needed_headroom, addr,
+					sizeof(eth_dev->rx_needed_headroom)))
+			break;
+		DBG(eth_dev, "[%s] ioctl(): set RX HEADROOM: %x\n",
+				dev->name, eth_dev->rx_needed_headroom);
+		rc = 0;
+		break;
+
+	case RMNET_IOCTL_EXTENDED:
+		rc = rmnet_ioctl_extended(dev, ifr);
+		break;
+
+	default:
+		pr_err("[%s] error: ioctl called for unsupported cmd[%d]",
+			dev->name, cmd);
+		rc = -EINVAL;
+	}
+
+	DBG(eth_dev, "[%s] %s: cmd=0x%x opmode old=0x%08x new=0x%08lx\n",
+		dev->name, __func__, cmd, old_opmode, eth_dev->flags);
+
+	return rc;
+}
+
 static struct device_type gadget_type = {
 	.name	= "gadget",
 };
@@ -968,6 +1152,9 @@
 
 	net->ethtool_ops = &ops;
 
+	/* set operation mode to eth by default */
+	set_bit(RMNET_MODE_LLP_ETH, &dev->flags);
+
 	dev->gadget = g;
 	SET_NETDEV_DEV(net, &g->dev);
 	SET_NETDEV_DEVTYPE(net, &gadget_type);
@@ -1025,6 +1212,10 @@
 	net->netdev_ops = &eth_netdev_ops;
 
 	net->ethtool_ops = &ops;
+
+	/* set operation mode to eth by default */
+	set_bit(RMNET_MODE_LLP_ETH, &dev->flags);
+
 	SET_NETDEV_DEVTYPE(net, &gadget_type);
 
 	return net;
diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c
index 19f3f18..ad4c0a3 100644
--- a/drivers/usb/phy/phy-msm-qusb-v2.c
+++ b/drivers/usb/phy/phy-msm-qusb-v2.c
@@ -71,6 +71,8 @@
 #define SQ_CTRL1_CHIRP_DISABLE		0x20
 #define SQ_CTRL2_CHIRP_DISABLE		0x80
 
+#define DEBUG_CTRL1_OVERRIDE_VAL	0x09
+
 /* PERIPH_SS_PHY_REFGEN_NORTH_BG_CTRL register bits */
 #define BANDGAP_BYPASS			BIT(0)
 
@@ -84,6 +86,7 @@
 	BIAS_CTRL_2,
 	SQ_CTRL1,
 	SQ_CTRL2,
+	DEBUG_CTRL1,
 	USB2_PHY_REG_MAX,
 };
 
@@ -180,7 +183,11 @@
 			err = PTR_ERR(buf);
 		}
 	} else {
-		val = *buf;
+		/*
+		 * The bits are read from bit-0 to bit-29
+		 * We're interested in bits 28:29
+		 */
+		val = (*buf >> 28) & 0x3;
 		kfree(buf);
 	}
 
@@ -553,6 +560,11 @@
 			writel_relaxed(BIAS_CTRL_2_OVERRIDE_VAL,
 				qphy->base + qphy->phy_reg[BIAS_CTRL_2]);
 
+	/* if soc revision is mentioned override DEBUG_CTRL1 value */
+	if (qphy->soc_min_rev)
+		writel_relaxed(DEBUG_CTRL1_OVERRIDE_VAL,
+				qphy->base + qphy->phy_reg[DEBUG_CTRL1]);
+
 	/* ensure above writes are completed before re-enabling PHY */
 	wmb();
 
@@ -1228,7 +1240,7 @@
 	 * qusb_phy_disable_chirp is not required if soc version is
 	 * mentioned and is not base version.
 	 */
-	if (qphy->soc_min_rev == 0)
+	if (!qphy->soc_min_rev)
 		qphy->phy.disable_chirp	= qusb_phy_disable_chirp;
 
 	qphy->phy.start_port_reset	= qusb_phy_enable_ext_pulldown;
diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c
index fffaad4..0b3b223 100644
--- a/fs/sdcardfs/derived_perm.c
+++ b/fs/sdcardfs/derived_perm.c
@@ -32,23 +32,20 @@
 	ci->data->under_android = pi->data->under_android;
 	ci->data->under_cache = pi->data->under_cache;
 	ci->data->under_obb = pi->data->under_obb;
-	set_top(ci, pi->top_data);
 }
 
 /* helper function for derived state */
 void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid,
-					uid_t uid, bool under_android,
-					struct sdcardfs_inode_data *top)
+					uid_t uid)
 {
 	struct sdcardfs_inode_info *info = SDCARDFS_I(inode);
 
 	info->data->perm = perm;
 	info->data->userid = userid;
 	info->data->d_uid = uid;
-	info->data->under_android = under_android;
+	info->data->under_android = false;
 	info->data->under_cache = false;
 	info->data->under_obb = false;
-	set_top(info, top);
 }
 
 /* While renaming, there is a point where we want the path from dentry,
@@ -58,8 +55,8 @@
 				const struct qstr *name)
 {
 	struct sdcardfs_inode_info *info = SDCARDFS_I(d_inode(dentry));
-	struct sdcardfs_inode_data *parent_data =
-			SDCARDFS_I(d_inode(parent))->data;
+	struct sdcardfs_inode_info *parent_info = SDCARDFS_I(d_inode(parent));
+	struct sdcardfs_inode_data *parent_data = parent_info->data;
 	appid_t appid;
 	unsigned long user_num;
 	int err;
@@ -80,13 +77,15 @@
 	inherit_derived_state(d_inode(parent), d_inode(dentry));
 
 	/* Files don't get special labels */
-	if (!S_ISDIR(d_inode(dentry)->i_mode))
+	if (!S_ISDIR(d_inode(dentry)->i_mode)) {
+		set_top(info, parent_info);
 		return;
+	}
 	/* Derive custom permissions based on parent and current node */
 	switch (parent_data->perm) {
 	case PERM_INHERIT:
 	case PERM_ANDROID_PACKAGE_CACHE:
-		/* Already inherited above */
+		set_top(info, parent_info);
 		break;
 	case PERM_PRE_ROOT:
 		/* Legacy internal layout places users at top level */
@@ -96,7 +95,6 @@
 			info->data->userid = 0;
 		else
 			info->data->userid = user_num;
-		set_top(info, info->data);
 		break;
 	case PERM_ROOT:
 		/* Assume masked off by default. */
@@ -104,24 +102,24 @@
 			/* App-specific directories inside; let anyone traverse */
 			info->data->perm = PERM_ANDROID;
 			info->data->under_android = true;
-			set_top(info, info->data);
+		} else {
+			set_top(info, parent_info);
 		}
 		break;
 	case PERM_ANDROID:
 		if (qstr_case_eq(name, &q_data)) {
 			/* App-specific directories inside; let anyone traverse */
 			info->data->perm = PERM_ANDROID_DATA;
-			set_top(info, info->data);
 		} else if (qstr_case_eq(name, &q_obb)) {
 			/* App-specific directories inside; let anyone traverse */
 			info->data->perm = PERM_ANDROID_OBB;
 			info->data->under_obb = true;
-			set_top(info, info->data);
 			/* Single OBB directory is always shared */
 		} else if (qstr_case_eq(name, &q_media)) {
 			/* App-specific directories inside; let anyone traverse */
 			info->data->perm = PERM_ANDROID_MEDIA;
-			set_top(info, info->data);
+		} else {
+			set_top(info, parent_info);
 		}
 		break;
 	case PERM_ANDROID_OBB:
@@ -132,13 +130,13 @@
 		if (appid != 0 && !is_excluded(name->name, parent_data->userid))
 			info->data->d_uid =
 				multiuser_get_uid(parent_data->userid, appid);
-		set_top(info, info->data);
 		break;
 	case PERM_ANDROID_PACKAGE:
 		if (qstr_case_eq(name, &q_cache)) {
 			info->data->perm = PERM_ANDROID_PACKAGE_CACHE;
 			info->data->under_cache = true;
 		}
+		set_top(info, parent_info);
 		break;
 	}
 }
diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c
index 8ed0ea1..137d876 100644
--- a/fs/sdcardfs/inode.c
+++ b/fs/sdcardfs/inode.c
@@ -821,8 +821,8 @@
 	return err;
 }
 
-static int sdcardfs_fillattr(struct vfsmount *mnt,
-				struct inode *inode, struct kstat *stat)
+static int sdcardfs_fillattr(struct vfsmount *mnt, struct inode *inode,
+				struct kstat *lower_stat, struct kstat *stat)
 {
 	struct sdcardfs_inode_info *info = SDCARDFS_I(inode);
 	struct sdcardfs_inode_data *top = top_data_get(info);
@@ -837,12 +837,12 @@
 	stat->uid = make_kuid(&init_user_ns, top->d_uid);
 	stat->gid = make_kgid(&init_user_ns, get_gid(mnt, top));
 	stat->rdev = inode->i_rdev;
-	stat->size = i_size_read(inode);
-	stat->atime = inode->i_atime;
-	stat->mtime = inode->i_mtime;
-	stat->ctime = inode->i_ctime;
-	stat->blksize = (1 << inode->i_blkbits);
-	stat->blocks = inode->i_blocks;
+	stat->size = lower_stat->size;
+	stat->atime = lower_stat->atime;
+	stat->mtime = lower_stat->mtime;
+	stat->ctime = lower_stat->ctime;
+	stat->blksize = lower_stat->blksize;
+	stat->blocks = lower_stat->blocks;
 	data_put(top);
 	return 0;
 }
@@ -868,8 +868,7 @@
 		goto out;
 	sdcardfs_copy_and_fix_attrs(d_inode(dentry),
 			      d_inode(lower_path.dentry));
-	err = sdcardfs_fillattr(mnt, d_inode(dentry), stat);
-	stat->blocks = lower_stat.blocks;
+	err = sdcardfs_fillattr(mnt, d_inode(dentry), &lower_stat, stat);
 out:
 	sdcardfs_put_lower_path(dentry, &lower_path);
 	return err;
diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c
index 0a2b516..37d4864 100644
--- a/fs/sdcardfs/main.c
+++ b/fs/sdcardfs/main.c
@@ -334,13 +334,11 @@
 	mutex_lock(&sdcardfs_super_list_lock);
 	if (sb_info->options.multiuser) {
 		setup_derived_state(d_inode(sb->s_root), PERM_PRE_ROOT,
-				sb_info->options.fs_user_id, AID_ROOT,
-				false, SDCARDFS_I(d_inode(sb->s_root))->data);
+				sb_info->options.fs_user_id, AID_ROOT);
 		snprintf(sb_info->obbpath_s, PATH_MAX, "%s/obb", dev_name);
 	} else {
 		setup_derived_state(d_inode(sb->s_root), PERM_ROOT,
-				sb_info->options.fs_user_id, AID_ROOT,
-				false, SDCARDFS_I(d_inode(sb->s_root))->data);
+				sb_info->options.fs_user_id, AID_ROOT);
 		snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name);
 	}
 	fixup_tmp_permissions(d_inode(sb->s_root));
diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h
index d1d8bab..eda8e7a 100644
--- a/fs/sdcardfs/sdcardfs.h
+++ b/fs/sdcardfs/sdcardfs.h
@@ -201,6 +201,7 @@
 	struct sdcardfs_inode_data *data;
 
 	/* top folder for ownership */
+	spinlock_t top_lock;
 	struct sdcardfs_inode_data *top_data;
 
 	struct inode vfs_inode;
@@ -379,7 +380,12 @@
 static inline struct sdcardfs_inode_data *top_data_get(
 		struct sdcardfs_inode_info *info)
 {
-	return data_get(info->top_data);
+	struct sdcardfs_inode_data *top_data;
+
+	spin_lock(&info->top_lock);
+	top_data = data_get(info->top_data);
+	spin_unlock(&info->top_lock);
+	return top_data;
 }
 
 extern void data_release(struct kref *ref);
@@ -401,15 +407,20 @@
 }
 
 static inline void set_top(struct sdcardfs_inode_info *info,
-			struct sdcardfs_inode_data *top)
+			struct sdcardfs_inode_info *top_owner)
 {
-	struct sdcardfs_inode_data *old_top = info->top_data;
+	struct sdcardfs_inode_data *old_top;
+	struct sdcardfs_inode_data *new_top = NULL;
 
-	if (top)
-		data_get(top);
-	info->top_data = top;
+	if (top_owner)
+		new_top = top_data_get(top_owner);
+
+	spin_lock(&info->top_lock);
+	old_top = info->top_data;
+	info->top_data = new_top;
 	if (old_top)
 		data_put(old_top);
+	spin_unlock(&info->top_lock);
 }
 
 static inline int get_gid(struct vfsmount *mnt,
@@ -513,8 +524,7 @@
 };
 
 extern void setup_derived_state(struct inode *inode, perm_t perm,
-		userid_t userid, uid_t uid, bool under_android,
-		struct sdcardfs_inode_data *top);
+			userid_t userid, uid_t uid);
 extern void get_derived_permission(struct dentry *parent, struct dentry *dentry);
 extern void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, const struct qstr *name);
 extern void fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit);
diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c
index b89947d..72d89b9 100644
--- a/fs/sdcardfs/super.c
+++ b/fs/sdcardfs/super.c
@@ -215,6 +215,9 @@
 
 	i->data = d;
 	kref_init(&d->refcount);
+	i->top_data = d;
+	spin_lock_init(&i->top_lock);
+	kref_get(&d->refcount);
 
 	i->vfs_inode.i_version = 1;
 	return &i->vfs_inode;
diff --git a/include/dt-bindings/clock/msm-clocks-8952.h b/include/dt-bindings/clock/msm-clocks-8952.h
index 80a95d9..e8afdba 100644
--- a/include/dt-bindings/clock/msm-clocks-8952.h
+++ b/include/dt-bindings/clock/msm-clocks-8952.h
@@ -1,4 +1,5 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/*
+ * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -317,7 +318,6 @@
 #define clk_ln_bb_clk				0x3ab0b36d
 #define clk_ln_bb_a_clk				0xc7257ea8
 
-
 /* clock_debug controlled clocks */
 #define clk_gcc_debug_mux			0x8121ac15
 #define clk_rpm_debug_mux			0x25cd1f3a
@@ -341,4 +341,11 @@
 #define clk_audio_pmi_clk			0xb7ba2274
 #define clk_audio_lpass_mclk			0x575ec22b
 
+/* GCC block resets */
+#define GCC_CAMSS_MICRO_BCR			0
+#define GCC_USB_FS_BCR				1
+#define GCC_USB_HS_BCR				2
+#define GCC_USB2_HS_PHY_ONLY_BCR		3
+#define GCC_QUSB2_PHY_BCR			4
+
 #endif
diff --git a/include/dt-bindings/clock/msm-clocks-hwio-8952.h b/include/dt-bindings/clock/msm-clocks-hwio-8952.h
new file mode 100644
index 0000000..888c2c7
--- /dev/null
+++ b/include/dt-bindings/clock/msm-clocks-hwio-8952.h
@@ -0,0 +1,444 @@
+/*
+ * Copyright (c) 2014-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_CLOCKS_8952_HWIO_H
+#define __MSM_CLOCKS_8952_HWIO_H
+
+#define GPLL0_MODE			0x21000
+#define GPLL0_STATUS			0x2101C
+#define GPLL6_STATUS			0x3701C
+#define GPLL3_MODE			0x22000
+#define GPLL4_MODE			0x24000
+#define GPLL4_STATUS			0x24024
+#define GX_DOMAIN_MISC			0x5B00C
+#define SYS_MM_NOC_AXI_CBCR		0x3D008
+#define BIMC_GFX_CBCR			0x59034
+#define MSS_CFG_AHB_CBCR		0x49000
+#define	MSS_Q6_BIMC_AXI_CBCR		0x49004
+#define USB_HS_BCR			0x41000
+#define USB_HS_SYSTEM_CBCR		0x41004
+#define USB_HS_AHB_CBCR			0x41008
+#define USB_HS_PHY_CFG_AHB_CBCR		0x41030
+#define USB_HS_SYSTEM_CMD_RCGR		0x41010
+#define USB2A_PHY_SLEEP_CBCR		0x4102C
+#define USB_FS_SYSTEM_CBCR		0x3F004
+#define USB_FS_AHB_CBCR			0x3F008
+#define USB_FS_IC_CBCR			0x3F030
+#define USB_FS_SYSTEM_CMD_RCGR		0x3F010
+#define USB_FS_IC_CMD_RCGR		0x3F034
+#define USB2_HS_PHY_ONLY_BCR		0x41034
+#define QUSB2_PHY_BCR			0x4103C
+#define SDCC1_APPS_CMD_RCGR		0x42004
+#define SDCC1_APPS_CBCR			0x42018
+#define SDCC1_AHB_CBCR			0x4201C
+#define SDCC1_ICE_CORE_CMD_RCGR		0x5D000
+#define SDCC1_ICE_CORE_CBCR		0x5D014
+#define SDCC2_APPS_CMD_RCGR		0x43004
+#define SDCC2_APPS_CBCR			0x43018
+#define SDCC2_AHB_CBCR			0x4301C
+#define BLSP1_AHB_CBCR			0x01008
+#define BLSP1_QUP1_SPI_APPS_CBCR	0x02004
+#define BLSP1_QUP1_I2C_APPS_CBCR	0x02008
+#define BLSP1_QUP1_I2C_APPS_CMD_RCGR	0x0200C
+#define BLSP1_QUP2_I2C_APPS_CMD_RCGR	0x03000
+#define BLSP1_QUP3_I2C_APPS_CMD_RCGR	0x04000
+#define BLSP1_QUP4_I2C_APPS_CMD_RCGR	0x05000
+#define BLSP1_QUP1_SPI_APPS_CMD_RCGR	0x02024
+#define BLSP1_UART1_APPS_CBCR		0x0203C
+#define BLSP1_UART1_APPS_CMD_RCGR	0x02044
+#define BLSP1_QUP2_SPI_APPS_CBCR	0x0300C
+#define BLSP1_QUP2_I2C_APPS_CBCR	0x03010
+#define BLSP1_QUP2_SPI_APPS_CMD_RCGR	0x03014
+#define BLSP1_UART2_APPS_CBCR		0x0302C
+#define BLSP1_UART2_APPS_CMD_RCGR	0x03034
+#define BLSP1_QUP3_SPI_APPS_CBCR	0x0401C
+#define BLSP1_QUP3_I2C_APPS_CBCR	0x04020
+#define BLSP1_QUP3_SPI_APPS_CMD_RCGR	0x04024
+#define BLSP1_QUP4_SPI_APPS_CBCR	0x0501C
+#define BLSP1_QUP4_I2C_APPS_CBCR	0x05020
+#define BLSP1_QUP4_SPI_APPS_CMD_RCGR	0x05024
+#define BLSP2_AHB_CBCR			0x0B008
+#define BLSP2_QUP1_SPI_APPS_CBCR	0x0C004
+#define BLSP2_QUP1_I2C_APPS_CBCR	0x0C008
+#define BLSP2_QUP1_I2C_APPS_CMD_RCGR	0x0C00C
+#define BLSP2_QUP2_I2C_APPS_CMD_RCGR	0x0D000
+#define BLSP2_QUP3_I2C_APPS_CMD_RCGR	0x0F000
+#define BLSP2_QUP4_I2C_APPS_CMD_RCGR	0x18000
+#define BLSP2_QUP1_SPI_APPS_CMD_RCGR	0x0C024
+#define BLSP2_UART1_APPS_CBCR		0x0C03C
+#define BLSP2_UART1_APPS_CMD_RCGR	0x0C044
+#define BLSP2_QUP2_SPI_APPS_CBCR	0x0D00C
+#define BLSP2_QUP2_I2C_APPS_CBCR	0x0D010
+#define BLSP2_QUP2_SPI_APPS_CMD_RCGR	0x0D014
+#define BLSP2_UART2_APPS_CBCR		0x0D02C
+#define BLSP2_UART2_APPS_CMD_RCGR	0x0D034
+#define BLSP2_QUP3_SPI_APPS_CBCR	0x0F01C
+#define BLSP2_QUP3_I2C_APPS_CBCR	0x0F020
+#define BLSP2_QUP3_SPI_APPS_CMD_RCGR	0x0F024
+#define BLSP2_QUP4_SPI_APPS_CBCR	0x1801C
+#define BLSP2_QUP4_I2C_APPS_CBCR	0x18020
+#define BLSP2_QUP4_SPI_APPS_CMD_RCGR	0x18024
+#define PDM_AHB_CBCR			0x44004
+#define PDM2_CBCR			0x4400C
+#define PDM2_CMD_RCGR			0x44010
+#define PRNG_AHB_CBCR			0x13004
+#define BOOT_ROM_AHB_CBCR		0x1300C
+#define CRYPTO_CMD_RCGR			0x16004
+#define CRYPTO_CBCR			0x1601C
+#define CRYPTO_AXI_CBCR			0x16020
+#define CRYPTO_AHB_CBCR			0x16024
+#define GCC_XO_DIV4_CBCR		0x30034
+#define APSS_AHB_CMD_RCGR		0x46000
+#define GCC_PLLTEST_PAD_CFG		0x7400C
+#define GFX_TBU_CBCR			0x12010
+#define VENUS_TBU_CBCR			0x12014
+#define APSS_TCU_CBCR			0x12018
+#define MDP_TBU_CBCR			0x1201C
+#define GFX_TCU_CBCR			0x12020
+#define JPEG_TBU_CBCR			0x12034
+#define SMMU_CFG_CBCR			0x12038
+#define QDSS_DAP_CBCR			0x29084
+#define VFE_TBU_CBCR			0x1203C
+#define VFE1_TBU_CBCR			0x12090
+#define CPP_TBU_CBCR			0x12040
+#define APCS_GPLL_ENA_VOTE		0x45000
+#define APCS_CLOCK_BRANCH_ENA_VOTE	0x45004
+#define APCS_SMMU_CLOCK_BRANCH_ENA_VOTE	0x4500C
+#define GCC_DEBUG_CLK_CTL		0x74000
+#define CLOCK_FRQ_MEASURE_CTL		0x74004
+#define CLOCK_FRQ_MEASURE_STATUS	0x74008
+#define GP1_CBCR			0x08000
+#define GP1_CMD_RCGR			0x08004
+#define GP1_CFG_RCGR			0x08008
+#define GP2_CBCR			0x09000
+#define GP2_CMD_RCGR			0x09004
+#define GP3_CBCR			0x0A000
+#define GP3_CMD_RCGR			0x0A004
+#define VCODEC0_CMD_RCGR		0x4C000
+#define VENUS0_VCODEC0_CBCR		0x4C01C
+#define VENUS0_CORE0_VCODEC0_CBCR	0x4C02C
+#define VENUS0_CORE1_VCODEC0_CBCR	0x4C034
+#define VENUS0_AHB_CBCR			0x4C020
+#define VENUS0_AXI_CBCR			0x4C024
+#define PCLK0_CMD_RCGR			0x4D000
+#define MDP_CMD_RCGR			0x4D014
+#define VSYNC_CMD_RCGR			0x4D02C
+#define BYTE0_CMD_RCGR			0x4D044
+#define ESC0_CMD_RCGR			0x4D05C
+#define MDSS_AHB_CBCR			0x4D07C
+#define MDSS_AXI_CBCR			0x4D080
+#define MDSS_PCLK0_CBCR			0x4D084
+#define MDSS_MDP_CBCR			0x4D088
+#define MDSS_VSYNC_CBCR			0x4D090
+#define MDSS_BYTE0_CBCR			0x4D094
+#define MDSS_ESC0_CBCR			0x4D098
+#define CSI0PHYTIMER_CMD_RCGR		0x4E000
+#define CAMSS_CSI0PHYTIMER_CBCR		0x4E01C
+#define CSI0_CMD_RCGR			0x4E020
+#define CAMSS_CSI0_CBCR			0x4E03C
+#define CAMSS_CSI0_AHB_CBCR		0x4E040
+#define CAMSS_CSI0PHY_CBCR		0x4E048
+#define CAMSS_CSI0RDI_CBCR		0x4E050
+#define CAMSS_CSI0PIX_CBCR		0x4E058
+#define CSI1PHYTIMER_CMD_RCGR		0x4F000
+#define CSI1_CMD_RCGR			0x4F020
+#define CAMSS_CSI1_CBCR			0x4F03C
+#define CAMSS_CSI1PHYTIMER_CBCR		0x4F01C
+#define CAMSS_CSI1_AHB_CBCR		0x4F040
+#define CAMSS_CSI1PHY_CBCR		0x4F048
+#define CAMSS_CSI1RDI_CBCR		0x4F050
+#define CAMSS_CSI1PIX_CBCR		0x4F058
+#define CSI2_CMD_RCGR			0x3C020
+#define CAMSS_CSI2_CBCR			0x3C03C
+#define CAMSS_CSI2_AHB_CBCR		0x3C040
+#define CAMSS_CSI2PHY_CBCR		0x3C048
+#define CAMSS_CSI2RDI_CBCR		0x3C050
+#define CAMSS_CSI2PIX_CBCR		0x3C058
+#define CAMSS_ISPIF_AHB_CBCR		0x50004
+#define CCI_CMD_RCGR			0x51000
+#define CAMSS_CCI_CBCR			0x51018
+#define CAMSS_CCI_AHB_CBCR		0x5101C
+#define MCLK0_CMD_RCGR			0x52000
+#define CAMSS_MCLK0_CBCR		0x52018
+#define MCLK1_CMD_RCGR			0x53000
+#define CAMSS_MCLK1_CBCR		0x53018
+#define MCLK2_CMD_RCGR			0x5C000
+#define CAMSS_MCLK2_CBCR		0x5C018
+#define MM_GP0_CMD_RCGR			0x54000
+#define CAMSS_GP0_CBCR			0x54018
+#define MM_GP1_CMD_RCGR			0x55000
+#define CAMSS_GP1_CBCR			0x55018
+#define CAMSS_TOP_AHB_CBCR		0x5A014
+#define CAMSS_AHB_CBCR			0x56004
+#define CAMSS_MICRO_AHB_CBCR		0x5600C
+#define CAMSS_MICRO_BCR			0x56008
+#define JPEG0_CMD_RCGR			0x57000
+#define CAMSS_JPEG0_CBCR		0x57020
+#define CAMSS_JPEG_AHB_CBCR		0x57024
+#define CAMSS_JPEG_AXI_CBCR		0x57028
+#define VFE0_CMD_RCGR			0x58000
+#define CPP_CMD_RCGR			0x58018
+#define CAMSS_VFE0_CBCR			0x58038
+#define CAMSS_CPP_CBCR			0x5803C
+#define CAMSS_CPP_AHB_CBCR		0x58040
+#define CAMSS_VFE_AHB_CBCR		0x58044
+#define CAMSS_VFE_AXI_CBCR		0x58048
+#define CAMSS_CSI_VFE0_CBCR		0x58050
+#define VFE1_CMD_RCGR			0x58054
+#define CAMSS_VFE1_CBCR			0x5805C
+#define CAMSS_VFE1_AHB_CBCR		0x58060
+#define CAMSS_CPP_AXI_CBCR		0x58064
+#define CAMSS_VFE1_AXI_CBCR		0x58068
+#define CAMSS_CSI_VFE1_CBCR		0x58074
+#define GFX3D_CMD_RCGR			0x59000
+#define OXILI_GFX3D_CBCR		0x59020
+#define OXILI_GMEM_CBCR			0x59024
+#define OXILI_AHB_CBCR			0x59028
+#define OXILI_TIMER_CBCR		0x59040
+#define OXILI_AON_CBCR			0x5904C
+#define CAMSS_TOP_AHB_CMD_RCGR		0x5A000
+#define BIMC_GPU_CBCR			0x59030
+#define GTCU_AHB_CBCR			0x12044
+#define IPA_TBU_CBCR			0x120A0
+#define SYSTEM_MM_NOC_CMD_RCGR		0x3D000
+#define USB_FS_BCR			0x3F000
+
+#define APCS_CLOCK_SLEEP_ENA_VOTE	0x45008
+#define BYTE1_CMD_RCGR			0x4D0B0
+#define ESC1_CMD_RCGR			0x4D0A8
+#define PCLK1_CMD_RCGR			0x4D0B8
+#define MDSS_BYTE1_CBCR			0x4D0A0
+#define MDSS_ESC1_CBCR			0x4D09C
+#define MDSS_PCLK1_CBCR			0x4D0A4
+#define DCC_CBCR			0x77004
+
+#define RPM_MISC_CLK_TYPE		0x306b6c63
+#define RPM_BUS_CLK_TYPE		0x316b6c63
+#define RPM_MEM_CLK_TYPE		0x326b6c63
+#define RPM_IPA_CLK_TYPE		0x617069
+#define RPM_SMD_KEY_ENABLE		0x62616E45
+
+#define CXO_CLK_SRC_ID			0x0
+#define QDSS_CLK_ID			0x1
+
+#define PNOC_CLK_ID			0x0
+#define SNOC_CLK_ID			0x1
+#define SYSMMNOC_CLK_ID			0x2
+#define BIMC_CLK_ID			0x0
+#define BIMC_GPU_CLK_ID			0x2
+#define IPA_CLK_ID			0x0
+
+#define BUS_SCALING		0x2
+
+/* XO clock */
+#define BB_CLK1_ID		0x1
+#define BB_CLK2_ID		0x2
+#define RF_CLK2_ID		0x5
+#define LN_BB_CLK_ID		0x8
+#define DIV_CLK1_ID		0xb
+#define DIV_CLK2_ID		0xc
+
+#define APCS_CCI_PLL_MODE		0x00000
+#define APCS_CCI_PLL_L_VAL		0x00004
+#define APCS_CCI_PLL_M_VAL		0x00008
+#define APCS_CCI_PLL_N_VAL		0x0000C
+#define APCS_CCI_PLL_USER_CTL		0x00010
+#define APCS_CCI_PLL_CONFIG_CTL		0x00014
+#define APCS_CCI_PLL_STATUS		0x0001C
+
+#define APCS_C0_PLL_MODE		0x00000
+#define APCS_C0_PLL_L_VAL		0x00004
+#define APCS_C0_PLL_M_VAL		0x00008
+#define APCS_C0_PLL_N_VAL		0x0000C
+#define APCS_C0_PLL_USER_CTL		0x00010
+#define APCS_C0_PLL_CONFIG_CTL		0x00014
+#define APCS_C0_PLL_STATUS		0x0001C
+
+#define APCS_C1_PLL_MODE		0x00000
+#define APCS_C1_PLL_L_VAL		0x00004
+#define APCS_C1_PLL_M_VAL		0x00008
+#define APCS_C1_PLL_N_VAL		0x0000C
+#define APCS_C1_PLL_USER_CTL		0x00010
+#define APCS_C1_PLL_CONFIG_CTL		0x00014
+#define APCS_C1_PLL_STATUS		0x0001C
+
+
+#define CLKFLAG_WAKEUP_CYCLES		0x0
+#define CLKFLAG_SLEEP_CYCLES		0x0
+
+/* Mux source select values */
+#define xo_source_val			0
+#define xo_a_source_val			0
+#define gpll0_source_val		1
+#define gpll3_source_val		2
+#define gpll0_out_main_source_val	1   /* sdcc1_ice_core */
+/* cci_clk_src and usb_fs_system_clk_src */
+#define gpll0_out_aux_source_val	2
+#define gpll4_source_val		2   /* sdcc1_apss_clk_src */
+#define gpll4_out_source_val		3   /* sdcc1_apss_clk_src */
+#define gpll6_source_val		2   /* mclk0_2_clk_src */
+#define gpll6_aux_source_val		3   /* gfx3d_clk_src */
+#define gpll6_out_main_source_val	1   /* usb_fs_ic_clk_src */
+#define dsi0_phypll_source_val		1
+#define dsi0_0phypll_source_val		1   /* byte0_clk & pclk0_clk */
+#define dsi0_1phypll_source_val         3   /* byte1_clk & pclk1_clk */
+#define dsi1_0phypll_source_val         3   /* byte0_clk & pclk0_clk */
+#define dsi1_1phypll_source_val         1   /* byte1_clk & pclk1_clk */
+
+
+#define F(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.src_clk = &s##_clk_src.c, \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)) * !!(n), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+			| BVAL(10, 8, s##_source_val), \
+	}
+
+#define F_SLEW(f, s_f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.src_freq = (s_f), \
+		.src_clk = &s##_clk_src.c, \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)) * !!(n), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+			| BVAL(10, 8, s##_source_val), \
+	}
+
+#define F_APCS_PLL(f, l, m, n, pre_div, post_div, vco) \
+	{ \
+		.freq_hz = (f), \
+		.l_val = (l), \
+		.m_val = (m), \
+		.n_val = (n), \
+		.pre_div_val = BVAL(12, 12, (pre_div)), \
+		.post_div_val = BVAL(9, 8, (post_div)), \
+		.vco_val = BVAL(29, 28, (vco)), \
+	}
+
+#define VDD_DIG_FMAX_MAP1(l1, f1) \
+	.vdd_class = &vdd_dig, \
+	.fmax = (unsigned long[VDD_DIG_NUM]) {  \
+		[VDD_DIG_##l1] = (f1),          \
+	},                                      \
+	.num_fmax = VDD_DIG_NUM
+
+#define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
+	.vdd_class = &vdd_dig, \
+	.fmax = (unsigned long[VDD_DIG_NUM]) {  \
+		[VDD_DIG_##l1] = (f1),          \
+		[VDD_DIG_##l2] = (f2),          \
+	},                                      \
+	.num_fmax = VDD_DIG_NUM
+
+# define OVERRIDE_FMAX1(clkname, l1, f1) \
+	clkname##_clk_src.c.fmax[VDD_DIG_##l1] = (f1)
+
+# define OVERRIDE_FMAX2(clkname, l1, f1, l2, f2) \
+	clkname##_clk_src.c.fmax[VDD_DIG_##l1] = (f1);  \
+	clkname##_clk_src.c.fmax[VDD_DIG_##l2] = (f2)
+
+#define VDD_DIG_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
+	.vdd_class = &vdd_dig, \
+	.fmax = (unsigned long[VDD_DIG_NUM]) {  \
+		[VDD_DIG_##l1] = (f1),          \
+		[VDD_DIG_##l2] = (f2),          \
+		[VDD_DIG_##l3] = (f3),          \
+	},                                      \
+	.num_fmax = VDD_DIG_NUM
+
+# define OVERRIDE_FMAX3(clkname, l1, f1, l2, f2, l3, f3) \
+	clkname##_clk_src.c.fmax[VDD_DIG_##l1] = (f1);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l2] = (f2);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l3] = (f3)
+
+
+# define OVERRIDE_FMAX4(clkname, l1, f1, l2, f2, l3, f3, l4, f4) \
+	clkname##_clk_src.c.fmax[VDD_DIG_##l1] = (f1);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l2] = (f2);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l3] = (f3);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l4] = (f4)
+
+#define VDD_DIG_FMAX_MAP5(l1, f1, l2, f2, l3, f3, l4, f4, l5, f5) \
+	.vdd_class = &vdd_dig, \
+	.fmax = (unsigned long[VDD_DIG_NUM]) {  \
+		[VDD_DIG_##l1] = (f1),\
+		[VDD_DIG_##l2] = (f2),\
+		[VDD_DIG_##l3] = (f3),\
+		[VDD_DIG_##l4] = (f4),\
+		[VDD_DIG_##l5] = (f5),\
+	},\
+	.num_fmax = VDD_DIG_NUM
+
+#define OVERRIDE_FMAX5(clkname, l1, f1, l2, f2, l3, f3, l4, f4, l5, f5) \
+	clkname##_clk_src.c.fmax[VDD_DIG_##l1] = (f1);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l2] = (f2);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l3] = (f3);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l4] = (f4);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l5] = (f5)
+
+#define OVERRIDE_FMAX6(clkname, \
+		l1, f1, l2, f2, l3, f3, l4, f4, l5, f5, l6, f6) \
+	clkname##_clk_src.c.fmax[VDD_DIG_##l1] = (f1);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l2] = (f2);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l3] = (f3);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l4] = (f4);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l5] = (f5);\
+	clkname##_clk_src.c.fmax[VDD_DIG_##l6] = (f6)
+
+#define OVERRIDE_FTABLE(clkname, ftable, name) \
+	clkname##_clk_src.freq_tbl = ftable##_##name
+
+enum vdd_dig_levels {
+	VDD_DIG_NONE,
+	VDD_DIG_LOWER,
+	VDD_DIG_LOW,
+	VDD_DIG_NOMINAL,
+	VDD_DIG_NOM_PLUS,
+	VDD_DIG_HIGH,
+	VDD_DIG_SUPER_TUR,
+	VDD_DIG_NUM
+};
+
+enum vdd_dig_levels_8917 {
+	VDD_DIG_NONE_8917,
+	VDD_DIG_LOWER_8917,
+	VDD_DIG_LOW_8917,
+	VDD_DIG_NOMINAL_8917,
+	VDD_DIG_NOM_PLUS_8917,
+	VDD_DIG_HIGH_8917,
+	VDD_DIG_NUM_8917
+};
+
+enum vdd_hf_pll_levels_8917 {
+	VDD_HF_PLL_OFF_8917,
+	VDD_HF_PLL_SVS_8917,
+	VDD_HF_PLL_NOM_8917,
+	VDD_HF_PLL_TUR_8917,
+	VDD_HF_PLL_NUM_8917,
+};
+
+static int vdd_corner[] = {
+	RPM_REGULATOR_LEVEL_NONE,		/* VDD_DIG_NONE */
+	RPM_REGULATOR_LEVEL_SVS,		/* VDD_DIG_SVS */
+	RPM_REGULATOR_LEVEL_SVS_PLUS,		/* VDD_DIG_SVS_PLUS */
+	RPM_REGULATOR_LEVEL_NOM,		/* VDD_DIG_NOM */
+	RPM_REGULATOR_LEVEL_NOM_PLUS,		/* VDD_DIG_NOM_PLUS */
+	RPM_REGULATOR_LEVEL_TURBO,		/* VDD_DIG_TURBO */
+	RPM_REGULATOR_LEVEL_BINNING,		/* VDD_DIG_SUPER_TUR */
+};
+#endif
diff --git a/include/dt-bindings/clock/msm-cpu-clocks-8939.h b/include/dt-bindings/clock/msm-cpu-clocks-8939.h
new file mode 100644
index 0000000..cb16dca
--- /dev/null
+++ b/include/dt-bindings/clock/msm-cpu-clocks-8939.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2014-2015, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_CLOCK_CPU_8939_H
+#define __MSM_CLOCK_CPU_8939_H
+
+#define clk_a53ssmux_lc				0x71a9377b
+#define clk_a53_lc_clk				0xc69f0878
+#define clk_a53ssmux_bc				0xb5983c42
+#define clk_a53_bc_clk				0xcf28e63a
+#define clk_a53ssmux_cci			0x15560bd5
+#define clk_cci_clk                             0x96854074
+#endif
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 21dd697..43d801e 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -275,6 +275,9 @@
 	POWER_SUPPLY_PROP_PARALLEL_FCC_MAX,
 	POWER_SUPPLY_PROP_MIN_ICL,
 	POWER_SUPPLY_PROP_MOISTURE_DETECTED,
+	POWER_SUPPLY_PROP_BATT_PROFILE_VERSION,
+	POWER_SUPPLY_PROP_BATT_FULL_CURRENT,
+	POWER_SUPPLY_PROP_RECHARGE_SOC,
 	/* Local extensions of type int64_t */
 	POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT,
 	/* Properties of type `const char *' */
diff --git a/include/soc/qcom/bam_dmux.h b/include/soc/qcom/bam_dmux.h
new file mode 100644
index 0000000..142b8e1
--- /dev/null
+++ b/include/soc/qcom/bam_dmux.h
@@ -0,0 +1,138 @@
+/* Copyright (c) 2011-2012, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/skbuff.h>
+
+#ifndef _BAM_DMUX_H
+#define _BAM_DMUX_H
+
+#define BAM_DMUX_CH_NAME_MAX_LEN	20
+
+enum {
+	BAM_DMUX_DATA_RMNET_0,
+	BAM_DMUX_DATA_RMNET_1,
+	BAM_DMUX_DATA_RMNET_2,
+	BAM_DMUX_DATA_RMNET_3,
+	BAM_DMUX_DATA_RMNET_4,
+	BAM_DMUX_DATA_RMNET_5,
+	BAM_DMUX_DATA_RMNET_6,
+	BAM_DMUX_DATA_RMNET_7,
+	BAM_DMUX_USB_RMNET_0,
+	BAM_DMUX_RESERVED_0, /* 9..11 are reserved*/
+	BAM_DMUX_RESERVED_1,
+	BAM_DMUX_RESERVED_2,
+	BAM_DMUX_DATA_REV_RMNET_0,
+	BAM_DMUX_DATA_REV_RMNET_1,
+	BAM_DMUX_DATA_REV_RMNET_2,
+	BAM_DMUX_DATA_REV_RMNET_3,
+	BAM_DMUX_DATA_REV_RMNET_4,
+	BAM_DMUX_DATA_REV_RMNET_5,
+	BAM_DMUX_DATA_REV_RMNET_6,
+	BAM_DMUX_DATA_REV_RMNET_7,
+	BAM_DMUX_DATA_REV_RMNET_8,
+	BAM_DMUX_USB_DPL,
+	BAM_DMUX_NUM_CHANNELS
+};
+
+/* event type enum */
+enum {
+	BAM_DMUX_RECEIVE, /* data is struct sk_buff */
+	BAM_DMUX_WRITE_DONE, /* data is struct sk_buff */
+	BAM_DMUX_UL_CONNECTED, /* data is null */
+	BAM_DMUX_UL_DISCONNECTED, /*data is null */
+	BAM_DMUX_TRANSMIT_SIZE, /* data is maximum negotiated transmit MTU */
+};
+
+/*
+ * Open a bam_dmux logical channel
+ *     id - the logical channel to open
+ *     priv - private data pointer to be passed to the notify callback
+ *     notify - event callback function
+ *          priv - private data pointer passed to msm_bam_dmux_open()
+ *          event_type - type of event
+ *          data - data relevant to event.  May not be valid. See event_type
+ *                    enum for valid cases.
+ */
+#ifdef CONFIG_MSM_BAM_DMUX
+int msm_bam_dmux_open(uint32_t id, void *priv,
+		       void (*notify)(void *priv, int event_type,
+						unsigned long data));
+
+int msm_bam_dmux_close(uint32_t id);
+
+int msm_bam_dmux_write(uint32_t id, struct sk_buff *skb);
+
+int msm_bam_dmux_kickoff_ul_wakeup(void);
+
+int msm_bam_dmux_ul_power_vote(void);
+
+int msm_bam_dmux_ul_power_unvote(void);
+
+int msm_bam_dmux_is_ch_full(uint32_t id);
+
+int msm_bam_dmux_is_ch_low(uint32_t id);
+
+int msm_bam_dmux_reg_notify(void *priv,
+		       void (*notify)(void *priv, int event_type,
+						unsigned long data));
+#else
+static inline int msm_bam_dmux_open(uint32_t id, void *priv,
+		       void (*notify)(void *priv, int event_type,
+						unsigned long data))
+{
+	return -ENODEV;
+}
+
+static inline int msm_bam_dmux_close(uint32_t id)
+{
+	return -ENODEV;
+}
+
+static inline int msm_bam_dmux_write(uint32_t id, struct sk_buff *skb)
+{
+	return -ENODEV;
+}
+
+static inline int msm_bam_dmux_kickoff_ul_wakeup(void)
+{
+	return -ENODEV;
+}
+
+static inline int msm_bam_dmux_ul_power_vote(void)
+{
+	return -ENODEV;
+}
+
+static inline int msm_bam_dmux_ul_power_unvote(void)
+{
+	return -ENODEV;
+}
+
+static inline int msm_bam_dmux_is_ch_full(uint32_t id)
+{
+	return -ENODEV;
+}
+
+static inline int msm_bam_dmux_is_ch_low(uint32_t id)
+{
+	return -ENODEV;
+}
+
+static inline int msm_bam_dmux_reg_notify(void *priv,
+		       void (*notify)(void *priv, int event_type,
+						unsigned long data))
+{
+	return -ENODEV;
+}
+#endif
+#endif /* _BAM_DMUX_H */
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index ea727f2..f8e92fbc 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -367,6 +367,8 @@
 header-y += qbt1000.h
 header-y += qcedev.h
 header-y += qcota.h
+header-y += qg.h
+header-y += qg-profile.h
 header-y += qnx4_fs.h
 header-y += qnxtypes.h
 header-y += qrng.h
diff --git a/include/uapi/linux/qg-profile.h b/include/uapi/linux/qg-profile.h
new file mode 100644
index 0000000..bffddbb
--- /dev/null
+++ b/include/uapi/linux/qg-profile.h
@@ -0,0 +1,66 @@
+#ifndef __QG_PROFILE_H__
+#define __QG_PROFILE_H__
+
+#include <linux/ioctl.h>
+
+/**
+ * enum profile_table - Table index for battery profile data
+ */
+enum profile_table {
+	TABLE_SOC_OCV1,
+	TABLE_SOC_OCV2,
+	TABLE_FCC1,
+	TABLE_FCC2,
+	TABLE_Z1,
+	TABLE_Z2,
+	TABLE_Z3,
+	TABLE_Z4,
+	TABLE_Z5,
+	TABLE_Z6,
+	TABLE_Y1,
+	TABLE_Y2,
+	TABLE_Y3,
+	TABLE_Y4,
+	TABLE_Y5,
+	TABLE_Y6,
+	TABLE_MAX,
+};
+
+/**
+ * struct battery_params - Battery profile data to be exchanged
+ * @soc:	SOC (state of charge) of the battery
+ * @ocv_uv:	OCV (open circuit voltage) of the battery
+ * @batt_temp:	Battery temperature in deci-degree
+ * @var:	'X' axis param for interpolation
+ * @table_index:Table index to be used for interpolation
+ */
+struct battery_params {
+	int soc;
+	int ocv_uv;
+	int fcc_mah;
+	int slope;
+	int var;
+	int batt_temp;
+	int table_index;
+};
+
+/* Profile MIN / MAX values */
+#define QG_MIN_SOC				0
+#define QG_MAX_SOC				10000
+#define QG_MIN_OCV_UV				3000000
+#define QG_MAX_OCV_UV				5000000
+#define QG_MIN_VAR				0
+#define QG_MAX_VAR				65535
+#define QG_MIN_FCC_MAH				100
+#define QG_MAX_FCC_MAH				16000
+#define QG_MIN_SLOPE				1
+#define QG_MAX_SLOPE				50000
+
+/*  IOCTLs to query battery profile data */
+#define BPIOCXSOC	_IOWR('B', 0x01, struct battery_params) /* SOC */
+#define BPIOCXOCV	_IOWR('B', 0x02, struct battery_params) /* OCV */
+#define BPIOCXFCC	_IOWR('B', 0x03, struct battery_params) /* FCC */
+#define BPIOCXSLOPE	_IOWR('B', 0x04, struct battery_params) /* Slope */
+#define BPIOCXVAR	_IOWR('B', 0x05, struct battery_params) /* All-other */
+
+#endif /* __QG_PROFILE_H__ */
diff --git a/include/uapi/linux/qg.h b/include/uapi/linux/qg.h
new file mode 100644
index 0000000..c0b2b6e
--- /dev/null
+++ b/include/uapi/linux/qg.h
@@ -0,0 +1,50 @@
+#ifndef __QG_H__
+#define __QG_H__
+
+#define MAX_FIFO_LENGTH		16
+
+enum qg {
+	QG_SOC,
+	QG_OCV_UV,
+	QG_RBAT_MOHM,
+	QG_PON_OCV_UV,
+	QG_GOOD_OCV_UV,
+	QG_ESR,
+	QG_CHARGE_COUNTER,
+	QG_FIFO_TIME_DELTA,
+	QG_RESERVED_1,
+	QG_RESERVED_2,
+	QG_RESERVED_3,
+	QG_RESERVED_4,
+	QG_RESERVED_5,
+	QG_RESERVED_6,
+	QG_RESERVED_7,
+	QG_RESERVED_8,
+	QG_RESERVED_9,
+	QG_RESERVED_10,
+	QG_MAX,
+};
+
+struct fifo_data {
+	unsigned int			v;
+	unsigned int			i;
+	unsigned int			count;
+	unsigned int			interval;
+};
+
+struct qg_param {
+	unsigned int			data;
+	bool				valid;
+};
+
+struct qg_kernel_data {
+	unsigned int			fifo_length;
+	struct fifo_data		fifo[MAX_FIFO_LENGTH];
+	struct qg_param			param[QG_MAX];
+};
+
+struct qg_user_data {
+	struct qg_param			param[QG_MAX];
+};
+
+#endif
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 4a60459..d3ea11f 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -3288,6 +3288,46 @@
 	return NULL;
 }
 
+#ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER
+static inline bool
+should_compact_lmk_retry(struct alloc_context *ac, int order, int alloc_flags)
+{
+	struct zone *zone;
+	struct zoneref *z;
+
+	/* Let costly order requests check for compaction progress */
+	if (order > PAGE_ALLOC_COSTLY_ORDER)
+		return false;
+
+	/*
+	 * For (0 < order < PAGE_ALLOC_COSTLY_ORDER) allow the shrinkers
+	 * to run and free up memory. Do not let these allocations fail
+	 * if shrinkers can free up memory. This is similar to
+	 * should_compact_retry implementation for !CONFIG_COMPACTION.
+	 */
+	for_each_zone_zonelist_nodemask(zone, z, ac->zonelist,
+				ac->high_zoneidx, ac->nodemask) {
+		unsigned long available;
+
+		available = zone_reclaimable_pages(zone);
+		available +=
+			zone_page_state_snapshot(zone, NR_FREE_PAGES);
+
+		if (__zone_watermark_ok(zone, 0, min_wmark_pages(zone),
+			ac_classzone_idx(ac), alloc_flags, available))
+			return true;
+	}
+
+	return false;
+}
+#else
+static inline bool
+should_compact_lmk_retry(struct alloc_context *ac, int order, int alloc_flags)
+{
+	return false;
+}
+#endif
+
 static inline bool
 should_compact_retry(struct alloc_context *ac, int order, int alloc_flags,
 		     enum compact_result compact_result,
@@ -3300,6 +3340,9 @@
 	if (!order)
 		return false;
 
+	if (should_compact_lmk_retry(ac, order, alloc_flags))
+		return true;
+
 	if (compaction_made_progress(compact_result))
 		(*compaction_retries)++;
 
@@ -3537,7 +3580,8 @@
 	 * their order will become available due to high fragmentation so
 	 * always increment the no progress counter for them
 	 */
-	if (did_some_progress && order <= PAGE_ALLOC_COSTLY_ORDER)
+	if ((did_some_progress && order <= PAGE_ALLOC_COSTLY_ORDER) ||
+			IS_ENABLED(CONFIG_ANDROID_LOW_MEMORY_KILLER))
 		*no_progress_loops = 0;
 	else
 		(*no_progress_loops)++;
@@ -3815,7 +3859,8 @@
 	 * implementation of the compaction depends on the sufficient amount
 	 * of free memory (see __compaction_suitable)
 	 */
-	if (did_some_progress > 0 &&
+	if ((did_some_progress > 0 ||
+			IS_ENABLED(CONFIG_ANDROID_LOW_MEMORY_KILLER)) &&
 			should_compact_retry(ac, order, alloc_flags,
 				compact_result, &compact_priority,
 				&compaction_retries))
diff --git a/mm/vmscan.c b/mm/vmscan.c
index bb18b47..2740973 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -212,7 +212,8 @@
 
 	nr = zone_page_state_snapshot(zone, NR_ZONE_INACTIVE_FILE) +
 		zone_page_state_snapshot(zone, NR_ZONE_ACTIVE_FILE);
-	if (get_nr_swap_pages() > 0)
+	if (get_nr_swap_pages() > 0
+			|| IS_ENABLED(CONFIG_ANDROID_LOW_MEMORY_KILLER))
 		nr += zone_page_state_snapshot(zone, NR_ZONE_INACTIVE_ANON) +
 			zone_page_state_snapshot(zone, NR_ZONE_ACTIVE_ANON);
 
diff --git a/sound/usb/usb_audio_qmi_svc.c b/sound/usb/usb_audio_qmi_svc.c
index e2cebf15..1c5b36d 100644
--- a/sound/usb/usb_audio_qmi_svc.c
+++ b/sound/usb/usb_audio_qmi_svc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -173,6 +173,9 @@
 	USB_QMI_PCM_FORMAT_U32_BE,
 };
 
+static void uaudio_iommu_unmap(enum mem_type mtype, unsigned long va,
+	size_t iova_size, size_t mapped_iova_size);
+
 static enum usb_audio_device_speed_enum_v01
 get_speed_info(enum usb_device_speed udev_speed)
 {
@@ -279,11 +282,14 @@
 }
 
 static unsigned long uaudio_iommu_map(enum mem_type mtype, phys_addr_t pa,
-		size_t size)
+		size_t size, struct sg_table *sgt)
 {
-	unsigned long va = 0;
+	unsigned long va_sg, va = 0;
 	bool map = true;
-	int ret;
+	int i, ret;
+	size_t sg_len, total_len = 0;
+	struct scatterlist *sg;
+	phys_addr_t pa_sg;
 
 	switch (mtype) {
 	case MEM_EVENT_RING:
@@ -306,18 +312,48 @@
 		pr_err("%s: unknown mem type %d\n", __func__, mtype);
 	}
 
-	if (!va)
-		map = false;
-
-	if (!map)
+	if (!va || !map)
 		goto done;
 
-	pr_debug("%s: map pa %pa to iova %lu for memtype %d\n", __func__, &pa,
-		va, mtype);
+	if (!sgt)
+		goto skip_sgt_map;
+
+	va_sg = va;
+	for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+		sg_len = PAGE_ALIGN(sg->offset + sg->length);
+		pa_sg = page_to_phys(sg_page(sg));
+		ret = iommu_map(uaudio_qdev->domain, va_sg, pa_sg, sg_len,
+			IOMMU_READ | IOMMU_WRITE | IOMMU_MMIO);
+		if (ret) {
+			pr_err("%s:mapping failed ret%d\n", __func__, ret);
+			pr_err("memtype:%d, pa:%pK iova:%lu sg_len:%zu\n",
+				mtype, &pa_sg, va_sg, sg_len);
+			uaudio_iommu_unmap(MEM_XFER_BUF, va, size, total_len);
+			va = 0;
+			goto done;
+		}
+		pr_debug("%s:memtype %d:map pa:%pK to iova:%lu len:%zu\n",
+			__func__, mtype, &pa_sg, va_sg, sg_len);
+		va_sg += sg_len;
+		total_len += sg_len;
+	}
+
+	if (size != total_len) {
+		pr_err("%s: iova size %zu != mapped iova size %zu\n", __func__,
+			size, total_len);
+		uaudio_iommu_unmap(MEM_XFER_BUF, va, size, total_len);
+		va = 0;
+	}
+	return va;
+
+skip_sgt_map:
+	pr_debug("%s:memtype:%d map pa:%pK to iova %lu size:%zu\n", __func__,
+		mtype, &pa, va, size);
+
 	ret = iommu_map(uaudio_qdev->domain, va, pa, size,
 		IOMMU_READ | IOMMU_WRITE | IOMMU_MMIO);
 	if (ret)
-		pr_err("%s:failed to map pa:%pa iova:%lu memtype:%d ret:%d\n",
+		pr_err("%s:failed to map pa:%pK iova:%lu memtype:%d ret:%d\n",
 			__func__, &pa, va, mtype, ret);
 done:
 	return va;
@@ -361,12 +397,12 @@
 }
 
 static void uaudio_iommu_unmap(enum mem_type mtype, unsigned long va,
-	size_t size)
+	size_t iova_size, size_t mapped_iova_size)
 {
 	size_t umap_size;
 	bool unmap = true;
 
-	if (!va || !size)
+	if (!va || !iova_size)
 		return;
 
 	switch (mtype) {
@@ -378,11 +414,11 @@
 		break;
 
 	case MEM_XFER_RING:
-		uaudio_put_iova(va, size, &uaudio_qdev->xfer_ring_list,
+		uaudio_put_iova(va, iova_size, &uaudio_qdev->xfer_ring_list,
 		&uaudio_qdev->xfer_ring_iova_size);
 		break;
 	case MEM_XFER_BUF:
-		uaudio_put_iova(va, size, &uaudio_qdev->xfer_buf_list,
+		uaudio_put_iova(va, iova_size, &uaudio_qdev->xfer_buf_list,
 		&uaudio_qdev->xfer_buf_iova_size);
 		break;
 	default:
@@ -390,15 +426,16 @@
 		unmap = false;
 	}
 
-	if (!unmap)
+	if (!unmap || !mapped_iova_size)
 		return;
 
-	pr_debug("%s: unmap iova %lu for memtype %d\n", __func__, va, mtype);
+	pr_debug("%s:memtype %d: unmap iova %lu size %zu\n", __func__, mtype,
+		va, mapped_iova_size);
 
-	umap_size = iommu_unmap(uaudio_qdev->domain, va, size);
-	if (umap_size != size)
-		pr_err("%s: unmapped size %zu for iova %lu\n", __func__,
-		umap_size, va);
+	umap_size = iommu_unmap(uaudio_qdev->domain, va, mapped_iova_size);
+	if (umap_size != mapped_iova_size)
+		pr_err("%s:unmapped size %zu for iova %lu of mapped size %zu\n",
+		__func__, umap_size, va, mapped_iova_size);
 }
 
 static int prepare_qmi_response(struct snd_usb_substream *subs,
@@ -418,12 +455,11 @@
 	void *hdr_ptr;
 	u8 *xfer_buf;
 	unsigned int data_ep_pipe = 0, sync_ep_pipe = 0;
-	u32 len, mult, remainder, xfer_buf_len, sg_len, i, total_len = 0;
-	unsigned long va, va_sg, tr_data_va = 0, tr_sync_va = 0;
+	u32 len, mult, remainder, xfer_buf_len;
+	unsigned long va, tr_data_va = 0, tr_sync_va = 0;
 	phys_addr_t xhci_pa, xfer_buf_pa, tr_data_pa = 0, tr_sync_pa = 0;
 	dma_addr_t dma;
 	struct sg_table sgt;
-	struct scatterlist *sg;
 
 	iface = usb_ifnum_to_if(subs->dev, subs->interface);
 	if (!iface) {
@@ -593,7 +629,7 @@
 		goto err;
 	}
 
-	va = uaudio_iommu_map(MEM_EVENT_RING, xhci_pa, PAGE_SIZE);
+	va = uaudio_iommu_map(MEM_EVENT_RING, xhci_pa, PAGE_SIZE, NULL);
 	if (!va)
 		goto err;
 
@@ -610,7 +646,7 @@
 	resp->speed_info_valid = 1;
 
 	/* data transfer ring */
-	va = uaudio_iommu_map(MEM_XFER_RING, tr_data_pa, PAGE_SIZE);
+	va = uaudio_iommu_map(MEM_XFER_RING, tr_data_pa, PAGE_SIZE, NULL);
 	if (!va)
 		goto unmap_er;
 
@@ -624,7 +660,7 @@
 		goto skip_sync;
 
 	xhci_pa = resp->xhci_mem_info.tr_sync.pa;
-	va = uaudio_iommu_map(MEM_XFER_RING, tr_sync_pa, PAGE_SIZE);
+	va = uaudio_iommu_map(MEM_XFER_RING, tr_sync_pa, PAGE_SIZE, NULL);
 	if (!va)
 		goto unmap_data;
 
@@ -655,20 +691,9 @@
 
 	dma_get_sgtable(subs->dev->bus->sysdev, &sgt, xfer_buf, xfer_buf_pa,
 			len);
-
-	va = 0;
-	for_each_sg(sgt.sgl, sg, sgt.nents, i) {
-		sg_len = PAGE_ALIGN(sg->offset + sg->length);
-		va_sg = uaudio_iommu_map(MEM_XFER_BUF,
-			page_to_phys(sg_page(sg)), sg_len);
-		if (!va_sg)
-			goto unmap_xfer_buf;
-
-		if (!va)
-			va = va_sg;
-
-		total_len += sg_len;
-	}
+	va = uaudio_iommu_map(MEM_XFER_BUF, xfer_buf_pa, len, &sgt);
+	if (!va)
+		goto unmap_sync;
 
 	resp->xhci_mem_info.xfer_buff.pa = xfer_buf_pa;
 	resp->xhci_mem_info.xfer_buff.size = len;
@@ -690,7 +715,7 @@
 			uadev[card_num].num_intf, GFP_KERNEL);
 		if (!uadev[card_num].info) {
 			ret = -ENOMEM;
-			goto unmap_xfer_buf;
+			goto unmap_sync;
 		}
 		uadev[card_num].udev = subs->dev;
 		atomic_set(&uadev[card_num].in_use, 1);
@@ -722,16 +747,13 @@
 
 	return 0;
 
-unmap_xfer_buf:
-	if (va)
-		uaudio_iommu_unmap(MEM_XFER_BUF, va, total_len);
 unmap_sync:
 	usb_free_coherent(subs->dev, len, xfer_buf, xfer_buf_pa);
-	uaudio_iommu_unmap(MEM_XFER_RING, tr_sync_va, PAGE_SIZE);
+	uaudio_iommu_unmap(MEM_XFER_RING, tr_sync_va, PAGE_SIZE, PAGE_SIZE);
 unmap_data:
-	uaudio_iommu_unmap(MEM_XFER_RING, tr_data_va, PAGE_SIZE);
+	uaudio_iommu_unmap(MEM_XFER_RING, tr_data_va, PAGE_SIZE, PAGE_SIZE);
 unmap_er:
-	uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE);
+	uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE, PAGE_SIZE);
 err:
 	return ret;
 }
@@ -760,17 +782,17 @@
 	}
 
 	uaudio_iommu_unmap(MEM_XFER_RING, info->data_xfer_ring_va,
-		info->data_xfer_ring_size);
+		info->data_xfer_ring_size, info->data_xfer_ring_size);
 	info->data_xfer_ring_va = 0;
 	info->data_xfer_ring_size = 0;
 
 	uaudio_iommu_unmap(MEM_XFER_RING, info->sync_xfer_ring_va,
-		info->sync_xfer_ring_size);
+		info->sync_xfer_ring_size, info->sync_xfer_ring_size);
 	info->sync_xfer_ring_va = 0;
 	info->sync_xfer_ring_size = 0;
 
 	uaudio_iommu_unmap(MEM_XFER_BUF, info->xfer_buf_va,
-		info->xfer_buf_size);
+		info->xfer_buf_size, info->xfer_buf_size);
 	info->xfer_buf_va = 0;
 
 	usb_free_coherent(udev, info->xfer_buf_size,
@@ -805,7 +827,8 @@
 
 	/* all audio devices are disconnected */
 	if (!uaudio_qdev->card_slot) {
-		uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE);
+		uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE,
+			PAGE_SIZE);
 		usb_sec_event_ring_cleanup(dev->udev, uaudio_qdev->intr_num);
 		pr_debug("%s: all audio devices disconnected\n", __func__);
 	}
@@ -881,7 +904,8 @@
 	/* all audio devices are disconnected */
 	if (!uaudio_qdev->card_slot) {
 		usb_sec_event_ring_cleanup(dev->udev, uaudio_qdev->intr_num);
-		uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE);
+		uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE,
+			PAGE_SIZE);
 		pr_debug("%s: all audio devices disconnected\n", __func__);
 	}