summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt21
-rw-r--r--Documentation/devicetree/bindings/power/reset/reboot-mode.txt25
-rw-r--r--Documentation/devicetree/bindings/power/reset/syscon-reboot-mode.txt35
-rw-r--r--arch/arm/boot/dts/qcom/Makefile1
-rw-r--r--arch/arm/boot/dts/qcom/msm-pm2falcon.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msm-pmcobalt-rpm-regulator.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi6
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dts29
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dtsi27
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-qrd.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi6
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-v2-qrd-vr1.dts23
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-coresight.dtsi433
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon.dtsi2
-rw-r--r--arch/arm/mach-qcom/board-falcon.c17
-rw-r--r--arch/arm64/include/asm/Kbuild1
-rw-r--r--arch/arm64/include/asm/checksum.h51
-rw-r--r--drivers/android/binder.c2
-rw-r--r--drivers/bluetooth/bluetooth-power.c19
-rw-r--r--drivers/char/adsprpc.c2
-rw-r--r--drivers/clk/msm/clock-osm.c48
-rw-r--r--drivers/crypto/msm/qce.c6
-rw-r--r--drivers/gpu/msm/adreno.c21
-rw-r--r--drivers/gpu/msm/adreno.h28
-rw-r--r--drivers/gpu/msm/adreno_a3xx.c5
-rw-r--r--drivers/gpu/msm/adreno_a4xx.c5
-rw-r--r--drivers/gpu/msm/adreno_a5xx.c5
-rw-r--r--drivers/leds/leds-qpnp-wled.c255
-rw-r--r--drivers/platform/msm/ipa/ipa_clients/ipa_usb.c499
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_client.c45
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_i.h4
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_utils.c2
-rw-r--r--drivers/power/reset/Kconfig14
-rw-r--r--drivers/power/reset/Makefile2
-rw-r--r--drivers/power/reset/reboot-mode.c140
-rw-r--r--drivers/power/reset/reboot-mode.h14
-rw-r--r--drivers/power/reset/syscon-reboot-mode.c99
-rw-r--r--drivers/soc/qcom/icnss.c47
-rw-r--r--drivers/usb/dwc3/dwc3-msm.c5
-rw-r--r--drivers/usb/gadget/function/f_gsi.c3
-rw-r--r--drivers/usb/host/xhci-plat.c4
-rw-r--r--drivers/usb/pd/policy_engine.c107
-rw-r--r--include/linux/bluetooth-power.h1
-rw-r--r--include/linux/clk/msm-clk.h11
-rw-r--r--include/linux/ipa_usb.h7
-rw-r--r--include/net/cfg80211.h48
-rw-r--r--kernel/sched/hmp.c4
-rw-r--r--net/mac80211/util.c44
-rw-r--r--net/wireless/util.c54
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x.c1
50 files changed, 1809 insertions, 425 deletions
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt
index 1ca2b6dd6d5c..ebbcfe5b2fd0 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt
@@ -33,7 +33,15 @@ Optional properties for WLED:
- 31100, 29600, 19600, 18100 for pmicobalt/pm2falcon.
Should only be used if qcom,disp-type-amoled is not
specified.
-- qcom,ilim-ma : maximum current limiter in ma. default is 980.
+- qcom,ilim-ma : Current limit threshold in mA.
+ For pmi8994/8952/8996, default value for LCD is 980mA
+ and AMOLED is 385mA.
+ Supported values are:
+ - 105, 385, 660, 980, 1150, 1420, 1700, 1980.
+ For pmicobalt/pm2falcon, default value for LCD is
+ 970mA and AMOLED is 620mA.
+ Supported values are:
+ - 105, 280, 450, 620, 970, 1150, 1300, 1500.
- qcom,boost-duty-ns : maximum boost duty cycle in ns. default is 104.
- qcom,mod-freq-khz : modulation frequency in khz. default is 9600.
- qcom,dim-mode : dimming mode. supporting dimming modes are "analog",
@@ -61,10 +69,13 @@ Optional properties if 'qcom,disp-type-amoled' is mentioned in DT:
- qcom,loop-ea-gm : control the gm for gm stage in control loop. default is 3.
- qcom,loop-comp-res-kohm : control to select the compensation resistor in kohm. default is 320.
- qcom,vref-psm-mv : reference psm voltage in mv. default for amoled is 450.
-- qcom,avdd-target-voltage-mv: The target voltage desired for the AVDD module in mV.
- The supported values are:
- 7900, 7600, 7300, 6400, 6100, 5800.
- If not specified, default value used is 7600.
+- qcom,avdd-mode-spmi: Boolean property to enable AMOLED_VOUT programming via SPMI. If not specified,
+ AMOLED_VOUT is programmed via S-wire. This can be specified only for newer
+ PMICs like pmicobalt/pm2falcon.
+- qcom,avdd-target-voltage-mv: The voltage required for AMOLED_VOUT. Accepted values are in the range
+ of 5650 to 7900 in steps of 150. Default value is 7600. Unit is in mV.
+ For old revisions, accepted values are: 7900, 7600, 7300, 6400, 6100,
+ 5800.
Example:
qcom,leds@d800 {
diff --git a/Documentation/devicetree/bindings/power/reset/reboot-mode.txt b/Documentation/devicetree/bindings/power/reset/reboot-mode.txt
new file mode 100644
index 000000000000..de34f27d509e
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/reset/reboot-mode.txt
@@ -0,0 +1,25 @@
+Generic reboot mode core map driver
+
+This driver get reboot mode arguments and call the write
+interface to store the magic value in special register
+or ram. Then the bootloader can read it and take different
+action according to the argument stored.
+
+All mode properties are vendor specific, it is a indication to tell
+the bootloader what to do when the system reboots, and should be named
+as mode-xxx = <magic> (xxx is mode name, magic should be a none-zero value).
+
+For example modes common on Android platform:
+- mode-normal: Normal reboot mode, system reboot with command "reboot".
+- mode-recovery: Android Recovery mode, it is a mode to format the device or update a new image.
+- mode-bootloader: Android fastboot mode, it's a mode to re-flash partitions on the Android based device.
+- mode-loader: A bootloader mode, it's a mode used to download image on Rockchip platform,
+ usually used in development.
+
+Example:
+ reboot-mode {
+ mode-normal = <BOOT_NORMAL>;
+ mode-recovery = <BOOT_RECOVERY>;
+ mode-bootloader = <BOOT_FASTBOOT>;
+ mode-loader = <BOOT_BL_DOWNLOAD>;
+ }
diff --git a/Documentation/devicetree/bindings/power/reset/syscon-reboot-mode.txt b/Documentation/devicetree/bindings/power/reset/syscon-reboot-mode.txt
new file mode 100644
index 000000000000..f7ce1d8af04a
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/reset/syscon-reboot-mode.txt
@@ -0,0 +1,35 @@
+SYSCON reboot mode driver
+
+This driver gets reboot mode magic value form reboot-mode driver
+and stores it in a SYSCON mapped register. Then the bootloader
+can read it and take different action according to the magic
+value stored.
+
+This DT node should be represented as a sub-node of a "syscon", "simple-mfd"
+node.
+
+Required properties:
+- compatible: should be "syscon-reboot-mode"
+- offset: offset in the register map for the storage register (in bytes)
+
+Optional property:
+- mask: bits mask of the bits in the register to store the reboot mode magic value,
+ default set to 0xffffffff if missing.
+
+The rest of the properties should follow the generic reboot-mode description
+found in reboot-mode.txt
+
+Example:
+ pmu: pmu@20004000 {
+ compatible = "rockchip,rk3066-pmu", "syscon", "simple-mfd";
+ reg = <0x20004000 0x100>;
+
+ reboot-mode {
+ compatible = "syscon-reboot-mode";
+ offset = <0x40>;
+ mode-normal = <BOOT_NORMAL>;
+ mode-recovery = <BOOT_RECOVERY>;
+ mode-bootloader = <BOOT_FASTBOOT>;
+ mode-loader = <BOOT_BL_DOWNLOAD>;
+ };
+ };
diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile
index bffa21a06462..f884e0ece735 100644
--- a/arch/arm/boot/dts/qcom/Makefile
+++ b/arch/arm/boot/dts/qcom/Makefile
@@ -114,6 +114,7 @@ dtb-$(CONFIG_ARCH_MSMCOBALT) += msmcobalt-sim.dtb \
msmcobalt-v2-qrd.dtb \
msmcobalt-qrd-skuk.dtb \
msmcobalt-qrd-vr1.dtb \
+ msmcobalt-v2-qrd-vr1.dtb \
apqcobalt-mtp.dtb \
apqcobalt-cdp.dtb \
apqcobalt-v2-mtp.dtb \
diff --git a/arch/arm/boot/dts/qcom/msm-pm2falcon.dtsi b/arch/arm/boot/dts/qcom/msm-pm2falcon.dtsi
index 91b4cc351010..41589d02f6fc 100644
--- a/arch/arm/boot/dts/qcom/msm-pm2falcon.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pm2falcon.dtsi
@@ -237,7 +237,7 @@
qcom,vref-mv = <350>;
qcom,switch-freq-khz = <800>;
qcom,ovp-mv = <29600>;
- qcom,ilim-ma = <980>;
+ qcom,ilim-ma = <970>;
qcom,boost-duty-ns = <26>;
qcom,mod-freq-khz = <9600>;
qcom,dim-mode = "hybrid";
diff --git a/arch/arm/boot/dts/qcom/msm-pmcobalt-rpm-regulator.dtsi b/arch/arm/boot/dts/qcom/msm-pmcobalt-rpm-regulator.dtsi
index 7a8e71d14291..7243a6b1d6d4 100644
--- a/arch/arm/boot/dts/qcom/msm-pmcobalt-rpm-regulator.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pmcobalt-rpm-regulator.dtsi
@@ -592,7 +592,7 @@
regulator-bob {
compatible = "qcom,rpm-smd-regulator";
- regulator-name = "pmcobalt_bob";
+ regulator-name = "pmicobalt_bob";
qcom,set = <3>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi
index ad56f1d3dd74..a5243aff4282 100644
--- a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi
@@ -597,7 +597,7 @@
qcom,vref-mv = <350>;
qcom,switch-freq-khz = <800>;
qcom,ovp-mv = <29600>;
- qcom,ilim-ma = <980>;
+ qcom,ilim-ma = <970>;
qcom,boost-duty-ns = <26>;
qcom,mod-freq-khz = <9600>;
qcom,dim-mode = "hybrid";
@@ -741,7 +741,7 @@
qcom,led-mask = <3>;
qcom,default-led-trigger = "switch0_trigger";
reg0 {
- regulator-name = "pmcobalt_bob";
+ regulator-name = "pmicobalt_bob";
max-voltage-uv = <3600000>;
};
};
@@ -752,7 +752,7 @@
qcom,led-mask = <4>;
qcom,default-led-trigger = "switch1_trigger";
reg0 {
- regulator-name = "pmcobalt_bob";
+ regulator-name = "pmicobalt_bob";
max-voltage-uv = <3600000>;
};
};
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dts b/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dts
index ee6a58a41b4f..e53912071502 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dts
+++ b/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dts
@@ -21,32 +21,3 @@
compatible = "qcom,msmcobalt-qrd", "qcom,msmcobalt", "qcom,qrd";
qcom,board-id = <0x02000b 0x80>;
};
-
-&soc {
- sound-tavil {
- qcom,model = "msmcobalt-qvr-tavil-snd-card";
- qcom,audio-routing =
- "RX_BIAS", "MCLK",
- "MADINPUT", "MCLK",
- "AMIC2", "MIC BIAS2",
- "MIC BIAS2", "Headset Mic",
- "DMIC0", "MIC BIAS1",
- "MIC BIAS1", "Digital Mic0",
- "DMIC1", "MIC BIAS1",
- "MIC BIAS1", "Digital Mic1",
- "DMIC2", "MIC BIAS3",
- "MIC BIAS3", "Digital Mic2",
- "DMIC4", "MIC BIAS4",
- "MIC BIAS4", "Digital Mic4",
- "SpkrLeft IN", "SPK1 OUT";
-
- qcom,msm-mbhc-hphl-swh = <1>;
- /delete-property/ qcom,us-euro-gpios;
- /delete-property/ qcom,hph-en0-gpio;
- /delete-property/ qcom,hph-en0-gpio;
-
- qcom,wsa-max-devs = <1>;
- qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0213>;
- qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrLeft";
- };
-};
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dtsi
index f8069856f3d8..f0607ac3a34a 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-qrd-vr1.dtsi
@@ -99,4 +99,31 @@
debounce-interval = <15>;
};
};
+
+ sound-tavil {
+ qcom,model = "msmcobalt-qvr-tavil-snd-card";
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "MADINPUT", "MCLK",
+ "AMIC2", "MIC BIAS2",
+ "MIC BIAS2", "Headset Mic",
+ "DMIC0", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic0",
+ "DMIC1", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic1",
+ "DMIC2", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic2",
+ "DMIC4", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic4",
+ "SpkrLeft IN", "SPK1 OUT";
+
+ qcom,msm-mbhc-hphl-swh = <1>;
+ /delete-property/ qcom,us-euro-gpios;
+ /delete-property/ qcom,hph-en0-gpio;
+ /delete-property/ qcom,hph-en0-gpio;
+
+ qcom,wsa-max-devs = <1>;
+ qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0213>;
+ qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrLeft";
+ };
};
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-qrd.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-qrd.dtsi
index 7d5509f0016c..682ea8a260ef 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-qrd.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-qrd.dtsi
@@ -264,7 +264,7 @@
};
&pmicobalt_wled {
- qcom,led-strings-list = [00 01];
+ qcom,led-strings-list = [01 02];
};
&dsi_dual_nt35597_video {
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi
index 2a61cccad273..bb72cf3a0d2c 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi
@@ -501,7 +501,7 @@
};
pmicobalt_bob_pin1: regulator-bob-pin1 {
compatible = "qcom,rpm-smd-regulator";
- regulator-name = "pmcobalt_bob_pin1";
+ regulator-name = "pmicobalt_bob_pin1";
qcom,set = <3>;
regulator-min-microvolt = <3312000>;
regulator-max-microvolt = <3600000>;
@@ -509,7 +509,7 @@
};
pmicobalt_bob_pin2: regulator-bob-pin2 {
compatible = "qcom,rpm-smd-regulator";
- regulator-name = "pmcobalt_bob_pin2";
+ regulator-name = "pmicobalt_bob_pin2";
qcom,set = <3>;
regulator-min-microvolt = <3312000>;
regulator-max-microvolt = <3600000>;
@@ -517,7 +517,7 @@
};
pmicobalt_bob_pin3: regulator-bob-pin3 {
compatible = "qcom,rpm-smd-regulator";
- regulator-name = "pmcobalt_bob_pin3";
+ regulator-name = "pmicobalt_bob_pin3";
qcom,set = <3>;
regulator-min-microvolt = <3312000>;
regulator-max-microvolt = <3600000>;
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-v2-qrd-vr1.dts b/arch/arm/boot/dts/qcom/msmcobalt-v2-qrd-vr1.dts
new file mode 100644
index 000000000000..15dd2d550b31
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msmcobalt-v2-qrd-vr1.dts
@@ -0,0 +1,23 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "msmcobalt-v2.dtsi"
+#include "msmcobalt-qrd-vr1.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM COBALT V2 VR1 Board";
+ compatible = "qcom,msmcobalt-qrd", "qcom,msmcobalt", "qcom,qrd";
+ qcom,board-id = <0x02000b 0x80>;
+};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-coresight.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-coresight.dtsi
index 3826b00bf09e..2f1ef974811e 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon-coresight.dtsi
+++ b/arch/arm/boot/dts/qcom/msmfalcon-coresight.dtsi
@@ -138,6 +138,14 @@
<&funnel_in0_out_funnel_merg>;
};
};
+ port@2 {
+ reg = <1>;
+ funnel_merg_in_funnel_in1:endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_in1_out_funnel_merg>;
+ };
+ };
};
};
@@ -183,6 +191,167 @@
};
};
+ funnel_in1: funnel@6042000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
+ reg = <0x6042000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-name = "coresight-funnel-in1";
+
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "apb_pclk", "core_a_clk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ funnel_in1_out_funnel_merg: endpoint {
+ remote-endpoint =
+ <&funnel_merg_in_funnel_in1>;
+ };
+ };
+ port@5 {
+ reg = <6>;
+ funnel_in1_in_funnel_apss_merg: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_apss_merg_out_funnel_in1>;
+ };
+ };
+ };
+ };
+
+ funnel_apss_merg: funnel@7b70000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
+ reg = <0x7b70000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-name = "coresight-funnel-apss-merg";
+
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "apb_pclk", "core_a_clk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ funnel_apss_merg_out_funnel_in1: endpoint {
+ remote-endpoint =
+ <&funnel_in1_in_funnel_apss_merg>;
+ };
+ };
+ port@1 {
+ reg = <0>;
+ funnel_apss_merg_in_funnel_apss: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_apss_out_funnel_apss_merg>;
+ };
+ };
+ };
+ };
+
+ funnel_apss: funnel@7b60000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
+ reg = <0x7b60000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-name = "coresight-funnel-apss";
+
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "apb_pclk", "core_a_clk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ funnel_apss_out_funnel_apss_merg: endpoint {
+ remote-endpoint =
+ <&funnel_apss_merg_in_funnel_apss>;
+ };
+ };
+ port@1 {
+ reg = <0>;
+ funnel_apss_in_etm0: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm0_out_funnel_apss>;
+ };
+ };
+ port@2 {
+ reg = <1>;
+ funnel_apss_in_etm1: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm1_out_funnel_apss>;
+ };
+ };
+ port@3 {
+ reg = <2>;
+ funnel_apss_in_etm2: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm2_out_funnel_apss>;
+ };
+ };
+ port@4 {
+ reg = <3>;
+ funnel_apss_in_etm3: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm3_out_funnel_apss>;
+ };
+ };
+ port@5 {
+ reg = <4>;
+ funnel_apss_in_etm4: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm4_out_funnel_apss>;
+ };
+ };
+ port@6 {
+ reg = <5>;
+ funnel_apss_in_etm5: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm5_out_funnel_apss>;
+ };
+ };
+ port@7 {
+ reg = <6>;
+ funnel_apss_in_etm6: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm6_out_funnel_apss>;
+ };
+ };
+ port@8 {
+ reg = <7>;
+ funnel_apss_in_etm7: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm7_out_funnel_apss>;
+ };
+ };
+ };
+ };
+
stm: stm@6002000 {
compatible = "arm,primecell";
arm,primecell-periphid = <0x0003b962>;
@@ -204,6 +373,166 @@
};
};
+ etm0: etm@7840000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b95d>;
+
+ reg = <0x7840000 0x1000>;
+ cpu = <&CPU0>;
+
+ coresight-name = "coresight-etm0";
+
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "apb_pclk", "core_a_clk";
+
+ port{
+ etm0_out_funnel_apss: endpoint {
+ remote-endpoint = <&funnel_apss_in_etm0>;
+ };
+ };
+ };
+
+ etm1: etm@7940000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b95d>;
+
+ reg = <0x7940000 0x1000>;
+ cpu = <&CPU1>;
+
+ coresight-name = "coresight-etm1";
+
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "apb_pclk", "core_a_clk";
+
+ port{
+ etm1_out_funnel_apss: endpoint {
+ remote-endpoint = <&funnel_apss_in_etm1>;
+ };
+ };
+ };
+
+ etm2: etm@7a40000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b95d>;
+
+ reg = <0x7a40000 0x1000>;
+ cpu = <&CPU2>;
+
+ coresight-name = "coresight-etm2";
+
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "apb_pclk", "core_a_clk";
+
+ port{
+ etm2_out_funnel_apss: endpoint {
+ remote-endpoint = <&funnel_apss_in_etm2>;
+ };
+ };
+ };
+
+ etm3: etm@7b40000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b95d>;
+
+ reg = <0x7b40000 0x1000>;
+ cpu = <&CPU3>;
+
+ coresight-name = "coresight-etm3";
+
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "apb_pclk", "core_a_clk";
+
+ port{
+ etm3_out_funnel_apss: endpoint {
+ remote-endpoint = <&funnel_apss_in_etm3>;
+ };
+ };
+ };
+
+ etm4: etm@7c40000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b95d>;
+
+ reg = <0x7c40000 0x1000>;
+ cpu = <&CPU4>;
+
+ coresight-name = "coresight-etm4";
+
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "apb_pclk", "core_a_clk";
+
+ port{
+ etm4_out_funnel_apss: endpoint {
+ remote-endpoint = <&funnel_apss_in_etm4>;
+ };
+ };
+ };
+
+ etm5: etm@7d40000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b95d>;
+
+ reg = <0x7d40000 0x1000>;
+ cpu = <&CPU5>;
+
+ coresight-name = "coresight-etm5";
+
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "apb_pclk", "core_a_clk";
+
+ port{
+ etm5_out_funnel_apss: endpoint {
+ remote-endpoint = <&funnel_apss_in_etm5>;
+ };
+ };
+ };
+
+ etm6: etm@7e40000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b95d>;
+
+ reg = <0x7e40000 0x1000>;
+ cpu = <&CPU6>;
+
+ coresight-name = "coresight-etm6";
+
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "apb_pclk", "core_a_clk";
+
+ port{
+ etm6_out_funnel_apss: endpoint {
+ remote-endpoint = <&funnel_apss_in_etm6>;
+ };
+ };
+ };
+
+ etm7: etm@7f40000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b95d>;
+
+ reg = <0x7f40000 0x1000>;
+ cpu = <&CPU7>;
+
+ coresight-name = "coresight-etm7";
+
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "apb_pclk", "core_a_clk";
+
+ port{
+ etm7_out_funnel_apss: endpoint {
+ remote-endpoint = <&funnel_apss_in_etm7>;
+ };
+ };
+ };
+
cti0: cti@6010000 {
compatible = "arm,coresight-cti";
reg = <0x6010000 0x1000>;
@@ -396,6 +725,110 @@
clock-names = "core_clk", "core_a_clk";
};
+ cti_cpu0: cti@7820000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x7820000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti-cpu0";
+ cpu = <&CPU0>;
+
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti_cpu1: cti@7920000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x7920000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti-cpu1";
+ cpu = <&CPU1>;
+
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti_cpu2: cti@7a20000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x7a20000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti-cpu2";
+ cpu = <&CPU2>;
+
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti_cpu3: cti@7b20000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x7b20000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti-cpu3";
+ cpu = <&CPU3>;
+
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti_cpu4: cti@7c20000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x7c20000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti-cpu4";
+ cpu = <&CPU4>;
+
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti_cpu5: cti@7d20000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x7d20000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti-cpu5";
+ cpu = <&CPU5>;
+
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti_cpu6: cti@7e20000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x7e20000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti-cpu6";
+ cpu = <&CPU6>;
+
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ cti_cpu7: cti@7f20000 {
+ compatible = "arm,coresight-cti";
+ reg = <0x7f20000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti-cpu7";
+ cpu = <&CPU7>;
+
+ clocks = <&clock_rpmcc RPM_QDSS_CLK>,
+ <&clock_rpmcc RPM_QDSS_A_CLK>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
funnel_qatb: funnel@6005000 {
compatible = "arm,primecell";
arm,primecell-periphid = <0x0003b908>;
diff --git a/arch/arm/boot/dts/qcom/msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msmfalcon.dtsi
index fffad9374a69..7a5d83a12bfa 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon.dtsi
+++ b/arch/arm/boot/dts/qcom/msmfalcon.dtsi
@@ -447,7 +447,7 @@
<0x10b4000 0x800>;
reg-names = "dcc-base", "dcc-ram-base";
- clocks = <&clock_rpmcc RPM_QDSS_CLK>;
+ clocks = <&clock_rpmcc GCC_DCC_AHB_CLK>;
clock-names = "dcc_clk";
};
diff --git a/arch/arm/mach-qcom/board-falcon.c b/arch/arm/mach-qcom/board-falcon.c
index e9374050b2cb..aec16886308d 100644
--- a/arch/arm/mach-qcom/board-falcon.c
+++ b/arch/arm/mach-qcom/board-falcon.c
@@ -31,3 +31,20 @@ DT_MACHINE_START(MSMFALCON_DT,
.init_machine = msmfalcon_init,
.dt_compat = msmfalcon_dt_match,
MACHINE_END
+
+static const char *msmtriton_dt_match[] __initconst = {
+ "qcom,msmtriton",
+ "qcom,apqtriton",
+ NULL
+};
+
+static void __init msmtriton_init(void)
+{
+ board_dt_populate(NULL);
+}
+
+DT_MACHINE_START(MSMTRITON_DT,
+ "Qualcomm Technologies, Inc. MSM TRITON (Flattened Device Tree)")
+ .init_machine = msmtriton_init,
+ .dt_compat = msmtriton_dt_match,
+MACHINE_END
diff --git a/arch/arm64/include/asm/Kbuild b/arch/arm64/include/asm/Kbuild
index 861ed8acdc3f..d49e164867e1 100644
--- a/arch/arm64/include/asm/Kbuild
+++ b/arch/arm64/include/asm/Kbuild
@@ -2,7 +2,6 @@
generic-y += bug.h
generic-y += bugs.h
-generic-y += checksum.h
generic-y += clkdev.h
generic-y += cputime.h
generic-y += current.h
diff --git a/arch/arm64/include/asm/checksum.h b/arch/arm64/include/asm/checksum.h
new file mode 100644
index 000000000000..09f65339d66d
--- /dev/null
+++ b/arch/arm64/include/asm/checksum.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_CHECKSUM_H
+#define __ASM_CHECKSUM_H
+
+#include <linux/types.h>
+
+static inline __sum16 csum_fold(__wsum csum)
+{
+ u32 sum = (__force u32)csum;
+ sum += (sum >> 16) | (sum << 16);
+ return ~(__force __sum16)(sum >> 16);
+}
+#define csum_fold csum_fold
+
+static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
+{
+ __uint128_t tmp;
+ u64 sum;
+
+ tmp = *(const __uint128_t *)iph;
+ iph += 16;
+ ihl -= 4;
+ tmp += ((tmp >> 64) | (tmp << 64));
+ sum = tmp >> 64;
+ do {
+ sum += *(const u32 *)iph;
+ iph += 4;
+ } while (--ihl);
+
+ sum += ((sum >> 32) | (sum << 32));
+ return csum_fold(sum >> 32);
+}
+#define ip_fast_csum ip_fast_csum
+
+#include <asm-generic/checksum.h>
+
+#endif /* __ASM_CHECKSUM_H */
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 20d17906fc9b..f80cfc36a354 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -3444,7 +3444,7 @@ static void print_binder_node(struct seq_file *m, struct binder_node *node)
static void print_binder_ref(struct seq_file *m, struct binder_ref *ref)
{
- seq_printf(m, " ref %d: desc %d %snode %d s %d w %d d %p\n",
+ seq_printf(m, " ref %d: desc %d %snode %d s %d w %d d %pK\n",
ref->debug_id, ref->desc, ref->node->proc ? "" : "dead ",
ref->node->debug_id, ref->strong, ref->weak, ref->death);
}
diff --git a/drivers/bluetooth/bluetooth-power.c b/drivers/bluetooth/bluetooth-power.c
index 1317ddaa3c23..b05b999fbbdc 100644
--- a/drivers/bluetooth/bluetooth-power.c
+++ b/drivers/bluetooth/bluetooth-power.c
@@ -46,6 +46,7 @@ static const struct of_device_id bt_power_match_table[] = {
static struct bluetooth_power_platform_data *bt_power_pdata;
static struct platform_device *btpdev;
static bool previous;
+static int pwr_state;
struct class *bt_class;
static int bt_major;
@@ -636,6 +637,7 @@ static int bt_power_probe(struct platform_device *pdev)
memcpy(bt_power_pdata, pdev->dev.platform_data,
sizeof(struct bluetooth_power_platform_data));
+ pwr_state = 0;
} else {
BT_PWR_ERR("Failed to get platform data");
goto free_pdata;
@@ -680,7 +682,7 @@ int bt_register_slimdev(struct device *dev)
static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- int ret;
+ int ret, pwr_cntrl = 0;
switch (cmd) {
case BT_CMD_SLIM_TEST:
@@ -692,6 +694,18 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
bt_power_pdata->slim_dev->platform_data
);
break;
+ case BT_CMD_PWR_CTRL:
+ pwr_cntrl = (int)arg;
+ BT_PWR_ERR("BT_CMD_PWR_CTRL pwr_cntrl:%d", pwr_cntrl);
+ if (pwr_state != pwr_cntrl) {
+ ret = bluetooth_power(pwr_cntrl);
+ if (!ret)
+ pwr_state = pwr_cntrl;
+ } else {
+ BT_PWR_ERR("BT chip state is already :%d no change d\n"
+ , pwr_state);
+ }
+ break;
default:
return -EINVAL;
}
@@ -711,6 +725,7 @@ static struct platform_driver bt_power_driver = {
static const struct file_operations bt_dev_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = bt_ioctl,
+ .compat_ioctl = bt_ioctl,
};
static int __init bluetooth_power_init(void)
@@ -733,7 +748,7 @@ static int __init bluetooth_power_init(void)
if (device_create(bt_class, NULL, MKDEV(bt_major, 0),
- NULL, "pintest") == NULL) {
+ NULL, "btpower") == NULL) {
BTFMSLIM_ERR("failed to allocate char dev\n");
goto chrdev_unreg;
}
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 67c1207d35be..ef8aaac6e0a2 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -1070,7 +1070,7 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx)
int idx = list[i].pgidx;
if (map->attr & FASTRPC_ATTR_NOVA) {
- offset = (uintptr_t)lpra[i].buf.pv;
+ offset = 0;
} else {
down_read(&current->mm->mmap_sem);
VERIFY(err, NULL != (vma = find_vma(current->mm,
diff --git a/drivers/clk/msm/clock-osm.c b/drivers/clk/msm/clock-osm.c
index b1c9a24c4087..5391ef456aae 100644
--- a/drivers/clk/msm/clock-osm.c
+++ b/drivers/clk/msm/clock-osm.c
@@ -2748,33 +2748,26 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev)
}
clk_prepare_enable(&sys_apcsaux_clk_gcc.c);
- /* Set boot rate */
- rc = clk_set_rate(&pwrcl_clk.c, msmcobalt_v1 ?
- MSMCOBALTV1_PWRCL_BOOT_RATE :
- MSMCOBALTV2_PWRCL_BOOT_RATE);
+ rc = clk_set_rate(&osm_clk_src.c, osm_clk_init_rate);
if (rc) {
- dev_err(&pdev->dev, "Unable to set boot rate on pwr cluster, rc=%d\n",
+ dev_err(&pdev->dev, "Unable to set init rate on osm_clk, rc=%d\n",
rc);
- clk_disable_unprepare(&sys_apcsaux_clk_gcc.c);
- return rc;
+ goto exit2;
}
- rc = clk_set_rate(&perfcl_clk.c, msmcobalt_v1 ?
- MSMCOBALTV1_PERFCL_BOOT_RATE :
- MSMCOBALTV2_PERFCL_BOOT_RATE);
+ /* Make sure index zero is selected */
+ rc = clk_set_rate(&pwrcl_clk.c, init_rate);
if (rc) {
- dev_err(&pdev->dev, "Unable to set boot rate on perf cluster, rc=%d\n",
+ dev_err(&pdev->dev, "Unable to set init rate on pwr cluster, rc=%d\n",
rc);
- clk_disable_unprepare(&sys_apcsaux_clk_gcc.c);
- return rc;
+ goto exit2;
}
- rc = clk_set_rate(&osm_clk_src.c, osm_clk_init_rate);
+ rc = clk_set_rate(&perfcl_clk.c, init_rate);
if (rc) {
- dev_err(&pdev->dev, "Unable to set init rate on osm_clk, rc=%d\n",
+ dev_err(&pdev->dev, "Unable to set init rate on perf cluster, rc=%d\n",
rc);
- clk_disable_unprepare(&sys_apcsaux_clk_gcc.c);
- return rc;
+ goto exit2;
}
get_online_cpus();
@@ -2785,6 +2778,25 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev)
"Failed to enable clock for cpu %d\n", cpu);
}
+ /* Set final boot rate */
+ rc = clk_set_rate(&pwrcl_clk.c, msmcobalt_v1 ?
+ MSMCOBALTV1_PWRCL_BOOT_RATE :
+ MSMCOBALTV2_PWRCL_BOOT_RATE);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to set boot rate on pwr cluster, rc=%d\n",
+ rc);
+ goto exit2;
+ }
+
+ rc = clk_set_rate(&perfcl_clk.c, msmcobalt_v1 ?
+ MSMCOBALTV1_PERFCL_BOOT_RATE :
+ MSMCOBALTV2_PERFCL_BOOT_RATE);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to set boot rate on perf cluster, rc=%d\n",
+ rc);
+ goto exit2;
+ }
+
pwrcl_clk.version = clk_osm_read_reg(&pwrcl_clk, VERSION_REG);
perfcl_clk.version = clk_osm_read_reg(&perfcl_clk, VERSION_REG);
@@ -2801,6 +2813,8 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev)
return 0;
+exit2:
+ clk_disable_unprepare(&sys_apcsaux_clk_gcc.c);
exit:
dev_err(&pdev->dev, "OSM driver failed to initialize, rc=%d\n",
rc);
diff --git a/drivers/crypto/msm/qce.c b/drivers/crypto/msm/qce.c
index 7ddbb1938400..4cf95b90a2df 100644
--- a/drivers/crypto/msm/qce.c
+++ b/drivers/crypto/msm/qce.c
@@ -1,6 +1,6 @@
/* Qualcomm Crypto Engine driver.
*
- * Copyright (c) 2010-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1962,8 +1962,8 @@ int qce_aead_req(void *handle, struct qce_req *q_req)
else
q_req->cryptlen = areq->cryptlen - authsize;
- if ((q_req->cryptlen > ULONG_MAX - ivsize) ||
- (q_req->cryptlen + ivsize > ULONG_MAX - areq->assoclen)) {
+ if ((q_req->cryptlen > UINT_MAX - ivsize) ||
+ (q_req->cryptlen + ivsize > UINT_MAX - areq->assoclen)) {
pr_err("Integer overflow on total aead req length.\n");
return -EINVAL;
}
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 9940f7a7c2b7..6160aa567fbf 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -589,11 +589,21 @@ static irqreturn_t adreno_irq_handler(struct kgsl_device *device)
struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
struct adreno_irq *irq_params = gpudev->irq;
irqreturn_t ret = IRQ_NONE;
- unsigned int status = 0, tmp;
+ unsigned int status = 0, tmp, int_bit;
int i;
adreno_readreg(adreno_dev, ADRENO_REG_RBBM_INT_0_STATUS, &status);
+ /*
+ * Clear all the interrupt bits but ADRENO_INT_RBBM_AHB_ERROR. Because
+ * even if we clear it here, it will stay high until it is cleared
+ * in its respective handler. Otherwise, the interrupt handler will
+ * fire again.
+ */
+ int_bit = ADRENO_INT_BIT(adreno_dev, ADRENO_INT_RBBM_AHB_ERROR);
+ adreno_writereg(adreno_dev, ADRENO_REG_RBBM_INT_CLEAR_CMD,
+ status & ~int_bit);
+
/* Loop through all set interrupts and call respective handlers */
for (tmp = status; tmp != 0;) {
i = fls(tmp) - 1;
@@ -612,9 +622,14 @@ static irqreturn_t adreno_irq_handler(struct kgsl_device *device)
gpudev->irq_trace(adreno_dev, status);
- if (status)
+ /*
+ * Clear ADRENO_INT_RBBM_AHB_ERROR bit after this interrupt has been
+ * cleared in its respective handler
+ */
+ if (status & int_bit)
adreno_writereg(adreno_dev, ADRENO_REG_RBBM_INT_CLEAR_CMD,
- status);
+ int_bit);
+
return ret;
}
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 0f3403cb0095..a2af26c81f50 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -198,6 +198,10 @@ struct adreno_gpudev;
/* Time to allow preemption to complete (in ms) */
#define ADRENO_PREEMPT_TIMEOUT 10000
+#define ADRENO_INT_BIT(a, _bit) (((a)->gpucore->gpudev->int_bits) ? \
+ (adreno_get_int(a, _bit) < 0 ? 0 : \
+ BIT(adreno_get_int(a, _bit))) : 0)
+
/**
* enum adreno_preempt_states
* ADRENO_PREEMPT_NONE: No preemption is scheduled
@@ -574,6 +578,11 @@ enum adreno_regs {
ADRENO_REG_REGISTER_MAX,
};
+enum adreno_int_bits {
+ ADRENO_INT_RBBM_AHB_ERROR,
+ ADRENO_INT_BITS_MAX,
+};
+
/**
* adreno_reg_offsets: Holds array of register offsets
* @offsets: Offset array of size defined by enum adreno_regs
@@ -589,6 +598,7 @@ struct adreno_reg_offsets {
#define ADRENO_REG_UNUSED 0xFFFFFFFF
#define ADRENO_REG_SKIP 0xFFFFFFFE
#define ADRENO_REG_DEFINE(_offset, _reg) [_offset] = _reg
+#define ADRENO_INT_DEFINE(_offset, _val) ADRENO_REG_DEFINE(_offset, _val)
/*
* struct adreno_vbif_data - Describes vbif register value pair
@@ -726,6 +736,7 @@ struct adreno_gpudev {
* so define them in the structure and use them as variables.
*/
const struct adreno_reg_offsets *reg_offsets;
+ unsigned int *const int_bits;
const struct adreno_ft_perf_counters *ft_perf_counters;
unsigned int ft_perf_counters_count;
@@ -1101,6 +1112,23 @@ static inline unsigned int adreno_getreg(struct adreno_device *adreno_dev,
return gpudev->reg_offsets->offsets[offset_name];
}
+/*
+ * adreno_get_int() - Returns the offset value of an interrupt bit from
+ * the interrupt bit array in the gpudev node
+ * @adreno_dev: Pointer to the the adreno device
+ * @bit_name: The interrupt bit enum whose bit is returned
+ */
+static inline unsigned int adreno_get_int(struct adreno_device *adreno_dev,
+ enum adreno_int_bits bit_name)
+{
+ struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
+
+ if (bit_name >= ADRENO_INT_BITS_MAX)
+ return -ERANGE;
+
+ return gpudev->int_bits[bit_name];
+}
+
/**
* adreno_gpu_fault() - Return the current state of the GPU
* @adreno_dev: A pointer to the adreno_device to query
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 97e71464c2df..3f5a9c6318f6 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -1425,6 +1425,10 @@ static struct adreno_coresight a3xx_coresight = {
.groups = a3xx_coresight_groups,
};
+static unsigned int a3xx_int_bits[ADRENO_INT_BITS_MAX] = {
+ ADRENO_INT_DEFINE(ADRENO_INT_RBBM_AHB_ERROR, A3XX_INT_RBBM_AHB_ERROR),
+};
+
/* Register offset defines for A3XX */
static unsigned int a3xx_register_offsets[ADRENO_REG_REGISTER_MAX] = {
ADRENO_REG_DEFINE(ADRENO_REG_CP_ME_RAM_WADDR, A3XX_CP_ME_RAM_WADDR),
@@ -1853,6 +1857,7 @@ int a3xx_microcode_load(struct adreno_device *adreno_dev,
struct adreno_gpudev adreno_a3xx_gpudev = {
.reg_offsets = &a3xx_reg_offsets,
+ .int_bits = a3xx_int_bits,
.ft_perf_counters = a3xx_ft_perf_counters,
.ft_perf_counters_count = ARRAY_SIZE(a3xx_ft_perf_counters),
.perfcounters = &a3xx_perfcounters,
diff --git a/drivers/gpu/msm/adreno_a4xx.c b/drivers/gpu/msm/adreno_a4xx.c
index bfbdb0e7ac1f..5ca04e522270 100644
--- a/drivers/gpu/msm/adreno_a4xx.c
+++ b/drivers/gpu/msm/adreno_a4xx.c
@@ -739,6 +739,10 @@ static void a4xx_err_callback(struct adreno_device *adreno_dev, int bit)
}
}
+static unsigned int a4xx_int_bits[ADRENO_INT_BITS_MAX] = {
+ ADRENO_INT_DEFINE(ADRENO_INT_RBBM_AHB_ERROR, A4XX_INT_RBBM_AHB_ERROR),
+};
+
/* Register offset defines for A4XX, in order of enum adreno_regs */
static unsigned int a4xx_register_offsets[ADRENO_REG_REGISTER_MAX] = {
ADRENO_REG_DEFINE(ADRENO_REG_CP_ME_RAM_WADDR, A4XX_CP_ME_RAM_WADDR),
@@ -1765,6 +1769,7 @@ static struct adreno_snapshot_data a4xx_snapshot_data = {
struct adreno_gpudev adreno_a4xx_gpudev = {
.reg_offsets = &a4xx_reg_offsets,
+ .int_bits = a4xx_int_bits,
.ft_perf_counters = a4xx_ft_perf_counters,
.ft_perf_counters_count = ARRAY_SIZE(a4xx_ft_perf_counters),
.perfcounters = &a4xx_perfcounters,
diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c
index 2891940b8f5b..860f6d2925f1 100644
--- a/drivers/gpu/msm/adreno_a5xx.c
+++ b/drivers/gpu/msm/adreno_a5xx.c
@@ -2872,6 +2872,10 @@ static struct adreno_ft_perf_counters a5xx_ft_perf_counters[] = {
{KGSL_PERFCOUNTER_GROUP_TSE, A5XX_TSE_INPUT_PRIM_NUM},
};
+static unsigned int a5xx_int_bits[ADRENO_INT_BITS_MAX] = {
+ ADRENO_INT_DEFINE(ADRENO_INT_RBBM_AHB_ERROR, A5XX_INT_RBBM_AHB_ERROR),
+};
+
/* Register offset defines for A5XX, in order of enum adreno_regs */
static unsigned int a5xx_register_offsets[ADRENO_REG_REGISTER_MAX] = {
ADRENO_REG_DEFINE(ADRENO_REG_CP_WFI_PEND_CTR, A5XX_CP_WFI_PEND_CTR),
@@ -3504,6 +3508,7 @@ static struct adreno_coresight a5xx_coresight = {
struct adreno_gpudev adreno_a5xx_gpudev = {
.reg_offsets = &a5xx_reg_offsets,
+ .int_bits = a5xx_int_bits,
.ft_perf_counters = a5xx_ft_perf_counters,
.ft_perf_counters_count = ARRAY_SIZE(a5xx_ft_perf_counters),
.coresight = &a5xx_coresight,
diff --git a/drivers/leds/leds-qpnp-wled.c b/drivers/leds/leds-qpnp-wled.c
index 18d968d3711d..894c1d88b3ef 100644
--- a/drivers/leds/leds-qpnp-wled.c
+++ b/drivers/leds/leds-qpnp-wled.c
@@ -45,11 +45,13 @@
#define QPNP_WLED_SWITCH_FREQ_REG(b) (b + 0x4C)
#define QPNP_WLED_OVP_REG(b) (b + 0x4D)
#define QPNP_WLED_ILIM_REG(b) (b + 0x4E)
+#define QPNP_WLED_AMOLED_VOUT_REG(b) (b + 0x4F)
#define QPNP_WLED_SOFTSTART_RAMP_DLY(b) (b + 0x53)
#define QPNP_WLED_VLOOP_COMP_RES_REG(b) (b + 0x55)
#define QPNP_WLED_VLOOP_COMP_GM_REG(b) (b + 0x56)
#define QPNP_WLED_PSM_CTRL_REG(b) (b + 0x5B)
#define QPNP_WLED_SC_PRO_REG(b) (b + 0x5E)
+#define QPNP_WLED_SWIRE_AVDD_REG(b) (b + 0x5F)
#define QPNP_WLED_CTRL_SPARE_REG(b) (b + 0xDF)
#define QPNP_WLED_TEST1_REG(b) (b + 0xE2)
#define QPNP_WLED_TEST4_REG(b) (b + 0xE5)
@@ -83,12 +85,15 @@
#define QPNP_WLED_VREF_PSM_DFLT_AMOLED_MV 450
#define QPNP_WLED_PSM_CTRL_OVERWRITE 0x80
-#define QPNP_WLED_ILIM_MASK 0xF8
-#define QPNP_WLED_ILIM_MIN_MA 105
-#define QPNP_WLED_ILIM_MAX_MA 1980
-#define QPNP_WLED_ILIM_STEP_MA 280
-#define QPNP_WLED_DFLT_ILIM_MA 980
-#define QPNP_WLED_ILIM_OVERWRITE 0x80
+#define QPNP_WLED_ILIM_MASK GENMASK(2, 0)
+#define QPNP_WLED_ILIM_OVERWRITE BIT(7)
+#define PMI8994_WLED_ILIM_MIN_MA 105
+#define PMI8994_WLED_ILIM_MAX_MA 1980
+#define PMI8994_WLED_DFLT_ILIM_MA 980
+#define PMI8994_AMOLED_DFLT_ILIM_MA 385
+#define PMICOBALT_WLED_ILIM_MAX_MA 1500
+#define PMICOBALT_WLED_DFLT_ILIM_MA 970
+#define PMICOBALT_AMOLED_DFLT_ILIM_MA 620
#define QPNP_WLED_BOOST_DUTY_MASK 0xFC
#define QPNP_WLED_BOOST_DUTY_STEP_NS 52
#define QPNP_WLED_BOOST_DUTY_MIN_NS 26
@@ -196,11 +201,19 @@
#define NUM_SUPPORTED_AVDD_VOLTAGES 6
#define QPNP_WLED_DFLT_AVDD_MV 7600
+#define QPNP_WLED_AVDD_MIN_MV 5650
+#define QPNP_WLED_AVDD_MAX_MV 7900
+#define QPNP_WLED_AVDD_STEP_MV 150
#define QPNP_WLED_AVDD_MIN_TRIM_VAL 0x0
#define QPNP_WLED_AVDD_MAX_TRIM_VAL 0xF
+#define QPNP_WLED_AVDD_SEL_SPMI_BIT BIT(7)
#define QPNP_WLED_AVDD_SET_BIT BIT(4)
#define NUM_SUPPORTED_OVP_THRESHOLDS 4
+#define NUM_SUPPORTED_ILIM_THRESHOLDS 8
+
+#define QPNP_WLED_AVDD_MV_TO_REG(val) \
+ ((val - QPNP_WLED_AVDD_MIN_MV) / QPNP_WLED_AVDD_STEP_MV)
/* output feedback mode */
enum qpnp_wled_fdbk_op {
@@ -254,6 +267,14 @@ static int qpnp_wled_ovp_thresholds_pmicobalt[NUM_SUPPORTED_OVP_THRESHOLDS] = {
31100, 29600, 19600, 18100,
};
+static int qpnp_wled_ilim_settings_pmi8994[NUM_SUPPORTED_ILIM_THRESHOLDS] = {
+ 105, 385, 660, 980, 1150, 1420, 1700, 1980,
+};
+
+static int qpnp_wled_ilim_settings_pmicobalt[NUM_SUPPORTED_ILIM_THRESHOLDS] = {
+ 105, 280, 450, 620, 970, 1150, 1300, 1500,
+};
+
/**
* qpnp_wled - wed data structure
* @ cdev - led class device
@@ -288,6 +309,7 @@ static int qpnp_wled_ovp_thresholds_pmicobalt[NUM_SUPPORTED_OVP_THRESHOLDS] = {
* @ cons_sync_write_delay_us - delay between two consecutive writes to SYNC
* @ strings - supported list of strings
* @ num_strings - number of strings
+ * @ avdd_mode_spmi - enable avdd programming via spmi
* @ en_9b_dim_res - enable or disable 9bit dimming
* @ en_phase_stag - enable or disable phase staggering
* @ en_cabc - enable or disable cabc
@@ -330,6 +352,7 @@ struct qpnp_wled {
u16 cons_sync_write_delay_us;
u8 strings[QPNP_WLED_MAX_STRINGS];
u8 num_strings;
+ bool avdd_mode_spmi;
bool en_9b_dim_res;
bool en_phase_stag;
bool en_cabc;
@@ -1089,6 +1112,142 @@ static int qpnp_wled_ovp_config(struct qpnp_wled *wled)
return 0;
}
+static int qpnp_wled_avdd_trim_config(struct qpnp_wled *wled)
+{
+ int rc, i;
+ u8 reg;
+
+ for (i = 0; i < NUM_SUPPORTED_AVDD_VOLTAGES; i++) {
+ if (wled->avdd_target_voltage_mv ==
+ qpnp_wled_avdd_target_voltages[i])
+ break;
+ }
+
+ if (i == NUM_SUPPORTED_AVDD_VOLTAGES) {
+ dev_err(&wled->pdev->dev,
+ "Invalid avdd target voltage specified in device tree\n");
+ return -EINVAL;
+ }
+
+ /* Update WLED_OVP register based on desired target voltage */
+ reg = qpnp_wled_ovp_reg_settings[i];
+ rc = qpnp_wled_masked_write_reg(wled, QPNP_WLED_OVP_MASK, &reg,
+ QPNP_WLED_OVP_REG(wled->ctrl_base));
+ if (rc)
+ return rc;
+
+ /* Update WLED_TRIM register based on desired target voltage */
+ rc = qpnp_wled_read_reg(wled, &reg,
+ QPNP_WLED_REF_7P7_TRIM_REG(wled->ctrl_base));
+ if (rc)
+ return rc;
+
+ reg += qpnp_wled_avdd_trim_adjustments[i];
+ if ((s8)reg < QPNP_WLED_AVDD_MIN_TRIM_VAL ||
+ (s8)reg > QPNP_WLED_AVDD_MAX_TRIM_VAL) {
+ dev_dbg(&wled->pdev->dev,
+ "adjusted trim %d is not within range, capping it\n",
+ (s8)reg);
+ if ((s8)reg < QPNP_WLED_AVDD_MIN_TRIM_VAL)
+ reg = QPNP_WLED_AVDD_MIN_TRIM_VAL;
+ else
+ reg = QPNP_WLED_AVDD_MAX_TRIM_VAL;
+ }
+
+ reg &= QPNP_WLED_7P7_TRIM_MASK;
+ rc = qpnp_wled_sec_write_reg(wled, reg,
+ QPNP_WLED_REF_7P7_TRIM_REG(wled->ctrl_base));
+ if (rc < 0)
+ dev_err(&wled->pdev->dev, "Write to 7P7_TRIM register failed, rc=%d\n",
+ rc);
+ return rc;
+}
+
+static int qpnp_wled_avdd_mode_config(struct qpnp_wled *wled)
+{
+ int rc;
+ u8 reg = 0;
+
+ /*
+ * At present, configuring the mode to SPMI/SWIRE for controlling
+ * AVDD voltage is available only in pmicobalt/pm2falcon.
+ */
+ if (wled->pmic_rev_id->pmic_subtype != PMICOBALT_SUBTYPE &&
+ wled->pmic_rev_id->pmic_subtype != PM2FALCON_SUBTYPE)
+ return 0;
+
+ /* AMOLED_VOUT should be configured for AMOLED */
+ if (!wled->disp_type_amoled)
+ return 0;
+
+ /* Configure avdd register */
+ if (wled->avdd_target_voltage_mv > QPNP_WLED_AVDD_MAX_MV) {
+ dev_dbg(&wled->pdev->dev, "Capping avdd target voltage to %d\n",
+ QPNP_WLED_AVDD_MAX_MV);
+ wled->avdd_target_voltage_mv = QPNP_WLED_AVDD_MAX_MV;
+ } else if (wled->avdd_target_voltage_mv < QPNP_WLED_AVDD_MIN_MV) {
+ dev_info(&wled->pdev->dev, "Capping avdd target voltage to %d\n",
+ QPNP_WLED_AVDD_MIN_MV);
+ wled->avdd_target_voltage_mv = QPNP_WLED_AVDD_MIN_MV;
+ }
+
+ reg = QPNP_WLED_AVDD_MV_TO_REG(wled->avdd_target_voltage_mv);
+
+ if (wled->avdd_mode_spmi) {
+ reg |= QPNP_WLED_AVDD_SEL_SPMI_BIT;
+ rc = qpnp_wled_write_reg(wled, reg,
+ QPNP_WLED_AMOLED_VOUT_REG(wled->ctrl_base));
+ } else {
+ rc = qpnp_wled_write_reg(wled, reg,
+ QPNP_WLED_SWIRE_AVDD_REG(wled->ctrl_base));
+ }
+
+ if (rc < 0)
+ dev_err(&wled->pdev->dev, "Write to VOUT/AVDD register failed, rc=%d\n",
+ rc);
+ return rc;
+}
+
+static int qpnp_wled_ilim_config(struct qpnp_wled *wled)
+{
+ int rc, i, *ilim_table;
+ u8 reg;
+
+ if (wled->ilim_ma < PMI8994_WLED_ILIM_MIN_MA)
+ wled->ilim_ma = PMI8994_WLED_ILIM_MIN_MA;
+
+ if (wled->pmic_rev_id->pmic_subtype == PMICOBALT_SUBTYPE ||
+ wled->pmic_rev_id->pmic_subtype == PM2FALCON_SUBTYPE) {
+ ilim_table = qpnp_wled_ilim_settings_pmicobalt;
+ if (wled->ilim_ma > PMICOBALT_WLED_ILIM_MAX_MA)
+ wled->ilim_ma = PMICOBALT_WLED_ILIM_MAX_MA;
+ } else {
+ ilim_table = qpnp_wled_ilim_settings_pmi8994;
+ if (wled->ilim_ma > PMI8994_WLED_ILIM_MAX_MA)
+ wled->ilim_ma = PMI8994_WLED_ILIM_MAX_MA;
+ }
+
+ for (i = 0; i < NUM_SUPPORTED_ILIM_THRESHOLDS; i++) {
+ if (wled->ilim_ma == ilim_table[i])
+ break;
+ }
+
+ if (i == NUM_SUPPORTED_ILIM_THRESHOLDS) {
+ dev_err(&wled->pdev->dev,
+ "Invalid ilim threshold specified in device tree\n");
+ return -EINVAL;
+ }
+
+ reg = (i & QPNP_WLED_ILIM_MASK) | QPNP_WLED_ILIM_OVERWRITE;
+ rc = qpnp_wled_masked_write_reg(wled,
+ QPNP_WLED_ILIM_MASK | QPNP_WLED_ILIM_OVERWRITE,
+ &reg, QPNP_WLED_ILIM_REG(wled->ctrl_base));
+ if (rc < 0)
+ dev_err(&wled->pdev->dev, "Write to ILIM register failed, rc=%d\n",
+ rc);
+ return rc;
+}
+
/* Configure WLED registers */
static int qpnp_wled_config(struct qpnp_wled *wled)
{
@@ -1131,24 +1290,10 @@ static int qpnp_wled_config(struct qpnp_wled *wled)
return rc;
/* Configure the ILIM register */
- if (wled->ilim_ma < QPNP_WLED_ILIM_MIN_MA)
- wled->ilim_ma = QPNP_WLED_ILIM_MIN_MA;
- else if (wled->ilim_ma > QPNP_WLED_ILIM_MAX_MA)
- wled->ilim_ma = QPNP_WLED_ILIM_MAX_MA;
-
- rc = qpnp_wled_read_reg(wled, &reg,
- QPNP_WLED_ILIM_REG(wled->ctrl_base));
- if (rc < 0)
+ rc = qpnp_wled_ilim_config(wled);
+ if (rc < 0) {
+ pr_err("Error in configuring wled ilim, rc=%d\n", rc);
return rc;
- temp = (wled->ilim_ma / QPNP_WLED_ILIM_STEP_MA);
- if (temp != (reg & ~QPNP_WLED_ILIM_MASK)) {
- reg &= QPNP_WLED_ILIM_MASK;
- reg |= temp;
- reg |= QPNP_WLED_ILIM_OVERWRITE;
- rc = qpnp_wled_write_reg(wled, reg,
- QPNP_WLED_ILIM_REG(wled->ctrl_base));
- if (rc)
- return rc;
}
/* Configure the Soft start Ramp delay: for AMOLED - 0,for LCD - 2 */
@@ -1199,50 +1344,15 @@ static int qpnp_wled_config(struct qpnp_wled *wled)
}
if (is_avdd_trim_adjustment_required(wled)) {
- for (i = 0; i < NUM_SUPPORTED_AVDD_VOLTAGES; i++) {
- if (wled->avdd_target_voltage_mv ==
- qpnp_wled_avdd_target_voltages[i])
- break;
- }
-
- if (i == NUM_SUPPORTED_AVDD_VOLTAGES) {
- dev_err(&wled->pdev->dev,
- "Invalid avdd target voltage specified in device tree\n");
- return -EINVAL;
- }
-
- /* Update WLED_OVP register based on desired target voltage */
- reg = qpnp_wled_ovp_reg_settings[i];
- rc = qpnp_wled_masked_write_reg(wled, QPNP_WLED_OVP_MASK, &reg,
- QPNP_WLED_OVP_REG(wled->ctrl_base));
- if (rc)
- return rc;
-
- /* Update WLED_TRIM register based on desired target voltage */
- rc = qpnp_wled_read_reg(wled, &reg,
- QPNP_WLED_REF_7P7_TRIM_REG(wled->ctrl_base));
- if (rc)
- return rc;
-
- reg += qpnp_wled_avdd_trim_adjustments[i];
- if ((s8)reg < QPNP_WLED_AVDD_MIN_TRIM_VAL ||
- (s8)reg > QPNP_WLED_AVDD_MAX_TRIM_VAL) {
- dev_info(&wled->pdev->dev,
- "adjusted trim %d is not within range, capping it\n",
- (s8)reg);
- if ((s8)reg < QPNP_WLED_AVDD_MIN_TRIM_VAL)
- reg = QPNP_WLED_AVDD_MIN_TRIM_VAL;
- else
- reg = QPNP_WLED_AVDD_MAX_TRIM_VAL;
- }
-
- reg &= QPNP_WLED_7P7_TRIM_MASK;
- rc = qpnp_wled_sec_write_reg(wled, reg,
- QPNP_WLED_REF_7P7_TRIM_REG(wled->ctrl_base));
- if (rc)
+ rc = qpnp_wled_avdd_trim_config(wled);
+ if (rc < 0)
return rc;
}
+ rc = qpnp_wled_avdd_mode_config(wled);
+ if (rc < 0)
+ return rc;
+
/* Configure the MODULATION register */
if (wled->mod_freq_khz <= QPNP_WLED_MOD_FREQ_1200_KHZ) {
wled->mod_freq_khz = QPNP_WLED_MOD_FREQ_1200_KHZ;
@@ -1561,6 +1671,9 @@ static int qpnp_wled_parse_dt(struct qpnp_wled *wled)
return rc;
}
+ wled->avdd_mode_spmi = of_property_read_bool(pdev->dev.of_node,
+ "qcom,avdd-mode-spmi");
+
wled->avdd_target_voltage_mv = QPNP_WLED_DFLT_AVDD_MV;
rc = of_property_read_u32(pdev->dev.of_node,
"qcom,avdd-target-voltage-mv", &temp_val);
@@ -1635,7 +1748,19 @@ static int qpnp_wled_parse_dt(struct qpnp_wled *wled)
return rc;
}
- wled->ilim_ma = QPNP_WLED_DFLT_ILIM_MA;
+ if (wled->pmic_rev_id->pmic_subtype == PMICOBALT_SUBTYPE ||
+ wled->pmic_rev_id->pmic_subtype == PM2FALCON_SUBTYPE) {
+ if (wled->disp_type_amoled)
+ wled->ilim_ma = PMICOBALT_AMOLED_DFLT_ILIM_MA;
+ else
+ wled->ilim_ma = PMICOBALT_WLED_DFLT_ILIM_MA;
+ } else {
+ if (wled->disp_type_amoled)
+ wled->ilim_ma = PMI8994_AMOLED_DFLT_ILIM_MA;
+ else
+ wled->ilim_ma = PMI8994_WLED_DFLT_ILIM_MA;
+ }
+
rc = of_property_read_u32(pdev->dev.of_node,
"qcom,ilim-ma", &temp_val);
if (!rc) {
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
index d18308344431..293371b88ab9 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
@@ -127,6 +127,7 @@ enum ipa3_usb_state {
IPA_USB_SUSPEND_REQUESTED,
IPA_USB_SUSPEND_IN_PROGRESS,
IPA_USB_SUSPENDED,
+ IPA_USB_SUSPENDED_NO_RWAKEUP,
IPA_USB_RESUME_IN_PROGRESS
};
@@ -152,6 +153,12 @@ struct finish_suspend_work_context {
u32 ul_clnt_hdl;
};
+struct ipa3_usb_teth_prot_conn_params {
+ u32 usb_to_ipa_clnt_hdl;
+ u32 ipa_to_usb_clnt_hdl;
+ struct ipa_usb_teth_prot_params params;
+};
+
/**
* Transport type - could be either data tethering or DPL
* Each transport has it's own RM resources and statuses
@@ -163,6 +170,7 @@ struct ipa3_usb_transport_type_ctx {
enum ipa3_usb_state state;
struct finish_suspend_work_context finish_suspend_work;
struct ipa_usb_xdci_chan_params ch_params;
+ struct ipa3_usb_teth_prot_conn_params teth_conn_params;
};
struct ipa3_usb_smmu_reg_map {
@@ -189,14 +197,15 @@ struct ipa3_usb_context {
};
enum ipa3_usb_op {
- IPA_USB_INIT_TETH_PROT,
- IPA_USB_REQUEST_CHANNEL,
- IPA_USB_CONNECT,
- IPA_USB_DISCONNECT,
- IPA_USB_RELEASE_CHANNEL,
- IPA_USB_DEINIT_TETH_PROT,
- IPA_USB_SUSPEND,
- IPA_USB_RESUME
+ IPA_USB_OP_INIT_TETH_PROT,
+ IPA_USB_OP_REQUEST_CHANNEL,
+ IPA_USB_OP_CONNECT,
+ IPA_USB_OP_DISCONNECT,
+ IPA_USB_OP_RELEASE_CHANNEL,
+ IPA_USB_OP_DEINIT_TETH_PROT,
+ IPA_USB_OP_SUSPEND,
+ IPA_USB_OP_SUSPEND_NO_RWAKEUP,
+ IPA_USB_OP_RESUME
};
struct ipa3_usb_status_dbg_info {
@@ -228,22 +237,24 @@ struct ipa3_usb_context *ipa3_usb_ctx;
static char *ipa3_usb_op_to_string(enum ipa3_usb_op op)
{
switch (op) {
- case IPA_USB_INIT_TETH_PROT:
- return "IPA_USB_INIT_TETH_PROT";
- case IPA_USB_REQUEST_CHANNEL:
- return "IPA_USB_REQUEST_CHANNEL";
- case IPA_USB_CONNECT:
- return "IPA_USB_CONNECT";
- case IPA_USB_DISCONNECT:
- return "IPA_USB_DISCONNECT";
- case IPA_USB_RELEASE_CHANNEL:
- return "IPA_USB_RELEASE_CHANNEL";
- case IPA_USB_DEINIT_TETH_PROT:
- return "IPA_USB_DEINIT_TETH_PROT";
- case IPA_USB_SUSPEND:
- return "IPA_USB_SUSPEND";
- case IPA_USB_RESUME:
- return "IPA_USB_RESUME";
+ case IPA_USB_OP_INIT_TETH_PROT:
+ return "IPA_USB_OP_INIT_TETH_PROT";
+ case IPA_USB_OP_REQUEST_CHANNEL:
+ return "IPA_USB_OP_REQUEST_CHANNEL";
+ case IPA_USB_OP_CONNECT:
+ return "IPA_USB_OP_CONNECT";
+ case IPA_USB_OP_DISCONNECT:
+ return "IPA_USB_OP_DISCONNECT";
+ case IPA_USB_OP_RELEASE_CHANNEL:
+ return "IPA_USB_OP_RELEASE_CHANNEL";
+ case IPA_USB_OP_DEINIT_TETH_PROT:
+ return "IPA_USB_OP_DEINIT_TETH_PROT";
+ case IPA_USB_OP_SUSPEND:
+ return "IPA_USB_OP_SUSPEND";
+ case IPA_USB_OP_SUSPEND_NO_RWAKEUP:
+ return "IPA_USB_OP_SUSPEND_NO_RWAKEUP";
+ case IPA_USB_OP_RESUME:
+ return "IPA_USB_OP_RESUME";
}
return "UNSUPPORTED";
@@ -266,6 +277,8 @@ static char *ipa3_usb_state_to_string(enum ipa3_usb_state state)
return "IPA_USB_SUSPEND_IN_PROGRESS";
case IPA_USB_SUSPENDED:
return "IPA_USB_SUSPENDED";
+ case IPA_USB_SUSPENDED_NO_RWAKEUP:
+ return "IPA_USB_SUSPENDED_NO_RWAKEUP";
case IPA_USB_RESUME_IN_PROGRESS:
return "IPA_USB_RESUME_IN_PROGRESS";
}
@@ -312,6 +325,7 @@ static bool ipa3_usb_set_state(enum ipa3_usb_state new_state, bool err_permit,
if (state == IPA_USB_INITIALIZED ||
state == IPA_USB_STOPPED ||
state == IPA_USB_RESUME_IN_PROGRESS ||
+ state == IPA_USB_SUSPENDED_NO_RWAKEUP ||
/*
* In case of failure during suspend request
* handling, state is reverted to connected.
@@ -327,7 +341,8 @@ static bool ipa3_usb_set_state(enum ipa3_usb_state new_state, bool err_permit,
case IPA_USB_STOPPED:
if (state == IPA_USB_SUSPEND_IN_PROGRESS ||
state == IPA_USB_CONNECTED ||
- state == IPA_USB_SUSPENDED)
+ state == IPA_USB_SUSPENDED ||
+ state == IPA_USB_SUSPENDED_NO_RWAKEUP)
state_legal = true;
break;
case IPA_USB_SUSPEND_REQUESTED:
@@ -354,6 +369,10 @@ static bool ipa3_usb_set_state(enum ipa3_usb_state new_state, bool err_permit,
(err_permit && state == IPA_USB_RESUME_IN_PROGRESS))
state_legal = true;
break;
+ case IPA_USB_SUSPENDED_NO_RWAKEUP:
+ if (state == IPA_USB_CONNECTED)
+ state_legal = true;
+ break;
case IPA_USB_RESUME_IN_PROGRESS:
if (state == IPA_USB_SUSPEND_IN_PROGRESS ||
state == IPA_USB_SUSPENDED)
@@ -418,32 +437,33 @@ static bool ipa3_usb_check_legal_op(enum ipa3_usb_op op,
spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
state = ipa3_usb_ctx->ttype_ctx[ttype].state;
switch (op) {
- case IPA_USB_INIT_TETH_PROT:
+ case IPA_USB_OP_INIT_TETH_PROT:
if (state == IPA_USB_INVALID ||
(!is_dpl && state == IPA_USB_INITIALIZED))
is_legal = true;
break;
- case IPA_USB_REQUEST_CHANNEL:
+ case IPA_USB_OP_REQUEST_CHANNEL:
if (state == IPA_USB_INITIALIZED)
is_legal = true;
break;
- case IPA_USB_CONNECT:
+ case IPA_USB_OP_CONNECT:
if (state == IPA_USB_INITIALIZED || state == IPA_USB_STOPPED)
is_legal = true;
break;
- case IPA_USB_DISCONNECT:
+ case IPA_USB_OP_DISCONNECT:
if (state == IPA_USB_CONNECTED ||
state == IPA_USB_SUSPEND_IN_PROGRESS ||
- state == IPA_USB_SUSPENDED)
+ state == IPA_USB_SUSPENDED ||
+ state == IPA_USB_SUSPENDED_NO_RWAKEUP)
is_legal = true;
break;
- case IPA_USB_RELEASE_CHANNEL:
+ case IPA_USB_OP_RELEASE_CHANNEL:
/* when releasing 1st channel state will be changed already */
if (state == IPA_USB_STOPPED ||
(!is_dpl && state == IPA_USB_INITIALIZED))
is_legal = true;
break;
- case IPA_USB_DEINIT_TETH_PROT:
+ case IPA_USB_OP_DEINIT_TETH_PROT:
/*
* For data tethering we should allow deinit an inited protocol
* always. E.g. rmnet is inited and rndis is connected.
@@ -453,13 +473,18 @@ static bool ipa3_usb_check_legal_op(enum ipa3_usb_op op,
if (!is_dpl || state == IPA_USB_INITIALIZED)
is_legal = true;
break;
- case IPA_USB_SUSPEND:
+ case IPA_USB_OP_SUSPEND:
if (state == IPA_USB_CONNECTED)
is_legal = true;
break;
- case IPA_USB_RESUME:
+ case IPA_USB_OP_SUSPEND_NO_RWAKEUP:
+ if (state == IPA_USB_CONNECTED)
+ is_legal = true;
+ break;
+ case IPA_USB_OP_RESUME:
if (state == IPA_USB_SUSPENDED ||
- state == IPA_USB_SUSPEND_IN_PROGRESS)
+ state == IPA_USB_SUSPEND_IN_PROGRESS ||
+ state == IPA_USB_SUSPENDED_NO_RWAKEUP)
is_legal = true;
break;
default:
@@ -638,6 +663,7 @@ static int ipa3_usb_cons_request_resource_cb_do(
ipa3_usb_ctx->ttype_ctx[ttype].state));
switch (ipa3_usb_ctx->ttype_ctx[ttype].state) {
case IPA_USB_CONNECTED:
+ case IPA_USB_SUSPENDED_NO_RWAKEUP:
rm_ctx->cons_state = IPA_USB_CONS_GRANTED;
result = 0;
break;
@@ -717,6 +743,7 @@ static int ipa3_usb_cons_release_resource_cb_do(
break;
case IPA_USB_STOPPED:
case IPA_USB_RESUME_IN_PROGRESS:
+ case IPA_USB_SUSPENDED_NO_RWAKEUP:
if (rm_ctx->cons_requested)
rm_ctx->cons_requested = false;
break;
@@ -886,7 +913,7 @@ int ipa_usb_init_teth_prot(enum ipa_usb_teth_prot teth_prot,
ttype = IPA3_USB_GET_TTYPE(teth_prot);
- if (!ipa3_usb_check_legal_op(IPA_USB_INIT_TETH_PROT, ttype)) {
+ if (!ipa3_usb_check_legal_op(IPA_USB_OP_INIT_TETH_PROT, ttype)) {
IPA_USB_ERR("Illegal operation.\n");
result = -EPERM;
goto bad_params;
@@ -1204,7 +1231,7 @@ static int ipa3_usb_request_xdci_channel(
ttype = IPA3_USB_GET_TTYPE(params->teth_prot);
- if (!ipa3_usb_check_legal_op(IPA_USB_REQUEST_CHANNEL, ttype)) {
+ if (!ipa3_usb_check_legal_op(IPA_USB_OP_REQUEST_CHANNEL, ttype)) {
IPA_USB_ERR("Illegal operation\n");
return -EPERM;
}
@@ -1347,7 +1374,7 @@ static int ipa3_usb_release_xdci_channel(u32 clnt_hdl,
return -EINVAL;
}
- if (!ipa3_usb_check_legal_op(IPA_USB_RELEASE_CHANNEL, ttype)) {
+ if (!ipa3_usb_check_legal_op(IPA_USB_OP_RELEASE_CHANNEL, ttype)) {
IPA_USB_ERR("Illegal operation.\n");
return -EPERM;
}
@@ -1511,81 +1538,79 @@ static int ipa3_usb_connect_dpl(void)
return 0;
}
-static int ipa3_usb_connect_teth_prot(
- struct ipa_usb_xdci_connect_params_internal *params,
- enum ipa3_usb_transport_type ttype)
+static int ipa3_usb_connect_teth_prot(enum ipa_usb_teth_prot teth_prot)
{
int result;
struct teth_bridge_connect_params teth_bridge_params;
+ struct ipa3_usb_teth_prot_conn_params *teth_conn_params;
+ enum ipa3_usb_transport_type ttype;
- IPA_USB_DBG("connecting protocol = %d\n",
- params->teth_prot);
- switch (params->teth_prot) {
+ IPA_USB_DBG("connecting protocol = %s\n",
+ ipa3_usb_teth_prot_to_string(teth_prot));
+
+ ttype = IPA3_USB_GET_TTYPE(teth_prot);
+
+ teth_conn_params = &(ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params);
+
+ switch (teth_prot) {
case IPA_USB_RNDIS:
if (ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].state ==
IPA_USB_TETH_PROT_CONNECTED) {
IPA_USB_DBG("%s is already connected.\n",
- ipa3_usb_teth_prot_to_string(
- params->teth_prot));
+ ipa3_usb_teth_prot_to_string(teth_prot));
break;
}
ipa3_usb_ctx->ttype_ctx[ttype].user_data =
ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].user_data;
result = rndis_ipa_pipe_connect_notify(
- params->usb_to_ipa_clnt_hdl,
- params->ipa_to_usb_clnt_hdl,
- params->teth_prot_params.max_xfer_size_bytes_to_dev,
- params->teth_prot_params.max_packet_number_to_dev,
- params->teth_prot_params.max_xfer_size_bytes_to_host,
+ teth_conn_params->usb_to_ipa_clnt_hdl,
+ teth_conn_params->ipa_to_usb_clnt_hdl,
+ teth_conn_params->params.max_xfer_size_bytes_to_dev,
+ teth_conn_params->params.max_packet_number_to_dev,
+ teth_conn_params->params.max_xfer_size_bytes_to_host,
ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].
teth_prot_params.rndis.private);
if (result) {
IPA_USB_ERR("failed to connect %s.\n",
- ipa3_usb_teth_prot_to_string(
- params->teth_prot));
+ ipa3_usb_teth_prot_to_string(teth_prot));
ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL;
return result;
}
ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].state =
IPA_USB_TETH_PROT_CONNECTED;
IPA_USB_DBG("%s is connected.\n",
- ipa3_usb_teth_prot_to_string(
- params->teth_prot));
+ ipa3_usb_teth_prot_to_string(teth_prot));
break;
case IPA_USB_ECM:
if (ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].state ==
IPA_USB_TETH_PROT_CONNECTED) {
IPA_USB_DBG("%s is already connected.\n",
- ipa3_usb_teth_prot_to_string(
- params->teth_prot));
+ ipa3_usb_teth_prot_to_string(teth_prot));
break;
}
ipa3_usb_ctx->ttype_ctx[ttype].user_data =
ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].user_data;
- result = ecm_ipa_connect(params->usb_to_ipa_clnt_hdl,
- params->ipa_to_usb_clnt_hdl,
+ result = ecm_ipa_connect(teth_conn_params->usb_to_ipa_clnt_hdl,
+ teth_conn_params->ipa_to_usb_clnt_hdl,
ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].
teth_prot_params.ecm.private);
if (result) {
IPA_USB_ERR("failed to connect %s.\n",
- ipa3_usb_teth_prot_to_string(
- params->teth_prot));
+ ipa3_usb_teth_prot_to_string(teth_prot));
ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL;
return result;
}
ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].state =
IPA_USB_TETH_PROT_CONNECTED;
IPA_USB_DBG("%s is connected.\n",
- ipa3_usb_teth_prot_to_string(
- params->teth_prot));
+ ipa3_usb_teth_prot_to_string(teth_prot));
break;
case IPA_USB_RMNET:
case IPA_USB_MBIM:
- if (ipa3_usb_ctx->teth_prot_ctx[params->teth_prot].state ==
+ if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state ==
IPA_USB_TETH_PROT_CONNECTED) {
IPA_USB_DBG("%s is already connected.\n",
- ipa3_usb_teth_prot_to_string(
- params->teth_prot));
+ ipa3_usb_teth_prot_to_string(teth_prot));
break;
}
result = ipa3_usb_init_teth_bridge();
@@ -1593,14 +1618,14 @@ static int ipa3_usb_connect_teth_prot(
return result;
ipa3_usb_ctx->ttype_ctx[ttype].user_data =
- ipa3_usb_ctx->teth_prot_ctx[params->teth_prot].
+ ipa3_usb_ctx->teth_prot_ctx[teth_prot].
user_data;
teth_bridge_params.ipa_usb_pipe_hdl =
- params->ipa_to_usb_clnt_hdl;
+ teth_conn_params->ipa_to_usb_clnt_hdl;
teth_bridge_params.usb_ipa_pipe_hdl =
- params->usb_to_ipa_clnt_hdl;
+ teth_conn_params->usb_to_ipa_clnt_hdl;
teth_bridge_params.tethering_mode =
- (params->teth_prot == IPA_USB_RMNET) ?
+ (teth_prot == IPA_USB_RMNET) ?
(TETH_TETHERING_MODE_RMNET):(TETH_TETHERING_MODE_MBIM);
teth_bridge_params.client_type = IPA_CLIENT_USB_PROD;
result = ipa3_usb_connect_teth_bridge(&teth_bridge_params);
@@ -1608,27 +1633,23 @@ static int ipa3_usb_connect_teth_prot(
ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL;
return result;
}
- ipa3_usb_ctx->teth_prot_ctx[params->teth_prot].state =
+ ipa3_usb_ctx->teth_prot_ctx[teth_prot].state =
IPA_USB_TETH_PROT_CONNECTED;
ipa3_usb_notify_do(ttype, IPA_USB_DEVICE_READY);
IPA_USB_DBG("%s (%s) is connected.\n",
- ipa3_usb_teth_prot_to_string(
- params->teth_prot),
- ipa3_usb_teth_bridge_prot_to_string(
- params->teth_prot));
+ ipa3_usb_teth_prot_to_string(teth_prot),
+ ipa3_usb_teth_bridge_prot_to_string(teth_prot));
break;
case IPA_USB_DIAG:
if (ipa3_usb_ctx->teth_prot_ctx[IPA_USB_DIAG].state ==
IPA_USB_TETH_PROT_CONNECTED) {
IPA_USB_DBG("%s is already connected.\n",
- ipa3_usb_teth_prot_to_string(
- params->teth_prot));
+ ipa3_usb_teth_prot_to_string(teth_prot));
break;
}
ipa3_usb_ctx->ttype_ctx[ttype].user_data =
- ipa3_usb_ctx->teth_prot_ctx[params->teth_prot].
- user_data;
+ ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data;
result = ipa3_usb_connect_dpl();
if (result) {
IPA_USB_ERR("Failed connecting DPL result=%d\n",
@@ -1640,8 +1661,7 @@ static int ipa3_usb_connect_teth_prot(
IPA_USB_TETH_PROT_CONNECTED;
ipa3_usb_notify_do(ttype, IPA_USB_DEVICE_READY);
IPA_USB_DBG("%s is connected.\n",
- ipa3_usb_teth_prot_to_string(
- params->teth_prot));
+ ipa3_usb_teth_prot_to_string(teth_prot));
break;
default:
IPA_USB_ERR("Invalid tethering protocol\n");
@@ -1775,11 +1795,19 @@ static int ipa3_usb_xdci_connect_internal(
ttype = (params->teth_prot == IPA_USB_DIAG) ? IPA_USB_TRANSPORT_DPL :
IPA_USB_TRANSPORT_TETH;
- if (!ipa3_usb_check_legal_op(IPA_USB_CONNECT, ttype)) {
+ if (!ipa3_usb_check_legal_op(IPA_USB_OP_CONNECT, ttype)) {
IPA_USB_ERR("Illegal operation.\n");
return -EPERM;
}
+ ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params.ipa_to_usb_clnt_hdl
+ = params->ipa_to_usb_clnt_hdl;
+ if (!IPA3_USB_IS_TTYPE_DPL(ttype))
+ ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params.
+ usb_to_ipa_clnt_hdl = params->usb_to_ipa_clnt_hdl;
+ ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params.params
+ = params->teth_prot_params;
+
/* Set EE xDCI specific scratch */
result = ipa3_set_usb_max_packet_size(params->max_pkt_size);
if (result) {
@@ -1816,7 +1844,7 @@ static int ipa3_usb_xdci_connect_internal(
if (params->teth_prot != IPA_USB_DIAG) {
/* Start UL channel */
- result = ipa3_xdci_connect(params->usb_to_ipa_clnt_hdl,
+ result = ipa3_xdci_start(params->usb_to_ipa_clnt_hdl,
params->usb_to_ipa_xferrscidx,
params->usb_to_ipa_xferrscidx_valid);
if (result) {
@@ -1826,7 +1854,7 @@ static int ipa3_usb_xdci_connect_internal(
}
/* Start DL/DPL channel */
- result = ipa3_xdci_connect(params->ipa_to_usb_clnt_hdl,
+ result = ipa3_xdci_start(params->ipa_to_usb_clnt_hdl,
params->ipa_to_usb_xferrscidx,
params->ipa_to_usb_xferrscidx_valid);
if (result) {
@@ -1835,7 +1863,7 @@ static int ipa3_usb_xdci_connect_internal(
}
/* Connect tethering protocol */
- result = ipa3_usb_connect_teth_prot(params, ttype);
+ result = ipa3_usb_connect_teth_prot(params->teth_prot);
if (result) {
IPA_USB_ERR("failed to connect teth protocol\n");
goto connect_teth_prot_fail;
@@ -2164,6 +2192,70 @@ static int ipa3_usb_check_disconnect_prot(enum ipa_usb_teth_prot teth_prot)
return 0;
}
+/* Assumes lock already acquired */
+static int ipa_usb_xdci_dismiss_channels(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
+ enum ipa_usb_teth_prot teth_prot)
+{
+ int result = 0;
+ enum ipa3_usb_transport_type ttype;
+
+ ttype = IPA3_USB_GET_TTYPE(teth_prot);
+
+ IPA_USB_DBG_LOW("entry\n");
+
+ /* Reset DL channel */
+ result = ipa3_reset_gsi_channel(dl_clnt_hdl);
+ if (result) {
+ IPA_USB_ERR("failed to reset DL channel.\n");
+ return result;
+ }
+
+ /* Reset DL event ring */
+ result = ipa3_reset_gsi_event_ring(dl_clnt_hdl);
+ if (result) {
+ IPA_USB_ERR("failed to reset DL event ring.\n");
+ return result;
+ }
+
+ if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
+ /* Reset UL channel */
+ result = ipa3_reset_gsi_channel(ul_clnt_hdl);
+ if (result) {
+ IPA_USB_ERR("failed to reset UL channel.\n");
+ return result;
+ }
+
+ /* Reset UL event ring */
+ result = ipa3_reset_gsi_event_ring(ul_clnt_hdl);
+ if (result) {
+ IPA_USB_ERR("failed to reset UL event ring.\n");
+ return result;
+ }
+ }
+
+ /* Change state to STOPPED */
+ if (!ipa3_usb_set_state(IPA_USB_STOPPED, false, ttype))
+ IPA_USB_ERR("failed to change state to stopped\n");
+
+ if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
+ result = ipa3_usb_release_xdci_channel(ul_clnt_hdl, ttype);
+ if (result) {
+ IPA_USB_ERR("failed to release UL channel.\n");
+ return result;
+ }
+ }
+
+ result = ipa3_usb_release_xdci_channel(dl_clnt_hdl, ttype);
+ if (result) {
+ IPA_USB_ERR("failed to release DL channel.\n");
+ return result;
+ }
+
+ IPA_USB_DBG_LOW("exit\n");
+
+ return 0;
+}
+
int ipa_usb_xdci_disconnect(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
enum ipa_usb_teth_prot teth_prot)
{
@@ -2175,20 +2267,31 @@ int ipa_usb_xdci_disconnect(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
mutex_lock(&ipa3_usb_ctx->general_mutex);
IPA_USB_DBG_LOW("entry\n");
- if (ipa3_usb_check_disconnect_prot(teth_prot)) {
- result = -EINVAL;
- goto bad_params;
- }
ttype = IPA3_USB_GET_TTYPE(teth_prot);
- if (!ipa3_usb_check_legal_op(IPA_USB_DISCONNECT, ttype)) {
+ if (!ipa3_usb_check_legal_op(IPA_USB_OP_DISCONNECT, ttype)) {
IPA_USB_ERR("Illegal operation.\n");
result = -EPERM;
goto bad_params;
}
spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
+ if (ipa3_usb_ctx->ttype_ctx[ttype].state ==
+ IPA_USB_SUSPENDED_NO_RWAKEUP) {
+ spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
+ result = ipa_usb_xdci_dismiss_channels(ul_clnt_hdl, dl_clnt_hdl,
+ teth_prot);
+ mutex_unlock(&ipa3_usb_ctx->general_mutex);
+ return result;
+ }
+
+ if (ipa3_usb_check_disconnect_prot(teth_prot)) {
+ spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
+ result = -EINVAL;
+ goto bad_params;
+ }
+
if (ipa3_usb_ctx->ttype_ctx[ttype].state != IPA_USB_SUSPENDED) {
spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
/* Stop DL/DPL channel */
@@ -2227,53 +2330,10 @@ int ipa_usb_xdci_disconnect(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
} else
spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
- /* Reset DL channel */
- result = ipa3_reset_gsi_channel(dl_clnt_hdl);
- if (result) {
- IPA_USB_ERR("failed to reset DL channel.\n");
- goto bad_params;
- }
-
- /* Reset DL event ring */
- result = ipa3_reset_gsi_event_ring(dl_clnt_hdl);
- if (result) {
- IPA_USB_ERR("failed to reset DL event ring.\n");
- goto bad_params;
- }
-
- if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
- /* Reset UL channel */
- result = ipa3_reset_gsi_channel(ul_clnt_hdl);
- if (result) {
- IPA_USB_ERR("failed to reset UL channel.\n");
- goto bad_params;
- }
-
- /* Reset UL event ring */
- result = ipa3_reset_gsi_event_ring(ul_clnt_hdl);
- if (result) {
- IPA_USB_ERR("failed to reset UL event ring.\n");
- goto bad_params;
- }
- }
-
- /* Change state to STOPPED */
- if (!ipa3_usb_set_state(IPA_USB_STOPPED, false, ttype))
- IPA_USB_ERR("failed to change state to stopped\n");
-
- if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
- result = ipa3_usb_release_xdci_channel(ul_clnt_hdl, ttype);
- if (result) {
- IPA_USB_ERR("failed to release UL channel.\n");
- goto bad_params;
- }
- }
-
- result = ipa3_usb_release_xdci_channel(dl_clnt_hdl, ttype);
- if (result) {
- IPA_USB_ERR("failed to release DL channel.\n");
+ result = ipa_usb_xdci_dismiss_channels(ul_clnt_hdl, dl_clnt_hdl,
+ teth_prot);
+ if (result)
goto bad_params;
- }
/* Disconnect tethering protocol */
result = ipa3_usb_disconnect_teth_prot(teth_prot);
@@ -2315,7 +2375,7 @@ int ipa_usb_deinit_teth_prot(enum ipa_usb_teth_prot teth_prot)
ttype = IPA3_USB_GET_TTYPE(teth_prot);
- if (!ipa3_usb_check_legal_op(IPA_USB_DEINIT_TETH_PROT, ttype)) {
+ if (!ipa3_usb_check_legal_op(IPA_USB_OP_DEINIT_TETH_PROT, ttype)) {
IPA_USB_ERR("Illegal operation.\n");
result = -EPERM;
goto bad_params;
@@ -2411,25 +2471,104 @@ bad_params:
}
EXPORT_SYMBOL(ipa_usb_deinit_teth_prot);
-int ipa_usb_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
+/* Assumes lock already acquired */
+static int ipa3_usb_suspend_no_remote_wakeup(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
enum ipa_usb_teth_prot teth_prot)
{
int result = 0;
+ enum ipa3_usb_transport_type ttype;
+
+ ttype = IPA3_USB_GET_TTYPE(teth_prot);
+
+ if (!ipa3_usb_check_legal_op(IPA_USB_OP_SUSPEND_NO_RWAKEUP, ttype)) {
+ IPA_USB_ERR("Illegal operation.\n");
+ result = -EPERM;
+ goto fail_exit;
+ }
+
+ IPA_USB_DBG("Start suspend with no remote wakeup sequence: %s\n",
+ IPA3_USB_IS_TTYPE_DPL(ttype) ?
+ "DPL channel":"Data Tethering channels");
+
+ if (ipa3_usb_check_disconnect_prot(teth_prot)) {
+ result = -EINVAL;
+ goto fail_exit;
+ }
+
+ /* Stop DL/DPL channel */
+ result = ipa3_xdci_disconnect(dl_clnt_hdl, false, -1);
+ if (result) {
+ IPA_USB_ERR("failed to disconnect DL/DPL channel.\n");
+ goto fail_exit;
+ }
+
+ if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
+ /* Stop UL channel */
+ result = ipa3_xdci_disconnect(ul_clnt_hdl, true,
+ ipa3_usb_ctx->qmi_req_id);
+ if (result) {
+ IPA_USB_ERR("failed disconnect UL channel\n");
+ goto start_dl;
+ }
+ ipa3_usb_ctx->qmi_req_id++;
+ }
+
+ /* Disconnect tethering protocol */
+ result = ipa3_usb_disconnect_teth_prot(teth_prot);
+ if (result)
+ goto start_ul;
+
+ result = ipa3_usb_release_prod(ttype);
+ if (result) {
+ IPA_USB_ERR("failed to release PROD.\n");
+ goto connect_teth;
+ }
+
+ /* Change ipa_usb state to SUSPENDED_NO_RWAKEUP */
+ if (!ipa3_usb_set_state(IPA_USB_SUSPENDED_NO_RWAKEUP, false, ttype))
+ IPA_USB_ERR("failed to change state to suspend no rwakeup\n");
+
+ IPA_USB_DBG_LOW("exit\n");
+ return 0;
+
+connect_teth:
+ (void)ipa3_usb_connect_teth_prot(teth_prot);
+start_ul:
+ if (!IPA3_USB_IS_TTYPE_DPL(ttype))
+ (void)ipa3_xdci_connect(ul_clnt_hdl);
+start_dl:
+ (void)ipa3_xdci_connect(dl_clnt_hdl);
+fail_exit:
+ return result;
+}
+
+int ipa_usb_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
+ enum ipa_usb_teth_prot teth_prot, bool with_remote_wakeup)
+{
+ int result = 0;
unsigned long flags;
enum ipa3_usb_cons_state curr_cons_state;
enum ipa3_usb_transport_type ttype;
mutex_lock(&ipa3_usb_ctx->general_mutex);
IPA_USB_DBG_LOW("entry\n");
+
if (teth_prot > IPA_USB_MAX_TETH_PROT_SIZE) {
IPA_USB_ERR("bad parameters.\n");
result = -EINVAL;
goto bad_params;
}
+ if (!with_remote_wakeup) {
+ result = ipa3_usb_suspend_no_remote_wakeup(ul_clnt_hdl,
+ dl_clnt_hdl, teth_prot);
+ mutex_unlock(&ipa3_usb_ctx->general_mutex);
+ return result;
+ }
+
ttype = IPA3_USB_GET_TTYPE(teth_prot);
- if (!ipa3_usb_check_legal_op(IPA_USB_SUSPEND, ttype)) {
+ if (!ipa3_usb_check_legal_op(IPA_USB_OP_SUSPEND, ttype)) {
IPA_USB_ERR("Illegal operation.\n");
result = -EPERM;
goto bad_params;
@@ -2538,6 +2677,72 @@ bad_params:
}
EXPORT_SYMBOL(ipa_usb_xdci_suspend);
+/* Assumes lock already acquired */
+static int ipa3_usb_resume_no_remote_wakeup(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
+ enum ipa_usb_teth_prot teth_prot)
+{
+ int result = -EFAULT;
+ enum ipa3_usb_transport_type ttype;
+
+ ttype = IPA3_USB_GET_TTYPE(teth_prot);
+
+ IPA_USB_DBG("Start resume with no remote wakeup sequence: %s\n",
+ IPA3_USB_IS_TTYPE_DPL(ttype) ?
+ "DPL channel":"Data Tethering channels");
+
+ /* Request USB_PROD */
+ result = ipa3_usb_request_prod(ttype);
+ if (result)
+ goto fail_exit;
+
+ /* Connect tethering protocol */
+ result = ipa3_usb_connect_teth_prot(teth_prot);
+ if (result) {
+ IPA_USB_ERR("failed to connect teth protocol\n");
+ goto release_prod;
+ }
+
+ if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
+ /* Start UL channel */
+ result = ipa3_xdci_connect(ul_clnt_hdl);
+ if (result) {
+ IPA_USB_ERR("failed to start UL channel.\n");
+ goto disconn_teth;
+ }
+ }
+
+ /* Start DL/DPL channel */
+ result = ipa3_xdci_connect(dl_clnt_hdl);
+ if (result) {
+ IPA_USB_ERR("failed to start DL/DPL channel.\n");
+ goto stop_ul;
+ }
+
+ /* Change state to CONNECTED */
+ if (!ipa3_usb_set_state(IPA_USB_CONNECTED, false, ttype)) {
+ IPA_USB_ERR("failed to change state to connected\n");
+ result = -EFAULT;
+ goto stop_dl;
+ }
+
+ return 0;
+
+stop_dl:
+ (void)ipa3_xdci_disconnect(dl_clnt_hdl, false, -1);
+stop_ul:
+ if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
+ (void)ipa3_xdci_disconnect(ul_clnt_hdl, true,
+ ipa3_usb_ctx->qmi_req_id);
+ ipa3_usb_ctx->qmi_req_id++;
+ }
+disconn_teth:
+ (void)ipa3_usb_disconnect_teth_prot(teth_prot);
+release_prod:
+ (void)ipa3_usb_release_prod(ttype);
+fail_exit:
+ return result;
+}
+
int ipa_usb_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
enum ipa_usb_teth_prot teth_prot)
{
@@ -2557,19 +2762,25 @@ int ipa_usb_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
ttype = IPA3_USB_GET_TTYPE(teth_prot);
- if (!ipa3_usb_check_legal_op(IPA_USB_RESUME, ttype)) {
+ if (!ipa3_usb_check_legal_op(IPA_USB_OP_RESUME, ttype)) {
IPA_USB_ERR("Illegal operation.\n");
result = -EPERM;
goto bad_params;
}
- IPA_USB_DBG_LOW("Start resume sequence: %s\n",
- IPA3_USB_IS_TTYPE_DPL(ttype) ?
- "DPL channel" : "Data Tethering channels");
-
spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
prev_state = ipa3_usb_ctx->ttype_ctx[ttype].state;
spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
+ if (prev_state == IPA_USB_SUSPENDED_NO_RWAKEUP) {
+ result = ipa3_usb_resume_no_remote_wakeup(ul_clnt_hdl,
+ dl_clnt_hdl, teth_prot);
+ mutex_unlock(&ipa3_usb_ctx->general_mutex);
+ return result;
+ }
+
+ IPA_USB_DBG("Start resume sequence: %s\n",
+ IPA3_USB_IS_TTYPE_DPL(ttype) ?
+ "DPL channel" : "Data Tethering channels");
/* Change state to RESUME_IN_PROGRESS */
if (!ipa3_usb_set_state(IPA_USB_RESUME_IN_PROGRESS, false, ttype)) {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
index 8326c3fdd9d1..d176552a3533 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
@@ -61,7 +61,7 @@ int ipa3_enable_data_path(u32 clnt_hdl)
!ipa3_should_pipe_be_suspended(ep->client))) {
memset(&ep_cfg_ctrl, 0 , sizeof(ep_cfg_ctrl));
ep_cfg_ctrl.ipa_ep_suspend = false;
- ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl);
+ res = ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl);
}
/* Assign the resource group for pipe */
@@ -101,7 +101,7 @@ int ipa3_disable_data_path(u32 clnt_hdl)
if (IPA_CLIENT_IS_CONS(ep->client)) {
memset(&ep_cfg_ctrl, 0 , sizeof(struct ipa_ep_cfg_ctrl));
ep_cfg_ctrl.ipa_ep_suspend = true;
- ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl);
+ res = ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl);
}
udelay(IPA_PKT_FLUSH_TO_US);
@@ -1311,7 +1311,46 @@ int ipa3_set_usb_max_packet_size(
return 0;
}
-int ipa3_xdci_connect(u32 clnt_hdl, u8 xferrscidx, bool xferrscidx_valid)
+int ipa3_xdci_connect(u32 clnt_hdl)
+{
+ int result;
+ struct ipa3_ep_context *ep;
+
+ IPADBG("entry\n");
+
+ if (clnt_hdl >= ipa3_ctx->ipa_num_pipes ||
+ ipa3_ctx->ep[clnt_hdl].valid == 0) {
+ IPAERR("Bad parameter.\n");
+ return -EINVAL;
+ }
+
+ ep = &ipa3_ctx->ep[clnt_hdl];
+ IPA_ACTIVE_CLIENTS_INC_EP(ipa3_get_client_mapping(clnt_hdl));
+
+ result = ipa3_start_gsi_channel(clnt_hdl);
+ if (result) {
+ IPAERR("failed to start gsi channel clnt_hdl=%u\n", clnt_hdl);
+ goto exit;
+ }
+
+ result = ipa3_enable_data_path(clnt_hdl);
+ if (result) {
+ IPAERR("enable data path failed res=%d clnt_hdl=%d.\n", result,
+ clnt_hdl);
+ goto stop_ch;
+ }
+
+ IPADBG("exit\n");
+ goto exit;
+
+stop_ch:
+ (void)ipa3_stop_gsi_channel(clnt_hdl);
+exit:
+ IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl));
+ return result;
+}
+
+int ipa3_xdci_start(u32 clnt_hdl, u8 xferrscidx, bool xferrscidx_valid)
{
struct ipa3_ep_context *ep;
int result = -EFAULT;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 33be22f98b9d..96cd550d7ef6 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -1482,7 +1482,9 @@ int ipa3_reset_gsi_event_ring(u32 clnt_hdl);
int ipa3_set_usb_max_packet_size(
enum ipa_usb_max_usb_packet_size usb_max_packet_size);
-int ipa3_xdci_connect(u32 clnt_hdl, u8 xferrscidx, bool xferrscidx_valid);
+int ipa3_xdci_start(u32 clnt_hdl, u8 xferrscidx, bool xferrscidx_valid);
+
+int ipa3_xdci_connect(u32 clnt_hdl);
int ipa3_xdci_disconnect(u32 clnt_hdl, bool should_force_clear, u32 qmi_req_id);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index c0a6e8b00d71..4ea68ae1e95c 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -3522,7 +3522,7 @@ int ipa3_stop_gsi_channel(u32 clnt_hdl)
goto end_sequence;
IPADBG("Inject a DMA_TASK with 1B packet to IPA and retry\n");
- /* Send a 1B packet DMA_RASK to IPA and try again*/
+ /* Send a 1B packet DMA_TASK to IPA and try again */
res = ipa3_inject_dma_task_for_gsi();
if (res) {
IPAERR("Failed to inject DMA TASk for GSI\n");
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index 17c8a5b00843..7569e35b59e0 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -183,5 +183,19 @@ config POWER_RESET_ZX
help
Reboot support for ZTE SoCs.
+config REBOOT_MODE
+ tristate
+
+config SYSCON_REBOOT_MODE
+ tristate "Generic SYSCON regmap reboot mode driver"
+ depends on OF
+ select REBOOT_MODE
+ select MFD_SYSCON
+ help
+ Say y here will enable reboot mode driver. This will
+ get reboot mode arguments and store it in SYSCON mapped
+ register, then the bootloader can read it to take different
+ action according to the mode.
+
endif
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index 3904e7977d07..66568c4497a4 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -20,3 +20,5 @@ obj-$(CONFIG_POWER_RESET_SYSCON) += syscon-reboot.o
obj-$(CONFIG_POWER_RESET_SYSCON_POWEROFF) += syscon-poweroff.o
obj-$(CONFIG_POWER_RESET_RMOBILE) += rmobile-reset.o
obj-$(CONFIG_POWER_RESET_ZX) += zx-reboot.o
+obj-$(CONFIG_REBOOT_MODE) += reboot-mode.o
+obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o
diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c
new file mode 100644
index 000000000000..2dfbbce0f817
--- /dev/null
+++ b/drivers/power/reset/reboot-mode.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/reboot.h>
+#include "reboot-mode.h"
+
+#define PREFIX "mode-"
+
+struct mode_info {
+ const char *mode;
+ u32 magic;
+ struct list_head list;
+};
+
+static unsigned int get_reboot_mode_magic(struct reboot_mode_driver *reboot,
+ const char *cmd)
+{
+ const char *normal = "normal";
+ int magic = 0;
+ struct mode_info *info;
+
+ if (!cmd)
+ cmd = normal;
+
+ list_for_each_entry(info, &reboot->head, list) {
+ if (!strcmp(info->mode, cmd)) {
+ magic = info->magic;
+ break;
+ }
+ }
+
+ return magic;
+}
+
+static int reboot_mode_notify(struct notifier_block *this,
+ unsigned long mode, void *cmd)
+{
+ struct reboot_mode_driver *reboot;
+ unsigned int magic;
+
+ reboot = container_of(this, struct reboot_mode_driver, reboot_notifier);
+ magic = get_reboot_mode_magic(reboot, cmd);
+ if (magic)
+ reboot->write(reboot, magic);
+
+ return NOTIFY_DONE;
+}
+
+/**
+ * reboot_mode_register - register a reboot mode driver
+ * @reboot: reboot mode driver
+ *
+ * Returns: 0 on success or a negative error code on failure.
+ */
+int reboot_mode_register(struct reboot_mode_driver *reboot)
+{
+ struct mode_info *info;
+ struct property *prop;
+ struct device_node *np = reboot->dev->of_node;
+ size_t len = strlen(PREFIX);
+ int ret;
+
+ INIT_LIST_HEAD(&reboot->head);
+
+ for_each_property_of_node(np, prop) {
+ if (strncmp(prop->name, PREFIX, len))
+ continue;
+
+ info = devm_kzalloc(reboot->dev, sizeof(*info), GFP_KERNEL);
+ if (!info) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ if (of_property_read_u32(np, prop->name, &info->magic)) {
+ dev_err(reboot->dev, "reboot mode %s without magic number\n",
+ info->mode);
+ devm_kfree(reboot->dev, info);
+ continue;
+ }
+
+ info->mode = kstrdup_const(prop->name + len, GFP_KERNEL);
+ if (!info->mode) {
+ ret = -ENOMEM;
+ goto error;
+ } else if (info->mode[0] == '\0') {
+ kfree_const(info->mode);
+ ret = -EINVAL;
+ dev_err(reboot->dev, "invalid mode name(%s): too short!\n",
+ prop->name);
+ goto error;
+ }
+
+ list_add_tail(&info->list, &reboot->head);
+ }
+
+ reboot->reboot_notifier.notifier_call = reboot_mode_notify;
+ register_reboot_notifier(&reboot->reboot_notifier);
+
+ return 0;
+
+error:
+ list_for_each_entry(info, &reboot->head, list)
+ kfree_const(info->mode);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(reboot_mode_register);
+
+/**
+ * reboot_mode_unregister - unregister a reboot mode driver
+ * @reboot: reboot mode driver
+ */
+int reboot_mode_unregister(struct reboot_mode_driver *reboot)
+{
+ struct mode_info *info;
+
+ unregister_reboot_notifier(&reboot->reboot_notifier);
+
+ list_for_each_entry(info, &reboot->head, list)
+ kfree_const(info->mode);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(reboot_mode_unregister);
+
+MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com");
+MODULE_DESCRIPTION("System reboot mode core library");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/power/reset/reboot-mode.h b/drivers/power/reset/reboot-mode.h
new file mode 100644
index 000000000000..2491bb71f591
--- /dev/null
+++ b/drivers/power/reset/reboot-mode.h
@@ -0,0 +1,14 @@
+#ifndef __REBOOT_MODE_H__
+#define __REBOOT_MODE_H__
+
+struct reboot_mode_driver {
+ struct device *dev;
+ struct list_head head;
+ int (*write)(struct reboot_mode_driver *reboot, unsigned int magic);
+ struct notifier_block reboot_notifier;
+};
+
+int reboot_mode_register(struct reboot_mode_driver *reboot);
+int reboot_mode_unregister(struct reboot_mode_driver *reboot);
+
+#endif
diff --git a/drivers/power/reset/syscon-reboot-mode.c b/drivers/power/reset/syscon-reboot-mode.c
new file mode 100644
index 000000000000..9e1cba5dd58e
--- /dev/null
+++ b/drivers/power/reset/syscon-reboot-mode.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include "reboot-mode.h"
+
+struct syscon_reboot_mode {
+ struct regmap *map;
+ struct reboot_mode_driver reboot;
+ u32 offset;
+ u32 mask;
+};
+
+static int syscon_reboot_mode_write(struct reboot_mode_driver *reboot,
+ unsigned int magic)
+{
+ struct syscon_reboot_mode *syscon_rbm;
+ int ret;
+
+ syscon_rbm = container_of(reboot, struct syscon_reboot_mode, reboot);
+
+ ret = regmap_update_bits(syscon_rbm->map, syscon_rbm->offset,
+ syscon_rbm->mask, magic);
+ if (ret < 0)
+ dev_err(reboot->dev, "update reboot mode bits failed\n");
+
+ return ret;
+}
+
+static int syscon_reboot_mode_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct syscon_reboot_mode *syscon_rbm;
+
+ syscon_rbm = devm_kzalloc(&pdev->dev, sizeof(*syscon_rbm), GFP_KERNEL);
+ if (!syscon_rbm)
+ return -ENOMEM;
+
+ syscon_rbm->reboot.dev = &pdev->dev;
+ syscon_rbm->reboot.write = syscon_reboot_mode_write;
+ syscon_rbm->mask = 0xffffffff;
+
+ dev_set_drvdata(&pdev->dev, syscon_rbm);
+
+ syscon_rbm->map = syscon_node_to_regmap(pdev->dev.parent->of_node);
+ if (IS_ERR(syscon_rbm->map))
+ return PTR_ERR(syscon_rbm->map);
+
+ if (of_property_read_u32(pdev->dev.of_node, "offset",
+ &syscon_rbm->offset))
+ return -EINVAL;
+
+ of_property_read_u32(pdev->dev.of_node, "mask", &syscon_rbm->mask);
+
+ ret = reboot_mode_register(&syscon_rbm->reboot);
+ if (ret)
+ dev_err(&pdev->dev, "can't register reboot mode\n");
+
+ return ret;
+}
+
+static int syscon_reboot_mode_remove(struct platform_device *pdev)
+{
+ struct syscon_reboot_mode *syscon_rbm = dev_get_drvdata(&pdev->dev);
+
+ return reboot_mode_unregister(&syscon_rbm->reboot);
+}
+
+static const struct of_device_id syscon_reboot_mode_of_match[] = {
+ { .compatible = "syscon-reboot-mode" },
+ {}
+};
+
+static struct platform_driver syscon_reboot_mode_driver = {
+ .probe = syscon_reboot_mode_probe,
+ .remove = syscon_reboot_mode_remove,
+ .driver = {
+ .name = "syscon-reboot-mode",
+ .of_match_table = syscon_reboot_mode_of_match,
+ },
+};
+module_platform_driver(syscon_reboot_mode_driver);
+
+MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com");
+MODULE_DESCRIPTION("SYSCON reboot mode driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index f1d3c7e99a4c..feeed645fc47 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -131,6 +131,9 @@ module_param(qmi_timeout, ulong, 0600);
* Registers: WCSS_HM_A_PMM_PMM
* Base Address: 0x18880000
*/
+#define WCSS_HM_A_PMM_ROOT_CLK_ENABLE 0x80010
+#define PMM_TCXO_CLK_ENABLE BIT(13)
+
#define PMM_COMMON_IDLEREQ_CSR_OFFSET 0x80120
#define PMM_COMMON_IDLEREQ_CSR_SW_WNOC_IDLEREQ_SET BIT(16)
#define PMM_COMMON_IDLEREQ_CSR_WNOC_IDLEACK BIT(26)
@@ -1332,8 +1335,28 @@ static int icnss_hw_reset_rf_reset_cmd(struct icnss_priv *priv)
static int icnss_hw_reset_switch_to_cxo(struct icnss_priv *priv)
{
+ u32 rdata;
+
icnss_pr_dbg("RESET: Switch to CXO, state: 0x%lx\n", priv->state);
+ rdata = icnss_hw_read_reg(priv->mem_base_va,
+ WCSS_HM_A_PMM_ROOT_CLK_ENABLE);
+
+ icnss_pr_dbg("RESET: PMM_TCXO_CLK_ENABLE : 0x%05lx\n",
+ rdata & PMM_TCXO_CLK_ENABLE);
+
+ if ((rdata & PMM_TCXO_CLK_ENABLE) == 0) {
+ icnss_pr_dbg("RESET: Set PMM_TCXO_CLK_ENABLE to 1\n");
+
+ icnss_hw_write_reg_field(priv->mem_base_va,
+ WCSS_HM_A_PMM_ROOT_CLK_ENABLE,
+ PMM_TCXO_CLK_ENABLE, 1);
+ icnss_hw_poll_reg_field(priv->mem_base_va,
+ WCSS_HM_A_PMM_ROOT_CLK_ENABLE,
+ PMM_TCXO_CLK_ENABLE, 1, 10,
+ ICNSS_HW_REG_RETRY);
+ }
+
icnss_hw_write_reg_field(priv->mem_base_va,
WCSS_CLK_CTL_NOC_CFG_RCGR_OFFSET,
WCSS_CLK_CTL_NOC_CFG_RCGR_SRC_SEL, 0);
@@ -1464,6 +1487,26 @@ static int icnss_hw_reset(struct icnss_priv *priv)
icnss_hw_reset_switch_to_cxo(priv);
+ for (i = 0; i < ICNSS_HW_REG_RETRY; i++) {
+ rdata = icnss_hw_read_reg(priv->mem_base_va, SR_PMM_SR_MSB);
+ usleep_range(5, 10);
+ rdata1 = icnss_hw_read_reg(priv->mem_base_va, SR_PMM_SR_MSB);
+
+ icnss_pr_dbg("RESET: SR_PMM_SR_MSB: 0x%08x/0x%08x, XO: 0x%05lx/0x%05lx, AHB: 0x%05lx/0x%05lx\n",
+ rdata, rdata1,
+ rdata & SR_PMM_SR_MSB_XO_CLOCK_MASK,
+ rdata1 & SR_PMM_SR_MSB_XO_CLOCK_MASK,
+ rdata & SR_PMM_SR_MSB_AHB_CLOCK_MASK,
+ rdata1 & SR_PMM_SR_MSB_AHB_CLOCK_MASK);
+
+ if ((rdata & SR_PMM_SR_MSB_AHB_CLOCK_MASK) !=
+ (rdata1 & SR_PMM_SR_MSB_AHB_CLOCK_MASK) &&
+ (rdata & SR_PMM_SR_MSB_XO_CLOCK_MASK) !=
+ (rdata1 & SR_PMM_SR_MSB_XO_CLOCK_MASK))
+ break;
+ usleep_range(5, 10);
+ }
+
ret = icnss_hw_reset_xo_disable_cmd(priv);
if (ret)
goto top_level_reset;
@@ -2612,10 +2655,10 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv,
icnss_call_driver_remove(priv);
out:
- icnss_remove_msa_permissions(priv);
-
ret = icnss_hw_power_off(priv);
+ icnss_remove_msa_permissions(priv);
+
kfree(data);
return ret;
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index e5a88adfce59..add035269ae7 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -2073,6 +2073,11 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc)
clk_prepare_enable(mdwc->iface_clk);
clk_set_rate(mdwc->core_clk, mdwc->core_clk_rate);
clk_prepare_enable(mdwc->core_clk);
+
+ /* set Memory core: ON, Memory periphery: ON */
+ clk_set_flags(mdwc->core_clk, CLKFLAG_RETAIN_MEM);
+ clk_set_flags(mdwc->core_clk, CLKFLAG_RETAIN_PERIPH);
+
clk_prepare_enable(mdwc->utmi_clk);
if (mdwc->bus_aggr_clk)
clk_prepare_enable(mdwc->bus_aggr_clk);
diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c
index c298c95d4ba0..738f20d935d6 100644
--- a/drivers/usb/gadget/function/f_gsi.c
+++ b/drivers/usb/gadget/function/f_gsi.c
@@ -497,7 +497,8 @@ static int ipa_suspend_work_handler(struct gsi_data_port *d_port)
log_event_dbg("%s: Calling xdci_suspend", __func__);
ret = ipa_usb_xdci_suspend(gsi->d_port.out_channel_handle,
- gsi->d_port.in_channel_handle, gsi->prot_id);
+ gsi->d_port.in_channel_handle, gsi->prot_id,
+ true);
if (!ret) {
d_port->sm_state = STATE_SUSPENDED;
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 3e49861a09a2..5193bf5eb8c3 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -241,10 +241,14 @@ static int xhci_plat_probe(struct platform_device *pdev)
if (ret)
goto disable_usb_phy;
+ device_wakeup_enable(&hcd->self.root_hub->dev);
+
ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED | IRQF_ONESHOT);
if (ret)
goto dealloc_usb2_hcd;
+ device_wakeup_enable(&xhci->shared_hcd->self.root_hub->dev);
+
ret = device_create_file(&pdev->dev, &dev_attr_config_imod);
if (ret)
dev_err(&pdev->dev, "%s: unable to create imod sysfs entry\n",
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index 2bc70d1cf6fa..e193182af225 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -274,7 +274,7 @@ struct usbpd {
struct extcon_dev *extcon;
enum usbpd_state current_state;
- bool hard_reset;
+ bool hard_reset_recvd;
u8 rx_msg_type;
u8 rx_msg_len;
u32 rx_payload[7];
@@ -487,16 +487,12 @@ static int pd_eval_src_caps(struct usbpd *pd, const u32 *src_caps)
static void pd_send_hard_reset(struct usbpd *pd)
{
- int ret;
-
usbpd_dbg(&pd->dev, "send hard reset");
/* Force CC logic to source/sink to keep Rp/Rd unchanged */
set_power_role(pd, pd->current_pr);
pd->hard_reset_count++;
- ret = pd_phy_signal(HARD_RESET_SIG, 5); /* tHardResetComplete */
- if (!ret)
- pd->hard_reset = true;
+ pd_phy_signal(HARD_RESET_SIG, 5); /* tHardResetComplete */
pd->in_pr_swap = false;
}
@@ -522,7 +518,7 @@ static void phy_sig_received(struct usbpd *pd, enum pd_sig_type type)
/* Force CC logic to source/sink to keep Rp/Rd unchanged */
set_power_role(pd, pd->current_pr);
- pd->hard_reset = true;
+ pd->hard_reset_recvd = true;
kick_sm(pd, 0);
}
@@ -753,40 +749,6 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
kobject_uevent(&pd->dev.kobj, KOBJ_CHANGE);
break;
- case PE_SRC_TRANSITION_TO_DEFAULT:
- pd->hard_reset = false;
-
- if (pd->vconn_enabled)
- regulator_disable(pd->vconn);
- regulator_disable(pd->vbus);
-
- if (pd->current_dr != DR_DFP) {
- extcon_set_cable_state_(pd->extcon, EXTCON_USB, 0);
- pd->current_dr = DR_DFP;
- pd_phy_update_roles(pd->current_dr, pd->current_pr);
- }
-
- msleep(SRC_RECOVER_TIME);
-
- ret = regulator_enable(pd->vbus);
- if (ret)
- usbpd_err(&pd->dev, "Unable to enable vbus\n");
-
- if (pd->vconn_enabled) {
- ret = regulator_enable(pd->vconn);
- if (ret) {
- usbpd_err(&pd->dev, "Unable to enable vconn\n");
- pd->vconn_enabled = false;
- }
- }
-
- val.intval = 0;
- power_supply_set_property(pd->usb_psy,
- POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val);
-
- usbpd_set_state(pd, PE_SRC_STARTUP);
- break;
-
case PE_SRC_HARD_RESET:
case PE_SNK_HARD_RESET:
/* hard reset may sleep; handle it in the workqueue */
@@ -1403,7 +1365,7 @@ static void usbpd_sm(struct work_struct *w)
pd->in_pr_swap = false;
pd->pd_connected = false;
pd->in_explicit_contract = false;
- pd->hard_reset = false;
+ pd->hard_reset_recvd = false;
pd->caps_count = 0;
pd->hard_reset_count = 0;
pd->src_cap_id = 0;
@@ -1456,7 +1418,9 @@ static void usbpd_sm(struct work_struct *w)
}
/* Hard reset? */
- if (pd->hard_reset) {
+ if (pd->hard_reset_recvd) {
+ pd->hard_reset_recvd = false;
+
val.intval = 1;
power_supply_set_property(pd->usb_psy,
POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val);
@@ -1464,10 +1428,12 @@ static void usbpd_sm(struct work_struct *w)
pd->in_pr_swap = false;
reset_vdm_state(pd);
- if (pd->current_pr == PR_SINK)
+ if (pd->current_pr == PR_SINK) {
usbpd_set_state(pd, PE_SNK_TRANSITION_TO_DEFAULT);
- else
- usbpd_set_state(pd, PE_SRC_TRANSITION_TO_DEFAULT);
+ } else {
+ pd->current_state = PE_SRC_TRANSITION_TO_DEFAULT;
+ kick_sm(pd, PS_HARD_RESET_TIME);
+ }
goto sm_done;
}
@@ -1632,6 +1598,38 @@ static void usbpd_sm(struct work_struct *w)
}
break;
+ case PE_SRC_TRANSITION_TO_DEFAULT:
+ if (pd->vconn_enabled)
+ regulator_disable(pd->vconn);
+ regulator_disable(pd->vbus);
+
+ if (pd->current_dr != DR_DFP) {
+ extcon_set_cable_state_(pd->extcon, EXTCON_USB, 0);
+ pd->current_dr = DR_DFP;
+ pd_phy_update_roles(pd->current_dr, pd->current_pr);
+ }
+
+ msleep(SRC_RECOVER_TIME);
+
+ ret = regulator_enable(pd->vbus);
+ if (ret)
+ usbpd_err(&pd->dev, "Unable to enable vbus\n");
+
+ if (pd->vconn_enabled) {
+ ret = regulator_enable(pd->vconn);
+ if (ret) {
+ usbpd_err(&pd->dev, "Unable to enable vconn\n");
+ pd->vconn_enabled = false;
+ }
+ }
+
+ val.intval = 0;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val);
+
+ usbpd_set_state(pd, PE_SRC_STARTUP);
+ break;
+
case PE_SRC_HARD_RESET:
val.intval = 1;
power_supply_set_property(pd->usb_psy,
@@ -1641,9 +1639,8 @@ static void usbpd_sm(struct work_struct *w)
pd->in_explicit_contract = false;
reset_vdm_state(pd);
- usleep_range(PS_HARD_RESET_TIME * USEC_PER_MSEC,
- (PS_HARD_RESET_TIME + 5) * USEC_PER_MSEC);
- usbpd_set_state(pd, PE_SRC_TRANSITION_TO_DEFAULT);
+ pd->current_state = PE_SRC_TRANSITION_TO_DEFAULT;
+ kick_sm(pd, PS_HARD_RESET_TIME);
break;
case PE_SNK_STARTUP:
@@ -1829,8 +1826,6 @@ static void usbpd_sm(struct work_struct *w)
break;
case PE_SNK_TRANSITION_TO_DEFAULT:
- pd->hard_reset = false;
-
val.intval = 0;
power_supply_set_property(pd->usb_psy,
POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val);
@@ -2117,11 +2112,11 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr)
* During hard reset when VBUS goes to 0 the CC logic
* will report this as a disconnection. In those cases
* it can be ignored, however the downside is that
- * pd->hard_reset can be momentarily true even when a
- * non-PD capable source is attached, and can't be
- * distinguished from a physical disconnect. In that
- * case, allow for the common case of disconnecting
- * from an SDP.
+ * we can also happen to be in the SNK_Transition_to_default
+ * state due to a hard reset attempt even with a non-PD
+ * capable source, in which a physical disconnect may get
+ * masked. In that case, allow for the common case of
+ * disconnecting from an SDP.
*
* The less common case is a PD-capable SDP which will
* result in a hard reset getting treated like a
diff --git a/include/linux/bluetooth-power.h b/include/linux/bluetooth-power.h
index 7be94d298b88..a822ba8c07d1 100644
--- a/include/linux/bluetooth-power.h
+++ b/include/linux/bluetooth-power.h
@@ -85,4 +85,5 @@ struct bluetooth_power_platform_data {
int bt_register_slimdev(struct device *dev);
#define BT_CMD_SLIM_TEST 0xbfac
+#define BT_CMD_PWR_CTRL 0xbfad
#endif /* __LINUX_BLUETOOTH_POWER_H */
diff --git a/include/linux/clk/msm-clk.h b/include/linux/clk/msm-clk.h
index 22587e8852e2..964909d25021 100644
--- a/include/linux/clk/msm-clk.h
+++ b/include/linux/clk/msm-clk.h
@@ -14,6 +14,16 @@
#include <linux/notifier.h>
+#if defined(CONFIG_COMMON_CLK_QCOM)
+enum branch_mem_flags {
+ CLKFLAG_RETAIN_PERIPH,
+ CLKFLAG_NORETAIN_PERIPH,
+ CLKFLAG_RETAIN_MEM,
+ CLKFLAG_NORETAIN_MEM,
+ CLKFLAG_PERIPH_OFF_SET,
+ CLKFLAG_PERIPH_OFF_CLEAR,
+};
+#elif defined(CONFIG_COMMON_CLK_MSM)
#define CLKFLAG_INVERT 0x00000001
#define CLKFLAG_NOINVERT 0x00000002
#define CLKFLAG_NONEST 0x00000004
@@ -32,6 +42,7 @@
#define CLKFLAG_EPROBE_DEFER 0x00010000
#define CLKFLAG_PERIPH_OFF_SET 0x00020000
#define CLKFLAG_PERIPH_OFF_CLEAR 0x00040000
+#endif
struct clk_lookup;
struct clk;
diff --git a/include/linux/ipa_usb.h b/include/linux/ipa_usb.h
index 0fe0e36c551f..de1163348c05 100644
--- a/include/linux/ipa_usb.h
+++ b/include/linux/ipa_usb.h
@@ -253,6 +253,7 @@ int ipa_usb_deinit_teth_prot(enum ipa_usb_teth_prot teth_prot);
* @dl_clnt_hdl: client handle previously obtained from
* ipa_usb_xdci_connect() for IN channel
* @teth_prot: tethering protocol
+ * @with_remote_wakeup: Does host support remote wakeup?
*
* Note: Should not be called from atomic context
* Note: for DPL, the ul will be ignored as irrelevant
@@ -260,7 +261,8 @@ int ipa_usb_deinit_teth_prot(enum ipa_usb_teth_prot teth_prot);
* @Return 0 on success, negative on failure
*/
int ipa_usb_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
- enum ipa_usb_teth_prot teth_prot);
+ enum ipa_usb_teth_prot teth_prot,
+ bool with_remote_wakeup);
/**
* ipa_usb_xdci_resume - Peripheral should call this function to resume
@@ -313,7 +315,8 @@ static inline int ipa_usb_deinit_teth_prot(enum ipa_usb_teth_prot teth_prot)
}
static inline int ipa_usb_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
- enum ipa_usb_teth_prot teth_prot)
+ enum ipa_usb_teth_prot teth_prot,
+ bool with_remote_wakeup)
{
return -EPERM;
}
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 9076fd9f92b2..35c527c7d2e4 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -784,6 +784,26 @@ struct cfg80211_csa_settings {
};
/**
+ * struct iface_combination_params - input parameters for interface combinations
+ *
+ * Used to pass interface combination parameters
+ *
+ * @num_different_channels: the number of different channels we want
+ * to use for verification
+ * @radar_detect: a bitmap where each bit corresponds to a channel
+ * width where radar detection is needed, as in the definition of
+ * &struct ieee80211_iface_combination.@radar_detect_widths
+ * @iftype_num: array with the number of interfaces of each interface
+ * type. The index is the interface type as specified in &enum
+ * nl80211_iftype.
+ */
+struct iface_combination_params {
+ int num_different_channels;
+ u8 radar_detect;
+ int iftype_num[NUM_NL80211_IFTYPES];
+};
+
+/**
* enum station_parameters_apply_mask - station parameter values to apply
* @STATION_PARAM_APPLY_UAPSD: apply new uAPSD parameters (uapsd_queues, max_sp)
* @STATION_PARAM_APPLY_CAPABILITY: apply new capability
@@ -5333,36 +5353,20 @@ unsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy);
* cfg80211_check_combinations - check interface combinations
*
* @wiphy: the wiphy
- * @num_different_channels: the number of different channels we want
- * to use for verification
- * @radar_detect: a bitmap where each bit corresponds to a channel
- * width where radar detection is needed, as in the definition of
- * &struct ieee80211_iface_combination.@radar_detect_widths
- * @iftype_num: array with the numbers of interfaces of each interface
- * type. The index is the interface type as specified in &enum
- * nl80211_iftype.
- *
+ * @params: the interface combinations parameter
+*
* This function can be called by the driver to check whether a
* combination of interfaces and their types are allowed according to
* the interface combinations.
*/
int cfg80211_check_combinations(struct wiphy *wiphy,
- const int num_different_channels,
- const u8 radar_detect,
- const int iftype_num[NUM_NL80211_IFTYPES]);
+ struct iface_combination_params *params);
/**
* cfg80211_iter_combinations - iterate over matching combinations
*
* @wiphy: the wiphy
- * @num_different_channels: the number of different channels we want
- * to use for verification
- * @radar_detect: a bitmap where each bit corresponds to a channel
- * width where radar detection is needed, as in the definition of
- * &struct ieee80211_iface_combination.@radar_detect_widths
- * @iftype_num: array with the numbers of interfaces of each interface
- * type. The index is the interface type as specified in &enum
- * nl80211_iftype.
+ * @params: the interface combinations parameter
* @iter: function to call for each matching combination
* @data: pointer to pass to iter function
*
@@ -5371,9 +5375,7 @@ int cfg80211_check_combinations(struct wiphy *wiphy,
* purposes.
*/
int cfg80211_iter_combinations(struct wiphy *wiphy,
- const int num_different_channels,
- const u8 radar_detect,
- const int iftype_num[NUM_NL80211_IFTYPES],
+ struct iface_combination_params *params,
void (*iter)(const struct ieee80211_iface_combination *c,
void *data),
void *data);
diff --git a/kernel/sched/hmp.c b/kernel/sched/hmp.c
index 50a6d8e0d4d4..1d55e226196f 100644
--- a/kernel/sched/hmp.c
+++ b/kernel/sched/hmp.c
@@ -3106,9 +3106,9 @@ static void reset_all_task_stats(void)
read_lock(&tasklist_lock);
do_each_thread(g, p) {
- raw_spin_lock(&p->pi_lock);
+ raw_spin_lock_irq(&p->pi_lock);
reset_task_stats(p);
- raw_spin_unlock(&p->pi_lock);
+ raw_spin_unlock_irq(&p->pi_lock);
} while_each_thread(g, p);
read_unlock(&tasklist_lock);
}
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 33344f5a66a8..9ea2cc098ad1 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -3198,10 +3198,11 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
struct ieee80211_local *local = sdata->local;
struct ieee80211_sub_if_data *sdata_iter;
enum nl80211_iftype iftype = sdata->wdev.iftype;
- int num[NUM_NL80211_IFTYPES];
struct ieee80211_chanctx *ctx;
- int num_different_channels = 0;
int total = 1;
+ struct iface_combination_params params = {
+ .radar_detect = radar_detect,
+ };
lockdep_assert_held(&local->chanctx_mtx);
@@ -3212,9 +3213,6 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
!chandef->chan))
return -EINVAL;
- if (chandef)
- num_different_channels = 1;
-
if (WARN_ON(iftype >= NUM_NL80211_IFTYPES))
return -EINVAL;
@@ -3225,24 +3223,26 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
return 0;
}
- memset(num, 0, sizeof(num));
+ if (chandef)
+ params.num_different_channels = 1;
if (iftype != NL80211_IFTYPE_UNSPECIFIED)
- num[iftype] = 1;
+ params.iftype_num[iftype] = 1;
list_for_each_entry(ctx, &local->chanctx_list, list) {
if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
continue;
- radar_detect |= ieee80211_chanctx_radar_detect(local, ctx);
+ params.radar_detect |=
+ ieee80211_chanctx_radar_detect(local, ctx);
if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) {
- num_different_channels++;
+ params.num_different_channels++;
continue;
}
if (chandef && chanmode == IEEE80211_CHANCTX_SHARED &&
cfg80211_chandef_compatible(chandef,
&ctx->conf.def))
continue;
- num_different_channels++;
+ params.num_different_channels++;
}
list_for_each_entry_rcu(sdata_iter, &local->interfaces, list) {
@@ -3255,16 +3255,14 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
local->hw.wiphy->software_iftypes & BIT(wdev_iter->iftype))
continue;
- num[wdev_iter->iftype]++;
+ params.iftype_num[wdev_iter->iftype]++;
total++;
}
- if (total == 1 && !radar_detect)
+ if (total == 1 && !params.radar_detect)
return 0;
- return cfg80211_check_combinations(local->hw.wiphy,
- num_different_channels,
- radar_detect, num);
+ return cfg80211_check_combinations(local->hw.wiphy, &params);
}
static void
@@ -3280,12 +3278,10 @@ ieee80211_iter_max_chans(const struct ieee80211_iface_combination *c,
int ieee80211_max_num_channels(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;
- int num[NUM_NL80211_IFTYPES] = {};
struct ieee80211_chanctx *ctx;
- int num_different_channels = 0;
- u8 radar_detect = 0;
u32 max_num_different_channels = 1;
int err;
+ struct iface_combination_params params = {0};
lockdep_assert_held(&local->chanctx_mtx);
@@ -3293,17 +3289,17 @@ int ieee80211_max_num_channels(struct ieee80211_local *local)
if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
continue;
- num_different_channels++;
+ params.num_different_channels++;
- radar_detect |= ieee80211_chanctx_radar_detect(local, ctx);
+ params.radar_detect |=
+ ieee80211_chanctx_radar_detect(local, ctx);
}
list_for_each_entry_rcu(sdata, &local->interfaces, list)
- num[sdata->wdev.iftype]++;
+ params.iftype_num[sdata->wdev.iftype]++;
- err = cfg80211_iter_combinations(local->hw.wiphy,
- num_different_channels, radar_detect,
- num, ieee80211_iter_max_chans,
+ err = cfg80211_iter_combinations(local->hw.wiphy, &params,
+ ieee80211_iter_max_chans,
&max_num_different_channels);
if (err < 0)
return err;
diff --git a/net/wireless/util.c b/net/wireless/util.c
index a5b20d75017e..6822b4e57fad 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1504,9 +1504,7 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
}
int cfg80211_iter_combinations(struct wiphy *wiphy,
- const int num_different_channels,
- const u8 radar_detect,
- const int iftype_num[NUM_NL80211_IFTYPES],
+ struct iface_combination_params *params,
void (*iter)(const struct ieee80211_iface_combination *c,
void *data),
void *data)
@@ -1517,7 +1515,7 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
int num_interfaces = 0;
u32 used_iftypes = 0;
- if (radar_detect) {
+ if (params->radar_detect) {
rcu_read_lock();
regdom = rcu_dereference(cfg80211_regdomain);
if (regdom)
@@ -1526,8 +1524,8 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
}
for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
- num_interfaces += iftype_num[iftype];
- if (iftype_num[iftype] > 0 &&
+ num_interfaces += params->iftype_num[iftype];
+ if (params->iftype_num[iftype] > 0 &&
!(wiphy->software_iftypes & BIT(iftype)))
used_iftypes |= BIT(iftype);
}
@@ -1541,7 +1539,7 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
if (num_interfaces > c->max_interfaces)
continue;
- if (num_different_channels > c->num_different_channels)
+ if (params->num_different_channels > c->num_different_channels)
continue;
limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits,
@@ -1556,16 +1554,17 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
all_iftypes |= limits[j].types;
if (!(limits[j].types & BIT(iftype)))
continue;
- if (limits[j].max < iftype_num[iftype])
+ if (limits[j].max < params->iftype_num[iftype])
goto cont;
- limits[j].max -= iftype_num[iftype];
+ limits[j].max -= params->iftype_num[iftype];
}
}
- if (radar_detect != (c->radar_detect_widths & radar_detect))
+ if (params->radar_detect !=
+ (c->radar_detect_widths & params->radar_detect))
goto cont;
- if (radar_detect && c->radar_detect_regions &&
+ if (params->radar_detect && c->radar_detect_regions &&
!(c->radar_detect_regions & BIT(region)))
goto cont;
@@ -1599,14 +1598,11 @@ cfg80211_iter_sum_ifcombs(const struct ieee80211_iface_combination *c,
}
int cfg80211_check_combinations(struct wiphy *wiphy,
- const int num_different_channels,
- const u8 radar_detect,
- const int iftype_num[NUM_NL80211_IFTYPES])
+ struct iface_combination_params *params)
{
int err, num = 0;
- err = cfg80211_iter_combinations(wiphy, num_different_channels,
- radar_detect, iftype_num,
+ err = cfg80211_iter_combinations(wiphy, params,
cfg80211_iter_sum_ifcombs, &num);
if (err)
return err;
@@ -1625,14 +1621,15 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
u8 radar_detect)
{
struct wireless_dev *wdev_iter;
- int num[NUM_NL80211_IFTYPES];
struct ieee80211_channel
*used_channels[CFG80211_MAX_NUM_DIFFERENT_CHANNELS];
struct ieee80211_channel *ch;
enum cfg80211_chan_mode chmode;
- int num_different_channels = 0;
int total = 1;
int i;
+ struct iface_combination_params params = {
+ .radar_detect = radar_detect,
+ };
ASSERT_RTNL();
@@ -1649,10 +1646,9 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
return 0;
}
- memset(num, 0, sizeof(num));
memset(used_channels, 0, sizeof(used_channels));
- num[iftype] = 1;
+ params.iftype_num[iftype] = 1;
/* TODO: We'll probably not need this anymore, since this
* should only be called with CHAN_MODE_UNDEFINED. There are
@@ -1665,10 +1661,10 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
case CHAN_MODE_SHARED:
WARN_ON(!chan);
used_channels[0] = chan;
- num_different_channels++;
+ params.num_different_channels++;
break;
case CHAN_MODE_EXCLUSIVE:
- num_different_channels++;
+ params.num_different_channels++;
break;
}
@@ -1696,7 +1692,8 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
*/
mutex_lock_nested(&wdev_iter->mtx, 1);
__acquire(wdev_iter->mtx);
- cfg80211_get_chan_state(wdev_iter, &ch, &chmode, &radar_detect);
+ cfg80211_get_chan_state(wdev_iter, &ch, &chmode,
+ &params.radar_detect);
wdev_unlock(wdev_iter);
switch (chmode) {
@@ -1712,23 +1709,22 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
if (used_channels[i] == NULL) {
used_channels[i] = ch;
- num_different_channels++;
+ params.num_different_channels++;
}
break;
case CHAN_MODE_EXCLUSIVE:
- num_different_channels++;
+ params.num_different_channels++;
break;
}
- num[wdev_iter->iftype]++;
+ params.iftype_num[wdev_iter->iftype]++;
total++;
}
- if (total == 1 && !radar_detect)
+ if (total == 1 && !params.radar_detect)
return 0;
- return cfg80211_check_combinations(&rdev->wiphy, num_different_channels,
- radar_detect, num);
+ return cfg80211_check_combinations(&rdev->wiphy, &params);
}
int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c
index 0213d9ba4a59..d19b13c1f83a 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.c
+++ b/sound/soc/codecs/wcd934x/wcd934x.c
@@ -8039,6 +8039,7 @@ static const struct tavil_reg_mask_val tavil_codec_reg_defaults[] = {
{WCD934X_HPH_OCP_CTL, 0xFF, 0x3A}, /* OCP current limit */
{WCD934X_HPH_L_TEST, 0x01, 0x01},
{WCD934X_HPH_R_TEST, 0x01, 0x01},
+ {WCD934X_CPE_FLL_CONFIG_CTL_2, 0xFF, 0x20},
};
static const struct tavil_reg_mask_val tavil_codec_reg_init_1_1_val[] = {