summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/input/hbtp-input.txt38
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt8
-rw-r--r--Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt27
-rw-r--r--Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt1
-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--Documentation/devicetree/bindings/qbt1000/qbt1000.txt54
-rw-r--r--Documentation/devicetree/bindings/qdsp/msm-ssc-sensors.txt15
-rw-r--r--arch/arm/boot/dts/qcom/Makefile1
-rw-r--r--arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi110
-rw-r--r--arch/arm/boot/dts/qcom/msm-pm2falcon.dtsi5
-rw-r--r--arch/arm/boot/dts/qcom/msm-pmcobalt-rpm-regulator.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msm-pmi8994.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi9
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi21
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-mdss-panels.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-qrd-skuk.dtsi2
-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/msmcobalt-v2.dtsi82
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt.dtsi3
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-coresight.dtsi433
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-smp2p.dtsi23
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon.dtsi55
-rw-r--r--arch/arm/boot/dts/qcom/msmtriton-smp2p.dtsi23
-rw-r--r--arch/arm/boot/dts/qcom/msmtriton.dtsi53
-rw-r--r--arch/arm/configs/msmcortex_defconfig1
-rw-r--r--arch/arm/configs/msmfalcon_defconfig1
-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/bluetooth/bluetooth-power.c19
-rw-r--r--drivers/char/adsprpc.c2
-rw-r--r--drivers/clk/msm/clock-gcc-cobalt.c25
-rw-r--r--drivers/clk/qcom/clk-smd-rpm.c4
-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/input/misc/hbtp_input.c674
-rw-r--r--drivers/input/touchscreen/gt9xx/goodix_tool.c45
-rw-r--r--drivers/input/touchscreen/gt9xx/gt9xx.c587
-rw-r--r--drivers/input/touchscreen/gt9xx/gt9xx.h17
-rw-r--r--drivers/input/touchscreen/gt9xx/gt9xx_update.c10
-rw-r--r--drivers/leds/leds-qpnp-flash-v2.c11
-rw-r--r--drivers/leds/leds-qpnp-wled.c570
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_core.c168
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_core.h10
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c4
-rw-r--r--drivers/mfd/wcd934x-regmap.c4
-rw-r--r--drivers/misc/qseecom.c32
-rw-r--r--drivers/platform/msm/ipa/ipa_clients/ipa_usb.c499
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_flt.c36
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_i.h2
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_nat.c77
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_rt.c26
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c5
-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_nat.c76
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_utils.c2
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c8
-rw-r--r--drivers/platform/msm/qpnp-revid.c2
-rw-r--r--drivers/power/qcom-charger/qpnp-smb2.c7
-rw-r--r--drivers/power/qcom-charger/smb-lib.c121
-rw-r--r--drivers/power/qcom-charger/smb-reg.h1
-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/sensors/sensors_ssc.c13
-rw-r--r--drivers/soc/qcom/Kconfig9
-rw-r--r--drivers/soc/qcom/Makefile1
-rw-r--r--drivers/soc/qcom/icnss.c52
-rw-r--r--drivers/soc/qcom/pil-q6v5.c16
-rw-r--r--drivers/soc/qcom/pil-q6v5.h1
-rw-r--r--drivers/soc/qcom/qbt1000.c1263
-rw-r--r--drivers/usb/dwc3/dwc3-msm.c10
-rw-r--r--drivers/usb/dwc3/gadget.c4
-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--drivers/video/fbdev/msm/mdss_debug.c32
-rw-r--r--drivers/video/fbdev/msm/mdss_dp.c102
-rw-r--r--drivers/video/fbdev/msm/mdss_dp.h2
-rw-r--r--drivers/video/fbdev/msm/mdss_dp_aux.c16
-rw-r--r--drivers/video/fbdev/msm/mdss_dp_util.c106
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.c1
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.c9
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_edid.c86
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.c2
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.h10
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_ctl.c27
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_video.c48
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_layer.c221
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_overlay.c2
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp.c49
-rw-r--r--drivers/video/fbdev/msm/mdss_panel.c10
-rw-r--r--drivers/video/fbdev/msm/mdss_panel.h1
-rw-r--r--include/dt-bindings/clock/msm-clocks-cobalt.h2
-rw-r--r--include/dt-bindings/clock/msm-clocks-hwio-cobalt.h2
-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/linux/qpnp/qpnp-revid.h4
-rw-r--r--include/net/cfg80211.h25
-rw-r--r--include/uapi/linux/Kbuild1
-rw-r--r--include/uapi/linux/hbtp_input.h15
-rw-r--r--include/uapi/linux/qbt1000.h99
-rw-r--r--kernel/sched/fair.c2
-rw-r--r--kernel/sched/hmp.c6
-rw-r--r--kernel/sched/sched.h1
-rw-r--r--net/wireless/nl80211.c509
-rw-r--r--sound/soc/codecs/wcd-dsp-mgr.c4
-rw-r--r--sound/soc/codecs/wcd-mbhc-v2.c2
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x-dsd.c47
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x-dsd.h5
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c168
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x-mbhc.c35
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x-mbhc.h2
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x.c152
-rw-r--r--sound/soc/msm/msmcobalt.c203
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c454
-rw-r--r--sound/soc/msm/qdsp6v2/q6adm.c2
-rw-r--r--sound/soc/msm/qdsp6v2/q6asm.c5
131 files changed, 7102 insertions, 1487 deletions
diff --git a/Documentation/devicetree/bindings/input/hbtp-input.txt b/Documentation/devicetree/bindings/input/hbtp-input.txt
index f422d75e037e..ad28952c5e7e 100644
--- a/Documentation/devicetree/bindings/input/hbtp-input.txt
+++ b/Documentation/devicetree/bindings/input/hbtp-input.txt
@@ -20,6 +20,19 @@ Optional properties:
- qcom,dig-vtg-max : Digital supply maximum voltage in uV
- qcom,display-resolution : Display resolution - maxX, maxY
- qcom,use-scale : boolean, enables the scaling for touch coordinates
+ - pinctrl-names : defines pinctrl names
+ "pmx_ts_active" : Required pinctrl name.
+ This should specify active config of TS RST gpio
+ "pmx_ts_suspend" : Required pinctrl name
+ This should specify suspend config of TS RST gpio
+ "ddic_rst_active" : Required pinctrl name
+ This should specify active config of DDIC RST gpio
+ "ddic_rst_suspend" : Required pinctrl name
+ This should specify suspend config of DDIC RST gpio
+ - pinctrl-0 : pin control to be used for TS active config
+ - pinctrl-1 : pin control to be used for TS suspend config
+ - pinctrl-2 : pin control to be used for DDIC active config
+ - pinctrl-3 : pin control to be used for DDIC suspend config
Optional properties if qcom,use-scale DT property is defined:
- qcom,def-maxx : default X-resolution of the touch panel.
@@ -29,6 +42,20 @@ Optional properties if qcom,use-scale DT property is defined:
- qcom,des-maxy : desired Y-resolution of the touch panel.
(Above two properties should be defined in pairs only)
+Optional Properties if pinctrl names are defined:
+ - qcom,pmx-ts-on-seq-delay-us : unsigned integer type for
+ delay after active TS RST gpio is changed
+ - qcom,fb-resume-delay-us : unsigned integer type for
+ delay in early resume framebuffer callback
+ - qcom,ddic-rst-on-seq-delay-us : array of unsigned integer type for
+ delay of each step in series of DDIC RST gpio control
+
+Optional Properties if qcom,afe-vtg and qcom,dig-vtg are defined
+ - qcom,afe-power-on-delay-us : unsigned integer type for
+ delay between turning on analog and digital power supply
+ - qcom,afe-power-off-delay-us : unsigned integer type for
+ delay between turning off digital and analog power supply
+
Example:
&soc {
hbtp {
@@ -47,5 +74,16 @@ Example:
qcom,default-max-y = <1920>;
qcom,desired-max-x = <720>;
qcom,desired-max-y = <1280>;
+ pinctrl-names = "pmx_ts_active","pmx_ts_suspend",
+ "ddic_rst_active", "ddic_rst_suspend";
+ pinctrl-0 = <&ts_rst_active>;
+ pinctrl-1 = <&ts_rst_suspend>;
+ pinctrl-2 = <&ddic_rst_active>;
+ pinctrl-3 = <&ddic_rst_suspend>;
+ qcom,pmx-ts-on-seq-delay-us = <1000>;
+ qcom,ddic-rst-on-seq-delay-us = <10000 10000 10000 10000>;
+ qcom,fb-resume-delay-us = <90000>;
+ qcom,afe-power-on-delay-us = <1000>;
+ qcom,afe-power-off-delay-us = <6>;
};
};
diff --git a/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
index ff8fb76166a3..bde115155eba 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
@@ -57,6 +57,12 @@ Optional properties:
- goodix,cfg-data5 : Touch screen controller config data group 5. Ask vendor
to provide that.
- goodix,fw-name : Touch screen controller firmware file name.
+ - goodix,slide-wakeup : To specify slide-wakeup property is enabled or not.
+ - goodix,dbl-clk-wakeup : To specify dbl-clk-wakeup property is enabled or not.
+ - goodix,change-x2y : To specify change-x2y property is enabled or not.
+ - goodix,driver-send-cfg : To specify driver-send-cfg property is enabled or not.
+ - goodix,have-touch-key : To specify have-touch-key property is enabled or not.
+ - goodix,with-pen : To specify with-pen property is enabled or not.
Example:
i2c@f9927000 {
goodix@5d {
@@ -92,5 +98,7 @@ i2c@f9927000 {
FF FF FF FF FF FF FF 22 22 22
22 22 22 FF 07 01];
goodix,fw_name = "gtp_fw.bin";
+ goodix,have-touch-key;
+ goodix,driver-send-cfg;
};
};
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt
index 8389fe57898a..ebbcfe5b2fd0 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt
@@ -12,6 +12,8 @@ Required properties:
- reg-names : names associated with base addresses. It
should be "qpnp-wled-ctrl-base", "qpnp-wled-sink-base",
"qpnp-wled-ibb-base", "qpnp-wled-lab-base".
+- qcom,pmic-revid : phandle of PMIC revid module. This is used to
+ identify the PMIC subtype.
Optional properties for WLED:
- interrupts : Specifies the interrupts associated with WLED. The available
@@ -25,8 +27,21 @@ Optional properties for WLED:
are "wled1", "wled2", "wled3", "wled4" and "auto". default is "auto".
- qcom,vref-mv : maximum reference voltage in mv. default is 350.
- qcom,switch-freq-khz : switch frequency in khz. default is 800.
-- qcom,ovp-mv : over voltage protection value in mv. default is 17800.
-- qcom,ilim-ma : maximum current limiter in ma. default is 980.
+- qcom,ovp-mv : Over voltage protection threshold in mV. Default is
+ 29500. Supported values are:
+ - 31000, 29500, 19400, 17800 for pmi8994/8952/8996.
+ - 31100, 29600, 19600, 18100 for pmicobalt/pm2falcon.
+ Should only be used if qcom,disp-type-amoled is not
+ specified.
+- 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",
@@ -54,7 +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-trim-steps-from-center : The number of steps to trim the OVP threshold voltage. The possible values can be between -7 to 8.
+- 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/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index a3dc40936e8e..54a3c5689b9c 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -79,6 +79,7 @@ Optional properties:
current issue.
- qcom,qdsp6v61-1-1: Boolean- Present if the qdsp version is v61 1.1
- qcom,qdsp6v62-1-2: Boolean- Present if the qdsp version is v62 1.2
+- qcom,qdsp6v62-1-5: Boolean- Present if the qdsp version is v62 1.5
- qcom,mx-spike-wa: Boolean- Present if we need to assert QDSP6 I/O clamp, memory
wordline clamp, and compiler memory clamp during MSS restart.
- qcom,qdsp6v56-1-10: Boolean- Present if the qdsp version is v56 1.10
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/Documentation/devicetree/bindings/qbt1000/qbt1000.txt b/Documentation/devicetree/bindings/qbt1000/qbt1000.txt
new file mode 100644
index 000000000000..c9861e4948f9
--- /dev/null
+++ b/Documentation/devicetree/bindings/qbt1000/qbt1000.txt
@@ -0,0 +1,54 @@
+Qualcomm Technologies, Inc. QBT1000 Specific Bindings
+
+QBT is a fingerprint sensor ASIC capable of performing fingerprint image scans
+and detecting finger presence on the sensor using programmable firmware.
+
+=======================
+Required Node Structure
+=======================
+
+- compatible
+ Usage: required
+ Value type: <string>
+ Definition: "qcom,qbt1000".
+
+- clock-names
+ Usage: required
+ Value type: <stringlist>
+ Definition: List of clock names that need to be voted on/off.
+
+- clocks
+ Usage: required
+ Value type: <prop_encoded-array>
+ Definition: Property pair that represents the clock controller and the clock
+ id. This in combination with the clock-name is used to obtain
+ the handle for the clock that needs to be voted on/off.
+
+- clock-frequency
+ Usage: required
+ Value type: <u32>
+ Definition: Frequency of clock in Hz.
+
+- qcom,ipc-gpio
+ Usage: required
+ Value type: <phandle>
+ Definition: phandle for GPIO to be used for IPC.
+
+- qcom,finger-detect-gpio
+ Usage: required
+ Value type: <phandle>
+ Definition: phandle for GPIO to be used for finger detect.
+
+=======
+Example
+=======
+
+qcom,qbt1000 {
+ compatible = "qcom,qbt1000";
+ clock-names = "core", "iface";
+ clocks = <&clock_gcc clk_gcc_blsp2_qup6_spi_apps_clk>,
+ <&clock_gcc clk_gcc_blsp2_ahb_clk>;
+ clock-frequency = <15000000>;
+ qcom,ipc-gpio = <&tlmm 121 0>;
+ qcom,finger-detect-gpio = <&pmcobalt_gpios 2 0>;
+};
diff --git a/Documentation/devicetree/bindings/qdsp/msm-ssc-sensors.txt b/Documentation/devicetree/bindings/qdsp/msm-ssc-sensors.txt
index 165153dde994..ea671a1ff14a 100644
--- a/Documentation/devicetree/bindings/qdsp/msm-ssc-sensors.txt
+++ b/Documentation/devicetree/bindings/qdsp/msm-ssc-sensors.txt
@@ -1,11 +1,16 @@
-* msm-ssc-sensors
+Qualcomm Technologies, Inc. SSC Driver
+
+msm-ssc-sensors driver implements the mechanism that allows to load SLPI firmware images.
Required properties:
- - compatible: "qcom,msm-ssc-sensors"
+ - compatible: This must be "qcom,msm-ssc-sensors"
+ - qcom,firmware-name: SLPI firmware name, must be "slpi_v1" or "slpi_v2"
Example:
+ The following for msmcobalt version 1.
- qcom,msm-ssc-sensors {
- compatible = "qcom,msm-ssc-sensors";
- };
+ qcom,msm-ssc-sensors {
+ compatible = "qcom,msm-ssc-sensors";
+ qcom,firmware-name = "slpi_v1";
+ };
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-audio-lpass.dtsi b/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi
index ba27e3912ee6..eb8a7a98b6b4 100644
--- a/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi
@@ -371,13 +371,84 @@
qcom,adsp-state = <0>;
};
+ qcom,msm-dai-tdm-pri-rx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37120>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36864>;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36864>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ qcom,msm-dai-tdm-pri-tx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37121>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36865>;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36865>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ qcom,msm-dai-tdm-sec-rx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37136>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36880>;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ dai_sec_tdm_rx_0: qcom,msm-dai-q6-tdm-sec-rx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36880>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ qcom,msm-dai-tdm-sec-tx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37137>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36881>;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ dai_sec_tdm_tx_0: qcom,msm-dai-q6-tdm-sec-tx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36881>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
qcom,msm-dai-tdm-tert-rx {
compatible = "qcom,msm-dai-tdm";
qcom,msm-cpudai-tdm-group-id = <37152>;
qcom,msm-cpudai-tdm-group-num-ports = <1>;
qcom,msm-cpudai-tdm-group-port-id = <36896>;
qcom,msm-cpudai-tdm-clk-rate = <1536000>;
- pinctrl-names = "default", "sleep";
dai_tert_tdm_rx_0: qcom,msm-dai-q6-tdm-tert-rx-0 {
compatible = "qcom,msm-dai-q6-tdm";
qcom,msm-cpudai-tdm-dev-id = <36896>;
@@ -396,7 +467,6 @@
qcom,msm-cpudai-tdm-group-num-ports = <1>;
qcom,msm-cpudai-tdm-group-port-id = <36897 >;
qcom,msm-cpudai-tdm-clk-rate = <1536000>;
- pinctrl-names = "default", "sleep";
dai_tert_tdm_tx_0: qcom,msm-dai-q6-tdm-tert-tx-0 {
compatible = "qcom,msm-dai-q6-tdm";
qcom,msm-cpudai-tdm-dev-id = <36897 >;
@@ -408,4 +478,40 @@
qcom,msm-cpudai-tdm-data-align = <0>;
};
};
+
+ qcom,msm-dai-tdm-quat-rx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37168>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36912>;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ dai_quat_tdm_rx_0: qcom,msm-dai-q6-tdm-quat-rx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36912>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ qcom,msm-dai-tdm-quat-tx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37169>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36913 >;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ dai_quat_tdm_tx_0: qcom,msm-dai-q6-tdm-quat-tx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36913 >;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
};
diff --git a/arch/arm/boot/dts/qcom/msm-pm2falcon.dtsi b/arch/arm/boot/dts/qcom/msm-pm2falcon.dtsi
index 399892f52b6f..41589d02f6fc 100644
--- a/arch/arm/boot/dts/qcom/msm-pm2falcon.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pm2falcon.dtsi
@@ -236,8 +236,8 @@
qcom,fdbk-output = "auto";
qcom,vref-mv = <350>;
qcom,switch-freq-khz = <800>;
- qcom,ovp-mv = <29500>;
- qcom,ilim-ma = <980>;
+ qcom,ovp-mv = <29600>;
+ qcom,ilim-ma = <970>;
qcom,boost-duty-ns = <26>;
qcom,mod-freq-khz = <9600>;
qcom,dim-mode = "hybrid";
@@ -248,6 +248,7 @@
qcom,en-phase-stag;
qcom,led-strings-list = [00 01 02];
qcom,en-ext-pfet-sc-pro;
+ qcom,pmic-revid = <&pm2falcon_revid>;
status = "ok";
};
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-pmi8994.dtsi b/arch/arm/boot/dts/qcom/msm-pmi8994.dtsi
index 96dfed8464e9..bba70329c819 100644
--- a/arch/arm/boot/dts/qcom/msm-pmi8994.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pmi8994.dtsi
@@ -537,6 +537,7 @@
qcom,en-phase-stag;
qcom,led-strings-list = [00 01 02 03];
qcom,en-ext-pfet-sc-pro;
+ qcom,pmic-revid = <&pmi8994_revid>;
};
pmi8994_haptics: qcom,haptic@c000 {
diff --git a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi
index 28d230dfb6bf..a5243aff4282 100644
--- a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi
@@ -596,8 +596,8 @@
qcom,fdbk-output = "auto";
qcom,vref-mv = <350>;
qcom,switch-freq-khz = <800>;
- qcom,ovp-mv = <29500>;
- qcom,ilim-ma = <980>;
+ qcom,ovp-mv = <29600>;
+ qcom,ilim-ma = <970>;
qcom,boost-duty-ns = <26>;
qcom,mod-freq-khz = <9600>;
qcom,dim-mode = "hybrid";
@@ -608,6 +608,7 @@
qcom,en-phase-stag;
qcom,led-strings-list = [00 01 02 03];
qcom,en-ext-pfet-sc-pro;
+ qcom,pmic-revid = <&pmicobalt_revid>;
};
pmicobalt_haptics: qcom,haptic@c000 {
@@ -740,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>;
};
};
@@ -751,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-audio.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi
index 3681f3d34b0c..ca12a520c2aa 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi
@@ -108,7 +108,10 @@
<&incall_music_2_rx>, <&sb_5_rx>, <&sb_6_rx>,
<&sb_7_rx>, <&sb_7_tx>, <&sb_8_tx>,
<&usb_audio_rx>, <&usb_audio_tx>,
- <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>;
+ <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>,
+ <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>,
+ <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>,
+ <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>;
asoc-cpu-names = "msm-dai-q6-hdmi.8", "msm-dai-q6-dp.24608",
"msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
"msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
@@ -127,7 +130,10 @@
"msm-dai-q6-dev.16396", "msm-dai-q6-dev.16398",
"msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401",
"msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673",
- "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897";
+ "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865",
+ "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881",
+ "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897",
+ "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913";
asoc-codec = <&stub_codec>, <&ext_disp_audio_codec>;
asoc-codec-names = "msm-stub-codec.1",
"msm-ext-disp-audio-codec-rx";
@@ -213,7 +219,10 @@
<&incall_music_2_rx>, <&sb_5_rx>, <&sb_6_rx>,
<&sb_7_rx>, <&sb_7_tx>, <&sb_8_tx>,
<&usb_audio_rx>, <&usb_audio_tx>,
- <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>;
+ <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>,
+ <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>,
+ <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>,
+ <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>;
asoc-cpu-names = "msm-dai-q6-hdmi.8", "msm-dai-q6-dp.24608",
"msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
"msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
@@ -232,7 +241,10 @@
"msm-dai-q6-dev.16396", "msm-dai-q6-dev.16398",
"msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401",
"msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673",
- "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897";
+ "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865",
+ "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881",
+ "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897",
+ "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913";
asoc-codec = <&stub_codec>, <&ext_disp_audio_codec>;
asoc-codec-names = "msm-stub-codec.1",
"msm-ext-disp-audio-codec-rx";
@@ -371,6 +383,7 @@
qcom,cdc-slim-ifd-elemental-addr = [00 00 A0 01 17 02];
qcom,cdc-dmic-sample-rate = <4800000>;
qcom,cdc-mad-dmic-rate = <600000>;
+ qcom,cdc-ecpp-dmic-rate = <1200000>;
};
wcd934x_cdc: tavil_codec {
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-mdss-panels.dtsi
index b64cd8eea19b..6afd593f9610 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-mdss-panels.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-mdss-panels.dtsi
@@ -158,6 +158,8 @@
qcom,mdss-dsi-panel-timings = [00 17 05 05 09 0f 05 06 04 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x06>;
qcom,mdss-dsi-t-clk-pre = <0x23>;
+ qcom,esd-check-enabled;
+ qcom,mdss-dsi-panel-status-check-mode = "te_signal_check";
};
&dsi_sharp_1080_cmd {
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-qrd-skuk.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-qrd-skuk.dtsi
index 5f89985db0a3..58471f6d0fd1 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-qrd-skuk.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-qrd-skuk.dtsi
@@ -62,7 +62,7 @@
50000000 100000000 200000000>;
qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
- cd-gpios = <&tlmm 95 0x1>;
+ cd-gpios = <&tlmm 95 0x0>;
status = "ok";
};
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/msmcobalt-v2.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi
index cde74aa2866d..beecee843778 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi
@@ -237,6 +237,84 @@
regulator-max-microvolt = <1056000>;
};
+&pcie0 {
+ qcom,phy-sequence = <0x804 0x01 0x00
+ 0x034 0x14 0x00
+ 0x138 0x30 0x00
+ 0x048 0x0f 0x00
+ 0x15c 0x06 0x00
+ 0x090 0x01 0x00
+ 0x088 0x20 0x00
+ 0x0f0 0x00 0x00
+ 0x0f8 0x01 0x00
+ 0x0f4 0xc9 0x00
+ 0x11c 0xff 0x00
+ 0x120 0x3f 0x00
+ 0x164 0x01 0x00
+ 0x154 0x00 0x00
+ 0x148 0x0a 0x00
+ 0x05C 0x19 0x00
+ 0x038 0x90 0x00
+ 0x0b0 0x82 0x00
+ 0x0c0 0x03 0x00
+ 0x0bc 0x55 0x00
+ 0x0b8 0x55 0x00
+ 0x0a0 0x00 0x00
+ 0x09c 0x0d 0x00
+ 0x098 0x04 0x00
+ 0x13c 0x00 0x00
+ 0x060 0x08 0x00
+ 0x068 0x16 0x00
+ 0x070 0x34 0x00
+ 0x15c 0x06 0x00
+ 0x138 0x33 0x00
+ 0x03c 0x02 0x00
+ 0x040 0x07 0x00
+ 0x080 0x04 0x00
+ 0x0dc 0x00 0x00
+ 0x0d8 0x3f 0x00
+ 0x00c 0x09 0x00
+ 0x010 0x01 0x00
+ 0x01c 0x40 0x00
+ 0x020 0x01 0x00
+ 0x014 0x02 0x00
+ 0x018 0x00 0x00
+ 0x024 0x7e 0x00
+ 0x028 0x15 0x00
+ 0x244 0x02 0x00
+ 0x2a4 0x12 0x00
+ 0x260 0x10 0x00
+ 0x28c 0x06 0x00
+ 0x504 0x03 0x00
+ 0x500 0x1c 0x00
+ 0x50c 0x14 0x00
+ 0x4d4 0x0a 0x00
+ 0x4d8 0x04 0x00
+ 0x4dc 0x1a 0x00
+ 0x434 0x4b 0x00
+ 0x414 0x04 0x00
+ 0x40c 0x04 0x00
+ 0x4f8 0x00 0x00
+ 0x4fc 0x80 0x00
+ 0x51c 0x40 0x00
+ 0x444 0x71 0x00
+ 0x43c 0x40 0x00
+ 0x854 0x04 0x00
+ 0x62c 0x52 0x00
+ 0x9ac 0x00 0x00
+ 0x8a0 0x01 0x00
+ 0x9e0 0x00 0x00
+ 0x9dc 0x01 0x00
+ 0x9a8 0x00 0x00
+ 0x8a4 0x01 0x00
+ 0x8a8 0x73 0x00
+ 0x9d8 0x99 0x00
+ 0x9b0 0x03 0x00
+ 0x804 0x03 0x00
+ 0x800 0x00 0x00
+ 0x808 0x03 0x00>;
+};
+
&apc0_cpr {
compatible = "qcom,cprh-msmcobalt-v2-kbss-regulator";
qcom,cpr-corner-switch-delay-time = <1042>;
@@ -862,3 +940,7 @@
lanes-per-direction = <2>;
};
+
+&ssc_sensors {
+ qcom,firmware-name = "slpi_v2";
+};
diff --git a/arch/arm/boot/dts/qcom/msmcobalt.dtsi b/arch/arm/boot/dts/qcom/msmcobalt.dtsi
index b21e2dcf8c1a..60b514c7ca20 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt.dtsi
@@ -2810,9 +2810,10 @@
};
};
- qcom,msm-ssc-sensors {
+ ssc_sensors: qcom,msm-ssc-sensors {
compatible = "qcom,msm-ssc-sensors";
status = "ok";
+ qcom,firmware-name = "slpi_v1";
};
dcc: dcc@10b3000 {
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-smp2p.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-smp2p.dtsi
index e93067e3697c..b43fae954ec2 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon-smp2p.dtsi
+++ b/arch/arm/boot/dts/qcom/msmfalcon-smp2p.dtsi
@@ -173,6 +173,29 @@
gpios = <&smp2pgpio_smp2p_5_out 0 0>;
};
+ /* ssr - inbound entry from mss */
+ smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "slave-kernel";
+ qcom,remote-pid = <1>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* ssr - outbound entry to mss */
+ smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "master-kernel";
+ qcom,remote-pid = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
/* ssr - inbound entry from lpass */
smp2pgpio_ssr_smp2p_2_in: qcom,smp2pgpio-ssr-smp2p-2-in {
compatible = "qcom,smp2pgpio";
diff --git a/arch/arm/boot/dts/qcom/msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msmfalcon.dtsi
index 8e8c407734eb..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";
};
@@ -754,6 +754,59 @@
qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_5_out 0 0>;
status = "ok";
};
+
+ pil_modem: qcom,mss@4080000 {
+ compatible = "qcom,pil-q6v55-mss";
+ reg = <0x4080000 0x100>,
+ <0x1f63000 0x008>,
+ <0x1f65000 0x008>,
+ <0x1f64000 0x008>,
+ <0x4180000 0x040>,
+ <0x00179000 0x004>;
+ reg-names = "qdsp6_base", "halt_q6", "halt_modem",
+ "halt_nc", "rmb_base", "restart_reg";
+
+ clocks = <&clock_rpmcc RPM_XO_CLK_SRC>,
+ <&clock_gcc GCC_MSS_CFG_AHB_CLK>,
+ <&clock_gcc GCC_BIMC_MSS_Q6_AXI_CLK>,
+ <&clock_gcc GCC_BOOT_ROM_AHB_CLK>,
+ <&clock_gcc GPLL0_OUT_MSSCC>,
+ <&clock_gcc GCC_MSS_SNOC_AXI_CLK>,
+ <&clock_gcc GCC_MSS_MNOC_BIMC_AXI_CLK>,
+ <&clock_rpmcc RPM_QDSS_CLK>;
+ clock-names = "xo", "iface_clk", "bus_clk",
+ "mem_clk", "gpll0_mss_clk", "snoc_axi_clk",
+ "mnoc_axi_clk", "qdss_clk";
+ qcom,proxy-clock-names = "xo", "qdss_clk";
+ qcom,active-clock-names = "iface_clk", "bus_clk", "mem_clk",
+ "gpll0_mss_clk", "snoc_axi_clk",
+ "mnoc_axi_clk";
+
+ interrupts = <0 448 1>;
+ vdd_cx-supply = <&pmfalcon_s3b_level>;
+ vdd_cx-voltage = <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ vdd_mx-supply = <&pmfalcon_s5b_level>;
+ vdd_mx-uV = <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,firmware-name = "modem";
+ qcom,pil-self-auth;
+ qcom,sysmon-id = <0>;
+ qcom,ssctl-instance-id = <0x12>;
+ qcom,override-acc;
+ qcom,qdsp6v62-1-5;
+ memory-region = <&modem_fw_mem>;
+ qcom,mem-protect-id = <0xF>;
+
+ /* GPIO inputs from mss */
+ qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
+ qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
+ qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_1_in 3 0>;
+ qcom,gpio-shutdown-ack = <&smp2pgpio_ssr_smp2p_1_in 7 0>;
+
+ /* GPIO output to mss */
+ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
+ status = "ok";
+ };
};
#include "msmfalcon-ion.dtsi"
diff --git a/arch/arm/boot/dts/qcom/msmtriton-smp2p.dtsi b/arch/arm/boot/dts/qcom/msmtriton-smp2p.dtsi
index 1a72414de094..b458bbb08dc2 100644
--- a/arch/arm/boot/dts/qcom/msmtriton-smp2p.dtsi
+++ b/arch/arm/boot/dts/qcom/msmtriton-smp2p.dtsi
@@ -134,6 +134,29 @@
gpios = <&smp2pgpio_sleepstate_2_out 0 0>;
};
+ /* ssr - inbound entry from mss */
+ smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "slave-kernel";
+ qcom,remote-pid = <1>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* ssr - outbound entry to mss */
+ smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "master-kernel";
+ qcom,remote-pid = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
/* ssr - inbound entry from lpass */
smp2pgpio_ssr_smp2p_2_in: qcom,smp2pgpio-ssr-smp2p-2-in {
compatible = "qcom,smp2pgpio";
diff --git a/arch/arm/boot/dts/qcom/msmtriton.dtsi b/arch/arm/boot/dts/qcom/msmtriton.dtsi
index 083c14af7839..807c40fcc46e 100644
--- a/arch/arm/boot/dts/qcom/msmtriton.dtsi
+++ b/arch/arm/boot/dts/qcom/msmtriton.dtsi
@@ -609,6 +609,59 @@
memory-region = <&venus_fw_mem>;
status = "ok";
};
+
+ pil_modem: qcom,mss@4080000 {
+ compatible = "qcom,pil-q6v55-mss";
+ reg = <0x4080000 0x100>,
+ <0x1f63000 0x008>,
+ <0x1f65000 0x008>,
+ <0x1f64000 0x008>,
+ <0x4180000 0x040>,
+ <0x00179000 0x004>;
+ reg-names = "qdsp6_base", "halt_q6", "halt_modem",
+ "halt_nc", "rmb_base", "restart_reg";
+
+ clocks = <&clock_rpmcc RPM_XO_CLK_SRC>,
+ <&clock_gcc GCC_MSS_CFG_AHB_CLK>,
+ <&clock_gcc GCC_BIMC_MSS_Q6_AXI_CLK>,
+ <&clock_gcc GCC_BOOT_ROM_AHB_CLK>,
+ <&clock_gcc GPLL0_OUT_MSSCC>,
+ <&clock_gcc GCC_MSS_SNOC_AXI_CLK>,
+ <&clock_gcc GCC_MSS_MNOC_BIMC_AXI_CLK>,
+ <&clock_rpmcc RPM_QDSS_CLK>;
+ clock-names = "xo", "iface_clk", "bus_clk",
+ "mem_clk", "gpll0_mss_clk", "snoc_axi_clk",
+ "mnoc_axi_clk", "qdss_clk";
+ qcom,proxy-clock-names = "xo", "qdss_clk";
+ qcom,active-clock-names = "iface_clk", "bus_clk", "mem_clk",
+ "gpll0_mss_clk", "snoc_axi_clk",
+ "mnoc_axi_clk";
+
+ interrupts = <0 448 1>;
+ vdd_cx-supply = <&pmfalcon_s3b_level>;
+ vdd_cx-voltage = <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ vdd_mx-supply = <&pmfalcon_s5b_level>;
+ vdd_mx-uV = <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,firmware-name = "modem";
+ qcom,pil-self-auth;
+ qcom,sysmon-id = <0>;
+ qcom,ssctl-instance-id = <0x12>;
+ qcom,override-acc;
+ qcom,qdsp6v62-1-5;
+ memory-region = <&modem_fw_mem>;
+ qcom,mem-protect-id = <0xF>;
+
+ /* GPIO inputs from mss */
+ qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
+ qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
+ qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_1_in 3 0>;
+ qcom,gpio-shutdown-ack = <&smp2pgpio_ssr_smp2p_1_in 7 0>;
+
+ /* GPIO output to mss */
+ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
+ status = "ok";
+ };
};
#include "msmtriton-ion.dtsi"
diff --git a/arch/arm/configs/msmcortex_defconfig b/arch/arm/configs/msmcortex_defconfig
index 48507eebe9f3..8be2b187a524 100644
--- a/arch/arm/configs/msmcortex_defconfig
+++ b/arch/arm/configs/msmcortex_defconfig
@@ -442,6 +442,7 @@ CONFIG_QCOM_SCM=y
CONFIG_QCOM_WATCHDOG_V2=y
CONFIG_QCOM_MEMORY_DUMP_V2=y
CONFIG_ICNSS=y
+CONFIG_ICNSS_DEBUG=y
CONFIG_MSM_GLADIATOR_ERP_V2=y
CONFIG_PANIC_ON_GLADIATOR_ERROR_V2=y
CONFIG_MSM_GLADIATOR_HANG_DETECT=y
diff --git a/arch/arm/configs/msmfalcon_defconfig b/arch/arm/configs/msmfalcon_defconfig
index 069603eefe48..0788a03ed219 100644
--- a/arch/arm/configs/msmfalcon_defconfig
+++ b/arch/arm/configs/msmfalcon_defconfig
@@ -451,6 +451,7 @@ CONFIG_QCOM_SCM=y
CONFIG_QCOM_WATCHDOG_V2=y
CONFIG_QCOM_MEMORY_DUMP_V2=y
CONFIG_ICNSS=y
+CONFIG_ICNSS_DEBUG=y
CONFIG_MSM_GLADIATOR_ERP_V2=y
CONFIG_PANIC_ON_GLADIATOR_ERROR_V2=y
CONFIG_MSM_GLADIATOR_HANG_DETECT=y
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/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-gcc-cobalt.c b/drivers/clk/msm/clock-gcc-cobalt.c
index 46e791b3cb99..f2a3f7402f67 100644
--- a/drivers/clk/msm/clock-gcc-cobalt.c
+++ b/drivers/clk/msm/clock-gcc-cobalt.c
@@ -1707,17 +1707,6 @@ static struct branch_clk gcc_gpu_bimc_gfx_clk = {
},
};
-static struct branch_clk gcc_gpu_bimc_gfx_src_clk = {
- .cbcr_reg = GCC_GPU_BIMC_GFX_SRC_CBCR,
- .has_sibling = 1,
- .base = &virt_base,
- .c = {
- .dbg_name = "gcc_gpu_bimc_gfx_src_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(gcc_gpu_bimc_gfx_src_clk.c),
- },
-};
-
static struct branch_clk gcc_gpu_cfg_ahb_clk = {
.cbcr_reg = GCC_GPU_CFG_AHB_CBCR,
.has_sibling = 1,
@@ -1731,17 +1720,6 @@ static struct branch_clk gcc_gpu_cfg_ahb_clk = {
},
};
-static struct branch_clk gcc_gpu_snoc_dvm_gfx_clk = {
- .cbcr_reg = GCC_GPU_SNOC_DVM_GFX_CBCR,
- .has_sibling = 1,
- .base = &virt_base,
- .c = {
- .dbg_name = "gcc_gpu_snoc_dvm_gfx_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(gcc_gpu_snoc_dvm_gfx_clk.c),
- },
-};
-
static struct branch_clk gcc_gpu_iref_clk = {
.cbcr_reg = GCC_GPU_IREF_EN,
.has_sibling = 1,
@@ -2454,7 +2432,6 @@ static struct mux_clk gcc_debug_mux = {
{ &gcc_mss_mnoc_bimc_axi_clk.c, 0x0120 },
{ &gcc_mss_snoc_axi_clk.c, 0x0123 },
{ &gcc_gpu_cfg_ahb_clk.c, 0x013b },
- { &gcc_gpu_bimc_gfx_src_clk.c, 0x013e },
{ &gcc_gpu_bimc_gfx_clk.c, 0x013f },
{ &gcc_qspi_ahb_clk.c, 0x0156 },
{ &gcc_qspi_ref_clk.c, 0x0157 },
@@ -2649,9 +2626,7 @@ static struct clk_lookup msm_clocks_gcc_cobalt[] = {
CLK_LIST(gcc_gp2_clk),
CLK_LIST(gcc_gp3_clk),
CLK_LIST(gcc_gpu_bimc_gfx_clk),
- CLK_LIST(gcc_gpu_bimc_gfx_src_clk),
CLK_LIST(gcc_gpu_cfg_ahb_clk),
- CLK_LIST(gcc_gpu_snoc_dvm_gfx_clk),
CLK_LIST(gcc_gpu_iref_clk),
CLK_LIST(gcc_hmss_ahb_clk),
CLK_LIST(gcc_hmss_dvm_bus_clk),
diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c
index 612e7b37a8d0..bc982c9bfa71 100644
--- a/drivers/clk/qcom/clk-smd-rpm.c
+++ b/drivers/clk/qcom/clk-smd-rpm.c
@@ -662,8 +662,6 @@ static struct clk_hw *msmfalcon_clks[] = {
[RPM_AGGR2_NOC_A_CLK] = &msmfalcon_aggre2_noc_a_clk.hw,
[RPM_CNOC_CLK] = &msmfalcon_cnoc_clk.hw,
[RPM_CNOC_A_CLK] = &msmfalcon_cnoc_a_clk.hw,
- [RPM_MMAXI_CLK] = &msmfalcon_mmssnoc_axi_clk.hw,
- [RPM_MMAXI_A_CLK] = &msmfalcon_mmssnoc_axi_a_clk.hw,
[RPM_IPA_CLK] = &msmfalcon_ipa_clk.hw,
[RPM_IPA_A_CLK] = &msmfalcon_ipa_a_clk.hw,
[RPM_CE1_CLK] = &msmfalcon_ce1_clk.hw,
@@ -684,6 +682,8 @@ static struct clk_hw *msmfalcon_clks[] = {
[RPM_LN_BB_CLK3_PIN_AO] = &msmfalcon_ln_bb_clk3_pin_ao.hw,
[RPM_CNOC_PERIPH_CLK] = &msmfalcon_cnoc_periph_clk.hw,
[RPM_CNOC_PERIPH_A_CLK] = &msmfalcon_cnoc_periph_a_clk.hw,
+ [MMSSNOC_AXI_CLK] = &msmfalcon_mmssnoc_axi_clk.hw,
+ [MMSSNOC_AXI_A_CLK] = &msmfalcon_mmssnoc_axi_a_clk.hw,
/* Voter Clocks */
[BIMC_MSMBUS_CLK] = &bimc_msmbus_clk.hw,
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/input/misc/hbtp_input.c b/drivers/input/misc/hbtp_input.c
index 519e3db4d73e..f94ecf02d9cb 100644
--- a/drivers/input/misc/hbtp_input.c
+++ b/drivers/input/misc/hbtp_input.c
@@ -23,6 +23,12 @@
#include <linux/regulator/consumer.h>
#include <uapi/linux/hbtp_input.h>
#include "../input-compat.h"
+#include <linux/ktime.h>
+#include <linux/uaccess.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
#if defined(CONFIG_FB)
#include <linux/notifier.h>
@@ -32,6 +38,10 @@
#define HBTP_INPUT_NAME "hbtp_input"
#define DISP_COORDS_SIZE 2
+#define HBTP_PINCTRL_VALID_STATE_CNT (2)
+#define HBTP_HOLD_DURATION_US (10)
+#define HBTP_PINCTRL_DDIC_SEQ_NUM (4)
+
struct hbtp_data {
struct platform_device *pdev;
struct input_dev *input_dev;
@@ -41,6 +51,20 @@ struct hbtp_data {
#if defined(CONFIG_FB)
struct notifier_block fb_notif;
#endif
+ struct pinctrl *ts_pinctrl;
+ struct pinctrl_state *gpio_state_active;
+ struct pinctrl_state *gpio_state_suspend;
+ struct pinctrl_state *ddic_rst_state_active;
+ struct pinctrl_state *ddic_rst_state_suspend;
+ u32 ts_pinctrl_seq_delay;
+ u32 ddic_pinctrl_seq_delay[HBTP_PINCTRL_DDIC_SEQ_NUM];
+ u32 fb_resume_seq_delay;
+ bool lcd_on;
+ bool power_suspended;
+ bool power_sync_enabled;
+ bool power_sig_enabled;
+ struct completion power_resume_sig;
+ struct completion power_suspend_sig;
struct regulator *vcc_ana;
struct regulator *vcc_dig;
int afe_load_ua;
@@ -59,31 +83,68 @@ struct hbtp_data {
bool override_disp_coords;
bool manage_afe_power_ana;
bool manage_power_dig;
+ u32 power_on_delay;
+ u32 power_off_delay;
+ bool manage_pin_ctrl;
};
static struct hbtp_data *hbtp;
#if defined(CONFIG_FB)
+static int hbtp_fb_suspend(struct hbtp_data *ts);
+static int hbtp_fb_early_resume(struct hbtp_data *ts);
+static int hbtp_fb_resume(struct hbtp_data *ts);
+#endif
+
+#if defined(CONFIG_FB)
static int fb_notifier_callback(struct notifier_block *self,
unsigned long event, void *data)
{
int blank;
struct fb_event *evdata = data;
struct hbtp_data *hbtp_data =
- container_of(self, struct hbtp_data, fb_notif);
- char *envp[2] = {HBTP_EVENT_TYPE_DISPLAY, NULL};
+ container_of(self, struct hbtp_data, fb_notif);
- if (evdata && evdata->data && event == FB_EVENT_BLANK &&
- hbtp_data && hbtp_data->input_dev) {
+ if (evdata && evdata->data && hbtp_data &&
+ (event == FB_EARLY_EVENT_BLANK ||
+ event == FB_R_EARLY_EVENT_BLANK)) {
blank = *(int *)(evdata->data);
- if (blank == FB_BLANK_UNBLANK)
- kobject_uevent_env(&hbtp_data->input_dev->dev.kobj,
- KOBJ_ONLINE, envp);
- else if (blank == FB_BLANK_POWERDOWN)
- kobject_uevent_env(&hbtp_data->input_dev->dev.kobj,
- KOBJ_OFFLINE, envp);
+ if (event == FB_EARLY_EVENT_BLANK) {
+ if (blank == FB_BLANK_UNBLANK) {
+ pr_debug("%s: receives EARLY_BLANK:UNBLANK\n",
+ __func__);
+ hbtp_data->lcd_on = true;
+ hbtp_fb_early_resume(hbtp_data);
+ } else if (blank == FB_BLANK_POWERDOWN) {
+ pr_debug("%s: receives EARLY_BLANK:POWERDOWN\n",
+ __func__);
+ hbtp_data->lcd_on = false;
+ }
+ } else if (event == FB_R_EARLY_EVENT_BLANK) {
+ if (blank == FB_BLANK_UNBLANK) {
+ pr_debug("%s: receives R_EARLY_BALNK:UNBLANK\n",
+ __func__);
+ hbtp_data->lcd_on = false;
+ hbtp_fb_suspend(hbtp_data);
+ } else if (blank == FB_BLANK_POWERDOWN) {
+ pr_debug("%s: receives R_EARLY_BALNK:POWERDOWN\n",
+ __func__);
+ hbtp_data->lcd_on = true;
+ }
+ }
}
+ if (evdata && evdata->data && hbtp_data &&
+ event == FB_EVENT_BLANK) {
+ blank = *(int *)(evdata->data);
+ if (blank == FB_BLANK_POWERDOWN) {
+ pr_debug("%s: receives BLANK:POWERDOWN\n", __func__);
+ hbtp_fb_suspend(hbtp_data);
+ } else if (blank == FB_BLANK_UNBLANK) {
+ pr_debug("%s: receives BLANK:UNBLANK\n", __func__);
+ hbtp_fb_resume(hbtp_data);
+ }
+ }
return 0;
}
#endif
@@ -111,6 +172,8 @@ static int hbtp_input_release(struct inode *inode, struct file *file)
return -ENOTTY;
}
hbtp->count--;
+ if (hbtp->power_sig_enabled)
+ hbtp->power_sig_enabled = false;
mutex_unlock(&hbtp->mutex);
return 0;
@@ -278,6 +341,14 @@ static int hbtp_pdev_power_on(struct hbtp_data *hbtp, bool on)
return ret;
}
}
+
+ if (hbtp->power_on_delay) {
+ pr_debug("%s: power-on-delay = %u\n", __func__,
+ hbtp->power_on_delay);
+ usleep_range(hbtp->power_on_delay,
+ hbtp->power_on_delay + HBTP_HOLD_DURATION_US);
+ }
+
if (hbtp->vcc_dig) {
ret = reg_set_load_check(hbtp->vcc_dig,
hbtp->dig_load_ua);
@@ -299,17 +370,171 @@ static int hbtp_pdev_power_on(struct hbtp_data *hbtp, bool on)
return 0;
reg_off:
- if (hbtp->vcc_ana) {
- reg_set_load_check(hbtp->vcc_ana, 0);
- regulator_disable(hbtp->vcc_ana);
- }
if (hbtp->vcc_dig) {
reg_set_load_check(hbtp->vcc_dig, 0);
regulator_disable(hbtp->vcc_dig);
}
+
+ if (hbtp->power_off_delay) {
+ pr_debug("%s: power-off-delay = %u\n", __func__,
+ hbtp->power_off_delay);
+ usleep_range(hbtp->power_off_delay,
+ hbtp->power_off_delay + HBTP_HOLD_DURATION_US);
+ }
+
+ if (hbtp->vcc_ana) {
+ reg_set_load_check(hbtp->vcc_ana, 0);
+ regulator_disable(hbtp->vcc_ana);
+ }
return 0;
}
+static int hbtp_gpio_select(struct hbtp_data *data, bool on)
+{
+ struct pinctrl_state *pins_state;
+ int ret = 0;
+
+ pins_state = on ? data->gpio_state_active : data->gpio_state_suspend;
+ if (!IS_ERR_OR_NULL(pins_state)) {
+ ret = pinctrl_select_state(data->ts_pinctrl, pins_state);
+ if (ret) {
+ dev_err(&data->pdev->dev,
+ "can not set %s pins\n",
+ on ? "ts_active" : "ts_suspend");
+ return ret;
+ }
+
+ if (on) {
+ if (data->ts_pinctrl_seq_delay) {
+ usleep_range(data->ts_pinctrl_seq_delay,
+ data->ts_pinctrl_seq_delay +
+ HBTP_HOLD_DURATION_US);
+ dev_dbg(&data->pdev->dev, "ts_pinctrl_seq_delay = %u\n",
+ data->ts_pinctrl_seq_delay);
+ }
+ }
+ } else {
+ dev_warn(&data->pdev->dev,
+ "not a valid '%s' pinstate\n",
+ on ? "ts_active" : "ts_suspend");
+ return ret;
+ }
+
+ return ret;
+}
+
+static int hbtp_ddic_rst_select(struct hbtp_data *data, bool on)
+{
+ struct pinctrl_state *active, *suspend;
+ int ret = 0;
+
+ active = data->ddic_rst_state_active;
+ if (IS_ERR_OR_NULL(active)) {
+ dev_warn(&data->pdev->dev,
+ "not a valid ddic_rst_active pinstate\n");
+ return ret;
+ }
+
+ suspend = data->ddic_rst_state_suspend;
+ if (IS_ERR_OR_NULL(suspend)) {
+ dev_warn(&data->pdev->dev,
+ "not a valid ddic_rst_suspend pinstate\n");
+ return ret;
+ }
+
+ if (on) {
+ if (data->ddic_pinctrl_seq_delay[0]) {
+ usleep_range(data->ddic_pinctrl_seq_delay[0],
+ data->ddic_pinctrl_seq_delay[0] +
+ HBTP_HOLD_DURATION_US);
+ dev_dbg(&data->pdev->dev, "ddic_seq_delay[0] = %u\n",
+ data->ddic_pinctrl_seq_delay[0]);
+ }
+
+ ret = pinctrl_select_state(data->ts_pinctrl, active);
+ if (ret) {
+ dev_err(&data->pdev->dev,
+ "can not set ddic_rst_active pins\n");
+ return ret;
+ }
+ if (data->ddic_pinctrl_seq_delay[1]) {
+ usleep_range(data->ddic_pinctrl_seq_delay[1],
+ data->ddic_pinctrl_seq_delay[1] +
+ HBTP_HOLD_DURATION_US);
+ dev_dbg(&data->pdev->dev, "ddic_seq_delay[1] = %u\n",
+ data->ddic_pinctrl_seq_delay[1]);
+ }
+ ret = pinctrl_select_state(data->ts_pinctrl, suspend);
+ if (ret) {
+ dev_err(&data->pdev->dev,
+ "can not set ddic_rst_suspend pins\n");
+ return ret;
+ }
+
+ if (data->ddic_pinctrl_seq_delay[2]) {
+ usleep_range(data->ddic_pinctrl_seq_delay[2],
+ data->ddic_pinctrl_seq_delay[2] +
+ HBTP_HOLD_DURATION_US);
+ dev_dbg(&data->pdev->dev, "ddic_seq_delay[2] = %u\n",
+ data->ddic_pinctrl_seq_delay[2]);
+ }
+
+ ret = pinctrl_select_state(data->ts_pinctrl, active);
+ if (ret) {
+ dev_err(&data->pdev->dev,
+ "can not set ddic_rst_active pins\n");
+ return ret;
+ }
+
+ if (data->ddic_pinctrl_seq_delay[3]) {
+ usleep_range(data->ddic_pinctrl_seq_delay[3],
+ data->ddic_pinctrl_seq_delay[3] +
+ HBTP_HOLD_DURATION_US);
+ dev_dbg(&data->pdev->dev, "ddic_seq_delay[3] = %u\n",
+ data->ddic_pinctrl_seq_delay[3]);
+ }
+ } else {
+ ret = pinctrl_select_state(data->ts_pinctrl, suspend);
+ if (ret) {
+ dev_err(&data->pdev->dev,
+ "can not set ddic_rst_suspend pins\n");
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static int hbtp_pinctrl_enable(struct hbtp_data *ts, bool on)
+{
+ int rc = 0;
+
+ if (!ts->manage_pin_ctrl) {
+ pr_info("%s: pinctrl info is not available\n", __func__);
+ return 0;
+ }
+
+ if (!on)
+ goto pinctrl_suspend;
+
+ rc = hbtp_gpio_select(ts, true);
+ if (rc < 0)
+ return -EINVAL;
+
+ rc = hbtp_ddic_rst_select(ts, true);
+ if (rc < 0)
+ goto err_ddic_rst_pinctrl_enable;
+
+ return rc;
+
+pinctrl_suspend:
+ if (ts->ddic_rst_state_suspend)
+ hbtp_ddic_rst_select(ts, true);
+err_ddic_rst_pinctrl_enable:
+ hbtp_gpio_select(ts, false);
+ return rc;
+}
+
static long hbtp_input_ioctl_handler(struct file *file, unsigned int cmd,
unsigned long arg, void __user *p)
{
@@ -318,6 +543,8 @@ static long hbtp_input_ioctl_handler(struct file *file, unsigned int cmd,
struct hbtp_input_absinfo absinfo[ABS_MT_LAST - ABS_MT_FIRST + 1];
struct hbtp_input_key key_data;
enum hbtp_afe_power_cmd power_cmd;
+ enum hbtp_afe_signal afe_signal;
+ enum hbtp_afe_power_ctrl afe_power_ctrl;
switch (cmd) {
case HBTP_SET_ABSPARAM:
@@ -408,6 +635,112 @@ static long hbtp_input_ioctl_handler(struct file *file, unsigned int cmd,
input_sync(hbtp->input_dev);
break;
+ case HBTP_SET_SYNCSIGNAL:
+ if (!hbtp || !hbtp->input_dev) {
+ pr_err("%s: The input device hasn't been created\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ if (!hbtp->power_sig_enabled) {
+ pr_err("%s: power_signal is not enabled", __func__);
+ return -EPERM;
+ }
+
+ if (copy_from_user(&afe_signal, (void *)arg,
+ sizeof(enum hbtp_afe_signal))) {
+ pr_err("%s: Error copying data\n", __func__);
+ return -EFAULT;
+ }
+
+ pr_debug("%s: receives %d signal\n", __func__, afe_signal);
+
+ switch (afe_signal) {
+ case HBTP_AFE_SIGNAL_ON_RESUME:
+ mutex_lock(&hbtp->mutex);
+ if (!hbtp->power_suspended) {
+ complete(&hbtp->power_resume_sig);
+ } else {
+ pr_err("%s: resume signal in wrong state\n",
+ __func__);
+ }
+ mutex_unlock(&hbtp->mutex);
+ break;
+ case HBTP_AFE_SIGNAL_ON_SUSPEND:
+ mutex_lock(&hbtp->mutex);
+ if (hbtp->power_suspended) {
+ complete(&hbtp->power_suspend_sig);
+ } else {
+ pr_err("%s: suspend signal in wrong state\n",
+ __func__);
+ }
+ mutex_unlock(&hbtp->mutex);
+ break;
+ default:
+ pr_err("%s: Unsupported command for afe signal, %d\n",
+ __func__, afe_signal);
+ return -EINVAL;
+ }
+ break;
+ case HBTP_SET_POWER_CTRL:
+ if (!hbtp || !hbtp->input_dev) {
+ pr_err("%s: The input device hasn't been created\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ if (copy_from_user(&afe_power_ctrl, (void *)arg,
+ sizeof(enum hbtp_afe_power_ctrl))) {
+ pr_err("%s: Error copying data\n", __func__);
+ return -EFAULT;
+ }
+ switch (afe_power_ctrl) {
+ case HBTP_AFE_POWER_ENABLE_SYNC:
+ pr_debug("%s: power_sync is enabled\n", __func__);
+ if (!hbtp->manage_pin_ctrl || !hbtp->manage_power_dig ||
+ !hbtp->manage_afe_power_ana) {
+ pr_err("%s: power/pin is not available\n",
+ __func__);
+ return -EFAULT;
+ }
+ mutex_lock(&hbtp->mutex);
+ error = hbtp_pdev_power_on(hbtp, true);
+ if (error) {
+ mutex_unlock(&hbtp->mutex);
+ pr_err("%s: failed to power on\n", __func__);
+ return error;
+ }
+ error = hbtp_pinctrl_enable(hbtp, true);
+ if (error) {
+ mutex_unlock(&hbtp->mutex);
+ pr_err("%s: failed to enable pins\n", __func__);
+ hbtp_pdev_power_on(hbtp, false);
+ return error;
+ }
+ hbtp->power_sync_enabled = true;
+ mutex_unlock(&hbtp->mutex);
+ pr_debug("%s: power_sync option is enabled\n",
+ __func__);
+ break;
+ case HBTP_AFE_POWER_ENABLE_SYNC_SIGNAL:
+ if (!hbtp->power_sync_enabled) {
+ pr_err("%s: power_sync is not enabled\n",
+ __func__);
+ return -EFAULT;
+ }
+ mutex_lock(&hbtp->mutex);
+ init_completion(&hbtp->power_resume_sig);
+ init_completion(&hbtp->power_suspend_sig);
+ hbtp->power_sig_enabled = true;
+ mutex_unlock(&hbtp->mutex);
+ pr_err("%s: sync_signal option is enabled\n", __func__);
+ break;
+ default:
+ pr_err("%s: unsupported power ctrl, %d\n",
+ __func__, afe_power_ctrl);
+ return -EINVAL;
+ }
+ break;
default:
pr_err("%s: Unsupported ioctl command %u\n", __func__, cmd);
error = -EINVAL;
@@ -514,6 +847,25 @@ static int hbtp_parse_dt(struct device *dev)
}
}
+ if (hbtp->manage_power_dig && hbtp->manage_afe_power_ana) {
+ rc = of_property_read_u32(np,
+ "qcom,afe-power-on-delay-us", &temp_val);
+ if (!rc)
+ hbtp->power_on_delay = (u32)temp_val;
+ else
+ dev_info(dev, "Power-On Delay is not specified\n");
+
+ rc = of_property_read_u32(np,
+ "qcom,afe-power-off-delay-us", &temp_val);
+ if (!rc)
+ hbtp->power_off_delay = (u32)temp_val;
+ else
+ dev_info(dev, "Power-Off Delay is not specified\n");
+
+ dev_dbg(dev, "power-on-delay = %u, power-off-delay = %u\n",
+ hbtp->power_on_delay, hbtp->power_off_delay);
+ }
+
prop = of_find_property(np, "qcom,display-resolution", NULL);
if (prop != NULL) {
if (!prop->value)
@@ -605,11 +957,292 @@ static int hbtp_parse_dt(struct device *dev)
}
#endif
+static int hbtp_pinctrl_init(struct hbtp_data *data)
+{
+ const char *statename;
+ int rc;
+ int state_cnt, i;
+ struct device_node *np = data->pdev->dev.of_node;
+ bool pinctrl_state_act_found = false;
+ bool pinctrl_state_sus_found = false;
+ bool pinctrl_ddic_act_found = false;
+ bool pinctrl_ddic_sus_found = false;
+ int count = 0;
+
+ data->ts_pinctrl = devm_pinctrl_get(&(data->pdev->dev));
+ if (IS_ERR_OR_NULL(data->ts_pinctrl)) {
+ dev_err(&data->pdev->dev,
+ "Target does not use pinctrl\n");
+ rc = PTR_ERR(data->ts_pinctrl);
+ data->ts_pinctrl = NULL;
+ return rc;
+ }
+
+ state_cnt = of_property_count_strings(np, "pinctrl-names");
+ if (state_cnt < HBTP_PINCTRL_VALID_STATE_CNT) {
+ /*
+ *if pinctrl names are not available then,
+ *power_sync can't be enabled
+ */
+ dev_info(&data->pdev->dev,
+ "pinctrl names are not available\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ for (i = 0; i < state_cnt; i++) {
+ rc = of_property_read_string_index(np,
+ "pinctrl-names", i, &statename);
+ if (rc) {
+ dev_err(&data->pdev->dev,
+ "failed to read pinctrl states by index\n");
+ goto error;
+ }
+
+ if (!strcmp(statename, "pmx_ts_active")) {
+ data->gpio_state_active
+ = pinctrl_lookup_state(data->ts_pinctrl,
+ statename);
+ if (IS_ERR_OR_NULL(data->gpio_state_active)) {
+ dev_err(&data->pdev->dev,
+ "Can not get ts default state\n");
+ rc = PTR_ERR(data->gpio_state_active);
+ goto error;
+ }
+ pinctrl_state_act_found = true;
+ } else if (!strcmp(statename, "pmx_ts_suspend")) {
+ data->gpio_state_suspend
+ = pinctrl_lookup_state(data->ts_pinctrl,
+ statename);
+ if (IS_ERR_OR_NULL(data->gpio_state_suspend)) {
+ dev_err(&data->pdev->dev,
+ "Can not get ts sleep state\n");
+ rc = PTR_ERR(data->gpio_state_suspend);
+ goto error;
+ }
+ pinctrl_state_sus_found = true;
+ } else if (!strcmp(statename, "ddic_rst_active")) {
+ data->ddic_rst_state_active
+ = pinctrl_lookup_state(data->ts_pinctrl,
+ statename);
+ if (IS_ERR(data->ddic_rst_state_active)) {
+ dev_err(&data->pdev->dev,
+ "Can not get DDIC rst act state\n");
+ rc = PTR_ERR(data->ddic_rst_state_active);
+ goto error;
+ }
+ pinctrl_ddic_act_found = true;
+ } else if (!strcmp(statename, "ddic_rst_suspend")) {
+ data->ddic_rst_state_suspend
+ = pinctrl_lookup_state(data->ts_pinctrl,
+ statename);
+ if (IS_ERR(data->ddic_rst_state_suspend)) {
+ dev_err(&data->pdev->dev,
+ "Can not get DDIC rst sleep state\n");
+ rc = PTR_ERR(data->ddic_rst_state_suspend);
+ goto error;
+ }
+ pinctrl_ddic_sus_found = true;
+ } else {
+ dev_err(&data->pdev->dev, "invalid pinctrl state\n");
+ rc = -EINVAL;
+ goto error;
+ }
+ }
+
+ if (!pinctrl_state_act_found || !pinctrl_state_sus_found) {
+ dev_err(&data->pdev->dev,
+ "missing required pinctrl states\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ if (of_property_read_u32(np, "qcom,pmx-ts-on-seq-delay-us",
+ &data->ts_pinctrl_seq_delay)) {
+ dev_warn(&data->pdev->dev, "Can not find ts seq delay\n");
+ }
+
+ if (of_property_read_u32(np, "qcom,fb-resume-delay-us",
+ &data->fb_resume_seq_delay)) {
+ dev_warn(&data->pdev->dev, "Can not find fb resume seq delay\n");
+ }
+
+ if (pinctrl_ddic_act_found && pinctrl_ddic_sus_found) {
+ count = of_property_count_u32_elems(np,
+ "qcom,ddic-rst-on-seq-delay-us");
+ if (count == HBTP_PINCTRL_DDIC_SEQ_NUM) {
+ of_property_read_u32_array(np,
+ "qcom,ddic-rst-on-seq-delay-us",
+ data->ddic_pinctrl_seq_delay, count);
+ } else {
+ dev_err(&data->pdev->dev, "count(%u) is not same as %u\n",
+ (u32)count, HBTP_PINCTRL_DDIC_SEQ_NUM);
+ }
+ } else {
+ dev_err(&data->pdev->dev, "ddic pinctrl act/sus not found\n");
+ }
+
+ data->manage_pin_ctrl = true;
+ return 0;
+
+error:
+ devm_pinctrl_put(data->ts_pinctrl);
+ data->ts_pinctrl = NULL;
+ return rc;
+}
+
+static int hbtp_fb_suspend(struct hbtp_data *ts)
+{
+ int rc;
+ char *envp[2] = {HBTP_EVENT_TYPE_DISPLAY, NULL};
+
+ mutex_lock(&hbtp->mutex);
+ if (ts->pdev && ts->power_sync_enabled) {
+ pr_debug("%s: power_sync is enabled\n", __func__);
+ if (ts->power_suspended) {
+ mutex_unlock(&hbtp->mutex);
+ pr_err("%s: power is not resumed\n", __func__);
+ return 0;
+ }
+ rc = hbtp_pinctrl_enable(ts, false);
+ if (rc) {
+ pr_err("%s: failed to disable GPIO pins\n", __func__);
+ goto err_pin_disable;
+ }
+
+ rc = hbtp_pdev_power_on(ts, false);
+ if (rc) {
+ pr_err("%s: failed to disable power\n", __func__);
+ goto err_power_disable;
+ }
+ ts->power_suspended = true;
+ }
+
+ if (ts->input_dev) {
+ kobject_uevent_env(&ts->input_dev->dev.kobj,
+ KOBJ_OFFLINE, envp);
+
+ if (ts->power_sig_enabled) {
+ pr_debug("%s: power_sig is enabled, wait for signal\n",
+ __func__);
+ mutex_unlock(&hbtp->mutex);
+ rc = wait_for_completion_interruptible(
+ &hbtp->power_suspend_sig);
+ if (rc != 0) {
+ pr_err("%s: wait for suspend is interrupted\n",
+ __func__);
+ }
+ mutex_lock(&hbtp->mutex);
+ pr_debug("%s: Wait is done for suspend\n", __func__);
+ } else {
+ pr_debug("%s: power_sig is NOT enabled", __func__);
+ }
+ }
+
+ mutex_unlock(&hbtp->mutex);
+ return 0;
+err_power_disable:
+ hbtp_pinctrl_enable(ts, true);
+err_pin_disable:
+ mutex_unlock(&hbtp->mutex);
+ return rc;
+}
+
+static int hbtp_fb_early_resume(struct hbtp_data *ts)
+{
+ char *envp[2] = {HBTP_EVENT_TYPE_DISPLAY, NULL};
+ int rc;
+
+ mutex_lock(&hbtp->mutex);
+
+ pr_debug("%s: hbtp_fb_early_resume\n", __func__);
+
+ if (ts->pdev && ts->power_sync_enabled) {
+ pr_debug("%s: power_sync is enabled\n", __func__);
+ if (!ts->power_suspended) {
+ pr_err("%s: power is not suspended\n", __func__);
+ mutex_unlock(&hbtp->mutex);
+ return 0;
+ }
+ rc = hbtp_pdev_power_on(ts, true);
+ if (rc) {
+ pr_err("%s: failed to enable panel power\n", __func__);
+ goto err_power_on;
+ }
+
+ rc = hbtp_pinctrl_enable(ts, true);
+
+ if (rc) {
+ pr_err("%s: failed to enable pin\n", __func__);
+ goto err_pin_enable;
+ }
+
+ ts->power_suspended = false;
+
+ if (ts->input_dev) {
+
+ kobject_uevent_env(&ts->input_dev->dev.kobj,
+ KOBJ_ONLINE, envp);
+
+ if (ts->power_sig_enabled) {
+ pr_err("%s: power_sig is enabled, wait for signal\n",
+ __func__);
+ mutex_unlock(&hbtp->mutex);
+ rc = wait_for_completion_interruptible(
+ &hbtp->power_resume_sig);
+ if (rc != 0) {
+ pr_err("%s: wait for resume is interrupted\n",
+ __func__);
+ }
+ mutex_lock(&hbtp->mutex);
+ pr_debug("%s: wait is done\n", __func__);
+ } else {
+ pr_debug("%s: power_sig is NOT enabled\n",
+ __func__);
+ }
+
+ if (ts->fb_resume_seq_delay) {
+ usleep_range(ts->fb_resume_seq_delay,
+ ts->fb_resume_seq_delay +
+ HBTP_HOLD_DURATION_US);
+ pr_err("%s: fb_resume_seq_delay = %u\n",
+ __func__, ts->fb_resume_seq_delay);
+ }
+ }
+ }
+ mutex_unlock(&hbtp->mutex);
+ return 0;
+
+err_pin_enable:
+ hbtp_pdev_power_on(ts, false);
+err_power_on:
+ mutex_unlock(&hbtp->mutex);
+ return rc;
+}
+
+static int hbtp_fb_resume(struct hbtp_data *ts)
+{
+ char *envp[2] = {HBTP_EVENT_TYPE_DISPLAY, NULL};
+
+ mutex_lock(&hbtp->mutex);
+ if (!ts->power_sync_enabled) {
+ pr_debug("%s: power_sync is disabled, send uevent\n", __func__);
+ if (ts->input_dev) {
+ kobject_uevent_env(&ts->input_dev->dev.kobj,
+ KOBJ_ONLINE, envp);
+ }
+ }
+ mutex_unlock(&hbtp->mutex);
+ return 0;
+}
+
static int hbtp_pdev_probe(struct platform_device *pdev)
{
int error;
struct regulator *vcc_ana, *vcc_dig;
+ hbtp->pdev = pdev;
+
if (pdev->dev.of_node) {
error = hbtp_parse_dt(&pdev->dev);
if (error) {
@@ -618,6 +1251,14 @@ static int hbtp_pdev_probe(struct platform_device *pdev)
}
}
+ platform_set_drvdata(pdev, hbtp);
+
+ error = hbtp_pinctrl_init(hbtp);
+ if (error) {
+ pr_info("%s: pinctrl isn't available, rc=%d\n", __func__,
+ error);
+ }
+
if (hbtp->manage_afe_power_ana) {
vcc_ana = regulator_get(&pdev->dev, "vcc_ana");
if (IS_ERR(vcc_ana)) {
@@ -662,8 +1303,6 @@ static int hbtp_pdev_probe(struct platform_device *pdev)
hbtp->vcc_dig = vcc_dig;
}
- hbtp->pdev = pdev;
-
return 0;
}
@@ -677,6 +1316,9 @@ static int hbtp_pdev_remove(struct platform_device *pdev)
regulator_put(hbtp->vcc_dig);
}
+ if (hbtp->ts_pinctrl)
+ devm_pinctrl_put(hbtp->ts_pinctrl);
+
return 0;
}
diff --git a/drivers/input/touchscreen/gt9xx/goodix_tool.c b/drivers/input/touchscreen/gt9xx/goodix_tool.c
index 99a29401b36f..1657f56558ce 100644
--- a/drivers/input/touchscreen/gt9xx/goodix_tool.c
+++ b/drivers/input/touchscreen/gt9xx/goodix_tool.c
@@ -236,14 +236,13 @@ static u8 relation(u8 src, u8 dst, u8 rlt)
return ret;
}
-/*******************************************************
+/*
* Function:
- * Comfirm function.
+ * Comfirm function.
* Input:
- * None.
+ * None.
* Output:
* Return write length.
- *******************************************************
*/
static u8 comfirm(void)
{
@@ -301,11 +300,11 @@ static s32 fill_update_info(char __user *user_buf,
* Function:
* Goodix tool write function.
* Input:
- * standard proc write function param.
+ * standard proc write function param.
* Output:
* Return write length.
*/
-static s32 goodix_tool_write(struct file *filp, const char __user *userbuf,
+static ssize_t goodix_tool_write(struct file *filp, const char __user *userbuf,
size_t count, loff_t *ppos)
{
s32 ret = 0;
@@ -318,20 +317,22 @@ static s32 goodix_tool_write(struct file *filp, const char __user *userbuf,
goto exit;
}
- dev_dbg(&gt_client->dev, "wr:0x%02x, flag:0x%02x, flag addr:0x%02x%02x,
- flag val:0x%02x, flag rel:0x%02x,", cmd_headd.wr,
- cmd_head.flag, cmd_head.flag_addr[0],
- cmd_head.flag_addr[1], cmd_head.flag_val,
- cmd_head.flag_relation);
- dev_dbg(&gt_client->dev, "circle:%d, times:%d, retry:%d, delay:%d,
- data len:%d, addr len:%d, addr:0x%02x%02x, write len: %d",
- (s32)cmd_head.circle, (s32)cmd_head.times, (s32)cmd_head.retry,
- (s32)cmd_head.delay, (s32)cmd_head.data_len,
- (s32)cmd_head.addr_len, cmd_head.addr[0], cmd_head.addr[1],
- (s32)count);
+ dev_dbg(&gt_client->dev,
+ "wr: 0x%02x, flag:0x%02x, flag addr:0x%02x%02x\n", cmd_head.wr,
+ cmd_head.flag, cmd_head.flag_addr[0], cmd_head.flag_addr[1]);
+ dev_dbg(&gt_client->dev,
+ "flag val:0x%02x, flag rel:0x%02x,\n", cmd_head.flag_val,
+ cmd_head.flag_relation);
+ dev_dbg(&gt_client->dev, "circle:%u, times:%u, retry:%u, delay:%u\n",
+ (s32) cmd_head.circle, (s32) cmd_head.times,
+ (s32) cmd_head.retry, (s32)cmd_head.delay);
+ dev_dbg(&gt_client->dev,
+ "data len:%u, addr len:%u, addr:0x%02x%02x, write len: %u\n",
+ (s32)cmd_head.data_len, (s32)cmd_head.addr_len,
+ cmd_head.addr[0], cmd_head.addr[1], (s32)count);
if (cmd_head.data_len > (data_length - GTP_ADDR_LENGTH)) {
- dev_err(&gt_client->dev, "data len %d > data buff %d, rejected\n",
+ dev_err(&gt_client->dev, "data len %u > data buff %d, rejected\n",
cmd_head.data_len, (data_length - GTP_ADDR_LENGTH));
ret = -EINVAL;
goto exit;
@@ -383,7 +384,7 @@ static s32 goodix_tool_write(struct file *filp, const char __user *userbuf,
if (cmd_head.data_len > sizeof(ic_type)) {
dev_err(&gt_client->dev,
- "data len %d > data buff %d, rejected\n",
+ "data len %u > data buff %zu, rejected\n",
cmd_head.data_len, sizeof(ic_type));
ret = -EINVAL;
goto exit;
@@ -445,7 +446,7 @@ static s32 goodix_tool_write(struct file *filp, const char __user *userbuf,
show_len = 0;
total_len = 0;
if (cmd_head.data_len + 1 > data_length) {
- dev_err(&gt_client->dev, "data len %d > data buff %d, rejected\n",
+ dev_err(&gt_client->dev, "data len %u > data buff %d, rejected\n",
cmd_head.data_len + 1, data_length);
ret = -EINVAL;
goto exit;
@@ -470,11 +471,11 @@ exit:
* Function:
* Goodix tool read function.
* Input:
- * standard proc read function param.
+ * standard proc read function param.
* Output:
* Return read length.
*/
-static s32 goodix_tool_read(struct file *file, char __user *user_buf,
+static ssize_t goodix_tool_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
u16 data_len = 0;
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.c b/drivers/input/touchscreen/gt9xx/gt9xx.c
index 3b19a45922c4..ead935120624 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx.c
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.c
@@ -48,6 +48,7 @@
#include <linux/module.h>
#include <linux/input/mt.h>
#include <linux/debugfs.h>
+#include <linux/interrupt.h>
#define GOODIX_DEV_NAME "Goodix-CTP"
#define CFG_MAX_TOUCH_POINTS 5
@@ -65,6 +66,8 @@
#define RESET_DELAY_T3_US 200 /* T3: > 100us */
#define RESET_DELAY_T4 20 /* T4: > 5ms */
+#define SLEEP_DELAY_US 5000
+#define WAKE_UP_DELAY_US 5000
#define PHY_BUF_SIZE 32
#define PROP_NAME_SIZE 24
@@ -72,11 +75,6 @@
#define GTP_MAX_TOUCH 5
#define GTP_ESD_CHECK_CIRCLE_MS 2000
-#if GTP_HAVE_TOUCH_KEY
-static const u16 touch_key_array[] = {KEY_MENU, KEY_HOMEPAGE, KEY_BACK};
-
-#endif
-
static void gtp_int_sync(struct goodix_ts_data *ts, int ms);
static int gtp_i2c_test(struct i2c_client *client);
static int goodix_power_off(struct goodix_ts_data *ts);
@@ -99,15 +97,14 @@ static void gtp_esd_check_func(struct work_struct *work);
static int gtp_init_ext_watchdog(struct i2c_client *client);
#endif
-#if GTP_SLIDE_WAKEUP
-enum doze_status {
+enum doze {
DOZE_DISABLED = 0,
DOZE_ENABLED = 1,
DOZE_WAKEUP = 2,
};
-static enum doze_status = DOZE_DISABLED;
+static enum doze doze_status = DOZE_DISABLED;
static s8 gtp_enter_doze(struct goodix_ts_data *ts);
-#endif
+
bool init_done;
static u8 chip_gt9xxs; /* true if ic is gt9xxs, like gt915s */
u8 grp_cfg_version;
@@ -157,11 +154,11 @@ int gtp_i2c_read(struct i2c_client *client, u8 *buf, int len)
dev_err(&client->dev, "I2C retry: %d\n", retries + 1);
}
if (retries == GTP_I2C_RETRY_5) {
-#if GTP_SLIDE_WAKEUP
- /* reset chip would quit doze mode */
- if (doze_status == DOZE_ENABLED)
- return ret;
-#endif
+ if (ts->pdata->slide_wakeup)
+ /* reset chip would quit doze mode */
+ if (doze_status == DOZE_ENABLED)
+ return ret;
+
if (init_done)
gtp_reset_guitar(ts, 10);
else
@@ -203,10 +200,10 @@ int gtp_i2c_write(struct i2c_client *client, u8 *buf, int len)
dev_err(&client->dev, "I2C retry: %d\n", retries + 1);
}
if (retries == GTP_I2C_RETRY_5) {
-#if GTP_SLIDE_WAKEUP
- if (doze_status == DOZE_ENABLED)
- return ret;
-#endif
+ if (ts->pdata->slide_wakeup)
+ if (doze_status == DOZE_ENABLED)
+ return ret;
+
if (init_done)
gtp_reset_guitar(ts, 10);
else
@@ -270,24 +267,25 @@ Output:
*********************************************************/
int gtp_send_cfg(struct goodix_ts_data *ts)
{
- int ret;
-#if GTP_DRIVER_SEND_CFG
- int retry = 0;
+ int ret = 0;
+ int retry;
- if (ts->fixed_cfg) {
- dev_dbg(&ts->client->dev,
- "Ic fixed config, no config sent!");
- ret = 2;
- } else {
- for (retry = 0; retry < GTP_I2C_RETRY_5; retry++) {
- ret = gtp_i2c_write(ts->client,
- ts->config_data,
- GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH);
- if (ret > 0)
- break;
+ if (ts->pdata->driver_send_cfg) {
+ if (ts->fixed_cfg) {
+ dev_dbg(&ts->client->dev,
+ "Ic fixed config, no config sent!");
+ ret = 2;
+ } else {
+ for (retry = 0; retry < GTP_I2C_RETRY_5; retry++) {
+ ret = gtp_i2c_write(ts->client,
+ ts->config_data,
+ GTP_CONFIG_MAX_LENGTH +
+ GTP_ADDR_LENGTH);
+ if (ret > 0)
+ break;
+ }
}
}
-#endif
return ret;
}
@@ -347,9 +345,8 @@ Output:
static void gtp_touch_down(struct goodix_ts_data *ts, int id, int x, int y,
int w)
{
-#if GTP_CHANGE_X2Y
- swap(x, y);
-#endif
+ if (ts->pdata->change_x2y)
+ swap(x, y);
input_mt_slot(ts->input_dev, id);
input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);
@@ -394,9 +391,7 @@ static void goodix_ts_work_func(struct work_struct *work)
u8 finger = 0;
static u16 pre_touch;
static u8 pre_key;
-#if GTP_WITH_PEN
static u8 pre_pen;
-#endif
u8 key_value = 0;
u8 *coor_data = NULL;
s32 input_x = 0;
@@ -406,10 +401,7 @@ static void goodix_ts_work_func(struct work_struct *work)
s32 i = 0;
int ret = -1;
struct goodix_ts_data *ts = NULL;
-
-#if GTP_SLIDE_WAKEUP
u8 doze_buf[3] = {0x81, 0x4B};
-#endif
ts = container_of(work, struct goodix_ts_data, work);
#ifdef CONFIG_GT9XX_TOUCHPANEL_UPDATE
@@ -417,55 +409,59 @@ static void goodix_ts_work_func(struct work_struct *work)
return;
#endif
-#if GTP_SLIDE_WAKEUP
- if (doze_status == DOZE_ENABLED) {
- ret = gtp_i2c_read(ts->client, doze_buf, 3);
- if (ret > 0) {
- if (doze_buf[2] == 0xAA) {
- dev_dbg(&ts->client->dev,
- "Slide(0xAA) To Light up the screen!");
- doze_status = DOZE_WAKEUP;
- input_report_key(
- ts->input_dev, KEY_POWER, 1);
- input_sync(ts->input_dev);
- input_report_key(
- ts->input_dev, KEY_POWER, 0);
- input_sync(ts->input_dev);
- /* clear 0x814B */
- doze_buf[2] = 0x00;
- gtp_i2c_write(ts->client, doze_buf, 3);
- } else if (doze_buf[2] == 0xBB) {
- dev_dbg(&ts->client->dev,
- "Slide(0xBB) To Light up the screen!");
- doze_status = DOZE_WAKEUP;
- input_report_key(ts->input_dev, KEY_POWER, 1);
- input_sync(ts->input_dev);
- input_report_key(ts->input_dev, KEY_POWER, 0);
- input_sync(ts->input_dev);
- /* clear 0x814B*/
- doze_buf[2] = 0x00;
- gtp_i2c_write(ts->client, doze_buf, 3);
- } else if (0xC0 == (doze_buf[2] & 0xC0)) {
- dev_dbg(&ts->client->dev,
- "double click to light up the screen!");
- doze_status = DOZE_WAKEUP;
- input_report_key(ts->input_dev, KEY_POWER, 1);
- input_sync(ts->input_dev);
- input_report_key(ts->input_dev, KEY_POWER, 0);
- input_sync(ts->input_dev);
- /* clear 0x814B */
- doze_buf[2] = 0x00;
- gtp_i2c_write(ts->client, doze_buf, 3);
- } else {
- gtp_enter_doze(ts);
+ if (ts->pdata->slide_wakeup) {
+ if (doze_status == DOZE_ENABLED) {
+ ret = gtp_i2c_read(ts->client, doze_buf, 3);
+ if (ret > 0) {
+ if (doze_buf[2] == 0xAA) {
+ dev_dbg(&ts->client->dev,
+ "Slide(0xAA) To Light up the screen!");
+ doze_status = DOZE_WAKEUP;
+ input_report_key(
+ ts->input_dev, KEY_POWER, 1);
+ input_sync(ts->input_dev);
+ input_report_key(
+ ts->input_dev, KEY_POWER, 0);
+ input_sync(ts->input_dev);
+ /* clear 0x814B */
+ doze_buf[2] = 0x00;
+ gtp_i2c_write(ts->client, doze_buf, 3);
+ } else if (doze_buf[2] == 0xBB) {
+ dev_dbg(&ts->client->dev,
+ "Slide(0xBB) To Light up the screen!");
+ doze_status = DOZE_WAKEUP;
+ input_report_key(ts->input_dev,
+ KEY_POWER, 1);
+ input_sync(ts->input_dev);
+ input_report_key(ts->input_dev,
+ KEY_POWER, 0);
+ input_sync(ts->input_dev);
+ /* clear 0x814B*/
+ doze_buf[2] = 0x00;
+ gtp_i2c_write(ts->client, doze_buf, 3);
+ } else if (0xC0 == (doze_buf[2] & 0xC0)) {
+ dev_dbg(&ts->client->dev,
+ "double click to light up the screen!");
+ doze_status = DOZE_WAKEUP;
+ input_report_key(ts->input_dev,
+ KEY_POWER, 1);
+ input_sync(ts->input_dev);
+ input_report_key(ts->input_dev,
+ KEY_POWER, 0);
+ input_sync(ts->input_dev);
+ /* clear 0x814B */
+ doze_buf[2] = 0x00;
+ gtp_i2c_write(ts->client, doze_buf, 3);
+ } else {
+ gtp_enter_doze(ts);
+ }
}
- }
- if (ts->use_irq)
- gtp_irq_enable(ts);
+ if (ts->use_irq)
+ gtp_irq_enable(ts);
- return;
+ return;
+ }
}
-#endif
ret = gtp_i2c_read(ts->client, point_data, 12);
if (ret < 0) {
@@ -506,15 +502,16 @@ static void goodix_ts_work_func(struct work_struct *work)
pre_key = key_value;
-#if GTP_WITH_PEN
- if (pre_pen && (touch_num == 0)) {
- dev_dbg(&ts->client->dev, "Pen touch UP(Slot)!");
- input_report_key(ts->input_dev, BTN_TOOL_PEN, 0);
- input_mt_slot(ts->input_dev, 5);
- input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1);
- pre_pen = 0;
+ if (ts->pdata->with_pen) {
+ if (pre_pen && (touch_num == 0)) {
+ dev_dbg(&ts->client->dev, "Pen touch UP(Slot)!");
+ input_report_key(ts->input_dev, BTN_TOOL_PEN, 0);
+ input_mt_slot(ts->input_dev, 5);
+ input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1);
+ pre_pen = 0;
+ }
}
-#endif
+
if (pre_touch || touch_num) {
s32 pos = 0;
u16 touch_index = 0;
@@ -522,45 +519,45 @@ static void goodix_ts_work_func(struct work_struct *work)
coor_data = &point_data[3];
if (touch_num) {
id = coor_data[pos] & 0x0F;
-#if GTP_WITH_PEN
- id = coor_data[pos];
- if (id == 128) {
- dev_dbg(&ts->client->dev,
- "Pen touch DOWN(Slot)!");
- input_x = coor_data[pos + 1]
- | (coor_data[pos + 2] << 8);
- input_y = coor_data[pos + 3]
- | (coor_data[pos + 4] << 8);
- input_w = coor_data[pos + 5]
- | (coor_data[pos + 6] << 8);
-
- input_report_key(ts->input_dev,
- BTN_TOOL_PEN, 1);
- input_mt_slot(ts->input_dev, 5);
- input_report_abs(ts->input_dev,
- ABS_MT_TRACKING_ID, 5);
- input_report_abs(ts->input_dev,
- ABS_MT_POSITION_X, input_x);
- input_report_abs(ts->input_dev,
- ABS_MT_POSITION_Y, input_y);
- input_report_abs(ts->input_dev,
- ABS_MT_TOUCH_MAJOR, input_w);
- dev_dbg(&ts->client->dev,
- "Pen/Stylus: (%d, %d)[%d]",
- input_x, input_y, input_w);
- pre_pen = 1;
- pre_touch = 0;
+ if (ts->pdata->with_pen) {
+ id = coor_data[pos];
+ if (id == 128) {
+ dev_dbg(&ts->client->dev,
+ "Pen touch DOWN(Slot)!");
+ input_x = coor_data[pos + 1]
+ | (coor_data[pos + 2] << 8);
+ input_y = coor_data[pos + 3]
+ | (coor_data[pos + 4] << 8);
+ input_w = coor_data[pos + 5]
+ | (coor_data[pos + 6] << 8);
+
+ input_report_key(ts->input_dev,
+ BTN_TOOL_PEN, 1);
+ input_mt_slot(ts->input_dev, 5);
+ input_report_abs(ts->input_dev,
+ ABS_MT_TRACKING_ID, 5);
+ input_report_abs(ts->input_dev,
+ ABS_MT_POSITION_X, input_x);
+ input_report_abs(ts->input_dev,
+ ABS_MT_POSITION_Y, input_y);
+ input_report_abs(ts->input_dev,
+ ABS_MT_TOUCH_MAJOR, input_w);
+ dev_dbg(&ts->client->dev,
+ "Pen/Stylus: (%d, %d)[%d]",
+ input_x, input_y, input_w);
+ pre_pen = 1;
+ pre_touch = 0;
+ }
}
-#endif
touch_index |= (0x01<<id);
}
for (i = 0; i < GTP_MAX_TOUCH; i++) {
-#if GTP_WITH_PEN
- if (pre_pen == 1)
- break;
-#endif
+ if (ts->pdata->with_pen)
+ if (pre_pen == 1)
+ break;
+
if (touch_index & (0x01<<i)) {
input_x = coor_data[pos + 1] |
coor_data[pos + 2] << 8;
@@ -651,7 +648,7 @@ void gtp_reset_guitar(struct goodix_ts_data *ts, int ms)
else
gpio_direction_output(ts->pdata->irq_gpio, 0);
- usleep(RESET_DELAY_T3_US);
+ usleep_range(RESET_DELAY_T3_US, RESET_DELAY_T3_US + 1);
gpio_direction_output(ts->pdata->reset_gpio, 1);
msleep(RESET_DELAY_T4);
@@ -665,7 +662,6 @@ void gtp_reset_guitar(struct goodix_ts_data *ts, int ms)
}
#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_FB)
-#if GTP_SLIDE_WAKEUP
/*******************************************************
Function:
Enter doze mode for sliding wakeup.
@@ -682,9 +678,9 @@ static s8 gtp_enter_doze(struct goodix_ts_data *ts)
(u8)(GTP_REG_SLEEP >> 8),
(u8)GTP_REG_SLEEP, 8};
-#if GTP_DBL_CLK_WAKEUP
- i2c_control_buf[2] = 0x09;
-#endif
+ if (ts->pdata->dbl_clk_wakeup)
+ i2c_control_buf[2] = 0x09;
+
gtp_irq_disable(ts);
while (retry++ < GTP_I2C_RETRY_3) {
@@ -713,7 +709,6 @@ static s8 gtp_enter_doze(struct goodix_ts_data *ts)
gtp_irq_enable(ts);
return ret;
}
-#else
/**
* gtp_enter_sleep - Enter sleep mode
* @ts: driver private data
@@ -746,7 +741,7 @@ static u8 gtp_enter_sleep(struct goodix_ts_data *ts)
}
return 0;
}
- usleep(5000);
+ usleep_range(SLEEP_DELAY_US, SLEEP_DELAY_US + 1);
while (retry++ < GTP_I2C_RETRY_5) {
ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
if (ret == 1) {
@@ -758,7 +753,6 @@ static u8 gtp_enter_sleep(struct goodix_ts_data *ts)
dev_err(&ts->client->dev, "GTP send sleep cmd failed.\n");
return ret;
}
-#endif /* !GTP_SLIDE_WAKEUP */
/*******************************************************
Function:
@@ -804,33 +798,34 @@ static s8 gtp_wakeup_sleep(struct goodix_ts_data *ts)
"Wakeup sleep send config success.");
} else {
err_retry:
-#if GTP_SLIDE_WAKEUP
- /* wakeup not by slide */
- if (doze_status != DOZE_WAKEUP)
- gtp_reset_guitar(ts, 10);
- else
- /* wakeup by slide */
- doze_status = DOZE_DISABLED;
-#else
- if (chip_gt9xxs == 1) {
- gtp_reset_guitar(ts, 10);
+ if (ts->pdata->slide_wakeup) { /* wakeup not by slide */
+ if (doze_status != DOZE_WAKEUP)
+ gtp_reset_guitar(ts, 10);
+ else
+ /* wakeup by slide */
+ doze_status = DOZE_DISABLED;
} else {
- ret = gpio_direction_output(ts->pdata->irq_gpio, 1);
- usleep(5000);
+ if (chip_gt9xxs == 1) {
+ gtp_reset_guitar(ts, 10);
+ } else {
+ ret = gpio_direction_output(
+ ts->pdata->irq_gpio, 1);
+ usleep_range(WAKE_UP_DELAY_US,
+ WAKE_UP_DELAY_US + 1);
+ }
}
-#endif
ret = gtp_i2c_test(ts->client);
if (ret == 2) {
dev_dbg(&ts->client->dev, "GTP wakeup sleep.");
-#if (!GTP_SLIDE_WAKEUP)
- if (chip_gt9xxs == 0) {
- gtp_int_sync(ts, 25);
- msleep(20);
+ if (!ts->pdata->slide_wakeup) {
+ if (chip_gt9xxs == 0) {
+ gtp_int_sync(ts, 25);
+ msleep(20);
#if GTP_ESD_PROTECT
- gtp_init_ext_watchdog(ts->client);
+ gtp_init_ext_watchdog(ts->client);
#endif
+ }
}
-#endif
return ret;
}
gtp_reset_guitar(ts, 20);
@@ -854,123 +849,126 @@ Output:
static int gtp_init_panel(struct goodix_ts_data *ts)
{
struct i2c_client *client = ts->client;
- unsigned char *config_data;
+ unsigned char *config_data = NULL;
int ret = -EIO;
-
-#if GTP_DRIVER_SEND_CFG
int i;
u8 check_sum = 0;
u8 opr_buf[16];
u8 sensor_id = 0;
- for (i = 0; i < GOODIX_MAX_CFG_GROUP; i++)
- dev_dbg(&client->dev, "Config Groups(%d) Lengths: %d",
- i, ts->pdata->config_data_len[i]);
-
- ret = gtp_i2c_read_dbl_check(ts->client, 0x41E4, opr_buf, 1);
- if (ret == SUCCESS) {
- if (opr_buf[0] != 0xBE) {
- ts->fw_error = 1;
- dev_err(&client->dev,
- "Firmware error, no config sent!");
- return -EINVAL;
- }
- }
+ if (ts->pdata->driver_send_cfg) {
+ for (i = 0; i < GOODIX_MAX_CFG_GROUP; i++)
+ dev_dbg(&client->dev, "Config Groups(%d) Lengths: %zu",
+ i, ts->pdata->config_data_len[i]);
- for (i = 1; i < GOODIX_MAX_CFG_GROUP; i++) {
- if (ts->pdata->config_data_len[i])
- break;
- }
- if (i == GOODIX_MAX_CFG_GROUP) {
- sensor_id = 0;
- } else {
- ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID,
- &sensor_id, 1);
+ ret = gtp_i2c_read_dbl_check(ts->client, 0x41E4, opr_buf, 1);
if (ret == SUCCESS) {
- if (sensor_id >= GOODIX_MAX_CFG_GROUP) {
+ if (opr_buf[0] != 0xBE) {
+ ts->fw_error = 1;
dev_err(&client->dev,
- "Invalid sensor_id(0x%02X), No Config Sent!",
- sensor_id);
+ "Firmware error, no config sent!");
return -EINVAL;
}
+ }
+
+ for (i = 1; i < GOODIX_MAX_CFG_GROUP; i++) {
+ if (ts->pdata->config_data_len[i])
+ break;
+ }
+
+ if (i == GOODIX_MAX_CFG_GROUP) {
+ sensor_id = 0;
} else {
- dev_err(&client->dev,
- "Failed to get sensor_id, No config sent!");
- return -EINVAL;
+ ret = gtp_i2c_read_dbl_check(ts->client,
+ GTP_REG_SENSOR_ID, &sensor_id, 1);
+ if (ret == SUCCESS) {
+ if (sensor_id >= GOODIX_MAX_CFG_GROUP) {
+ dev_err(&client->dev,
+ "Invalid sensor_id(0x%02X), No Config Sent!",
+ sensor_id);
+ return -EINVAL;
+ }
+ } else {
+ dev_err(&client->dev,
+ "Failed to get sensor_id, No config sent!");
+ return -EINVAL;
+ }
}
- }
- dev_dbg(&client->dev, "Sensor ID selected: %d", sensor_id);
+ dev_info(&client->dev, "Sensor ID selected: %d", sensor_id);
- if (ts->pdata->config_data_len[sensor_id] < GTP_CONFIG_MIN_LENGTH ||
- !ts->pdata->config_data[sensor_id]) {
- dev_err(&client->dev,
- "Sensor_ID(%d) matches with NULL or invalid config group!\n",
- sensor_id);
- return -EINVAL;
- }
+ if (ts->pdata->config_data_len[sensor_id] <
+ GTP_CONFIG_MIN_LENGTH ||
+ !ts->pdata->config_data[sensor_id]) {
+ dev_err(&client->dev,
+ "Sensor_ID(%d) matches with NULL or invalid config group!\n",
+ sensor_id);
+ return -EINVAL;
+ }
- ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA,
- &opr_buf[0], 1);
- if (ret == SUCCESS) {
- if (opr_buf[0] < 90) {
- /* backup group config version */
- grp_cfg_version =
- ts->pdata->config_data[sensor_id][GTP_ADDR_LENGTH];
- ts->pdata->config_data[sensor_id][GTP_ADDR_LENGTH] =
- 0x00;
- ts->fixed_cfg = 0;
+ ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA,
+ &opr_buf[0], 1);
+ if (ret == SUCCESS) {
+ if (opr_buf[0] < 90) {
+ /* backup group config version */
+ grp_cfg_version =
+ ts->pdata->
+ config_data[sensor_id][GTP_ADDR_LENGTH];
+ ts->pdata->
+ config_data[sensor_id][GTP_ADDR_LENGTH]
+ = 0x00;
+ ts->fixed_cfg = 0;
+ } else {
+ /* treated as fixed config, not send config */
+ dev_warn(&client->dev,
+ "Ic fixed config with config version(%d, 0x%02X)",
+ opr_buf[0], opr_buf[0]);
+ ts->fixed_cfg = 1;
+ }
} else {
- /* treated as fixed config, not send config */
- dev_warn(&client->dev,
- "Ic fixed config with config version(%d, 0x%02X)",
- opr_buf[0], opr_buf[0]);
- ts->fixed_cfg = 1;
+ dev_err(&client->dev,
+ "Failed to get ic config version!No config sent!");
+ return -EINVAL;
}
- } else {
- dev_err(&client->dev,
- "Failed to get ic config version!No config sent!");
- return -EINVAL;
- }
- config_data = ts->pdata->config_data[sensor_id];
- ts->config_data = ts->pdata->config_data[sensor_id];
- ts->gtp_cfg_len = ts->pdata->config_data_len[sensor_id];
+ config_data = ts->pdata->config_data[sensor_id];
+ ts->config_data = ts->pdata->config_data[sensor_id];
+ ts->gtp_cfg_len = ts->pdata->config_data_len[sensor_id];
#if GTP_CUSTOM_CFG
- config_data[RESOLUTION_LOC] =
- (unsigned char)(GTP_MAX_WIDTH && 0xFF);
- config_data[RESOLUTION_LOC + 1] =
- (unsigned char)(GTP_MAX_WIDTH >> 8);
- config_data[RESOLUTION_LOC + 2] =
- (unsigned char)(GTP_MAX_HEIGHT && 0xFF);
- config_data[RESOLUTION_LOC + 3] =
- (unsigned char)(GTP_MAX_HEIGHT >> 8);
-
- if (GTP_INT_TRIGGER == 0)
- config_data[TRIGGER_LOC] &= 0xfe;
- else if (GTP_INT_TRIGGER == 1)
- config_data[TRIGGER_LOC] |= 0x01;
+ config_data[RESOLUTION_LOC] =
+ (unsigned char)(GTP_MAX_WIDTH && 0xFF);
+ config_data[RESOLUTION_LOC + 1] =
+ (unsigned char)(GTP_MAX_WIDTH >> 8);
+ config_data[RESOLUTION_LOC + 2] =
+ (unsigned char)(GTP_MAX_HEIGHT && 0xFF);
+ config_data[RESOLUTION_LOC + 3] =
+ (unsigned char)(GTP_MAX_HEIGHT >> 8);
+
+ if (GTP_INT_TRIGGER == 0)
+ config_data[TRIGGER_LOC] &= 0xfe;
+ else if (GTP_INT_TRIGGER == 1)
+ config_data[TRIGGER_LOC] |= 0x01;
#endif /* !GTP_CUSTOM_CFG */
- check_sum = 0;
- for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++)
- check_sum += config_data[i];
+ check_sum = 0;
+ for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++)
+ check_sum += config_data[i];
- config_data[ts->gtp_cfg_len] = (~check_sum) + 1;
+ config_data[ts->gtp_cfg_len] = (~check_sum) + 1;
-#else /* DRIVER NOT SEND CONFIG */
- ts->gtp_cfg_len = GTP_CONFIG_MAX_LENGTH;
- ret = gtp_i2c_read(ts->client, config_data,
+ } else { /* DRIVER NOT SEND CONFIG */
+ ts->gtp_cfg_len = GTP_CONFIG_MAX_LENGTH;
+ ret = gtp_i2c_read(ts->client, config_data,
ts->gtp_cfg_len + GTP_ADDR_LENGTH);
- if (ret < 0) {
- dev_err(&client->dev,
+ if (ret < 0) {
+ dev_err(&client->dev,
"Read Config Failed, Using DEFAULT Resolution & INT Trigger!\n");
- ts->abs_x_max = GTP_MAX_WIDTH;
- ts->abs_y_max = GTP_MAX_HEIGHT;
- ts->int_trigger_type = GTP_INT_TRIGGER;
- }
-#endif /* !DRIVER NOT SEND CONFIG */
+ ts->abs_x_max = GTP_MAX_WIDTH;
+ ts->abs_y_max = GTP_MAX_HEIGHT;
+ ts->int_trigger_type = GTP_INT_TRIGGER;
+ }
+ } /* !DRIVER NOT SEND CONFIG */
if ((ts->abs_x_max == 0) && (ts->abs_y_max == 0)) {
ts->abs_x_max = (config_data[RESOLUTION_LOC + 1] << 8)
@@ -1177,7 +1175,8 @@ static int gtp_request_irq(struct goodix_ts_data *ts)
int ret;
const u8 irq_table[] = GTP_IRQ_TAB;
- GTP_DEBUG("INT trigger type:%x, irq=%d", ts->int_trigger_type,
+ dev_dbg(&ts->client->dev, "INT trigger type:%x, irq=%d",
+ ts->int_trigger_type,
ts->client->irq);
ret = request_threaded_irq(ts->client->irq, NULL,
@@ -1206,9 +1205,7 @@ static int gtp_request_input_dev(struct goodix_ts_data *ts)
{
int ret;
char phys[PHY_BUF_SIZE];
-#if GTP_HAVE_TOUCH_KEY
int index = 0;
-#endif
ts->input_dev = input_allocate_device();
if (ts->input_dev == NULL) {
@@ -1224,26 +1221,24 @@ static int gtp_request_input_dev(struct goodix_ts_data *ts)
/* in case of "out of memory" */
input_mt_init_slots(ts->input_dev, 10, 0);
- for (index = 0; index < ts->pdata->num_button; index++) {
- input_set_capability(ts->input_dev,
+ if (ts->pdata->have_touch_key) {
+ for (index = 0; index < ts->pdata->num_button; index++) {
+ input_set_capability(ts->input_dev,
EV_KEY, ts->pdata->button_map[index]);
+ }
}
+ if (ts->pdata->slide_wakeup)
+ input_set_capability(ts->input_dev, EV_KEY, KEY_POWER);
-#if GTP_SLIDE_WAKEUP
- input_set_capability(ts->input_dev, EV_KEY, KEY_POWER);
-#endif
-
-#if GTP_WITH_PEN
- /* pen support */
- __set_bit(BTN_TOOL_PEN, ts->input_dev->keybit);
- __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
- __set_bit(INPUT_PROP_POINTER, ts->input_dev->propbit);
-#endif
+ if (ts->pdata->with_pen) { /* pen support */
+ __set_bit(BTN_TOOL_PEN, ts->input_dev->keybit);
+ __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+ __set_bit(INPUT_PROP_POINTER, ts->input_dev->propbit);
+ }
-#if GTP_CHANGE_X2Y
- swap(ts->abs_x_max, ts->abs_y_max);
-#endif
+ if (ts->pdata->change_x2y)
+ swap(ts->abs_x_max, ts->abs_y_max);
input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,
0, ts->abs_x_max, 0, 0);
@@ -1283,7 +1278,7 @@ exit_free_inputdev:
static int reg_set_optimum_mode_check(struct regulator *reg, int load_uA)
{
return (regulator_count_voltages(reg) > 0) ?
- regulator_set_optimum_mode(reg, load_uA) : 0;
+ regulator_set_load(reg, load_uA) : 0;
}
/**
@@ -1828,7 +1823,7 @@ static int goodix_parse_dt(struct device *dev,
u32 temp_val, num_buttons;
u32 button_map[MAX_BUTTONS];
char prop_name[PROP_NAME_SIZE];
- int i, read_cfg_num;
+ int i, read_cfg_num, temp;
rc = goodix_ts_get_dt_coords(dev, "goodix,panel-coords", pdata);
if (rc && (rc != -EINVAL))
@@ -1846,6 +1841,25 @@ static int goodix_parse_dt(struct device *dev,
pdata->enable_power_off = of_property_read_bool(np,
"goodix,enable-power-off");
+
+ pdata->have_touch_key = of_property_read_bool(np,
+ "goodix,have-touch-key");
+
+ pdata->driver_send_cfg = of_property_read_bool(np,
+ "goodix,driver-send-cfg");
+
+ pdata->change_x2y = of_property_read_bool(np,
+ "goodix,change-x2y");
+
+ pdata->with_pen = of_property_read_bool(np,
+ "goodix,with-pen");
+
+ pdata->slide_wakeup = of_property_read_bool(np,
+ "goodix,slide-wakeup");
+
+ pdata->dbl_clk_wakeup = of_property_read_bool(np,
+ "goodix,dbl_clk_wakeup");
+
/* reset, irq gpio info */
pdata->reset_gpio = of_get_named_gpio_flags(np, "reset-gpios",
0, &pdata->reset_gpio_flags);
@@ -1891,14 +1905,15 @@ static int goodix_parse_dt(struct device *dev,
read_cfg_num = 0;
for (i = 0; i < GOODIX_MAX_CFG_GROUP; i++) {
+ temp = 0;
snprintf(prop_name, sizeof(prop_name), "goodix,cfg-data%d", i);
- prop = of_find_property(np, prop_name,
- &pdata->config_data_len[i]);
+ prop = of_find_property(np, prop_name, &temp);
if (!prop || !prop->value) {
pdata->config_data_len[i] = 0;
pdata->config_data[i] = NULL;
continue;
}
+ pdata->config_data_len[i] = temp;
pdata->config_data[i] = devm_kzalloc(dev,
GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH,
GFP_KERNEL);
@@ -2101,8 +2116,6 @@ exit_free_irq:
#endif
if (ts->use_irq)
free_irq(client->irq, ts);
- else
- hrtimer_cancel(&ts->timer);
cancel_work_sync(&ts->work);
flush_workqueue(ts->goodix_wq);
destroy_workqueue(ts->goodix_wq);
@@ -2166,8 +2179,6 @@ static int goodix_ts_remove(struct i2c_client *client)
if (ts) {
if (ts->use_irq)
free_irq(client->irq, ts);
- else
- hrtimer_cancel(&ts->timer);
cancel_work_sync(&ts->work);
flush_workqueue(ts->goodix_wq);
@@ -2225,23 +2236,21 @@ static int goodix_ts_suspend(struct device *dev)
gtp_esd_switch(ts->client, SWITCH_OFF);
#endif
-#if GTP_SLIDE_WAKEUP
- ret = gtp_enter_doze(ts);
-#else
- if (ts->use_irq)
- gtp_irq_disable(ts);
- else
- hrtimer_cancel(&ts->timer);
+ if (ts->pdata->slide_wakeup) {
+ ret = gtp_enter_doze(ts);
+ } else {
+ if (ts->use_irq)
+ gtp_irq_disable(ts);
- for (i = 0; i < GTP_MAX_TOUCH; i++)
- gtp_touch_up(ts, i);
+ for (i = 0; i < GTP_MAX_TOUCH; i++)
+ gtp_touch_up(ts, i);
- input_sync(ts->input_dev);
+ input_sync(ts->input_dev);
- ret = gtp_enter_sleep(ts);
-#endif
- if (ret < 0)
- dev_err(&ts->client->dev, "GTP early suspend failed\n");
+ ret = gtp_enter_sleep(ts);
+ if (ret < 0)
+ dev_err(&ts->client->dev, "GTP early suspend failed.\n");
+ }
/* to avoid waking up while not sleeping,
* delay 48 + 10ms to ensure reliability
*/
@@ -2273,18 +2282,14 @@ static int goodix_ts_resume(struct device *dev)
mutex_lock(&ts->lock);
ret = gtp_wakeup_sleep(ts);
-#if GTP_SLIDE_WAKEUP
- doze_status = DOZE_DISABLED;
-#endif
+ if (ts->pdata->slide_wakeup)
+ doze_status = DOZE_DISABLED;
if (ret <= 0)
dev_err(&ts->client->dev, "GTP resume failed\n");
if (ts->use_irq)
gtp_irq_enable(ts);
- else
- hrtimer_start(&ts->timer,
- ktime_set(1, 0), HRTIMER_MODE_REL);
#if GTP_ESD_PROTECT
gtp_esd_switch(ts->client, SWITCH_ON);
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.h b/drivers/input/touchscreen/gt9xx/gt9xx.h
index 779a0ddd93f8..1e85e2fce276 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx.h
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.h
@@ -60,6 +60,12 @@ struct goodix_ts_platform_data {
u8 *config_data[GOODIX_MAX_CFG_GROUP];
u32 button_map[MAX_BUTTONS];
u8 num_button;
+ bool have_touch_key;
+ bool driver_send_cfg;
+ bool change_x2y;
+ bool with_pen;
+ bool slide_wakeup;
+ bool dbl_clk_wakeup;
};
struct goodix_ts_data {
spinlock_t irq_lock;
@@ -69,6 +75,7 @@ struct goodix_ts_data {
struct hrtimer timer;
struct workqueue_struct *goodix_wq;
struct work_struct work;
+ char fw_name[GTP_FW_NAME_MAXSIZE];
struct delayed_work goodix_update_work;
s32 irq_is_disabled;
s32 use_irq;
@@ -107,17 +114,7 @@ extern u16 total_len;
/***************************PART1:ON/OFF define*******************************/
#define GTP_CUSTOM_CFG 0
-#define GTP_CHANGE_X2Y 0
-#define GTP_DRIVER_SEND_CFG 1
-#define GTP_HAVE_TOUCH_KEY 1
-
#define GTP_ESD_PROTECT 0
-#define GTP_WITH_PEN 0
-
-/* This cannot work when enable-power-off is on */
-#define GTP_SLIDE_WAKEUP 0
-/* double-click wakeup, function together with GTP_SLIDE_WAKEUP */
-#define GTP_DBL_CLK_WAKEUP 0
#define GTP_IRQ_TAB {\
IRQ_TYPE_EDGE_RISING,\
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx_update.c b/drivers/input/touchscreen/gt9xx/gt9xx_update.c
index a91256c576e3..6bc243492272 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx_update.c
+++ b/drivers/input/touchscreen/gt9xx/gt9xx_update.c
@@ -67,6 +67,8 @@
#define FAIL 0
#define SUCCESS 1
+#define RESET_DELAY_US 20000
+
struct st_fw_head {
u8 hw_info[4]; /* hardware info */
u8 pid[8]; /* product id */
@@ -390,7 +392,7 @@ s32 gup_enter_update_mode(struct i2c_client *client)
/* step1:RST output low last at least 2ms */
gpio_direction_output(ts->pdata->reset_gpio, 0);
- usleep(20000);
+ usleep_range(RESET_DELAY_US, RESET_DELAY_US + 1);
/* step2:select I2C slave addr,INT:0--0xBA;1--0x28. */
gpio_direction_output(ts->pdata->irq_gpio,
@@ -565,8 +567,8 @@ static s8 gup_update_config(struct i2c_client *client,
!memcmp(&pid[GTP_ADDR_LENGTH], "960", 3)) {
chip_cfg_len = 228;
}
- pr_debug("config file ASCII len:%d", cfg->size);
- pr_debug("need config binary len:%d", chip_cfg_len);
+ pr_debug("config file ASCII len: %zu", cfg->size);
+ pr_debug("need config binary len: %u", chip_cfg_len);
if ((cfg->size + 5) < chip_cfg_len * 5) {
pr_err("Config length error");
return -EINVAL;
@@ -643,7 +645,7 @@ static s32 gup_get_firmware_file(struct i2c_client *client,
return -EEXIST;
}
- dev_dbg(&client->dev, "Config File: %s size=%d", path, fw->size);
+ dev_dbg(&client->dev, "Config File: %s size: %zu", path, fw->size);
msg->fw_data =
devm_kzalloc(&client->dev, fw->size, GFP_KERNEL);
if (!msg->fw_data) {
diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c
index bc94dff08d21..325bdb35e8a3 100644
--- a/drivers/leds/leds-qpnp-flash-v2.c
+++ b/drivers/leds/leds-qpnp-flash-v2.c
@@ -82,6 +82,8 @@
#define VPH_DROOP_THRESH_MV_TO_VAL(val_mv) ((val_mv / 100) - 25)
#define VPH_DROOP_THRESH_VAL_TO_UV(val) ((val + 25) * 100000)
#define MITIGATION_THRSH_MA_TO_VAL(val_ma) (val_ma / 100)
+#define CURRENT_MA_TO_REG_VAL(curr_ma, ires_ua) ((curr_ma * 1000) / ires_ua - 1)
+#define SAFETY_TMR_TO_REG_VAL(duration_ms) ((duration_ms / 10) - 1)
#define FLASH_LED_ISC_WARMUP_DELAY_SHIFT 6
#define FLASH_LED_WARMUP_DELAY_DEFAULT 2
@@ -97,8 +99,6 @@
#define FLASH_LED_VLED_MAX_DEFAULT_UV 3500000
#define FLASH_LED_IBATT_OCP_THRESH_DEFAULT_UA 4500000
#define FLASH_LED_RPARA_DEFAULT_UOHM 0
-#define FLASH_LED_SAFETY_TMR_VAL_OFFSET 1
-#define FLASH_LED_SAFETY_TMR_VAL_DIVISOR 10
#define FLASH_LED_SAFETY_TMR_ENABLE BIT(7)
#define FLASH_LED_LMH_LEVEL_DEFAULT 0
#define FLASH_LED_LMH_MITIGATION_ENABLE 1
@@ -738,7 +738,8 @@ static void qpnp_flash_led_node_set(struct flash_node_data *fnode, int value)
prgm_current_ma = min(prgm_current_ma, fnode->max_current);
fnode->current_ma = prgm_current_ma;
fnode->cdev.brightness = prgm_current_ma;
- fnode->current_reg_val = prgm_current_ma * 1000 / fnode->ires_ua + 1;
+ fnode->current_reg_val = CURRENT_MA_TO_REG_VAL(prgm_current_ma,
+ fnode->ires_ua);
fnode->led_on = prgm_current_ma != 0;
}
@@ -1341,9 +1342,7 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
fnode->duration = FLASH_LED_SAFETY_TMR_DISABLED;
rc = of_property_read_u32(node, "qcom,duration-ms", &val);
if (!rc) {
- fnode->duration = (u8)(((val -
- FLASH_LED_SAFETY_TMR_VAL_OFFSET) /
- FLASH_LED_SAFETY_TMR_VAL_DIVISOR) |
+ fnode->duration = (u8)(SAFETY_TMR_TO_REG_VAL(val) |
FLASH_LED_SAFETY_TMR_ENABLE);
} else if (rc == -EINVAL) {
if (fnode->type == FLASH_LED_TYPE_FLASH) {
diff --git a/drivers/leds/leds-qpnp-wled.c b/drivers/leds/leds-qpnp-wled.c
index d9626c29ce76..894c1d88b3ef 100644
--- a/drivers/leds/leds-qpnp-wled.c
+++ b/drivers/leds/leds-qpnp-wled.c
@@ -25,6 +25,7 @@
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/leds-qpnp-wled.h>
+#include <linux/qpnp/qpnp-revid.h>
#define QPNP_IRQ_FLAGS (IRQF_TRIGGER_RISING | \
IRQF_TRIGGER_FALLING | \
@@ -44,15 +45,19 @@
#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)
#define QPNP_WLED_REF_7P7_TRIM_REG(b) (b + 0xF2)
+#define QPNP_WLED_7P7_TRIM_MASK GENMASK(3, 0)
#define QPNP_WLED_EN_MASK 0x7F
#define QPNP_WLED_EN_SHIFT 7
#define QPNP_WLED_FDBK_OP_MASK 0xF8
@@ -79,16 +84,16 @@
#define QPNP_WLED_VREF_PSM_MAX_MV 750
#define QPNP_WLED_VREF_PSM_DFLT_AMOLED_MV 450
#define QPNP_WLED_PSM_CTRL_OVERWRITE 0x80
-#define QPNP_WLED_AVDD_MIN_TRIM_VALUE -7
-#define QPNP_WLED_AVDD_MAX_TRIM_VALUE 8
-#define QPNP_WLED_AVDD_TRIM_CENTER_VALUE 7
-
-#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
@@ -98,11 +103,7 @@
#define QPNP_WLED_SWITCH_FREQ_800_KHZ 800
#define QPNP_WLED_SWITCH_FREQ_1600_KHZ 1600
#define QPNP_WLED_SWITCH_FREQ_OVERWRITE 0x80
-#define QPNP_WLED_OVP_MASK 0xFC
-#define QPNP_WLED_OVP_17800_MV 17800
-#define QPNP_WLED_OVP_19400_MV 19400
-#define QPNP_WLED_OVP_29500_MV 29500
-#define QPNP_WLED_OVP_31000_MV 31000
+#define QPNP_WLED_OVP_MASK GENMASK(1, 0)
#define QPNP_WLED_TEST4_EN_VREF_UP 0x32
#define QPNP_WLED_INT_EN_SET_OVP_EN 0x02
#define QPNP_WLED_OVP_FLT_SLEEP_US 10
@@ -198,6 +199,22 @@
#define QPNP_WLED_MIN_MSLEEP 20
#define QPNP_WLED_SC_DLY_MS 20
+#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 {
QPNP_WLED_FDBK_AUTO,
@@ -230,10 +247,38 @@ static u8 qpnp_wled_sink_dbg_regs[] = {
0xe6,
};
+static int qpnp_wled_avdd_target_voltages[NUM_SUPPORTED_AVDD_VOLTAGES] = {
+ 7900, 7600, 7300, 6400, 6100, 5800,
+};
+
+static u8 qpnp_wled_ovp_reg_settings[NUM_SUPPORTED_AVDD_VOLTAGES] = {
+ 0x0, 0x0, 0x1, 0x2, 0x2, 0x3,
+};
+
+static int qpnp_wled_avdd_trim_adjustments[NUM_SUPPORTED_AVDD_VOLTAGES] = {
+ 3, 0, -2, 7, 3, 3,
+};
+
+static int qpnp_wled_ovp_thresholds_pmi8994[NUM_SUPPORTED_OVP_THRESHOLDS] = {
+ 31000, 29500, 19400, 17800,
+};
+
+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
- * @ spmi - spmi device
+ * @ pdev - platform device
* @ work - worker for led operation
* @ lock - mutex lock for exclusive access
* @ fdbk_op - output feedback mode
@@ -241,7 +286,7 @@ static u8 qpnp_wled_sink_dbg_regs[] = {
* @ ovp_irq - over voltage protection irq
* @ sc_irq - short circuit irq
* @ sc_cnt - short circuit irq count
- * @ avdd_trim_steps_from_center - number of steps to trim from center value
+ * @ avdd_target_voltage_mv - target voltage for AVDD module in mV
* @ ctrl_base - base address for wled ctrl
* @ sink_base - base address for wled sink
* @ ibb_base - base address for IBB(Inverting Buck Boost)
@@ -264,6 +309,7 @@ static u8 qpnp_wled_sink_dbg_regs[] = {
* @ 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
@@ -276,14 +322,16 @@ struct qpnp_wled {
struct led_classdev cdev;
struct platform_device *pdev;
struct regmap *regmap;
+ struct pmic_revid_data *pmic_rev_id;
struct work_struct work;
struct mutex lock;
+ struct mutex bus_lock;
enum qpnp_wled_fdbk_op fdbk_op;
enum qpnp_wled_dim_mode dim_mode;
int ovp_irq;
int sc_irq;
u32 sc_cnt;
- u32 avdd_trim_steps_from_center;
+ u32 avdd_target_voltage_mv;
u16 ctrl_base;
u16 sink_base;
u16 mod_freq_khz;
@@ -304,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;
@@ -319,39 +368,79 @@ static int qpnp_wled_read_reg(struct qpnp_wled *wled, u8 *data, u16 addr)
uint val;
rc = regmap_read(wled->regmap, addr, &val);
- if (rc < 0)
+ if (rc < 0) {
dev_err(&wled->pdev->dev,
"Error reading address: %x(%d)\n", addr, rc);
+ return rc;
+ }
+
*data = (u8)val;
- return rc;
+ return 0;
}
/* helper to write a pmic register */
-static int qpnp_wled_write_reg(struct qpnp_wled *wled, u8 *data, u16 addr)
+static int qpnp_wled_write_reg(struct qpnp_wled *wled, u8 data, u16 addr)
{
int rc;
- rc = regmap_write(wled->regmap, addr, *data);
+ mutex_lock(&wled->bus_lock);
+ rc = regmap_write(wled->regmap, addr, data);
+ if (rc < 0) {
+ dev_err(&wled->pdev->dev, "Error writing address: %x(%d)\n",
+ addr, rc);
+ goto out;
+ }
+
+ dev_dbg(&wled->pdev->dev, "wrote: WLED_0x%x = 0x%x\n", addr, data);
+out:
+ mutex_unlock(&wled->bus_lock);
+ return rc;
+}
+
+static int qpnp_wled_masked_write_reg(struct qpnp_wled *wled, u8 mask, u8 *data,
+ u16 addr)
+{
+ u8 reg;
+ int rc;
+
+ rc = qpnp_wled_read_reg(wled, &reg, addr);
if (rc < 0)
- dev_err(&wled->pdev->dev,
- "Error writing address: %x(%d)\n", addr, rc);
+ return rc;
+
+ reg &= ~mask;
+ reg |= *data & mask;
- dev_dbg(&wled->pdev->dev, "write: WLED_0x%x = 0x%x\n", addr, *data);
+ rc = qpnp_wled_write_reg(wled, reg, addr);
return rc;
}
-static int qpnp_wled_sec_access(struct qpnp_wled *wled, u16 base_addr)
+static int qpnp_wled_sec_write_reg(struct qpnp_wled *wled, u8 data, u16 addr)
{
int rc;
u8 reg = QPNP_WLED_SEC_UNLOCK;
+ u16 base_addr = addr & 0xFF00;
- rc = qpnp_wled_write_reg(wled, &reg,
- QPNP_WLED_SEC_ACCESS_REG(base_addr));
- if (rc)
- return rc;
+ mutex_lock(&wled->bus_lock);
+ rc = regmap_write(wled->regmap, QPNP_WLED_SEC_ACCESS_REG(base_addr),
+ reg);
+ if (rc < 0) {
+ dev_err(&wled->pdev->dev, "Error writing address: %x(%d)\n",
+ QPNP_WLED_SEC_ACCESS_REG(base_addr), rc);
+ goto out;
+ }
- return 0;
+ rc = regmap_write(wled->regmap, addr, data);
+ if (rc < 0) {
+ dev_err(&wled->pdev->dev, "Error writing address: %x(%d)\n",
+ addr, rc);
+ goto out;
+ }
+
+ dev_dbg(&wled->pdev->dev, "wrote: WLED_0x%x = 0x%x\n", addr, data);
+out:
+ mutex_unlock(&wled->bus_lock);
+ return rc;
}
static int qpnp_wled_sync_reg_toggle(struct qpnp_wled *wled)
@@ -361,7 +450,7 @@ static int qpnp_wled_sync_reg_toggle(struct qpnp_wled *wled)
/* sync */
reg = QPNP_WLED_SYNC;
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_write_reg(wled, reg,
QPNP_WLED_SYNC_REG(wled->sink_base));
if (rc < 0)
return rc;
@@ -371,7 +460,7 @@ static int qpnp_wled_sync_reg_toggle(struct qpnp_wled *wled)
wled->cons_sync_write_delay_us + 1);
reg = QPNP_WLED_SYNC_RESET;
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_write_reg(wled, reg,
QPNP_WLED_SYNC_REG(wled->sink_base));
if (rc < 0)
return rc;
@@ -388,7 +477,7 @@ static int qpnp_wled_set_level(struct qpnp_wled *wled, int level)
/* set brightness registers */
for (i = 0; i < wled->num_strings; i++) {
reg = level & QPNP_WLED_BRIGHT_LSB_MASK;
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_write_reg(wled, reg,
QPNP_WLED_BRIGHT_LSB_REG(wled->sink_base,
wled->strings[i]));
if (rc < 0)
@@ -396,7 +485,7 @@ static int qpnp_wled_set_level(struct qpnp_wled *wled, int level)
reg = level >> QPNP_WLED_BRIGHT_MSB_SHIFT;
reg = reg & QPNP_WLED_BRIGHT_MSB_MASK;
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_write_reg(wled, reg,
QPNP_WLED_BRIGHT_MSB_REG(wled->sink_base,
wled->strings[i]));
if (rc < 0)
@@ -421,7 +510,7 @@ static int qpnp_wled_module_en(struct qpnp_wled *wled,
/* disable OVP fault interrupt */
if (state) {
reg = QPNP_WLED_INT_EN_SET_OVP_EN;
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_write_reg(wled, reg,
QPNP_WLED_INT_EN_CLR(base_addr));
if (rc)
return rc;
@@ -433,7 +522,7 @@ static int qpnp_wled_module_en(struct qpnp_wled *wled,
return rc;
reg &= QPNP_WLED_MODULE_EN_MASK;
reg |= (state << QPNP_WLED_MODULE_EN_SHIFT);
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_write_reg(wled, reg,
QPNP_WLED_MODULE_EN_REG(base_addr));
if (rc)
return rc;
@@ -442,7 +531,7 @@ static int qpnp_wled_module_en(struct qpnp_wled *wled,
if (state && (wled->ovp_irq > 0)) {
udelay(QPNP_WLED_OVP_FLT_SLEEP_US);
reg = QPNP_WLED_INT_EN_SET_OVP_EN;
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_write_reg(wled, reg,
QPNP_WLED_INT_EN_SET(base_addr));
if (rc)
return rc;
@@ -678,7 +767,7 @@ static ssize_t qpnp_wled_dim_mode_store(struct device *dev,
reg |= temp;
}
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_write_reg(wled, reg,
QPNP_WLED_MOD_REG(wled->sink_base));
if (rc)
return rc;
@@ -722,7 +811,7 @@ static ssize_t qpnp_wled_fs_curr_ua_store(struct device *dev,
reg &= QPNP_WLED_FS_CURR_MASK;
temp = data / QPNP_WLED_FS_CURR_STEP_UA;
reg |= temp;
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_write_reg(wled, reg,
QPNP_WLED_FS_CURR_REG(wled->sink_base,
wled->strings[i]));
if (rc)
@@ -838,11 +927,7 @@ static int qpnp_wled_set_disp(struct qpnp_wled *wled, u16 base_addr)
reg &= QPNP_WLED_DISP_SEL_MASK;
reg |= (wled->disp_type_amoled << QPNP_WLED_DISP_SEL_SHIFT);
- rc = qpnp_wled_sec_access(wled, base_addr);
- if (rc)
- return rc;
-
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_sec_write_reg(wled, reg,
QPNP_WLED_DISP_SEL_REG(base_addr));
if (rc)
return rc;
@@ -863,7 +948,7 @@ static int qpnp_wled_set_disp(struct qpnp_wled *wled, u16 base_addr)
reg |= ((wled->vref_psm_mv - QPNP_WLED_VREF_PSM_MIN_MV)/
QPNP_WLED_VREF_PSM_STEP_MV);
reg |= QPNP_WLED_PSM_CTRL_OVERWRITE;
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_write_reg(wled, reg,
QPNP_WLED_PSM_CTRL_REG(wled->ctrl_base));
if (rc)
return rc;
@@ -887,7 +972,7 @@ static int qpnp_wled_set_disp(struct qpnp_wled *wled, u16 base_addr)
QPNP_WLED_LOOP_COMP_RES_MIN_KOHM)/
QPNP_WLED_LOOP_COMP_RES_STEP_KOHM);
reg |= QPNP_WLED_VLOOP_COMP_RES_OVERWRITE;
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_write_reg(wled, reg,
QPNP_WLED_VLOOP_COMP_RES_REG(wled->ctrl_base));
if (rc)
return rc;
@@ -905,7 +990,7 @@ static int qpnp_wled_set_disp(struct qpnp_wled *wled, u16 base_addr)
reg &= QPNP_WLED_VLOOP_COMP_GM_MASK;
reg |= (wled->loop_ea_gm | QPNP_WLED_VLOOP_COMP_GM_OVERWRITE);
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_write_reg(wled, reg,
QPNP_WLED_VLOOP_COMP_GM_REG(wled->ctrl_base));
if (rc)
return rc;
@@ -916,12 +1001,8 @@ static int qpnp_wled_set_disp(struct qpnp_wled *wled, u16 base_addr)
if (rc < 0)
return rc;
- rc = qpnp_wled_sec_access(wled, base_addr);
- if (rc)
- return rc;
-
reg |= QPNP_WLED_TEST4_EN_IIND_UP;
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_sec_write_reg(wled, reg,
QPNP_WLED_TEST4_REG(base_addr));
if (rc)
return rc;
@@ -929,12 +1010,8 @@ static int qpnp_wled_set_disp(struct qpnp_wled *wled, u16 base_addr)
/*
* enable VREF_UP to avoid false ovp on low brightness for LCD
*/
- rc = qpnp_wled_sec_access(wled, base_addr);
- if (rc)
- return rc;
-
reg = QPNP_WLED_TEST4_EN_VREF_UP;
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_sec_write_reg(wled, reg,
QPNP_WLED_TEST4_REG(base_addr));
if (rc)
return rc;
@@ -968,6 +1045,209 @@ static irqreturn_t qpnp_wled_sc_irq(int irq, void *_wled)
return IRQ_HANDLED;
}
+static bool is_avdd_trim_adjustment_required(struct qpnp_wled *wled)
+{
+ int rc;
+ u8 reg = 0;
+
+ /*
+ * AVDD trim adjustment is not required for pmicobalt/pm2falcon and not
+ * supported for pmi8994.
+ */
+ if (wled->pmic_rev_id->pmic_subtype == PMICOBALT_SUBTYPE ||
+ wled->pmic_rev_id->pmic_subtype == PM2FALCON_SUBTYPE ||
+ wled->pmic_rev_id->pmic_subtype == PMI8994_SUBTYPE)
+ return false;
+
+ /*
+ * Configure TRIM_REG only if disp_type_amoled and it has
+ * not already been programmed by bootloader.
+ */
+ if (!wled->disp_type_amoled)
+ return false;
+
+ rc = qpnp_wled_read_reg(wled, &reg,
+ QPNP_WLED_CTRL_SPARE_REG(wled->ctrl_base));
+ if (rc < 0)
+ return false;
+
+ return !(reg & QPNP_WLED_AVDD_SET_BIT);
+}
+
+static int qpnp_wled_ovp_config(struct qpnp_wled *wled)
+{
+ int rc, i, *ovp_table;
+ u8 reg;
+
+ /*
+ * Configure the OVP register based on ovp_mv only if display type is
+ * not AMOLED.
+ */
+ if (wled->disp_type_amoled)
+ return 0;
+
+ if (wled->pmic_rev_id->pmic_subtype == PMICOBALT_SUBTYPE ||
+ wled->pmic_rev_id->pmic_subtype == PM2FALCON_SUBTYPE)
+ ovp_table = qpnp_wled_ovp_thresholds_pmicobalt;
+ else
+ ovp_table = qpnp_wled_ovp_thresholds_pmi8994;
+
+ for (i = 0; i < NUM_SUPPORTED_OVP_THRESHOLDS; i++) {
+ if (wled->ovp_mv == ovp_table[i])
+ break;
+ }
+
+ if (i == NUM_SUPPORTED_OVP_THRESHOLDS) {
+ dev_err(&wled->pdev->dev,
+ "Invalid ovp threshold specified in device tree\n");
+ return -EINVAL;
+ }
+
+ reg = i & QPNP_WLED_OVP_MASK;
+ rc = qpnp_wled_masked_write_reg(wled, QPNP_WLED_OVP_MASK, &reg,
+ QPNP_WLED_OVP_REG(wled->ctrl_base));
+ if (rc)
+ return rc;
+
+ 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)
{
@@ -986,7 +1266,7 @@ static int qpnp_wled_config(struct qpnp_wled *wled)
return rc;
reg &= QPNP_WLED_FDBK_OP_MASK;
reg |= wled->fdbk_op;
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_write_reg(wled, reg,
QPNP_WLED_FDBK_OP_REG(wled->ctrl_base));
if (rc)
return rc;
@@ -1004,35 +1284,21 @@ static int qpnp_wled_config(struct qpnp_wled *wled)
reg &= QPNP_WLED_VREF_MASK;
temp = wled->vref_mv - QPNP_WLED_VREF_MIN_MV;
reg |= (temp / QPNP_WLED_VREF_STEP_MV);
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_write_reg(wled, reg,
QPNP_WLED_VREF_REG(wled->ctrl_base));
if (rc)
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 */
reg = (wled->disp_type_amoled) ? 0 : 2;
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_write_reg(wled, reg,
QPNP_WLED_SOFTSTART_RAMP_DLY(wled->ctrl_base));
if (rc)
return rc;
@@ -1049,7 +1315,7 @@ static int qpnp_wled_config(struct qpnp_wled *wled)
return rc;
reg &= QPNP_WLED_BOOST_DUTY_MASK;
reg |= (wled->boost_duty_ns / QPNP_WLED_BOOST_DUTY_STEP_NS);
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_write_reg(wled, reg,
QPNP_WLED_BOOST_DUTY_REG(wled->ctrl_base));
if (rc)
return rc;
@@ -1066,62 +1332,27 @@ static int qpnp_wled_config(struct qpnp_wled *wled)
return rc;
reg &= QPNP_WLED_SWITCH_FREQ_MASK;
reg |= (temp | QPNP_WLED_SWITCH_FREQ_OVERWRITE);
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_write_reg(wled, reg,
QPNP_WLED_SWITCH_FREQ_REG(wled->ctrl_base));
if (rc)
return rc;
- /* Configure the OVP register */
- if (wled->ovp_mv <= QPNP_WLED_OVP_17800_MV) {
- wled->ovp_mv = QPNP_WLED_OVP_17800_MV;
- temp = 3;
- } else if (wled->ovp_mv <= QPNP_WLED_OVP_19400_MV) {
- wled->ovp_mv = QPNP_WLED_OVP_19400_MV;
- temp = 2;
- } else if (wled->ovp_mv <= QPNP_WLED_OVP_29500_MV) {
- wled->ovp_mv = QPNP_WLED_OVP_29500_MV;
- temp = 1;
- } else {
- wled->ovp_mv = QPNP_WLED_OVP_31000_MV;
- temp = 0;
- }
-
- rc = qpnp_wled_read_reg(wled, &reg,
- QPNP_WLED_OVP_REG(wled->ctrl_base));
- if (rc < 0)
- return rc;
- reg &= QPNP_WLED_OVP_MASK;
- reg |= temp;
- rc = qpnp_wled_write_reg(wled, &reg,
- QPNP_WLED_OVP_REG(wled->ctrl_base));
- if (rc)
+ rc = qpnp_wled_ovp_config(wled);
+ if (rc < 0) {
+ pr_err("Error in configuring OVP threshold, rc=%d\n", rc);
return rc;
+ }
- if (wled->disp_type_amoled) {
- /* Configure avdd trim register */
- rc = qpnp_wled_sec_access(wled, wled->ctrl_base);
- if (rc)
- return rc;
-
- /* Check if wled->avdd_trim_steps_from_center is negative */
- if ((s32)wled->avdd_trim_steps_from_center <
- QPNP_WLED_AVDD_MIN_TRIM_VALUE) {
- wled->avdd_trim_steps_from_center =
- QPNP_WLED_AVDD_MIN_TRIM_VALUE;
- } else if ((s32)wled->avdd_trim_steps_from_center >
- QPNP_WLED_AVDD_MAX_TRIM_VALUE) {
- wled->avdd_trim_steps_from_center =
- QPNP_WLED_AVDD_MAX_TRIM_VALUE;
- }
- reg = wled->avdd_trim_steps_from_center +
- QPNP_WLED_AVDD_TRIM_CENTER_VALUE;
-
- rc = qpnp_wled_write_reg(wled, &reg,
- QPNP_WLED_REF_7P7_TRIM_REG(wled->ctrl_base));
- if (rc)
+ if (is_avdd_trim_adjustment_required(wled)) {
+ 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;
@@ -1166,7 +1397,7 @@ static int qpnp_wled_config(struct qpnp_wled *wled)
reg |= wled->dim_mode;
}
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_write_reg(wled, reg,
QPNP_WLED_MOD_REG(wled->sink_base));
if (rc)
return rc;
@@ -1184,7 +1415,7 @@ static int qpnp_wled_config(struct qpnp_wled *wled)
reg &= QPNP_WLED_HYB_THRES_MASK;
temp = fls(wled->hyb_thres / QPNP_WLED_HYB_THRES_MIN) - 1;
reg |= temp;
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_write_reg(wled, reg,
QPNP_WLED_HYB_THRES_REG(wled->sink_base));
if (rc)
return rc;
@@ -1195,17 +1426,14 @@ static int qpnp_wled_config(struct qpnp_wled *wled)
else
reg = QPNP_WLED_SINK_TEST5_HYB;
- rc = qpnp_wled_sec_access(wled, wled->sink_base);
- if (rc)
- return rc;
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_sec_write_reg(wled, reg,
QPNP_WLED_SINK_TEST5_REG(wled->sink_base));
if (rc)
return rc;
/* disable all current sinks and enable selected strings */
reg = 0x00;
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_write_reg(wled, reg,
QPNP_WLED_CURR_SINK_REG(wled->sink_base));
for (i = 0; i < wled->num_strings; i++) {
@@ -1228,7 +1456,7 @@ static int qpnp_wled_config(struct qpnp_wled *wled)
else
reg |= ~QPNP_WLED_GATE_DRV_MASK;
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_write_reg(wled, reg,
QPNP_WLED_MOD_EN_REG(wled->sink_base,
wled->strings[i]));
if (rc)
@@ -1246,7 +1474,7 @@ static int qpnp_wled_config(struct qpnp_wled *wled)
reg &= QPNP_WLED_SYNC_DLY_MASK;
temp = wled->sync_dly_us / QPNP_WLED_SYNC_DLY_STEP_US;
reg |= temp;
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_write_reg(wled, reg,
QPNP_WLED_SYNC_DLY_REG(wled->sink_base,
wled->strings[i]));
if (rc)
@@ -1264,7 +1492,7 @@ static int qpnp_wled_config(struct qpnp_wled *wled)
reg &= QPNP_WLED_FS_CURR_MASK;
temp = wled->fs_curr_ua / QPNP_WLED_FS_CURR_STEP_UA;
reg |= temp;
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_write_reg(wled, reg,
QPNP_WLED_FS_CURR_REG(wled->sink_base,
wled->strings[i]));
if (rc)
@@ -1278,7 +1506,7 @@ static int qpnp_wled_config(struct qpnp_wled *wled)
return rc;
reg &= QPNP_WLED_CABC_MASK;
reg |= (wled->en_cabc << QPNP_WLED_CABC_SHIFT);
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_write_reg(wled, reg,
QPNP_WLED_CABC_REG(wled->sink_base,
wled->strings[i]));
if (rc)
@@ -1291,7 +1519,7 @@ static int qpnp_wled_config(struct qpnp_wled *wled)
return rc;
temp = wled->strings[i] + QPNP_WLED_CURR_SINK_SHIFT;
reg |= (1 << temp);
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_write_reg(wled, reg,
QPNP_WLED_CURR_SINK_REG(wled->sink_base));
if (rc)
return rc;
@@ -1348,18 +1576,14 @@ static int qpnp_wled_config(struct qpnp_wled *wled)
if (wled->disp_type_amoled)
reg |= QPNP_WLED_SC_PRO_EN_DSCHGR;
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_write_reg(wled, reg,
QPNP_WLED_SC_PRO_REG(wled->ctrl_base));
if (rc)
return rc;
if (wled->en_ext_pfet_sc_pro) {
- rc = qpnp_wled_sec_access(wled, wled->ctrl_base);
- if (rc)
- return rc;
-
reg = QPNP_WLED_EXT_FET_DTEST2;
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_sec_write_reg(wled, reg,
QPNP_WLED_TEST1_REG(wled->ctrl_base));
if (rc)
return rc;
@@ -1378,7 +1602,7 @@ static int qpnp_wled_config(struct qpnp_wled *wled)
temp = fls(wled->sc_deb_cycles) - QPNP_WLED_SC_DEB_CYCLES_SUB;
reg |= (temp << 1);
- rc = qpnp_wled_write_reg(wled, &reg,
+ rc = qpnp_wled_write_reg(wled, reg,
QPNP_WLED_SC_PRO_REG(wled->ctrl_base));
if (rc)
return rc;
@@ -1447,13 +1671,16 @@ static int qpnp_wled_parse_dt(struct qpnp_wled *wled)
return rc;
}
- wled->avdd_trim_steps_from_center = 0;
+ 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-trim-steps-from-center", &temp_val);
+ "qcom,avdd-target-voltage-mv", &temp_val);
if (!rc) {
- wled->avdd_trim_steps_from_center = temp_val;
+ wled->avdd_target_voltage_mv = temp_val;
} else if (rc != -EINVAL) {
- dev_err(&pdev->dev, "Unable to read avdd trim steps from center value\n");
+ dev_err(&pdev->dev, "Unable to read avdd target voltage\n");
return rc;
}
}
@@ -1507,17 +1734,33 @@ static int qpnp_wled_parse_dt(struct qpnp_wled *wled)
return rc;
}
- wled->ovp_mv = QPNP_WLED_OVP_29500_MV;
+ if (wled->pmic_rev_id->pmic_subtype == PMICOBALT_SUBTYPE ||
+ wled->pmic_rev_id->pmic_subtype == PM2FALCON_SUBTYPE)
+ wled->ovp_mv = 29600;
+ else
+ wled->ovp_mv = 29500;
rc = of_property_read_u32(pdev->dev.of_node,
"qcom,ovp-mv", &temp_val);
if (!rc) {
wled->ovp_mv = temp_val;
} else if (rc != -EINVAL) {
- dev_err(&pdev->dev, "Unable to read vref\n");
+ dev_err(&pdev->dev, "Unable to read ovp\n");
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) {
@@ -1638,6 +1881,7 @@ static int qpnp_wled_parse_dt(struct qpnp_wled *wled)
static int qpnp_wled_probe(struct platform_device *pdev)
{
struct qpnp_wled *wled;
+ struct device_node *revid_node;
int rc = 0, i;
const __be32 *prop;
@@ -1652,6 +1896,27 @@ static int qpnp_wled_probe(struct platform_device *pdev)
wled->pdev = pdev;
+ revid_node = of_parse_phandle(pdev->dev.of_node, "qcom,pmic-revid", 0);
+ if (!revid_node) {
+ pr_err("Missing qcom,pmic-revid property - driver failed\n");
+ return -EINVAL;
+ }
+
+ wled->pmic_rev_id = get_revid_data(revid_node);
+ if (IS_ERR_OR_NULL(wled->pmic_rev_id)) {
+ pr_err("Unable to get pmic_revid rc=%ld\n",
+ PTR_ERR(wled->pmic_rev_id));
+ /*
+ * the revid peripheral must be registered, any failure
+ * here only indicates that the rev-id module has not
+ * probed yet.
+ */
+ return -EPROBE_DEFER;
+ }
+
+ pr_debug("PMIC subtype %d Digital major %d\n",
+ wled->pmic_rev_id->pmic_subtype, wled->pmic_rev_id->rev4);
+
prop = of_get_address_by_name(pdev->dev.of_node, QPNP_WLED_SINK_BASE,
0, 0);
if (!prop) {
@@ -1676,6 +1941,7 @@ static int qpnp_wled_probe(struct platform_device *pdev)
return rc;
}
+ mutex_init(&wled->bus_lock);
rc = qpnp_wled_config(wled);
if (rc) {
dev_err(&pdev->dev, "wled config failed\n");
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
index 594bac6c5902..0d8c6cb8f3f3 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
@@ -266,7 +266,7 @@ static int sde_rotator_update_clk(struct sde_rot_mgr *mgr)
SDEROT_DBG("core_clk %lu\n", total_clk_rate);
ATRACE_INT("core_clk", total_clk_rate);
- sde_rotator_set_clk_rate(mgr, total_clk_rate, mgr->core_clk_idx);
+ sde_rotator_set_clk_rate(mgr, total_clk_rate, SDE_ROTATOR_CLK_ROT_CORE);
return 0;
}
@@ -300,11 +300,34 @@ static void sde_rotator_footswitch_ctrl(struct sde_rot_mgr *mgr, bool on)
mgr->regulator_enable = on;
}
-int sde_rotator_clk_ctrl(struct sde_rot_mgr *mgr, int enable)
+static int sde_rotator_enable_clk(struct sde_rot_mgr *mgr, int clk_idx)
+{
+ struct clk *clk;
+ int ret = 0;
+
+ clk = sde_rotator_get_clk(mgr, clk_idx);
+ if (clk) {
+ ret = clk_prepare_enable(clk);
+ if (ret)
+ SDEROT_ERR("enable failed clk_idx %d\n", clk_idx);
+ }
+
+ return ret;
+}
+
+static void sde_rotator_disable_clk(struct sde_rot_mgr *mgr, int clk_idx)
{
struct clk *clk;
+
+ clk = sde_rotator_get_clk(mgr, clk_idx);
+ if (clk)
+ clk_disable_unprepare(clk);
+}
+
+int sde_rotator_clk_ctrl(struct sde_rot_mgr *mgr, int enable)
+{
int ret = 0;
- int i, changed = 0;
+ int changed = 0;
if (enable) {
if (mgr->rot_enable_clk_cnt == 0)
@@ -323,32 +346,41 @@ int sde_rotator_clk_ctrl(struct sde_rot_mgr *mgr, int enable)
if (changed) {
SDEROT_EVTLOG(enable);
SDEROT_DBG("Rotator clk %s\n", enable ? "enable" : "disable");
- for (i = 0; i < mgr->num_rot_clk; i++) {
- clk = mgr->rot_clk[i].clk;
-
- if (!clk)
- continue;
-
- if (enable) {
- ret = clk_prepare_enable(clk);
- if (ret) {
- SDEROT_ERR(
- "enable failed clk_idx %d\n",
- i);
- goto error;
- }
- } else {
- clk_disable_unprepare(clk);
- }
- }
if (enable) {
+ ret = sde_rotator_enable_clk(mgr,
+ SDE_ROTATOR_CLK_MNOC_AHB);
+ if (ret)
+ goto error_mnoc_ahb;
+ ret = sde_rotator_enable_clk(mgr,
+ SDE_ROTATOR_CLK_MDSS_AHB);
+ if (ret)
+ goto error_mdss_ahb;
+ ret = sde_rotator_enable_clk(mgr,
+ SDE_ROTATOR_CLK_MDSS_AXI);
+ if (ret)
+ goto error_mdss_axi;
+ ret = sde_rotator_enable_clk(mgr,
+ SDE_ROTATOR_CLK_ROT_CORE);
+ if (ret)
+ goto error_rot_core;
+ ret = sde_rotator_enable_clk(mgr,
+ SDE_ROTATOR_CLK_MDSS_ROT);
+ if (ret)
+ goto error_mdss_rot;
+
/* Active+Sleep */
msm_bus_scale_client_update_context(
mgr->data_bus.bus_hdl, false,
mgr->data_bus.curr_bw_uc_idx);
trace_rot_bw_ao_as_context(0);
} else {
+ sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_ROT);
+ sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_ROT_CORE);
+ sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_AXI);
+ sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_AHB);
+ sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MNOC_AHB);
+
/* Active Only */
msm_bus_scale_client_update_context(
mgr->data_bus.bus_hdl, true,
@@ -358,9 +390,15 @@ int sde_rotator_clk_ctrl(struct sde_rot_mgr *mgr, int enable)
}
return ret;
-error:
- for (i--; i >= 0; i--)
- clk_disable_unprepare(mgr->rot_clk[i].clk);
+error_mdss_rot:
+ sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_ROT_CORE);
+error_rot_core:
+ sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_AXI);
+error_mdss_axi:
+ sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_AHB);
+error_mdss_ahb:
+ sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MNOC_AHB);
+error_mnoc_ahb:
return ret;
}
@@ -2101,7 +2139,6 @@ static ssize_t sde_rotator_show_state(struct device *dev,
SPRINT("footswitch_cnt=%d\n", mgr->res_ref_cnt);
SPRINT("regulator_enable=%d\n", mgr->regulator_enable);
SPRINT("enable_clk_cnt=%d\n", mgr->rot_enable_clk_cnt);
- SPRINT("core_clk_idx=%d\n", mgr->core_clk_idx);
for (i = 0; i < mgr->num_rot_clk; i++)
if (mgr->rot_clk[i].clk)
SPRINT("%s=%lu\n", mgr->rot_clk[i].clk_name,
@@ -2301,17 +2338,39 @@ static int sde_rotator_bus_scale_register(struct sde_rot_mgr *mgr)
return 0;
}
+static inline int sde_rotator_search_dt_clk(struct platform_device *pdev,
+ struct sde_rot_mgr *mgr, char *clk_name, int clk_idx)
+{
+ struct clk *tmp;
+
+ if (clk_idx >= SDE_ROTATOR_CLK_MAX) {
+ SDEROT_ERR("invalid clk index %d\n", clk_idx);
+ return -EINVAL;
+ }
+
+ tmp = devm_clk_get(&pdev->dev, clk_name);
+ if (IS_ERR(tmp)) {
+ SDEROT_ERR("unable to get clk: %s\n", clk_name);
+ return PTR_ERR(tmp);
+ }
+
+ strlcpy(mgr->rot_clk[clk_idx].clk_name, clk_name,
+ sizeof(mgr->rot_clk[clk_idx].clk_name));
+
+ mgr->rot_clk[clk_idx].clk = tmp;
+ return 0;
+}
+
static int sde_rotator_parse_dt_clk(struct platform_device *pdev,
struct sde_rot_mgr *mgr)
{
- u32 i = 0, rc = 0;
- const char *clock_name;
+ u32 rc = 0;
int num_clk;
num_clk = of_property_count_strings(pdev->dev.of_node,
"clock-names");
- if (num_clk <= 0) {
- SDEROT_ERR("clocks are not defined\n");
+ if ((num_clk <= 0) || (num_clk > SDE_ROTATOR_CLK_MAX)) {
+ SDEROT_ERR("Number of clocks are out of range: %d\n", num_clk);
goto clk_err;
}
@@ -2325,19 +2384,17 @@ static int sde_rotator_parse_dt_clk(struct platform_device *pdev,
goto clk_err;
}
- for (i = 0; i < mgr->num_rot_clk; i++) {
- u32 clock_rate = 0;
-
- of_property_read_string_index(pdev->dev.of_node, "clock-names",
- i, &clock_name);
- strlcpy(mgr->rot_clk[i].clk_name, clock_name,
- sizeof(mgr->rot_clk[i].clk_name));
-
- of_property_read_u32_index(pdev->dev.of_node, "clock-rate",
- i, &clock_rate);
- mgr->rot_clk[i].rate = clock_rate;
- }
-
+ if (sde_rotator_search_dt_clk(pdev, mgr, "mnoc_clk",
+ SDE_ROTATOR_CLK_MNOC_AHB) ||
+ sde_rotator_search_dt_clk(pdev, mgr, "iface_clk",
+ SDE_ROTATOR_CLK_MDSS_AHB) ||
+ sde_rotator_search_dt_clk(pdev, mgr, "axi_clk",
+ SDE_ROTATOR_CLK_MDSS_AXI) ||
+ sde_rotator_search_dt_clk(pdev, mgr, "rot_core_clk",
+ SDE_ROTATOR_CLK_ROT_CORE) ||
+ sde_rotator_search_dt_clk(pdev, mgr, "rot_clk",
+ SDE_ROTATOR_CLK_MDSS_ROT))
+ rc = -EINVAL;
clk_err:
return rc;
}
@@ -2345,10 +2402,7 @@ clk_err:
static int sde_rotator_register_clk(struct platform_device *pdev,
struct sde_rot_mgr *mgr)
{
- int i, ret;
- struct clk *clk;
- struct sde_rot_clk *rot_clk;
- int core_clk_idx = -1;
+ int ret;
ret = sde_rotator_parse_dt_clk(pdev, mgr);
if (ret) {
@@ -2356,28 +2410,6 @@ static int sde_rotator_register_clk(struct platform_device *pdev,
return -EINVAL;
}
- for (i = 0; i < mgr->num_rot_clk; i++) {
- rot_clk = &mgr->rot_clk[i];
-
- clk = devm_clk_get(&pdev->dev, rot_clk->clk_name);
- if (IS_ERR(clk)) {
- SDEROT_ERR("unable to get clk: %s\n",
- rot_clk->clk_name);
- return PTR_ERR(clk);
- }
- rot_clk->clk = clk;
-
- if (strcmp(rot_clk->clk_name, "rot_core_clk") == 0)
- core_clk_idx = i;
- }
-
- if (core_clk_idx < 0) {
- SDEROT_ERR("undefined core clk\n");
- return -ENXIO;
- }
-
- mgr->core_clk_idx = core_clk_idx;
-
return 0;
}
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
index 781b03e1b974..e1b326b8eb1c 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
@@ -92,6 +92,15 @@ enum sde_rotator_ts {
SDE_ROTATOR_TS_MAX
};
+enum sde_rotator_clk_type {
+ SDE_ROTATOR_CLK_MDSS_AHB,
+ SDE_ROTATOR_CLK_MDSS_AXI,
+ SDE_ROTATOR_CLK_ROT_CORE,
+ SDE_ROTATOR_CLK_MDSS_ROT,
+ SDE_ROTATOR_CLK_MNOC_AHB,
+ SDE_ROTATOR_CLK_MAX
+};
+
struct sde_rotation_item {
/* rotation request flag */
uint32_t flags;
@@ -275,7 +284,6 @@ struct sde_rot_mgr {
int rot_enable_clk_cnt;
struct sde_rot_clk *rot_clk;
int num_rot_clk;
- int core_clk_idx;
u32 rdot_limit;
u32 wrot_limit;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
index d2bc76874c48..925b8497273a 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -2337,9 +2337,9 @@ int sde_rotator_r3_init(struct sde_rot_mgr *mgr)
goto error_hw_rev_init;
/* set rotator CBCR to shutoff memory/periphery on clock off.*/
- clk_set_flags(mgr->rot_clk[mgr->core_clk_idx].clk,
+ clk_set_flags(mgr->rot_clk[SDE_ROTATOR_CLK_ROT_CORE].clk,
CLKFLAG_NORETAIN_MEM);
- clk_set_flags(mgr->rot_clk[mgr->core_clk_idx].clk,
+ clk_set_flags(mgr->rot_clk[SDE_ROTATOR_CLK_ROT_CORE].clk,
CLKFLAG_NORETAIN_PERIPH);
mdata->sde_rot_hw = rot;
diff --git a/drivers/mfd/wcd934x-regmap.c b/drivers/mfd/wcd934x-regmap.c
index 3ed3d125f430..fbaf05e58aff 100644
--- a/drivers/mfd/wcd934x-regmap.c
+++ b/drivers/mfd/wcd934x-regmap.c
@@ -1922,6 +1922,10 @@ static bool wcd934x_is_volatile_register(struct device *dev, unsigned int reg)
case WCD934X_SIDO_NEW_VOUT_A_STARTUP:
case WCD934X_SIDO_NEW_VOUT_D_STARTUP:
case WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL:
+ case WCD934X_ANA_MBHC_MECH:
+ case WCD934X_ANA_MBHC_ELECT:
+ case WCD934X_ANA_MBHC_ZDET:
+ case WCD934X_ANA_MICB2:
return true;
}
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 644178a0cdfc..862d72cb86cf 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -3591,7 +3591,7 @@ static bool __qseecom_is_fw_image_valid(const struct firmware *fw_entry)
return true;
}
-static int __qseecom_get_fw_size(char *appname, uint32_t *fw_size,
+static int __qseecom_get_fw_size(const char *appname, uint32_t *fw_size,
uint32_t *app_arch)
{
int ret = -1;
@@ -3629,14 +3629,21 @@ static int __qseecom_get_fw_size(char *appname, uint32_t *fw_size,
}
pr_debug("QSEE %s app, arch %u\n", appname, *app_arch);
release_firmware(fw_entry);
+ fw_entry = NULL;
for (i = 0; i < num_images; i++) {
memset(fw_name, 0, sizeof(fw_name));
snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
if (ret)
goto err;
+ if (*fw_size > U32_MAX - fw_entry->size) {
+ pr_err("QSEE %s app file size overflow\n", appname);
+ ret = -EINVAL;
+ goto err;
+ }
*fw_size += fw_entry->size;
release_firmware(fw_entry);
+ fw_entry = NULL;
}
return ret;
@@ -3647,8 +3654,9 @@ err:
return ret;
}
-static int __qseecom_get_fw_data(char *appname, u8 *img_data,
- struct qseecom_load_app_ireq *load_req)
+static int __qseecom_get_fw_data(const char *appname, u8 *img_data,
+ uint32_t fw_size,
+ struct qseecom_load_app_ireq *load_req)
{
int ret = -1;
int i = 0, rc = 0;
@@ -3668,6 +3676,12 @@ static int __qseecom_get_fw_data(char *appname, u8 *img_data,
}
load_req->img_len = fw_entry->size;
+ if (load_req->img_len > fw_size) {
+ pr_err("app %s size %zu is larger than buf size %u\n",
+ appname, fw_entry->size, fw_size);
+ ret = -EINVAL;
+ goto err;
+ }
memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
img_data_ptr = img_data_ptr + fw_entry->size;
load_req->mdt_len = fw_entry->size; /*Get MDT LEN*/
@@ -3686,6 +3700,7 @@ static int __qseecom_get_fw_data(char *appname, u8 *img_data,
goto err;
}
release_firmware(fw_entry);
+ fw_entry = NULL;
for (i = 0; i < num_images; i++) {
snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
@@ -3693,10 +3708,17 @@ static int __qseecom_get_fw_data(char *appname, u8 *img_data,
pr_err("Failed to locate blob %s\n", fw_name);
goto err;
}
+ if ((fw_entry->size > U32_MAX - load_req->img_len) ||
+ (fw_entry->size + load_req->img_len > fw_size)) {
+ pr_err("Invalid file size for %s\n", fw_name);
+ ret = -EINVAL;
+ goto err;
+ }
memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
img_data_ptr = img_data_ptr + fw_entry->size;
load_req->img_len += fw_entry->size;
release_firmware(fw_entry);
+ fw_entry = NULL;
}
return ret;
err:
@@ -3801,7 +3823,7 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname)
if (ret)
return ret;
- ret = __qseecom_get_fw_data(appname, img_data, &load_req);
+ ret = __qseecom_get_fw_data(appname, img_data, fw_size, &load_req);
if (ret) {
ret = -EIO;
goto exit_free_img_data;
@@ -3922,7 +3944,7 @@ static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data,
if (ret)
return -EIO;
- ret = __qseecom_get_fw_data(cmnlib_name, img_data, &load_req);
+ ret = __qseecom_get_fw_data(cmnlib_name, img_data, fw_size, &load_req);
if (ret) {
ret = -EIO;
goto exit_free_img_data;
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_v2/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
index c36ecfef66f1..d6e563b935b6 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -235,7 +235,7 @@ static int ipa_generate_flt_hw_rule(enum ipa_ip_type ip,
* @ip: the ip address family type
* @hdr_sz: header size
*
- * Returns: 0 on success, negative on failure
+ * Returns: size on success, negative on failure
*
* caller needs to hold any needed locks to ensure integrity
*
@@ -373,7 +373,12 @@ static int ipa_generate_flt_hw_tbl_common(enum ipa_ip_type ip, u8 *base,
((long)body &
IPA_FLT_ENTRY_MEMORY_ALLIGNMENT));
} else {
- WARN_ON(tbl->sz == 0);
+ if (tbl->sz == 0) {
+ IPAERR("tbl size is 0\n");
+ WARN_ON(1);
+ goto proc_err;
+ }
+
/* allocate memory for the flt tbl */
flt_tbl_mem.size = tbl->sz;
flt_tbl_mem.base =
@@ -460,7 +465,12 @@ static int ipa_generate_flt_hw_tbl_common(enum ipa_ip_type ip, u8 *base,
((long)body &
IPA_FLT_ENTRY_MEMORY_ALLIGNMENT));
} else {
- WARN_ON(tbl->sz == 0);
+ if (tbl->sz == 0) {
+ IPAERR("tbl size is 0\n");
+ WARN_ON(1);
+ goto proc_err;
+ }
+
/* allocate memory for the flt tbl */
flt_tbl_mem.size = tbl->sz;
flt_tbl_mem.base =
@@ -534,8 +544,15 @@ static int ipa_generate_flt_hw_tbl_v1_1(enum ipa_ip_type ip,
u8 *hdr;
u8 *body;
u8 *base;
+ int res;
+
+ res = ipa_get_flt_hw_tbl_size(ip, &hdr_sz);
+ if (res < 0) {
+ IPAERR("ipa_get_flt_hw_tbl_size failed %d\n", res);
+ return res;
+ }
- mem->size = ipa_get_flt_hw_tbl_size(ip, &hdr_sz);
+ mem->size = res;
mem->size = IPA_HW_TABLE_ALIGNMENT(mem->size);
if (mem->size == 0) {
@@ -720,6 +737,7 @@ static int ipa_generate_flt_hw_tbl_v2(enum ipa_ip_type ip,
u32 *entr;
u32 body_start_offset;
u32 hdr_top;
+ int res;
if (ip == IPA_IP_v4)
body_start_offset = IPA_MEM_PART(apps_v4_flt_ofst) -
@@ -756,7 +774,13 @@ static int ipa_generate_flt_hw_tbl_v2(enum ipa_ip_type ip,
entr++;
}
- mem->size = ipa_get_flt_hw_tbl_size(ip, &hdr_sz);
+ res = ipa_get_flt_hw_tbl_size(ip, &hdr_sz);
+ if (res < 0) {
+ IPAERR("ipa_get_flt_hw_tbl_size failed %d\n", res);
+ goto body_err;
+ }
+
+ mem->size = res;
mem->size -= hdr_sz;
mem->size = IPA_HW_TABLE_ALIGNMENT(mem->size);
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
index fec4d5484d28..73206abf9cfd 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
@@ -139,7 +139,7 @@
#define IPA_HW_TABLE_ALIGNMENT(start_ofst) \
(((start_ofst) + 127) & ~127)
-#define IPA_RT_FLT_HW_RULE_BUF_SIZE (128)
+#define IPA_RT_FLT_HW_RULE_BUF_SIZE (256)
#define IPA_HDR_PROC_CTX_TABLE_ALIGNMENT_BYTE 8
#define IPA_HDR_PROC_CTX_TABLE_ALIGNMENT(start_ofst) \
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c b/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c
index 6202992c2c4e..314b09593026 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -25,6 +25,16 @@
#define IPA_NAT_SHARED_MEMORY 1
#define IPA_NAT_TEMP_MEM_SIZE 128
+enum nat_table_type {
+ IPA_NAT_BASE_TBL = 0,
+ IPA_NAT_EXPN_TBL = 1,
+ IPA_NAT_INDX_TBL = 2,
+ IPA_NAT_INDEX_EXPN_TBL = 3,
+};
+
+#define NAT_TABLE_ENTRY_SIZE_BYTE 32
+#define NAT_INTEX_TABLE_ENTRY_SIZE_BYTE 4
+
static int ipa_nat_vma_fault_remap(
struct vm_area_struct *vma, struct vm_fault *vmf)
{
@@ -568,6 +578,71 @@ int ipa2_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma)
goto bail;
}
+ for (cnt = 0; cnt < dma->entries; cnt++) {
+ if (dma->dma[cnt].table_index >= 1) {
+ IPAERR("Invalid table index %d\n",
+ dma->dma[cnt].table_index);
+ ret = -EPERM;
+ goto bail;
+ }
+
+ switch (dma->dma[cnt].base_addr) {
+ case IPA_NAT_BASE_TBL:
+ if (dma->dma[cnt].offset >=
+ (ipa_ctx->nat_mem.size_base_tables + 1) *
+ NAT_TABLE_ENTRY_SIZE_BYTE) {
+ IPAERR("Invalid offset %d\n",
+ dma->dma[cnt].offset);
+ ret = -EPERM;
+ goto bail;
+ }
+
+ break;
+
+ case IPA_NAT_EXPN_TBL:
+ if (dma->dma[cnt].offset >=
+ ipa_ctx->nat_mem.size_expansion_tables *
+ NAT_TABLE_ENTRY_SIZE_BYTE) {
+ IPAERR("Invalid offset %d\n",
+ dma->dma[cnt].offset);
+ ret = -EPERM;
+ goto bail;
+ }
+
+ break;
+
+ case IPA_NAT_INDX_TBL:
+ if (dma->dma[cnt].offset >=
+ (ipa_ctx->nat_mem.size_base_tables + 1) *
+ NAT_INTEX_TABLE_ENTRY_SIZE_BYTE) {
+ IPAERR("Invalid offset %d\n",
+ dma->dma[cnt].offset);
+ ret = -EPERM;
+ goto bail;
+ }
+
+ break;
+
+ case IPA_NAT_INDEX_EXPN_TBL:
+ if (dma->dma[cnt].offset >=
+ ipa_ctx->nat_mem.size_expansion_tables *
+ NAT_INTEX_TABLE_ENTRY_SIZE_BYTE) {
+ IPAERR("Invalid offset %d\n",
+ dma->dma[cnt].offset);
+ ret = -EPERM;
+ goto bail;
+ }
+
+ break;
+
+ default:
+ IPAERR("Invalid base_addr %d\n",
+ dma->dma[cnt].base_addr);
+ ret = -EPERM;
+ goto bail;
+ }
+ }
+
size = sizeof(struct ipa_desc) * NUM_OF_DESC;
desc = kzalloc(size, GFP_KERNEL);
if (desc == NULL) {
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
index 15476f38cf44..5e7a5383334c 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
@@ -227,7 +227,7 @@ int __ipa_generate_rt_hw_rule_v2_6L(enum ipa_ip_type ip,
* @hdr_sz: header size
* @max_rt_idx: maximal index
*
- * Returns: 0 on success, negative on failure
+ * Returns: size on success, negative on failure
*
* caller needs to hold any needed locks to ensure integrity
*
@@ -356,7 +356,11 @@ static int ipa_generate_rt_hw_tbl_common(enum ipa_ip_type ip, u8 *base, u8 *hdr,
((long)body &
IPA_RT_ENTRY_MEMORY_ALLIGNMENT));
} else {
- WARN_ON(tbl->sz == 0);
+ if (tbl->sz == 0) {
+ IPAERR("cannot generate 0 size table\n");
+ goto proc_err;
+ }
+
/* allocate memory for the RT tbl */
rt_tbl_mem.size = tbl->sz;
rt_tbl_mem.base =
@@ -429,8 +433,15 @@ static int ipa_generate_rt_hw_tbl_v1_1(enum ipa_ip_type ip,
u8 *base;
int max_rt_idx;
int i;
+ int res;
- mem->size = ipa_get_rt_hw_tbl_size(ip, &hdr_sz, &max_rt_idx);
+ res = ipa_get_rt_hw_tbl_size(ip, &hdr_sz, &max_rt_idx);
+ if (res < 0) {
+ IPAERR("ipa_get_rt_hw_tbl_size failed %d\n", res);
+ goto error;
+ }
+
+ mem->size = res;
mem->size = (mem->size + IPA_RT_TABLE_MEMORY_ALLIGNMENT) &
~IPA_RT_TABLE_MEMORY_ALLIGNMENT;
@@ -603,6 +614,7 @@ static int ipa_generate_rt_hw_tbl_v2(enum ipa_ip_type ip,
int num_index;
u32 body_start_offset;
u32 apps_start_idx;
+ int res;
if (ip == IPA_IP_v4) {
num_index = IPA_MEM_PART(v4_apps_rt_index_hi) -
@@ -632,7 +644,13 @@ static int ipa_generate_rt_hw_tbl_v2(enum ipa_ip_type ip,
entr++;
}
- mem->size = ipa_get_rt_hw_tbl_size(ip, &hdr_sz, &max_rt_idx);
+ res = ipa_get_rt_hw_tbl_size(ip, &hdr_sz, &max_rt_idx);
+ if (res < 0) {
+ IPAERR("ipa_get_rt_hw_tbl_size failed %d\n", res);
+ goto base_err;
+ }
+
+ mem->size = res;
mem->size -= hdr_sz;
mem->size = (mem->size + IPA_RT_TABLE_MEMORY_ALLIGNMENT) &
~IPA_RT_TABLE_MEMORY_ALLIGNMENT;
diff --git a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
index 96003d7a16a0..520f139ee38a 100644
--- a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
@@ -1053,6 +1053,8 @@ static int ipa_wwan_xmit(struct sk_buff *skb, struct net_device *dev)
IPAWANDBG
("SW filtering out none QMAP packet received from %s",
current->comm);
+ dev_kfree_skb_any(skb);
+ dev->stats.tx_dropped++;
return NETDEV_TX_OK;
}
@@ -1094,6 +1096,8 @@ send:
if (ret) {
pr_err("[%s] fatal: ipa rm timer request resource failed %d\n",
dev->name, ret);
+ dev_kfree_skb_any(skb);
+ dev->stats.tx_dropped++;
return -EFAULT;
}
/* IPA_RM checking end */
@@ -1109,7 +1113,6 @@ send:
if (ret) {
ret = NETDEV_TX_BUSY;
- dev->stats.tx_dropped++;
goto out;
}
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_nat.c b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c
index 67e9b397a8b4..e7e5cf114242 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c
@@ -24,6 +24,17 @@
#define IPA_NAT_TEMP_MEM_SIZE 128
+enum nat_table_type {
+ IPA_NAT_BASE_TBL = 0,
+ IPA_NAT_EXPN_TBL = 1,
+ IPA_NAT_INDX_TBL = 2,
+ IPA_NAT_INDEX_EXPN_TBL = 3,
+};
+
+#define NAT_TABLE_ENTRY_SIZE_BYTE 32
+#define NAT_INTEX_TABLE_ENTRY_SIZE_BYTE 4
+
+
static int ipa3_nat_vma_fault_remap(
struct vm_area_struct *vma, struct vm_fault *vmf)
{
@@ -571,6 +582,71 @@ int ipa3_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma)
goto bail;
}
+ for (cnt = 0; cnt < dma->entries; cnt++) {
+ if (dma->dma[cnt].table_index >= 1) {
+ IPAERR("Invalid table index %d\n",
+ dma->dma[cnt].table_index);
+ ret = -EPERM;
+ goto bail;
+ }
+
+ switch (dma->dma[cnt].base_addr) {
+ case IPA_NAT_BASE_TBL:
+ if (dma->dma[cnt].offset >=
+ (ipa3_ctx->nat_mem.size_base_tables + 1) *
+ NAT_TABLE_ENTRY_SIZE_BYTE) {
+ IPAERR("Invalid offset %d\n",
+ dma->dma[cnt].offset);
+ ret = -EPERM;
+ goto bail;
+ }
+
+ break;
+
+ case IPA_NAT_EXPN_TBL:
+ if (dma->dma[cnt].offset >=
+ ipa3_ctx->nat_mem.size_expansion_tables *
+ NAT_TABLE_ENTRY_SIZE_BYTE) {
+ IPAERR("Invalid offset %d\n",
+ dma->dma[cnt].offset);
+ ret = -EPERM;
+ goto bail;
+ }
+
+ break;
+
+ case IPA_NAT_INDX_TBL:
+ if (dma->dma[cnt].offset >=
+ (ipa3_ctx->nat_mem.size_base_tables + 1) *
+ NAT_INTEX_TABLE_ENTRY_SIZE_BYTE) {
+ IPAERR("Invalid offset %d\n",
+ dma->dma[cnt].offset);
+ ret = -EPERM;
+ goto bail;
+ }
+
+ break;
+
+ case IPA_NAT_INDEX_EXPN_TBL:
+ if (dma->dma[cnt].offset >=
+ ipa3_ctx->nat_mem.size_expansion_tables *
+ NAT_INTEX_TABLE_ENTRY_SIZE_BYTE) {
+ IPAERR("Invalid offset %d\n",
+ dma->dma[cnt].offset);
+ ret = -EPERM;
+ goto bail;
+ }
+
+ break;
+
+ default:
+ IPAERR("Invalid base_addr %d\n",
+ dma->dma[cnt].base_addr);
+ ret = -EPERM;
+ goto bail;
+ }
+ }
+
size = sizeof(struct ipa3_desc) * NUM_OF_DESC;
desc = kzalloc(size, GFP_KERNEL);
if (desc == NULL) {
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/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index f134852e046e..8f6c303d2867 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
@@ -1066,6 +1066,8 @@ static int ipa3_wwan_xmit(struct sk_buff *skb, struct net_device *dev)
IPAWANDBG_LOW
("SW filtering out none QMAP packet received from %s",
current->comm);
+ dev_kfree_skb_any(skb);
+ dev->stats.tx_dropped++;
return NETDEV_TX_OK;
}
@@ -1077,7 +1079,8 @@ static int ipa3_wwan_xmit(struct sk_buff *skb, struct net_device *dev)
pr_err("[%s]Queue stop, send ctrl pkts\n", dev->name);
goto send;
} else {
- pr_err("[%s]fatal: ipa_wwan_xmit stopped\n", dev->name);
+ pr_err("[%s]fatal: ipa3_wwan_xmit stopped\n",
+ dev->name);
return NETDEV_TX_BUSY;
}
}
@@ -1107,6 +1110,8 @@ send:
if (ret) {
pr_err("[%s] fatal: ipa rm timer request resource failed %d\n",
dev->name, ret);
+ dev_kfree_skb_any(skb);
+ dev->stats.tx_dropped++;
return -EFAULT;
}
/* IPA_RM checking end */
@@ -1122,7 +1127,6 @@ send:
if (ret) {
ret = NETDEV_TX_BUSY;
- dev->stats.tx_dropped++;
goto out;
}
diff --git a/drivers/platform/msm/qpnp-revid.c b/drivers/platform/msm/qpnp-revid.c
index 78e685f789cd..1ef8ebe3ed7d 100644
--- a/drivers/platform/msm/qpnp-revid.c
+++ b/drivers/platform/msm/qpnp-revid.c
@@ -56,6 +56,8 @@ static const char *const pmic_names[] = {
[PMICOBALT_SUBTYPE] = "PMICOBALT",
[PM8005_SUBTYPE] = "PM8005",
[PM8937_SUBTYPE] = "PM8937",
+ [PM2FALCON_SUBTYPE] = "PM2FALCON",
+ [PMFALCON_SUBTYPE] = "PMFALCON",
[PMI8937_SUBTYPE] = "PMI8937",
};
diff --git a/drivers/power/qcom-charger/qpnp-smb2.c b/drivers/power/qcom-charger/qpnp-smb2.c
index 93965dbe99ae..f9d76c56aa2e 100644
--- a/drivers/power/qcom-charger/qpnp-smb2.c
+++ b/drivers/power/qcom-charger/qpnp-smb2.c
@@ -203,6 +203,13 @@ static struct smb_params v1_params = {
.get_proc = smblib_mapping_cc_delta_to_field_value,
.set_proc = smblib_mapping_cc_delta_from_field_value,
},
+ .freq_buck = {
+ .name = "buck switching frequency",
+ .reg = CFG_BUCKBOOST_FREQ_SELECT_BUCK_REG,
+ .min_u = 600,
+ .max_u = 2000,
+ .step_u = 200,
+ },
};
#define STEP_CHARGING_MAX_STEPS 5
diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c
index de4391024970..198e77469bbe 100644
--- a/drivers/power/qcom-charger/smb-lib.c
+++ b/drivers/power/qcom-charger/smb-lib.c
@@ -220,6 +220,34 @@ int smblib_get_usb_suspend(struct smb_charger *chg, int *suspend)
return rc;
}
+#define FSW_600HZ_FOR_5V 600
+#define FSW_800HZ_FOR_6V_8V 800
+#define FSW_1MHZ_FOR_REMOVAL 1000
+#define FSW_1MHZ_FOR_9V 1000
+#define FSW_1P2MHZ_FOR_12V 1200
+static int smblib_set_opt_freq_buck(struct smb_charger *chg, int fsw_khz)
+{
+ union power_supply_propval pval = {0, };
+ int rc = 0;
+
+ rc = smblib_set_charge_param(chg, &chg->param.freq_buck, fsw_khz);
+ if (rc < 0)
+ dev_err(chg->dev, "Error in setting freq_buck rc=%d\n", rc);
+
+ if (chg->mode == PARALLEL_MASTER && chg->pl.psy) {
+ pval.intval = fsw_khz;
+ rc = power_supply_set_property(chg->pl.psy,
+ POWER_SUPPLY_PROP_BUCK_FREQ, &pval);
+ if (rc < 0) {
+ dev_err(chg->dev,
+ "Could not set parallel buck_freq rc=%d\n", rc);
+ return rc;
+ }
+ }
+
+ return rc;
+}
+
struct apsd_result {
const char * const name;
const u8 bit;
@@ -416,10 +444,13 @@ static int smblib_set_usb_pd_allowed_voltage(struct smb_charger *chg,
if (min_allowed_uv == MICRO_5V && max_allowed_uv == MICRO_5V) {
allowed_voltage = USBIN_ADAPTER_ALLOW_5V;
+ smblib_set_opt_freq_buck(chg, FSW_600HZ_FOR_5V);
} else if (min_allowed_uv == MICRO_9V && max_allowed_uv == MICRO_9V) {
allowed_voltage = USBIN_ADAPTER_ALLOW_9V;
+ smblib_set_opt_freq_buck(chg, FSW_1MHZ_FOR_9V);
} else if (min_allowed_uv == MICRO_12V && max_allowed_uv == MICRO_12V) {
allowed_voltage = USBIN_ADAPTER_ALLOW_12V;
+ smblib_set_opt_freq_buck(chg, FSW_1P2MHZ_FOR_12V);
} else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_9V) {
allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_9V;
} else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_12V) {
@@ -2178,6 +2209,16 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
int rc;
u8 stat;
+ rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
+ return IRQ_HANDLED;
+ }
+
+ chg->vbus_present = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
+ smblib_set_opt_freq_buck(chg,
+ chg->vbus_present ? FSW_600HZ_FOR_5V : FSW_1MHZ_FOR_REMOVAL);
+
/* fetch the DPDM regulator */
if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
"dpdm-supply", NULL)) {
@@ -2192,14 +2233,6 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
if (!chg->dpdm_reg)
goto skip_dpdm_float;
- rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
- return IRQ_HANDLED;
- }
-
- chg->vbus_present = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
-
if (chg->vbus_present) {
if (!regulator_is_enabled(chg->dpdm_reg)) {
smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n");
@@ -2271,6 +2304,60 @@ static void smblib_handle_sdp_enumeration_done(struct smb_charger *chg,
rising ? "rising" : "falling");
}
+#define QC3_PULSES_FOR_6V 5
+#define QC3_PULSES_FOR_9V 20
+#define QC3_PULSES_FOR_12V 35
+static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg)
+{
+ int rc;
+ u8 stat;
+ int pulses;
+
+ if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB_HVDCP) {
+ rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg,
+ "Couldn't read QC_CHANGE_STATUS rc=%d\n", rc);
+ return;
+ }
+
+ switch (stat & QC_2P0_STATUS_MASK) {
+ case QC_5V_BIT:
+ smblib_set_opt_freq_buck(chg, FSW_600HZ_FOR_5V);
+ break;
+ case QC_9V_BIT:
+ smblib_set_opt_freq_buck(chg, FSW_1MHZ_FOR_9V);
+ break;
+ case QC_12V_BIT:
+ smblib_set_opt_freq_buck(chg, FSW_1P2MHZ_FOR_12V);
+ break;
+ default:
+ smblib_set_opt_freq_buck(chg, FSW_1MHZ_FOR_REMOVAL);
+ break;
+ }
+ }
+
+ if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB_HVDCP_3) {
+ rc = smblib_read(chg, QC_PULSE_COUNT_STATUS_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg,
+ "Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
+ return;
+ }
+ pulses = (stat & QC_PULSE_COUNT_MASK);
+
+ if (pulses < QC3_PULSES_FOR_6V)
+ smblib_set_opt_freq_buck(chg, FSW_600HZ_FOR_5V);
+ else if (pulses < QC3_PULSES_FOR_9V)
+ smblib_set_opt_freq_buck(chg, FSW_800HZ_FOR_6V_8V);
+ else if (pulses < QC3_PULSES_FOR_12V)
+ smblib_set_opt_freq_buck(chg, FSW_1MHZ_FOR_9V);
+ else
+ smblib_set_opt_freq_buck(chg, FSW_1P2MHZ_FOR_12V);
+
+ }
+}
+
static void smblib_handle_adaptive_voltage_done(struct smb_charger *chg,
bool rising)
{
@@ -2283,10 +2370,20 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
bool rising)
{
const struct apsd_result *apsd_result;
+ int rc;
if (!rising)
return;
+ /*
+ * Disable AUTH_IRQ_EN_CFG_BIT to receive adapter voltage
+ * change interrupt.
+ */
+ rc = smblib_masked_write(chg, USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
+ AUTH_IRQ_EN_CFG_BIT, 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't enable QC auth setting rc=%d\n", rc);
+
if (chg->mode == PARALLEL_MASTER)
vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0);
@@ -2392,6 +2489,8 @@ irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
smblib_handle_slow_plugin_timeout(chg,
(bool)(stat & SLOW_PLUGIN_TIMEOUT_BIT));
+ smblib_hvdcp_adaptive_voltage_change(chg);
+
power_supply_changed(chg->usb_psy);
return IRQ_HANDLED;
@@ -2410,6 +2509,12 @@ static void typec_source_removal(struct smb_charger *chg)
cancel_delayed_work_sync(&chg->hvdcp_detect_work);
+ /* reset AUTH_IRQ_EN_CFG_BIT */
+ rc = smblib_masked_write(chg, USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
+ AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't enable QC auth setting rc=%d\n", rc);
+
/* reconfigure allowed voltage for HVDCP */
rc = smblib_write(chg, USBIN_ADAPTER_ALLOW_CFG_REG,
USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
diff --git a/drivers/power/qcom-charger/smb-reg.h b/drivers/power/qcom-charger/smb-reg.h
index ba501761c209..a74fcf730a8c 100644
--- a/drivers/power/qcom-charger/smb-reg.h
+++ b/drivers/power/qcom-charger/smb-reg.h
@@ -428,6 +428,7 @@ enum {
#define USBIN_5V_TO_12V_BIT BIT(2)
#define USBIN_5V_TO_9V_BIT BIT(1)
#define USBIN_5V_BIT BIT(0)
+#define QC_2P0_STATUS_MASK GENMASK(2, 0)
#define APSD_STATUS_REG (USBIN_BASE + 0x07)
#define APSD_STATUS_7_BIT BIT(7)
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/sensors/sensors_ssc.c b/drivers/sensors/sensors_ssc.c
index 4707f74404f2..0910ef34e777 100644
--- a/drivers/sensors/sensors_ssc.c
+++ b/drivers/sensors/sensors_ssc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -69,6 +69,8 @@ static void slpi_loader_do(struct platform_device *pdev)
{
struct slpi_loader_private *priv = NULL;
+ int ret;
+ const char *firmware_name = NULL;
if (!pdev) {
dev_err(&pdev->dev, "%s: Platform device null\n", __func__);
@@ -81,6 +83,13 @@ static void slpi_loader_do(struct platform_device *pdev)
goto fail;
}
+ ret = of_property_read_string(pdev->dev.of_node,
+ "qcom,firmware-name", &firmware_name);
+ if (ret < 0) {
+ pr_err("can't get fw name.\n");
+ goto fail;
+ }
+
priv = platform_get_drvdata(pdev);
if (!priv) {
dev_err(&pdev->dev,
@@ -88,7 +97,7 @@ static void slpi_loader_do(struct platform_device *pdev)
goto fail;
}
- priv->pil_h = subsystem_get("slpi");
+ priv->pil_h = subsystem_get_with_fwname("slpi", firmware_name);
if (IS_ERR(priv->pil_h)) {
dev_err(&pdev->dev, "%s: pil get failed,\n",
__func__);
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 8c43effadc70..d3f967319d21 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -768,6 +768,15 @@ config MSM_SERVICE_NOTIFIER
like audio, the identifier for which is provided by the service
locator.
+config MSM_QBT1000
+ bool "QBT1000 Ultrasonic Fingerprint Sensor"
+ help
+ This driver provides services for configuring the fingerprint
+ sensor hardware and for communicating with the trusted app which
+ uses it. It enables clocks and provides commands for loading
+ trusted apps, unloading them and marshalling buffers to the
+ trusted fingerprint app.
+
config MSM_RPM_RBCPR_STATS_V2_LOG
tristate "MSM Resource Power Manager RPBCPR Stat Driver"
depends on DEBUG_FS
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 0105e03b082d..f56c6bf1539a 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -93,6 +93,7 @@ obj-$(CONFIG_MSM_KERNEL_PROTECT) += kernel_protect.o
obj-$(CONFIG_MSM_RTB) += msm_rtb-hotplug.o
obj-$(CONFIG_QCOM_REMOTEQDSS) += remoteqdss.o
obj-$(CONFIG_MSM_SERVICE_LOCATOR) += service-locator.o
+obj-$(CONFIG_MSM_QBT1000) += qbt1000.o
obj-$(CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG) += rpm_rbcpr_stats_v2.o
obj-$(CONFIG_MSM_RPM_STATS_LOG) += rpm_stats.o rpm_master_stat.o system_stats.o
obj-$(CONFIG_MSM_RPM_LOG) += rpm_log.o
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 36622e30fbe7..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;
@@ -4236,6 +4279,11 @@ static int icnss_get_vbatt_info(struct icnss_priv *priv)
struct qpnp_vadc_chip *vadc_dev = NULL;
int ret = 0;
+ if (test_bit(VBATT_DISABLE, &quirks)) {
+ icnss_pr_dbg("VBATT feature is disabled\n");
+ return ret;
+ }
+
adc_tm_dev = qpnp_get_adc_tm(&priv->pdev->dev, "icnss");
if (PTR_ERR(adc_tm_dev) == -EPROBE_DEFER) {
icnss_pr_err("adc_tm_dev probe defer\n");
diff --git a/drivers/soc/qcom/pil-q6v5.c b/drivers/soc/qcom/pil-q6v5.c
index f8895e8a7b3d..5752aecb82bd 100644
--- a/drivers/soc/qcom/pil-q6v5.c
+++ b/drivers/soc/qcom/pil-q6v5.c
@@ -388,7 +388,7 @@ static int __pil_q6v55_reset(struct pil_desc *pil)
mb();
udelay(1);
- if (drv->qdsp6v62_1_2) {
+ if (drv->qdsp6v62_1_2 || drv->qdsp6v62_1_5) {
for (i = BHS_CHECK_MAX_LOOPS; i > 0; i--) {
if (readl_relaxed(drv->reg_base + QDSP6V62SS_BHS_STATUS)
& QDSP6v55_BHS_EN_REST_ACK)
@@ -488,7 +488,8 @@ static int __pil_q6v55_reset(struct pil_desc *pil)
*/
udelay(1);
}
- } else if (drv->qdsp6v61_1_1 || drv->qdsp6v62_1_2) {
+ } else if (drv->qdsp6v61_1_1 || drv->qdsp6v62_1_2 ||
+ drv->qdsp6v62_1_5) {
/* Deassert QDSP6 compiler memory clamp */
val = readl_relaxed(drv->reg_base + QDSP6SS_PWR_CTL);
val &= ~QDSP6v55_CLAMP_QMC_MEM;
@@ -501,7 +502,13 @@ static int __pil_q6v55_reset(struct pil_desc *pil)
/* Turn on L1, L2, ETB and JU memories 1 at a time */
val = readl_relaxed(drv->reg_base +
QDSP6V6SS_MEM_PWR_CTL);
- for (i = 28; i >= 0; i--) {
+
+ if (drv->qdsp6v62_1_5)
+ i = 29;
+ else
+ i = 28;
+
+ for ( ; i >= 0; i--) {
val |= BIT(i);
writel_relaxed(val, drv->reg_base +
QDSP6V6SS_MEM_PWR_CTL);
@@ -663,6 +670,9 @@ struct q6v5_data *pil_q6v5_init(struct platform_device *pdev)
drv->qdsp6v62_1_2 = of_property_read_bool(pdev->dev.of_node,
"qcom,qdsp6v62-1-2");
+ drv->qdsp6v62_1_5 = of_property_read_bool(pdev->dev.of_node,
+ "qcom,qdsp6v62-1-5");
+
drv->non_elf_image = of_property_read_bool(pdev->dev.of_node,
"qcom,mba-image-is-not-elf");
diff --git a/drivers/soc/qcom/pil-q6v5.h b/drivers/soc/qcom/pil-q6v5.h
index 6a59b06f7b6c..9e8b8511e69b 100644
--- a/drivers/soc/qcom/pil-q6v5.h
+++ b/drivers/soc/qcom/pil-q6v5.h
@@ -62,6 +62,7 @@ struct q6v5_data {
bool qdsp6v56_1_10;
bool qdsp6v61_1_1;
bool qdsp6v62_1_2;
+ bool qdsp6v62_1_5;
bool non_elf_image;
bool restart_reg_sec;
bool override_acc;
diff --git a/drivers/soc/qcom/qbt1000.c b/drivers/soc/qcom/qbt1000.c
new file mode 100644
index 000000000000..dd543daca1b4
--- /dev/null
+++ b/drivers/soc/qcom/qbt1000.c
@@ -0,0 +1,1263 @@
+/* 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.
+ */
+
+#define pr_fmt(fmt) "qbt1000:%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/types.h>
+#include <linux/cdev.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/pm.h>
+#include <linux/of.h>
+#include <linux/mutex.h>
+#include <linux/atomic.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/input.h>
+#include <linux/kfifo.h>
+#include <linux/poll.h>
+#include <uapi/linux/qbt1000.h>
+#include <soc/qcom/scm.h>
+#include "qseecom_kernel.h"
+
+#define QBT1000_DEV "qbt1000"
+#define QBT1000_IN_DEV_NAME "qbt1000_key_input"
+#define QBT1000_IN_DEV_VERSION 0x0100
+#define MAX_FW_EVENTS 128
+#define FP_APP_CMD_RX_IPC 132
+#define FW_MAX_IPC_MSG_DATA_SIZE 0x500
+#define IPC_MSG_ID_CBGE_REQUIRED 29
+
+/*
+ * shared buffer size - init with max value,
+ * user space will provide new value upon tz app load
+ */
+static uint32_t g_app_buf_size = SZ_256K;
+static char const *const FP_APP_NAME = "fingerpr";
+
+struct finger_detect_gpio {
+ int gpio;
+ int active_low;
+ int irq;
+ struct work_struct work;
+ unsigned int key_code;
+ int power_key_enabled;
+ int last_gpio_state;
+ int event_reported;
+};
+
+struct fw_event_desc {
+ enum qbt1000_fw_event ev;
+};
+
+struct fw_ipc_info {
+ int gpio;
+ int irq;
+};
+
+struct qbt1000_drvdata {
+ struct class *qbt1000_class;
+ struct cdev qbt1000_cdev;
+ struct device *dev;
+ char *qbt1000_node;
+ struct clk **clocks;
+ unsigned clock_count;
+ uint8_t clock_state;
+ unsigned root_clk_idx;
+ unsigned frequency;
+ atomic_t available;
+ struct mutex mutex;
+ struct mutex fw_events_mutex;
+ struct input_dev *in_dev;
+ struct fw_ipc_info fw_ipc;
+ struct finger_detect_gpio fd_gpio;
+ DECLARE_KFIFO(fw_events, struct fw_event_desc, MAX_FW_EVENTS);
+ wait_queue_head_t read_wait_queue;
+ struct qseecom_handle *fp_app_handle;
+};
+
+/*
+* struct fw_ipc_cmd -
+* used to store IPC commands to/from firmware
+* @status - indicates whether sending/getting the IPC message was successful
+* @msg_type - the type of IPC message
+* @msg_len - the length of the message data
+* @resp_needed - whether a response is needed for this message
+* @msg_data - any extra data associated with the message
+*/
+struct fw_ipc_cmd {
+ uint32_t status;
+ uint32_t msg_type;
+ uint32_t msg_len;
+ uint32_t resp_needed;
+ uint8_t msg_data[FW_MAX_IPC_MSG_DATA_SIZE];
+};
+
+/*
+* struct ipc_msg_type_to_fw_event -
+* entry in mapping between an IPC message type to a firmware event
+* @msg_type - IPC message type, as reported by firmware
+* @fw_event - corresponding firmware event code to report to driver client
+*/
+struct ipc_msg_type_to_fw_event {
+ uint32_t msg_type;
+ enum qbt1000_fw_event fw_event;
+};
+
+/* mapping between firmware IPC message types to HLOS firmware events */
+struct ipc_msg_type_to_fw_event g_msg_to_event[] = {
+ {IPC_MSG_ID_CBGE_REQUIRED, FW_EVENT_CBGE_REQUIRED}
+};
+
+/**
+ * get_cmd_rsp_buffers() - Function sets cmd & rsp buffer pointers and
+ * aligns buffer lengths
+ * @hdl: index of qseecom_handle
+ * @cmd: req buffer - set to qseecom_handle.sbuf
+ * @cmd_len: ptr to req buffer len
+ * @rsp: rsp buffer - set to qseecom_handle.sbuf + offset
+ * @rsp_len: ptr to rsp buffer len
+ *
+ * Return: 0 on success. Error code on failure.
+ */
+static int get_cmd_rsp_buffers(struct qseecom_handle *hdl,
+ void **cmd,
+ uint32_t *cmd_len,
+ void **rsp,
+ uint32_t *rsp_len)
+{
+ /* 64 bytes alignment for QSEECOM */
+ *cmd_len = ALIGN(*cmd_len, 64);
+ *rsp_len = ALIGN(*rsp_len, 64);
+
+ if ((*rsp_len + *cmd_len) > g_app_buf_size) {
+ pr_err("buffer too small to hold cmd=%d and rsp=%d\n",
+ *cmd_len, *rsp_len);
+ return -ENOMEM;
+ }
+
+ *cmd = hdl->sbuf;
+ *rsp = hdl->sbuf + *cmd_len;
+ return 0;
+}
+
+/**
+ * clocks_on() - Function votes for SPI and AHB clocks to be on and sets
+ * the clk rate to predetermined value for SPI.
+ * @drvdata: ptr to driver data
+ *
+ * Return: 0 on success. Error code on failure.
+ */
+static int clocks_on(struct qbt1000_drvdata *drvdata)
+{
+ int rc = 0;
+ int index;
+
+ if (!drvdata->clock_state) {
+ for (index = 0; index < drvdata->clock_count; index++) {
+ pr_debug("set clock rate at idx:%d, freq: %u\n",
+ index, drvdata->frequency);
+ if (index == drvdata->root_clk_idx) {
+ rc = clk_set_rate(drvdata->clocks[index],
+ drvdata->frequency);
+ if (rc) {
+ pr_err("failure set clock rate at idx:%d\n",
+ index);
+ goto unprepare;
+ }
+ }
+
+ rc = clk_prepare_enable(drvdata->clocks[index]);
+ if (rc) {
+ pr_err("failure to prepare clk at idx:%d\n",
+ index);
+ goto unprepare;
+ }
+
+
+ }
+ drvdata->clock_state = 1;
+ }
+ goto end;
+
+unprepare:
+ for (--index; index >= 0; index--)
+ clk_disable_unprepare(drvdata->clocks[index]);
+
+end:
+ return rc;
+}
+
+/**
+ * clocks_off() - Function votes for SPI and AHB clocks to be off
+ * @drvdata: ptr to driver data
+ *
+ * Return: None
+ */
+static void clocks_off(struct qbt1000_drvdata *drvdata)
+{
+ int index;
+
+ if (drvdata->clock_state) {
+ for (index = 0; index < drvdata->clock_count; index++)
+ clk_disable_unprepare(drvdata->clocks[index]);
+ drvdata->clock_state = 0;
+ }
+}
+
+/**
+ * send_tz_cmd() - Function sends a command to TZ
+ *
+ * @drvdata: pointer to driver data
+ * @app_handle: handle to tz app
+ * @is_user_space: 1 if the cmd buffer is in user space, 0
+ * otherwise
+ * @cmd: command buffer to send
+ * @cmd_len: length of the command buffer
+ * @rsp: output, will be set to location of response buffer
+ * @rsp_len: max size of response
+ *
+ * Return: 0 on success.
+ */
+static int send_tz_cmd(struct qbt1000_drvdata *drvdata,
+ struct qseecom_handle *app_handle,
+ int is_user_space,
+ void *cmd, uint32_t cmd_len,
+ void **rsp, uint32_t rsp_len)
+{
+ int rc = 0;
+ void *aligned_cmd;
+ void *aligned_rsp;
+ uint32_t aligned_cmd_len;
+ uint32_t aligned_rsp_len;
+
+ /* init command and response buffers and align lengths */
+ aligned_cmd_len = cmd_len;
+ aligned_rsp_len = rsp_len;
+
+ rc = get_cmd_rsp_buffers(app_handle,
+ (void **)&aligned_cmd,
+ &aligned_cmd_len,
+ (void **)&aligned_rsp,
+ &aligned_rsp_len);
+
+ if (rc != 0)
+ goto end;
+
+ if (aligned_cmd - cmd + cmd_len > g_app_buf_size) {
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ if (is_user_space) {
+ rc = copy_from_user(aligned_cmd, (void __user *)cmd,
+ cmd_len);
+ if (rc != 0) {
+ pr_err("failure to copy user space buf %d\n", rc);
+ rc = -EFAULT;
+ goto end;
+ }
+ } else
+ memcpy(aligned_cmd, cmd, cmd_len);
+
+
+ /* vote for clocks before sending TZ command */
+ rc = clocks_on(drvdata);
+ if (rc != 0) {
+ pr_err("failure to enable clocks %d\n", rc);
+ goto end;
+ }
+
+ /* send cmd to TZ */
+ rc = qseecom_send_command(app_handle,
+ aligned_cmd,
+ aligned_cmd_len,
+ aligned_rsp,
+ aligned_rsp_len);
+
+ /* un-vote for clocks */
+ clocks_off(drvdata);
+
+ if (rc != 0) {
+ pr_err("failure to send tz cmd %d\n", rc);
+ goto end;
+ }
+
+ *rsp = aligned_rsp;
+
+end:
+ return rc;
+}
+
+/**
+ * qbt1000_open() - Function called when user space opens device.
+ * Successful if driver not currently open.
+ * @inode: ptr to inode object
+ * @file: ptr to file object
+ *
+ * Return: 0 on success. Error code on failure.
+ */
+static int qbt1000_open(struct inode *inode, struct file *file)
+{
+ int rc = 0;
+
+ struct qbt1000_drvdata *drvdata = container_of(inode->i_cdev,
+ struct qbt1000_drvdata,
+ qbt1000_cdev);
+ file->private_data = drvdata;
+
+ pr_debug("qbt1000_open begin\n");
+ /* disallowing concurrent opens */
+ if (!atomic_dec_and_test(&drvdata->available)) {
+ atomic_inc(&drvdata->available);
+ rc = -EBUSY;
+ }
+
+ pr_debug("qbt1000_open end : %d\n", rc);
+ return rc;
+}
+
+/**
+ * qbt1000_release() - Function called when user space closes device.
+
+ * @inode: ptr to inode object
+ * @file: ptr to file object
+ *
+ * Return: 0 on success. Error code on failure.
+ */
+static int qbt1000_release(struct inode *inode, struct file *file)
+{
+ struct qbt1000_drvdata *drvdata = file->private_data;
+
+ atomic_inc(&drvdata->available);
+ return 0;
+}
+
+/**
+ * qbt1000_ioctl() - Function called when user space calls ioctl.
+ * @file: struct file - not used
+ * @cmd: cmd identifier:QBT1000_LOAD_APP,QBT1000_UNLOAD_APP,
+ * QBT1000_SEND_TZCMD
+ * @arg: ptr to relevant structe: either qbt1000_app or
+ * qbt1000_send_tz_cmd depending on which cmd is passed
+ *
+ * Return: 0 on success. Error code on failure.
+ */
+static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg)
+{
+ int rc = 0;
+ void __user *priv_arg = (void __user *)arg;
+ struct qbt1000_drvdata *drvdata;
+
+ drvdata = file->private_data;
+
+ mutex_lock(&drvdata->mutex);
+
+ pr_debug("qbt1000_ioctl %d\n", cmd);
+
+ switch (cmd) {
+ case QBT1000_LOAD_APP:
+ {
+ struct qbt1000_app app;
+ struct qseecom_handle *app_handle;
+
+ if (copy_from_user(&app, priv_arg,
+ sizeof(app)) != 0) {
+ rc = -EFAULT;
+ pr_err("failed copy from user space-LOAD\n");
+ goto end;
+ }
+
+ if (!app.app_handle) {
+ dev_err(drvdata->dev, "%s: LOAD app_handle is null\n",
+ __func__);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ pr_debug("app %s load before\n", app.name);
+
+ /* start the TZ app */
+ rc = qseecom_start_app(&app_handle, app.name, app.size);
+ if (rc == 0) {
+ g_app_buf_size = app.size;
+ rc = qseecom_set_bandwidth(app_handle,
+ app.high_band_width == 1 ? true : false);
+ if (rc != 0) {
+ /* log error, allow to continue */
+ pr_err("App %s failed to set bw\n", app.name);
+ }
+ } else {
+ pr_err("app %s failed to load\n", app.name);
+ goto end;
+ }
+
+ /* copy the app handle to user */
+ rc = copy_to_user((void __user *)app.app_handle, &app_handle,
+ sizeof(*app.app_handle));
+
+ if (rc != 0) {
+ dev_err(drvdata->dev,
+ "%s: Failed copy 2us LOAD rc:%d\n",
+ __func__, rc);
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ pr_debug("app %s load after\n", app.name);
+
+ if (!strcmp(app.name, FP_APP_NAME))
+ drvdata->fp_app_handle = app_handle;
+
+ break;
+ }
+ case QBT1000_UNLOAD_APP:
+ {
+ struct qbt1000_app app;
+ struct qseecom_handle *app_handle;
+
+ if (copy_from_user(&app, priv_arg,
+ sizeof(app)) != 0) {
+ rc = -ENOMEM;
+ pr_err("failed copy from user space-UNLOAD\n");
+ goto end;
+ }
+
+ if (!app.app_handle) {
+ dev_err(drvdata->dev, "%s: UNLOAD app_handle is null\n",
+ __func__);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ rc = copy_from_user(&app_handle, app.app_handle,
+ sizeof(app_handle));
+
+ if (rc != 0) {
+ dev_err(drvdata->dev,
+ "%s: Failed copy from user space-UNLOAD handle rc:%d\n",
+ __func__, rc);
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ /* if the app hasn't been loaded already, return err */
+ if (!app_handle) {
+ pr_err("app not loaded\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if (drvdata->fp_app_handle == app_handle)
+ drvdata->fp_app_handle = 0;
+
+ /* set bw & shutdown the TZ app */
+ qseecom_set_bandwidth(app_handle,
+ app.high_band_width == 1 ? true : false);
+ rc = qseecom_shutdown_app(&app_handle);
+ if (rc != 0) {
+ pr_err("app failed to shutdown\n");
+ goto end;
+ }
+
+ /* copy the app handle (should be null) to user */
+ rc = copy_to_user((void __user *)app.app_handle, &app_handle,
+ sizeof(*app.app_handle));
+
+ if (rc != 0) {
+ dev_err(drvdata->dev,
+ "%s: Failed copy 2us UNLOAD rc:%d\n",
+ __func__, rc);
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ break;
+ }
+ case QBT1000_SEND_TZCMD:
+ {
+ struct qbt1000_send_tz_cmd tzcmd;
+ void *rsp_buf;
+
+ if (copy_from_user(&tzcmd, priv_arg,
+ sizeof(tzcmd))
+ != 0) {
+ rc = -EFAULT;
+ pr_err("failed copy from user space %d\n", rc);
+ goto end;
+ }
+
+ if (tzcmd.req_buf_len > g_app_buf_size ||
+ tzcmd.rsp_buf_len > g_app_buf_size) {
+ rc = -ENOMEM;
+ pr_err("invalid cmd buf len, req=%d, rsp=%d\n",
+ tzcmd.req_buf_len, tzcmd.rsp_buf_len);
+ goto end;
+ }
+
+ /* if the app hasn't been loaded already, return err */
+ if (!tzcmd.app_handle) {
+ pr_err("app not loaded\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ rc = send_tz_cmd(drvdata,
+ tzcmd.app_handle, 1,
+ tzcmd.req_buf, tzcmd.req_buf_len,
+ &rsp_buf, tzcmd.rsp_buf_len);
+
+ if (rc < 0) {
+ pr_err("failure sending command to tz\n");
+ goto end;
+ }
+
+ /* copy rsp buf back to user space buffer */
+ rc = copy_to_user((void __user *)tzcmd.rsp_buf,
+ rsp_buf, tzcmd.rsp_buf_len);
+ if (rc != 0) {
+ pr_err("failed copy 2us rc:%d bytes %d:\n",
+ rc, tzcmd.rsp_buf_len);
+ rc = -EFAULT;
+ goto end;
+ }
+
+ break;
+ }
+ case QBT1000_SET_FINGER_DETECT_KEY:
+ {
+ struct qbt1000_set_finger_detect_key set_fd_key;
+
+ if (copy_from_user(&set_fd_key, priv_arg,
+ sizeof(set_fd_key))
+ != 0) {
+ rc = -EFAULT;
+ pr_err("failed copy from user space %d\n", rc);
+ goto end;
+ }
+
+ drvdata->fd_gpio.key_code = set_fd_key.key_code;
+
+ break;
+ }
+ case QBT1000_CONFIGURE_POWER_KEY:
+ {
+ struct qbt1000_configure_power_key power_key;
+
+ if (copy_from_user(&power_key, priv_arg,
+ sizeof(power_key))
+ != 0) {
+ rc = -EFAULT;
+ pr_err("failed copy from user space %d\n", rc);
+ goto end;
+ }
+
+ drvdata->fd_gpio.power_key_enabled = power_key.enable;
+
+ break;
+ }
+ default:
+ pr_err("invalid cmd %d\n", cmd);
+ rc = -ENOIOCTLCMD;
+ goto end;
+ }
+
+end:
+ mutex_unlock(&drvdata->mutex);
+ return rc;
+}
+
+static int get_events_fifo_len_locked(struct qbt1000_drvdata *drvdata)
+{
+ int len;
+
+ mutex_lock(&drvdata->fw_events_mutex);
+ len = kfifo_len(&drvdata->fw_events);
+ mutex_unlock(&drvdata->fw_events_mutex);
+
+ return len;
+}
+
+static ssize_t qbt1000_read(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ struct fw_event_desc fw_event;
+ struct qbt1000_drvdata *drvdata = filp->private_data;
+
+ if (cnt < sizeof(fw_event.ev))
+ return -EINVAL;
+
+ mutex_lock(&drvdata->fw_events_mutex);
+
+ while (kfifo_len(&drvdata->fw_events) == 0) {
+ mutex_unlock(&drvdata->fw_events_mutex);
+
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ pr_debug("fw_events fifo: empty, waiting\n");
+
+ if (wait_event_interruptible(drvdata->read_wait_queue,
+ (get_events_fifo_len_locked(drvdata) > 0)))
+ return -ERESTARTSYS;
+
+ mutex_lock(&drvdata->fw_events_mutex);
+ }
+
+ if (!kfifo_get(&drvdata->fw_events, &fw_event)) {
+ pr_debug("fw_events fifo: unexpectedly empty\n");
+
+ mutex_unlock(&drvdata->fw_events_mutex);
+ return -EINVAL;
+ }
+
+ mutex_unlock(&drvdata->fw_events_mutex);
+
+ pr_debug("fw_event: %d\n", (int)fw_event.ev);
+ return copy_to_user(ubuf, &fw_event.ev, sizeof(fw_event.ev));
+}
+
+static unsigned int qbt1000_poll(struct file *filp,
+ struct poll_table_struct *wait)
+{
+ struct qbt1000_drvdata *drvdata = filp->private_data;
+ unsigned int mask = 0;
+
+ poll_wait(filp, &drvdata->read_wait_queue, wait);
+
+ if (kfifo_len(&drvdata->fw_events) > 0)
+ mask |= (POLLIN | POLLRDNORM);
+
+ return mask;
+}
+
+static const struct file_operations qbt1000_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = qbt1000_ioctl,
+ .open = qbt1000_open,
+ .release = qbt1000_release,
+ .read = qbt1000_read,
+ .poll = qbt1000_poll
+};
+
+static int qbt1000_dev_register(struct qbt1000_drvdata *drvdata)
+{
+ dev_t dev_no;
+ int ret = 0;
+ size_t node_size;
+ char *node_name = QBT1000_DEV;
+ struct device *dev = drvdata->dev;
+ struct device *device;
+
+ node_size = strlen(node_name) + 1;
+
+ drvdata->qbt1000_node = devm_kzalloc(dev, node_size, GFP_KERNEL);
+ if (!drvdata->qbt1000_node) {
+ ret = -ENOMEM;
+ goto err_alloc;
+ }
+
+ strlcpy(drvdata->qbt1000_node, node_name, node_size);
+
+ ret = alloc_chrdev_region(&dev_no, 0, 1, drvdata->qbt1000_node);
+ if (ret) {
+ pr_err("alloc_chrdev_region failed %d\n", ret);
+ goto err_alloc;
+ }
+
+ cdev_init(&drvdata->qbt1000_cdev, &qbt1000_fops);
+
+ drvdata->qbt1000_cdev.owner = THIS_MODULE;
+ ret = cdev_add(&drvdata->qbt1000_cdev, dev_no, 1);
+ if (ret) {
+ pr_err("cdev_add failed %d\n", ret);
+ goto err_cdev_add;
+ }
+
+ drvdata->qbt1000_class = class_create(THIS_MODULE,
+ drvdata->qbt1000_node);
+ if (IS_ERR(drvdata->qbt1000_class)) {
+ ret = PTR_ERR(drvdata->qbt1000_class);
+ pr_err("class_create failed %d\n", ret);
+ goto err_class_create;
+ }
+
+ device = device_create(drvdata->qbt1000_class, NULL,
+ drvdata->qbt1000_cdev.dev, drvdata,
+ drvdata->qbt1000_node);
+ if (IS_ERR(device)) {
+ ret = PTR_ERR(device);
+ pr_err("device_create failed %d\n", ret);
+ goto err_dev_create;
+ }
+
+ return 0;
+err_dev_create:
+ class_destroy(drvdata->qbt1000_class);
+err_class_create:
+ cdev_del(&drvdata->qbt1000_cdev);
+err_cdev_add:
+ unregister_chrdev_region(drvdata->qbt1000_cdev.dev, 1);
+err_alloc:
+ return ret;
+}
+
+/**
+ * qbt1000_create_input_device() - Function allocates an input
+ * device, configures it for key events and registers it
+ *
+ * @drvdata: ptr to driver data
+ *
+ * Return: 0 on success. Error code on failure.
+ */
+static int qbt1000_create_input_device(struct qbt1000_drvdata *drvdata)
+{
+ int rc = 0;
+
+ drvdata->in_dev = input_allocate_device();
+ if (drvdata->in_dev == NULL) {
+ dev_err(drvdata->dev, "%s: input_allocate_device() failed\n",
+ __func__);
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ drvdata->in_dev->name = QBT1000_IN_DEV_NAME;
+ drvdata->in_dev->phys = NULL;
+ drvdata->in_dev->id.bustype = BUS_HOST;
+ drvdata->in_dev->id.vendor = 0x0001;
+ drvdata->in_dev->id.product = 0x0001;
+ drvdata->in_dev->id.version = QBT1000_IN_DEV_VERSION;
+
+ drvdata->in_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ drvdata->in_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+ drvdata->in_dev->keybit[BIT_WORD(KEY_HOMEPAGE)] |=
+ BIT_MASK(KEY_HOMEPAGE);
+ drvdata->in_dev->keybit[BIT_WORD(KEY_CAMERA)] |=
+ BIT_MASK(KEY_CAMERA);
+ drvdata->in_dev->keybit[BIT_WORD(KEY_POWER)] |=
+ BIT_MASK(KEY_POWER);
+
+ input_set_abs_params(drvdata->in_dev, ABS_X,
+ 0,
+ 1000,
+ 0, 0);
+ input_set_abs_params(drvdata->in_dev, ABS_Y,
+ 0,
+ 1000,
+ 0, 0);
+
+ rc = input_register_device(drvdata->in_dev);
+ if (rc) {
+ dev_err(drvdata->dev, "%s: input_reg_dev() failed %d\n",
+ __func__, rc);
+ goto end;
+ }
+
+end:
+ if (rc)
+ input_free_device(drvdata->in_dev);
+ return rc;
+}
+
+static void purge_finger_events(struct qbt1000_drvdata *drvdata)
+{
+ int i, fifo_len;
+ struct fw_event_desc fw_event;
+
+ fifo_len = kfifo_len(&drvdata->fw_events);
+
+ for (i = 0; i < fifo_len; i++) {
+ if (!kfifo_get(&drvdata->fw_events, &fw_event))
+ pr_err("fw events fifo: could not remove oldest item\n");
+ else if (fw_event.ev != FW_EVENT_FINGER_DOWN
+ && fw_event.ev != FW_EVENT_FINGER_UP)
+ kfifo_put(&drvdata->fw_events, fw_event);
+ }
+}
+
+static void qbt1000_gpio_report_event(struct qbt1000_drvdata *drvdata)
+{
+ int state;
+ struct fw_event_desc fw_event;
+
+ state = (__gpio_get_value(drvdata->fd_gpio.gpio) ? 1 : 0)
+ ^ drvdata->fd_gpio.active_low;
+
+ if (drvdata->fd_gpio.event_reported
+ && state == drvdata->fd_gpio.last_gpio_state)
+ return;
+
+ pr_debug("gpio %d: report state %d\n", drvdata->fd_gpio.gpio, state);
+
+ drvdata->fd_gpio.event_reported = 1;
+ drvdata->fd_gpio.last_gpio_state = state;
+
+ if (drvdata->fd_gpio.key_code) {
+ input_event(drvdata->in_dev, EV_KEY,
+ drvdata->fd_gpio.key_code, !!state);
+ input_sync(drvdata->in_dev);
+ }
+
+ if (state && drvdata->fd_gpio.power_key_enabled) {
+ input_event(drvdata->in_dev, EV_KEY, KEY_POWER, 1);
+ input_sync(drvdata->in_dev);
+ input_event(drvdata->in_dev, EV_KEY, KEY_POWER, 0);
+ input_sync(drvdata->in_dev);
+ }
+
+ fw_event.ev = (state ? FW_EVENT_FINGER_DOWN : FW_EVENT_FINGER_UP);
+
+ mutex_lock(&drvdata->fw_events_mutex);
+
+ if (kfifo_is_full(&drvdata->fw_events)) {
+ struct fw_event_desc dummy_fw_event;
+
+ pr_warn("fw events fifo: full, dropping oldest item\n");
+ if (!kfifo_get(&drvdata->fw_events, &dummy_fw_event))
+ pr_err("fw events fifo: could not remove oldest item\n");
+ }
+
+ purge_finger_events(drvdata);
+
+ if (!kfifo_put(&drvdata->fw_events, fw_event))
+ pr_err("fw events fifo: error adding item\n");
+
+ mutex_unlock(&drvdata->fw_events_mutex);
+ wake_up_interruptible(&drvdata->read_wait_queue);
+}
+
+static void qbt1000_gpio_work_func(struct work_struct *work)
+{
+ struct qbt1000_drvdata *drvdata =
+ container_of(work, struct qbt1000_drvdata, fd_gpio.work);
+
+ qbt1000_gpio_report_event(drvdata);
+
+ pm_relax(drvdata->dev);
+}
+
+static irqreturn_t qbt1000_gpio_isr(int irq, void *dev_id)
+{
+ struct qbt1000_drvdata *drvdata = dev_id;
+
+ if (irq != drvdata->fd_gpio.irq) {
+ pr_warn("invalid irq %d (expected %d)\n",
+ irq, drvdata->fd_gpio.irq);
+ return IRQ_HANDLED;
+ }
+
+ pm_stay_awake(drvdata->dev);
+ schedule_work(&drvdata->fd_gpio.work);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * qbt1000_ipc_irq_handler() - function processes IPC
+ * interrupts on its own thread
+ * @irq: the interrupt that occurred
+ * @dev_id: pointer to the qbt1000_drvdata
+ *
+ * Return: IRQ_HANDLED when complete
+ */
+static irqreturn_t qbt1000_ipc_irq_handler(int irq, void *dev_id)
+{
+ struct fw_ipc_cmd *rx_cmd;
+ int i;
+ uint32_t rxipc = FP_APP_CMD_RX_IPC;
+ struct qbt1000_drvdata *drvdata = (struct qbt1000_drvdata *)dev_id;
+ int rc = 0;
+
+ pm_stay_awake(drvdata->dev);
+
+ mutex_lock(&drvdata->mutex);
+
+ if (irq != drvdata->fw_ipc.irq) {
+ pr_warn("invalid irq %d (expected %d)\n",
+ irq, drvdata->fw_ipc.irq);
+ goto end;
+ }
+
+ pr_debug("firmware interrupt received (irq %d)\n", irq);
+
+ if (!drvdata->fp_app_handle)
+ goto end;
+
+ /*
+ * send the TZ command to fetch the message from firmware
+ * TZ will process the message if it can
+ */
+ rc = send_tz_cmd(drvdata, drvdata->fp_app_handle, 0,
+ &rxipc, sizeof(rxipc),
+ (void *)&rx_cmd, sizeof(*rx_cmd));
+
+ if (rc < 0) {
+ pr_err("failure sending tz cmd %d\n", rxipc);
+ goto end;
+ }
+
+ if (rx_cmd->status != 0) {
+ pr_err("tz command failed to complete\n");
+ goto end;
+ }
+
+ /*
+ * given the IPC message type, search for a corresponding event for the
+ * driver client. If found, add to the events FIFO
+ */
+ for (i = 0; i < ARRAY_SIZE(g_msg_to_event); i++) {
+ if (g_msg_to_event[i].msg_type == rx_cmd->msg_type) {
+ enum qbt1000_fw_event ev = g_msg_to_event[i].fw_event;
+ struct fw_event_desc fw_ev_desc;
+
+ mutex_lock(&drvdata->fw_events_mutex);
+ pr_debug("fw events: add %d\n", (int) ev);
+ fw_ev_desc.ev = ev;
+
+ if (!kfifo_put(&drvdata->fw_events, fw_ev_desc))
+ pr_err("fw events: fifo full, drop event %d\n",
+ (int) ev);
+
+ mutex_unlock(&drvdata->fw_events_mutex);
+ wake_up_interruptible(&drvdata->read_wait_queue);
+ break;
+ }
+ }
+
+end:
+ mutex_unlock(&drvdata->mutex);
+ pm_relax(drvdata->dev);
+ return IRQ_HANDLED;
+}
+
+static int setup_fd_gpio_irq(struct platform_device *pdev,
+ struct qbt1000_drvdata *drvdata)
+{
+ int rc = 0;
+ int irq;
+ const char *desc = "qbt_finger_detect";
+
+ rc = devm_gpio_request_one(&pdev->dev, drvdata->fd_gpio.gpio,
+ GPIOF_IN, desc);
+
+ if (rc < 0) {
+ pr_err("failed to request gpio %d, error %d\n",
+ drvdata->fd_gpio.gpio, rc);
+ goto end;
+ }
+
+ irq = gpio_to_irq(drvdata->fd_gpio.gpio);
+ if (irq < 0) {
+ rc = irq;
+ pr_err("unable to get irq number for gpio %d, error %d\n",
+ drvdata->fd_gpio.gpio, rc);
+ goto end;
+ }
+
+ drvdata->fd_gpio.irq = irq;
+ INIT_WORK(&drvdata->fd_gpio.work, qbt1000_gpio_work_func);
+
+ rc = devm_request_any_context_irq(&pdev->dev, drvdata->fd_gpio.irq,
+ qbt1000_gpio_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ desc, drvdata);
+
+ if (rc < 0) {
+ pr_err("unable to claim irq %d; error %d\n",
+ drvdata->fd_gpio.irq, rc);
+ goto end;
+ }
+
+end:
+ return rc;
+}
+
+static int setup_ipc_irq(struct platform_device *pdev,
+ struct qbt1000_drvdata *drvdata)
+{
+ int rc = 0;
+ const char *desc = "qbt_ipc";
+
+ drvdata->fw_ipc.irq = gpio_to_irq(drvdata->fw_ipc.gpio);
+ if (drvdata->fw_ipc.irq < 0) {
+ rc = drvdata->fw_ipc.irq;
+ pr_err("no irq for gpio %d, error=%d\n",
+ drvdata->fw_ipc.gpio, rc);
+ goto end;
+ }
+
+ rc = devm_gpio_request_one(&pdev->dev, drvdata->fw_ipc.gpio,
+ GPIOF_IN, desc);
+
+ if (rc < 0) {
+ pr_err("failed to request gpio %d, error %d\n",
+ drvdata->fw_ipc.gpio, rc);
+ goto end;
+ }
+
+ rc = devm_request_threaded_irq(&pdev->dev,
+ drvdata->fw_ipc.irq,
+ NULL,
+ qbt1000_ipc_irq_handler,
+ IRQF_ONESHOT | IRQF_TRIGGER_RISING,
+ desc,
+ drvdata);
+
+ if (rc < 0) {
+ pr_err("failed to register for ipc irq %d, rc = %d\n",
+ drvdata->fw_ipc.irq, rc);
+ goto end;
+ }
+
+end:
+ return rc;
+}
+
+/**
+ * qbt1000_read_device_tree() - Function reads device tree
+ * properties into driver data
+ * @pdev: ptr to platform device object
+ * @drvdata: ptr to driver data
+ *
+ * Return: 0 on success. Error code on failure.
+ */
+static int qbt1000_read_device_tree(struct platform_device *pdev,
+ struct qbt1000_drvdata *drvdata)
+{
+ int rc = 0;
+ uint8_t clkcnt = 0;
+ int index = 0;
+ uint32_t rate;
+ const char *clock_name;
+ int gpio;
+ enum of_gpio_flags flags;
+
+ /* obtain number of clocks from hw config */
+ clkcnt = of_property_count_strings(pdev->dev.of_node, "clock-names");
+ if (IS_ERR_VALUE(drvdata->clock_count)) {
+ pr_err("failed to get clock names\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ /* sanity check for max clock count */
+ if (clkcnt > 16) {
+ pr_err("invalid clock count %d\n", clkcnt);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ /* alloc mem for clock array - auto free if probe fails */
+ drvdata->clock_count = clkcnt;
+ pr_debug("clock count %d\n", clkcnt);
+ drvdata->clocks = devm_kzalloc(&pdev->dev,
+ sizeof(struct clk *) * drvdata->clock_count, GFP_KERNEL);
+ if (!drvdata->clocks) {
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ /* load clock names */
+ for (index = 0; index < drvdata->clock_count; index++) {
+ of_property_read_string_index(pdev->dev.of_node,
+ "clock-names",
+ index, &clock_name);
+ pr_debug("getting clock %s\n", clock_name);
+ drvdata->clocks[index] = devm_clk_get(&pdev->dev, clock_name);
+ if (IS_ERR(drvdata->clocks[index])) {
+ rc = PTR_ERR(drvdata->clocks[index]);
+ if (rc != -EPROBE_DEFER)
+ pr_err("failed to get %s\n", clock_name);
+ goto end;
+ }
+
+ if (!strcmp(clock_name, "iface_clk")) {
+ pr_debug("root index %d\n", index);
+ drvdata->root_clk_idx = index;
+ }
+ }
+
+ /* read clock frequency */
+ if (of_property_read_u32(pdev->dev.of_node,
+ "clock-frequency", &rate) == 0) {
+ pr_debug("clk frequency %d\n", rate);
+ drvdata->frequency = rate;
+ }
+
+ /* read IPC gpio */
+ drvdata->fw_ipc.gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,ipc-gpio", 0);
+ if (drvdata->fw_ipc.gpio < 0) {
+ rc = drvdata->fw_ipc.gpio;
+ pr_err("ipc gpio not found, error=%d\n", rc);
+ goto end;
+ }
+
+ /* read finger detect GPIO configuration */
+ gpio = of_get_named_gpio_flags(pdev->dev.of_node,
+ "qcom,finger-detect-gpio", 0, &flags);
+ if (gpio < 0) {
+ pr_err("failed to get gpio flags\n");
+ rc = gpio;
+ goto end;
+ }
+
+ drvdata->fd_gpio.gpio = gpio;
+ drvdata->fd_gpio.active_low = flags & OF_GPIO_ACTIVE_LOW;
+
+end:
+ return rc;
+}
+
+/**
+ * qbt1000_probe() - Function loads hardware config from device tree
+ * @pdev: ptr to platform device object
+ *
+ * Return: 0 on success. Error code on failure.
+ */
+static int qbt1000_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct qbt1000_drvdata *drvdata;
+ int rc = 0;
+
+ pr_debug("qbt1000_probe begin\n");
+ drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ drvdata->dev = &pdev->dev;
+ platform_set_drvdata(pdev, drvdata);
+
+ rc = qbt1000_read_device_tree(pdev, drvdata);
+ if (rc < 0)
+ goto end;
+
+ atomic_set(&drvdata->available, 1);
+
+ mutex_init(&drvdata->mutex);
+ mutex_init(&drvdata->fw_events_mutex);
+
+ rc = qbt1000_dev_register(drvdata);
+ if (rc < 0)
+ goto end;
+
+ INIT_KFIFO(drvdata->fw_events);
+ init_waitqueue_head(&drvdata->read_wait_queue);
+
+ rc = qbt1000_create_input_device(drvdata);
+ if (rc < 0)
+ goto end;
+
+ rc = setup_fd_gpio_irq(pdev, drvdata);
+ if (rc < 0)
+ goto end;
+
+ rc = setup_ipc_irq(pdev, drvdata);
+ if (rc < 0)
+ goto end;
+
+ rc = device_init_wakeup(&pdev->dev, 1);
+ if (rc < 0)
+ goto end;
+
+end:
+ pr_debug("qbt1000_probe end : %d\n", rc);
+ return rc;
+}
+
+static int qbt1000_remove(struct platform_device *pdev)
+{
+ struct qbt1000_drvdata *drvdata = platform_get_drvdata(pdev);
+
+ input_unregister_device(drvdata->in_dev);
+
+ clocks_off(drvdata);
+ mutex_destroy(&drvdata->mutex);
+ mutex_destroy(&drvdata->fw_events_mutex);
+
+ device_destroy(drvdata->qbt1000_class, drvdata->qbt1000_cdev.dev);
+ class_destroy(drvdata->qbt1000_class);
+ cdev_del(&drvdata->qbt1000_cdev);
+ unregister_chrdev_region(drvdata->qbt1000_cdev.dev, 1);
+
+ device_init_wakeup(&pdev->dev, 0);
+
+ return 0;
+}
+
+static int qbt1000_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ int rc = 0;
+ struct qbt1000_drvdata *drvdata = platform_get_drvdata(pdev);
+
+ /*
+ * Returning an error code if driver currently making a TZ call.
+ * Note: The purpose of this driver is to ensure that the clocks are on
+ * while making a TZ call. Hence the clock check to determine if the
+ * driver will allow suspend to occur.
+ */
+ if (!mutex_trylock(&drvdata->mutex))
+ return -EBUSY;
+
+ if (drvdata->clock_state)
+ rc = -EBUSY;
+ else {
+ enable_irq_wake(drvdata->fd_gpio.irq);
+ enable_irq_wake(drvdata->fw_ipc.irq);
+ }
+
+ mutex_unlock(&drvdata->mutex);
+
+ return rc;
+}
+
+static int qbt1000_resume(struct platform_device *pdev)
+{
+ struct qbt1000_drvdata *drvdata = platform_get_drvdata(pdev);
+
+ disable_irq_wake(drvdata->fd_gpio.irq);
+ disable_irq_wake(drvdata->fw_ipc.irq);
+
+ return 0;
+}
+
+static const struct of_device_id qbt1000_match[] = {
+ { .compatible = "qcom,qbt1000" },
+ {}
+};
+
+static struct platform_driver qbt1000_plat_driver = {
+ .probe = qbt1000_probe,
+ .remove = qbt1000_remove,
+ .suspend = qbt1000_suspend,
+ .resume = qbt1000_resume,
+ .driver = {
+ .name = "qbt1000",
+ .owner = THIS_MODULE,
+ .of_match_table = qbt1000_match,
+ },
+};
+
+module_platform_driver(qbt1000_plat_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Qualcomm Technologies, Inc. QBT1000 driver");
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 08006d84fb38..add035269ae7 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -1651,9 +1651,10 @@ static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned event)
/*
* Below sequence is used when controller is working without
- * having ssphy and only USB high speed is supported.
+ * having ssphy and only USB high/full speed is supported.
*/
- if (dwc->maximum_speed == USB_SPEED_HIGH) {
+ if (dwc->maximum_speed == USB_SPEED_HIGH ||
+ dwc->maximum_speed == USB_SPEED_FULL) {
dwc3_msm_write_reg(mdwc->base, QSCRATCH_GENERAL_CFG,
dwc3_msm_read_reg(mdwc->base,
QSCRATCH_GENERAL_CFG)
@@ -2072,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/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 805c5e1931e1..687d51e25d4b 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -802,8 +802,8 @@ static int dwc3_gadget_ep_disable(struct usb_ep *ep)
dwc = dep->dwc;
if (!(dep->flags & DWC3_EP_ENABLED)) {
- dev_WARN_ONCE(dwc->dev, true, "%s is already disabled\n",
- dep->name);
+ dev_dbg(dwc->dev, "%s is already disabled\n", dep->name);
+ dbg_event(dep->number, "ALRDY DISABLED", dep->flags);
return 0;
}
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/drivers/video/fbdev/msm/mdss_debug.c b/drivers/video/fbdev/msm/mdss_debug.c
index 79980acc2201..8663797f1730 100644
--- a/drivers/video/fbdev/msm/mdss_debug.c
+++ b/drivers/video/fbdev/msm/mdss_debug.c
@@ -39,6 +39,9 @@
#define PANEL_CMD_MIN_TX_COUNT 2
#define PANEL_DATA_NODE_LEN 80
+/* Hex number + whitespace */
+#define NEXT_VALUE_OFFSET 3
+
#define INVALID_XIN_ID 0xFF
static char panel_reg[2] = {DEFAULT_READ_PANEL_POWER_MODE_REG, 0x00};
@@ -81,7 +84,7 @@ static ssize_t panel_debug_base_offset_write(struct file *file,
buf[count] = 0; /* end of string */
- if (sscanf(buf, "%x %d", &off, &cnt) != 2)
+ if (sscanf(buf, "%x %u", &off, &cnt) != 2)
return -EFAULT;
if (off > dbg->max_offset)
@@ -129,7 +132,7 @@ static ssize_t panel_debug_base_reg_write(struct file *file,
struct mdss_debug_base *dbg = file->private_data;
char buf[PANEL_TX_MAX_BUF] = {0x0};
char reg[PANEL_TX_MAX_BUF] = {0x0};
- u32 len = 0, step = 0, value = 0;
+ u32 len = 0, value = 0;
char *bufp;
struct mdss_data_type *mdata = mdss_res;
@@ -152,13 +155,21 @@ static ssize_t panel_debug_base_reg_write(struct file *file,
buf[count] = 0; /* end of string */
bufp = buf;
- while (sscanf(bufp, "%x%n", &value, &step) > 0) {
+ /* End of a hex value in given string */
+ bufp[NEXT_VALUE_OFFSET - 1] = 0;
+ while (kstrtouint(bufp, 16, &value) == 0) {
reg[len++] = value;
if (len >= PANEL_TX_MAX_BUF) {
pr_err("wrong input reg len\n");
return -EFAULT;
}
- bufp += step;
+ bufp += NEXT_VALUE_OFFSET;
+ if ((bufp >= (buf + count)) || (bufp < buf)) {
+ pr_warn("%s,buffer out-of-bounds\n", __func__);
+ break;
+ }
+ /* End of a hex value in given string */
+ bufp[NEXT_VALUE_OFFSET - 1] = 0;
}
if (len < PANEL_CMD_MIN_TX_COUNT) {
pr_err("wrong input reg len\n");
@@ -203,6 +214,7 @@ static ssize_t panel_debug_base_reg_read(struct file *file,
struct mdss_panel_data *panel_data = ctl->panel_data;
struct mdss_dsi_ctrl_pdata *ctrl_pdata = container_of(panel_data,
struct mdss_dsi_ctrl_pdata, panel_data);
+ int rc = -EFAULT;
if (!dbg)
return -ENODEV;
@@ -221,7 +233,8 @@ static ssize_t panel_debug_base_reg_read(struct file *file,
if (!rx_buf || !panel_reg_buf) {
pr_err("not enough memory to hold panel reg dump\n");
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto read_reg_fail;
}
if (mdata->debug_inf.debug_enable_clock)
@@ -260,8 +273,7 @@ static ssize_t panel_debug_base_reg_read(struct file *file,
read_reg_fail:
kfree(rx_buf);
kfree(panel_reg_buf);
- return -EFAULT;
-
+ return rc;
}
static const struct file_operations panel_off_fops = {
@@ -739,11 +751,11 @@ static ssize_t mdss_debug_factor_write(struct file *file,
if (strnchr(buf, count, '/')) {
/* Parsing buf as fraction */
- if (sscanf(buf, "%d/%d", &numer, &denom) != 2)
+ if (sscanf(buf, "%u/%u", &numer, &denom) != 2)
return -EFAULT;
} else {
/* Parsing buf as percentage */
- if (sscanf(buf, "%d", &numer) != 1)
+ if (kstrtouint(buf, 0, &numer))
return -EFAULT;
denom = 100;
}
@@ -1051,7 +1063,7 @@ static ssize_t mdss_debug_perf_bw_limit_write(struct file *file,
if (strnchr(buf, count, ' ')) {
/* Parsing buf */
- if (sscanf(buf, "%d %d", &mode, &val) != 2)
+ if (sscanf(buf, "%u %u", &mode, &val) != 2)
return -EFAULT;
}
diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c
index 516cbdc9192b..fa2e47e06503 100644
--- a/drivers/video/fbdev/msm/mdss_dp.c
+++ b/drivers/video/fbdev/msm/mdss_dp.c
@@ -898,8 +898,6 @@ static int dp_audio_info_setup(struct platform_device *pdev,
}
mdss_dp_audio_setup_sdps(&dp_ctrl->ctrl_io);
- mdss_dp_audio_set_sample_rate(&dp_ctrl->ctrl_io,
- dp_ctrl->link_rate, params->sample_rate_hz);
mdss_dp_config_audio_acr_ctrl(&dp_ctrl->ctrl_io, dp_ctrl->link_rate);
mdss_dp_set_safe_to_exit_level(&dp_ctrl->ctrl_io, dp_ctrl->lane_cnt);
mdss_dp_audio_enable(&dp_ctrl->ctrl_io, true);
@@ -1303,17 +1301,23 @@ int mdss_dp_on(struct mdss_panel_data *pdata)
return mdss_dp_on_hpd(dp_drv);
}
-static void mdss_dp_reset_test_data(struct mdss_dp_drv_pdata *dp)
+static inline void mdss_dp_reset_test_data(struct mdss_dp_drv_pdata *dp)
{
dp->test_data = (const struct dpcd_test_request){ 0 };
}
-static bool mdss_dp_is_link_training_requested(struct mdss_dp_drv_pdata *dp)
+static inline bool mdss_dp_is_link_status_updated(struct mdss_dp_drv_pdata *dp)
+{
+ return dp->link_status.link_status_updated;
+}
+
+static inline bool mdss_dp_is_link_training_requested(
+ struct mdss_dp_drv_pdata *dp)
{
return (dp->test_data.test_requested == TEST_LINK_TRAINING);
}
-static bool mdss_dp_soft_hpd_reset(struct mdss_dp_drv_pdata *dp)
+static inline bool mdss_dp_soft_hpd_reset(struct mdss_dp_drv_pdata *dp)
{
return mdss_dp_is_link_training_requested(dp) &&
dp->alt_mode.dp_status.hpd_irq;
@@ -2281,7 +2285,7 @@ end:
* This function will send the test response to the sink but only after
* any previous link training has been completed.
*/
-static void mdss_dp_send_test_response(struct mdss_dp_drv_pdata *dp)
+static inline void mdss_dp_send_test_response(struct mdss_dp_drv_pdata *dp)
{
mutex_lock(&dp->train_mutex);
mdss_dp_aux_send_test_response(dp);
@@ -2318,11 +2322,76 @@ static int mdss_dp_hpd_irq_notify_clients(struct mdss_dp_drv_pdata *dp)
}
/**
+ * mdss_dp_link_retraining() - initiates link retraining
+ * @dp: Display Port Driver data
+ *
+ * This function will initiate link retraining by first notifying
+ * DP clients and triggering DP shutdown, and then enabling DP after
+ * notification is done successfully.
+ */
+static inline void mdss_dp_link_retraining(struct mdss_dp_drv_pdata *dp)
+{
+ if (mdss_dp_hpd_irq_notify_clients(dp))
+ return;
+
+ mdss_dp_on_irq(dp);
+}
+
+/**
+ * mdss_dp_process_link_status_update() - processes link status updates
+ * @dp: Display Port Driver data
+ *
+ * This function will check for changes in the link status, e.g. clock
+ * recovery done on all lanes, and trigger link training if there is a
+ * failure/error on the link.
+ */
+static void mdss_dp_process_link_status_update(struct mdss_dp_drv_pdata *dp)
+{
+ if (!mdss_dp_is_link_status_updated(dp) ||
+ (mdss_dp_aux_channel_eq_done(dp) &&
+ mdss_dp_aux_clock_recovery_done(dp)))
+ return;
+
+ pr_info("channel_eq_done = %d, clock_recovery_done = %d\n",
+ mdss_dp_aux_channel_eq_done(dp),
+ mdss_dp_aux_clock_recovery_done(dp));
+
+ mdss_dp_link_retraining(dp);
+}
+
+/**
+ * mdss_dp_process_link_training_request() - processes new training requests
+ * @dp: Display Port Driver data
+ *
+ * This function will handle new link training requests that are initiated by
+ * the sink. In particular, it will update the requested lane count and link
+ * link rate, and then trigger the link retraining procedure.
+ */
+static void mdss_dp_process_link_training_request(struct mdss_dp_drv_pdata *dp)
+{
+ if (!mdss_dp_is_link_training_requested(dp))
+ return;
+
+ mdss_dp_send_test_response(dp);
+
+ pr_info("%s link rate = 0x%x, lane count = 0x%x\n",
+ mdss_dp_get_test_name(TEST_LINK_TRAINING),
+ dp->test_data.test_link_rate,
+ dp->test_data.test_lane_count);
+ dp->dpcd.max_lane_count =
+ dp->test_data.test_lane_count;
+ dp->link_rate = dp->test_data.test_link_rate;
+
+ mdss_dp_link_retraining(dp);
+}
+
+/**
* mdss_dp_process_hpd_irq_high() - handle HPD IRQ transition to HIGH
* @dp: Display Port Driver data
*
- * This function will handle the HPD IRQ state transitions from HIGH to HIGH
- * or LOW to HIGH, indicating the start of a new test request.
+ * This function will handle the HPD IRQ state transitions from LOW to HIGH
+ * (including cases when there are back to back HPD IRQ HIGH) indicating
+ * the start of a new link training request or sink status update.
*/
static void mdss_dp_process_hpd_irq_high(struct mdss_dp_drv_pdata *dp)
{
@@ -2332,22 +2401,9 @@ static void mdss_dp_process_hpd_irq_high(struct mdss_dp_drv_pdata *dp)
mdss_dp_aux_parse_sink_status_field(dp);
- if (mdss_dp_is_link_training_requested(dp)) {
- mdss_dp_send_test_response(dp);
-
- pr_info("%s requested: link rate = 0x%x, lane count = 0x%x\n",
- mdss_dp_get_test_name(TEST_LINK_TRAINING),
- dp->test_data.test_link_rate,
- dp->test_data.test_lane_count);
- dp->dpcd.max_lane_count =
- dp->test_data.test_lane_count;
- dp->link_rate = dp->test_data.test_link_rate;
+ mdss_dp_process_link_training_request(dp);
- if (mdss_dp_hpd_irq_notify_clients(dp))
- return;
-
- mdss_dp_on_irq(dp);
- }
+ mdss_dp_process_link_status_update(dp);
mdss_dp_reset_test_data(dp);
diff --git a/drivers/video/fbdev/msm/mdss_dp.h b/drivers/video/fbdev/msm/mdss_dp.h
index beeb4d4b1a91..4ba2d20d4261 100644
--- a/drivers/video/fbdev/msm/mdss_dp.h
+++ b/drivers/video/fbdev/msm/mdss_dp.h
@@ -585,5 +585,7 @@ int mdss_dp_aux_set_sink_power_state(struct mdss_dp_drv_pdata *ep, char state);
void mdss_dp_aux_send_test_response(struct mdss_dp_drv_pdata *ep);
void *mdss_dp_get_hdcp_data(struct device *dev);
int mdss_dp_hdcp2p2_init(struct mdss_dp_drv_pdata *dp_drv);
+bool mdss_dp_aux_clock_recovery_done(struct mdss_dp_drv_pdata *ep);
+bool mdss_dp_aux_channel_eq_done(struct mdss_dp_drv_pdata *ep);
#endif /* MDSS_DP_H */
diff --git a/drivers/video/fbdev/msm/mdss_dp_aux.c b/drivers/video/fbdev/msm/mdss_dp_aux.c
index 4d9a110cf6af..91066662e793 100644
--- a/drivers/video/fbdev/msm/mdss_dp_aux.c
+++ b/drivers/video/fbdev/msm/mdss_dp_aux.c
@@ -1238,7 +1238,7 @@ static int dp_train_pattern_set_write(struct mdss_dp_drv_pdata *ep,
return dp_aux_write_buf(ep, 0x102, buf, 1, 0);
}
-static int dp_sink_clock_recovery_done(struct mdss_dp_drv_pdata *ep)
+bool mdss_dp_aux_clock_recovery_done(struct mdss_dp_drv_pdata *ep)
{
u32 mask;
u32 data;
@@ -1259,12 +1259,12 @@ static int dp_sink_clock_recovery_done(struct mdss_dp_drv_pdata *ep)
pr_debug("data=%x mask=%x\n", data, mask);
data &= mask;
if (data == mask) /* all done */
- return 1;
+ return true;
- return 0;
+ return false;
}
-static int dp_sink_channel_eq_done(struct mdss_dp_drv_pdata *ep)
+bool mdss_dp_aux_channel_eq_done(struct mdss_dp_drv_pdata *ep)
{
u32 mask;
u32 data;
@@ -1293,9 +1293,9 @@ static int dp_sink_channel_eq_done(struct mdss_dp_drv_pdata *ep)
data &= mask;
if (data == mask)/* all done */
- return 1;
+ return true;
- return 0;
+ return false;
}
void dp_sink_train_set_adjust(struct mdss_dp_drv_pdata *ep)
@@ -1446,7 +1446,7 @@ static int dp_start_link_train_1(struct mdss_dp_drv_pdata *ep)
usleep_range(usleep_time, usleep_time);
dp_link_status_read(ep, 6);
- if (dp_sink_clock_recovery_done(ep)) {
+ if (mdss_dp_aux_clock_recovery_done(ep)) {
ret = 0;
break;
}
@@ -1499,7 +1499,7 @@ static int dp_start_link_train_2(struct mdss_dp_drv_pdata *ep)
dp_link_status_read(ep, 6);
- if (dp_sink_channel_eq_done(ep)) {
+ if (mdss_dp_aux_channel_eq_done(ep)) {
ret = 0;
break;
}
diff --git a/drivers/video/fbdev/msm/mdss_dp_util.c b/drivers/video/fbdev/msm/mdss_dp_util.c
index b1eb8e0c9579..2d24d8499105 100644
--- a/drivers/video/fbdev/msm/mdss_dp_util.c
+++ b/drivers/video/fbdev/msm/mdss_dp_util.c
@@ -27,10 +27,6 @@
#define DP_LS_FREQ_162 162000000
#define DP_LS_FREQ_270 270000000
#define DP_LS_FREQ_540 540000000
-#define AUDIO_FREQ_32 32000
-#define AUDIO_FREQ_44_1 44100
-#define AUDIO_FREQ_48 48000
-#define DP_AUDIO_FREQ_COUNT 3
enum mdss_dp_pin_assignment {
PIN_ASSIGNMENT_A,
@@ -55,68 +51,12 @@ static const char *mdss_dp_pin_name(u8 pin)
}
}
-static const uint32_t naud_value[DP_AUDIO_FREQ_COUNT][DP_AUDIO_FREQ_COUNT] = {
- { 10125, 16875, 33750 },
- { 5625, 9375, 18750 },
- { 3375, 5625, 11250 }
-};
-
-static const uint32_t maud_rate[DP_AUDIO_FREQ_COUNT] = { 1024, 784, 512 };
-
-static const uint32_t audio_timing_rbr[DP_AUDIO_FREQ_COUNT] = {
- MMSS_DP_AUDIO_TIMING_RBR_32,
- MMSS_DP_AUDIO_TIMING_RBR_44,
- MMSS_DP_AUDIO_TIMING_RBR_48
-};
-
-static const uint32_t std_audio_freq_list[DP_AUDIO_FREQ_COUNT] = {
- AUDIO_FREQ_32,
- AUDIO_FREQ_44_1,
- AUDIO_FREQ_48
-};
-
struct mdss_hw mdss_dp_hw = {
.hw_ndx = MDSS_HW_EDP,
.ptr = NULL,
.irq_handler = dp_isr,
};
-static int mdss_dp_get_rate_index(uint32_t rate)
-{
- int index = 0;
-
- switch (rate) {
- case DP_LS_FREQ_162:
- case AUDIO_FREQ_32:
- index = 0;
- break;
- case DP_LS_FREQ_270:
- case AUDIO_FREQ_44_1:
- index = 1;
- break;
- case DP_LS_FREQ_540:
- case AUDIO_FREQ_48:
- index = 2;
- break;
- default:
- index = 0;
- pr_err("unsupported rate\n");
- break;
- }
-
- return index;
-}
-
-static bool match_std_freq(uint32_t audio_freq, uint32_t std_freq)
-{
- int quotient = audio_freq / std_freq;
-
- if (quotient & (quotient - 1))
- return false;
- else
- return true;
-}
-
/* DP retrieve ctrl HW version */
u32 mdss_dp_get_ctrl_hw_version(struct dss_io_data *ctrl_io)
{
@@ -866,52 +806,6 @@ void mdss_dp_audio_setup_sdps(struct dss_io_data *ctrl_io)
mdss_dp_audio_setup_isrc_sdp(ctrl_io);
}
-void mdss_dp_audio_set_sample_rate(struct dss_io_data *ctrl_io,
- char dp_link_rate, uint32_t audio_freq)
-{
- uint32_t link_rate;
- uint32_t default_audio_freq = AUDIO_FREQ_32;
- int i, multiplier = 1;
- uint32_t maud_index, lrate_index, register_index, value;
-
- link_rate = (uint32_t)dp_link_rate * DP_LINK_RATE_MULTIPLIER;
-
- pr_debug("link_rate = %u, audio_freq = %u\n", link_rate, audio_freq);
-
- for (i = 0; i < DP_AUDIO_FREQ_COUNT; i++) {
- if (audio_freq % std_audio_freq_list[i])
- continue;
-
- if (match_std_freq(audio_freq, std_audio_freq_list[i])) {
- default_audio_freq = std_audio_freq_list[i];
- multiplier = audio_freq / default_audio_freq;
- break;
- }
- }
-
- pr_debug("default_audio_freq = %u, multiplier = %d\n",
- default_audio_freq, multiplier);
-
- lrate_index = mdss_dp_get_rate_index(link_rate);
- maud_index = mdss_dp_get_rate_index(default_audio_freq);
-
- pr_debug("lrate_index = %u, maud_index = %u, maud = %u, naud = %u\n",
- lrate_index, maud_index,
- maud_rate[maud_index] * multiplier,
- naud_value[maud_index][lrate_index]);
-
- register_index = mdss_dp_get_rate_index(default_audio_freq);
- value = ((maud_rate[maud_index] * multiplier) << 16) |
- naud_value[maud_index][lrate_index];
-
- pr_debug("reg index = %d, offset = 0x%x, value = 0x%x\n",
- (int)register_index, audio_timing_rbr[register_index],
- value);
-
- writel_relaxed(value, ctrl_io->base +
- audio_timing_rbr[register_index]);
-}
-
void mdss_dp_set_safe_to_exit_level(struct dss_io_data *ctrl_io,
uint32_t lane_cnt)
{
diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c
index 66cd99720afa..cf7a398c13ce 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.c
+++ b/drivers/video/fbdev/msm/mdss_dsi.c
@@ -995,6 +995,7 @@ static void mdss_dsi_debugfs_cleanup(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
struct mdss_dsi_debugfs_info *dfs = ctrl->debugfs_info;
if (dfs && dfs->root)
debugfs_remove_recursive(dfs->root);
+ kfree(dfs);
pdata = pdata->next;
} while (pdata);
pr_debug("%s: Cleaned up mdss_dsi_debugfs_info\n", __func__);
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index fc8d3898351e..0316f4e86d39 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -615,8 +615,8 @@ static ssize_t mdss_fb_force_panel_dead(struct device *dev,
return len;
}
- if (sscanf(buf, "%d", &pdata->panel_info.panel_force_dead) != 1)
- pr_err("sccanf buf error!\n");
+ if (kstrtouint(buf, 0, &pdata->panel_info.panel_force_dead))
+ pr_err("kstrtouint buf error!\n");
return len;
}
@@ -729,8 +729,8 @@ static ssize_t mdss_fb_change_dfps_mode(struct device *dev,
}
pinfo = &pdata->panel_info;
- if (sscanf(buf, "%d", &dfps_mode) != 1) {
- pr_err("sccanf buf error!\n");
+ if (kstrtouint(buf, 0, &dfps_mode)) {
+ pr_err("kstrtouint buf error!\n");
return len;
}
@@ -1280,6 +1280,7 @@ static int mdss_fb_remove(struct platform_device *pdev)
return -EINVAL;
mdss_fb_unregister_input_handler(mfd);
+ mdss_panel_debugfs_cleanup(mfd->panel_info);
if (mdss_fb_suspend_sub(mfd))
pr_err("msm_fb_remove: can't stop the device %d\n",
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.c b/drivers/video/fbdev/msm/mdss_hdmi_edid.c
index 2047a047b537..b90ac82049c6 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_edid.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.c
@@ -831,14 +831,10 @@ static const u8 *hdmi_edid_find_block(const u8 *in_buf, u32 start_offset,
u32 offset = start_offset;
u32 dbc_offset = in_buf[2];
- if (dbc_offset >= EDID_BLOCK_SIZE - EDID_DTD_LEN)
- return NULL;
- *len = 0;
-
/*
* * edid buffer 1, byte 2 being 4 means no non-DTD/Data block
* collection present.
- * * edid buffer 1, byte 2 being 0 menas no non-DTD/DATA block
+ * * edid buffer 1, byte 2 being 0 means no non-DTD/DATA block
* collection present and no DTD data present.
*/
if ((dbc_offset == 0) || (dbc_offset == 4)) {
@@ -858,8 +854,6 @@ static const u8 *hdmi_edid_find_block(const u8 *in_buf, u32 start_offset,
}
offset += 1 + block_len;
}
- DEV_WARN("%s: EDID: type=%d block not found in EDID block\n",
- __func__, type);
return NULL;
} /* hdmi_edid_find_block */
@@ -1602,7 +1596,6 @@ static void hdmi_edid_detail_desc(struct hdmi_edid_ctrl *edid_ctrl,
if (rc < 0)
rc = hdmi_set_resv_timing_info(&timing);
} else {
- DEV_ERR("%s: Invalid frame data\n", __func__);
rc = -EINVAL;
}
@@ -1611,7 +1604,6 @@ static void hdmi_edid_detail_desc(struct hdmi_edid_ctrl *edid_ctrl,
DEV_DBG("%s: DTD mode found: %d\n", __func__, *disp_mode);
} else {
*disp_mode = HDMI_VFRMT_UNKNOWN;
- DEV_ERR("%s: error adding mode from DTD: %d\n", __func__, rc);
}
} /* hdmi_edid_detail_desc */
@@ -1987,7 +1979,6 @@ static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl)
u32 has60hz_mode = false;
u32 has50hz_mode = false;
u32 desc_offset = 0;
- bool read_block0_res = false;
struct hdmi_edid_sink_data *sink_data = NULL;
if (!edid_ctrl) {
@@ -2004,12 +1995,6 @@ static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl)
hdmi_edid_find_block(data_buf+0x80, DBC_START_OFFSET,
VIDEO_DATA_BLOCK, &len) : NULL;
- if (num_of_cea_blocks && (len == 0 || len > MAX_DATA_BLOCK_SIZE)) {
- DEV_DBG("%s: fall back to block 0 res\n", __func__);
- svd = NULL;
- read_block0_res = true;
- }
-
sink_data = &edid_ctrl->sink_data;
sink_data->disp_multi_3d_mode_list_cnt = 0;
@@ -2059,20 +2044,21 @@ static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl)
edid_blk0+0x36+desc_offset,
&video_format);
- DEV_DBG("[%s:%d] Block-0 Adding vid fmt = [%s]\n",
- __func__, __LINE__,
- msm_hdmi_mode_2string(video_format));
+ if (video_format != HDMI_VFRMT_UNKNOWN) {
+ DEV_DBG("[%s:%d] Block-0 Adding vid fmt = [%s]\n",
+ __func__, __LINE__,
+ msm_hdmi_mode_2string(video_format));
- hdmi_edid_add_sink_video_format(edid_ctrl,
- video_format);
+ hdmi_edid_add_sink_video_format(edid_ctrl,
+ video_format);
- if (video_format == HDMI_VFRMT_640x480p60_4_3)
- has480p = true;
+ if (video_format == HDMI_VFRMT_640x480p60_4_3)
+ has480p = true;
- /* Make a note of the preferred video format */
- if (i == 0) {
- sink_data->preferred_video_format =
- video_format;
+ /* Make a note of the preferred video format */
+ if (i == 0)
+ sink_data->preferred_video_format =
+ video_format;
}
desc_offset += 0x12;
++i;
@@ -2088,28 +2074,32 @@ static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl)
* * EDID_BLOCK_SIZE = 0x80 Each page size in the EDID ROM
*/
desc_offset = edid_blk1[0x02];
- i = 0;
- while (!edid_blk1[desc_offset]) {
- hdmi_edid_detail_desc(edid_ctrl,
- edid_blk1+desc_offset,
- &video_format);
-
- DEV_DBG("[%s:%d] Block-1 Adding vid fmt = [%s]\n",
- __func__, __LINE__,
- msm_hdmi_mode_2string(video_format));
-
- hdmi_edid_add_sink_video_format(edid_ctrl,
- video_format);
- if (video_format == HDMI_VFRMT_640x480p60_4_3)
- has480p = true;
-
- /* Make a note of the preferred video format */
- if (i == 0) {
- sink_data->preferred_video_format =
- video_format;
+ if (desc_offset < (EDID_BLOCK_SIZE - EDID_DTD_LEN)) {
+ i = 0;
+ while (!edid_blk1[desc_offset]) {
+ hdmi_edid_detail_desc(edid_ctrl,
+ edid_blk1+desc_offset,
+ &video_format);
+
+ if (video_format != HDMI_VFRMT_UNKNOWN) {
+ DEV_DBG("%s Block-1 Adding vid fmt = [%s]\n",
+ __func__,
+ msm_hdmi_mode_2string(video_format));
+
+ hdmi_edid_add_sink_video_format(edid_ctrl,
+ video_format);
+ if (video_format == HDMI_VFRMT_640x480p60_4_3)
+ has480p = true;
+
+ /* Make a note of the preferred video format */
+ if (i == 0) {
+ sink_data->preferred_video_format =
+ video_format;
+ }
+ }
+ desc_offset += 0x12;
+ ++i;
}
- desc_offset += 0x12;
- ++i;
}
std_blk = 0;
diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c
index a0637109c7b3..04e8fa4ba576 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp.c
@@ -2605,7 +2605,7 @@ static ssize_t mdss_mdp_store_max_limit_bw(struct device *dev,
struct mdss_data_type *mdata = dev_get_drvdata(dev);
u32 data = 0;
- if (1 != sscanf(buf, "%d", &data)) {
+ if (kstrtouint(buf, 0, &data)) {
pr_info("Not able scan to bw_mode_bitmap\n");
} else {
mdata->bw_mode_bitmap = data;
diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h
index 8ac63aaaefce..a561fed80ce6 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.h
+++ b/drivers/video/fbdev/msm/mdss_mdp.h
@@ -109,6 +109,9 @@
* QSEED3 parameters needs to be updated.
* @DS_ENHANCER_UPDATE: Setting this bit indicates current Desitnation Scaler
* QSEED3 Detial enhancer parameters need to be updated.
+ * @DS_VALIDATE: Indicate destination data structure parameters are validated
+ * and can be used for programming the HW and perform a flush.
+ * @DS_DIRTY_UPDATE: Mark for dirty update for Power resume usecase.
*/
#define DS_ENABLE BIT(0)
#define DS_DUAL_MODE BIT(1)
@@ -116,6 +119,8 @@
#define DS_RIGHT BIT(3)
#define DS_SCALE_UPDATE BIT(4)
#define DS_ENHANCER_UPDATE BIT(5)
+#define DS_VALIDATE BIT(6)
+#define DS_DIRTY_UPDATE BIT(7)
/**
* Destination Scaler DUAL mode overfetch pixel count
@@ -370,6 +375,8 @@ struct mdss_mdp_destination_scaler {
char __iomem *lut_base;
u16 src_width;
u16 src_height;
+ u16 last_mixer_width;
+ u16 last_mixer_height;
u32 flags;
struct mdp_scale_data_v2 scaler;
};
@@ -404,7 +411,7 @@ struct mdss_mdp_ctl_intfs_ops {
/* to update lineptr, [1..yres] - enable, 0 - disable */
int (*update_lineptr)(struct mdss_mdp_ctl *ctl, bool enable);
- int (*avr_ctrl_fnc)(struct mdss_mdp_ctl *);
+ int (*avr_ctrl_fnc)(struct mdss_mdp_ctl *, bool enable);
};
struct mdss_mdp_cwb {
@@ -1706,6 +1713,7 @@ void mdss_mdp_pp_term(struct device *dev);
int mdss_mdp_pp_overlay_init(struct msm_fb_data_type *mfd);
int mdss_mdp_pp_resume(struct msm_fb_data_type *mfd);
+void mdss_mdp_pp_dest_scaler_resume(struct mdss_mdp_ctl *ctl);
int mdss_mdp_pp_setup(struct mdss_mdp_ctl *ctl);
int mdss_mdp_pp_setup_locked(struct mdss_mdp_ctl *ctl);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
index eb1e0b5c47a6..1d61653b76bb 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
@@ -3508,7 +3508,9 @@ int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl)
if (is_dest_scaling_enable(ctl->mixer_left)) {
width = get_ds_input_width(ctl->mixer_left);
height = get_ds_input_height(ctl->mixer_left);
- if (ctl->panel_data->next && is_pingpong_split(ctl->mfd))
+ if (is_dual_lm_single_display(ctl->mfd) ||
+ (ctl->panel_data->next &&
+ is_pingpong_split(ctl->mfd)))
width *= 2;
} else {
width = get_panel_width(ctl);
@@ -3548,9 +3550,13 @@ int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl)
}
if (split_fb) {
- width = ctl->mfd->split_fb_left;
- width += (pinfo->lcdc.border_left +
- pinfo->lcdc.border_right);
+ if (is_dest_scaling_enable(ctl->mixer_left)) {
+ width = get_ds_input_width(ctl->mixer_left);
+ } else {
+ width = ctl->mfd->split_fb_left;
+ width += (pinfo->lcdc.border_left +
+ pinfo->lcdc.border_right);
+ }
} else if (width > max_mixer_width) {
width /= 2;
}
@@ -3576,8 +3582,12 @@ int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl)
return 0;
}
- if (split_fb)
- width = ctl->mfd->split_fb_right;
+ if (split_fb) {
+ if (is_dest_scaling_enable(ctl->mixer_left))
+ width = get_ds_input_width(ctl->mixer_left);
+ else
+ width = ctl->mfd->split_fb_right;
+ }
if (width < ctl->width) {
if (ctl->mixer_right == NULL) {
@@ -4038,6 +4048,7 @@ static void mdss_mdp_ctl_restore_sub(struct mdss_mdp_ctl *ctl)
if (ctl->mfd && ctl->panel_data) {
ctl->mfd->ipc_resume = true;
mdss_mdp_pp_resume(ctl->mfd);
+ mdss_mdp_pp_dest_scaler_resume(ctl);
if (is_dsc_compression(&ctl->panel_data->panel_info)) {
/*
@@ -5593,7 +5604,7 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg,
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
if (ctl->ops.avr_ctrl_fnc) {
- ret = ctl->ops.avr_ctrl_fnc(ctl);
+ ret = ctl->ops.avr_ctrl_fnc(ctl, true);
if (ret) {
pr_err("error configuring avr ctrl registers ctl=%d err=%d\n",
ctl->num, ret);
@@ -5603,7 +5614,7 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg,
}
if (sctl && sctl->ops.avr_ctrl_fnc) {
- ret = sctl->ops.avr_ctrl_fnc(sctl);
+ ret = sctl->ops.avr_ctrl_fnc(sctl, true);
if (ret) {
pr_err("error configuring avr ctrl registers sctl=%d err=%d\n",
sctl->num, ret);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
index d316ab6d263a..048e5fce30c6 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
@@ -108,6 +108,8 @@ static void mdss_mdp_fetch_end_config(struct mdss_mdp_video_ctx *ctx,
static void early_wakeup_dfps_update_work(struct work_struct *work);
+static int mdss_mdp_video_avr_ctrl(struct mdss_mdp_ctl *ctl, bool enable);
+
static inline void mdp_video_write(struct mdss_mdp_video_ctx *ctx,
u32 reg, u32 val)
{
@@ -459,13 +461,15 @@ static int mdss_mdp_video_avr_trigger_setup(struct mdss_mdp_ctl *ctl)
}
static void mdss_mdp_video_avr_ctrl_setup(struct mdss_mdp_video_ctx *ctx,
- struct mdss_mdp_avr_info *avr_info, bool is_master)
+ struct mdss_mdp_avr_info *avr_info, bool is_master, bool enable)
{
u32 avr_ctrl = 0;
u32 avr_mode = 0;
- avr_ctrl = avr_info->avr_enabled;
- avr_mode = avr_info->avr_mode;
+ if (enable) {
+ avr_ctrl = avr_info->avr_enabled;
+ avr_mode = avr_info->avr_mode;
+ }
/* Enable avr_vsync_clear_en bit to clear avr in next vsync */
if (avr_mode == MDSS_MDP_AVR_ONE_SHOT)
@@ -1429,6 +1433,20 @@ static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl, int new_fps)
}
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
+
+ /*
+ * Need to disable AVR during DFPS update period.
+ * Next commit will restore the AVR settings.
+ */
+ if (test_bit(MDSS_CAPS_AVR_SUPPORTED,
+ mdata->mdss_caps_map) &&
+ ctl->avr_info.avr_enabled) {
+ mdss_mdp_video_avr_ctrl(ctl, false);
+ rc = mdss_mdp_video_dfps_wait4vsync(ctl);
+ if (rc < 0)
+ pr_err("Error in dfps_wait: %d\n", rc);
+ }
+
spin_lock_irqsave(&ctx->dfps_lock, flags);
if (mdata->mdp_rev < MDSS_MDP_HW_REV_105) {
@@ -2112,6 +2130,7 @@ static void early_wakeup_dfps_update_work(struct work_struct *work)
struct mdss_panel_info *pinfo;
struct msm_fb_data_type *mfd;
struct mdss_mdp_ctl *ctl;
+ struct mdss_data_type *mdata;
struct dynamic_fps_data data = {0};
int ret = 0;
int dfps;
@@ -2123,7 +2142,8 @@ static void early_wakeup_dfps_update_work(struct work_struct *work)
ctl = ctx->ctl;
- if (!ctl || !ctl->panel_data || !ctl->mfd || !ctl->mfd->fbi) {
+ if (!ctl || !ctl->panel_data || !ctl->mfd || !ctl->mfd->fbi ||
+ !ctl->mdata) {
pr_err("%s: invalid ctl\n", __func__);
return;
}
@@ -2131,6 +2151,7 @@ static void early_wakeup_dfps_update_work(struct work_struct *work)
pdata = ctl->panel_data;
pinfo = &ctl->panel_data->panel_info;
mfd = ctl->mfd;
+ mdata = ctl->mdata;
if (!pinfo->dynamic_fps || !ctl->ops.config_fps_fnc ||
!pdata->panel_info.default_fps) {
@@ -2138,6 +2159,17 @@ static void early_wakeup_dfps_update_work(struct work_struct *work)
return;
}
+ /*
+ * Bypass DFPS update when AVR is enabled because
+ * AVR will take control of the programmable fetch
+ */
+ if (test_bit(MDSS_CAPS_AVR_SUPPORTED,
+ mdata->mdss_caps_map) &&
+ ctl->avr_info.avr_enabled) {
+ pr_debug("Bypass DFPS update when AVR is enabled\n");
+ return;
+ }
+
/* get the default fps that was cached before any dfps update */
dfps = pdata->panel_info.default_fps;
@@ -2213,7 +2245,7 @@ static int mdss_mdp_video_early_wake_up(struct mdss_mdp_ctl *ctl)
return 0;
}
-static int mdss_mdp_video_avr_ctrl(struct mdss_mdp_ctl *ctl)
+static int mdss_mdp_video_avr_ctrl(struct mdss_mdp_ctl *ctl, bool enable)
{
struct mdss_mdp_video_ctx *ctx = NULL, *sctx = NULL;
@@ -2222,7 +2254,8 @@ static int mdss_mdp_video_avr_ctrl(struct mdss_mdp_ctl *ctl)
pr_err("invalid master ctx\n");
return -EINVAL;
}
- mdss_mdp_video_avr_ctrl_setup(ctx, &ctl->avr_info, ctl->is_master);
+ mdss_mdp_video_avr_ctrl_setup(ctx, &ctl->avr_info, ctl->is_master,
+ enable);
if (is_pingpong_split(ctl->mfd)) {
sctx = (struct mdss_mdp_video_ctx *) ctl->intf_ctx[SLAVE_CTX];
@@ -2230,7 +2263,8 @@ static int mdss_mdp_video_avr_ctrl(struct mdss_mdp_ctl *ctl)
pr_err("invalid slave ctx\n");
return -EINVAL;
}
- mdss_mdp_video_avr_ctrl_setup(sctx, &ctl->avr_info, false);
+ mdss_mdp_video_avr_ctrl_setup(sctx, &ctl->avr_info, false,
+ enable);
}
return 0;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c
index e26b3843d7b0..353d07ad64ac 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_layer.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c
@@ -67,13 +67,89 @@ static inline void *u64_to_ptr(uint64_t address)
return (void *)(uintptr_t)address;
}
+static void mdss_mdp_disable_destination_scaler_setup(struct mdss_mdp_ctl *ctl)
+{
+ struct mdss_data_type *mdata = ctl->mdata;
+ struct mdss_panel_info *pinfo = &ctl->panel_data->panel_info;
+
+ if (test_bit(MDSS_CAPS_DEST_SCALER, mdata->mdss_caps_map)) {
+ if (ctl->mixer_left && ctl->mixer_right &&
+ ctl->mixer_left->ds && ctl->mixer_right->ds &&
+ ctl->mixer_left->ds->scaler.enable &&
+ ctl->mixer_right->ds->scaler.enable) {
+ /*
+ * DUAL mode disable
+ */
+ ctl->mixer_left->width = get_panel_width(ctl);
+ ctl->mixer_left->height = get_panel_yres(pinfo);
+ ctl->mixer_left->width /= 2;
+ ctl->mixer_right->width = ctl->mixer_left->width;
+ ctl->mixer_right->height = ctl->mixer_left->height;
+ ctl->mixer_left->roi = (struct mdss_rect) { 0, 0,
+ ctl->mixer_left->width,
+ ctl->mixer_left->height };
+ ctl->mixer_right->roi = (struct mdss_rect) { 0, 0,
+ ctl->mixer_right->width,
+ ctl->mixer_right->height };
+
+ /*
+ * Disable destination scaler by resetting the control
+ * flags and also need to disable in the QSEED3
+ * settings.
+ */
+ ctl->mixer_left->ds->flags = DS_SCALE_UPDATE |
+ DS_VALIDATE;
+ ctl->mixer_right->ds->flags = DS_SCALE_UPDATE |
+ DS_VALIDATE;
+ ctl->mixer_left->ds->scaler.enable = 0;
+ ctl->mixer_left->ds->scaler.detail_enhance.enable = 0;
+ ctl->mixer_right->ds->scaler.enable = 0;
+ ctl->mixer_right->ds->scaler.detail_enhance.enable = 0;
+
+ pr_debug("DS-Left+Right disable: left:%dx%d, right:%dx%d\n",
+ ctl->mixer_left->width,
+ ctl->mixer_left->height,
+ ctl->mixer_right->width,
+ ctl->mixer_right->height);
+ MDSS_XLOG(ctl->mixer_left->width,
+ ctl->mixer_left->height,
+ ctl->mixer_right->width,
+ ctl->mixer_right->height);
+ } else if (ctl->mixer_left && ctl->mixer_left->ds &&
+ ctl->mixer_left->ds->scaler.enable) {
+ /*
+ * Single DS disable
+ */
+ ctl->mixer_left->width = get_panel_width(ctl);
+ ctl->mixer_left->height = get_panel_yres(pinfo);
+ ctl->mixer_left->roi = (struct mdss_rect) { 0, 0,
+ ctl->mixer_left->width,
+ ctl->mixer_left->height };
+
+ ctl->mixer_left->ds->flags = DS_SCALE_UPDATE |
+ DS_VALIDATE;
+ ctl->mixer_left->ds->scaler.enable = 0;
+ ctl->mixer_left->ds->scaler.detail_enhance.enable = 0;
+
+ pr_debug("DS-left disable: wxh=%dx%d\n",
+ ctl->mixer_left->width,
+ ctl->mixer_left->height);
+ MDSS_XLOG(ctl->mixer_left->width,
+ ctl->mixer_left->height);
+ }
+ }
+}
+
static int __dest_scaler_data_setup(struct mdp_destination_scaler_data *ds_data,
struct mdss_mdp_destination_scaler *ds,
u32 max_input_width, u32 max_output_width)
{
struct mdp_scale_data_v2 *scale;
- ds->flags = (ds_data->flags & MDP_DESTSCALER_ENABLE) ? DS_ENABLE : 0;
+ if (ds_data->flags & MDP_DESTSCALER_ENABLE)
+ ds->flags |= DS_ENABLE;
+ else
+ ds->flags &= ~DS_ENABLE;
if (ds_data->flags & (MDP_DESTSCALER_SCALE_UPDATE |
MDP_DESTSCALER_ENHANCER_UPDATE)) {
@@ -101,8 +177,12 @@ static int __dest_scaler_data_setup(struct mdp_destination_scaler_data *ds_data,
ds->flags |= DS_SCALE_UPDATE;
if (ds_data->flags & MDP_DESTSCALER_ENHANCER_UPDATE)
ds->flags |= DS_ENHANCER_UPDATE;
- ds->src_width = scale->src_width[0];
- ds->src_height = scale->src_height[0];
+
+ /*
+ * Update with LM resolution
+ */
+ ds->src_width = ds_data->lm_width;
+ ds->src_height = ds_data->lm_height;
}
if (ds_data->flags == 0) {
@@ -110,6 +190,11 @@ static int __dest_scaler_data_setup(struct mdp_destination_scaler_data *ds_data,
ds_data->dest_scaler_ndx);
}
+ /*
+ * Confirm all check pass validation, and to be cleared in CTL after
+ * flush is issued.
+ */
+ ds->flags |= DS_VALIDATE;
return 0;
}
@@ -118,7 +203,7 @@ static int mdss_mdp_destination_scaler_pre_validate(struct mdss_mdp_ctl *ctl,
{
struct mdss_data_type *mdata;
struct mdss_panel_info *pinfo;
-
+ u16 mxleft_w = 0, mxleft_h = 0, mxright_w = 0, mxright_h = 0;
mdata = ctl->mdata;
/*
@@ -134,7 +219,7 @@ static int mdss_mdp_destination_scaler_pre_validate(struct mdss_mdp_ctl *ctl,
* height.
*/
pinfo = &ctl->panel_data->panel_info;
- if ((ds_data->lm_width > get_panel_xres(pinfo)) ||
+ if ((ds_data->lm_width > get_panel_width(ctl)) ||
(ds_data->lm_height > get_panel_yres(pinfo)) ||
(ds_data->lm_width == 0) ||
(ds_data->lm_height == 0)) {
@@ -142,14 +227,8 @@ static int mdss_mdp_destination_scaler_pre_validate(struct mdss_mdp_ctl *ctl,
ds_data->lm_width, ds_data->lm_height);
return -EINVAL;
}
-
- ctl->width = ds_data->lm_width;
- ctl->height = ds_data->lm_height;
-
- ctl->mixer_left->width = ds_data->lm_width;
- ctl->mixer_left->height = ds_data->lm_height;
- pr_debug("Update mixer-left width/height: %dx%d\n",
- ds_data->lm_width, ds_data->lm_width);
+ mxleft_w = ds_data->lm_width;
+ mxleft_h = ds_data->lm_height;
}
if (ctl->mixer_right && ctl->mixer_right->ds) {
@@ -174,25 +253,51 @@ static int mdss_mdp_destination_scaler_pre_validate(struct mdss_mdp_ctl *ctl,
* Split display both left and right should have the
* same width and height
*/
- ctl->mixer_right->width = ds_data->lm_width;
- ctl->mixer_right->height = ds_data->lm_height;
- pr_debug("Update mixer-right width/height: %dx%d\n",
- ds_data->lm_width, ds_data->lm_height);
+ mxright_w = ds_data->lm_width;
+ mxright_h = ds_data->lm_height;
if (ctl->mixer_left &&
- ((ctl->mixer_right->width !=
- ctl->mixer_left->width) ||
- (ctl->mixer_right->height !=
- ctl->mixer_left->height))) {
+ ((mxright_w != mxleft_w) ||
+ (mxright_h != mxleft_h))) {
pr_err("Mismatch width/heigth in LM for split display\n");
return -EINVAL;
}
+ }
+
+ /*
+ * Update mixer and control dimension after successful
+ * pre-validation
+ */
+ if (mxleft_w && mxleft_h) {
+ ctl->mixer_left->ds->last_mixer_width =
+ ctl->mixer_left->width;
+ ctl->mixer_left->ds->last_mixer_height =
+ ctl->mixer_left->height;
+
+ ctl->width = mxleft_w;
+ ctl->height = mxleft_h;
+ ctl->mixer_left->width = mxleft_w;
+ ctl->mixer_left->height = mxleft_h;
+ pr_debug("Update mixer-left width/height: %dx%d\n",
+ mxleft_w, mxleft_h);
+ }
+
+ if (mxright_w && mxright_h) {
+ ctl->mixer_right->ds->last_mixer_width =
+ ctl->mixer_right->width;
+ ctl->mixer_right->ds->last_mixer_height =
+ ctl->mixer_right->height;
+
+ ctl->mixer_right->width = mxright_w;
+ ctl->mixer_right->height = mxright_h;
+ pr_debug("Update mixer-right width/height: %dx%d\n",
+ mxright_w, mxright_h);
/*
* For split display, CTL width should be equal to
* whole panel size
*/
- ctl->width += ds_data->lm_width;
+ ctl->width += mxright_w;
}
pr_debug("Updated CTL width:%d, height:%d\n",
@@ -236,19 +341,23 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd,
MDSS_MDP_DS_OVERFETCH_SIZE,
mdata->max_dest_scaler_output_width);
if (ret)
- return ret;
+ goto reset_mixer;
ret = __dest_scaler_data_setup(&ds_data[1], ds_right,
mdata->max_dest_scaler_input_width -
MDSS_MDP_DS_OVERFETCH_SIZE,
mdata->max_dest_scaler_output_width);
if (ret)
- return ret;
+ goto reset_mixer;
ds_left->flags &= ~(DS_LEFT|DS_RIGHT);
ds_left->flags |= DS_DUAL_MODE;
ds_right->flags &= ~(DS_LEFT|DS_RIGHT);
ds_right->flags |= DS_DUAL_MODE;
+ MDSS_XLOG(ds_left->num, ds_left->src_width,
+ ds_left->src_height, ds_left->flags,
+ ds_right->num, ds_right->src_width,
+ ds_right->src_height, ds_right->flags);
break;
case DS_LEFT:
@@ -262,6 +371,11 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd,
ret = __dest_scaler_data_setup(&ds_data[0], ds_left,
mdata->max_dest_scaler_input_width,
mdata->max_dest_scaler_output_width);
+ if (ret)
+ goto reset_mixer;
+
+ MDSS_XLOG(ds_left->num, ds_left->src_width,
+ ds_left->src_height, ds_left->flags);
break;
case DS_RIGHT:
@@ -276,6 +390,11 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd,
ret = __dest_scaler_data_setup(&ds_data[0], ds_right,
mdata->max_dest_scaler_input_width,
mdata->max_dest_scaler_output_width);
+ if (ret)
+ goto reset_mixer;
+
+ MDSS_XLOG(ds_right->num, ds_right->src_width,
+ ds_right->src_height, ds_right->flags);
break;
}
@@ -312,6 +431,40 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd,
pr_err("Invalid Dest-scaler output width/height: %d/%d\n",
scaler_width, scaler_height);
ret = -EINVAL;
+ goto reset_mixer;
+ }
+
+ return ret;
+
+reset_mixer:
+ /* reverting mixer and control dimension */
+ if (ctl->mixer_left && ctl->mixer_left->ds &&
+ ctl->mixer_left->ds->last_mixer_width) {
+ ctl->width = ctl->mixer_left->ds->last_mixer_width;
+ ctl->height = ctl->mixer_left->ds->last_mixer_height;
+ ctl->mixer_left->width =
+ ctl->mixer_left->ds->last_mixer_width;
+ ctl->mixer_left->height =
+ ctl->mixer_left->ds->last_mixer_height;
+ if (ds_left)
+ ds_left->flags &= ~DS_ENABLE;
+ MDSS_XLOG(ctl->width, ctl->height,
+ ctl->mixer_left->width,
+ ctl->mixer_left->height);
+ }
+
+ if (ctl->mixer_right && ctl->mixer_right->ds &&
+ ctl->mixer_right->ds->last_mixer_width) {
+ ctl->width += ctl->mixer_right->ds->last_mixer_width;
+ ctl->mixer_right->width =
+ ctl->mixer_right->ds->last_mixer_width;
+ ctl->mixer_right->height =
+ ctl->mixer_right->ds->last_mixer_height;
+ if (ds_right)
+ ds_right->flags &= ~DS_ENABLE;
+ MDSS_XLOG(ctl->width, ctl->height,
+ ctl->mixer_right->width,
+ ctl->mixer_right->height);
}
return ret;
@@ -1939,6 +2092,7 @@ static int __validate_layers(struct msm_fb_data_type *mfd,
enum layer_pipe_q pipe_q_type;
enum layer_zorder_used zorder_used[MDSS_MDP_MAX_STAGE] = {0};
enum mdss_mdp_pipe_rect rect_num;
+ struct mdp_destination_scaler_data *ds_data;
ret = mutex_lock_interruptible(&mdp5_data->ov_lock);
if (ret)
@@ -2194,11 +2348,10 @@ static int __validate_layers(struct msm_fb_data_type *mfd,
layer->z_order -= MDSS_MDP_STAGE_0;
}
+ ds_data = commit->dest_scaler;
if (test_bit(MDSS_CAPS_DEST_SCALER, mdata->mdss_caps_map) &&
- commit->dest_scaler &&
+ ds_data && (ds_data->flags & MDP_DESTSCALER_ENABLE) &&
commit->dest_scaler_cnt) {
- struct mdp_destination_scaler_data *ds_data =
- commit->dest_scaler;
/*
* Find out which DS block to use based on DS commit info
@@ -2217,8 +2370,7 @@ static int __validate_layers(struct msm_fb_data_type *mfd,
}
ret = mdss_mdp_validate_destination_scaler(mfd,
- commit->dest_scaler,
- ds_mode);
+ ds_data, ds_mode);
if (ret) {
pr_err("fail to validate destination scaler\n");
layer->error_code = ret;
@@ -2472,6 +2624,7 @@ int mdss_mdp_layer_atomic_validate(struct msm_fb_data_type *mfd,
struct file *file, struct mdp_layer_commit_v1 *commit)
{
struct mdss_overlay_private *mdp5_data;
+ struct mdp_destination_scaler_data *ds_data;
int rc = 0;
if (!mfd || !commit) {
@@ -2505,15 +2658,17 @@ int mdss_mdp_layer_atomic_validate(struct msm_fb_data_type *mfd,
}
}
- if (commit->dest_scaler && commit->dest_scaler_cnt) {
+ ds_data = commit->dest_scaler;
+ if (ds_data && commit->dest_scaler_cnt &&
+ (ds_data->flags & MDP_DESTSCALER_ENABLE)) {
rc = mdss_mdp_destination_scaler_pre_validate(mdp5_data->ctl,
- commit->dest_scaler,
- commit->dest_scaler_cnt);
+ ds_data, commit->dest_scaler_cnt);
if (IS_ERR_VALUE(rc)) {
pr_err("Destination scaler pre-validate failed\n");
return -EINVAL;
}
- }
+ } else
+ mdss_mdp_disable_destination_scaler_setup(mdp5_data->ctl);
rc = mdss_mdp_avr_validate(mfd, commit);
if (IS_ERR_VALUE(rc)) {
diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
index 965d4a6cfb5e..9bdc66232dd5 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
@@ -2958,7 +2958,7 @@ static ssize_t dynamic_fps_sysfs_wta_dfps(struct device *dev,
if (pdata->panel_info.dfps_update ==
DFPS_IMMEDIATE_MULTI_UPDATE_MODE_CLK_HFP) {
- if (sscanf(buf, "%d %d %d %d %d",
+ if (sscanf(buf, "%u %u %u %u %u",
&data.hfp, &data.hbp, &data.hpw,
&data.clk_rate, &data.fps) != 5) {
pr_err("could not read input\n");
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c
index ee1cd8fd623e..47edc320233a 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c
@@ -2480,6 +2480,28 @@ static int pp_dest_scaler_setup(struct mdss_mdp_mixer *mixer)
if (!test_bit(MDSS_CAPS_DEST_SCALER, mdata->mdss_caps_map) || !ds)
return 0;
+ /*
+ * Non-validated DS data will be related to PM event. It is required
+ * to send out last setup to match the mixer and panel configuration.
+ */
+ if (!(ds->flags & DS_VALIDATE)) {
+ pr_debug("Apply old DS[%d] for non validate data\n", ds->num);
+ if (ds->flags & DS_ENABLE)
+ ds->flags |= (DS_SCALE_UPDATE | DS_ENHANCER_UPDATE);
+ ds->flags |= DS_VALIDATE;
+ }
+
+ /*
+ * If mark for dirty update, force update to scaler and detail
+ * enhancer.
+ */
+ if (ds->flags & DS_DIRTY_UPDATE) {
+ pr_debug("Scale dirty update requested\n");
+ ds->flags |= (DS_SCALE_UPDATE | DS_ENHANCER_UPDATE |
+ DS_VALIDATE);
+ ds->flags &= ~DS_DIRTY_UPDATE;
+ }
+
ds_offset = ds->ds_base;
op_mode = readl_relaxed(MDSS_MDP_REG_DEST_SCALER_OP_MODE +
ds_offset);
@@ -2519,12 +2541,37 @@ static int pp_dest_scaler_setup(struct mdss_mdp_mixer *mixer)
}
/* Destinations scaler shared the flush with DSPP in control */
- if (ds->flags & DS_ENABLE)
+ if (ds->flags & (DS_ENABLE | DS_VALIDATE)) {
+ pr_debug("FLUSH[%d]: flags:%X, op_mode:%x\n",
+ ds->num, ds->flags, op_mode);
ctl->flush_bits |= BIT(13 + ds->num);
+ }
+ ds->flags &= ~DS_VALIDATE;
return 0;
}
+void mdss_mdp_pp_dest_scaler_resume(struct mdss_mdp_ctl *ctl)
+{
+ if (!ctl || !ctl->mdata) {
+ pr_err("Invalid ctl\n");
+ return;
+ }
+
+ if (!test_bit(MDSS_CAPS_DEST_SCALER, ctl->mdata->mdss_caps_map))
+ return;
+
+ if (ctl->mixer_left && ctl->mixer_left->ds) {
+ ctl->mixer_left->ds->flags |= DS_DIRTY_UPDATE;
+ pr_debug("DS left mark dirty\n");
+ }
+
+ if (ctl->mixer_right && ctl->mixer_right->ds) {
+ ctl->mixer_right->ds->flags |= DS_DIRTY_UPDATE;
+ pr_debug("DS right mark dirty\n");
+ }
+}
+
int mdss_mdp_pp_setup(struct mdss_mdp_ctl *ctl)
{
int ret = 0;
diff --git a/drivers/video/fbdev/msm/mdss_panel.c b/drivers/video/fbdev/msm/mdss_panel.c
index 16c2d4e6e92d..31cf74274131 100644
--- a/drivers/video/fbdev/msm/mdss_panel.c
+++ b/drivers/video/fbdev/msm/mdss_panel.c
@@ -455,10 +455,12 @@ int mdss_panel_debugfs_setup(struct mdss_panel_info *panel_info, struct dentry
return -ENOMEM;
}
+ debugfs_info->parent = parent;
debugfs_info->root = debugfs_create_dir(intf_str, parent);
if (IS_ERR_OR_NULL(debugfs_info->root)) {
pr_err("Debugfs create dir failed with error: %ld\n",
PTR_ERR(debugfs_info->root));
+ kfree(debugfs_info);
return -ENODEV;
}
@@ -503,6 +505,7 @@ int mdss_panel_debugfs_init(struct mdss_panel_info *panel_info,
intf_str);
if (rc) {
pr_err("error in initilizing panel debugfs\n");
+ mdss_panel_debugfs_cleanup(&pdata->panel_info);
return rc;
}
pdata = pdata->next;
@@ -516,13 +519,16 @@ void mdss_panel_debugfs_cleanup(struct mdss_panel_info *panel_info)
{
struct mdss_panel_data *pdata;
struct mdss_panel_debugfs_info *debugfs_info;
+ struct dentry *parent = NULL;
pdata = container_of(panel_info, struct mdss_panel_data, panel_info);
do {
debugfs_info = pdata->panel_info.debugfs_info;
- if (debugfs_info && debugfs_info->root)
- debugfs_remove_recursive(debugfs_info->root);
+ if (debugfs_info && !parent)
+ parent = debugfs_info->parent;
+ kfree(debugfs_info);
pdata = pdata->next;
} while (pdata);
+ debugfs_remove_recursive(parent);
pr_debug("Cleaned up mdss_panel_debugfs_info\n");
}
diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h
index be0491195263..18a93f9d3c3e 100644
--- a/drivers/video/fbdev/msm/mdss_panel.h
+++ b/drivers/video/fbdev/msm/mdss_panel.h
@@ -879,6 +879,7 @@ struct mdss_panel_data {
struct mdss_panel_debugfs_info {
struct dentry *root;
+ struct dentry *parent;
struct mdss_panel_info panel_info;
u32 override_flag;
struct mdss_panel_debugfs_info *next;
diff --git a/include/dt-bindings/clock/msm-clocks-cobalt.h b/include/dt-bindings/clock/msm-clocks-cobalt.h
index 251b7e314238..4bacef303967 100644
--- a/include/dt-bindings/clock/msm-clocks-cobalt.h
+++ b/include/dt-bindings/clock/msm-clocks-cobalt.h
@@ -198,9 +198,7 @@
#define clk_gcc_gp1_clk 0x057f7b69
#define clk_gcc_gp2_clk 0x9bf83ffd
#define clk_gcc_gp3_clk 0xec6539ee
-#define clk_gcc_gpu_snoc_dvm_gfx_clk 0xc9147451
#define clk_gcc_gpu_bimc_gfx_clk 0x3909459b
-#define clk_gcc_gpu_bimc_gfx_src_clk 0x377cb748
#define clk_gcc_gpu_cfg_ahb_clk 0x72f20a57
#define clk_gcc_gpu_iref_clk 0xfd82abad
#define clk_gcc_hmss_ahb_clk 0x62818713
diff --git a/include/dt-bindings/clock/msm-clocks-hwio-cobalt.h b/include/dt-bindings/clock/msm-clocks-hwio-cobalt.h
index 81d75bc9a8d6..f10afffc74b2 100644
--- a/include/dt-bindings/clock/msm-clocks-hwio-cobalt.h
+++ b/include/dt-bindings/clock/msm-clocks-hwio-cobalt.h
@@ -167,9 +167,7 @@
#define GCC_GP2_CBCR 0x65000
#define GCC_GP3_CBCR 0x66000
#define GCC_GPU_BIMC_GFX_CBCR 0x71010
-#define GCC_GPU_BIMC_GFX_SRC_CBCR 0x7100C
#define GCC_GPU_CFG_AHB_CBCR 0x71004
-#define GCC_GPU_SNOC_DVM_GFX_CBCR 0x71018
#define GCC_GPU_IREF_EN 0x88010
#define GCC_HMSS_AHB_CBCR 0x48000
#define GCC_HMSS_DVM_BUS_CBCR 0x4808C
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/linux/qpnp/qpnp-revid.h b/include/linux/qpnp/qpnp-revid.h
index 7c12823894df..652d68ac63bf 100644
--- a/include/linux/qpnp/qpnp-revid.h
+++ b/include/linux/qpnp/qpnp-revid.h
@@ -177,6 +177,10 @@
/* PMICOBALT */
#define PMICOBALT_SUBTYPE 0x15
+/* PMFALCON */
+#define PM2FALCON_SUBTYPE 0x1A
+#define PMFALCON_SUBTYPE 0x1B
+
#define PMICOBALT_V1P0_REV1 0x00
#define PMICOBALT_V1P0_REV2 0x00
#define PMICOBALT_V1P0_REV3 0x00
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 801315d1d405..9076fd9f92b2 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -695,6 +695,18 @@ struct cfg80211_acl_data {
struct mac_address mac_addrs[];
};
+/*
+ * cfg80211_bitrate_mask - masks for bitrate control
+ */
+struct cfg80211_bitrate_mask {
+ struct {
+ u32 legacy;
+ u8 ht_mcs[IEEE80211_HT_MCS_MASK_LEN];
+ u16 vht_mcs[NL80211_VHT_NSS_MAX];
+ enum nl80211_txrate_gi gi;
+ } control[IEEE80211_NUM_BANDS];
+};
+
/**
* struct cfg80211_ap_settings - AP configuration
*
@@ -719,6 +731,7 @@ struct cfg80211_acl_data {
* MAC address based access control
* @pbss: If set, start as a PCP instead of AP. Relevant for DMG
* networks.
+ * @beacon_rate: masks for setting user configured beacon tx rate.
*/
struct cfg80211_ap_settings {
struct cfg80211_chan_def chandef;
@@ -738,6 +751,7 @@ struct cfg80211_ap_settings {
bool p2p_opp_ps;
const struct cfg80211_acl_data *acl;
bool pbss;
+ struct cfg80211_bitrate_mask beacon_rate;
};
/**
@@ -1945,17 +1959,6 @@ enum wiphy_params_flags {
WIPHY_PARAM_DYN_ACK = 1 << 5,
};
-/*
- * cfg80211_bitrate_mask - masks for bitrate control
- */
-struct cfg80211_bitrate_mask {
- struct {
- u32 legacy;
- u8 ht_mcs[IEEE80211_HT_MCS_MASK_LEN];
- u16 vht_mcs[NL80211_VHT_NSS_MAX];
- enum nl80211_txrate_gi gi;
- } control[IEEE80211_NUM_BANDS];
-};
/**
* struct cfg80211_pmksa - PMK Security Association
*
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index 0bac6947a1cb..d6ff882ad6a7 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -381,6 +381,7 @@ header-y += prctl.h
header-y += psci.h
header-y += ptp_clock.h
header-y += ptrace.h
+header-y += qbt1000.h
header-y += qcedev.h
header-y += qcota.h
header-y += qnx4_fs.h
diff --git a/include/uapi/linux/hbtp_input.h b/include/uapi/linux/hbtp_input.h
index 67692ed8e3b8..9173c2ab72ed 100644
--- a/include/uapi/linux/hbtp_input.h
+++ b/include/uapi/linux/hbtp_input.h
@@ -43,6 +43,17 @@ struct hbtp_input_key {
__s32 value;
};
+enum hbtp_afe_signal {
+ HBTP_AFE_SIGNAL_ON_RESUME,
+ HBTP_AFE_SIGNAL_ON_SUSPEND,
+};
+
+enum hbtp_afe_power_ctrl {
+ HBTP_AFE_POWER_ENABLE_SYNC,
+ HBTP_AFE_POWER_ENABLE_SYNC_SIGNAL,
+};
+
+
/* ioctl */
#define HBTP_INPUT_IOCTL_BASE 'T'
#define HBTP_SET_ABSPARAM _IOW(HBTP_INPUT_IOCTL_BASE, 201, \
@@ -53,6 +64,10 @@ struct hbtp_input_key {
enum hbtp_afe_power_cmd)
#define HBTP_SET_KEYDATA _IOW(HBTP_INPUT_IOCTL_BASE, 204, \
struct hbtp_input_key)
+#define HBTP_SET_SYNCSIGNAL _IOW(HBTP_INPUT_IOCTL_BASE, 205, \
+ enum hbtp_afe_signal)
+#define HBTP_SET_POWER_CTRL _IOW(HBTP_INPUT_IOCTL_BASE, 206, \
+ enum hbtp_afe_power_ctrl)
#endif /* _UAPI_HBTP_INPUT_H */
diff --git a/include/uapi/linux/qbt1000.h b/include/uapi/linux/qbt1000.h
new file mode 100644
index 000000000000..8a3be2c634d3
--- /dev/null
+++ b/include/uapi/linux/qbt1000.h
@@ -0,0 +1,99 @@
+#ifndef _UAPI_QBT1000_H_
+#define _UAPI_QBT1000_H_
+
+#define MAX_NAME_SIZE 32
+
+/*
+* enum qbt1000_commands -
+* enumeration of command options
+* @QBT1000_LOAD_APP - cmd loads TZ app
+* @QBT1000_UNLOAD_APP - cmd unloads TZ app
+* @QBT1000_SEND_TZCMD - sends cmd to TZ app
+* @QBT1000_SET_FINGER_DETECT_KEY - sets the input key to send on finger detect
+* @QBT1000_CONFIGURE_POWER_KEY - enables/disables sending the power key on
+ finger down events
+*/
+enum qbt1000_commands {
+ QBT1000_LOAD_APP = 100,
+ QBT1000_UNLOAD_APP = 101,
+ QBT1000_SEND_TZCMD = 102,
+ QBT1000_SET_FINGER_DETECT_KEY = 103,
+ QBT1000_CONFIGURE_POWER_KEY = 104
+};
+
+/*
+* enum qbt1000_fw_event -
+* enumeration of firmware events
+* @FW_EVENT_FINGER_DOWN - finger down detected
+* @FW_EVENT_FINGER_UP - finger up detected
+* @FW_EVENT_INDICATION - an indication IPC from the firmware is pending
+*/
+enum qbt1000_fw_event {
+ FW_EVENT_FINGER_DOWN = 1,
+ FW_EVENT_FINGER_UP = 2,
+ FW_EVENT_CBGE_REQUIRED = 3,
+};
+
+/*
+* struct qbt1000_app -
+* used to load and unload apps in TZ
+* @app_handle - qseecom handle for clients
+* @name - Name of secure app to load
+* @size - Size of requested buffer of secure app
+* @high_band_width - 1 - for high bandwidth usage
+* 0 - for normal bandwidth usage
+*/
+struct qbt1000_app {
+ struct qseecom_handle **app_handle;
+ char name[MAX_NAME_SIZE];
+ uint32_t size;
+ uint8_t high_band_width;
+};
+
+/*
+* struct qbt1000_send_tz_cmd -
+* used to cmds to TZ App
+* @app_handle - qseecom handle for clients
+* @req_buf - Buffer containing request for secure app
+* @req_buf_len - Length of request buffer
+* @rsp_buf - Buffer containing response from secure app
+* @rsp_buf_len - Length of response buffer
+*/
+struct qbt1000_send_tz_cmd {
+ struct qseecom_handle *app_handle;
+ uint8_t *req_buf;
+ uint32_t req_buf_len;
+ uint8_t *rsp_buf;
+ uint32_t rsp_buf_len;
+};
+
+/*
+* struct qbt1000_erie_event -
+* used to receive events from Erie
+* @buf - Buffer containing event from Erie
+* @buf_len - Length of buffer
+*/
+struct qbt1000_erie_event {
+ uint8_t *buf;
+ uint32_t buf_len;
+};
+
+/*
+* struct qbt1000_set_finger_detect_key -
+* used to configure the input key which is sent on finger down/up event
+* @key_code - Key code to send on finger down/up. 0 disables sending key events
+*/
+struct qbt1000_set_finger_detect_key {
+ unsigned int key_code;
+};
+
+/*
+* struct qbt1000_configure_power_key -
+* used to configure whether the power key is sent on finger down
+* @enable - if non-zero, power key is sent on finger down
+*/
+struct qbt1000_configure_power_key {
+ unsigned int enable;
+};
+
+#endif /* _UAPI_QBT1000_H_ */
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index e32d4d7903b0..e0f212743c77 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -3525,7 +3525,7 @@ static void dec_throttled_cfs_rq_hmp_stats(struct hmp_sched_stats *stats,
BUG_ON(stats->nr_big_tasks < 0 ||
(s64)stats->cumulative_runnable_avg < 0);
- verify_pred_demands_sum(stats);
+ BUG_ON((s64)stats->pred_demands_sum < 0);
}
#else /* CONFIG_CFS_BANDWIDTH */
diff --git a/kernel/sched/hmp.c b/kernel/sched/hmp.c
index d220482f4dbc..1d55e226196f 100644
--- a/kernel/sched/hmp.c
+++ b/kernel/sched/hmp.c
@@ -1387,7 +1387,7 @@ void dec_rq_hmp_stats(struct rq *rq, struct task_struct *p, int change_cra)
dec_cumulative_runnable_avg(&rq->hmp_stats, p);
}
-static void reset_hmp_stats(struct hmp_sched_stats *stats, int reset_cra)
+void reset_hmp_stats(struct hmp_sched_stats *stats, int reset_cra)
{
stats->nr_big_tasks = 0;
if (reset_cra) {
@@ -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/kernel/sched/sched.h b/kernel/sched/sched.h
index 471dc9faab35..4289bf6cd642 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -1407,6 +1407,7 @@ extern void inc_rq_hmp_stats(struct rq *rq,
struct task_struct *p, int change_cra);
extern void dec_rq_hmp_stats(struct rq *rq,
struct task_struct *p, int change_cra);
+extern void reset_hmp_stats(struct hmp_sched_stats *stats, int reset_cra);
extern int is_big_task(struct task_struct *p);
extern int upmigrate_discouraged(struct task_struct *p);
extern struct sched_cluster *rq_cluster(struct rq *rq);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 569b77de3cae..4d7281df26b6 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3245,6 +3245,279 @@ static int nl80211_set_mac_acl(struct sk_buff *skb, struct genl_info *info)
return err;
}
+static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
+ u8 *rates, u8 rates_len)
+{
+ u8 i;
+ u32 mask = 0;
+
+ for (i = 0; i < rates_len; i++) {
+ int rate = (rates[i] & 0x7f) * 5;
+ int ridx;
+
+ for (ridx = 0; ridx < sband->n_bitrates; ridx++) {
+ struct ieee80211_rate *srate =
+ &sband->bitrates[ridx];
+ if (rate == srate->bitrate) {
+ mask |= 1 << ridx;
+ break;
+ }
+ }
+ if (ridx == sband->n_bitrates)
+ return 0; /* rate not found */
+ }
+
+ return mask;
+}
+
+static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband,
+ u8 *rates, u8 rates_len,
+ u8 mcs[IEEE80211_HT_MCS_MASK_LEN])
+{
+ u8 i;
+
+ memset(mcs, 0, IEEE80211_HT_MCS_MASK_LEN);
+
+ for (i = 0; i < rates_len; i++) {
+ int ridx, rbit;
+
+ ridx = rates[i] / 8;
+ rbit = BIT(rates[i] % 8);
+
+ /* check validity */
+ if ((ridx < 0) || (ridx >= IEEE80211_HT_MCS_MASK_LEN))
+ return false;
+
+ /* check availability */
+ if (sband->ht_cap.mcs.rx_mask[ridx] & rbit)
+ mcs[ridx] |= rbit;
+ else
+ return false;
+ }
+
+ return true;
+}
+
+static u16 vht_mcs_map_to_mcs_mask(u8 vht_mcs_map)
+{
+ u16 mcs_mask = 0;
+
+ switch (vht_mcs_map) {
+ case IEEE80211_VHT_MCS_NOT_SUPPORTED:
+ break;
+ case IEEE80211_VHT_MCS_SUPPORT_0_7:
+ mcs_mask = 0x00FF;
+ break;
+ case IEEE80211_VHT_MCS_SUPPORT_0_8:
+ mcs_mask = 0x01FF;
+ break;
+ case IEEE80211_VHT_MCS_SUPPORT_0_9:
+ mcs_mask = 0x03FF;
+ break;
+ default:
+ break;
+ }
+
+ return mcs_mask;
+}
+
+static void vht_build_mcs_mask(u16 vht_mcs_map,
+ u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
+{
+ u8 nss;
+
+ for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) {
+ vht_mcs_mask[nss] = vht_mcs_map_to_mcs_mask(vht_mcs_map & 0x03);
+ vht_mcs_map >>= 2;
+ }
+}
+
+static bool vht_set_mcs_mask(struct ieee80211_supported_band *sband,
+ struct nl80211_txrate_vht *txrate,
+ u16 mcs[NL80211_VHT_NSS_MAX])
+{
+ u16 tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
+ u16 tx_mcs_mask[NL80211_VHT_NSS_MAX] = {};
+ u8 i;
+
+ if (!sband->vht_cap.vht_supported)
+ return false;
+
+ memset(mcs, 0, sizeof(u16) * NL80211_VHT_NSS_MAX);
+
+ /* Build vht_mcs_mask from VHT capabilities */
+ vht_build_mcs_mask(tx_mcs_map, tx_mcs_mask);
+
+ for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
+ if ((tx_mcs_mask[i] & txrate->mcs[i]) == txrate->mcs[i])
+ mcs[i] = txrate->mcs[i];
+ else
+ return false;
+ }
+
+ return true;
+}
+
+static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
+ [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY,
+ .len = NL80211_MAX_SUPP_RATES },
+ [NL80211_TXRATE_HT] = { .type = NLA_BINARY,
+ .len = NL80211_MAX_SUPP_HT_RATES },
+ [NL80211_TXRATE_VHT] = { .len = sizeof(struct nl80211_txrate_vht)},
+ [NL80211_TXRATE_GI] = { .type = NLA_U8 },
+};
+
+static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
+ struct cfg80211_bitrate_mask *mask)
+{
+ struct nlattr *tb[NL80211_TXRATE_MAX + 1];
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ int rem, i;
+ struct nlattr *tx_rates;
+ struct ieee80211_supported_band *sband;
+ u16 vht_tx_mcs_map;
+
+ memset(mask, 0, sizeof(*mask));
+ /* Default to all rates enabled */
+ for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
+ sband = rdev->wiphy.bands[i];
+
+ if (!sband)
+ continue;
+
+ mask->control[i].legacy = (1 << sband->n_bitrates) - 1;
+ memcpy(mask->control[i].ht_mcs,
+ sband->ht_cap.mcs.rx_mask,
+ sizeof(mask->control[i].ht_mcs));
+
+ if (!sband->vht_cap.vht_supported)
+ continue;
+
+ vht_tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
+ vht_build_mcs_mask(vht_tx_mcs_map, mask->control[i].vht_mcs);
+ }
+
+ /* if no rates are given set it back to the defaults */
+ if (!info->attrs[NL80211_ATTR_TX_RATES])
+ goto out;
+
+ /* The nested attribute uses enum nl80211_band as the index. This maps
+ * directly to the enum nl80211_band values used in cfg80211.
+ */
+ BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8);
+ nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) {
+ enum ieee80211_band band = nla_type(tx_rates);
+ int err;
+
+ if (band < 0 || band >= IEEE80211_NUM_BANDS)
+ return -EINVAL;
+ sband = rdev->wiphy.bands[band];
+ if (sband == NULL)
+ return -EINVAL;
+ err = nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates),
+ nla_len(tx_rates), nl80211_txattr_policy);
+ if (err)
+ return err;
+ if (tb[NL80211_TXRATE_LEGACY]) {
+ mask->control[band].legacy = rateset_to_mask(
+ sband,
+ nla_data(tb[NL80211_TXRATE_LEGACY]),
+ nla_len(tb[NL80211_TXRATE_LEGACY]));
+ if ((mask->control[band].legacy == 0) &&
+ nla_len(tb[NL80211_TXRATE_LEGACY]))
+ return -EINVAL;
+ }
+ if (tb[NL80211_TXRATE_HT]) {
+ if (!ht_rateset_to_mask(
+ sband,
+ nla_data(tb[NL80211_TXRATE_HT]),
+ nla_len(tb[NL80211_TXRATE_HT]),
+ mask->control[band].ht_mcs))
+ return -EINVAL;
+ }
+ if (tb[NL80211_TXRATE_VHT]) {
+ if (!vht_set_mcs_mask(
+ sband,
+ nla_data(tb[NL80211_TXRATE_VHT]),
+ mask->control[band].vht_mcs))
+ return -EINVAL;
+ }
+ if (tb[NL80211_TXRATE_GI]) {
+ mask->control[band].gi =
+ nla_get_u8(tb[NL80211_TXRATE_GI]);
+ if (mask->control[band].gi > NL80211_TXRATE_FORCE_LGI)
+ return -EINVAL;
+ }
+
+ if (mask->control[band].legacy == 0) {
+ /* don't allow empty legacy rates if HT or VHT
+ * are not even supported.
+ */
+ if (!(rdev->wiphy.bands[band]->ht_cap.ht_supported ||
+ rdev->wiphy.bands[band]->vht_cap.vht_supported))
+ return -EINVAL;
+
+ for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
+ if (mask->control[band].ht_mcs[i])
+ goto out;
+
+ for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
+ if (mask->control[band].vht_mcs[i])
+ goto out;
+
+ /* legacy and mcs rates may not be both empty */
+ return -EINVAL;
+ }
+ }
+
+out:
+ return 0;
+}
+
+static int validate_beacon_tx_rate(struct cfg80211_ap_settings *params)
+{
+ u32 rate, count_ht, count_vht, i;
+ enum nl80211_band band;
+
+ band = params->chandef.chan->band;
+ rate = params->beacon_rate.control[band].legacy;
+
+ /* Allow only one rate */
+ if (hweight32(rate) > 1)
+ return -EINVAL;
+
+ count_ht = 0;
+ for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
+ if (hweight8(params->beacon_rate.control[band].ht_mcs[i]) > 1) {
+ return -EINVAL;
+ } else if (params->beacon_rate.control[band].ht_mcs[i]) {
+ count_ht++;
+ if (count_ht > 1)
+ return -EINVAL;
+ }
+ if (count_ht && rate)
+ return -EINVAL;
+ }
+
+ count_vht = 0;
+ for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
+ if (hweight16(params->beacon_rate.control[band].vht_mcs[i]) > 1) {
+ return -EINVAL;
+ } else if (params->beacon_rate.control[band].vht_mcs[i]) {
+ count_vht++;
+ if (count_vht > 1)
+ return -EINVAL;
+ }
+ if (count_vht && rate)
+ return -EINVAL;
+ }
+
+ if ((count_ht && count_vht) || (!rate && !count_ht && !count_vht))
+ return -EINVAL;
+
+ return 0;
+}
+
static int nl80211_parse_beacon(struct nlattr *attrs[],
struct cfg80211_beacon_data *bcn)
{
@@ -3474,6 +3747,16 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
wdev->iftype))
return -EINVAL;
+ if (info->attrs[NL80211_ATTR_TX_RATES]) {
+ err = nl80211_parse_tx_bitrate_mask(info, &params.beacon_rate);
+ if (err)
+ return err;
+
+ err = validate_beacon_tx_rate(&params);
+ if (err)
+ return err;
+ }
+
if (info->attrs[NL80211_ATTR_SMPS_MODE]) {
params.smps_mode =
nla_get_u8(info->attrs[NL80211_ATTR_SMPS_MODE]);
@@ -8292,237 +8575,21 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
return rdev_cancel_remain_on_channel(rdev, wdev, cookie);
}
-static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
- u8 *rates, u8 rates_len)
-{
- u8 i;
- u32 mask = 0;
-
- for (i = 0; i < rates_len; i++) {
- int rate = (rates[i] & 0x7f) * 5;
- int ridx;
- for (ridx = 0; ridx < sband->n_bitrates; ridx++) {
- struct ieee80211_rate *srate =
- &sband->bitrates[ridx];
- if (rate == srate->bitrate) {
- mask |= 1 << ridx;
- break;
- }
- }
- if (ridx == sband->n_bitrates)
- return 0; /* rate not found */
- }
-
- return mask;
-}
-
-static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband,
- u8 *rates, u8 rates_len,
- u8 mcs[IEEE80211_HT_MCS_MASK_LEN])
-{
- u8 i;
-
- memset(mcs, 0, IEEE80211_HT_MCS_MASK_LEN);
-
- for (i = 0; i < rates_len; i++) {
- int ridx, rbit;
-
- ridx = rates[i] / 8;
- rbit = BIT(rates[i] % 8);
-
- /* check validity */
- if ((ridx < 0) || (ridx >= IEEE80211_HT_MCS_MASK_LEN))
- return false;
-
- /* check availability */
- if (sband->ht_cap.mcs.rx_mask[ridx] & rbit)
- mcs[ridx] |= rbit;
- else
- return false;
- }
-
- return true;
-}
-
-static u16 vht_mcs_map_to_mcs_mask(u8 vht_mcs_map)
-{
- u16 mcs_mask = 0;
-
- switch (vht_mcs_map) {
- case IEEE80211_VHT_MCS_NOT_SUPPORTED:
- break;
- case IEEE80211_VHT_MCS_SUPPORT_0_7:
- mcs_mask = 0x00FF;
- break;
- case IEEE80211_VHT_MCS_SUPPORT_0_8:
- mcs_mask = 0x01FF;
- break;
- case IEEE80211_VHT_MCS_SUPPORT_0_9:
- mcs_mask = 0x03FF;
- break;
- default:
- break;
- }
-
- return mcs_mask;
-}
-
-static void vht_build_mcs_mask(u16 vht_mcs_map,
- u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
-{
- u8 nss;
-
- for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) {
- vht_mcs_mask[nss] = vht_mcs_map_to_mcs_mask(vht_mcs_map & 0x03);
- vht_mcs_map >>= 2;
- }
-}
-
-static bool vht_set_mcs_mask(struct ieee80211_supported_band *sband,
- struct nl80211_txrate_vht *txrate,
- u16 mcs[NL80211_VHT_NSS_MAX])
-{
- u16 tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
- u16 tx_mcs_mask[NL80211_VHT_NSS_MAX] = {};
- u8 i;
-
- if (!sband->vht_cap.vht_supported)
- return false;
-
- memset(mcs, 0, sizeof(u16) * NL80211_VHT_NSS_MAX);
-
- /* Build vht_mcs_mask from VHT capabilities */
- vht_build_mcs_mask(tx_mcs_map, tx_mcs_mask);
-
- for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
- if ((tx_mcs_mask[i] & txrate->mcs[i]) == txrate->mcs[i])
- mcs[i] = txrate->mcs[i];
- else
- return false;
- }
-
- return true;
-}
-
-static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
- [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY,
- .len = NL80211_MAX_SUPP_RATES },
- [NL80211_TXRATE_HT] = { .type = NLA_BINARY,
- .len = NL80211_MAX_SUPP_HT_RATES },
- [NL80211_TXRATE_VHT] = { .len = sizeof(struct nl80211_txrate_vht)},
- [NL80211_TXRATE_GI] = { .type = NLA_U8 },
-};
-
static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
struct genl_info *info)
{
- struct nlattr *tb[NL80211_TXRATE_MAX + 1];
- struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct cfg80211_bitrate_mask mask;
- int rem, i;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
- struct nlattr *tx_rates;
- struct ieee80211_supported_band *sband;
- u16 vht_tx_mcs_map;
+ int err;
if (!rdev->ops->set_bitrate_mask)
return -EOPNOTSUPP;
- memset(&mask, 0, sizeof(mask));
- /* Default to all rates enabled */
- for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
- sband = rdev->wiphy.bands[i];
-
- if (!sband)
- continue;
-
- mask.control[i].legacy = (1 << sband->n_bitrates) - 1;
- memcpy(mask.control[i].ht_mcs,
- sband->ht_cap.mcs.rx_mask,
- sizeof(mask.control[i].ht_mcs));
-
- if (!sband->vht_cap.vht_supported)
- continue;
-
- vht_tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
- vht_build_mcs_mask(vht_tx_mcs_map, mask.control[i].vht_mcs);
- }
-
- /* if no rates are given set it back to the defaults */
- if (!info->attrs[NL80211_ATTR_TX_RATES])
- goto out;
-
- /*
- * The nested attribute uses enum nl80211_band as the index. This maps
- * directly to the enum ieee80211_band values used in cfg80211.
- */
- BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8);
- nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) {
- enum ieee80211_band band = nla_type(tx_rates);
- int err;
-
- if (band < 0 || band >= IEEE80211_NUM_BANDS)
- return -EINVAL;
- sband = rdev->wiphy.bands[band];
- if (sband == NULL)
- return -EINVAL;
- err = nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates),
- nla_len(tx_rates), nl80211_txattr_policy);
- if (err)
- return err;
- if (tb[NL80211_TXRATE_LEGACY]) {
- mask.control[band].legacy = rateset_to_mask(
- sband,
- nla_data(tb[NL80211_TXRATE_LEGACY]),
- nla_len(tb[NL80211_TXRATE_LEGACY]));
- if ((mask.control[band].legacy == 0) &&
- nla_len(tb[NL80211_TXRATE_LEGACY]))
- return -EINVAL;
- }
- if (tb[NL80211_TXRATE_HT]) {
- if (!ht_rateset_to_mask(
- sband,
- nla_data(tb[NL80211_TXRATE_HT]),
- nla_len(tb[NL80211_TXRATE_HT]),
- mask.control[band].ht_mcs))
- return -EINVAL;
- }
- if (tb[NL80211_TXRATE_VHT]) {
- if (!vht_set_mcs_mask(
- sband,
- nla_data(tb[NL80211_TXRATE_VHT]),
- mask.control[band].vht_mcs))
- return -EINVAL;
- }
- if (tb[NL80211_TXRATE_GI]) {
- mask.control[band].gi =
- nla_get_u8(tb[NL80211_TXRATE_GI]);
- if (mask.control[band].gi > NL80211_TXRATE_FORCE_LGI)
- return -EINVAL;
- }
-
- if (mask.control[band].legacy == 0) {
- /* don't allow empty legacy rates if HT or VHT
- * are not even supported.
- */
- if (!(rdev->wiphy.bands[band]->ht_cap.ht_supported ||
- rdev->wiphy.bands[band]->vht_cap.vht_supported))
- return -EINVAL;
-
- for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
- if (mask.control[band].ht_mcs[i])
- goto out;
-
- for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
- if (mask.control[band].vht_mcs[i])
- goto out;
-
- /* legacy and mcs rates may not be both empty */
- return -EINVAL;
- }
- }
+ err = nl80211_parse_tx_bitrate_mask(info, &mask);
+ if (err)
+ return err;
-out:
return rdev_set_bitrate_mask(rdev, dev, NULL, &mask);
}
diff --git a/sound/soc/codecs/wcd-dsp-mgr.c b/sound/soc/codecs/wcd-dsp-mgr.c
index d9d413f0a80a..f51301d1ab08 100644
--- a/sound/soc/codecs/wcd-dsp-mgr.c
+++ b/sound/soc/codecs/wcd-dsp-mgr.c
@@ -717,8 +717,8 @@ static void wdsp_ssr_work_fn(struct work_struct *work)
*/
WDSP_CLEAR_STATUS(wdsp, WDSP_STATUS_CODE_DLOADED);
- /* If codec went down, then all components must be re-initialized */
- if (wdsp->ssr_type == WDSP_SSR_TYPE_CDC_DOWN) {
+ /* If codec restarted, then all components must be re-initialized */
+ if (wdsp->ssr_type == WDSP_SSR_TYPE_CDC_UP) {
wdsp_deinit_components(wdsp);
WDSP_CLEAR_STATUS(wdsp, WDSP_STATUS_INITIALIZED);
}
diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c
index 3cbc1e7821cf..a1f23685beb5 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.c
+++ b/sound/soc/codecs/wcd-mbhc-v2.c
@@ -2593,6 +2593,8 @@ void wcd_mbhc_deinit(struct wcd_mbhc *mbhc)
if (mbhc->mbhc_cb && mbhc->mbhc_cb->register_notifier)
mbhc->mbhc_cb->register_notifier(mbhc, &mbhc->nblock, false);
mutex_destroy(&mbhc->codec_resource_lock);
+ mutex_destroy(&mbhc->hphl_pa_lock);
+ mutex_destroy(&mbhc->hphr_pa_lock);
}
EXPORT_SYMBOL(wcd_mbhc_deinit);
diff --git a/sound/soc/codecs/wcd934x/wcd934x-dsd.c b/sound/soc/codecs/wcd934x/wcd934x-dsd.c
index 4e3e769585e6..580591a32ba1 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-dsd.c
+++ b/sound/soc/codecs/wcd934x/wcd934x-dsd.c
@@ -619,6 +619,53 @@ static const struct snd_soc_dapm_widget tavil_dsd_widgets[] = {
};
/**
+ * tavil_dsd_post_ssr_init - DSD intialization after subsystem restart
+ *
+ * @codec: pointer to snd_soc_codec
+ *
+ * Returns 0 on success or error on failure
+ */
+int tavil_dsd_post_ssr_init(struct tavil_dsd_config *dsd_conf)
+{
+ struct snd_soc_codec *codec;
+
+ if (!dsd_conf || !dsd_conf->codec)
+ return -EINVAL;
+
+ codec = dsd_conf->codec;
+ /* Disable DSD Interrupts */
+ snd_soc_update_bits(codec, WCD934X_INTR_CODEC_MISC_MASK, 0x08, 0x08);
+
+ /* DSD registers init */
+ if (dsd_conf->version == TAVIL_VERSION_1_0) {
+ snd_soc_update_bits(codec, WCD934X_CDC_DSD0_CFG2, 0x02, 0x00);
+ snd_soc_update_bits(codec, WCD934X_CDC_DSD1_CFG2, 0x02, 0x00);
+ }
+ /* DSD0: Mute EN */
+ snd_soc_update_bits(codec, WCD934X_CDC_DSD0_CFG2, 0x04, 0x04);
+ /* DSD1: Mute EN */
+ snd_soc_update_bits(codec, WCD934X_CDC_DSD1_CFG2, 0x04, 0x04);
+ snd_soc_update_bits(codec, WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG3, 0x10,
+ 0x10);
+ snd_soc_update_bits(codec, WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG3, 0x10,
+ 0x10);
+ snd_soc_update_bits(codec, WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG0, 0x0E,
+ 0x0A);
+ snd_soc_update_bits(codec, WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG0, 0x0E,
+ 0x0A);
+ snd_soc_update_bits(codec, WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG1, 0x07,
+ 0x04);
+ snd_soc_update_bits(codec, WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG1, 0x07,
+ 0x04);
+
+ /* Enable DSD Interrupts */
+ snd_soc_update_bits(codec, WCD934X_INTR_CODEC_MISC_MASK, 0x08, 0x00);
+
+ return 0;
+}
+EXPORT_SYMBOL(tavil_dsd_post_ssr_init);
+
+/**
* tavil_dsd_init - DSD intialization
*
* @codec: pointer to snd_soc_codec
diff --git a/sound/soc/codecs/wcd934x/wcd934x-dsd.h b/sound/soc/codecs/wcd934x/wcd934x-dsd.h
index 21450c90a272..498288335b3b 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-dsd.h
+++ b/sound/soc/codecs/wcd934x/wcd934x-dsd.h
@@ -55,6 +55,7 @@ void tavil_dsd_set_interp_rate(struct tavil_dsd_config *dsd_conf, u16 rx_port,
u32 sample_rate, u8 sample_rate_val);
struct tavil_dsd_config *tavil_dsd_init(struct snd_soc_codec *codec);
void tavil_dsd_deinit(struct tavil_dsd_config *dsd_config);
+int tavil_dsd_post_ssr_init(struct tavil_dsd_config *dsd_config);
#else
int tavil_dsd_set_mixer_value(struct tavil_dsd_config *dsd_conf,
int interp_num, int sw_value)
@@ -88,5 +89,9 @@ struct tavil_dsd_config *tavil_dsd_init(struct snd_soc_codec *codec)
void tavil_dsd_deinit(struct tavil_dsd_config *dsd_config)
{ }
+int tavil_dsd_post_ssr_init(struct tavil_dsd_config *dsd_config)
+{
+ return 0;
+}
#endif
#endif
diff --git a/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c b/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c
index 8d2247176607..7e4cd6ce55a7 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c
+++ b/sound/soc/codecs/wcd934x/wcd934x-dsp-cntl.c
@@ -46,6 +46,11 @@
mutex_unlock(&lock); \
}
+enum wcd_mem_type {
+ WCD_MEM_TYPE_ALWAYS_ON,
+ WCD_MEM_TYPE_SWITCHABLE,
+};
+
struct wcd_cntl_attribute {
struct attribute attr;
ssize_t (*show)(struct wcd_dsp_cntl *cntl, char *buf);
@@ -469,7 +474,8 @@ static void wcd_cntl_cpar_ctrl(struct wcd_dsp_cntl *cntl,
snd_soc_write(codec, WCD934X_CPE_SS_CPAR_CTL, 0x00);
}
-static int wcd_cntl_enable_memory(struct wcd_dsp_cntl *cntl)
+static int wcd_cntl_enable_memory(struct wcd_dsp_cntl *cntl,
+ enum wcd_mem_type mem_type)
{
struct snd_soc_codec *codec = cntl->codec;
struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
@@ -477,77 +483,115 @@ static int wcd_cntl_enable_memory(struct wcd_dsp_cntl *cntl)
u8 status;
int ret = 0;
- snd_soc_update_bits(codec, WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL,
- 0x04, 0x00);
- snd_soc_update_bits(codec, WCD934X_TEST_DEBUG_MEM_CTRL,
- 0x80, 0x80);
- snd_soc_update_bits(codec, WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL,
- 0x01, 0x01);
- do {
- loop_cnt++;
- /* Time to enable the power domain for memory */
- usleep_range(100, 150);
- status = snd_soc_read(codec,
- WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL);
- } while ((status & 0x02) != 0x02 &&
- loop_cnt != WCD_MEM_ENABLE_MAX_RETRIES);
-
- if ((status & 0x02) != 0x02) {
- dev_err(cntl->codec->dev,
- "%s: power domain not enabled, status = 0x%02x\n",
- __func__, status);
- ret = -EIO;
- goto done;
- }
+ switch (mem_type) {
- /* 512KB of always on region */
- wcd9xxx_slim_write_repeat(wcd9xxx,
- WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_0,
- ARRAY_SIZE(mem_enable_values),
- mem_enable_values);
- wcd9xxx_slim_write_repeat(wcd9xxx,
- WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_1,
- ARRAY_SIZE(mem_enable_values),
- mem_enable_values);
-
- snd_soc_write(codec, WCD934X_CPE_SS_PWR_CPE_DRAM1_SHUTDOWN, 0x05);
-
- /* Rest of the memory */
- wcd9xxx_slim_write_repeat(wcd9xxx,
- WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_2,
- ARRAY_SIZE(mem_enable_values),
- mem_enable_values);
- wcd9xxx_slim_write_repeat(wcd9xxx,
- WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_3,
- ARRAY_SIZE(mem_enable_values),
- mem_enable_values);
+ case WCD_MEM_TYPE_ALWAYS_ON:
+ /* 512KB of always on region */
+ wcd9xxx_slim_write_repeat(wcd9xxx,
+ WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_0,
+ ARRAY_SIZE(mem_enable_values),
+ mem_enable_values);
+ wcd9xxx_slim_write_repeat(wcd9xxx,
+ WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_1,
+ ARRAY_SIZE(mem_enable_values),
+ mem_enable_values);
+ break;
+
+ case WCD_MEM_TYPE_SWITCHABLE:
+
+ snd_soc_update_bits(codec, WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL,
+ 0x04, 0x00);
+ snd_soc_update_bits(codec, WCD934X_TEST_DEBUG_MEM_CTRL,
+ 0x80, 0x80);
+ snd_soc_update_bits(codec, WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL,
+ 0x01, 0x01);
+ do {
+ loop_cnt++;
+ /* Time to enable the power domain for memory */
+ usleep_range(100, 150);
+ status = snd_soc_read(codec,
+ WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL);
+ } while ((status & 0x02) != 0x02 &&
+ loop_cnt != WCD_MEM_ENABLE_MAX_RETRIES);
+
+ if ((status & 0x02) != 0x02) {
+ dev_err(cntl->codec->dev,
+ "%s: power domain not enabled, status = 0x%02x\n",
+ __func__, status);
+ ret = -EIO;
+ goto done;
+ }
+
+ /* Rest of the memory */
+ wcd9xxx_slim_write_repeat(wcd9xxx,
+ WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_2,
+ ARRAY_SIZE(mem_enable_values),
+ mem_enable_values);
+ wcd9xxx_slim_write_repeat(wcd9xxx,
+ WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_3,
+ ARRAY_SIZE(mem_enable_values),
+ mem_enable_values);
+
+ snd_soc_write(codec, WCD934X_CPE_SS_PWR_CPE_DRAM1_SHUTDOWN,
+ 0x05);
+ break;
+
+ default:
+ dev_err(cntl->codec->dev, "%s: Invalid mem_type %d\n",
+ __func__, mem_type);
+ ret = -EINVAL;
+ break;
+ }
+done:
/* Make sure Deep sleep of memories is enabled for all banks */
snd_soc_write(codec, WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_0, 0xFF);
snd_soc_write(codec, WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_1, 0x0F);
-done:
+
return ret;
}
-static void wcd_cntl_disable_memory(struct wcd_dsp_cntl *cntl)
+static void wcd_cntl_disable_memory(struct wcd_dsp_cntl *cntl,
+ enum wcd_mem_type mem_type)
{
struct snd_soc_codec *codec = cntl->codec;
+ u8 val;
+
+ switch (mem_type) {
+ case WCD_MEM_TYPE_ALWAYS_ON:
+ snd_soc_write(codec, WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_1,
+ 0xFF);
+ snd_soc_write(codec, WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_0,
+ 0xFF);
+ break;
+ case WCD_MEM_TYPE_SWITCHABLE:
+ snd_soc_write(codec, WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_3,
+ 0xFF);
+ snd_soc_write(codec, WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_2,
+ 0xFF);
+ snd_soc_write(codec, WCD934X_CPE_SS_PWR_CPE_DRAM1_SHUTDOWN,
+ 0x07);
+
+ snd_soc_update_bits(codec, WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL,
+ 0x01, 0x00);
+ val = snd_soc_read(codec, WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL);
+ if (val & 0x02)
+ dev_err(codec->dev,
+ "%s: Disable switchable failed, val = 0x%02x",
+ __func__, val);
+
+ snd_soc_update_bits(codec, WCD934X_TEST_DEBUG_MEM_CTRL,
+ 0x80, 0x00);
+ break;
+ default:
+ dev_err(cntl->codec->dev, "%s: Invalid mem_type %d\n",
+ __func__, mem_type);
+ break;
+ }
snd_soc_write(codec, WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_0, 0xFF);
snd_soc_write(codec, WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_1, 0x0F);
- snd_soc_write(codec, WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_3, 0xFF);
- snd_soc_write(codec, WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_2, 0xFF);
- snd_soc_write(codec, WCD934X_CPE_SS_PWR_CPE_DRAM1_SHUTDOWN, 0x07);
- snd_soc_write(codec, WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_1, 0xFF);
- snd_soc_write(codec, WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_0, 0xFF);
-
- snd_soc_update_bits(codec, WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL,
- 0x01, 0x00);
- snd_soc_update_bits(codec, WCD934X_TEST_DEBUG_MEM_CTRL,
- 0x80, 0x00);
- snd_soc_update_bits(codec, WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL,
- 0x04, 0x04);
}
static void wcd_cntl_do_shutdown(struct wcd_dsp_cntl *cntl)
@@ -743,7 +787,9 @@ static int wcd_control_handler(struct device *dev, void *priv_data,
wcd_cntl_cpar_ctrl(cntl, true);
if (event == WDSP_EVENT_PRE_DLOAD_CODE)
- wcd_cntl_enable_memory(cntl);
+ wcd_cntl_enable_memory(cntl, WCD_MEM_TYPE_ALWAYS_ON);
+ else if (event == WDSP_EVENT_PRE_DLOAD_DATA)
+ wcd_cntl_enable_memory(cntl, WCD_MEM_TYPE_SWITCHABLE);
break;
case WDSP_EVENT_DO_BOOT:
@@ -758,6 +804,7 @@ static int wcd_control_handler(struct device *dev, void *priv_data,
case WDSP_EVENT_DO_SHUTDOWN:
wcd_cntl_do_shutdown(cntl);
+ wcd_cntl_disable_memory(cntl, WCD_MEM_TYPE_SWITCHABLE);
break;
default:
@@ -1188,7 +1235,8 @@ void wcd_dsp_cntl_deinit(struct wcd_dsp_cntl **cntl)
* irrespective of DSP was booted up or not.
*/
wcd_cntl_do_shutdown(control);
- wcd_cntl_disable_memory(control);
+ wcd_cntl_disable_memory(control, WCD_MEM_TYPE_SWITCHABLE);
+ wcd_cntl_disable_memory(control, WCD_MEM_TYPE_ALWAYS_ON);
component_del(codec->dev, &wcd_ctrl_component_ops);
diff --git a/sound/soc/codecs/wcd934x/wcd934x-mbhc.c b/sound/soc/codecs/wcd934x/wcd934x-mbhc.c
index b3a30eb10b92..d713edbbb355 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-mbhc.c
+++ b/sound/soc/codecs/wcd934x/wcd934x-mbhc.c
@@ -912,6 +912,37 @@ void tavil_mbhc_hs_detect_exit(struct snd_soc_codec *codec)
EXPORT_SYMBOL(tavil_mbhc_hs_detect_exit);
/*
+ * tavil_mbhc_post_ssr_init: initialize mbhc for tavil post subsystem restart
+ * @mbhc: poniter to wcd934x_mbhc structure
+ * @codec: handle to snd_soc_codec *
+ *
+ * return 0 if mbhc_init is success or error code in case of failure
+ */
+int tavil_mbhc_post_ssr_init(struct wcd934x_mbhc *mbhc,
+ struct snd_soc_codec *codec)
+{
+ int ret;
+
+ if (!mbhc || !codec)
+ return -EINVAL;
+
+ wcd_mbhc_deinit(&mbhc->wcd_mbhc);
+ ret = wcd_mbhc_init(&mbhc->wcd_mbhc, codec, &mbhc_cb, &intr_ids,
+ wcd_mbhc_registers, TAVIL_ZDET_SUPPORTED);
+ if (ret) {
+ dev_err(codec->dev, "%s: mbhc initialization failed\n",
+ __func__);
+ goto done;
+ }
+ snd_soc_update_bits(codec, WCD934X_MBHC_NEW_CTL_1, 0x04, 0x04);
+ snd_soc_update_bits(codec, WCD934X_MBHC_CTL_BCS, 0x01, 0x01);
+
+done:
+ return ret;
+}
+EXPORT_SYMBOL(tavil_mbhc_post_ssr_init);
+
+/*
* tavil_mbhc_init: initialize mbhc for tavil
* @mbhc: poniter to wcd934x_mbhc struct pointer to store the configs
* @codec: handle to snd_soc_codec *
@@ -977,7 +1008,9 @@ void tavil_mbhc_deinit(struct snd_soc_codec *codec)
{
struct wcd934x_mbhc *wcd934x_mbhc = tavil_soc_get_mbhc(codec);
- if (!wcd934x_mbhc)
+ if (wcd934x_mbhc) {
+ wcd_mbhc_deinit(&wcd934x_mbhc->wcd_mbhc);
devm_kfree(codec->dev, wcd934x_mbhc);
+ }
}
EXPORT_SYMBOL(tavil_mbhc_deinit);
diff --git a/sound/soc/codecs/wcd934x/wcd934x-mbhc.h b/sound/soc/codecs/wcd934x/wcd934x-mbhc.h
index 120a7b0f8177..3c88a12194af 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-mbhc.h
+++ b/sound/soc/codecs/wcd934x/wcd934x-mbhc.h
@@ -42,6 +42,8 @@ extern void tavil_mbhc_hs_detect_exit(struct snd_soc_codec *codec);
extern int tavil_mbhc_hs_detect(struct snd_soc_codec *codec,
struct wcd_mbhc_config *mbhc_cfg);
extern void tavil_mbhc_deinit(struct snd_soc_codec *codec);
+extern int tavil_mbhc_post_ssr_init(struct wcd934x_mbhc *mbhc,
+ struct snd_soc_codec *codec);
#endif /* __WCD934X_MBHC_H__ */
diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c
index 2f117159402e..0213d9ba4a59 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.c
+++ b/sound/soc/codecs/wcd934x/wcd934x.c
@@ -657,6 +657,8 @@ static const struct tavil_reg_mask_val tavil_spkr_mode1[] = {
{WCD934X_CDC_BOOST1_BOOST_CTL, 0x7C, 0x44},
};
+static int __tavil_enable_efuse_sensing(struct tavil_priv *tavil);
+
/*
* wcd934x_get_codec_info: Get codec specific information
*
@@ -4159,7 +4161,8 @@ int tavil_micbias_control(struct snd_soc_codec *codec,
snd_soc_update_bits(codec, micb_reg, 0xC0, 0x80);
break;
case MICB_PULLUP_DISABLE:
- tavil->pullup_ref[micb_index]--;
+ if (tavil->pullup_ref[micb_index] > 0)
+ tavil->pullup_ref[micb_index]--;
if ((tavil->pullup_ref[micb_index] == 0) &&
(tavil->micb_ref[micb_index] == 0))
snd_soc_update_bits(codec, micb_reg, 0xC0, 0x00);
@@ -4179,7 +4182,8 @@ int tavil_micbias_control(struct snd_soc_codec *codec,
post_dapm_on, &tavil->mbhc->wcd_mbhc);
break;
case MICB_DISABLE:
- tavil->micb_ref[micb_index]--;
+ if (tavil->pullup_ref[micb_index] > 0)
+ tavil->micb_ref[micb_index]--;
if ((tavil->micb_ref[micb_index] == 0) &&
(tavil->pullup_ref[micb_index] > 0))
snd_soc_update_bits(codec, micb_reg, 0xC0, 0x80);
@@ -8337,6 +8341,7 @@ static void tavil_cleanup_irqs(struct tavil_priv *tavil)
&wcd9xxx->core_res;
wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, tavil);
+ wcd9xxx_free_irq(core_res, WCD934X_IRQ_MISC, tavil);
}
/*
@@ -8588,6 +8593,131 @@ static void tavil_mclk2_reg_defaults(struct tavil_priv *tavil)
}
}
+static int tavil_device_down(struct wcd9xxx *wcd9xxx)
+{
+ struct snd_soc_codec *codec;
+ struct tavil_priv *priv;
+ int count;
+
+ codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
+ priv = snd_soc_codec_get_drvdata(codec);
+ swrm_wcd_notify(priv->swr.ctrl_data[0].swr_pdev,
+ SWR_DEVICE_DOWN, NULL);
+ tavil_dsd_reset(priv->dsd_config);
+ snd_soc_card_change_online_state(codec->component.card, 0);
+ for (count = 0; count < NUM_CODEC_DAIS; count++)
+ priv->dai[count].bus_down_in_recovery = true;
+ wcd_dsp_ssr_event(priv->wdsp_cntl, WCD_CDC_DOWN_EVENT);
+ priv->resmgr->sido_input_src = SIDO_SOURCE_INTERNAL;
+
+ return 0;
+}
+
+static int tavil_post_reset_cb(struct wcd9xxx *wcd9xxx)
+{
+ int i, ret = 0;
+ struct wcd9xxx *control;
+ struct snd_soc_codec *codec;
+ struct tavil_priv *tavil;
+ struct wcd9xxx_pdata *pdata;
+ struct wcd_mbhc *mbhc;
+
+ codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
+ tavil = snd_soc_codec_get_drvdata(codec);
+ control = dev_get_drvdata(codec->dev->parent);
+
+ wcd9xxx_set_power_state(tavil->wcd9xxx,
+ WCD_REGION_POWER_COLLAPSE_REMOVE,
+ WCD9XXX_DIG_CORE_REGION_1);
+
+ mutex_lock(&tavil->codec_mutex);
+ /*
+ * Codec hardware by default comes up in SVS mode.
+ * Initialize the svs_ref_cnt to 1 to reflect the hardware
+ * state in the driver.
+ */
+ tavil->svs_ref_cnt = 1;
+
+ tavil_slimbus_slave_port_cfg.slave_dev_intfdev_la =
+ control->slim_slave->laddr;
+ tavil_slimbus_slave_port_cfg.slave_dev_pgd_la =
+ control->slim->laddr;
+ tavil_init_slim_slave_cfg(codec);
+ snd_soc_card_change_online_state(codec->component.card, 1);
+
+ /* Class-H Init */
+ wcd_clsh_init(&tavil->clsh_d);
+ /* Default HPH Mode to Class-H LOHiFi */
+ tavil->hph_mode = CLS_H_LOHIFI;
+
+ for (i = 0; i < TAVIL_MAX_MICBIAS; i++)
+ tavil->micb_ref[i] = 0;
+
+ for (i = 0; i < COMPANDER_MAX; i++)
+ tavil->comp_enabled[i] = 0;
+
+ dev_dbg(codec->dev, "%s: MCLK Rate = %x\n",
+ __func__, control->mclk_rate);
+
+ if (control->mclk_rate == WCD934X_MCLK_CLK_12P288MHZ)
+ snd_soc_update_bits(codec, WCD934X_CODEC_RPM_CLK_MCLK_CFG,
+ 0x03, 0x00);
+ else if (control->mclk_rate == WCD934X_MCLK_CLK_9P6MHZ)
+ snd_soc_update_bits(codec, WCD934X_CODEC_RPM_CLK_MCLK_CFG,
+ 0x03, 0x01);
+ wcd_resmgr_post_ssr_v2(tavil->resmgr);
+ tavil_update_reg_defaults(tavil);
+ tavil_codec_init_reg(tavil);
+ __tavil_enable_efuse_sensing(tavil);
+ tavil_mclk2_reg_defaults(tavil);
+
+ __tavil_cdc_mclk_enable(tavil, true);
+ regcache_mark_dirty(codec->component.regmap);
+ regcache_sync(codec->component.regmap);
+ __tavil_cdc_mclk_enable(tavil, false);
+
+ pdata = dev_get_platdata(codec->dev->parent);
+ ret = tavil_handle_pdata(tavil, pdata);
+ if (IS_ERR_VALUE(ret))
+ dev_err(codec->dev, "%s: invalid pdata\n", __func__);
+
+ /* Initialize MBHC module */
+ mbhc = &tavil->mbhc->wcd_mbhc;
+ ret = tavil_mbhc_post_ssr_init(tavil->mbhc, codec);
+ if (ret) {
+ dev_err(codec->dev, "%s: mbhc initialization failed\n",
+ __func__);
+ goto done;
+ } else {
+ tavil_mbhc_hs_detect(codec, mbhc->mbhc_cfg);
+ }
+
+ /* DSD initialization */
+ ret = tavil_dsd_post_ssr_init(tavil->dsd_config);
+ if (ret)
+ dev_dbg(tavil->dev, "%s: DSD init failed\n", __func__);
+
+ tavil_cleanup_irqs(tavil);
+ ret = tavil_setup_irqs(tavil);
+ if (ret) {
+ dev_err(codec->dev, "%s: tavil irq setup failed %d\n",
+ __func__, ret);
+ goto done;
+ }
+
+ tavil_set_spkr_mode(codec, tavil->swr.spkr_mode);
+ /*
+ * Once the codec initialization is completed, the svs vote
+ * can be released allowing the codec to go to SVS2.
+ */
+ tavil_vote_svs(tavil, false);
+ wcd_dsp_ssr_event(tavil->wdsp_cntl, WCD_CDC_UP_EVENT);
+
+done:
+ mutex_unlock(&tavil->codec_mutex);
+ return ret;
+}
+
static int tavil_soc_codec_probe(struct snd_soc_codec *codec)
{
struct wcd9xxx *control;
@@ -8603,8 +8733,12 @@ static int tavil_soc_codec_probe(struct snd_soc_codec *codec)
tavil = snd_soc_codec_get_drvdata(codec);
tavil->intf_type = wcd9xxx_get_intf_type();
+ control->dev_down = tavil_device_down;
+ control->post_reset = tavil_post_reset_cb;
+ control->ssr_priv = (void *)codec;
+
/* Resource Manager post Init */
- ret = wcd_resmgr_post_init(tavil->resmgr, NULL, codec);
+ ret = wcd_resmgr_post_init(tavil->resmgr, &tavil_resmgr_cb, codec);
if (ret) {
dev_err(codec->dev, "%s: wcd resmgr post init failed\n",
__func__);
@@ -9215,6 +9349,7 @@ err_mem:
static int __tavil_enable_efuse_sensing(struct tavil_priv *tavil)
{
int val, rc;
+ struct snd_soc_codec *codec;
__tavil_cdc_mclk_enable(tavil, true);
@@ -9231,8 +9366,17 @@ static int __tavil_enable_efuse_sensing(struct tavil_priv *tavil)
rc = regmap_read(tavil->wcd9xxx->regmap,
WCD934X_CHIP_TIER_CTRL_EFUSE_STATUS, &val);
if (rc || (!(val & 0x01)))
- WARN(1, "%s: Efuse sense is not complete\n", __func__);
+ WARN(1, "%s: Efuse sense is not complete val=%x, ret=%d\n",
+ __func__, val, rc);
+ codec = tavil->codec;
+ if (!codec) {
+ pr_debug("%s: codec is not yet registered\n", __func__);
+ goto done;
+ }
+ tavil_enable_sido_buck(codec);
+
+done:
__tavil_cdc_mclk_enable(tavil, false);
return rc;
diff --git a/sound/soc/msm/msmcobalt.c b/sound/soc/msm/msmcobalt.c
index c82e0ad13db3..05a0e27cb45a 100644
--- a/sound/soc/msm/msmcobalt.c
+++ b/sound/soc/msm/msmcobalt.c
@@ -511,13 +511,20 @@ static struct wcd_mbhc_config wcd_mbhc_cfg = {
.moisture_en = true,
};
-static struct snd_soc_dapm_route wcd_audio_paths[] = {
+static struct snd_soc_dapm_route wcd_audio_paths_tasha[] = {
{"MIC BIAS1", NULL, "MCLK TX"},
{"MIC BIAS2", NULL, "MCLK TX"},
{"MIC BIAS3", NULL, "MCLK TX"},
{"MIC BIAS4", NULL, "MCLK TX"},
};
+static struct snd_soc_dapm_route wcd_audio_paths[] = {
+ {"MIC BIAS1", NULL, "MCLK"},
+ {"MIC BIAS2", NULL, "MCLK"},
+ {"MIC BIAS3", NULL, "MCLK"},
+ {"MIC BIAS4", NULL, "MCLK"},
+};
+
static struct afe_clk_set mi2s_clk[MI2S_MAX] = {
{
AFE_API_VERSION_I2S_CONFIG,
@@ -2362,6 +2369,42 @@ static const struct snd_kcontrol_new msm_snd_controls[] = {
SOC_ENUM_EXT("Display Port RX SampleRate", ext_disp_rx_sample_rate,
ext_disp_rx_sample_rate_get,
ext_disp_rx_sample_rate_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
+ tdm_rx_sample_rate_get,
+ tdm_rx_sample_rate_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_0 SampleRate", tdm_tx_sample_rate,
+ tdm_tx_sample_rate_get,
+ tdm_tx_sample_rate_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_0 Format", tdm_rx_format,
+ tdm_rx_format_get,
+ tdm_rx_format_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_0 Format", tdm_tx_format,
+ tdm_tx_format_get,
+ tdm_tx_format_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_0 Channels", tdm_rx_chs,
+ tdm_rx_ch_get,
+ tdm_rx_ch_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_0 Channels", tdm_tx_chs,
+ tdm_tx_ch_get,
+ tdm_tx_ch_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
+ tdm_rx_sample_rate_get,
+ tdm_rx_sample_rate_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_0 SampleRate", tdm_tx_sample_rate,
+ tdm_tx_sample_rate_get,
+ tdm_tx_sample_rate_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_0 Format", tdm_rx_format,
+ tdm_rx_format_get,
+ tdm_rx_format_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_0 Format", tdm_tx_format,
+ tdm_tx_format_get,
+ tdm_tx_format_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_0 Channels", tdm_rx_chs,
+ tdm_rx_ch_get,
+ tdm_rx_ch_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_0 Channels", tdm_tx_chs,
+ tdm_tx_ch_get,
+ tdm_tx_ch_put),
SOC_ENUM_EXT("TERT_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
tdm_rx_sample_rate_get,
tdm_rx_sample_rate_put),
@@ -2380,6 +2423,24 @@ static const struct snd_kcontrol_new msm_snd_controls[] = {
SOC_ENUM_EXT("TERT_TDM_TX_0 Channels", tdm_tx_chs,
tdm_tx_ch_get,
tdm_tx_ch_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
+ tdm_rx_sample_rate_get,
+ tdm_rx_sample_rate_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_0 SampleRate", tdm_tx_sample_rate,
+ tdm_tx_sample_rate_get,
+ tdm_tx_sample_rate_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_0 Format", tdm_rx_format,
+ tdm_rx_format_get,
+ tdm_rx_format_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_0 Format", tdm_tx_format,
+ tdm_tx_format_get,
+ tdm_tx_format_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_0 Channels", tdm_rx_chs,
+ tdm_rx_ch_get,
+ tdm_rx_ch_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_0 Channels", tdm_tx_chs,
+ tdm_tx_ch_get,
+ tdm_tx_ch_put),
SOC_ENUM_EXT("PRIM_AUX_PCM_RX SampleRate", prim_aux_pcm_rx_sample_rate,
aux_pcm_rx_sample_rate_get,
aux_pcm_rx_sample_rate_put),
@@ -2751,6 +2812,38 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
rate->min = rate->max = SAMPLING_RATE_48KHZ;
break;
+ case MSM_BACKEND_DAI_PRI_TDM_RX_0:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_PRI][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_PRI][TDM_0].bit_format);
+ rate->min = rate->max = tdm_rx_cfg[TDM_PRI][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_PRI_TDM_TX_0:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_PRI][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_PRI][TDM_0].bit_format);
+ rate->min = rate->max = tdm_tx_cfg[TDM_PRI][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_SEC_TDM_RX_0:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_SEC][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_SEC][TDM_0].bit_format);
+ rate->min = rate->max = tdm_rx_cfg[TDM_SEC][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_SEC_TDM_TX_0:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_SEC][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_SEC][TDM_0].bit_format);
+ rate->min = rate->max = tdm_tx_cfg[TDM_SEC][TDM_0].sample_rate;
+ break;
+
case MSM_BACKEND_DAI_TERT_TDM_RX_0:
channels->min = channels->max =
tdm_rx_cfg[TDM_TERT][TDM_0].channels;
@@ -2767,6 +2860,22 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
rate->min = rate->max = tdm_tx_cfg[TDM_TERT][TDM_0].sample_rate;
break;
+ case MSM_BACKEND_DAI_QUAT_TDM_RX_0:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_QUAT][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_QUAT][TDM_0].bit_format);
+ rate->min = rate->max = tdm_rx_cfg[TDM_QUAT][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_QUAT_TDM_TX_0:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_QUAT][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_QUAT][TDM_0].bit_format);
+ rate->min = rate->max = tdm_tx_cfg[TDM_QUAT][TDM_0].sample_rate;
+ break;
+
case MSM_BACKEND_DAI_AUXPCM_RX:
rate->min = rate->max =
aux_pcm_rx_cfg[PRIM_AUX_PCM].sample_rate;
@@ -3123,8 +3232,12 @@ static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_new_controls(dapm, msm_dapm_widgets,
ARRAY_SIZE(msm_dapm_widgets));
- snd_soc_dapm_add_routes(dapm, wcd_audio_paths,
- ARRAY_SIZE(wcd_audio_paths));
+ if (!strcmp(dev_name(codec_dai->dev), "tasha_codec"))
+ snd_soc_dapm_add_routes(dapm, wcd_audio_paths_tasha,
+ ARRAY_SIZE(wcd_audio_paths_tasha));
+ else
+ snd_soc_dapm_add_routes(dapm, wcd_audio_paths,
+ ARRAY_SIZE(wcd_audio_paths));
snd_soc_dapm_ignore_suspend(dapm, "Handset Mic");
snd_soc_dapm_ignore_suspend(dapm, "Headset Mic");
@@ -4836,6 +4949,62 @@ static struct snd_soc_dai_link msm_common_be_dai_links[] = {
.ignore_suspend = 1,
},
{
+ .name = LPASS_BE_PRI_TDM_RX_0,
+ .stream_name = "Primary TDM0 Playback",
+ .cpu_dai_name = "msm-dai-q6-tdm.36864",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_PRI_TDM_TX_0,
+ .stream_name = "Primary TDM0 Capture",
+ .cpu_dai_name = "msm-dai-q6-tdm.36865",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_TDM_RX_0,
+ .stream_name = "Secondary TDM0 Playback",
+ .cpu_dai_name = "msm-dai-q6-tdm.36880",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_TDM_TX_0,
+ .stream_name = "Secondary TDM0 Capture",
+ .cpu_dai_name = "msm-dai-q6-tdm.36881",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
.name = LPASS_BE_TERT_TDM_RX_0,
.stream_name = "Tertiary TDM0 Playback",
.cpu_dai_name = "msm-dai-q6-tdm.36896",
@@ -4863,6 +5032,34 @@ static struct snd_soc_dai_link msm_common_be_dai_links[] = {
.ops = &msm_tdm_be_ops,
.ignore_suspend = 1,
},
+ {
+ .name = LPASS_BE_QUAT_TDM_RX_0,
+ .stream_name = "Quaternary TDM0 Playback",
+ .cpu_dai_name = "msm-dai-q6-tdm.36912",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_QUAT_TDM_TX_0,
+ .stream_name = "Quaternary TDM0 Capture",
+ .cpu_dai_name = "msm-dai-q6-tdm.36913",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
};
static struct snd_soc_dai_link msm_tasha_be_dai_links[] = {
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 547af163c5c0..13d4ba27d990 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -121,14 +121,14 @@ static int msm_routing_get_bit_width(unsigned int format)
return bit_width;
}
-static bool msm_is_fractional_resample_needed(int input_sr, int output_sr)
+static bool msm_is_resample_needed(int input_sr, int output_sr)
{
bool rc = false;
- if ((input_sr % output_sr != 0) && (output_sr % input_sr != 0))
+ if (input_sr != output_sr)
rc = true;
- pr_debug("performing fractional resample (%s) for copp rate (%d)afe rate (%d)",
+ pr_debug("perform resampling (%s) for copp rate (%d)afe rate (%d)",
(rc ? "oh yes" : "not really"),
input_sr, output_sr);
@@ -901,7 +901,7 @@ int msm_pcm_routing_reg_phy_compr_stream(int fe_id, int perf_mode,
set_bit(copp_idx,
&session_copp_map[fe_id][session_type][i]);
- if (msm_is_fractional_resample_needed(
+ if (msm_is_resample_needed(
sample_rate,
msm_bedais[i].sample_rate))
adm_copp_mfc_cfg(
@@ -1057,7 +1057,7 @@ int msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode,
set_bit(copp_idx,
&session_copp_map[fedai_id][session_type][i]);
- if (msm_is_fractional_resample_needed(
+ if (msm_is_resample_needed(
sample_rate,
msm_bedais[i].sample_rate))
adm_copp_mfc_cfg(
@@ -1284,7 +1284,7 @@ static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set)
set_bit(copp_idx,
&session_copp_map[val][session_type][reg]);
- if (msm_is_fractional_resample_needed(
+ if (msm_is_resample_needed(
sample_rate,
msm_bedais[reg].sample_rate))
adm_copp_mfc_cfg(
@@ -3628,6 +3628,210 @@ static const struct snd_kcontrol_new quat_auxpcm_rx_mixer_controls[] = {
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new pri_tdm_rx_0_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new pri_tdm_tx_0_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new sec_tdm_rx_0_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new sec_tdm_tx_0_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
static const struct snd_kcontrol_new tert_tdm_rx_0_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERT_TDM_RX_0 ,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
@@ -3679,6 +3883,57 @@ static const struct snd_kcontrol_new tert_tdm_rx_0_mixer_controls[] = {
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new tert_tdm_tx_0_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
static const struct snd_kcontrol_new tert_tdm_rx_1_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERT_TDM_RX_1 ,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
@@ -3883,6 +4138,57 @@ static const struct snd_kcontrol_new quat_tdm_rx_0_mixer_controls[] = {
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new quat_tdm_tx_0_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
static const struct snd_kcontrol_new quat_tdm_rx_1_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUAT_TDM_RX_1 ,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
@@ -8141,9 +8447,24 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
SND_SOC_DAPM_MIXER("QUIN_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
quinary_mi2s_rx_mixer_controls,
ARRAY_SIZE(quinary_mi2s_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("PRI_TDM_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ pri_tdm_rx_0_mixer_controls,
+ ARRAY_SIZE(pri_tdm_rx_0_mixer_controls)),
+ SND_SOC_DAPM_MIXER("PRI_TDM_TX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ pri_tdm_tx_0_mixer_controls,
+ ARRAY_SIZE(pri_tdm_tx_0_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_TDM_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ sec_tdm_rx_0_mixer_controls,
+ ARRAY_SIZE(sec_tdm_rx_0_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_TDM_TX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ sec_tdm_tx_0_mixer_controls,
+ ARRAY_SIZE(sec_tdm_tx_0_mixer_controls)),
SND_SOC_DAPM_MIXER("TERT_TDM_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
tert_tdm_rx_0_mixer_controls,
ARRAY_SIZE(tert_tdm_rx_0_mixer_controls)),
+ SND_SOC_DAPM_MIXER("TERT_TDM_TX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ tert_tdm_tx_0_mixer_controls,
+ ARRAY_SIZE(tert_tdm_tx_0_mixer_controls)),
SND_SOC_DAPM_MIXER("TERT_TDM_RX_1 Audio Mixer", SND_SOC_NOPM, 0, 0,
tert_tdm_rx_1_mixer_controls,
ARRAY_SIZE(tert_tdm_rx_1_mixer_controls)),
@@ -8156,6 +8477,9 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
SND_SOC_DAPM_MIXER("QUAT_TDM_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
quat_tdm_rx_0_mixer_controls,
ARRAY_SIZE(quat_tdm_rx_0_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUAT_TDM_TX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quat_tdm_tx_0_mixer_controls,
+ ARRAY_SIZE(quat_tdm_tx_0_mixer_controls)),
SND_SOC_DAPM_MIXER("QUAT_TDM_RX_1 Audio Mixer", SND_SOC_NOPM, 0, 0,
quat_tdm_rx_1_mixer_controls,
ARRAY_SIZE(quat_tdm_rx_1_mixer_controls)),
@@ -8775,6 +9099,78 @@ static const struct snd_soc_dapm_route intercon[] = {
{"QUIN_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
{"QUIN_MI2S_RX", NULL, "QUIN_MI2S_RX Audio Mixer"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"PRI_TDM_RX_0", NULL, "PRI_TDM_RX_0 Audio Mixer"},
+
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"PRI_TDM_TX_0", NULL, "PRI_TDM_TX_0 Audio Mixer"},
+
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"SEC_TDM_RX_0", NULL, "SEC_TDM_RX_0 Audio Mixer"},
+
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"SEC_TDM_TX_0", NULL, "SEC_TDM_TX_0 Audio Mixer"},
+
{"TERT_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
{"TERT_TDM_RX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
{"TERT_TDM_RX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
@@ -8793,6 +9189,24 @@ static const struct snd_soc_dapm_route intercon[] = {
{"TERT_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
{"TERT_TDM_RX_0", NULL, "TERT_TDM_RX_0 Audio Mixer"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"TERT_TDM_TX_0", NULL, "TERT_TDM_TX_0 Audio Mixer"},
+
{"TERT_TDM_RX_1 Audio Mixer", "MultiMedia1", "MM_DL1"},
{"TERT_TDM_RX_1 Audio Mixer", "MultiMedia2", "MM_DL2"},
{"TERT_TDM_RX_1 Audio Mixer", "MultiMedia3", "MM_DL3"},
@@ -8865,6 +9279,24 @@ static const struct snd_soc_dapm_route intercon[] = {
{"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
{"QUAT_TDM_RX_0", NULL, "QUAT_TDM_RX_0 Audio Mixer"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"QUAT_TDM_TX_0", NULL, "QUAT_TDM_TX_0 Audio Mixer"},
+
{"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia1", "MM_DL1"},
{"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia2", "MM_DL2"},
{"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia3", "MM_DL3"},
@@ -9735,6 +10167,10 @@ static const struct snd_soc_dapm_route intercon[] = {
{"TERT_MI2S_RX", NULL, "TERT_MI2S_DL_HL"},
{"QUAT_MI2S_UL_HL", NULL, "QUAT_MI2S_TX"},
+ {"PRI_TDM_TX_0_UL_HL", NULL, "PRI_TDM_TX_0"},
+ {"PRI_TDM_RX_0", NULL, "PRI_TDM_RX_0_DL_HL"},
+ {"SEC_TDM_TX_0_UL_HL", NULL, "SEC_TDM_TX_0"},
+ {"SEC_TDM_RX_0", NULL, "SEC_TDM_RX_0_DL_HL"},
{"TERT_TDM_TX_0_UL_HL", NULL, "TERT_TDM_TX_0"},
{"TERT_TDM_TX_1_UL_HL", NULL, "TERT_TDM_TX_1"},
{"TERT_TDM_TX_2_UL_HL", NULL, "TERT_TDM_TX_2"},
@@ -10140,6 +10576,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"BE_OUT", NULL, "SLIMBUS_3_RX"},
{"BE_OUT", NULL, "VOICE_PLAYBACK_TX"},
{"BE_OUT", NULL, "VOICE2_PLAYBACK_TX"},
+ {"BE_OUT", NULL, "PRI_TDM_RX_0"},
+ {"BE_OUT", NULL, "SEC_TDM_RX_0"},
{"BE_OUT", NULL, "TERT_TDM_RX_0"},
{"BE_OUT", NULL, "TERT_TDM_RX_1"},
{"BE_OUT", NULL, "TERT_TDM_RX_2"},
@@ -10186,6 +10624,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"SLIMBUS_0_RX", NULL, "SLIM0_RX_VI_FB_LCH_MUX"},
{"SLIMBUS_0_RX", NULL, "SLIM0_RX_VI_FB_RCH_MUX"},
{"PRI_MI2S_RX", NULL, "PRI_MI2S_RX_VI_FB_MUX"},
+ {"PRI_TDM_TX_0", NULL, "BE_IN"},
+ {"SEC_TDM_TX_0", NULL, "BE_IN"},
{"TERT_TDM_TX_0", NULL, "BE_IN"},
{"TERT_TDM_TX_1", NULL, "BE_IN"},
{"TERT_TDM_TX_2", NULL, "BE_IN"},
@@ -10381,7 +10821,7 @@ static int msm_pcm_routing_prepare(struct snd_pcm_substream *substream)
set_bit(copp_idx,
&session_copp_map[i][session_type][be_id]);
- if (msm_is_fractional_resample_needed(
+ if (msm_is_resample_needed(
sample_rate,
bedai->sample_rate))
adm_copp_mfc_cfg(
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index e30a4efa6e60..564b67c9f76b 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -2508,8 +2508,6 @@ void adm_copp_mfc_cfg(int port_id, int copp_idx, int dst_sample_rate)
mfc_cfg.sampling_rate = dst_sample_rate;
mfc_cfg.bits_per_sample =
atomic_read(&this_adm.copp.bit_width[port_idx][copp_idx]);
- if (24 == mfc_cfg.bits_per_sample)
- mfc_cfg.bits_per_sample = 32;
open.dev_num_channel = mfc_cfg.num_channels =
atomic_read(&this_adm.copp.channels[port_idx][copp_idx]);
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 88c27339b299..0ea94cb52bfb 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -1221,8 +1221,9 @@ int q6asm_audio_client_buf_alloc(unsigned int dir,
struct audio_buffer *buf;
size_t len;
- if (!(ac) || ((dir != IN) && (dir != OUT))) {
- pr_err("%s: ac %pK dir %d\n", __func__, ac, dir);
+ if (!(ac) || !(bufsz) || ((dir != IN) && (dir != OUT))) {
+ pr_err("%s: ac %pK bufsz %d dir %d\n", __func__, ac, bufsz,
+ dir);
return -EINVAL;
}