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 = <<9611_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", ®)) {
+ 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 = ®,
+ },
+ {
+ .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, ®_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, ®_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, ®_val, 1);
+
+ if ((reg_val & 0x60) == 0x60) {
+ byte_clk = (reg_val & 0x0f) * 65536;
+ lt9611_read(pdata, 0xce, ®_val, 1);
+ byte_clk = byte_clk + reg_val * 256;
+ lt9611_read(pdata, 0xcf, ®_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, ®_val, 1);
+
+ if ((reg_val & 0x60) == 0x60) {
+ byte_clk = (reg_val & 0x0f) * 65536;
+ lt9611_read(pdata, 0xce, ®_val, 1);
+ byte_clk = byte_clk + reg_val * 256;
+ lt9611_read(pdata, 0xcf, ®_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 <9611_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, ®_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, <9611_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, <9611_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 = <9611_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(<9611_driver);
+}
+
+static void __exit lt9611_exit(void)
+{
+ i2c_del_driver(<9611_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, ¶m);
+ 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, ®, 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,
+ ®, 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,
+ ®, 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,
+ ®, 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, ®, 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,
+ ®, 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,
+ ®, 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,
+ ®, 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,
+ ®, 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,
+ ®, 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,
+ ®, 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, ð_dev->flags)) {
+ ether_setup(dev);
+ dev->mtu = prev_mtu;
+ dev->netdev_ops = ð_netdev_ops;
+ clear_bit(RMNET_MODE_LLP_IP, ð_dev->flags);
+ set_bit(RMNET_MODE_LLP_ETH, ð_dev->flags);
+ DBG(eth_dev, "[%s] ioctl(): set Ethernet proto mode\n",
+ dev->name);
+ }
+ if (test_bit(RMNET_MODE_LLP_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, ð_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 = ð_netdev_ops_ip;
+ clear_bit(RMNET_MODE_LLP_ETH, ð_dev->flags);
+ set_bit(RMNET_MODE_LLP_IP, ð_dev->flags);
+ DBG(eth_dev, "[%s] ioctl(): set IP protocol mode\n",
+ dev->name);
+ }
+ if (test_bit(RMNET_MODE_LLP_IP, ð_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(ð_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 = ð_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__);
}