diff options
178 files changed, 8067 insertions, 23758 deletions
diff --git a/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt b/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt deleted file mode 100644 index c10fd981df2b..000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt +++ /dev/null @@ -1,57 +0,0 @@ -Synaptics DSXV26 touch controller - -Please add this description here: The Synaptics Touch controller is connected to the -host processor via I2C. The controller generates interrupts when the user touches -the panel. The host controller is expected to read the touch coordinates over I2C and -pass the coordinates to the rest of the system. - -Required properties: - - - compatible : should be "synaptics,dsx-i2c". - - reg : i2c slave address of the device. - - interrupt-parent : parent of interrupt. - - synaptics,irq-gpio : irq gpio. - - synaptics,irq-flags : irq flags. - -Optional property: - - vdd_ana-supply : digital voltage power supply needed to power device. - - vcc_i2c-supply : analog voltage power supply needed to power device. - - synaptics,pwr-reg-name : power reg name of digital voltage. - - synaptics,bus-reg-name : bus reg name of analog voltage. - - synaptics,irq-on-state : status of irq gpio. - - synaptics,cap-button-codes : virtual key code mappings to be used. - - synaptics,vir-button-codes : virtual key code and the response region on panel. - - synaptics,x-flip : modify orientation of the x axis. - - synaptics,y-flip : modify orientation of the y axis. - - synaptics,reset-delay-ms : reset delay for controller (ms), default 100. - - synaptics,max-y-for-2d : maximal y value of the panel. - - clock-names : Clock names used for secure touch. They are: "iface_clk", "core_clk" - - clocks : Defined if 'clock-names' DT property is defined. These clocks - are associated with the underlying I2C bus. - -Example: - i2c@78b7000 { - status = "ok"; - synaptics@4b { - compatible = "synaptics,dsx-i2c"; - reg = <0x4b>; - interrupt-parent = <&tlmm>; - interrupts = <65 0x2008>; - vdd_ana-supply = <&pmtitanium_l17>; - vcc_i2c-supply = <&pmtitanium_l6>; - synaptics,pwr-reg-name = "vdd_ana"; - synaptics,bus-reg-name = "vcc_i2c"; - synaptics,irq-gpio = <&tlmm 65 0x2008>; - synaptics,irq-on-state = <0>; - synaptics,irq-flags = <0x2008>; /* IRQF_ONESHOT | IRQF_TRIGGER_LOW */ - synaptics,power-delay-ms = <200>; - synaptics,reset-delay-ms = <200>; - synaptics,max-y-for-2d = <1919>; /* remove if no virtual buttons */ - synaptics,cap-button-codes = <139 172 158>; - synaptics,vir-button-codes = <139 180 2000 320 160 172 540 2000 320 160 158 900 2000 320 160>; - /* Underlying clocks used by secure touch */ - clock-names = "iface_clk", "core_clk"; - clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>, - <&clock_gcc clk_gcc_blsp1_qup3_i2c_apps_clk>; - }; - }; diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt index 0b46fd3d8ebf..d00e26b4d5ed 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt @@ -75,6 +75,11 @@ Optional Properties: during clock scaling. If this property is not defined, then it falls back to the default HS bus speed mode to maintain backward compatibility. + - qcom,sdr104-wa: On Certain chipsets, SDR104 mode might be unstable causing CRC errors + on the interface. So there is a workaround implemented to skip printing + register dumps on CRC errors and also downgrade bus speed mode to + SDR50/DDR50 in case of continuous CRC errors. Set this flag to enable + this workaround. In the following, <supply> can be vdd (flash core voltage) or vdd-io (I/O voltage). - qcom,<supply>-always-on - specifies whether supply should be kept "on" always. diff --git a/Documentation/devicetree/bindings/pci/msm_pcie.txt b/Documentation/devicetree/bindings/pci/msm_pcie.txt index a50e0c2b2c35..fc019bda50a7 100644 --- a/Documentation/devicetree/bindings/pci/msm_pcie.txt +++ b/Documentation/devicetree/bindings/pci/msm_pcie.txt @@ -79,8 +79,12 @@ Optional Properties: PCIe port PHY. Should be specified in groups (offset, value, delay). - qcom,use-19p2mhz-aux-clk: The frequency of PCIe AUX clock is 19.2MHz. - - qcom,ep-wakeirq: The endpoint will issue wake signal when it is up, and the - root complex has the capability to enumerate the endpoint for this case. + - qcom,boot-option: Bits that alter PCIe bus driver boot sequence. + Below details what happens when each bit is set + BIT(0): PCIe bus driver will not start enumeration during its probe. + Clients will control when PCIe bus driver should do enumeration. + BIT(1): PCIe bus driver will not start enumeration if it receives a WAKE + interrupt. - qcom,msi-gicm-addr: MSI address for GICv2m. - qcom,msi-gicm-base: MSI IRQ base for GICv2m. - qcom,ext-ref-clk: The reference clock is external. @@ -263,7 +267,7 @@ Example: qcom,aux-clk-sync; qcom,n-fts = <0x50>; qcom,pcie-phy-ver = <1>; - qcom,ep-wakeirq; + qcom,boot-option = <0x1>; qcom,msi-gicm-addr = <0xf9040040>; qcom,msi-gicm-base = <0x160>; qcom,ext-ref-clk; diff --git a/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt index 63da8ecbfa4c..ed383ce9ea8f 100644 --- a/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt @@ -26,12 +26,10 @@ First Level Node - LCDB module Value type: <prop-encoded-array> Definition: Base address of the LCDB SPMI peripheral. -- qcom,force-module-reenable - Usage: required if using SW mode for module enable - Value type: <bool> - Definition: This enables the workaround to force enable - the vph_pwr_2p5_ok signal required for - turning on the LCDB module. +- qcom,pmic-revid + Usage: required + Value type: <phandle> + Definition: Phandle to the PMIC's revid node Touch-to-wake (TTW) properties: diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index 6f0d99d560cd..acf12239c813 100644 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -2107,7 +2107,9 @@ Required properties: "qcom,apq8096-asoc-snd-adp-agave" for adp agave codec and node is "sound-adp-agave", "qcom,apq8096-asoc-snd-adp-mmxf" for adp mmxf codec and - node is "sound-adp-mmxf". + node is "sound-adp-mmxf", + "qcom,apq8096-asoc-snd-auto-custom" for auto custom codec and + node is "sound-auto-custom". - qcom,model : The user-visible name of this sound card. - asoc-platform: This is phandle list containing the references to platform device nodes that are used as part of the sound card dai-links. diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index a2e7311705e3..74aefe4e616d 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -166,6 +166,7 @@ dtb-$(CONFIG_ARCH_SDM660) += sdm660-sim.dtb \ sdm660-pm660a-headset-jacktype-no-cdp.dtb \ sdm660-pm660a-headset-jacktype-no-rcm.dtb \ sdm660-usbc-audio-mtp.dtb \ + sdm660-usbc-audio-rcm.dtb \ sdm658-mtp.dtb \ sdm658-cdp.dtb \ sdm658-rcm.dtb \ @@ -191,6 +192,7 @@ dtb-$(CONFIG_ARCH_SDM630) += sdm630-rumi.dtb \ sdm630-pm660a-rumi.dtb \ sdm630-mtp.dtb \ sdm630-usbc-audio-mtp.dtb \ + sdm630-usbc-audio-rcm.dtb \ sdm630-cdp.dtb \ sdm630-rcm.dtb \ sdm630-internal-codec-mtp.dtb \ diff --git a/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi b/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi index b7a3d3f5cba5..e74aded8c9e3 100644 --- a/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi +++ b/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -624,11 +624,13 @@ "msm-pcm-routing", "msm-compr-dsp", "msm-pcm-loopback.1"; asoc-cpu = <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, <&dai_hdmi>, - <&dai_mi2s>, <&dai_mi2s_quat>, + <&dai_mi2s_sec>, <&dai_mi2s>, <&dai_mi2s_quat>, <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, <&afe_proxy_tx>, <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, <&incall_music2_rx>, + <&dai_sec_tdm_tx_0>, <&dai_sec_tdm_tx_1>, + <&dai_sec_tdm_tx_2>, <&dai_sec_tdm_tx_3>, <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>, <&dai_tert_tdm_rx_2>, <&dai_tert_tdm_rx_3>, <&dai_tert_tdm_tx_0>, <&dai_tert_tdm_tx_1>, @@ -638,12 +640,14 @@ <&dai_quat_tdm_tx_0>, <&dai_quat_tdm_tx_1>, <&dai_quat_tdm_tx_2>, <&dai_quat_tdm_tx_3>; asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2", - "msm-dai-q6-hdmi.8", + "msm-dai-q6-hdmi.8", "msm-dai-q6-mi2s.1", "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", "msm-dai-q6-dev.224", "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", + "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36883", + "msm-dai-q6-tdm.36885", "msm-dai-q6-tdm.36887", "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898", "msm-dai-q6-tdm.36900", "msm-dai-q6-tdm.36902", "msm-dai-q6-tdm.36897", "msm-dai-q6-tdm.36899", @@ -668,6 +672,16 @@ }; qcom,msm-dai-mi2s { + dai_mi2s_sec: qcom,msm-dai-q6-mi2s-sec { + qcom,msm-mi2s-rx-lines = <2>; + qcom,msm-mi2s-tx-lines = <1>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&sec_mi2s_active &sec_mi2s_sd0_active + &sec_mi2s_sd1_active>; + pinctrl-1 = <&sec_mi2s_sleep &sec_mi2s_sd0_sleep + &sec_mi2s_sd1_sleep>; + }; + dai_mi2s_quat: qcom,msm-dai-q6-mi2s-quat { pinctrl-names = "default", "sleep"; pinctrl-0 = <&quat_mi2s_active &quat_mi2s_sd0_active>; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-sharp-split-link-wuxga-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-sharp-split-link-wuxga-video.dtsi new file mode 100644 index 000000000000..143b0152dcf4 --- /dev/null +++ b/arch/arm/boot/dts/qcom/dsi-panel-sharp-split-link-wuxga-video.dtsi @@ -0,0 +1,68 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&mdss_mdp { + dsi_sharp_split_link_wuxga_video: + qcom,mdss_dsi_sharp_split_link_wuxga_video { + qcom,mdss-dsi-panel-name = + "SHARP split DSI video mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <600>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <54>; + qcom,mdss-dsi-h-back-porch = <4>; + qcom,mdss-dsi-h-pulse-width = <6>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <6>; + qcom,mdss-dsi-v-front-porch = <12>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0x654321>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-on-command = [05 01 00 00 a0 00 02 11 00]; + qcom,mdss-dsi-pre-off-command = [05 01 00 00 02 00 02 28 00 + 05 01 00 00 a0 00 02 10 00]; + qcom,mdss-dsi-post-panel-on-command = + [05 01 00 00 a0 00 02 29 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-panel-timings = + [00 24 07 08 0e 14 07 09 07 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x0e>; + qcom,mdss-dsi-t-clk-pre = <0x35>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <50>; + qcom,mdss-dsi-bl-pmic-bank-select = <2>; + qcom,mdss-dsi-reset-sequence = <1 2>, <0 5>, <1 120>; + qcom,mdss-pan-physical-width-dimension = <83>; + qcom,mdss-pan-physical-height-dimension = <133>; + qcom,mdss-dsi-tx-eot-append; + qcom,split-link-enabled = <1>; + qcom,sublinks-count = <2>; + qcom,lanes-per-sublink = <2>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.dtsi b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.dtsi index 03801ee90589..3888047b9f8c 100644 --- a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.dtsi +++ b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.dtsi @@ -14,7 +14,7 @@ qcom,itech_3000mah { /* #Itech_B00826LF_3000mAh_ver1660_averaged_MasterSlave_Jan10th2017*/ qcom,max-voltage-uv = <4350000>; qcom,fg-cc-cv-threshold-mv = <4340>; - qcom,fastchg-current-ma = <3000>; + qcom,fastchg-current-ma = <2000>; qcom,batt-id-kohm = <100>; qcom,battery-beta = <3435>; qcom,battery-type = "itech_b00826lf_3000mah_ver1660_jan10th2017"; diff --git a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-qrd-skuk-4v4-3000mah.dtsi b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-qrd-skuk-4v4-3000mah.dtsi index 8cbb29aac927..11600ef2bfd3 100644 --- a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-qrd-skuk-4v4-3000mah.dtsi +++ b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-qrd-skuk-4v4-3000mah.dtsi @@ -13,6 +13,7 @@ qcom,qrd_msm8998_skuk_3000mah { /* QRD8997_ST1031GA_3000mAh_averaged_MasterSlave_Jan10th2017 */ qcom,max-voltage-uv = <4400000>; + qcom,fg-cc-cv-threshold-mv = <4390>; qcom,fastchg-current-ma = <3000>; qcom,batt-id-kohm = <68>; qcom,battery-beta = <3380>; diff --git a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi index bcdbc4ed7c55..fdc04b9726b4 100644 --- a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi @@ -330,9 +330,6 @@ qcom,ires-ua = <12500>; qcom,hdrm-voltage-mv = <325>; qcom,hdrm-vol-hi-lo-win-mv = <100>; - pinctrl-names = "led_enable","led_disable"; - pinctrl-0 = <&led_enable>; - pinctrl-1 = <&led_disable>; }; pm660l_torch0: qcom,torch_0 { @@ -369,9 +366,6 @@ qcom,ires-ua = <12500>; qcom,hdrm-voltage-mv = <325>; qcom,hdrm-vol-hi-lo-win-mv = <100>; - pinctrl-names = "led_enable","led_disable"; - pinctrl-0 = <&led_enable>; - pinctrl-1 = <&led_disable>; }; pm660l_switch0: qcom,led_switch_0 { @@ -386,6 +380,9 @@ qcom,led-name = "led:switch_1"; qcom,led-mask = <4>; qcom,default-led-trigger = "switch1_trigger"; + pinctrl-names = "led_enable","led_disable"; + pinctrl-0 = <&led_enable>; + pinctrl-1 = <&led_disable>; }; }; @@ -397,7 +394,7 @@ interrupts = <0x3 0xec 0x1 IRQ_TYPE_EDGE_RISING>; interrupt-names = "sc-irq"; - qcom,force-module-reenable; + qcom,pmic-revid = <&pm660l_revid>; lcdb_ldo_vreg: ldo { label = "ldo"; diff --git a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi index 0cf67dd938e6..2d2b628ca815 100644 --- a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi @@ -712,9 +712,6 @@ qcom,ires-ua = <12500>; qcom,hdrm-voltage-mv = <325>; qcom,hdrm-vol-hi-lo-win-mv = <100>; - pinctrl-names = "led_enable","led_disable"; - pinctrl-0 = <&led_enable>; - pinctrl-1 = <&led_disable>; }; pmi8998_torch0: qcom,torch_0 { @@ -751,9 +748,6 @@ qcom,ires-ua = <12500>; qcom,hdrm-voltage-mv = <325>; qcom,hdrm-vol-hi-lo-win-mv = <100>; - pinctrl-names = "led_enable","led_disable"; - pinctrl-0 = <&led_enable>; - pinctrl-1 = <&led_disable>; }; pmi8998_switch0: qcom,led_switch_0 { @@ -768,6 +762,9 @@ qcom,led-name = "led:switch_1"; qcom,led-mask = <4>; qcom,default-led-trigger = "switch1_trigger"; + pinctrl-names = "led_enable","led_disable"; + pinctrl-0 = <&led_enable>; + pinctrl-1 = <&led_disable>; }; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi index 8d7309e96c0f..d007e8bcfc33 100644 --- a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -607,11 +607,13 @@ "msm-pcm-routing", "msm-compr-dsp", "msm-pcm-loopback.1"; asoc-cpu = <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, <&dai_hdmi>, - <&dai_mi2s>, <&dai_mi2s_quat>, + <&dai_mi2s_sec>, <&dai_mi2s>, <&dai_mi2s_quat>, <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, <&afe_proxy_tx>, <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, <&incall_music2_rx>, + <&dai_sec_tdm_tx_0>, <&dai_sec_tdm_tx_1>, + <&dai_sec_tdm_tx_2>, <&dai_sec_tdm_tx_3>, <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>, <&dai_tert_tdm_rx_2>, <&dai_tert_tdm_rx_3>, <&dai_tert_tdm_tx_0>, <&dai_tert_tdm_tx_1>, @@ -621,12 +623,14 @@ <&dai_quat_tdm_tx_0>, <&dai_quat_tdm_tx_1>, <&dai_quat_tdm_tx_2>, <&dai_quat_tdm_tx_3>; asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2", - "msm-dai-q6-hdmi.8", + "msm-dai-q6-hdmi.8", "msm-dai-q6-mi2s.1", "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", "msm-dai-q6-dev.224", "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", + "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36883", + "msm-dai-q6-tdm.36885", "msm-dai-q6-tdm.36887", "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898", "msm-dai-q6-tdm.36900", "msm-dai-q6-tdm.36902", "msm-dai-q6-tdm.36897", "msm-dai-q6-tdm.36899", @@ -651,6 +655,8 @@ qcom,msm-dai-mi2s { dai_mi2s_sec: qcom,msm-dai-q6-mi2s-sec { + qcom,msm-mi2s-rx-lines = <2>; + qcom,msm-mi2s-tx-lines = <1>; pinctrl-names = "default", "sleep"; pinctrl-0 = <&sec_mi2s_active &sec_mi2s_sd0_active &sec_mi2s_sd1_active>; diff --git a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi index 84b4efd71253..7fffe81c7614 100644 --- a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -628,11 +628,13 @@ "msm-pcm-routing", "msm-compr-dsp", "msm-pcm-loopback.1"; asoc-cpu = <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, <&dai_hdmi>, - <&dai_mi2s>, <&dai_mi2s_quat>, + <&dai_mi2s_sec>, <&dai_mi2s>, <&dai_mi2s_quat>, <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, <&afe_proxy_tx>, <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, <&incall_music2_rx>, + <&dai_sec_tdm_tx_0>, <&dai_sec_tdm_tx_1>, + <&dai_sec_tdm_tx_2>, <&dai_sec_tdm_tx_3>, <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>, <&dai_tert_tdm_rx_2>, <&dai_tert_tdm_rx_3>, <&dai_tert_tdm_tx_0>, <&dai_tert_tdm_tx_1>, @@ -642,12 +644,14 @@ <&dai_quat_tdm_tx_0>, <&dai_quat_tdm_tx_1>, <&dai_quat_tdm_tx_2>, <&dai_quat_tdm_tx_3>; asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2", - "msm-dai-q6-hdmi.8", + "msm-dai-q6-hdmi.8", "msm-dai-q6-mi2s.1", "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", "msm-dai-q6-dev.224", "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", + "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36883", + "msm-dai-q6-tdm.36885", "msm-dai-q6-tdm.36887", "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898", "msm-dai-q6-tdm.36900", "msm-dai-q6-tdm.36902", "msm-dai-q6-tdm.36897", "msm-dai-q6-tdm.36899", @@ -688,6 +692,16 @@ }; qcom,msm-dai-mi2s { + dai_mi2s_sec: qcom,msm-dai-q6-mi2s-sec { + qcom,msm-mi2s-rx-lines = <2>; + qcom,msm-mi2s-tx-lines = <1>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&sec_mi2s_active &sec_mi2s_sd0_active + &sec_mi2s_sd1_active>; + pinctrl-1 = <&sec_mi2s_sleep &sec_mi2s_sd0_sleep + &sec_mi2s_sd1_sleep>; + }; + dai_mi2s_quat: qcom,msm-dai-q6-mi2s-quat { pinctrl-names = "default", "sleep"; pinctrl-0 = <&quat_mi2s_active &quat_mi2s_sd0_active>; @@ -960,14 +974,14 @@ }; &pcie1 { - /delete-property/ qcom,ep-wakeirq; + /delete-property/ qcom,boot-option; }; &pcie2 { perst-gpio = <&tlmm 90 0>; wake-gpio = <&tlmm 54 0>; - /delete-property/ qcom,ep-wakeirq; + /delete-property/ qcom,boot-option; }; &wsa881x_211 { diff --git a/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi b/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi index 7370422d737e..b6e6fb4193b4 100644 --- a/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -533,11 +533,13 @@ "msm-pcm-routing", "msm-compr-dsp", "msm-pcm-loopback.1"; asoc-cpu = <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, <&dai_hdmi>, - <&dai_mi2s>, <&dai_mi2s_quat>, + <&dai_mi2s_sec>, <&dai_mi2s>, <&dai_mi2s_quat>, <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, <&afe_proxy_tx>, <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, <&incall_music2_rx>, + <&dai_sec_tdm_tx_0>, <&dai_sec_tdm_tx_1>, + <&dai_sec_tdm_tx_2>, <&dai_sec_tdm_tx_3>, <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>, <&dai_tert_tdm_rx_2>, <&dai_tert_tdm_rx_3>, <&dai_tert_tdm_tx_0>, <&dai_tert_tdm_tx_1>, @@ -547,12 +549,14 @@ <&dai_quat_tdm_tx_0>, <&dai_quat_tdm_tx_1>, <&dai_quat_tdm_tx_2>, <&dai_quat_tdm_tx_3>; asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2", - "msm-dai-q6-hdmi.8", + "msm-dai-q6-hdmi.8", "msm-dai-q6-mi2s.1", "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", "msm-dai-q6-dev.224", "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", + "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36883", + "msm-dai-q6-tdm.36885", "msm-dai-q6-tdm.36887", "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898", "msm-dai-q6-tdm.36900", "msm-dai-q6-tdm.36902", "msm-dai-q6-tdm.36897", "msm-dai-q6-tdm.36899", @@ -571,6 +575,16 @@ }; qcom,msm-dai-mi2s { + dai_mi2s_sec: qcom,msm-dai-q6-mi2s-sec { + qcom,msm-mi2s-rx-lines = <2>; + qcom,msm-mi2s-tx-lines = <1>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&sec_mi2s_active &sec_mi2s_sd0_active + &sec_mi2s_sd1_active>; + pinctrl-1 = <&sec_mi2s_sleep &sec_mi2s_sd0_sleep + &sec_mi2s_sd1_sleep>; + }; + dai_mi2s_quat: qcom,msm-dai-q6-mi2s-quat { pinctrl-names = "default", "sleep"; pinctrl-0 = <&quat_mi2s_active &quat_mi2s_sd0_active>; diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi index 49eafeaa5d70..c73a2ff23369 100644 --- a/arch/arm/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1371,7 +1371,7 @@ iommus = <&anoc0_smmu>; - qcom,ep-wakeirq; + qcom,boot-option = <0x1>; linux,pci-domain = <0>; @@ -1524,7 +1524,7 @@ iommus = <&anoc0_smmu>; - qcom,ep-wakeirq; + qcom,boot-option = <0x1>; qcom,ep-latency = <10>; @@ -1677,7 +1677,7 @@ iommus = <&anoc0_smmu>; - qcom,ep-wakeirq; + qcom,boot-option = <0x1>; qcom,ep-latency = <10>; @@ -3337,6 +3337,57 @@ }; }; + 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 = <4>; + qcom,msm-cpudai-tdm-group-port-id = <36881 36883 36885 36887>; + qcom,msm-cpudai-tdm-clk-rate = <0>; + 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 = <0>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_sec_tdm_tx_1: qcom,msm-dai-q6-tdm-sec-tx-1 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36883>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <0>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_sec_tdm_tx_2: qcom,msm-dai-q6-tdm-sec-tx-2 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36885>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <0>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_sec_tdm_tx_3: qcom,msm-dai-q6-tdm-sec-tx-3 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36887>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <0>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; + 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>; diff --git a/arch/arm/boot/dts/qcom/msm8996pro.dtsi b/arch/arm/boot/dts/qcom/msm8996pro.dtsi index abff47ff8d58..28577dc6d72f 100644 --- a/arch/arm/boot/dts/qcom/msm8996pro.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996pro.dtsi @@ -1245,6 +1245,9 @@ &soc { qcom,msm-thermal { + qcom,poll-ms = <50>; + qcom,limit-temp = <80>; + qcom,core-limit-temp = <90>; qcom,vdd-gfx-rstr{ qcom,levels = <6 8 9>; /* Nominal, Turbo, Turbo_L1 */ }; diff --git a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi index 2ed0f2250de5..d7372f2bb2e4 100644 --- a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi @@ -99,7 +99,6 @@ pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_actuator_vaf_active>; pinctrl-1 = <&cam_actuator_vaf_suspend>; - status = "disabled"; }; eeprom0: qcom,eeprom@0 { @@ -278,6 +277,7 @@ qcom,csid-sd-index = <1>; qcom,mount-angle = <90>; qcom,eeprom-src = <&eeprom1>; + qcom,led-flash-src = <&led_flash0>; qcom,actuator-src = <&actuator1>; cam_vdig-supply = <&pm8998_lvs1>; cam_vio-supply = <&pm8998_lvs1>; diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-sdm660.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-sdm660.dtsi index cfb71e3b1cb3..4a47942ce5dd 100644 --- a/arch/arm/boot/dts/qcom/msm8998-interposer-sdm660.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-interposer-sdm660.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1590,7 +1590,7 @@ qcom,ep-latency = <10>; - qcom,ep-wakeirq; + qcom,boot-option = <0x1>; linux,pci-domain = <0>; diff --git a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi index d2e18db982ef..220bad31d7f8 100644 --- a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi @@ -1960,16 +1960,28 @@ led_enable: led_enable { mux { pins = "gpio21"; - drive_strength = <16>; + function = "gpio"; + }; + + config { + pins = "gpio21"; + drive_strength = <2>; output-high; + bias-disable; }; }; led_disable: led_disable { mux { pins = "gpio21"; + function = "gpio"; + }; + + config { + pins = "gpio21"; drive_strength = <2>; output-low; + bias-disable; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi index 02b7a44ee0d2..7a0ed2497a7e 100644 --- a/arch/arm/boot/dts/qcom/msm8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998.dtsi @@ -1575,6 +1575,8 @@ qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 100000000 200000000 4294967295>; + qcom,sdr104-wa; + status = "disabled"; }; @@ -2676,7 +2678,7 @@ qcom,ep-latency = <10>; - qcom,ep-wakeirq; + qcom,boot-option = <0x1>; linux,pci-domain = <0>; diff --git a/arch/arm/boot/dts/qcom/sdm630-camera.dtsi b/arch/arm/boot/dts/qcom/sdm630-camera.dtsi index 8b226586ca7b..75b30791ffdc 100644 --- a/arch/arm/boot/dts/qcom/sdm630-camera.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-camera.dtsi @@ -54,8 +54,8 @@ "csiphy_timer_src_clk", "csiphy_timer_clk", "camss_ispif_ahb_clk", "csiphy_clk_src", "csiphy_clk", "csiphy_ahb2crif"; - qcom,clock-rates = <0 0 0 0 0 0 384000000 0 0 269333333 0 - 0 384000000 0 0>; + qcom,clock-rates = <0 0 0 0 0 0 310000000 0 0 269333333 0 + 0 200000000 0 0>; status = "ok"; }; @@ -92,8 +92,8 @@ "csiphy_timer_src_clk", "csiphy_timer_clk", "camss_ispif_ahb_clk", "csiphy_clk_src", "csiphy_clk", "csiphy_ahb2crif"; - qcom,clock-rates = <0 0 0 0 0 0 384000000 0 0 269333333 0 - 0 384000000 0 0>; + qcom,clock-rates = <0 0 0 0 0 0 310000000 0 0 269333333 0 + 0 200000000 0 0>; status = "ok"; }; @@ -130,8 +130,8 @@ "csiphy_timer_src_clk", "csiphy_timer_clk", "camss_ispif_ahb_clk", "csiphy_clk_src", "csiphy_clk", "csiphy_ahb2crif"; - qcom,clock-rates = <0 0 0 0 0 0 384000000 0 0 269333333 0 - 0 384000000 0 0>; + qcom,clock-rates = <0 0 0 0 0 0 310000000 0 0 269333333 0 + 0 200000000 0 0>; status = "ok"; }; @@ -171,7 +171,7 @@ "ispif_ahb_clk", "csi_src_clk", "csiphy_clk_src", "csi_clk", "csi_ahb_clk", "csi_rdi_clk", "csi_pix_clk", "cphy_csid_clk"; - qcom,clock-rates = <0 0 0 0 0 0 0 384000000 384000000 + qcom,clock-rates = <0 0 0 0 0 0 0 310000000 200000000 0 0 0 0 0>; status = "ok"; }; @@ -212,7 +212,7 @@ "ispif_ahb_clk", "csi_src_clk", "csiphy_clk_src", "csi_clk", "csi_ahb_clk", "csi_rdi_clk", "csi_pix_clk", "cphy_csid_clk"; - qcom,clock-rates = <0 0 0 0 0 0 0 256000000 256000000 + qcom,clock-rates = <0 0 0 0 0 0 0 310000000 200000000 0 0 0 0 0>; status = "ok"; }; @@ -253,7 +253,7 @@ "ispif_ahb_clk", "csi_src_clk", "csiphy_clk_src", "csi_clk", "csi_ahb_clk", "csi_rdi_clk", "csi_pix_clk", "cphy_csid_clk"; - qcom,clock-rates = <0 0 0 0 0 0 0 256000000 256000000 + qcom,clock-rates = <0 0 0 0 0 0 0 310000000 200000000 0 0 0 0 0>; status = "ok"; }; @@ -294,7 +294,7 @@ "ispif_ahb_clk", "csi_src_clk", "csiphy_clk_src", "csi_clk", "csi_ahb_clk", "csi_rdi_clk", "csi_pix_clk", "cphy_csid_clk"; - qcom,clock-rates = <0 0 0 0 0 0 0 256000000 256000000 + qcom,clock-rates = <0 0 0 0 0 0 0 310000000 200000000 0 0 0 0 0>; status = "ok"; }; diff --git a/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi b/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi index 9ac76f7e2f6e..d35704224f45 100644 --- a/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi @@ -38,8 +38,8 @@ qcom,mdss-ib-factor = <1 1>; /* 1 time */ qcom,mdss-clk-factor = <105 100>; /* 1.05 times */ - qcom,max-mixer-width = <2560>; - qcom,max-pipe-width = <2560>; + qcom,max-mixer-width = <2048>; + qcom,max-pipe-width = <2048>; qcom,max-dest-scaler-input-width = <2048>; qcom,max-dest-scaler-output-width = <2560>; diff --git a/arch/arm/boot/dts/qcom/sdm630-usbc-audio-rcm.dts b/arch/arm/boot/dts/qcom/sdm630-usbc-audio-rcm.dts new file mode 100644 index 000000000000..6c944305acff --- /dev/null +++ b/arch/arm/boot/dts/qcom/sdm630-usbc-audio-rcm.dts @@ -0,0 +1,30 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include "sdm630.dtsi" +#include "sdm630-cdp.dtsi" +#include "sdm660-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 630 PM660 + PM660L, USBC Audio, RCM"; + compatible = "qcom,sdm630-cdp", "qcom,sdm630", "qcom,cdp"; + qcom,board-id = <21 3>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; + +&tavil_snd { + qcom,msm-mbhc-usbc-audio-supported = <1>; +}; diff --git a/arch/arm/boot/dts/qcom/sdm630.dtsi b/arch/arm/boot/dts/qcom/sdm630.dtsi index 9626e0548789..67e899d8ba5e 100644 --- a/arch/arm/boot/dts/qcom/sdm630.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630.dtsi @@ -1628,6 +1628,8 @@ reg-names = "membase", "smmu_iova_base", "smmu_iova_ipa"; iommus = <&anoc2_smmu 0x1a00>, <&anoc2_smmu 0x1a01>; + clocks = <&clock_rpmcc RPM_RF_CLK1_PIN>; + clock-names = "cxo_ref_clk_pin"; interrupts = <0 413 0>, /* CE0 */ <0 414 0>, /* CE1 */ <0 415 0>, /* CE2 */ @@ -1640,6 +1642,14 @@ <0 423 0>, /* CE9 */ <0 424 0>, /* CE10 */ <0 425 0>; /* CE11 */ + vdd-0.8-cx-mx-supply = <&pm660_l5>; + vdd-1.8-xo-supply = <&pm660_l9_pin_ctrl>; + vdd-1.3-rfa-supply = <&pm660_l6_pin_ctrl>; + vdd-3.3-ch0-supply = <&pm660_l19_pin_ctrl>; + qcom,vdd-0.8-cx-mx-config = <525000 950000>; + qcom,vdd-1.8-xo-config = <1750000 1900000>; + qcom,vdd-1.3-rfa-config = <1200000 1370000>; + qcom,vdd-3.3-ch0-config = <3200000 3400000>; qcom,wlan-msa-memory = <0x100000>; qcom,smmu-s1-bypass; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi b/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi index 37a88ea0dcec..efe58563a1f3 100644 --- a/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi @@ -36,16 +36,28 @@ led_enable: led_enable { mux { pins = "gpio40"; - drive_strength = <16>; + function = "gpio"; + }; + + config { + pins = "gpio40"; + drive_strength = <2>; output-high; + bias-disable; }; }; led_disable: led_disable { mux { pins = "gpio40"; + function = "gpio"; + }; + + config { + pins = "gpio40"; drive_strength = <2>; output-low; + bias-disable; }; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-usbc-audio-rcm.dts b/arch/arm/boot/dts/qcom/sdm660-usbc-audio-rcm.dts new file mode 100644 index 000000000000..6528558e92ec --- /dev/null +++ b/arch/arm/boot/dts/qcom/sdm660-usbc-audio-rcm.dts @@ -0,0 +1,30 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include "sdm660.dtsi" +#include "sdm660-cdp.dtsi" +#include "sdm660-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660L, USBC Audio, RCM"; + compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp"; + qcom,board-id = <21 3>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; + +&tavil_snd { + qcom,msm-mbhc-usbc-audio-supported = <1>; +}; diff --git a/arch/arm/boot/dts/qcom/sdm660.dtsi b/arch/arm/boot/dts/qcom/sdm660.dtsi index 1e0b6136e1b4..be200f8dd531 100644 --- a/arch/arm/boot/dts/qcom/sdm660.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660.dtsi @@ -1879,6 +1879,8 @@ reg-names = "membase", "smmu_iova_base", "smmu_iova_ipa"; iommus = <&anoc2_smmu 0x1a00>, <&anoc2_smmu 0x1a01>; + clocks = <&clock_rpmcc RPM_RF_CLK1_PIN>; + clock-names = "cxo_ref_clk_pin"; interrupts = <0 413 0>, /* CE0 */ <0 414 0>, /* CE1 */ <0 415 0>, /* CE2 */ @@ -1891,6 +1893,14 @@ <0 423 0>, /* CE9 */ <0 424 0>, /* CE10 */ <0 425 0>; /* CE11 */ + vdd-0.8-cx-mx-supply = <&pm660_l5>; + vdd-1.8-xo-supply = <&pm660_l9_pin_ctrl>; + vdd-1.3-rfa-supply = <&pm660_l6_pin_ctrl>; + vdd-3.3-ch0-supply = <&pm660_l19_pin_ctrl>; + qcom,vdd-0.8-cx-mx-config = <525000 950000>; + qcom,vdd-1.8-xo-config = <1750000 1900000>; + qcom,vdd-1.3-rfa-config = <1200000 1370000>; + qcom,vdd-3.3-ch0-config = <3200000 3400000>; qcom,wlan-msa-memory = <0x100000>; qcom,smmu-s1-bypass; }; diff --git a/arch/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig index 0f51c3b3e7d6..4f55414454fc 100644 --- a/arch/arm64/configs/msmcortex-perf_defconfig +++ b/arch/arm64/configs/msmcortex-perf_defconfig @@ -240,6 +240,7 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_QSEECOM=y CONFIG_HDCP_QSEECOM=y +CONFIG_UID_CPUTIME=y CONFIG_QPNP_MISC=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y @@ -272,9 +273,15 @@ CONFIG_SMSC911X=y CONFIG_PPP=y CONFIG_PPP_BSDCOMP=y CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y CONFIG_USB_USBNET=y CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_ATH_CARDS=y diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig index 43ca4093117e..dc50257f5b7a 100644 --- a/arch/arm64/configs/msmcortex_defconfig +++ b/arch/arm64/configs/msmcortex_defconfig @@ -273,9 +273,15 @@ CONFIG_RNDIS_IPA=y CONFIG_PPP=y CONFIG_PPP_BSDCOMP=y CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y CONFIG_USB_USBNET=y CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_ATH_CARDS=y @@ -659,7 +665,6 @@ CONFIG_DEBUG_SPINLOCK=y CONFIG_DEBUG_MUTEXES=y CONFIG_DEBUG_ATOMIC_SLEEP=y CONFIG_DEBUG_LIST=y -CONFIG_RCU_STALL_WATCHDOG_BITE=y CONFIG_FAULT_INJECTION=y CONFIG_FAIL_PAGE_ALLOC=y CONFIG_UFS_FAULT_INJECTION=y diff --git a/block/blk-core.c b/block/blk-core.c index 4162327d8804..500447be3db4 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -609,8 +609,6 @@ void blk_cleanup_queue(struct request_queue *q) q->queue_lock = &q->__queue_lock; spin_unlock_irq(lock); - bdi_unregister(&q->backing_dev_info); - /* @q is and will stay empty, shutdown and put */ blk_put_queue(q); } diff --git a/block/genhd.c b/block/genhd.c index fad9db981675..7f1e8f81ceb4 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -656,7 +656,16 @@ void del_gendisk(struct gendisk *disk) disk->flags &= ~GENHD_FL_UP; sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi"); - blk_unregister_queue(disk); + if (disk->queue) { + /* + * Unregister bdi before releasing device numbers (as they can + * get reused and we'd get clashes in sysfs). + */ + bdi_unregister(&disk->queue->backing_dev_info); + blk_unregister_queue(disk); + } else { + WARN_ON(1); + } blk_unregister_region(disk_devt(disk), disk->minors); part_stat_set_all(&disk->part0, 0); diff --git a/drivers/android/binder.c b/drivers/android/binder.c index d0334e50f2f9..37b9eecf5c71 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -3440,7 +3440,7 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) const char *failure_string; struct binder_buffer *buffer; - if (proc->tsk != current) + if (proc->tsk != current->group_leader) return -EINVAL; if ((vma->vm_end - vma->vm_start) > SZ_4M) @@ -3546,8 +3546,8 @@ static int binder_open(struct inode *nodp, struct file *filp) proc = kzalloc(sizeof(*proc), GFP_KERNEL); if (proc == NULL) return -ENOMEM; - get_task_struct(current); - proc->tsk = current; + get_task_struct(current->group_leader); + proc->tsk = current->group_leader; INIT_LIST_HEAD(&proc->todo); init_waitqueue_head(&proc->wait); proc->default_priority = task_nice(current); diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 8882f0bc94a5..51a08995442d 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -393,6 +393,7 @@ static struct cpu_attr cpu_attrs[] = { _CPU_ATTR(online, &cpu_online_mask), _CPU_ATTR(possible, &cpu_possible_mask), _CPU_ATTR(present, &cpu_present_mask), + _CPU_ATTR(core_ctl_isolated, &cpu_isolated_mask), }; /* @@ -627,6 +628,7 @@ static struct attribute *cpu_root_attrs[] = { &cpu_attrs[0].attr.attr, &cpu_attrs[1].attr.attr, &cpu_attrs[2].attr.attr, + &cpu_attrs[3].attr.attr, &dev_attr_kernel_max.attr, &dev_attr_offline.attr, &dev_attr_isolated.attr, diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index e0106a7e31fa..479599473381 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -553,7 +553,7 @@ static void fastrpc_mmap_free(struct fastrpc_mmap *map) if (!IS_ERR_OR_NULL(map->handle)) ion_free(fl->apps->client, map->handle); - if (sess->smmu.enabled) { + if (sess && sess->smmu.enabled) { if (map->size || map->phys) msm_dma_unmap_sg(sess->smmu.dev, map->table->sgl, @@ -645,6 +645,9 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, unsigned attr, else sess = fl->sctx; + VERIFY(err, !IS_ERR_OR_NULL(sess)); + if (err) + goto bail; VERIFY(err, !IS_ERR_OR_NULL(map->buf = dma_buf_get(fd))); if (err) goto bail; @@ -2416,7 +2419,7 @@ static int fastrpc_channel_open(struct fastrpc_file *fl) kref_init(&me->channel[cid].kref); pr_info("'opened /dev/%s c %d %d'\n", gcinfo[cid].name, MAJOR(me->dev_no), cid); - if (me->channel[cid].ssrcount != + if (cid == 0 && me->channel[cid].ssrcount != me->channel[cid].prevssrcount) { if (fastrpc_mmap_remove_ssr(fl)) pr_err("ADSPRPC: SSR: Failed to unmap remote heap\n"); diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c index 55d36abe4679..7a4e6c82579c 100644 --- a/drivers/char/diag/diagfwd_peripheral.c +++ b/drivers/char/diag/diagfwd_peripheral.c @@ -990,11 +990,6 @@ static void __diag_fwd_open(struct diagfwd_info *fwd_info) if (!fwd_info->inited) return; - if (fwd_info->buf_1) - atomic_set(&fwd_info->buf_1->in_busy, 0); - if (fwd_info->buf_2) - atomic_set(&fwd_info->buf_2->in_busy, 0); - if (fwd_info->p_ops && fwd_info->p_ops->open) fwd_info->p_ops->open(fwd_info->ctxt); diff --git a/drivers/clk/msm/clock-gcc-8998.c b/drivers/clk/msm/clock-gcc-8998.c index f9d713a22c76..b1c8cc43769f 100644 --- a/drivers/clk/msm/clock-gcc-8998.c +++ b/drivers/clk/msm/clock-gcc-8998.c @@ -42,6 +42,7 @@ static void __iomem *virt_dbgbase; #define gpll0_out_main_source_val 1 #define gpll0_ao_source_val 1 #define gpll4_out_main_source_val 5 +#define gpll0_early_div_source_val 6 #define FIXDIV(div) (div ? (2 * (div) - 1) : (0)) @@ -164,6 +165,7 @@ static struct pll_vote_clk gpll0_ao = { }; DEFINE_EXT_CLK(gpll0_out_main, &gpll0.c); +DEFINE_EXT_CLK(gpll0_early_div, &gpll0.c); static struct local_vote_clk gcc_mmss_gpll0_clk = { .cbcr_reg = GCC_APCS_CLOCK_BRANCH_ENA_VOTE_1, @@ -328,7 +330,7 @@ static struct clk_freq_tbl ftbl_blsp_qup_spi_apps_clk_src[] = { F( 960000, cxo_clk_src, 10, 1, 2), F( 4800000, cxo_clk_src, 4, 0, 0), F( 9600000, cxo_clk_src, 2, 0, 0), - F( 15000000, gpll0_out_main, 10, 1, 4), + F( 15000000, gpll0_early_div, 5, 1, 4), F( 19200000, cxo_clk_src, 1, 0, 0), F( 25000000, gpll0_out_main, 12, 1, 2), F( 50000000, gpll0_out_main, 12, 0, 0), @@ -496,10 +498,10 @@ static struct rcg_clk blsp1_qup6_spi_apps_clk_src = { }; static struct clk_freq_tbl ftbl_blsp_uart_apps_clk_src[] = { - F( 3686400, gpll0_out_main, 1, 96, 15625), - F( 7372800, gpll0_out_main, 1, 192, 15625), - F( 14745600, gpll0_out_main, 1, 384, 15625), - F( 16000000, gpll0_out_main, 5, 2, 15), + F( 3686400, gpll0_early_div, 1, 192, 15625), + F( 7372800, gpll0_early_div, 1, 384, 15625), + F( 14745600, gpll0_early_div, 1, 768, 15625), + F( 16000000, gpll0_early_div, 1, 4, 75), F( 19200000, cxo_clk_src, 1, 0, 0), F( 24000000, gpll0_out_main, 5, 1, 5), F( 32000000, gpll0_out_main, 1, 4, 75), @@ -2732,6 +2734,8 @@ static int msm_gcc_8998_probe(struct platform_device *pdev) if (ret) return ret; + gpll0_early_div.c.rate = 300000000; + ret = enable_rpm_scaling(); if (ret < 0) return ret; diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c b/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c index e51cd437cf7c..eb69ed35f46d 100644 --- a/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c +++ b/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -38,41 +38,76 @@ /* Register Offsets from PLL base address */ #define PLL_ANALOG_CONTROLS_ONE 0x000 #define PLL_ANALOG_CONTROLS_TWO 0x004 +#define PLL_INT_LOOP_SETTINGS 0x008 +#define PLL_INT_LOOP_SETTINGS_TWO 0x00c #define PLL_ANALOG_CONTROLS_THREE 0x010 -#define PLL_DSM_DIVIDER 0x01c +#define PLL_ANALOG_CONTROLS_FOUR 0x014 +#define PLL_INT_LOOP_CONTROLS 0x018 +#define PLL_DSM_DIVIDER 0x01c #define PLL_FEEDBACK_DIVIDER 0x020 #define PLL_SYSTEM_MUXES 0x024 +#define PLL_FREQ_UPDATE_CONTROL_OVERRIDES 0x028 #define PLL_CMODE 0x02c #define PLL_CALIBRATION_SETTINGS 0x030 +#define PLL_BAND_SEL_CAL_TIMER_LOW 0x034 +#define PLL_BAND_SEL_CAL_TIMER_HIGH 0x038 +#define PLL_BAND_SEL_CAL_SETTINGS 0x03c +#define PLL_BAND_SEL_MIN 0x040 +#define PLL_BAND_SEL_MAX 0x044 +#define PLL_BAND_SEL_PFILT 0x048 +#define PLL_BAND_SEL_IFILT 0x04c +#define PLL_BAND_SEL_CAL_SETTINGS_TWO 0x050 #define PLL_BAND_SEL_CAL_SETTINGS_THREE 0x054 +#define PLL_BAND_SEL_CAL_SETTINGS_FOUR 0x058 +#define PLL_BAND_SEL_ICODE_HIGH 0x05c +#define PLL_BAND_SEL_ICODE_LOW 0x060 #define PLL_FREQ_DETECT_SETTINGS_ONE 0x064 #define PLL_PFILT 0x07c #define PLL_IFILT 0x080 +#define PLL_GAIN 0x084 +#define PLL_ICODE_LOW 0x088 +#define PLL_ICODE_HIGH 0x08c +#define PLL_LOCKDET 0x090 #define PLL_OUTDIV 0x094 -#define PLL_CORE_OVERRIDE 0x0a4 +#define PLL_FASTLOCK_CONTROL 0x098 +#define PLL_PASS_OUT_OVERRIDE_ONE 0x09c +#define PLL_PASS_OUT_OVERRIDE_TWO 0x0a0 +#define PLL_CORE_OVERRIDE 0x0a4 #define PLL_CORE_INPUT_OVERRIDE 0x0a8 +#define PLL_RATE_CHANGE 0x0ac +#define PLL_PLL_DIGITAL_TIMERS 0x0b0 #define PLL_PLL_DIGITAL_TIMERS_TWO 0x0b4 +#define PLL_DEC_FRAC_MUXES 0x0c8 #define PLL_DECIMAL_DIV_START_1 0x0cc #define PLL_FRAC_DIV_START_LOW_1 0x0d0 #define PLL_FRAC_DIV_START_MID_1 0x0d4 #define PLL_FRAC_DIV_START_HIGH_1 0x0d8 +#define PLL_MASH_CONTROL 0x0ec +#define PLL_SSC_MUX_CONTROL 0x108 #define PLL_SSC_STEPSIZE_LOW_1 0x10c #define PLL_SSC_STEPSIZE_HIGH_1 0x110 #define PLL_SSC_DIV_PER_LOW_1 0x114 #define PLL_SSC_DIV_PER_HIGH_1 0x118 #define PLL_SSC_DIV_ADJPER_LOW_1 0x11c #define PLL_SSC_DIV_ADJPER_HIGH_1 0x120 -#define PLL_SSC_CONTROL 0x13c -#define PLL_PLL_OUTDIV_RATE 0x140 +#define PLL_SSC_CONTROL 0x13c +#define PLL_PLL_OUTDIV_RATE 0x140 #define PLL_PLL_LOCKDET_RATE_1 0x144 #define PLL_PLL_PROP_GAIN_RATE_1 0x14c #define PLL_PLL_BAND_SET_RATE_1 0x154 #define PLL_PLL_INT_GAIN_IFILT_BAND_1 0x15c #define PLL_PLL_FL_INT_GAIN_PFILT_BAND_1 0x164 -#define PLL_PLL_LOCK_OVERRIDE 0x180 -#define PLL_PLL_LOCK_DELAY 0x184 -#define PLL_CLOCK_INVERTERS 0x18c -#define PLL_COMMON_STATUS_ONE 0x1a0 +#define PLL_FASTLOCK_EN_BAND 0x16c +#define PLL_FREQ_TUNE_ACCUM_INIT_MUX 0x17c +#define PLL_PLL_LOCK_OVERRIDE 0x180 +#define PLL_PLL_LOCK_DELAY 0x184 +#define PLL_PLL_LOCK_MIN_DELAY 0x188 +#define PLL_CLOCK_INVERTERS 0x18c +#define PLL_SPARE_AND_JPC_OVERRIDES 0x190 +#define PLL_BIAS_CONTROL_1 0x194 +#define PLL_BIAS_CONTROL_2 0x198 +#define PLL_ALOG_OBSV_BUS_CTRL_1 0x19c +#define PLL_COMMON_STATUS_ONE 0x1a0 /* Register Offsets from PHY base address */ #define PHY_CMN_CLK_CFG0 0x010 @@ -384,6 +419,49 @@ static void dsi_pll_config_hzindep_reg(struct dsi_pll_8998 *pll, MDSS_PLL_REG_W(pll_base, PLL_IFILT, 0x3f); } +static void dsi_pll_init_val(struct mdss_pll_resources *rsc) +{ + void __iomem *pll_base = rsc->pll_base; + + MDSS_PLL_REG_W(pll_base, PLL_CORE_INPUT_OVERRIDE, 0x10); + MDSS_PLL_REG_W(pll_base, PLL_INT_LOOP_SETTINGS, 0x3f); + MDSS_PLL_REG_W(pll_base, PLL_INT_LOOP_SETTINGS_TWO, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_FOUR, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_INT_LOOP_CONTROLS, 0x80); + MDSS_PLL_REG_W(pll_base, PLL_FREQ_UPDATE_CONTROL_OVERRIDES, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_TIMER_LOW, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_TIMER_HIGH, 0x02); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS, 0x82); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_MIN, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_MAX, 0xff); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_PFILT, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_IFILT, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_TWO, 0x25); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_FOUR, 0x4f); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_ICODE_HIGH, 0x0a); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_ICODE_LOW, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_GAIN, 0x42); + MDSS_PLL_REG_W(pll_base, PLL_ICODE_LOW, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_ICODE_HIGH, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_LOCKDET, 0x30); + MDSS_PLL_REG_W(pll_base, PLL_FASTLOCK_CONTROL, 0x04); + MDSS_PLL_REG_W(pll_base, PLL_PASS_OUT_OVERRIDE_ONE, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_PASS_OUT_OVERRIDE_TWO, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_RATE_CHANGE, 0x01); + MDSS_PLL_REG_W(pll_base, PLL_PLL_DIGITAL_TIMERS, 0x08); + MDSS_PLL_REG_W(pll_base, PLL_DEC_FRAC_MUXES, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_MASH_CONTROL, 0x03); + MDSS_PLL_REG_W(pll_base, PLL_SSC_MUX_CONTROL, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_SSC_CONTROL, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_FASTLOCK_EN_BAND, 0x03); + MDSS_PLL_REG_W(pll_base, PLL_FREQ_TUNE_ACCUM_INIT_MUX, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_MIN_DELAY, 0x19); + MDSS_PLL_REG_W(pll_base, PLL_SPARE_AND_JPC_OVERRIDES, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_BIAS_CONTROL_1, 0x40); + MDSS_PLL_REG_W(pll_base, PLL_BIAS_CONTROL_2, 0x20); + MDSS_PLL_REG_W(pll_base, PLL_ALOG_OBSV_BUS_CTRL_1, 0x0); +} + static void dsi_pll_commit(struct dsi_pll_8998 *pll, struct mdss_pll_resources *rsc) { @@ -440,6 +518,8 @@ static int vco_8998_set_rate(struct clk *c, unsigned long rate) return rc; } + dsi_pll_init_val(rsc); + dsi_pll_setup_config(pll, rsc); dsi_pll_calc_dec_frac(pll, rsc); @@ -554,7 +634,6 @@ error: static void dsi_pll_disable_sub(struct mdss_pll_resources *rsc) { - dsi_pll_disable_global_clk(rsc); MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_RBUF_CTRL, 0); dsi_pll_disable_pll_bias(rsc); } @@ -573,11 +652,20 @@ static void dsi_pll_disable(struct dsi_pll_vco_clk *vco) pr_debug("stop PLL (%d)\n", rsc->index); + /* + * To avoid any stray glitches while + * abruptly powering down the PLL + * make sure to gate the clock using + * the clock enable bit before powering + * down the PLL + **/ + dsi_pll_disable_global_clk(rsc); MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_PLL_CNTRL, 0); dsi_pll_disable_sub(rsc); - if (rsc->slave) + if (rsc->slave) { + dsi_pll_disable_global_clk(rsc->slave); dsi_pll_disable_sub(rsc->slave); - + } /* flush, ensure all register writes are done*/ wmb(); rsc->pll_on = false; diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index 64c4bf8f58a8..ce67145bb142 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -1123,6 +1123,8 @@ static int cluster_configure(struct lpm_cluster *cluster, int idx, struct cpumask nextcpu, *cpumask; uint64_t us; uint32_t pred_us; + uint64_t sec; + uint64_t nsec; us = get_cluster_sleep_time(cluster, &nextcpu, from_idle, &pred_us); @@ -1134,11 +1136,20 @@ static int cluster_configure(struct lpm_cluster *cluster, int idx, goto failed_set_mode; } - us = (us + 1) * 1000; clear_predict_history(); clear_cl_predict_history(); - do_div(us, NSEC_PER_SEC/SCLK_HZ); + us = us + 1; + sec = us; + do_div(sec, USEC_PER_SEC); + nsec = us - sec * USEC_PER_SEC; + + sec = sec * SCLK_HZ; + if (nsec > 0) { + nsec = nsec * NSEC_PER_USEC; + do_div(nsec, NSEC_PER_SEC/SCLK_HZ); + } + us = sec + nsec; msm_mpm_enter_sleep(us, from_idle, cpumask); } diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c index ab21334d5813..4002a5b57250 100644 --- a/drivers/crypto/msm/ice.c +++ b/drivers/crypto/msm/ice.c @@ -1608,7 +1608,8 @@ static struct ice_device *get_ice_device_from_storage_type list_for_each_entry(ice_dev, &ice_devices, list) { if (!strcmp(ice_dev->ice_instance_type, storage_type)) { - pr_info("%s: found ice device %p\n", __func__, ice_dev); + pr_debug("%s: found ice device %pK\n", + __func__, ice_dev); break; } } diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 3faa5aaf9d03..89c7590ad121 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -2675,11 +2675,11 @@ static void adreno_pwrlevel_change_settings(struct kgsl_device *device, } static void adreno_clk_set_options(struct kgsl_device *device, const char *name, - struct clk *clk) + struct clk *clk, bool on) { if (ADRENO_GPU_DEVICE(ADRENO_DEVICE(device))->clk_set_options) ADRENO_GPU_DEVICE(ADRENO_DEVICE(device))->clk_set_options( - ADRENO_DEVICE(device), name, clk); + ADRENO_DEVICE(device), name, clk, on); } static void adreno_iommu_sync(struct kgsl_device *device, bool sync) diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 33fdb9ae11fa..218d08e6dfc3 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -789,7 +789,7 @@ struct adreno_gpudev { void (*preemption_schedule)(struct adreno_device *); void (*enable_64bit)(struct adreno_device *); void (*clk_set_options)(struct adreno_device *, - const char *, struct clk *); + const char *, struct clk *, bool on); }; /** diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index 87300096fbf1..0715022be6e3 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -1640,11 +1640,15 @@ static void a5xx_pwrlevel_change_settings(struct adreno_device *adreno_dev, } static void a5xx_clk_set_options(struct adreno_device *adreno_dev, - const char *name, struct clk *clk) + const char *name, struct clk *clk, bool on) { + + if (!adreno_is_a540(adreno_dev) && !adreno_is_a512(adreno_dev) && + !adreno_is_a508(adreno_dev)) + return; + /* Handle clock settings for GFX PSCBCs */ - if (adreno_is_a540(adreno_dev) || adreno_is_a512(adreno_dev) || - adreno_is_a508(adreno_dev)) { + if (on) { if (!strcmp(name, "mem_iface_clk")) { clk_set_flags(clk, CLKFLAG_NORETAIN_PERIPH); clk_set_flags(clk, CLKFLAG_NORETAIN_MEM); @@ -1652,6 +1656,11 @@ static void a5xx_clk_set_options(struct adreno_device *adreno_dev, clk_set_flags(clk, CLKFLAG_RETAIN_PERIPH); clk_set_flags(clk, CLKFLAG_RETAIN_MEM); } + } else { + if (!strcmp(name, "core_clk")) { + clk_set_flags(clk, CLKFLAG_NORETAIN_PERIPH); + clk_set_flags(clk, CLKFLAG_NORETAIN_MEM); + } } } diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c index 161b718b8a38..d79d9613043f 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.c +++ b/drivers/gpu/msm/adreno_ringbuffer.c @@ -813,10 +813,10 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, dwords += 6; /* - * REG_TO_MEM packet on A5xx needs another ordinal. + * REG_TO_MEM packet on A5xx and above needs another ordinal. * Add 2 more dwords since we do profiling before and after. */ - if (adreno_is_a5xx(adreno_dev)) + if (!ADRENO_LEGACY_PM4(adreno_dev)) dwords += 2; /* @@ -833,7 +833,7 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, if (test_bit(CMDOBJ_PROFILE, &cmdobj->priv)) { kernel_profiling = true; dwords += 6; - if (adreno_is_a5xx(adreno_dev)) + if (!ADRENO_LEGACY_PM4(adreno_dev)) dwords += 2; } diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index aca484618268..177b283a2dda 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -166,7 +166,7 @@ struct kgsl_functable { unsigned int prelevel, unsigned int postlevel, bool post); void (*regulator_disable_poll)(struct kgsl_device *device); void (*clk_set_options)(struct kgsl_device *device, - const char *name, struct clk *clk); + const char *name, struct clk *clk, bool on); void (*gpu_model)(struct kgsl_device *device, char *str, size_t bufsz); void (*stop_fault_timer)(struct kgsl_device *device); diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index e4c431546d2a..0150d50c925b 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -150,9 +150,6 @@ static void _ab_buslevel_update(struct kgsl_pwrctrl *pwr, *ab = pwr->bus_ab_mbytes; else *ab = (pwr->bus_percent_ab * max_bw) / 100; - - if (*ab > ib) - *ab = ib; } /** @@ -2003,10 +2000,6 @@ static int _get_clocks(struct kgsl_device *device) if (!strcmp(name, "isense_clk")) pwr->isense_clk_indx = i; - - if (device->ftbl->clk_set_options) - device->ftbl->clk_set_options(device, name, - pwr->grp_clks[i]); break; } } @@ -2453,6 +2446,22 @@ static void kgsl_pwrctrl_disable(struct kgsl_device *device) kgsl_pwrctrl_pwrrail(device, KGSL_PWRFLAGS_OFF); } +static void +kgsl_pwrctrl_clk_set_options(struct kgsl_device *device, bool on) +{ + struct kgsl_pwrctrl *pwr = &device->pwrctrl; + int i; + + for (i = 0; i < KGSL_MAX_CLKS; i++) { + if (pwr->grp_clks[i] == NULL) + continue; + + if (device->ftbl->clk_set_options) + device->ftbl->clk_set_options(device, clocks[i], + pwr->grp_clks[i], on); + } +} + /** * _init() - Get the GPU ready to start, but don't turn anything on * @device - Pointer to the kgsl_device struct @@ -2499,6 +2508,7 @@ static int _wake(struct kgsl_device *device) device->ftbl->resume(device); /* fall through */ case KGSL_STATE_SLUMBER: + kgsl_pwrctrl_clk_set_options(device, true); status = device->ftbl->start(device, device->pwrctrl.superfast); device->pwrctrl.superfast = false; @@ -2535,6 +2545,7 @@ static int _wake(struct kgsl_device *device) device->pwrctrl.interval_timeout); break; case KGSL_STATE_AWARE: + kgsl_pwrctrl_clk_set_options(device, true); /* Enable state before turning on irq */ kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE); kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON); @@ -2649,6 +2660,7 @@ _slumber(struct kgsl_device *device) status = kgsl_pwrctrl_enable(device); device->ftbl->suspend_context(device); device->ftbl->stop(device); + kgsl_pwrctrl_clk_set_options(device, false); kgsl_pwrctrl_disable(device); kgsl_pwrscale_sleep(device); kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF); diff --git a/drivers/input/misc/vl53L0/stmvl53l0.h b/drivers/input/misc/vl53L0/stmvl53l0.h index ae517ebe461a..b15d78cc6825 100644 --- a/drivers/input/misc/vl53L0/stmvl53l0.h +++ b/drivers/input/misc/vl53L0/stmvl53l0.h @@ -131,6 +131,7 @@ struct stmvl53l0_data { struct miscdevice miscdev; int irq; + int irq_gpio; unsigned int reset; /* control flag from HAL */ diff --git a/drivers/input/misc/vl53L0/stmvl53l0_module-cci.c b/drivers/input/misc/vl53L0/stmvl53l0_module-cci.c index e08edbcc73f9..79fba00ea086 100644 --- a/drivers/input/misc/vl53L0/stmvl53l0_module-cci.c +++ b/drivers/input/misc/vl53L0/stmvl53l0_module-cci.c @@ -248,6 +248,7 @@ static int stmvl53l0_cci_init(struct cci_data *data) cci_client->retries = 3; cci_client->id_map = 0; cci_client->cci_i2c_master = data->cci_master; + cci_client->i2c_freq_mode = I2C_FAST_MODE; rc = data->client->i2c_func_tbl->i2c_util(data->client, MSM_CCI_INIT); if (rc < 0) { vl53l0_errmsg("%d: CCI Init failed\n", __LINE__); @@ -295,8 +296,20 @@ static int32_t stmvl53l0_platform_probe(struct platform_device *pdev) rc = stmvl53l0_get_dt_data(&pdev->dev, cci_object); if (rc < 0) { vl53l0_errmsg("%d, failed rc %d\n", __LINE__, rc); + kfree(vl53l0_data->client_object); + kfree(vl53l0_data); return rc; } + vl53l0_data->irq_gpio = of_get_named_gpio_flags(pdev->dev.of_node, + "stm,irq-gpio", 0, NULL); + + if (!gpio_is_valid(vl53l0_data->irq_gpio)) { + vl53l0_errmsg("%d failed get irq gpio", __LINE__); + kfree(vl53l0_data->client_object); + kfree(vl53l0_data); + return -EINVAL; + } + cci_object->subdev_id = pdev->id; /* Set device type as platform device */ @@ -418,6 +431,7 @@ int stmvl53l0_power_up_cci(void *cci_object, unsigned int *preset_flag) } } data->power_up = 1; + usleep_range(3000, 3500); *preset_flag = 1; vl53l0_dbgmsg("End\n"); diff --git a/drivers/input/misc/vl53L0/stmvl53l0_module.c b/drivers/input/misc/vl53L0/stmvl53l0_module.c index f242e5f497d0..6881aba9fc64 100644 --- a/drivers/input/misc/vl53L0/stmvl53l0_module.c +++ b/drivers/input/misc/vl53L0/stmvl53l0_module.c @@ -38,8 +38,8 @@ #include "vl53l0_api.h" #include "vl53l010_api.h" -/*#define USE_INT */ -#define IRQ_NUM 59 +#define USE_INT + /* #define DEBUG_TIME_LOG */ #ifdef DEBUG_TIME_LOG struct timeval start_tv, stop_tv; @@ -2668,12 +2668,12 @@ int stmvl53l0_setup(struct stmvl53l0_data *data) #ifdef USE_INT /* init interrupt */ - gpio_request(IRQ_NUM, "vl53l0_gpio_int"); - gpio_direction_input(IRQ_NUM); - irq = gpio_to_irq(IRQ_NUM); + gpio_request(data->irq_gpio, "vl53l0_gpio_int"); + gpio_direction_input(data->irq_gpio); + irq = gpio_to_irq(data->irq_gpio); if (irq < 0) { vl53l0_errmsg("filed to map GPIO: %d to interrupt:%d\n", - IRQ_NUM, irq); + data->irq_gpio, irq); } else { vl53l0_dbgmsg("register_irq:%d\n", irq); /* IRQF_TRIGGER_FALLING- poliarity:0 IRQF_TRIGGER_RISNG - diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 1d4e8a4ce206..2d564aabbc74 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -12,7 +12,6 @@ menuconfig INPUT_TOUCHSCREEN if INPUT_TOUCHSCREEN source "drivers/input/touchscreen/synaptics_dsx/Kconfig" -source "drivers/input/touchscreen/synaptics_dsx_2.6/Kconfig" config OF_TOUCHSCREEN def_tristate INPUT diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 2e0161cf95bc..f5be6fc19751 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -70,7 +70,6 @@ obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o obj-$(CONFIG_TOUCHSCREEN_SUN4I) += sun4i-ts.o obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v21) += synaptics_dsx/ -obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v26) += synaptics_dsx_2.6/ obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c index 3e85cb5e2ebc..206941708141 100644 --- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c +++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c @@ -3666,7 +3666,7 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) return -EINVAL; } - rmi4_data = devm_kzalloc(&pdev->dev, sizeof(*rmi4_data), GFP_KERNEL); + rmi4_data = kzalloc(sizeof(*rmi4_data), GFP_KERNEL); if (!rmi4_data) { dev_err(&pdev->dev, "%s: Failed to alloc mem for rmi4_data\n", @@ -3684,12 +3684,6 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) rmi4_data->fingers_on_2d = false; rmi4_data->update_coords = true; - rmi4_data->write_buf = devm_kzalloc(&pdev->dev, I2C_WRITE_BUF_MAX_LEN, - GFP_KERNEL); - if (!rmi4_data->write_buf) - return -ENOMEM; - rmi4_data->write_buf_len = I2C_WRITE_BUF_MAX_LEN; - rmi4_data->irq_enable = synaptics_rmi4_irq_enable; rmi4_data->reset_device = synaptics_rmi4_reset_device; diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.h b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.h index a642092e2f63..7d7e045d7917 100644 --- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.h +++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.h @@ -101,7 +101,6 @@ #define PINCTRL_STATE_RELEASE "pmx_ts_release" #define SYNA_FW_NAME_MAX_LEN 50 -#define I2C_WRITE_BUF_MAX_LEN 32 enum exp_fn { RMI_DEV = 0, @@ -278,8 +277,6 @@ struct synaptics_rmi4_data { unsigned char no_sleep_setting; unsigned char intr_mask[MAX_INTR_REGISTERS]; unsigned char *button_txrx_mapping; - unsigned char *write_buf; - unsigned short write_buf_len; unsigned short num_of_intr_regs; unsigned short f01_query_base_addr; unsigned short f01_cmd_base_addr; diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c index 0be7e0bc9045..0b3fbaf9f462 100644 --- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c +++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c @@ -134,33 +134,18 @@ static int synaptics_rmi4_i2c_write(struct synaptics_rmi4_data *rmi4_data, { int retval; unsigned char retry; + unsigned char buf[length + 1]; struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent); struct i2c_msg msg[] = { { .addr = i2c->addr, .flags = 0, .len = length + 1, + .buf = buf, } }; mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex); - /* - * Reassign memory for write_buf in case length is greater than 32 bytes - */ - if (rmi4_data->write_buf_len < length + 1) { - devm_kfree(rmi4_data->pdev->dev.parent, rmi4_data->write_buf); - rmi4_data->write_buf = devm_kzalloc(rmi4_data->pdev->dev.parent, - length + 1, GFP_KERNEL); - if (!rmi4_data->write_buf) { - rmi4_data->write_buf_len = 0; - retval = -ENOMEM; - goto exit; - } - rmi4_data->write_buf_len = length + 1; - } - - /* Assign the write_buf of driver structure to i2c_msg buf */ - msg[0].buf = rmi4_data->write_buf; retval = synaptics_rmi4_i2c_set_page(rmi4_data, addr); if (retval != PAGE_SELECT_LEN) { @@ -168,8 +153,8 @@ static int synaptics_rmi4_i2c_write(struct synaptics_rmi4_data *rmi4_data, goto exit; } - rmi4_data->write_buf[0] = addr & MASK_8BIT; - memcpy(&rmi4_data->write_buf[1], &data[0], length); + buf[0] = addr & MASK_8BIT; + memcpy(&buf[1], &data[0], length); for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) { if (i2c_transfer(i2c->adapter, msg, 1) == 1) { diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/Kconfig b/drivers/input/touchscreen/synaptics_dsx_2.6/Kconfig deleted file mode 100644 index 53896288ba77..000000000000 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/Kconfig +++ /dev/null @@ -1,127 +0,0 @@ -# -# Synaptics DSX v2.6 touchscreen driver configuration -# -menuconfig TOUCHSCREEN_SYNAPTICS_DSX_v26 - bool "Synaptics DSX v2.6 touchscreen" - default y - help - Say Y here if you have a Synaptics DSX touchscreen connected - to your system. - - If unsure, say N. - -if TOUCHSCREEN_SYNAPTICS_DSX_v26 - -choice - default TOUCHSCREEN_SYNAPTICS_DSX_I2C_v26 - prompt "Synaptics DSX v2.6 bus interface" -config TOUCHSCREEN_SYNAPTICS_DSX_I2C_v26 - bool "RMI over I2C" - depends on I2C -config TOUCHSCREEN_SYNAPTICS_DSX_SPI_v26 - bool "RMI over SPI" - depends on SPI_MASTER -config TOUCHSCREEN_SYNAPTICS_DSX_RMI_HID_I2C_v26 - bool "HID over I2C" - depends on I2C -endchoice - -config TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26 - tristate "Synaptics DSX v2.6 core driver module" - depends on I2C || SPI_MASTER - help - Say Y here to enable basic touch reporting functionality. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called synaptics_dsx_core. - -config TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_v26 - tristate "Synaptics DSX v2.6 RMI device module" - depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26 - help - Say Y here to enable support for direct RMI register access. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called synaptics_dsx_rmi_dev. - -config TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v26 - tristate "Synaptics DSX v2.6 firmware update module" - depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26 - help - Say Y here to enable support for doing firmware update. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called synaptics_dsx_fw_update. - -config TOUCHSCREEN_SYNAPTICS_DSX_TEST_REPORTING_v26 - tristate "Synaptics DSX v2.6 test reporting module" - depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26 - help - Say Y here to enable support for retrieving production test reports. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called synaptics_dsx_test_reporting. - -config TOUCHSCREEN_SYNAPTICS_DSX_PROXIMITY_v26 - tristate "Synaptics DSX v2.6 proximity module" - depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26 - help - Say Y here to enable support for proximity functionality. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called synaptics_dsx_proximity. - -config TOUCHSCREEN_SYNAPTICS_DSX_ACTIVE_PEN_v26 - tristate "Synaptics DSX v2.6 active pen module" - depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26 - help - Say Y here to enable support for active pen functionality. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called synaptics_dsx_active_pen. - -config TOUCHSCREEN_SYNAPTICS_DSX_GESTURE_v26 - tristate "Synaptics DSX v2.6 user defined gesture module" - depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26 - help - Say Y here to enable support for user defined gesture functionality. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called synaptics_dsx_gesture. - -config TOUCHSCREEN_SYNAPTICS_DSX_VIDEO_v26 - tristate "Synaptics DSX v2.6 video module" - depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26 - help - Say Y here to enable support for video communication functionality. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called synaptics_dsx_video. - -config SECURE_TOUCH_SYNAPTICS_DSX_V26 - bool "Secure Touch support for Synaptics V2.6 Touchscreen" - depends on TOUCHSCREEN_SYNAPTICS_DSX_I2C_v26 - help - Say Y here - -Synaptics DSX V2.6 touch driver is connected - -To enable secure touch for Synaptics DSX V2.6 touch driver - - If unsure, say N. - -endif diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/Makefile b/drivers/input/touchscreen/synaptics_dsx_2.6/Makefile deleted file mode 100644 index e5e72153f8c4..000000000000 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# -# Makefile for the Synaptics DSX touchscreen driver. -# - -# Each configuration option enables a list of files. - -obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_I2C_v26) += synaptics_dsx_i2c.o -obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_SPI_v26) += synaptics_dsx_spi.o -obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_HID_I2C_v26) += synaptics_dsx_rmi_hid_i2c.o -obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26) += synaptics_dsx_core.o -obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_v26) += synaptics_dsx_rmi_dev.o -obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v26) += synaptics_dsx_fw_update.o -obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_TEST_REPORTING_v26) += synaptics_dsx_test_reporting.o -obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_PROXIMITY_v26) += synaptics_dsx_proximity.o -obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_ACTIVE_PEN_v26) += synaptics_dsx_active_pen.o -obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_GESTURE_v26) += synaptics_dsx_gesture.o -obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_VIDEO_v26) += synaptics_dsx_video.o diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_active_pen.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_active_pen.c deleted file mode 100644 index db5324ab09fe..000000000000 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_active_pen.c +++ /dev/null @@ -1,624 +0,0 @@ -/* - * Synaptics DSX touchscreen driver - * - * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved. - * - * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com> - * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com> - * - * 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. - * - * 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. - * - * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS - * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, - * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS. - * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION - * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED - * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES - * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' - * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. - * DOLLARS. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/input.h> -#include <linux/platform_device.h> -#include <linux/input/synaptics_dsx_v2_6.h> -#include "synaptics_dsx_core.h" - -#define APEN_PHYS_NAME "synaptics_dsx/active_pen" - -#define ACTIVE_PEN_MAX_PRESSURE_16BIT 65535 -#define ACTIVE_PEN_MAX_PRESSURE_8BIT 255 - -struct synaptics_rmi4_f12_query_8 { - union { - struct { - unsigned char size_of_query9; - struct { - unsigned char data0_is_present:1; - unsigned char data1_is_present:1; - unsigned char data2_is_present:1; - unsigned char data3_is_present:1; - unsigned char data4_is_present:1; - unsigned char data5_is_present:1; - unsigned char data6_is_present:1; - unsigned char data7_is_present:1; - } __packed; - }; - unsigned char data[2]; - }; -}; - -struct apen_data_8b_pressure { - union { - struct { - unsigned char status_pen:1; - unsigned char status_invert:1; - unsigned char status_barrel:1; - unsigned char status_reserved:5; - unsigned char x_lsb; - unsigned char x_msb; - unsigned char y_lsb; - unsigned char y_msb; - unsigned char pressure_msb; - unsigned char battery_state; - unsigned char pen_id_0_7; - unsigned char pen_id_8_15; - unsigned char pen_id_16_23; - unsigned char pen_id_24_31; - } __packed; - unsigned char data[11]; - }; -}; - -struct apen_data { - union { - struct { - unsigned char status_pen:1; - unsigned char status_invert:1; - unsigned char status_barrel:1; - unsigned char status_reserved:5; - unsigned char x_lsb; - unsigned char x_msb; - unsigned char y_lsb; - unsigned char y_msb; - unsigned char pressure_lsb; - unsigned char pressure_msb; - unsigned char battery_state; - unsigned char pen_id_0_7; - unsigned char pen_id_8_15; - unsigned char pen_id_16_23; - unsigned char pen_id_24_31; - } __packed; - unsigned char data[12]; - }; -}; - -struct synaptics_rmi4_apen_handle { - bool apen_present; - unsigned char intr_mask; - unsigned char battery_state; - unsigned short query_base_addr; - unsigned short control_base_addr; - unsigned short data_base_addr; - unsigned short command_base_addr; - unsigned short apen_data_addr; - unsigned short max_pressure; - unsigned int pen_id; - struct input_dev *apen_dev; - struct apen_data *apen_data; - struct synaptics_rmi4_data *rmi4_data; -}; - -static struct synaptics_rmi4_apen_handle *apen; - -DECLARE_COMPLETION(apen_remove_complete); - -static void apen_lift(void) -{ - input_report_key(apen->apen_dev, BTN_TOUCH, 0); - input_report_key(apen->apen_dev, BTN_TOOL_PEN, 0); - input_report_key(apen->apen_dev, BTN_TOOL_RUBBER, 0); - input_sync(apen->apen_dev); - apen->apen_present = false; - - return; -} - -static void apen_report(void) -{ - int retval; - int x; - int y; - int pressure; - static int invert = -1; - struct apen_data_8b_pressure *apen_data_8b; - struct synaptics_rmi4_data *rmi4_data = apen->rmi4_data; - - retval = synaptics_rmi4_reg_read(rmi4_data, - apen->apen_data_addr, - apen->apen_data->data, - sizeof(apen->apen_data->data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read active pen data\n", - __func__); - return; - } - - if (apen->apen_data->status_pen == 0) { - if (apen->apen_present) - apen_lift(); - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: No active pen data\n", - __func__); - - return; - } - - x = (apen->apen_data->x_msb << 8) | (apen->apen_data->x_lsb); - y = (apen->apen_data->y_msb << 8) | (apen->apen_data->y_lsb); - - if ((x == -1) && (y == -1)) { - if (apen->apen_present) - apen_lift(); - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Active pen in range but no valid x & y\n", - __func__); - - return; - } - - if (!apen->apen_present) - invert = -1; - - if (invert != -1 && invert != apen->apen_data->status_invert) - apen_lift(); - - invert = apen->apen_data->status_invert; - - if (apen->max_pressure == ACTIVE_PEN_MAX_PRESSURE_16BIT) { - pressure = (apen->apen_data->pressure_msb << 8) | - apen->apen_data->pressure_lsb; - apen->battery_state = apen->apen_data->battery_state; - apen->pen_id = (apen->apen_data->pen_id_24_31 << 24) | - (apen->apen_data->pen_id_16_23 << 16) | - (apen->apen_data->pen_id_8_15 << 8) | - apen->apen_data->pen_id_0_7; - } else { - apen_data_8b = (struct apen_data_8b_pressure *)apen->apen_data; - pressure = apen_data_8b->pressure_msb; - apen->battery_state = apen_data_8b->battery_state; - apen->pen_id = (apen_data_8b->pen_id_24_31 << 24) | - (apen_data_8b->pen_id_16_23 << 16) | - (apen_data_8b->pen_id_8_15 << 8) | - apen_data_8b->pen_id_0_7; - } - - input_report_key(apen->apen_dev, BTN_TOUCH, pressure > 0 ? 1 : 0); - input_report_key(apen->apen_dev, - apen->apen_data->status_invert > 0 ? - BTN_TOOL_RUBBER : BTN_TOOL_PEN, 1); - input_report_key(apen->apen_dev, - BTN_STYLUS, apen->apen_data->status_barrel > 0 ? - 1 : 0); - input_report_abs(apen->apen_dev, ABS_X, x); - input_report_abs(apen->apen_dev, ABS_Y, y); - input_report_abs(apen->apen_dev, ABS_PRESSURE, pressure); - - input_sync(apen->apen_dev); - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Active pen: status = %d, invert = %d, barrel = %d, x = %d, y = %d, pressure = %d\n", - __func__, - apen->apen_data->status_pen, - apen->apen_data->status_invert, - apen->apen_data->status_barrel, - x, y, pressure); - - apen->apen_present = true; - - return; -} - -static void apen_set_params(void) -{ - input_set_abs_params(apen->apen_dev, ABS_X, 0, - apen->rmi4_data->sensor_max_x, 0, 0); - input_set_abs_params(apen->apen_dev, ABS_Y, 0, - apen->rmi4_data->sensor_max_y, 0, 0); - input_set_abs_params(apen->apen_dev, ABS_PRESSURE, 0, - apen->max_pressure, 0, 0); - - return; -} - -static int apen_pressure(struct synaptics_rmi4_f12_query_8 *query_8) -{ - int retval; - unsigned char ii; - unsigned char data_reg_presence; - unsigned char size_of_query_9; - unsigned char *query_9; - unsigned char *data_desc; - struct synaptics_rmi4_data *rmi4_data = apen->rmi4_data; - - data_reg_presence = query_8->data[1]; - - size_of_query_9 = query_8->size_of_query9; - query_9 = kmalloc(size_of_query_9, GFP_KERNEL); - - retval = synaptics_rmi4_reg_read(rmi4_data, - apen->query_base_addr + 9, - query_9, - size_of_query_9); - if (retval < 0) - goto exit; - - data_desc = query_9; - - for (ii = 0; ii < 6; ii++) { - if (!(data_reg_presence & (1 << ii))) - continue; /* The data register is not present */ - data_desc++; /* Jump over the size entry */ - while (*data_desc & (1 << 7)) - data_desc++; - data_desc++; /* Go to the next descriptor */ - } - - data_desc++; /* Jump over the size entry */ - /* Check for the presence of subpackets 1 and 2 */ - if ((*data_desc & (3 << 1)) == (3 << 1)) - apen->max_pressure = ACTIVE_PEN_MAX_PRESSURE_16BIT; - else - apen->max_pressure = ACTIVE_PEN_MAX_PRESSURE_8BIT; - -exit: - kfree(query_9); - - return retval; -} - -static int apen_reg_init(void) -{ - int retval; - unsigned char data_offset; - unsigned char size_of_query8; - struct synaptics_rmi4_f12_query_8 query_8; - struct synaptics_rmi4_data *rmi4_data = apen->rmi4_data; - - retval = synaptics_rmi4_reg_read(rmi4_data, - apen->query_base_addr + 7, - &size_of_query8, - sizeof(size_of_query8)); - if (retval < 0) - return retval; - - retval = synaptics_rmi4_reg_read(rmi4_data, - apen->query_base_addr + 8, - query_8.data, - sizeof(query_8.data)); - if (retval < 0) - return retval; - - if ((size_of_query8 >= 2) && (query_8.data6_is_present)) { - data_offset = query_8.data0_is_present + - query_8.data1_is_present + - query_8.data2_is_present + - query_8.data3_is_present + - query_8.data4_is_present + - query_8.data5_is_present; - apen->apen_data_addr = apen->data_base_addr + data_offset; - retval = apen_pressure(&query_8); - if (retval < 0) - return retval; - } else { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Active pen support unavailable\n", - __func__); - retval = -ENODEV; - } - - return retval; -} - -static int apen_scan_pdt(void) -{ - int retval; - unsigned char ii; - unsigned char page; - unsigned char intr_count = 0; - unsigned char intr_off; - unsigned char intr_src; - unsigned short addr; - struct synaptics_rmi4_fn_desc fd; - struct synaptics_rmi4_data *rmi4_data = apen->rmi4_data; - - for (page = 0; page < PAGES_TO_SERVICE; page++) { - for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) { - addr |= (page << 8); - - retval = synaptics_rmi4_reg_read(rmi4_data, - addr, - (unsigned char *)&fd, - sizeof(fd)); - if (retval < 0) - return retval; - - addr &= ~(MASK_8BIT << 8); - - if (fd.fn_number) { - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Found F%02x\n", - __func__, fd.fn_number); - switch (fd.fn_number) { - case SYNAPTICS_RMI4_F12: - goto f12_found; - break; - } - } else { - break; - } - - intr_count += fd.intr_src_count; - } - } - - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to find F12\n", - __func__); - return -EINVAL; - -f12_found: - apen->query_base_addr = fd.query_base_addr | (page << 8); - apen->control_base_addr = fd.ctrl_base_addr | (page << 8); - apen->data_base_addr = fd.data_base_addr | (page << 8); - apen->command_base_addr = fd.cmd_base_addr | (page << 8); - - retval = apen_reg_init(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to initialize active pen registers\n", - __func__); - return retval; - } - - apen->intr_mask = 0; - intr_src = fd.intr_src_count; - intr_off = intr_count % 8; - for (ii = intr_off; - ii < (intr_src + intr_off); - ii++) { - apen->intr_mask |= 1 << ii; - } - - rmi4_data->intr_mask[0] |= apen->intr_mask; - - addr = rmi4_data->f01_ctrl_base_addr + 1; - - retval = synaptics_rmi4_reg_write(rmi4_data, - addr, - &(rmi4_data->intr_mask[0]), - sizeof(rmi4_data->intr_mask[0])); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to set interrupt enable bit\n", - __func__); - return retval; - } - - return 0; -} - -static void synaptics_rmi4_apen_attn(struct synaptics_rmi4_data *rmi4_data, - unsigned char intr_mask) -{ - if (!apen) - return; - - if (apen->intr_mask & intr_mask) - apen_report(); - - return; -} - -static int synaptics_rmi4_apen_init(struct synaptics_rmi4_data *rmi4_data) -{ - int retval; - - if (apen) { - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Handle already exists\n", - __func__); - return 0; - } - - apen = kzalloc(sizeof(*apen), GFP_KERNEL); - if (!apen) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for apen\n", - __func__); - retval = -ENOMEM; - goto exit; - } - - apen->apen_data = kzalloc(sizeof(*(apen->apen_data)), GFP_KERNEL); - if (!apen->apen_data) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for apen_data\n", - __func__); - retval = -ENOMEM; - goto exit_free_apen; - } - - apen->rmi4_data = rmi4_data; - - retval = apen_scan_pdt(); - if (retval < 0) - goto exit_free_apen_data; - - apen->apen_dev = input_allocate_device(); - if (apen->apen_dev == NULL) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to allocate active pen device\n", - __func__); - retval = -ENOMEM; - goto exit_free_apen_data; - } - - apen->apen_dev->name = ACTIVE_PEN_DRIVER_NAME; - apen->apen_dev->phys = APEN_PHYS_NAME; - apen->apen_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT; - apen->apen_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION; - apen->apen_dev->dev.parent = rmi4_data->pdev->dev.parent; - input_set_drvdata(apen->apen_dev, rmi4_data); - - set_bit(EV_KEY, apen->apen_dev->evbit); - set_bit(EV_ABS, apen->apen_dev->evbit); - set_bit(BTN_TOUCH, apen->apen_dev->keybit); - set_bit(BTN_TOOL_PEN, apen->apen_dev->keybit); - set_bit(BTN_TOOL_RUBBER, apen->apen_dev->keybit); - set_bit(BTN_STYLUS, apen->apen_dev->keybit); -#ifdef INPUT_PROP_DIRECT - set_bit(INPUT_PROP_DIRECT, apen->apen_dev->propbit); -#endif - - apen_set_params(); - - retval = input_register_device(apen->apen_dev); - if (retval) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to register active pen device\n", - __func__); - goto exit_free_input_device; - } - - return 0; - -exit_free_input_device: - input_free_device(apen->apen_dev); - -exit_free_apen_data: - kfree(apen->apen_data); - -exit_free_apen: - kfree(apen); - apen = NULL; - -exit: - return retval; -} - -static void synaptics_rmi4_apen_remove(struct synaptics_rmi4_data *rmi4_data) -{ - if (!apen) - goto exit; - - input_unregister_device(apen->apen_dev); - kfree(apen->apen_data); - kfree(apen); - apen = NULL; - -exit: - complete(&apen_remove_complete); - - return; -} - -static void synaptics_rmi4_apen_reset(struct synaptics_rmi4_data *rmi4_data) -{ - if (!apen) { - synaptics_rmi4_apen_init(rmi4_data); - return; - } - - apen_lift(); - - apen_scan_pdt(); - - return; -} - -static void synaptics_rmi4_apen_reinit(struct synaptics_rmi4_data *rmi4_data) -{ - if (!apen) - return; - - apen_lift(); - - return; -} - -static void synaptics_rmi4_apen_e_suspend(struct synaptics_rmi4_data *rmi4_data) -{ - if (!apen) - return; - - apen_lift(); - - return; -} - -static void synaptics_rmi4_apen_suspend(struct synaptics_rmi4_data *rmi4_data) -{ - if (!apen) - return; - - apen_lift(); - - return; -} - -static struct synaptics_rmi4_exp_fn active_pen_module = { - .fn_type = RMI_ACTIVE_PEN, - .init = synaptics_rmi4_apen_init, - .remove = synaptics_rmi4_apen_remove, - .reset = synaptics_rmi4_apen_reset, - .reinit = synaptics_rmi4_apen_reinit, - .early_suspend = synaptics_rmi4_apen_e_suspend, - .suspend = synaptics_rmi4_apen_suspend, - .resume = NULL, - .late_resume = NULL, - .attn = synaptics_rmi4_apen_attn, -}; - -static int __init rmi4_active_pen_module_init(void) -{ - synaptics_rmi4_new_function(&active_pen_module, true); - - return 0; -} - -static void __exit rmi4_active_pen_module_exit(void) -{ - synaptics_rmi4_new_function(&active_pen_module, false); - - wait_for_completion(&apen_remove_complete); - - return; -} - -module_init(rmi4_active_pen_module_init); -module_exit(rmi4_active_pen_module_exit); - -MODULE_AUTHOR("Synaptics, Inc."); -MODULE_DESCRIPTION("Synaptics DSX Active Pen Module"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c deleted file mode 100644 index d358f329e7a8..000000000000 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c +++ /dev/null @@ -1,4711 +0,0 @@ -/* - * Synaptics DSX touchscreen driver - * - * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved. - * - * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com> - * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com> - * - * 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. - * - * 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. - * - * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS - * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, - * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS. - * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION - * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED - * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES - * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' - * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. - * DOLLARS. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/input.h> -#include <linux/gpio.h> -#include <linux/platform_device.h> -#include <linux/regulator/consumer.h> -#include <linux/input/synaptics_dsx_v2_6.h> -#include "synaptics_dsx_core.h" -#ifdef KERNEL_ABOVE_2_6_38 -#include <linux/input/mt.h> -#endif - -#define INPUT_PHYS_NAME "synaptics_dsx/touch_input" -#define STYLUS_PHYS_NAME "synaptics_dsx/stylus" - -#define VIRTUAL_KEY_MAP_FILE_NAME "virtualkeys." PLATFORM_DRIVER_NAME - -#ifdef KERNEL_ABOVE_2_6_38 -#define TYPE_B_PROTOCOL -#endif - -#define WAKEUP_GESTURE false - -#define NO_0D_WHILE_2D -#define REPORT_2D_Z -#define REPORT_2D_W -/* -#define REPORT_2D_PRESSURE -*/ - -#define F12_DATA_15_WORKAROUND - -#define IGNORE_FN_INIT_FAILURE - -#define FB_READY_RESET -#define FB_READY_WAIT_MS 100 -#define FB_READY_TIMEOUT_S 30 - -#define RPT_TYPE (1 << 0) -#define RPT_X_LSB (1 << 1) -#define RPT_X_MSB (1 << 2) -#define RPT_Y_LSB (1 << 3) -#define RPT_Y_MSB (1 << 4) -#define RPT_Z (1 << 5) -#define RPT_WX (1 << 6) -#define RPT_WY (1 << 7) -#define RPT_DEFAULT (RPT_TYPE | RPT_X_LSB | RPT_X_MSB | RPT_Y_LSB | RPT_Y_MSB) - -#define REBUILD_WORK_DELAY_MS 500 /* ms */ - -#define EXP_FN_WORK_DELAY_MS 500 /* ms */ -#define MAX_F11_TOUCH_WIDTH 15 -#define MAX_F12_TOUCH_WIDTH 255 -#define MAX_F12_TOUCH_PRESSURE 255 - -#define CHECK_STATUS_TIMEOUT_MS 100 - -#define F01_STD_QUERY_LEN 21 -#define F01_BUID_ID_OFFSET 18 - -#define STATUS_NO_ERROR 0x00 -#define STATUS_RESET_OCCURRED 0x01 -#define STATUS_INVALID_CONFIG 0x02 -#define STATUS_DEVICE_FAILURE 0x03 -#define STATUS_CONFIG_CRC_FAILURE 0x04 -#define STATUS_FIRMWARE_CRC_FAILURE 0x05 -#define STATUS_CRC_IN_PROGRESS 0x06 - -#define NORMAL_OPERATION (0 << 0) -#define SENSOR_SLEEP (1 << 0) -#define NO_SLEEP_OFF (0 << 2) -#define NO_SLEEP_ON (1 << 2) -#define CONFIGURED (1 << 7) - -#define F11_CONTINUOUS_MODE 0x00 -#define F11_WAKEUP_GESTURE_MODE 0x04 -#define F12_CONTINUOUS_MODE 0x00 -#define F12_WAKEUP_GESTURE_MODE 0x02 -#define F12_UDG_DETECT 0x0f - -static int synaptics_rmi4_check_status(struct synaptics_rmi4_data *rmi4_data, - bool *was_in_bl_mode); -static int synaptics_rmi4_free_fingers(struct synaptics_rmi4_data *rmi4_data); -static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data, - bool rebuild); - -#ifdef CONFIG_FB -static void synaptics_rmi4_fb_notify_resume_work(struct work_struct *work); -static int synaptics_rmi4_fb_notifier_cb(struct notifier_block *self, - unsigned long event, void *data); -#endif - -#ifdef CONFIG_HAS_EARLYSUSPEND -#ifndef CONFIG_FB -#define USE_EARLYSUSPEND -#endif -#endif - -#ifdef USE_EARLYSUSPEND -static void synaptics_rmi4_early_suspend(struct early_suspend *h); - -static void synaptics_rmi4_late_resume(struct early_suspend *h); -#endif - -static int synaptics_rmi4_suspend(struct device *dev); - -static int synaptics_rmi4_resume(struct device *dev); - -static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t synaptics_rmi4_f01_productinfo_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t synaptics_rmi4_f01_buildid_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t synaptics_rmi4_f01_flashprog_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t synaptics_rmi4_0dbutton_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t synaptics_rmi4_0dbutton_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t synaptics_rmi4_suspend_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t synaptics_rmi4_wake_gesture_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t synaptics_rmi4_wake_gesture_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t synaptics_rmi4_virtual_key_map_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf); - -#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26) -static ssize_t synaptics_rmi4_secure_touch_enable_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t synaptics_rmi4_secure_touch_enable_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t synaptics_rmi4_secure_touch_show(struct device *dev, - struct device_attribute *attr, char *buf); -#endif - -static irqreturn_t synaptics_rmi4_irq(int irq, void *data); - -struct synaptics_rmi4_f01_device_status { - union { - struct { - unsigned char status_code:4; - unsigned char reserved:2; - unsigned char flash_prog:1; - unsigned char unconfigured:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct synaptics_rmi4_f11_query_0_5 { - union { - struct { - /* query 0 */ - unsigned char f11_query0_b0__2:3; - unsigned char has_query_9:1; - unsigned char has_query_11:1; - unsigned char has_query_12:1; - unsigned char has_query_27:1; - unsigned char has_query_28:1; - - /* query 1 */ - unsigned char num_of_fingers:3; - unsigned char has_rel:1; - unsigned char has_abs:1; - unsigned char has_gestures:1; - unsigned char has_sensitibity_adjust:1; - unsigned char f11_query1_b7:1; - - /* query 2 */ - unsigned char num_of_x_electrodes; - - /* query 3 */ - unsigned char num_of_y_electrodes; - - /* query 4 */ - unsigned char max_electrodes:7; - unsigned char f11_query4_b7:1; - - /* query 5 */ - unsigned char abs_data_size:2; - unsigned char has_anchored_finger:1; - unsigned char has_adj_hyst:1; - unsigned char has_dribble:1; - unsigned char has_bending_correction:1; - unsigned char has_large_object_suppression:1; - unsigned char has_jitter_filter:1; - } __packed; - unsigned char data[6]; - }; -}; - -struct synaptics_rmi4_f11_query_7_8 { - union { - struct { - /* query 7 */ - unsigned char has_single_tap:1; - unsigned char has_tap_and_hold:1; - unsigned char has_double_tap:1; - unsigned char has_early_tap:1; - unsigned char has_flick:1; - unsigned char has_press:1; - unsigned char has_pinch:1; - unsigned char has_chiral_scroll:1; - - /* query 8 */ - unsigned char has_palm_detect:1; - unsigned char has_rotate:1; - unsigned char has_touch_shapes:1; - unsigned char has_scroll_zones:1; - unsigned char individual_scroll_zones:1; - unsigned char has_multi_finger_scroll:1; - unsigned char has_multi_finger_scroll_edge_motion:1; - unsigned char has_multi_finger_scroll_inertia:1; - } __packed; - unsigned char data[2]; - }; -}; - -struct synaptics_rmi4_f11_query_9 { - union { - struct { - unsigned char has_pen:1; - unsigned char has_proximity:1; - unsigned char has_large_object_sensitivity:1; - unsigned char has_suppress_on_large_object_detect:1; - unsigned char has_two_pen_thresholds:1; - unsigned char has_contact_geometry:1; - unsigned char has_pen_hover_discrimination:1; - unsigned char has_pen_hover_and_edge_filters:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct synaptics_rmi4_f11_query_12 { - union { - struct { - unsigned char has_small_object_detection:1; - unsigned char has_small_object_detection_tuning:1; - unsigned char has_8bit_w:1; - unsigned char has_2d_adjustable_mapping:1; - unsigned char has_general_information_2:1; - unsigned char has_physical_properties:1; - unsigned char has_finger_limit:1; - unsigned char has_linear_cofficient_2:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct synaptics_rmi4_f11_query_27 { - union { - struct { - unsigned char f11_query27_b0:1; - unsigned char has_pen_position_correction:1; - unsigned char has_pen_jitter_filter_coefficient:1; - unsigned char has_group_decomposition:1; - unsigned char has_wakeup_gesture:1; - unsigned char has_small_finger_correction:1; - unsigned char has_data_37:1; - unsigned char f11_query27_b7:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct synaptics_rmi4_f11_ctrl_6_9 { - union { - struct { - unsigned char sensor_max_x_pos_7_0; - unsigned char sensor_max_x_pos_11_8:4; - unsigned char f11_ctrl7_b4__7:4; - unsigned char sensor_max_y_pos_7_0; - unsigned char sensor_max_y_pos_11_8:4; - unsigned char f11_ctrl9_b4__7:4; - } __packed; - unsigned char data[4]; - }; -}; - -struct synaptics_rmi4_f11_data_1_5 { - union { - struct { - unsigned char x_position_11_4; - unsigned char y_position_11_4; - unsigned char x_position_3_0:4; - unsigned char y_position_3_0:4; - unsigned char wx:4; - unsigned char wy:4; - unsigned char z; - } __packed; - unsigned char data[5]; - }; -}; - -struct synaptics_rmi4_f12_query_5 { - union { - struct { - unsigned char size_of_query6; - struct { - unsigned char ctrl0_is_present:1; - unsigned char ctrl1_is_present:1; - unsigned char ctrl2_is_present:1; - unsigned char ctrl3_is_present:1; - unsigned char ctrl4_is_present:1; - unsigned char ctrl5_is_present:1; - unsigned char ctrl6_is_present:1; - unsigned char ctrl7_is_present:1; - } __packed; - struct { - unsigned char ctrl8_is_present:1; - unsigned char ctrl9_is_present:1; - unsigned char ctrl10_is_present:1; - unsigned char ctrl11_is_present:1; - unsigned char ctrl12_is_present:1; - unsigned char ctrl13_is_present:1; - unsigned char ctrl14_is_present:1; - unsigned char ctrl15_is_present:1; - } __packed; - struct { - unsigned char ctrl16_is_present:1; - unsigned char ctrl17_is_present:1; - unsigned char ctrl18_is_present:1; - unsigned char ctrl19_is_present:1; - unsigned char ctrl20_is_present:1; - unsigned char ctrl21_is_present:1; - unsigned char ctrl22_is_present:1; - unsigned char ctrl23_is_present:1; - } __packed; - struct { - unsigned char ctrl24_is_present:1; - unsigned char ctrl25_is_present:1; - unsigned char ctrl26_is_present:1; - unsigned char ctrl27_is_present:1; - unsigned char ctrl28_is_present:1; - unsigned char ctrl29_is_present:1; - unsigned char ctrl30_is_present:1; - unsigned char ctrl31_is_present:1; - } __packed; - }; - unsigned char data[5]; - }; -}; - -struct synaptics_rmi4_f12_query_8 { - union { - struct { - unsigned char size_of_query9; - struct { - unsigned char data0_is_present:1; - unsigned char data1_is_present:1; - unsigned char data2_is_present:1; - unsigned char data3_is_present:1; - unsigned char data4_is_present:1; - unsigned char data5_is_present:1; - unsigned char data6_is_present:1; - unsigned char data7_is_present:1; - } __packed; - struct { - unsigned char data8_is_present:1; - unsigned char data9_is_present:1; - unsigned char data10_is_present:1; - unsigned char data11_is_present:1; - unsigned char data12_is_present:1; - unsigned char data13_is_present:1; - unsigned char data14_is_present:1; - unsigned char data15_is_present:1; - } __packed; - struct { - unsigned char data16_is_present:1; - unsigned char data17_is_present:1; - unsigned char data18_is_present:1; - unsigned char data19_is_present:1; - unsigned char data20_is_present:1; - unsigned char data21_is_present:1; - unsigned char data22_is_present:1; - unsigned char data23_is_present:1; - } __packed; - }; - unsigned char data[4]; - }; -}; - -struct synaptics_rmi4_f12_ctrl_8 { - union { - struct { - unsigned char max_x_coord_lsb; - unsigned char max_x_coord_msb; - unsigned char max_y_coord_lsb; - unsigned char max_y_coord_msb; - unsigned char rx_pitch_lsb; - unsigned char rx_pitch_msb; - unsigned char tx_pitch_lsb; - unsigned char tx_pitch_msb; - unsigned char low_rx_clip; - unsigned char high_rx_clip; - unsigned char low_tx_clip; - unsigned char high_tx_clip; - unsigned char num_of_rx; - unsigned char num_of_tx; - }; - unsigned char data[14]; - }; -}; - -struct synaptics_rmi4_f12_ctrl_23 { - union { - struct { - unsigned char finger_enable:1; - unsigned char active_stylus_enable:1; - unsigned char palm_enable:1; - unsigned char unclassified_object_enable:1; - unsigned char hovering_finger_enable:1; - unsigned char gloved_finger_enable:1; - unsigned char f12_ctr23_00_b6__7:2; - unsigned char max_reported_objects; - unsigned char f12_ctr23_02_b0:1; - unsigned char report_active_stylus_as_finger:1; - unsigned char report_palm_as_finger:1; - unsigned char report_unclassified_object_as_finger:1; - unsigned char report_hovering_finger_as_finger:1; - unsigned char report_gloved_finger_as_finger:1; - unsigned char report_narrow_object_swipe_as_finger:1; - unsigned char report_handedge_as_finger:1; - unsigned char cover_enable:1; - unsigned char stylus_enable:1; - unsigned char eraser_enable:1; - unsigned char small_object_enable:1; - unsigned char f12_ctr23_03_b4__7:4; - unsigned char report_cover_as_finger:1; - unsigned char report_stylus_as_finger:1; - unsigned char report_eraser_as_finger:1; - unsigned char report_small_object_as_finger:1; - unsigned char f12_ctr23_04_b4__7:4; - }; - unsigned char data[5]; - }; -}; - -struct synaptics_rmi4_f12_ctrl_31 { - union { - struct { - unsigned char max_x_coord_lsb; - unsigned char max_x_coord_msb; - unsigned char max_y_coord_lsb; - unsigned char max_y_coord_msb; - unsigned char rx_pitch_lsb; - unsigned char rx_pitch_msb; - unsigned char rx_clip_low; - unsigned char rx_clip_high; - unsigned char wedge_clip_low; - unsigned char wedge_clip_high; - unsigned char num_of_p; - unsigned char num_of_q; - }; - unsigned char data[12]; - }; -}; - -struct synaptics_rmi4_f12_finger_data { - unsigned char object_type_and_status; - unsigned char x_lsb; - unsigned char x_msb; - unsigned char y_lsb; - unsigned char y_msb; -#ifdef REPORT_2D_Z - unsigned char z; -#endif -#ifdef REPORT_2D_W - unsigned char wx; - unsigned char wy; -#endif -}; - -struct synaptics_rmi4_f1a_query { - union { - struct { - unsigned char max_button_count:3; - unsigned char f1a_query0_b3__4:2; - unsigned char has_query4:1; - unsigned char has_query3:1; - unsigned char has_query2:1; - unsigned char has_general_control:1; - unsigned char has_interrupt_enable:1; - unsigned char has_multibutton_select:1; - unsigned char has_tx_rx_map:1; - unsigned char has_perbutton_threshold:1; - unsigned char has_release_threshold:1; - unsigned char has_strongestbtn_hysteresis:1; - unsigned char has_filter_strength:1; - } __packed; - unsigned char data[2]; - }; -}; - -struct synaptics_rmi4_f1a_query_4 { - union { - struct { - unsigned char has_ctrl19:1; - unsigned char f1a_query4_b1__4:4; - unsigned char has_ctrl24:1; - unsigned char f1a_query4_b6__7:2; - } __packed; - unsigned char data[1]; - }; -}; - -struct synaptics_rmi4_f1a_control_0 { - union { - struct { - unsigned char multibutton_report:2; - unsigned char filter_mode:2; - unsigned char reserved:4; - } __packed; - unsigned char data[1]; - }; -}; - -struct synaptics_rmi4_f1a_control { - struct synaptics_rmi4_f1a_control_0 general_control; - unsigned char button_int_enable; - unsigned char multi_button; - unsigned char *txrx_map; - unsigned char *button_threshold; - unsigned char button_release_threshold; - unsigned char strongest_button_hysteresis; - unsigned char filter_strength; -}; - -struct synaptics_rmi4_f1a_handle { - int button_bitmask_size; - unsigned char max_count; - unsigned char valid_button_count; - unsigned char *button_data_buffer; - unsigned char *button_map; - struct synaptics_rmi4_f1a_query button_query; - struct synaptics_rmi4_f1a_control button_control; -}; - -struct synaptics_rmi4_exp_fhandler { - struct synaptics_rmi4_exp_fn *exp_fn; - bool insert; - bool remove; - struct list_head link; -}; - -struct synaptics_rmi4_exp_fn_data { - bool initialized; - bool queue_work; - struct mutex mutex; - struct list_head list; - struct delayed_work work; - struct workqueue_struct *workqueue; - struct synaptics_rmi4_data *rmi4_data; -}; - -static struct synaptics_rmi4_exp_fn_data exp_data; - -static struct synaptics_dsx_button_map *vir_button_map; - -static struct device_attribute attrs[] = { - __ATTR(reset, S_IWUSR | S_IWGRP, - NULL, - synaptics_rmi4_f01_reset_store), - __ATTR(productinfo, S_IRUGO, - synaptics_rmi4_f01_productinfo_show, - NULL), - __ATTR(buildid, S_IRUGO, - synaptics_rmi4_f01_buildid_show, - NULL), - __ATTR(flashprog, S_IRUGO, - synaptics_rmi4_f01_flashprog_show, - NULL), - __ATTR(0dbutton, (S_IRUGO | S_IWUSR | S_IWGRP), - synaptics_rmi4_0dbutton_show, - synaptics_rmi4_0dbutton_store), - __ATTR(suspend, S_IWUSR | S_IWGRP, - NULL, - synaptics_rmi4_suspend_store), - __ATTR(wake_gesture, (S_IRUGO | S_IWUSR | S_IWGRP), - synaptics_rmi4_wake_gesture_show, - synaptics_rmi4_wake_gesture_store), -#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26) - __ATTR(secure_touch_enable, (S_IRUGO | S_IWUSR | S_IWGRP), - synaptics_rmi4_secure_touch_enable_show, - synaptics_rmi4_secure_touch_enable_store), - __ATTR(secure_touch, S_IRUGO, - synaptics_rmi4_secure_touch_show, - NULL), -#endif -}; - -static struct kobj_attribute virtual_key_map_attr = { - .attr = { - .name = VIRTUAL_KEY_MAP_FILE_NAME, - .mode = S_IRUGO, - }, - .show = synaptics_rmi4_virtual_key_map_show, -}; - -#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26) -static void synaptics_secure_touch_init(struct synaptics_rmi4_data *data) -{ - data->st_initialized = 0; - init_completion(&data->st_powerdown); - init_completion(&data->st_irq_processed); - - /* Get clocks */ - data->core_clk = devm_clk_get(data->pdev->dev.parent, "core_clk"); - if (IS_ERR(data->core_clk)) { - dev_warn(data->pdev->dev.parent, - "%s: error on clk_get(core_clk): %ld\n", __func__, - PTR_ERR(data->core_clk)); - data->core_clk = NULL; - } - - data->iface_clk = devm_clk_get(data->pdev->dev.parent, "iface_clk"); - if (IS_ERR(data->iface_clk)) { - dev_warn(data->pdev->dev.parent, - "%s: error on clk_get(iface_clk): %ld\n", __func__, - PTR_ERR(data->iface_clk)); - data->iface_clk = NULL; - } - - data->st_initialized = 1; -} - -static void synaptics_secure_touch_notify(struct synaptics_rmi4_data *rmi4_data) -{ - sysfs_notify(&rmi4_data->input_dev->dev.kobj, NULL, "secure_touch"); -} - -static irqreturn_t synaptics_filter_interrupt( - struct synaptics_rmi4_data *rmi4_data) -{ - if (atomic_read(&rmi4_data->st_enabled)) { - if (atomic_cmpxchg(&rmi4_data->st_pending_irqs, 0, 1) == 0) { - reinit_completion(&rmi4_data->st_irq_processed); - synaptics_secure_touch_notify(rmi4_data); - wait_for_completion_interruptible( - &rmi4_data->st_irq_processed); - } - return IRQ_HANDLED; - } - return IRQ_NONE; -} - -/* - * 'blocking' variable will have value 'true' when we want to prevent the driver - * from accessing the xPU/SMMU protected HW resources while the session is - * active. - */ -static void synaptics_secure_touch_stop(struct synaptics_rmi4_data *rmi4_data, - bool blocking) -{ - if (atomic_read(&rmi4_data->st_enabled)) { - atomic_set(&rmi4_data->st_pending_irqs, -1); - synaptics_secure_touch_notify(rmi4_data); - if (blocking) - wait_for_completion_interruptible( - &rmi4_data->st_powerdown); - } -} - -#else -static void synaptics_secure_touch_init(struct synaptics_rmi4_data *rmi4_data) -{ -} - -static irqreturn_t synaptics_filter_interrupt( - struct synaptics_rmi4_data *rmi4_data) -{ - return IRQ_NONE; -} - -static void synaptics_secure_touch_stop(struct synaptics_rmi4_data *rmi4_data, - bool blocking) -{ -} -#endif - -#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26) -static ssize_t synaptics_rmi4_secure_touch_enable_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); - - return scnprintf(buf, PAGE_SIZE, "%d", - atomic_read(&rmi4_data->st_enabled)); -} -/* - * Accept only "0" and "1" valid values. - * "0" will reset the st_enabled flag, then wake up the reading process and - * the interrupt handler. - * The bus driver is notified via pm_runtime that it is not required to stay - * awake anymore. - * It will also make sure the queue of events is emptied in the controller, - * in case a touch happened in between the secure touch being disabled and - * the local ISR being ungated. - * "1" will set the st_enabled flag and clear the st_pending_irqs flag. - * The bus driver is requested via pm_runtime to stay awake. - */ -static ssize_t synaptics_rmi4_secure_touch_enable_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); - unsigned long value; - int err = 0; - - if (count > 2) - return -EINVAL; - - err = kstrtoul(buf, 10, &value); - if (err != 0) - return err; - - if (!rmi4_data->st_initialized) - return -EIO; - - err = count; - - switch (value) { - case 0: - if (atomic_read(&rmi4_data->st_enabled) == 0) - break; - - synaptics_rmi4_bus_put(rmi4_data); - atomic_set(&rmi4_data->st_enabled, 0); - synaptics_secure_touch_notify(rmi4_data); - complete(&rmi4_data->st_irq_processed); - synaptics_rmi4_irq(rmi4_data->irq, rmi4_data); - complete(&rmi4_data->st_powerdown); - - break; - case 1: - if (atomic_read(&rmi4_data->st_enabled)) { - err = -EBUSY; - break; - } - - synchronize_irq(rmi4_data->irq); - - if (synaptics_rmi4_bus_get(rmi4_data) < 0) { - dev_err( - rmi4_data->pdev->dev.parent, - "synaptics_rmi4_bus_get failed\n"); - err = -EIO; - break; - } - reinit_completion(&rmi4_data->st_powerdown); - reinit_completion(&rmi4_data->st_irq_processed); - atomic_set(&rmi4_data->st_enabled, 1); - atomic_set(&rmi4_data->st_pending_irqs, 0); - break; - default: - dev_err( - rmi4_data->pdev->dev.parent, - "unsupported value: %lu\n", value); - err = -EINVAL; - break; - } - return err; -} - -/* - * This function returns whether there are pending interrupts, or - * other error conditions that need to be signaled to the userspace library, - * according tot he following logic: - * - st_enabled is 0 if secure touch is not enabled, returning -EBADF - * - st_pending_irqs is -1 to signal that secure touch is in being stopped, - * returning -EINVAL - * - st_pending_irqs is 1 to signal that there is a pending irq, returning - * the value "1" to the sysfs read operation - * - st_pending_irqs is 0 (only remaining case left) if the pending interrupt - * has been processed, so the interrupt handler can be allowed to continue. - */ -static ssize_t synaptics_rmi4_secure_touch_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); - int val = 0; - - if (atomic_read(&rmi4_data->st_enabled) == 0) - return -EBADF; - - if (atomic_cmpxchg(&rmi4_data->st_pending_irqs, -1, 0) == -1) - return -EINVAL; - - if (atomic_cmpxchg(&rmi4_data->st_pending_irqs, 1, 0) == 1) - val = 1; - else - complete(&rmi4_data->st_irq_processed); - - return scnprintf(buf, PAGE_SIZE, "%u", val); - -} -#endif - -static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned int reset; - struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); - - if (sscanf(buf, "%u", &reset) != 1) - return -EINVAL; - - if (reset != 1) - return -EINVAL; - - retval = synaptics_rmi4_reset_device(rmi4_data, false); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to issue reset command, error = %d\n", - __func__, retval); - return retval; - } - - return count; -} - -static ssize_t synaptics_rmi4_f01_productinfo_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); - - return snprintf(buf, PAGE_SIZE, "0x%02x 0x%02x\n", - (rmi4_data->rmi4_mod_info.product_info[0]), - (rmi4_data->rmi4_mod_info.product_info[1])); -} - -static ssize_t synaptics_rmi4_f01_buildid_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); - - return snprintf(buf, PAGE_SIZE, "%u\n", - rmi4_data->firmware_id); -} - -static ssize_t synaptics_rmi4_f01_flashprog_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int retval; - struct synaptics_rmi4_f01_device_status device_status; - struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); - - retval = synaptics_rmi4_reg_read(rmi4_data, - rmi4_data->f01_data_base_addr, - device_status.data, - sizeof(device_status.data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read device status, error = %d\n", - __func__, retval); - return retval; - } - - return snprintf(buf, PAGE_SIZE, "%u\n", - device_status.flash_prog); -} - -static ssize_t synaptics_rmi4_0dbutton_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); - - return snprintf(buf, PAGE_SIZE, "%u\n", - rmi4_data->button_0d_enabled); -} - -static ssize_t synaptics_rmi4_0dbutton_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned int input; - unsigned char ii; - unsigned char intr_enable; - struct synaptics_rmi4_fn *fhandler; - struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); - struct synaptics_rmi4_device_info *rmi; - - rmi = &(rmi4_data->rmi4_mod_info); - - if (sscanf(buf, "%u", &input) != 1) - return -EINVAL; - - input = input > 0 ? 1 : 0; - - if (rmi4_data->button_0d_enabled == input) - return count; - - if (list_empty(&rmi->support_fn_list)) - return -ENODEV; - - list_for_each_entry(fhandler, &rmi->support_fn_list, link) { - if (fhandler->fn_number == SYNAPTICS_RMI4_F1A) { - ii = fhandler->intr_reg_num; - - retval = synaptics_rmi4_reg_read(rmi4_data, - rmi4_data->f01_ctrl_base_addr + 1 + ii, - &intr_enable, - sizeof(intr_enable)); - if (retval < 0) - return retval; - - if (input == 1) - intr_enable |= fhandler->intr_mask; - else - intr_enable &= ~fhandler->intr_mask; - - retval = synaptics_rmi4_reg_write(rmi4_data, - rmi4_data->f01_ctrl_base_addr + 1 + ii, - &intr_enable, - sizeof(intr_enable)); - if (retval < 0) - return retval; - } - } - - rmi4_data->button_0d_enabled = input; - - return count; -} - -static ssize_t synaptics_rmi4_suspend_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - unsigned int input; - - if (sscanf(buf, "%u", &input) != 1) - return -EINVAL; - - if (input == 1) - synaptics_rmi4_suspend(dev); - else if (input == 0) - synaptics_rmi4_resume(dev); - else - return -EINVAL; - - return count; -} - -static ssize_t synaptics_rmi4_wake_gesture_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); - - return snprintf(buf, PAGE_SIZE, "%u\n", - rmi4_data->enable_wakeup_gesture); -} - -static ssize_t synaptics_rmi4_wake_gesture_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - unsigned int input; - struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); - - if (sscanf(buf, "%u", &input) != 1) - return -EINVAL; - - input = input > 0 ? 1 : 0; - - if (rmi4_data->f11_wakeup_gesture || rmi4_data->f12_wakeup_gesture) - rmi4_data->enable_wakeup_gesture = input; - - return count; -} - -static ssize_t synaptics_rmi4_virtual_key_map_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - int ii; - int cnt; - int count = 0; - - for (ii = 0; ii < vir_button_map->nbuttons; ii++) { - cnt = snprintf(buf, PAGE_SIZE - count, "0x01:%d:%d:%d:%d:%d\n", - vir_button_map->map[ii * 5 + 0], - vir_button_map->map[ii * 5 + 1], - vir_button_map->map[ii * 5 + 2], - vir_button_map->map[ii * 5 + 3], - vir_button_map->map[ii * 5 + 4]); - buf += cnt; - count += cnt; - } - - return count; -} - -static int synaptics_rmi4_f11_abs_report(struct synaptics_rmi4_data *rmi4_data, - struct synaptics_rmi4_fn *fhandler) -{ - int retval; - unsigned char touch_count = 0; /* number of touch points */ - unsigned char reg_index; - unsigned char finger; - unsigned char fingers_supported; - unsigned char num_of_finger_status_regs; - unsigned char finger_shift; - unsigned char finger_status; - unsigned char finger_status_reg[3]; - unsigned char detected_gestures; - unsigned short data_addr; - unsigned short data_offset; - int x; - int y; - int wx; - int wy; - int temp; - struct synaptics_rmi4_f11_data_1_5 data; - struct synaptics_rmi4_f11_extra_data *extra_data; - - /* - * The number of finger status registers is determined by the - * maximum number of fingers supported - 2 bits per finger. So - * the number of finger status registers to read is: - * register_count = ceil(max_num_of_fingers / 4) - */ - fingers_supported = fhandler->num_of_data_points; - num_of_finger_status_regs = (fingers_supported + 3) / 4; - data_addr = fhandler->full_addr.data_base; - - extra_data = (struct synaptics_rmi4_f11_extra_data *)fhandler->extra; - - if (rmi4_data->suspend && rmi4_data->enable_wakeup_gesture) { - retval = synaptics_rmi4_reg_read(rmi4_data, - data_addr + extra_data->data38_offset, - &detected_gestures, - sizeof(detected_gestures)); - if (retval < 0) - return 0; - - if (detected_gestures) { - input_report_key(rmi4_data->input_dev, KEY_WAKEUP, 1); - input_sync(rmi4_data->input_dev); - input_report_key(rmi4_data->input_dev, KEY_WAKEUP, 0); - input_sync(rmi4_data->input_dev); - rmi4_data->suspend = false; - } - - return 0; - } - - retval = synaptics_rmi4_reg_read(rmi4_data, - data_addr, - finger_status_reg, - num_of_finger_status_regs); - if (retval < 0) - return 0; - - mutex_lock(&(rmi4_data->rmi4_report_mutex)); - - for (finger = 0; finger < fingers_supported; finger++) { - reg_index = finger / 4; - finger_shift = (finger % 4) * 2; - finger_status = (finger_status_reg[reg_index] >> finger_shift) - & MASK_2BIT; - - /* - * Each 2-bit finger status field represents the following: - * 00 = finger not present - * 01 = finger present and data accurate - * 10 = finger present but data may be inaccurate - * 11 = reserved - */ -#ifdef TYPE_B_PROTOCOL - input_mt_slot(rmi4_data->input_dev, finger); - input_mt_report_slot_state(rmi4_data->input_dev, - MT_TOOL_FINGER, finger_status); -#endif - - if (finger_status) { - data_offset = data_addr + - num_of_finger_status_regs + - (finger * sizeof(data.data)); - retval = synaptics_rmi4_reg_read(rmi4_data, - data_offset, - data.data, - sizeof(data.data)); - if (retval < 0) { - touch_count = 0; - goto exit; - } - - x = (data.x_position_11_4 << 4) | data.x_position_3_0; - y = (data.y_position_11_4 << 4) | data.y_position_3_0; - wx = data.wx; - wy = data.wy; - - if (rmi4_data->hw_if->board_data->swap_axes) { - temp = x; - x = y; - y = temp; - temp = wx; - wx = wy; - wy = temp; - } - - if (rmi4_data->hw_if->board_data->x_flip) - x = rmi4_data->sensor_max_x - x; - if (rmi4_data->hw_if->board_data->y_flip) - y = rmi4_data->sensor_max_y - y; - - input_report_key(rmi4_data->input_dev, - BTN_TOUCH, 1); - input_report_key(rmi4_data->input_dev, - BTN_TOOL_FINGER, 1); - input_report_abs(rmi4_data->input_dev, - ABS_MT_POSITION_X, x); - input_report_abs(rmi4_data->input_dev, - ABS_MT_POSITION_Y, y); -#ifdef REPORT_2D_W - input_report_abs(rmi4_data->input_dev, - ABS_MT_TOUCH_MAJOR, max(wx, wy)); - input_report_abs(rmi4_data->input_dev, - ABS_MT_TOUCH_MINOR, min(wx, wy)); -#endif -#ifndef TYPE_B_PROTOCOL - input_mt_sync(rmi4_data->input_dev); -#endif - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Finger %d: status = 0x%02x, x = %d, y = %d, wx = %d, wy = %d\n", - __func__, finger, - finger_status, - x, y, wx, wy); - - touch_count++; - } - } - - if (touch_count == 0) { - input_report_key(rmi4_data->input_dev, - BTN_TOUCH, 0); - input_report_key(rmi4_data->input_dev, - BTN_TOOL_FINGER, 0); -#ifndef TYPE_B_PROTOCOL - input_mt_sync(rmi4_data->input_dev); -#endif - } - - input_sync(rmi4_data->input_dev); - -exit: - mutex_unlock(&(rmi4_data->rmi4_report_mutex)); - - return touch_count; -} - -static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data, - struct synaptics_rmi4_fn *fhandler) -{ - int retval; - unsigned char touch_count = 0; /* number of touch points */ - unsigned char index; - unsigned char finger; - unsigned char fingers_to_process; - unsigned char finger_status; - unsigned char size_of_2d_data; - unsigned char gesture_type; - unsigned short data_addr; - int x; - int y; - int wx; - int wy; - int temp; -#ifdef REPORT_2D_PRESSURE - int pressure; -#endif - struct synaptics_rmi4_f12_extra_data *extra_data; - struct synaptics_rmi4_f12_finger_data *data; - struct synaptics_rmi4_f12_finger_data *finger_data; - static unsigned char finger_presence; - static unsigned char stylus_presence; -#ifdef F12_DATA_15_WORKAROUND - static unsigned char objects_already_present; -#endif - - fingers_to_process = fhandler->num_of_data_points; - data_addr = fhandler->full_addr.data_base; - extra_data = (struct synaptics_rmi4_f12_extra_data *)fhandler->extra; - size_of_2d_data = sizeof(struct synaptics_rmi4_f12_finger_data); - - if (rmi4_data->suspend && rmi4_data->enable_wakeup_gesture) { - retval = synaptics_rmi4_reg_read(rmi4_data, - data_addr + extra_data->data4_offset, - rmi4_data->gesture_detection, - sizeof(rmi4_data->gesture_detection)); - if (retval < 0) - return 0; - - gesture_type = rmi4_data->gesture_detection[0]; - - if (gesture_type && gesture_type != F12_UDG_DETECT) { - input_report_key(rmi4_data->input_dev, KEY_WAKEUP, 1); - input_sync(rmi4_data->input_dev); - input_report_key(rmi4_data->input_dev, KEY_WAKEUP, 0); - input_sync(rmi4_data->input_dev); - rmi4_data->suspend = false; - } - - return 0; - } - - /* Determine the total number of fingers to process */ - if (extra_data->data15_size) { - retval = synaptics_rmi4_reg_read(rmi4_data, - data_addr + extra_data->data15_offset, - extra_data->data15_data, - extra_data->data15_size); - if (retval < 0) - return 0; - - /* Start checking from the highest bit */ - index = extra_data->data15_size - 1; /* Highest byte */ - finger = (fingers_to_process - 1) % 8; /* Highest bit */ - do { - if (extra_data->data15_data[index] & (1 << finger)) - break; - - if (finger) { - finger--; - } else if (index > 0) { - index--; /* Move to the next lower byte */ - finger = 7; - } - - fingers_to_process--; - } while (fingers_to_process); - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Number of fingers to process = %d\n", - __func__, fingers_to_process); - } - -#ifdef F12_DATA_15_WORKAROUND - fingers_to_process = max(fingers_to_process, objects_already_present); -#endif - - if (!fingers_to_process) { - synaptics_rmi4_free_fingers(rmi4_data); - finger_presence = 0; - stylus_presence = 0; - return 0; - } - - retval = synaptics_rmi4_reg_read(rmi4_data, - data_addr + extra_data->data1_offset, - (unsigned char *)fhandler->data, - fingers_to_process * size_of_2d_data); - if (retval < 0) - return 0; - - data = (struct synaptics_rmi4_f12_finger_data *)fhandler->data; - -#ifdef REPORT_2D_PRESSURE - if (rmi4_data->report_pressure) { - retval = synaptics_rmi4_reg_read(rmi4_data, - data_addr + extra_data->data23_offset, - extra_data->data23_data, - fingers_to_process); - if (retval < 0) - return 0; - } -#endif - - mutex_lock(&(rmi4_data->rmi4_report_mutex)); - - for (finger = 0; finger < fingers_to_process; finger++) { - finger_data = data + finger; - finger_status = finger_data->object_type_and_status; - -#ifdef F12_DATA_15_WORKAROUND - objects_already_present = finger + 1; -#endif - - x = (finger_data->x_msb << 8) | (finger_data->x_lsb); - y = (finger_data->y_msb << 8) | (finger_data->y_lsb); -#ifdef REPORT_2D_W - wx = finger_data->wx; - wy = finger_data->wy; -#endif - - if (rmi4_data->hw_if->board_data->swap_axes) { - temp = x; - x = y; - y = temp; - temp = wx; - wx = wy; - wy = temp; - } - - if (rmi4_data->hw_if->board_data->x_flip) - x = rmi4_data->sensor_max_x - x; - if (rmi4_data->hw_if->board_data->y_flip) - y = rmi4_data->sensor_max_y - y; - - switch (finger_status) { - case F12_FINGER_STATUS: - case F12_GLOVED_FINGER_STATUS: - /* Stylus has priority over fingers */ - if (stylus_presence) - break; -#ifdef TYPE_B_PROTOCOL - input_mt_slot(rmi4_data->input_dev, finger); - input_mt_report_slot_state(rmi4_data->input_dev, - MT_TOOL_FINGER, 1); -#endif - - input_report_key(rmi4_data->input_dev, - BTN_TOUCH, 1); - input_report_key(rmi4_data->input_dev, - BTN_TOOL_FINGER, 1); - input_report_abs(rmi4_data->input_dev, - ABS_MT_POSITION_X, x); - input_report_abs(rmi4_data->input_dev, - ABS_MT_POSITION_Y, y); -#ifdef REPORT_2D_W - if (rmi4_data->wedge_sensor) { - input_report_abs(rmi4_data->input_dev, - ABS_MT_TOUCH_MAJOR, wx); - input_report_abs(rmi4_data->input_dev, - ABS_MT_TOUCH_MINOR, wx); - } else { - input_report_abs(rmi4_data->input_dev, - ABS_MT_TOUCH_MAJOR, - max(wx, wy)); - input_report_abs(rmi4_data->input_dev, - ABS_MT_TOUCH_MINOR, - min(wx, wy)); - } -#endif -#ifdef REPORT_2D_PRESSURE - if (rmi4_data->report_pressure) { - pressure = extra_data->data23_data[finger]; - input_report_abs(rmi4_data->input_dev, - ABS_MT_PRESSURE, pressure); - } -#endif -#ifndef TYPE_B_PROTOCOL - input_mt_sync(rmi4_data->input_dev); -#endif - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Finger %d: status = 0x%02x, x = %d, y = %d, wx = %d, wy = %d\n", - __func__, finger, - finger_status, - x, y, wx, wy); - - finger_presence = 1; - touch_count++; - break; - case F12_PALM_STATUS: - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Finger %d: x = %d, y = %d, wx = %d, wy = %d\n", - __func__, finger, - x, y, wx, wy); - break; - case F12_STYLUS_STATUS: - case F12_ERASER_STATUS: - if (!rmi4_data->stylus_enable) - break; - /* Stylus has priority over fingers */ - if (finger_presence) { - mutex_unlock(&(rmi4_data->rmi4_report_mutex)); - synaptics_rmi4_free_fingers(rmi4_data); - mutex_lock(&(rmi4_data->rmi4_report_mutex)); - finger_presence = 0; - } - if (stylus_presence) {/* Allow one stylus at a timee */ - if (finger + 1 != stylus_presence) - break; - } - input_report_key(rmi4_data->stylus_dev, - BTN_TOUCH, 1); - if (finger_status == F12_STYLUS_STATUS) { - input_report_key(rmi4_data->stylus_dev, - BTN_TOOL_PEN, 1); - } else { - input_report_key(rmi4_data->stylus_dev, - BTN_TOOL_RUBBER, 1); - } - input_report_abs(rmi4_data->stylus_dev, - ABS_X, x); - input_report_abs(rmi4_data->stylus_dev, - ABS_Y, y); - input_sync(rmi4_data->stylus_dev); - - stylus_presence = finger + 1; - touch_count++; - break; - default: -#ifdef TYPE_B_PROTOCOL - input_mt_slot(rmi4_data->input_dev, finger); - input_mt_report_slot_state(rmi4_data->input_dev, - MT_TOOL_FINGER, 0); -#endif - break; - } - } - - if (touch_count == 0) { - finger_presence = 0; -#ifdef F12_DATA_15_WORKAROUND - objects_already_present = 0; -#endif - input_report_key(rmi4_data->input_dev, - BTN_TOUCH, 0); - input_report_key(rmi4_data->input_dev, - BTN_TOOL_FINGER, 0); -#ifndef TYPE_B_PROTOCOL - input_mt_sync(rmi4_data->input_dev); -#endif - - if (rmi4_data->stylus_enable) { - stylus_presence = 0; - input_report_key(rmi4_data->stylus_dev, - BTN_TOUCH, 0); - input_report_key(rmi4_data->stylus_dev, - BTN_TOOL_PEN, 0); - if (rmi4_data->eraser_enable) { - input_report_key(rmi4_data->stylus_dev, - BTN_TOOL_RUBBER, 0); - } - input_sync(rmi4_data->stylus_dev); - } - } - - input_sync(rmi4_data->input_dev); - - mutex_unlock(&(rmi4_data->rmi4_report_mutex)); - - return touch_count; -} - -static void synaptics_rmi4_f1a_report(struct synaptics_rmi4_data *rmi4_data, - struct synaptics_rmi4_fn *fhandler) -{ - int retval; - unsigned char touch_count = 0; - unsigned char button; - unsigned char index; - unsigned char shift; - unsigned char status; - unsigned char *data; - unsigned short data_addr = fhandler->full_addr.data_base; - struct synaptics_rmi4_f1a_handle *f1a = fhandler->data; - static unsigned char do_once = 1; - static bool current_status[MAX_NUMBER_OF_BUTTONS]; -#ifdef NO_0D_WHILE_2D - static bool before_2d_status[MAX_NUMBER_OF_BUTTONS]; - static bool while_2d_status[MAX_NUMBER_OF_BUTTONS]; -#endif - - if (do_once) { - memset(current_status, 0, sizeof(current_status)); -#ifdef NO_0D_WHILE_2D - memset(before_2d_status, 0, sizeof(before_2d_status)); - memset(while_2d_status, 0, sizeof(while_2d_status)); -#endif - do_once = 0; - } - - retval = synaptics_rmi4_reg_read(rmi4_data, - data_addr, - f1a->button_data_buffer, - f1a->button_bitmask_size); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read button data registers\n", - __func__); - return; - } - - data = f1a->button_data_buffer; - - mutex_lock(&(rmi4_data->rmi4_report_mutex)); - - for (button = 0; button < f1a->valid_button_count; button++) { - index = button / 8; - shift = button % 8; - status = ((data[index] >> shift) & MASK_1BIT); - - if (current_status[button] == status) - continue; - else - current_status[button] = status; - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Button %d (code %d) ->%d\n", - __func__, button, - f1a->button_map[button], - status); -#ifdef NO_0D_WHILE_2D - if (rmi4_data->fingers_on_2d == false) { - if (status == 1) { - before_2d_status[button] = 1; - } else { - if (while_2d_status[button] == 1) { - while_2d_status[button] = 0; - continue; - } else { - before_2d_status[button] = 0; - } - } - touch_count++; - input_report_key(rmi4_data->input_dev, - f1a->button_map[button], - status); - } else { - if (before_2d_status[button] == 1) { - before_2d_status[button] = 0; - touch_count++; - input_report_key(rmi4_data->input_dev, - f1a->button_map[button], - status); - } else { - if (status == 1) - while_2d_status[button] = 1; - else - while_2d_status[button] = 0; - } - } -#else - touch_count++; - input_report_key(rmi4_data->input_dev, - f1a->button_map[button], - status); -#endif - } - - if (touch_count) - input_sync(rmi4_data->input_dev); - - mutex_unlock(&(rmi4_data->rmi4_report_mutex)); - - return; -} - -static void synaptics_rmi4_report_touch(struct synaptics_rmi4_data *rmi4_data, - struct synaptics_rmi4_fn *fhandler) -{ - unsigned char touch_count_2d; - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Function %02x reporting\n", - __func__, fhandler->fn_number); - - switch (fhandler->fn_number) { - case SYNAPTICS_RMI4_F11: - touch_count_2d = synaptics_rmi4_f11_abs_report(rmi4_data, - fhandler); - - if (touch_count_2d) - rmi4_data->fingers_on_2d = true; - else - rmi4_data->fingers_on_2d = false; - break; - case SYNAPTICS_RMI4_F12: - touch_count_2d = synaptics_rmi4_f12_abs_report(rmi4_data, - fhandler); - - if (touch_count_2d) - rmi4_data->fingers_on_2d = true; - else - rmi4_data->fingers_on_2d = false; - break; - case SYNAPTICS_RMI4_F1A: - synaptics_rmi4_f1a_report(rmi4_data, fhandler); - break; - default: - break; - } - - return; -} - -static void synaptics_rmi4_sensor_report(struct synaptics_rmi4_data *rmi4_data, - bool report) -{ - int retval; - unsigned char data[MAX_INTR_REGISTERS + 1]; - unsigned char *intr = &data[1]; - bool was_in_bl_mode; - struct synaptics_rmi4_f01_device_status status; - struct synaptics_rmi4_fn *fhandler; - struct synaptics_rmi4_exp_fhandler *exp_fhandler; - struct synaptics_rmi4_device_info *rmi; - - rmi = &(rmi4_data->rmi4_mod_info); - - if (rmi4_data->stay_awake) { - msleep(30); - return; - } - - /* - * Get interrupt status information from F01 Data1 register to - * determine the source(s) that are flagging the interrupt. - */ - retval = synaptics_rmi4_reg_read(rmi4_data, - rmi4_data->f01_data_base_addr, - data, - rmi4_data->num_of_intr_regs + 1); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read interrupt status\n", - __func__); - return; - } - - status.data[0] = data[0]; - if (status.status_code == STATUS_CRC_IN_PROGRESS) { - retval = synaptics_rmi4_check_status(rmi4_data, - &was_in_bl_mode); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to check status\n", - __func__); - return; - } - retval = synaptics_rmi4_reg_read(rmi4_data, - rmi4_data->f01_data_base_addr, - status.data, - sizeof(status.data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read device status\n", - __func__); - return; - } - } - if (status.unconfigured && !status.flash_prog) { - pr_notice("%s: spontaneous reset detected\n", __func__); - } - - if (!report) - return; - - /* - * Traverse the function handler list and service the source(s) - * of the interrupt accordingly. - */ - if (!list_empty(&rmi->support_fn_list)) { - list_for_each_entry(fhandler, &rmi->support_fn_list, link) { - if (fhandler->num_of_data_sources) { - if (fhandler->intr_mask & - intr[fhandler->intr_reg_num]) { - synaptics_rmi4_report_touch(rmi4_data, - fhandler); - } - } - } - } - - mutex_lock(&exp_data.mutex); - if (!list_empty(&exp_data.list)) { - list_for_each_entry(exp_fhandler, &exp_data.list, link) { - if (!exp_fhandler->insert && - !exp_fhandler->remove && - (exp_fhandler->exp_fn->attn != NULL)) - exp_fhandler->exp_fn->attn(rmi4_data, intr[0]); - } - } - mutex_unlock(&exp_data.mutex); - - return; -} - -static irqreturn_t synaptics_rmi4_irq(int irq, void *data) -{ - struct synaptics_rmi4_data *rmi4_data = data; - const struct synaptics_dsx_board_data *bdata = - rmi4_data->hw_if->board_data; - - if (synaptics_filter_interrupt(data) == IRQ_HANDLED) - return IRQ_HANDLED; - - if (gpio_get_value(bdata->irq_gpio) != bdata->irq_on_state) - goto exit; - - synaptics_rmi4_sensor_report(rmi4_data, true); - -exit: - return IRQ_HANDLED; -} - -static int synaptics_rmi4_int_enable(struct synaptics_rmi4_data *rmi4_data, - bool enable) -{ - int retval = 0; - unsigned char ii; - unsigned char zero = 0x00; - unsigned char *intr_mask; - unsigned short intr_addr; - - intr_mask = rmi4_data->intr_mask; - - for (ii = 0; ii < rmi4_data->num_of_intr_regs; ii++) { - if (intr_mask[ii] != 0x00) { - intr_addr = rmi4_data->f01_ctrl_base_addr + 1 + ii; - if (enable) { - retval = synaptics_rmi4_reg_write(rmi4_data, - intr_addr, - &(intr_mask[ii]), - sizeof(intr_mask[ii])); - if (retval < 0) - return retval; - } else { - retval = synaptics_rmi4_reg_write(rmi4_data, - intr_addr, - &zero, - sizeof(zero)); - if (retval < 0) - return retval; - } - } - } - - return retval; -} - -static int synaptics_rmi4_irq_enable(struct synaptics_rmi4_data *rmi4_data, - bool enable, bool attn_only) -{ - int retval = 0; - const struct synaptics_dsx_board_data *bdata = - rmi4_data->hw_if->board_data; - - if (attn_only) { - retval = synaptics_rmi4_int_enable(rmi4_data, enable); - return retval; - } - - if (enable) { - if (rmi4_data->irq_enabled) - return retval; - - retval = synaptics_rmi4_int_enable(rmi4_data, false); - if (retval < 0) - return retval; - - /* Process and clear interrupts */ - synaptics_rmi4_sensor_report(rmi4_data, false); - - retval = request_threaded_irq(rmi4_data->irq, NULL, - synaptics_rmi4_irq, bdata->irq_flags, - PLATFORM_DRIVER_NAME, rmi4_data); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create irq thread\n", - __func__); - return retval; - } - - retval = synaptics_rmi4_int_enable(rmi4_data, true); - if (retval < 0) - return retval; - - rmi4_data->irq_enabled = true; - } else { - if (rmi4_data->irq_enabled) { - disable_irq(rmi4_data->irq); - free_irq(rmi4_data->irq, rmi4_data); - rmi4_data->irq_enabled = false; - } - } - - return retval; -} - -static void synaptics_rmi4_set_intr_mask(struct synaptics_rmi4_fn *fhandler, - struct synaptics_rmi4_fn_desc *fd, - unsigned int intr_count) -{ - unsigned char ii; - unsigned char intr_offset; - - fhandler->intr_reg_num = (intr_count + 7) / 8; - if (fhandler->intr_reg_num != 0) - fhandler->intr_reg_num -= 1; - - /* Set an enable bit for each data source */ - intr_offset = intr_count % 8; - fhandler->intr_mask = 0; - for (ii = intr_offset; - ii < (fd->intr_src_count + intr_offset); - ii++) - fhandler->intr_mask |= 1 << ii; - - return; -} - -static int synaptics_rmi4_f01_init(struct synaptics_rmi4_data *rmi4_data, - struct synaptics_rmi4_fn *fhandler, - struct synaptics_rmi4_fn_desc *fd, - unsigned int intr_count) -{ - fhandler->fn_number = fd->fn_number; - fhandler->num_of_data_sources = fd->intr_src_count; - fhandler->data = NULL; - fhandler->extra = NULL; - - synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count); - - rmi4_data->f01_query_base_addr = fd->query_base_addr; - rmi4_data->f01_ctrl_base_addr = fd->ctrl_base_addr; - rmi4_data->f01_data_base_addr = fd->data_base_addr; - rmi4_data->f01_cmd_base_addr = fd->cmd_base_addr; - - return 0; -} - -static int synaptics_rmi4_f11_init(struct synaptics_rmi4_data *rmi4_data, - struct synaptics_rmi4_fn *fhandler, - struct synaptics_rmi4_fn_desc *fd, - unsigned int intr_count) -{ - int retval; - int temp; - unsigned char offset; - unsigned char fingers_supported; - struct synaptics_rmi4_f11_extra_data *extra_data; - struct synaptics_rmi4_f11_query_0_5 query_0_5; - struct synaptics_rmi4_f11_query_7_8 query_7_8; - struct synaptics_rmi4_f11_query_9 query_9; - struct synaptics_rmi4_f11_query_12 query_12; - struct synaptics_rmi4_f11_query_27 query_27; - struct synaptics_rmi4_f11_ctrl_6_9 control_6_9; - const struct synaptics_dsx_board_data *bdata = - rmi4_data->hw_if->board_data; - - fhandler->fn_number = fd->fn_number; - fhandler->num_of_data_sources = fd->intr_src_count; - fhandler->extra = kmalloc(sizeof(*extra_data), GFP_KERNEL); - if (!fhandler->extra) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for fhandler->extra\n", - __func__); - return -ENOMEM; - } - extra_data = (struct synaptics_rmi4_f11_extra_data *)fhandler->extra; - - retval = synaptics_rmi4_reg_read(rmi4_data, - fhandler->full_addr.query_base, - query_0_5.data, - sizeof(query_0_5.data)); - if (retval < 0) - return retval; - - /* Maximum number of fingers supported */ - if (query_0_5.num_of_fingers <= 4) - fhandler->num_of_data_points = query_0_5.num_of_fingers + 1; - else if (query_0_5.num_of_fingers == 5) - fhandler->num_of_data_points = 10; - - rmi4_data->num_of_fingers = fhandler->num_of_data_points; - - retval = synaptics_rmi4_reg_read(rmi4_data, - fhandler->full_addr.ctrl_base + 6, - control_6_9.data, - sizeof(control_6_9.data)); - if (retval < 0) - return retval; - - /* Maximum x and y */ - rmi4_data->sensor_max_x = control_6_9.sensor_max_x_pos_7_0 | - (control_6_9.sensor_max_x_pos_11_8 << 8); - rmi4_data->sensor_max_y = control_6_9.sensor_max_y_pos_7_0 | - (control_6_9.sensor_max_y_pos_11_8 << 8); - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Function %02x max x = %d max y = %d\n", - __func__, fhandler->fn_number, - rmi4_data->sensor_max_x, - rmi4_data->sensor_max_y); - - rmi4_data->max_touch_width = MAX_F11_TOUCH_WIDTH; - - if (bdata->swap_axes) { - temp = rmi4_data->sensor_max_x; - rmi4_data->sensor_max_x = rmi4_data->sensor_max_y; - rmi4_data->sensor_max_y = temp; - } - - synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count); - - fhandler->data = NULL; - - offset = sizeof(query_0_5.data); - - /* query 6 */ - if (query_0_5.has_rel) - offset += 1; - - /* queries 7 8 */ - if (query_0_5.has_gestures) { - retval = synaptics_rmi4_reg_read(rmi4_data, - fhandler->full_addr.query_base + offset, - query_7_8.data, - sizeof(query_7_8.data)); - if (retval < 0) - return retval; - - offset += sizeof(query_7_8.data); - } - - /* query 9 */ - if (query_0_5.has_query_9) { - retval = synaptics_rmi4_reg_read(rmi4_data, - fhandler->full_addr.query_base + offset, - query_9.data, - sizeof(query_9.data)); - if (retval < 0) - return retval; - - offset += sizeof(query_9.data); - } - - /* query 10 */ - if (query_0_5.has_gestures && query_7_8.has_touch_shapes) - offset += 1; - - /* query 11 */ - if (query_0_5.has_query_11) - offset += 1; - - /* query 12 */ - if (query_0_5.has_query_12) { - retval = synaptics_rmi4_reg_read(rmi4_data, - fhandler->full_addr.query_base + offset, - query_12.data, - sizeof(query_12.data)); - if (retval < 0) - return retval; - - offset += sizeof(query_12.data); - } - - /* query 13 */ - if (query_0_5.has_jitter_filter) - offset += 1; - - /* query 14 */ - if (query_0_5.has_query_12 && query_12.has_general_information_2) - offset += 1; - - /* queries 15 16 17 18 19 20 21 22 23 24 25 26*/ - if (query_0_5.has_query_12 && query_12.has_physical_properties) - offset += 12; - - /* query 27 */ - if (query_0_5.has_query_27) { - retval = synaptics_rmi4_reg_read(rmi4_data, - fhandler->full_addr.query_base + offset, - query_27.data, - sizeof(query_27.data)); - if (retval < 0) - return retval; - - rmi4_data->f11_wakeup_gesture = query_27.has_wakeup_gesture; - } - - if (!rmi4_data->f11_wakeup_gesture) - return retval; - - /* data 0 */ - fingers_supported = fhandler->num_of_data_points; - offset = (fingers_supported + 3) / 4; - - /* data 1 2 3 4 5 */ - offset += 5 * fingers_supported; - - /* data 6 7 */ - if (query_0_5.has_rel) - offset += 2 * fingers_supported; - - /* data 8 */ - if (query_0_5.has_gestures && query_7_8.data[0]) - offset += 1; - - /* data 9 */ - if (query_0_5.has_gestures && (query_7_8.data[0] || query_7_8.data[1])) - offset += 1; - - /* data 10 */ - if (query_0_5.has_gestures && - (query_7_8.has_pinch || query_7_8.has_flick)) - offset += 1; - - /* data 11 12 */ - if (query_0_5.has_gestures && - (query_7_8.has_flick || query_7_8.has_rotate)) - offset += 2; - - /* data 13 */ - if (query_0_5.has_gestures && query_7_8.has_touch_shapes) - offset += (fingers_supported + 3) / 4; - - /* data 14 15 */ - if (query_0_5.has_gestures && - (query_7_8.has_scroll_zones || - query_7_8.has_multi_finger_scroll || - query_7_8.has_chiral_scroll)) - offset += 2; - - /* data 16 17 */ - if (query_0_5.has_gestures && - (query_7_8.has_scroll_zones && - query_7_8.individual_scroll_zones)) - offset += 2; - - /* data 18 19 20 21 22 23 24 25 26 27 */ - if (query_0_5.has_query_9 && query_9.has_contact_geometry) - offset += 10 * fingers_supported; - - /* data 28 */ - if (query_0_5.has_bending_correction || - query_0_5.has_large_object_suppression) - offset += 1; - - /* data 29 30 31 */ - if (query_0_5.has_query_9 && query_9.has_pen_hover_discrimination) - offset += 3; - - /* data 32 */ - if (query_0_5.has_query_12 && - query_12.has_small_object_detection_tuning) - offset += 1; - - /* data 33 34 */ - if (query_0_5.has_query_27 && query_27.f11_query27_b0) - offset += 2; - - /* data 35 */ - if (query_0_5.has_query_12 && query_12.has_8bit_w) - offset += fingers_supported; - - /* data 36 */ - if (query_0_5.has_bending_correction) - offset += 1; - - /* data 37 */ - if (query_0_5.has_query_27 && query_27.has_data_37) - offset += 1; - - /* data 38 */ - if (query_0_5.has_query_27 && query_27.has_wakeup_gesture) - extra_data->data38_offset = offset; - - return retval; -} - -static int synaptics_rmi4_f12_set_enables(struct synaptics_rmi4_data *rmi4_data, - unsigned short ctrl28) -{ - int retval; - static unsigned short ctrl_28_address; - - if (ctrl28) - ctrl_28_address = ctrl28; - - retval = synaptics_rmi4_reg_write(rmi4_data, - ctrl_28_address, - &rmi4_data->report_enable, - sizeof(rmi4_data->report_enable)); - if (retval < 0) - return retval; - - return retval; -} - -static int synaptics_rmi4_f12_ctrl_sub(struct synaptics_rmi4_data *rmi4_data, - struct synaptics_rmi4_fn *fhandler, - struct synaptics_rmi4_f12_query_5 *query_5, - unsigned char ctrlreg, unsigned char subpacket) -{ - int retval; - unsigned char cnt; - unsigned char regnum; - unsigned char bitnum; - unsigned char q5_index; - unsigned char q6_index; - unsigned char offset; - unsigned char max_ctrlreg; - unsigned char *query_6; - - max_ctrlreg = (sizeof(query_5->data) - 1) * 8 - 1; - - if (ctrlreg > max_ctrlreg) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Control register number (%d) over limit\n", - __func__, ctrlreg); - return -EINVAL; - } - - q5_index = ctrlreg / 8 + 1; - bitnum = ctrlreg % 8; - if ((query_5->data[q5_index] & (1 << bitnum)) == 0x00) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Control %d is not present\n", - __func__, ctrlreg); - return -EINVAL; - } - - query_6 = kmalloc(query_5->size_of_query6, GFP_KERNEL); - if (!query_6) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for query 6\n", - __func__); - return -ENOMEM; - } - - retval = synaptics_rmi4_reg_read(rmi4_data, - fhandler->full_addr.query_base + 6, - query_6, - query_5->size_of_query6); - if (retval < 0) - goto exit; - - q6_index = 0; - - for (regnum = 0; regnum < ctrlreg; regnum++) { - q5_index = regnum / 8 + 1; - bitnum = regnum % 8; - if ((query_5->data[q5_index] & (1 << bitnum)) == 0x00) - continue; - - if (query_6[q6_index] == 0x00) - q6_index += 3; - else - q6_index++; - - while (query_6[q6_index] & ~MASK_7BIT) - q6_index++; - - q6_index++; - } - - cnt = 0; - q6_index++; - offset = subpacket / 7; - bitnum = subpacket % 7; - - do { - if (cnt == offset) { - if (query_6[q6_index + cnt] & (1 << bitnum)) - retval = 1; - else - retval = 0; - goto exit; - } - cnt++; - } while (query_6[q6_index + cnt - 1] & ~MASK_7BIT); - - retval = 0; - -exit: - kfree(query_6); - - return retval; -} - -static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data, - struct synaptics_rmi4_fn *fhandler, - struct synaptics_rmi4_fn_desc *fd, - unsigned int intr_count) -{ - int retval = 0; - int temp; - unsigned char subpacket; - unsigned char ctrl_23_size; - unsigned char size_of_2d_data; - unsigned char size_of_query8; - unsigned char ctrl_8_offset; - unsigned char ctrl_20_offset; - unsigned char ctrl_23_offset; - unsigned char ctrl_28_offset; - unsigned char ctrl_31_offset; - unsigned char num_of_fingers; - struct synaptics_rmi4_f12_extra_data *extra_data; - struct synaptics_rmi4_f12_query_5 *query_5 = NULL; - struct synaptics_rmi4_f12_query_8 *query_8 = NULL; - struct synaptics_rmi4_f12_ctrl_8 *ctrl_8 = NULL; - struct synaptics_rmi4_f12_ctrl_23 *ctrl_23 = NULL; - struct synaptics_rmi4_f12_ctrl_31 *ctrl_31 = NULL; - const struct synaptics_dsx_board_data *bdata = - rmi4_data->hw_if->board_data; - - fhandler->fn_number = fd->fn_number; - fhandler->num_of_data_sources = fd->intr_src_count; - fhandler->extra = kmalloc(sizeof(*extra_data), GFP_KERNEL); - if (!fhandler->extra) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for fhandler->extra\n", - __func__); - return -ENOMEM; - } - extra_data = (struct synaptics_rmi4_f12_extra_data *)fhandler->extra; - size_of_2d_data = sizeof(struct synaptics_rmi4_f12_finger_data); - - query_5 = kmalloc(sizeof(*query_5), GFP_KERNEL); - if (!query_5) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for query_5\n", - __func__); - retval = -ENOMEM; - goto exit; - } - - query_8 = kmalloc(sizeof(*query_8), GFP_KERNEL); - if (!query_8) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for query_8\n", - __func__); - retval = -ENOMEM; - goto exit; - } - - ctrl_8 = kmalloc(sizeof(*ctrl_8), GFP_KERNEL); - if (!ctrl_8) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for ctrl_8\n", - __func__); - retval = -ENOMEM; - goto exit; - } - - ctrl_23 = kmalloc(sizeof(*ctrl_23), GFP_KERNEL); - if (!ctrl_23) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for ctrl_23\n", - __func__); - retval = -ENOMEM; - goto exit; - } - - ctrl_31 = kmalloc(sizeof(*ctrl_31), GFP_KERNEL); - if (!ctrl_31) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for ctrl_31\n", - __func__); - retval = -ENOMEM; - goto exit; - } - - retval = synaptics_rmi4_reg_read(rmi4_data, - fhandler->full_addr.query_base + 5, - query_5->data, - sizeof(query_5->data)); - if (retval < 0) - goto exit; - - ctrl_8_offset = query_5->ctrl0_is_present + - query_5->ctrl1_is_present + - query_5->ctrl2_is_present + - query_5->ctrl3_is_present + - query_5->ctrl4_is_present + - query_5->ctrl5_is_present + - query_5->ctrl6_is_present + - query_5->ctrl7_is_present; - - ctrl_20_offset = ctrl_8_offset + - query_5->ctrl8_is_present + - query_5->ctrl9_is_present + - query_5->ctrl10_is_present + - query_5->ctrl11_is_present + - query_5->ctrl12_is_present + - query_5->ctrl13_is_present + - query_5->ctrl14_is_present + - query_5->ctrl15_is_present + - query_5->ctrl16_is_present + - query_5->ctrl17_is_present + - query_5->ctrl18_is_present + - query_5->ctrl19_is_present; - - ctrl_23_offset = ctrl_20_offset + - query_5->ctrl20_is_present + - query_5->ctrl21_is_present + - query_5->ctrl22_is_present; - - ctrl_28_offset = ctrl_23_offset + - query_5->ctrl23_is_present + - query_5->ctrl24_is_present + - query_5->ctrl25_is_present + - query_5->ctrl26_is_present + - query_5->ctrl27_is_present; - - ctrl_31_offset = ctrl_28_offset + - query_5->ctrl28_is_present + - query_5->ctrl29_is_present + - query_5->ctrl30_is_present; - - ctrl_23_size = 2; - for (subpacket = 2; subpacket <= 4; subpacket++) { - retval = synaptics_rmi4_f12_ctrl_sub(rmi4_data, - fhandler, query_5, 23, subpacket); - if (retval == 1) - ctrl_23_size++; - else if (retval < 0) - goto exit; - } - - retval = synaptics_rmi4_reg_read(rmi4_data, - fhandler->full_addr.ctrl_base + ctrl_23_offset, - ctrl_23->data, - ctrl_23_size); - if (retval < 0) - goto exit; - - /* Maximum number of fingers supported */ - fhandler->num_of_data_points = min_t(unsigned char, - ctrl_23->max_reported_objects, - (unsigned char)F12_FINGERS_TO_SUPPORT); - - num_of_fingers = fhandler->num_of_data_points; - rmi4_data->num_of_fingers = num_of_fingers; - - rmi4_data->stylus_enable = ctrl_23->stylus_enable; - rmi4_data->eraser_enable = ctrl_23->eraser_enable; - - retval = synaptics_rmi4_reg_read(rmi4_data, - fhandler->full_addr.query_base + 7, - &size_of_query8, - sizeof(size_of_query8)); - if (retval < 0) - goto exit; - - retval = synaptics_rmi4_reg_read(rmi4_data, - fhandler->full_addr.query_base + 8, - query_8->data, - size_of_query8); - if (retval < 0) - goto exit; - - /* Determine the presence of the Data0 register */ - extra_data->data1_offset = query_8->data0_is_present; - - if ((size_of_query8 >= 3) && (query_8->data15_is_present)) { - extra_data->data15_offset = query_8->data0_is_present + - query_8->data1_is_present + - query_8->data2_is_present + - query_8->data3_is_present + - query_8->data4_is_present + - query_8->data5_is_present + - query_8->data6_is_present + - query_8->data7_is_present + - query_8->data8_is_present + - query_8->data9_is_present + - query_8->data10_is_present + - query_8->data11_is_present + - query_8->data12_is_present + - query_8->data13_is_present + - query_8->data14_is_present; - extra_data->data15_size = (num_of_fingers + 7) / 8; - } else { - extra_data->data15_size = 0; - } - -#ifdef REPORT_2D_PRESSURE - if ((size_of_query8 >= 4) && (query_8->data23_is_present)) { - extra_data->data23_offset = query_8->data0_is_present + - query_8->data1_is_present + - query_8->data2_is_present + - query_8->data3_is_present + - query_8->data4_is_present + - query_8->data5_is_present + - query_8->data6_is_present + - query_8->data7_is_present + - query_8->data8_is_present + - query_8->data9_is_present + - query_8->data10_is_present + - query_8->data11_is_present + - query_8->data12_is_present + - query_8->data13_is_present + - query_8->data14_is_present + - query_8->data15_is_present + - query_8->data16_is_present + - query_8->data17_is_present + - query_8->data18_is_present + - query_8->data19_is_present + - query_8->data20_is_present + - query_8->data21_is_present + - query_8->data22_is_present; - extra_data->data23_size = num_of_fingers; - rmi4_data->report_pressure = true; - } else { - extra_data->data23_size = 0; - rmi4_data->report_pressure = false; - } -#endif - - rmi4_data->report_enable = RPT_DEFAULT; -#ifdef REPORT_2D_Z - rmi4_data->report_enable |= RPT_Z; -#endif -#ifdef REPORT_2D_W - rmi4_data->report_enable |= (RPT_WX | RPT_WY); -#endif - - retval = synaptics_rmi4_f12_set_enables(rmi4_data, - fhandler->full_addr.ctrl_base + ctrl_28_offset); - if (retval < 0) - goto exit; - - if (query_5->ctrl8_is_present) { - rmi4_data->wedge_sensor = false; - - retval = synaptics_rmi4_reg_read(rmi4_data, - fhandler->full_addr.ctrl_base + ctrl_8_offset, - ctrl_8->data, - sizeof(ctrl_8->data)); - if (retval < 0) - goto exit; - - /* Maximum x and y */ - rmi4_data->sensor_max_x = - ((unsigned int)ctrl_8->max_x_coord_lsb << 0) | - ((unsigned int)ctrl_8->max_x_coord_msb << 8); - rmi4_data->sensor_max_y = - ((unsigned int)ctrl_8->max_y_coord_lsb << 0) | - ((unsigned int)ctrl_8->max_y_coord_msb << 8); - - rmi4_data->max_touch_width = MAX_F12_TOUCH_WIDTH; - } else { - rmi4_data->wedge_sensor = true; - - retval = synaptics_rmi4_reg_read(rmi4_data, - fhandler->full_addr.ctrl_base + ctrl_31_offset, - ctrl_31->data, - sizeof(ctrl_31->data)); - if (retval < 0) - goto exit; - - /* Maximum x and y */ - rmi4_data->sensor_max_x = - ((unsigned int)ctrl_31->max_x_coord_lsb << 0) | - ((unsigned int)ctrl_31->max_x_coord_msb << 8); - rmi4_data->sensor_max_y = - ((unsigned int)ctrl_31->max_y_coord_lsb << 0) | - ((unsigned int)ctrl_31->max_y_coord_msb << 8); - - rmi4_data->max_touch_width = MAX_F12_TOUCH_WIDTH; - } - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Function %02x max x = %d max y = %d\n", - __func__, fhandler->fn_number, - rmi4_data->sensor_max_x, - rmi4_data->sensor_max_y); - - if (bdata->swap_axes) { - temp = rmi4_data->sensor_max_x; - rmi4_data->sensor_max_x = rmi4_data->sensor_max_y; - rmi4_data->sensor_max_y = temp; - } - - rmi4_data->f12_wakeup_gesture = query_5->ctrl27_is_present; - if (rmi4_data->f12_wakeup_gesture) { - extra_data->ctrl20_offset = ctrl_20_offset; - extra_data->data4_offset = query_8->data0_is_present + - query_8->data1_is_present + - query_8->data2_is_present + - query_8->data3_is_present; - } - - synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count); - - /* Allocate memory for finger data storage space */ - fhandler->data_size = num_of_fingers * size_of_2d_data; - fhandler->data = kmalloc(fhandler->data_size, GFP_KERNEL); - if (!fhandler->data) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for fhandler->data\n", - __func__); - retval = -ENOMEM; - goto exit; - } - -exit: - kfree(query_5); - kfree(query_8); - kfree(ctrl_8); - kfree(ctrl_23); - kfree(ctrl_31); - - return retval; -} - -static int synaptics_rmi4_f1a_alloc_mem(struct synaptics_rmi4_data *rmi4_data, - struct synaptics_rmi4_fn *fhandler) -{ - int retval; - struct synaptics_rmi4_f1a_handle *f1a; - - f1a = kzalloc(sizeof(*f1a), GFP_KERNEL); - if (!f1a) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for function handle\n", - __func__); - return -ENOMEM; - } - - fhandler->data = (void *)f1a; - fhandler->extra = NULL; - - retval = synaptics_rmi4_reg_read(rmi4_data, - fhandler->full_addr.query_base, - f1a->button_query.data, - sizeof(f1a->button_query.data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read query registers\n", - __func__); - return retval; - } - - f1a->max_count = f1a->button_query.max_button_count + 1; - - f1a->button_control.txrx_map = kzalloc(f1a->max_count * 2, GFP_KERNEL); - if (!f1a->button_control.txrx_map) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for tx rx mapping\n", - __func__); - return -ENOMEM; - } - - f1a->button_bitmask_size = (f1a->max_count + 7) / 8; - - f1a->button_data_buffer = kcalloc(f1a->button_bitmask_size, - sizeof(*(f1a->button_data_buffer)), GFP_KERNEL); - if (!f1a->button_data_buffer) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for data buffer\n", - __func__); - return -ENOMEM; - } - - f1a->button_map = kcalloc(f1a->max_count, - sizeof(*(f1a->button_map)), GFP_KERNEL); - if (!f1a->button_map) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for button map\n", - __func__); - return -ENOMEM; - } - - return 0; -} - -static int synaptics_rmi4_f1a_button_map(struct synaptics_rmi4_data *rmi4_data, - struct synaptics_rmi4_fn *fhandler) -{ - int retval; - unsigned char ii; - unsigned char offset = 0; - struct synaptics_rmi4_f1a_query_4 query_4; - struct synaptics_rmi4_f1a_handle *f1a = fhandler->data; - const struct synaptics_dsx_board_data *bdata = - rmi4_data->hw_if->board_data; - - offset = f1a->button_query.has_general_control + - f1a->button_query.has_interrupt_enable + - f1a->button_query.has_multibutton_select; - - if (f1a->button_query.has_tx_rx_map) { - retval = synaptics_rmi4_reg_read(rmi4_data, - fhandler->full_addr.ctrl_base + offset, - f1a->button_control.txrx_map, - f1a->max_count * 2); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read tx rx mapping\n", - __func__); - return retval; - } - - rmi4_data->button_txrx_mapping = f1a->button_control.txrx_map; - } - - if (f1a->button_query.has_query4) { - offset = 2 + f1a->button_query.has_query2 + - f1a->button_query.has_query3; - - retval = synaptics_rmi4_reg_read(rmi4_data, - fhandler->full_addr.query_base + offset, - query_4.data, - sizeof(query_4.data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read button features 4\n", - __func__); - return retval; - } - - if (query_4.has_ctrl24) - rmi4_data->external_afe_buttons = true; - else - rmi4_data->external_afe_buttons = false; - } - - if (!bdata->cap_button_map) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: cap_button_map is NULL in board file\n", - __func__); - return -ENODEV; - } else if (!bdata->cap_button_map->map) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Button map is missing in board file\n", - __func__); - return -ENODEV; - } else { - if (bdata->cap_button_map->nbuttons != f1a->max_count) { - f1a->valid_button_count = min(f1a->max_count, - bdata->cap_button_map->nbuttons); - } else { - f1a->valid_button_count = f1a->max_count; - } - - for (ii = 0; ii < f1a->valid_button_count; ii++) - f1a->button_map[ii] = bdata->cap_button_map->map[ii]; - } - - return 0; -} - -static void synaptics_rmi4_f1a_kfree(struct synaptics_rmi4_fn *fhandler) -{ - struct synaptics_rmi4_f1a_handle *f1a = fhandler->data; - - if (f1a) { - kfree(f1a->button_control.txrx_map); - kfree(f1a->button_data_buffer); - kfree(f1a->button_map); - kfree(f1a); - fhandler->data = NULL; - } - - return; -} - -static int synaptics_rmi4_f1a_init(struct synaptics_rmi4_data *rmi4_data, - struct synaptics_rmi4_fn *fhandler, - struct synaptics_rmi4_fn_desc *fd, - unsigned int intr_count) -{ - int retval; - - fhandler->fn_number = fd->fn_number; - fhandler->num_of_data_sources = fd->intr_src_count; - - synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count); - - retval = synaptics_rmi4_f1a_alloc_mem(rmi4_data, fhandler); - if (retval < 0) - goto error_exit; - - retval = synaptics_rmi4_f1a_button_map(rmi4_data, fhandler); - if (retval < 0) - goto error_exit; - - rmi4_data->button_0d_enabled = 1; - - return 0; - -error_exit: - synaptics_rmi4_f1a_kfree(fhandler); - - return retval; -} - -static void synaptics_rmi4_empty_fn_list(struct synaptics_rmi4_data *rmi4_data) -{ - struct synaptics_rmi4_fn *fhandler; - struct synaptics_rmi4_fn *fhandler_temp; - struct synaptics_rmi4_device_info *rmi; - - rmi = &(rmi4_data->rmi4_mod_info); - - if (!list_empty(&rmi->support_fn_list)) { - list_for_each_entry_safe(fhandler, - fhandler_temp, - &rmi->support_fn_list, - link) { - if (fhandler->fn_number == SYNAPTICS_RMI4_F1A) { - synaptics_rmi4_f1a_kfree(fhandler); - } else { - kfree(fhandler->extra); - kfree(fhandler->data); - } - list_del(&fhandler->link); - kfree(fhandler); - } - } - INIT_LIST_HEAD(&rmi->support_fn_list); - - return; -} - -static int synaptics_rmi4_check_status(struct synaptics_rmi4_data *rmi4_data, - bool *was_in_bl_mode) -{ - int retval; - int timeout = CHECK_STATUS_TIMEOUT_MS; - struct synaptics_rmi4_f01_device_status status; - - retval = synaptics_rmi4_reg_read(rmi4_data, - rmi4_data->f01_data_base_addr, - status.data, - sizeof(status.data)); - if (retval < 0) - return retval; - - while (status.status_code == STATUS_CRC_IN_PROGRESS) { - if (timeout > 0) - msleep(20); - else - return -EINVAL; - - retval = synaptics_rmi4_reg_read(rmi4_data, - rmi4_data->f01_data_base_addr, - status.data, - sizeof(status.data)); - if (retval < 0) - return retval; - - timeout -= 20; - } - - if (timeout != CHECK_STATUS_TIMEOUT_MS) - *was_in_bl_mode = true; - - if (status.flash_prog == 1) { - rmi4_data->flash_prog_mode = true; - pr_notice("%s: In flash prog mode, status = 0x%02x\n", - __func__, - status.status_code); - } else { - rmi4_data->flash_prog_mode = false; - } - - return 0; -} - -static void synaptics_rmi4_set_configured(struct synaptics_rmi4_data *rmi4_data) -{ - int retval; - unsigned char device_ctrl; - - retval = synaptics_rmi4_reg_read(rmi4_data, - rmi4_data->f01_ctrl_base_addr, - &device_ctrl, - sizeof(device_ctrl)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to set configured\n", - __func__); - return; - } - - rmi4_data->no_sleep_setting = device_ctrl & NO_SLEEP_ON; - device_ctrl |= CONFIGURED; - - retval = synaptics_rmi4_reg_write(rmi4_data, - rmi4_data->f01_ctrl_base_addr, - &device_ctrl, - sizeof(device_ctrl)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to set configured\n", - __func__); - } - - return; -} - -static int synaptics_rmi4_alloc_fh(struct synaptics_rmi4_fn **fhandler, - struct synaptics_rmi4_fn_desc *rmi_fd, int page_number) -{ - *fhandler = kmalloc(sizeof(**fhandler), GFP_KERNEL); - if (!(*fhandler)) - return -ENOMEM; - - (*fhandler)->full_addr.data_base = - (rmi_fd->data_base_addr | - (page_number << 8)); - (*fhandler)->full_addr.ctrl_base = - (rmi_fd->ctrl_base_addr | - (page_number << 8)); - (*fhandler)->full_addr.cmd_base = - (rmi_fd->cmd_base_addr | - (page_number << 8)); - (*fhandler)->full_addr.query_base = - (rmi_fd->query_base_addr | - (page_number << 8)); - - return 0; -} - -static int synaptics_rmi4_query_device(struct synaptics_rmi4_data *rmi4_data) -{ - int retval; - unsigned char page_number; - unsigned char intr_count; - unsigned char *f01_query; - unsigned short pdt_entry_addr; - bool f01found; - bool f35found; - bool was_in_bl_mode; - struct synaptics_rmi4_fn_desc rmi_fd; - struct synaptics_rmi4_fn *fhandler; - struct synaptics_rmi4_device_info *rmi; - - rmi = &(rmi4_data->rmi4_mod_info); - -rescan_pdt: - f01found = false; - f35found = false; - was_in_bl_mode = false; - intr_count = 0; - INIT_LIST_HEAD(&rmi->support_fn_list); - - /* Scan the page description tables of the pages to service */ - for (page_number = 0; page_number < PAGES_TO_SERVICE; page_number++) { - for (pdt_entry_addr = PDT_START; pdt_entry_addr > PDT_END; - pdt_entry_addr -= PDT_ENTRY_SIZE) { - pdt_entry_addr |= (page_number << 8); - - retval = synaptics_rmi4_reg_read(rmi4_data, - pdt_entry_addr, - (unsigned char *)&rmi_fd, - sizeof(rmi_fd)); - if (retval < 0) - return retval; - - pdt_entry_addr &= ~(MASK_8BIT << 8); - - fhandler = NULL; - - if (rmi_fd.fn_number == 0) { - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Reached end of PDT\n", - __func__); - break; - } - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: F%02x found (page %d)\n", - __func__, rmi_fd.fn_number, - page_number); - - switch (rmi_fd.fn_number) { - case SYNAPTICS_RMI4_F01: - if (rmi_fd.intr_src_count == 0) - break; - - f01found = true; - - retval = synaptics_rmi4_alloc_fh(&fhandler, - &rmi_fd, page_number); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc for F%d\n", - __func__, - rmi_fd.fn_number); - return retval; - } - - retval = synaptics_rmi4_f01_init(rmi4_data, - fhandler, &rmi_fd, intr_count); - if (retval < 0) - return retval; - - retval = synaptics_rmi4_check_status(rmi4_data, - &was_in_bl_mode); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to check status\n", - __func__); - return retval; - } - - if (was_in_bl_mode) { - kfree(fhandler); - fhandler = NULL; - goto rescan_pdt; - } - - if (rmi4_data->flash_prog_mode) - goto flash_prog_mode; - - break; - case SYNAPTICS_RMI4_F11: - if (rmi_fd.intr_src_count == 0) - break; - - retval = synaptics_rmi4_alloc_fh(&fhandler, - &rmi_fd, page_number); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc for F%d\n", - __func__, - rmi_fd.fn_number); - return retval; - } - - retval = synaptics_rmi4_f11_init(rmi4_data, - fhandler, &rmi_fd, intr_count); - if (retval < 0) - return retval; - break; - case SYNAPTICS_RMI4_F12: - if (rmi_fd.intr_src_count == 0) - break; - - retval = synaptics_rmi4_alloc_fh(&fhandler, - &rmi_fd, page_number); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc for F%d\n", - __func__, - rmi_fd.fn_number); - return retval; - } - - retval = synaptics_rmi4_f12_init(rmi4_data, - fhandler, &rmi_fd, intr_count); - if (retval < 0) - return retval; - break; - case SYNAPTICS_RMI4_F1A: - if (rmi_fd.intr_src_count == 0) - break; - - retval = synaptics_rmi4_alloc_fh(&fhandler, - &rmi_fd, page_number); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc for F%d\n", - __func__, - rmi_fd.fn_number); - return retval; - } - - retval = synaptics_rmi4_f1a_init(rmi4_data, - fhandler, &rmi_fd, intr_count); - if (retval < 0) { -#ifdef IGNORE_FN_INIT_FAILURE - kfree(fhandler); - fhandler = NULL; -#else - return retval; -#endif - } - break; - case SYNAPTICS_RMI4_F35: - f35found = true; - break; - } - - /* Accumulate the interrupt count */ - intr_count += rmi_fd.intr_src_count; - - if (fhandler && rmi_fd.intr_src_count) { - list_add_tail(&fhandler->link, - &rmi->support_fn_list); - } - } - } - - if (!f01found) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to find F01\n", - __func__); - if (!f35found) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to find F35\n", - __func__); - return -EINVAL; - } else { - pr_notice("%s: In microbootloader mode\n", - __func__); - return 0; - } - } - -flash_prog_mode: - rmi4_data->num_of_intr_regs = (intr_count + 7) / 8; - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Number of interrupt registers = %d\n", - __func__, rmi4_data->num_of_intr_regs); - - f01_query = kmalloc(F01_STD_QUERY_LEN, GFP_KERNEL); - if (!f01_query) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for f01_query\n", - __func__); - return -ENOMEM; - } - - retval = synaptics_rmi4_reg_read(rmi4_data, - rmi4_data->f01_query_base_addr, - f01_query, - F01_STD_QUERY_LEN); - if (retval < 0) { - kfree(f01_query); - return retval; - } - - /* RMI Version 4.0 currently supported */ - rmi->version_major = 4; - rmi->version_minor = 0; - - rmi->manufacturer_id = f01_query[0]; - rmi->product_props = f01_query[1]; - rmi->product_info[0] = f01_query[2]; - rmi->product_info[1] = f01_query[3]; - retval = secure_memcpy(rmi->product_id_string, - sizeof(rmi->product_id_string), - &f01_query[11], - F01_STD_QUERY_LEN - 11, - PRODUCT_ID_SIZE); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to copy product ID string\n", - __func__); - } - - kfree(f01_query); - - if (rmi->manufacturer_id != 1) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Non-Synaptics device found, manufacturer ID = %d\n", - __func__, rmi->manufacturer_id); - } - - retval = synaptics_rmi4_reg_read(rmi4_data, - rmi4_data->f01_query_base_addr + F01_BUID_ID_OFFSET, - rmi->build_id, - sizeof(rmi->build_id)); - if (retval < 0) - return retval; - - rmi4_data->firmware_id = (unsigned int)rmi->build_id[0] + - (unsigned int)rmi->build_id[1] * 0x100 + - (unsigned int)rmi->build_id[2] * 0x10000; - - memset(rmi4_data->intr_mask, 0x00, sizeof(rmi4_data->intr_mask)); - - /* - * Map out the interrupt bit masks for the interrupt sources - * from the registered function handlers. - */ - if (!list_empty(&rmi->support_fn_list)) { - list_for_each_entry(fhandler, &rmi->support_fn_list, link) { - if (fhandler->num_of_data_sources) { - rmi4_data->intr_mask[fhandler->intr_reg_num] |= - fhandler->intr_mask; - } - } - } - - if (rmi4_data->f11_wakeup_gesture || rmi4_data->f12_wakeup_gesture) - rmi4_data->enable_wakeup_gesture = WAKEUP_GESTURE; - else - rmi4_data->enable_wakeup_gesture = false; - - synaptics_rmi4_set_configured(rmi4_data); - - return 0; -} - -static int synaptics_rmi4_gpio_setup(int gpio, bool config, int dir, int state) -{ - int retval = 0; - unsigned char buf[16]; - - if (config) { - retval = snprintf(buf, ARRAY_SIZE(buf), "dsx_gpio_%u\n", gpio); - if (retval >= 16) - return -EINVAL; - - retval = gpio_request(gpio, buf); - if (retval) { - pr_err("%s: Failed to get gpio %d (code: %d)", - __func__, gpio, retval); - return retval; - } - - if (dir == 0) - retval = gpio_direction_input(gpio); - else - retval = gpio_direction_output(gpio, state); - if (retval) { - pr_err("%s: Failed to set gpio %d direction", - __func__, gpio); - return retval; - } - } else { - gpio_free(gpio); - } - - return retval; -} - -static void synaptics_rmi4_set_params(struct synaptics_rmi4_data *rmi4_data) -{ - unsigned char ii; - struct synaptics_rmi4_f1a_handle *f1a; - struct synaptics_rmi4_fn *fhandler; - struct synaptics_rmi4_device_info *rmi; - - rmi = &(rmi4_data->rmi4_mod_info); - - input_set_abs_params(rmi4_data->input_dev, - ABS_MT_POSITION_X, 0, - rmi4_data->sensor_max_x, 0, 0); - input_set_abs_params(rmi4_data->input_dev, - ABS_MT_POSITION_Y, 0, - rmi4_data->sensor_max_y, 0, 0); -#ifdef REPORT_2D_W - input_set_abs_params(rmi4_data->input_dev, - ABS_MT_TOUCH_MAJOR, 0, - rmi4_data->max_touch_width, 0, 0); - input_set_abs_params(rmi4_data->input_dev, - ABS_MT_TOUCH_MINOR, 0, - rmi4_data->max_touch_width, 0, 0); -#endif - -#ifdef REPORT_2D_PRESSURE - if (rmi4_data->report_pressure) { - input_set_abs_params(rmi4_data->input_dev, - ABS_MT_PRESSURE, 0, - MAX_F12_TOUCH_PRESSURE, 0, 0); - } -#endif - -#ifdef TYPE_B_PROTOCOL -#ifdef KERNEL_ABOVE_3_6 - input_mt_init_slots(rmi4_data->input_dev, - rmi4_data->num_of_fingers, INPUT_MT_DIRECT); -#else - input_mt_init_slots(rmi4_data->input_dev, - rmi4_data->num_of_fingers); -#endif -#endif - - f1a = NULL; - if (!list_empty(&rmi->support_fn_list)) { - list_for_each_entry(fhandler, &rmi->support_fn_list, link) { - if (fhandler->fn_number == SYNAPTICS_RMI4_F1A) - f1a = fhandler->data; - } - } - - if (f1a) { - for (ii = 0; ii < f1a->valid_button_count; ii++) { - set_bit(f1a->button_map[ii], - rmi4_data->input_dev->keybit); - input_set_capability(rmi4_data->input_dev, - EV_KEY, f1a->button_map[ii]); - } - } - - if (vir_button_map->nbuttons) { - for (ii = 0; ii < vir_button_map->nbuttons; ii++) { - set_bit(vir_button_map->map[ii * 5], - rmi4_data->input_dev->keybit); - input_set_capability(rmi4_data->input_dev, - EV_KEY, vir_button_map->map[ii * 5]); - } - } - - if (rmi4_data->f11_wakeup_gesture || rmi4_data->f12_wakeup_gesture) { - set_bit(KEY_WAKEUP, rmi4_data->input_dev->keybit); - input_set_capability(rmi4_data->input_dev, EV_KEY, KEY_WAKEUP); - } - - return; -} - -static int synaptics_rmi4_set_input_dev(struct synaptics_rmi4_data *rmi4_data) -{ - int retval; - const struct synaptics_dsx_board_data *bdata = - rmi4_data->hw_if->board_data; - - rmi4_data->input_dev = input_allocate_device(); - if (rmi4_data->input_dev == NULL) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to allocate input device\n", - __func__); - retval = -ENOMEM; - goto err_input_device; - } - - retval = synaptics_rmi4_query_device(rmi4_data); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to query device\n", - __func__); - goto err_query_device; - } - - rmi4_data->input_dev->name = PLATFORM_DRIVER_NAME; - rmi4_data->input_dev->phys = INPUT_PHYS_NAME; - rmi4_data->input_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT; - rmi4_data->input_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION; - rmi4_data->input_dev->dev.parent = rmi4_data->pdev->dev.parent; - input_set_drvdata(rmi4_data->input_dev, rmi4_data); - - set_bit(EV_SYN, rmi4_data->input_dev->evbit); - set_bit(EV_KEY, rmi4_data->input_dev->evbit); - set_bit(EV_ABS, rmi4_data->input_dev->evbit); - set_bit(BTN_TOUCH, rmi4_data->input_dev->keybit); - set_bit(BTN_TOOL_FINGER, rmi4_data->input_dev->keybit); -#ifdef INPUT_PROP_DIRECT - set_bit(INPUT_PROP_DIRECT, rmi4_data->input_dev->propbit); -#endif - - if (bdata->max_y_for_2d >= 0) - rmi4_data->sensor_max_y = bdata->max_y_for_2d; - - synaptics_rmi4_set_params(rmi4_data); - - retval = input_register_device(rmi4_data->input_dev); - if (retval) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to register input device\n", - __func__); - goto err_register_input; - } - - if (!rmi4_data->stylus_enable) - return 0; - - rmi4_data->stylus_dev = input_allocate_device(); - if (rmi4_data->stylus_dev == NULL) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to allocate stylus device\n", - __func__); - retval = -ENOMEM; - goto err_stylus_device; - } - - rmi4_data->stylus_dev->name = STYLUS_DRIVER_NAME; - rmi4_data->stylus_dev->phys = STYLUS_PHYS_NAME; - rmi4_data->stylus_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT; - rmi4_data->stylus_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION; - rmi4_data->stylus_dev->dev.parent = rmi4_data->pdev->dev.parent; - input_set_drvdata(rmi4_data->stylus_dev, rmi4_data); - - set_bit(EV_KEY, rmi4_data->stylus_dev->evbit); - set_bit(EV_ABS, rmi4_data->stylus_dev->evbit); - set_bit(BTN_TOUCH, rmi4_data->stylus_dev->keybit); - set_bit(BTN_TOOL_PEN, rmi4_data->stylus_dev->keybit); - if (rmi4_data->eraser_enable) - set_bit(BTN_TOOL_RUBBER, rmi4_data->stylus_dev->keybit); -#ifdef INPUT_PROP_DIRECT - set_bit(INPUT_PROP_DIRECT, rmi4_data->stylus_dev->propbit); -#endif - - input_set_abs_params(rmi4_data->stylus_dev, ABS_X, 0, - rmi4_data->sensor_max_x, 0, 0); - input_set_abs_params(rmi4_data->stylus_dev, ABS_Y, 0, - rmi4_data->sensor_max_y, 0, 0); - - retval = input_register_device(rmi4_data->stylus_dev); - if (retval) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to register stylus device\n", - __func__); - goto err_register_stylus; - } - - return 0; - -err_register_stylus: - rmi4_data->stylus_dev = NULL; - -err_stylus_device: - input_unregister_device(rmi4_data->input_dev); - rmi4_data->input_dev = NULL; - -err_register_input: -err_query_device: - synaptics_rmi4_empty_fn_list(rmi4_data); - input_free_device(rmi4_data->input_dev); - -err_input_device: - return retval; -} - -static int synaptics_rmi4_set_gpio(struct synaptics_rmi4_data *rmi4_data) -{ - int retval; - const struct synaptics_dsx_board_data *bdata = - rmi4_data->hw_if->board_data; - - retval = synaptics_rmi4_gpio_setup( - bdata->irq_gpio, - true, 0, 0); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to configure attention GPIO\n", - __func__); - goto err_gpio_irq; - } - - if (bdata->power_gpio >= 0) { - retval = synaptics_rmi4_gpio_setup( - bdata->power_gpio, - true, 1, !bdata->power_on_state); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to configure power GPIO\n", - __func__); - goto err_gpio_power; - } - } - - if (bdata->reset_gpio >= 0) { - retval = synaptics_rmi4_gpio_setup( - bdata->reset_gpio, - true, 1, !bdata->reset_on_state); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to configure reset GPIO\n", - __func__); - goto err_gpio_reset; - } - } - - if (bdata->power_gpio >= 0) { - gpio_set_value(bdata->power_gpio, bdata->power_on_state); - msleep(bdata->power_delay_ms); - } - - if (bdata->reset_gpio >= 0) { - gpio_set_value(bdata->reset_gpio, bdata->reset_on_state); - msleep(bdata->reset_active_ms); - gpio_set_value(bdata->reset_gpio, !bdata->reset_on_state); - msleep(bdata->reset_delay_ms); - } - - return 0; - -err_gpio_reset: - if (bdata->power_gpio >= 0) - synaptics_rmi4_gpio_setup(bdata->power_gpio, false, 0, 0); - -err_gpio_power: - synaptics_rmi4_gpio_setup(bdata->irq_gpio, false, 0, 0); - -err_gpio_irq: - return retval; -} - -static int synaptics_rmi4_get_reg(struct synaptics_rmi4_data *rmi4_data, - bool get) -{ - int retval; - const struct synaptics_dsx_board_data *bdata = - rmi4_data->hw_if->board_data; - - if (!get) { - retval = 0; - goto regulator_put; - } - - if ((bdata->pwr_reg_name != NULL) && (*bdata->pwr_reg_name != 0)) { - rmi4_data->pwr_reg = regulator_get(rmi4_data->pdev->dev.parent, - bdata->pwr_reg_name); - if (IS_ERR(rmi4_data->pwr_reg)) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to get power regulator\n", - __func__); - retval = PTR_ERR(rmi4_data->pwr_reg); - goto regulator_put; - } - } - - if ((bdata->bus_reg_name != NULL) && (*bdata->bus_reg_name != 0)) { - rmi4_data->bus_reg = regulator_get(rmi4_data->pdev->dev.parent, - bdata->bus_reg_name); - if (IS_ERR(rmi4_data->bus_reg)) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to get bus pullup regulator\n", - __func__); - retval = PTR_ERR(rmi4_data->bus_reg); - goto regulator_put; - } - } - - return 0; - -regulator_put: - if (rmi4_data->pwr_reg) { - regulator_put(rmi4_data->pwr_reg); - rmi4_data->pwr_reg = NULL; - } - - if (rmi4_data->bus_reg) { - regulator_put(rmi4_data->bus_reg); - rmi4_data->bus_reg = NULL; - } - - return retval; -} - -static int synaptics_rmi4_enable_reg(struct synaptics_rmi4_data *rmi4_data, - bool enable) -{ - int retval; - const struct synaptics_dsx_board_data *bdata = - rmi4_data->hw_if->board_data; - - if (!enable) { - retval = 0; - goto disable_pwr_reg; - } - - if (rmi4_data->bus_reg) { - retval = regulator_enable(rmi4_data->bus_reg); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to enable bus pullup regulator\n", - __func__); - goto exit; - } - } - - if (rmi4_data->pwr_reg) { - retval = regulator_enable(rmi4_data->pwr_reg); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to enable power regulator\n", - __func__); - goto disable_bus_reg; - } - msleep(bdata->power_delay_ms); - } - - return 0; - -disable_pwr_reg: - if (rmi4_data->pwr_reg) - regulator_disable(rmi4_data->pwr_reg); - -disable_bus_reg: - if (rmi4_data->bus_reg) - regulator_disable(rmi4_data->bus_reg); - -exit: - return retval; -} - -static int synaptics_rmi4_free_fingers(struct synaptics_rmi4_data *rmi4_data) -{ - unsigned char ii; - - mutex_lock(&(rmi4_data->rmi4_report_mutex)); - -#ifdef TYPE_B_PROTOCOL - for (ii = 0; ii < rmi4_data->num_of_fingers; ii++) { - input_mt_slot(rmi4_data->input_dev, ii); - input_mt_report_slot_state(rmi4_data->input_dev, - MT_TOOL_FINGER, 0); - } -#endif - input_report_key(rmi4_data->input_dev, - BTN_TOUCH, 0); - input_report_key(rmi4_data->input_dev, - BTN_TOOL_FINGER, 0); -#ifndef TYPE_B_PROTOCOL - input_mt_sync(rmi4_data->input_dev); -#endif - input_sync(rmi4_data->input_dev); - - if (rmi4_data->stylus_enable) { - input_report_key(rmi4_data->stylus_dev, - BTN_TOUCH, 0); - input_report_key(rmi4_data->stylus_dev, - BTN_TOOL_PEN, 0); - if (rmi4_data->eraser_enable) { - input_report_key(rmi4_data->stylus_dev, - BTN_TOOL_RUBBER, 0); - } - input_sync(rmi4_data->stylus_dev); - } - - mutex_unlock(&(rmi4_data->rmi4_report_mutex)); - - rmi4_data->fingers_on_2d = false; - - return 0; -} - -static int synaptics_rmi4_sw_reset(struct synaptics_rmi4_data *rmi4_data) -{ - int retval; - unsigned char command = 0x01; - - retval = synaptics_rmi4_reg_write(rmi4_data, - rmi4_data->f01_cmd_base_addr, - &command, - sizeof(command)); - if (retval < 0) - return retval; - - msleep(rmi4_data->hw_if->board_data->reset_delay_ms); - - if (rmi4_data->hw_if->ui_hw_init) { - retval = rmi4_data->hw_if->ui_hw_init(rmi4_data); - if (retval < 0) - return retval; - } - - return 0; -} - -static void synaptics_rmi4_rebuild_work(struct work_struct *work) -{ - int retval; - unsigned char attr_count; - struct synaptics_rmi4_exp_fhandler *exp_fhandler; - struct delayed_work *delayed_work = - container_of(work, struct delayed_work, work); - struct synaptics_rmi4_data *rmi4_data = - container_of(delayed_work, struct synaptics_rmi4_data, - rb_work); - - mutex_lock(&(rmi4_data->rmi4_reset_mutex)); - - mutex_lock(&exp_data.mutex); - - synaptics_rmi4_irq_enable(rmi4_data, false, false); - - if (!list_empty(&exp_data.list)) { - list_for_each_entry(exp_fhandler, &exp_data.list, link) - if (exp_fhandler->exp_fn->remove != NULL) - exp_fhandler->exp_fn->remove(rmi4_data); - } - - for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { - sysfs_remove_file(&rmi4_data->input_dev->dev.kobj, - &attrs[attr_count].attr); - } - - synaptics_rmi4_free_fingers(rmi4_data); - synaptics_rmi4_empty_fn_list(rmi4_data); - input_unregister_device(rmi4_data->input_dev); - rmi4_data->input_dev = NULL; - if (rmi4_data->stylus_enable) { - input_unregister_device(rmi4_data->stylus_dev); - rmi4_data->stylus_dev = NULL; - } - - retval = synaptics_rmi4_sw_reset(rmi4_data); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to issue reset command\n", - __func__); - goto exit; - } - - retval = synaptics_rmi4_set_input_dev(rmi4_data); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to set up input device\n", - __func__); - goto exit; - } - - for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { - retval = sysfs_create_file(&rmi4_data->input_dev->dev.kobj, - &attrs[attr_count].attr); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create sysfs attributes\n", - __func__); - goto exit; - } - } - - if (!list_empty(&exp_data.list)) { - list_for_each_entry(exp_fhandler, &exp_data.list, link) - if (exp_fhandler->exp_fn->init != NULL) - exp_fhandler->exp_fn->init(rmi4_data); - } - - retval = 0; - -exit: - synaptics_rmi4_irq_enable(rmi4_data, true, false); - - mutex_unlock(&exp_data.mutex); - - mutex_unlock(&(rmi4_data->rmi4_reset_mutex)); - - return; -} - -static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data, - bool rebuild) -{ - int retval; - struct synaptics_rmi4_exp_fhandler *exp_fhandler; - - if (rebuild) { - queue_delayed_work(rmi4_data->rb_workqueue, - &rmi4_data->rb_work, - msecs_to_jiffies(REBUILD_WORK_DELAY_MS)); - return 0; - } - - mutex_lock(&(rmi4_data->rmi4_reset_mutex)); - - synaptics_rmi4_irq_enable(rmi4_data, false, false); - - retval = synaptics_rmi4_sw_reset(rmi4_data); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to issue reset command\n", - __func__); - goto exit; - } - - synaptics_rmi4_free_fingers(rmi4_data); - - synaptics_rmi4_empty_fn_list(rmi4_data); - - retval = synaptics_rmi4_query_device(rmi4_data); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to query device\n", - __func__); - goto exit; - } - - mutex_lock(&exp_data.mutex); - if (!list_empty(&exp_data.list)) { - list_for_each_entry(exp_fhandler, &exp_data.list, link) - if (exp_fhandler->exp_fn->reset != NULL) - exp_fhandler->exp_fn->reset(rmi4_data); - } - mutex_unlock(&exp_data.mutex); - - retval = 0; - -exit: - synaptics_rmi4_irq_enable(rmi4_data, true, false); - - mutex_unlock(&(rmi4_data->rmi4_reset_mutex)); - - return retval; -} - -#ifdef FB_READY_RESET -static void synaptics_rmi4_reset_work(struct work_struct *work) -{ - int retval; - unsigned int timeout; - struct synaptics_rmi4_data *rmi4_data = - container_of(work, struct synaptics_rmi4_data, - reset_work); - - timeout = FB_READY_TIMEOUT_S * 1000 / FB_READY_WAIT_MS + 1; - - while (!rmi4_data->fb_ready) { - msleep(FB_READY_WAIT_MS); - timeout--; - if (timeout == 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Timed out waiting for FB ready\n", - __func__); - return; - } - } - - mutex_lock(&rmi4_data->rmi4_exp_init_mutex); - - retval = synaptics_rmi4_reset_device(rmi4_data, false); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to issue reset command\n", - __func__); - } - - mutex_unlock(&rmi4_data->rmi4_exp_init_mutex); - - return; -} -#endif - -static void synaptics_rmi4_sleep_enable(struct synaptics_rmi4_data *rmi4_data, - bool enable) -{ - int retval; - unsigned char device_ctrl; - unsigned char no_sleep_setting = rmi4_data->no_sleep_setting; - - retval = synaptics_rmi4_reg_read(rmi4_data, - rmi4_data->f01_ctrl_base_addr, - &device_ctrl, - sizeof(device_ctrl)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read device control\n", - __func__); - return; - } - - device_ctrl = device_ctrl & ~MASK_3BIT; - if (enable) - device_ctrl = device_ctrl | NO_SLEEP_OFF | SENSOR_SLEEP; - else - device_ctrl = device_ctrl | no_sleep_setting | NORMAL_OPERATION; - - retval = synaptics_rmi4_reg_write(rmi4_data, - rmi4_data->f01_ctrl_base_addr, - &device_ctrl, - sizeof(device_ctrl)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write device control\n", - __func__); - return; - } - - rmi4_data->sensor_sleep = enable; - - return; -} - -static void synaptics_rmi4_exp_fn_work(struct work_struct *work) -{ - struct synaptics_rmi4_exp_fhandler *exp_fhandler; - struct synaptics_rmi4_exp_fhandler *exp_fhandler_temp; - struct synaptics_rmi4_data *rmi4_data = exp_data.rmi4_data; - - mutex_lock(&rmi4_data->rmi4_exp_init_mutex); - mutex_lock(&rmi4_data->rmi4_reset_mutex); - mutex_lock(&exp_data.mutex); - if (!list_empty(&exp_data.list)) { - list_for_each_entry_safe(exp_fhandler, - exp_fhandler_temp, - &exp_data.list, - link) { - if ((exp_fhandler->exp_fn->init != NULL) && - exp_fhandler->insert) { - exp_fhandler->exp_fn->init(rmi4_data); - exp_fhandler->insert = false; - } else if ((exp_fhandler->exp_fn->remove != NULL) && - exp_fhandler->remove) { - exp_fhandler->exp_fn->remove(rmi4_data); - list_del(&exp_fhandler->link); - kfree(exp_fhandler); - } - } - } - mutex_unlock(&exp_data.mutex); - mutex_unlock(&rmi4_data->rmi4_reset_mutex); - mutex_unlock(&rmi4_data->rmi4_exp_init_mutex); - - return; -} - -void synaptics_rmi4_new_function(struct synaptics_rmi4_exp_fn *exp_fn, - bool insert) -{ - struct synaptics_rmi4_exp_fhandler *exp_fhandler; - - if (!exp_data.initialized) { - mutex_init(&exp_data.mutex); - INIT_LIST_HEAD(&exp_data.list); - exp_data.initialized = true; - } - - mutex_lock(&exp_data.mutex); - if (insert) { - exp_fhandler = kzalloc(sizeof(*exp_fhandler), GFP_KERNEL); - if (!exp_fhandler) { - pr_err("%s: Failed to alloc mem for expansion function\n", - __func__); - goto exit; - } - exp_fhandler->exp_fn = exp_fn; - exp_fhandler->insert = true; - exp_fhandler->remove = false; - list_add_tail(&exp_fhandler->link, &exp_data.list); - } else if (!list_empty(&exp_data.list)) { - list_for_each_entry(exp_fhandler, &exp_data.list, link) { - if (exp_fhandler->exp_fn->fn_type == exp_fn->fn_type) { - exp_fhandler->insert = false; - exp_fhandler->remove = true; - goto exit; - } - } - } - -exit: - mutex_unlock(&exp_data.mutex); - - if (exp_data.queue_work) { - queue_delayed_work(exp_data.workqueue, - &exp_data.work, - msecs_to_jiffies(EXP_FN_WORK_DELAY_MS)); - } - - return; -} -EXPORT_SYMBOL(synaptics_rmi4_new_function); - -static int synaptics_dsx_pinctrl_init(struct synaptics_rmi4_data *rmi4_data) -{ - int retval; - - /* Get pinctrl if target uses pinctrl */ - rmi4_data->ts_pinctrl = devm_pinctrl_get((rmi4_data->pdev->dev.parent)); - if (IS_ERR_OR_NULL(rmi4_data->ts_pinctrl)) { - retval = PTR_ERR(rmi4_data->ts_pinctrl); - dev_err(rmi4_data->pdev->dev.parent, - "Target does not use pinctrl %d\n", retval); - goto err_pinctrl_get; - } - - rmi4_data->pinctrl_state_active - = pinctrl_lookup_state(rmi4_data->ts_pinctrl, "pmx_ts_active"); - if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_active)) { - retval = PTR_ERR(rmi4_data->pinctrl_state_active); - dev_err(rmi4_data->pdev->dev.parent, - "Can not lookup %s pinstate %d\n", - PINCTRL_STATE_ACTIVE, retval); - goto err_pinctrl_lookup; - } - - rmi4_data->pinctrl_state_suspend - = pinctrl_lookup_state(rmi4_data->ts_pinctrl, "pmx_ts_suspend"); - if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_suspend)) { - retval = PTR_ERR(rmi4_data->pinctrl_state_suspend); - dev_dbg(rmi4_data->pdev->dev.parent, - "Can not lookup %s pinstate %d\n", - PINCTRL_STATE_SUSPEND, retval); - goto err_pinctrl_lookup; - } - - rmi4_data->pinctrl_state_release - = pinctrl_lookup_state(rmi4_data->ts_pinctrl, "pmx_ts_release"); - if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_release)) { - retval = PTR_ERR(rmi4_data->pinctrl_state_release); - dev_dbg(rmi4_data->pdev->dev.parent, - "Can not lookup %s pinstate %d\n", - PINCTRL_STATE_RELEASE, retval); - } - - return 0; - -err_pinctrl_lookup: - devm_pinctrl_put(rmi4_data->ts_pinctrl); -err_pinctrl_get: - rmi4_data->ts_pinctrl = NULL; - return retval; -} - -static int synaptics_rmi4_probe(struct platform_device *pdev) -{ - int retval; - unsigned char attr_count; - struct synaptics_rmi4_data *rmi4_data; - const struct synaptics_dsx_hw_interface *hw_if; - const struct synaptics_dsx_board_data *bdata; - - hw_if = pdev->dev.platform_data; - if (!hw_if) { - dev_err(&pdev->dev, - "%s: No hardware interface found\n", - __func__); - return -EINVAL; - } - - bdata = hw_if->board_data; - if (!bdata) { - dev_err(&pdev->dev, - "%s: No board data found\n", - __func__); - return -EINVAL; - } - - rmi4_data = kzalloc(sizeof(*rmi4_data), GFP_KERNEL); - if (!rmi4_data) { - dev_err(&pdev->dev, - "%s: Failed to alloc mem for rmi4_data\n", - __func__); - return -ENOMEM; - } - - rmi4_data->pdev = pdev; - rmi4_data->current_page = MASK_8BIT; - rmi4_data->hw_if = hw_if; - rmi4_data->suspend = false; - rmi4_data->irq_enabled = false; - rmi4_data->fingers_on_2d = false; - - rmi4_data->reset_device = synaptics_rmi4_reset_device; - rmi4_data->irq_enable = synaptics_rmi4_irq_enable; - rmi4_data->sleep_enable = synaptics_rmi4_sleep_enable; - rmi4_data->report_touch = synaptics_rmi4_report_touch; - - mutex_init(&(rmi4_data->rmi4_reset_mutex)); - mutex_init(&(rmi4_data->rmi4_report_mutex)); - mutex_init(&(rmi4_data->rmi4_io_ctrl_mutex)); - mutex_init(&(rmi4_data->rmi4_exp_init_mutex)); - - platform_set_drvdata(pdev, rmi4_data); - - vir_button_map = bdata->vir_button_map; - - retval = synaptics_rmi4_get_reg(rmi4_data, true); - if (retval < 0) { - dev_err(&pdev->dev, - "%s: Failed to get regulators\n", - __func__); - goto err_get_reg; - } - - retval = synaptics_rmi4_enable_reg(rmi4_data, true); - if (retval < 0) { - dev_err(&pdev->dev, - "%s: Failed to enable regulators\n", - __func__); - goto err_enable_reg; - } - - retval = synaptics_dsx_pinctrl_init(rmi4_data); - if (!retval && rmi4_data->ts_pinctrl) { - /* - * Pinctrl handle is optional. If pinctrl handle is found - * let pins to be configured in active state. If not - * found continue further without error. - */ - retval = pinctrl_select_state(rmi4_data->ts_pinctrl, - rmi4_data->pinctrl_state_active); - if (retval < 0) { - dev_err(&pdev->dev, - "%s: Failed to select %s pinstate %d\n", - __func__, PINCTRL_STATE_ACTIVE, retval); - } - } - retval = synaptics_rmi4_set_gpio(rmi4_data); - if (retval < 0) { - dev_err(&pdev->dev, - "%s: Failed to set up GPIO's\n", - __func__); - goto err_set_gpio; - } - - if (hw_if->ui_hw_init) { - retval = hw_if->ui_hw_init(rmi4_data); - if (retval < 0) { - dev_err(&pdev->dev, - "%s: Failed to initialize hardware interface\n", - __func__); - goto err_ui_hw_init; - } - } - - retval = synaptics_rmi4_set_input_dev(rmi4_data); - if (retval < 0) { - dev_err(&pdev->dev, - "%s: Failed to set up input device\n", - __func__); - goto err_set_input_dev; - } - -#ifdef CONFIG_FB - INIT_WORK(&rmi4_data->fb_notify_work, - synaptics_rmi4_fb_notify_resume_work); - rmi4_data->fb_notifier.notifier_call = synaptics_rmi4_fb_notifier_cb; - retval = fb_register_client(&rmi4_data->fb_notifier); - if (retval < 0) { - dev_err(&pdev->dev, - "%s: Failed to register fb notifier client\n", - __func__); - } -#endif - -#ifdef USE_EARLYSUSPEND - rmi4_data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; - rmi4_data->early_suspend.suspend = synaptics_rmi4_early_suspend; - rmi4_data->early_suspend.resume = synaptics_rmi4_late_resume; - register_early_suspend(&rmi4_data->early_suspend); -#endif - - if (!exp_data.initialized) { - mutex_init(&exp_data.mutex); - INIT_LIST_HEAD(&exp_data.list); - exp_data.initialized = true; - } - - rmi4_data->irq = gpio_to_irq(bdata->irq_gpio); - - retval = synaptics_rmi4_irq_enable(rmi4_data, true, false); - if (retval < 0) { - dev_err(&pdev->dev, - "%s: Failed to enable attention interrupt\n", - __func__); - goto err_enable_irq; - } - - if (vir_button_map->nbuttons) { - rmi4_data->board_prop_dir = kobject_create_and_add( - "board_properties", NULL); - if (!rmi4_data->board_prop_dir) { - dev_err(&pdev->dev, - "%s: Failed to create board_properties directory\n", - __func__); - goto err_virtual_buttons; - } else { - retval = sysfs_create_file(rmi4_data->board_prop_dir, - &virtual_key_map_attr.attr); - if (retval < 0) { - dev_err(&pdev->dev, - "%s: Failed to create virtual key map file\n", - __func__); - goto err_virtual_buttons; - } - } - } - - for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { - retval = sysfs_create_file(&rmi4_data->input_dev->dev.kobj, - &attrs[attr_count].attr); - if (retval < 0) { - dev_err(&pdev->dev, - "%s: Failed to create sysfs attributes\n", - __func__); - goto err_sysfs; - } - } - - rmi4_data->rb_workqueue = - create_singlethread_workqueue("dsx_rebuild_workqueue"); - if (!rmi4_data->rb_workqueue) { - retval = -ENOMEM; - goto err_rb_workqueue; - } - INIT_DELAYED_WORK(&rmi4_data->rb_work, synaptics_rmi4_rebuild_work); - - exp_data.workqueue = create_singlethread_workqueue("dsx_exp_workqueue"); - if (!exp_data.workqueue) { - retval = -ENOMEM; - goto err_exp_data_workqueue; - } - INIT_DELAYED_WORK(&exp_data.work, synaptics_rmi4_exp_fn_work); - exp_data.rmi4_data = rmi4_data; - exp_data.queue_work = true; - queue_delayed_work(exp_data.workqueue, &exp_data.work, 0); - -#ifdef FB_READY_RESET - rmi4_data->reset_workqueue = - create_singlethread_workqueue("dsx_reset_workqueue"); - if (!rmi4_data->reset_workqueue) { - retval = -ENOMEM; - goto err_reset_workqueue; - } - INIT_WORK(&rmi4_data->reset_work, synaptics_rmi4_reset_work); - queue_work(rmi4_data->reset_workqueue, &rmi4_data->reset_work); -#endif - - /* Initialize secure touch */ - synaptics_secure_touch_init(rmi4_data); - synaptics_secure_touch_stop(rmi4_data, true); - - return retval; - -#ifdef FB_READY_RESET -err_reset_workqueue: -#endif - cancel_delayed_work_sync(&exp_data.work); - flush_workqueue(exp_data.workqueue); - destroy_workqueue(exp_data.workqueue); - -err_exp_data_workqueue: - cancel_delayed_work_sync(&rmi4_data->rb_work); - flush_workqueue(rmi4_data->rb_workqueue); - destroy_workqueue(rmi4_data->rb_workqueue); - -err_rb_workqueue: -err_sysfs: - for (attr_count--; attr_count >= 0; attr_count--) { - sysfs_remove_file(&rmi4_data->input_dev->dev.kobj, - &attrs[attr_count].attr); - } - -err_virtual_buttons: - if (rmi4_data->board_prop_dir) { - sysfs_remove_file(rmi4_data->board_prop_dir, - &virtual_key_map_attr.attr); - kobject_put(rmi4_data->board_prop_dir); - } - - synaptics_rmi4_irq_enable(rmi4_data, false, false); - -err_enable_irq: -#ifdef CONFIG_FB - fb_unregister_client(&rmi4_data->fb_notifier); -#endif - -#ifdef USE_EARLYSUSPEND - unregister_early_suspend(&rmi4_data->early_suspend); -#endif - - synaptics_rmi4_empty_fn_list(rmi4_data); - input_unregister_device(rmi4_data->input_dev); - rmi4_data->input_dev = NULL; - if (rmi4_data->stylus_enable) { - input_unregister_device(rmi4_data->stylus_dev); - rmi4_data->stylus_dev = NULL; - } - -err_set_input_dev: - synaptics_rmi4_gpio_setup(bdata->irq_gpio, false, 0, 0); - - if (bdata->reset_gpio >= 0) - synaptics_rmi4_gpio_setup(bdata->reset_gpio, false, 0, 0); - - if (bdata->power_gpio >= 0) - synaptics_rmi4_gpio_setup(bdata->power_gpio, false, 0, 0); - -err_ui_hw_init: -err_set_gpio: - synaptics_rmi4_enable_reg(rmi4_data, false); - - if (rmi4_data->ts_pinctrl) { - if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_release)) { - devm_pinctrl_put(rmi4_data->ts_pinctrl); - rmi4_data->ts_pinctrl = NULL; - } else { - retval = pinctrl_select_state( - rmi4_data->ts_pinctrl, - rmi4_data->pinctrl_state_release); - if (retval) - dev_err(&pdev->dev, - "%s: Failed to create sysfs attributes\n", - __func__); - } - } - -err_enable_reg: - synaptics_rmi4_get_reg(rmi4_data, false); - -err_get_reg: - kfree(rmi4_data); - - return retval; -} - -static int synaptics_rmi4_remove(struct platform_device *pdev) -{ - unsigned char attr_count; - int err; - struct synaptics_rmi4_data *rmi4_data = platform_get_drvdata(pdev); - const struct synaptics_dsx_board_data *bdata = - rmi4_data->hw_if->board_data; - -#ifdef FB_READY_RESET - cancel_work_sync(&rmi4_data->reset_work); - flush_workqueue(rmi4_data->reset_workqueue); - destroy_workqueue(rmi4_data->reset_workqueue); -#endif - - cancel_delayed_work_sync(&exp_data.work); - flush_workqueue(exp_data.workqueue); - destroy_workqueue(exp_data.workqueue); - - cancel_delayed_work_sync(&rmi4_data->rb_work); - flush_workqueue(rmi4_data->rb_workqueue); - destroy_workqueue(rmi4_data->rb_workqueue); - - for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { - sysfs_remove_file(&rmi4_data->input_dev->dev.kobj, - &attrs[attr_count].attr); - } - - if (rmi4_data->board_prop_dir) { - sysfs_remove_file(rmi4_data->board_prop_dir, - &virtual_key_map_attr.attr); - kobject_put(rmi4_data->board_prop_dir); - } - - synaptics_rmi4_irq_enable(rmi4_data, false, false); - -#ifdef CONFIG_FB - fb_unregister_client(&rmi4_data->fb_notifier); -#endif - -#ifdef USE_EARLYSUSPEND - unregister_early_suspend(&rmi4_data->early_suspend); -#endif - - synaptics_rmi4_empty_fn_list(rmi4_data); - input_unregister_device(rmi4_data->input_dev); - rmi4_data->input_dev = NULL; - if (rmi4_data->stylus_enable) { - input_unregister_device(rmi4_data->stylus_dev); - rmi4_data->stylus_dev = NULL; - } - - synaptics_rmi4_gpio_setup(bdata->irq_gpio, false, 0, 0); - - if (bdata->reset_gpio >= 0) - synaptics_rmi4_gpio_setup(bdata->reset_gpio, false, 0, 0); - - if (bdata->power_gpio >= 0) - synaptics_rmi4_gpio_setup(bdata->power_gpio, false, 0, 0); - - - if (rmi4_data->ts_pinctrl) { - if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_release)) { - devm_pinctrl_put(rmi4_data->ts_pinctrl); - rmi4_data->ts_pinctrl = NULL; - } else { - err = pinctrl_select_state( - rmi4_data->ts_pinctrl, - rmi4_data->pinctrl_state_release); - if (err) - dev_err(&pdev->dev, - "Failed to select release pinctrl state %d\n", - err); - } - } - - synaptics_rmi4_enable_reg(rmi4_data, false); - synaptics_rmi4_get_reg(rmi4_data, false); - - kfree(rmi4_data); - - return 0; -} - -static void synaptics_rmi4_f11_wg(struct synaptics_rmi4_data *rmi4_data, - bool enable) -{ - int retval; - unsigned char reporting_control; - struct synaptics_rmi4_fn *fhandler; - struct synaptics_rmi4_device_info *rmi; - - rmi = &(rmi4_data->rmi4_mod_info); - - list_for_each_entry(fhandler, &rmi->support_fn_list, link) { - if (fhandler->fn_number == SYNAPTICS_RMI4_F11) - break; - } - - retval = synaptics_rmi4_reg_read(rmi4_data, - fhandler->full_addr.ctrl_base, - &reporting_control, - sizeof(reporting_control)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to change reporting mode\n", - __func__); - return; - } - - reporting_control = (reporting_control & ~MASK_3BIT); - if (enable) - reporting_control |= F11_WAKEUP_GESTURE_MODE; - else - reporting_control |= F11_CONTINUOUS_MODE; - - retval = synaptics_rmi4_reg_write(rmi4_data, - fhandler->full_addr.ctrl_base, - &reporting_control, - sizeof(reporting_control)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to change reporting mode\n", - __func__); - return; - } - - return; -} - -static void synaptics_rmi4_f12_wg(struct synaptics_rmi4_data *rmi4_data, - bool enable) -{ - int retval; - unsigned char offset; - unsigned char reporting_control[3]; - struct synaptics_rmi4_f12_extra_data *extra_data; - struct synaptics_rmi4_fn *fhandler; - struct synaptics_rmi4_device_info *rmi; - - rmi = &(rmi4_data->rmi4_mod_info); - - list_for_each_entry(fhandler, &rmi->support_fn_list, link) { - if (fhandler->fn_number == SYNAPTICS_RMI4_F12) - break; - } - - extra_data = (struct synaptics_rmi4_f12_extra_data *)fhandler->extra; - offset = extra_data->ctrl20_offset; - - retval = synaptics_rmi4_reg_read(rmi4_data, - fhandler->full_addr.ctrl_base + offset, - reporting_control, - sizeof(reporting_control)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to change reporting mode\n", - __func__); - return; - } - - if (enable) - reporting_control[2] = F12_WAKEUP_GESTURE_MODE; - else - reporting_control[2] = F12_CONTINUOUS_MODE; - - retval = synaptics_rmi4_reg_write(rmi4_data, - fhandler->full_addr.ctrl_base + offset, - reporting_control, - sizeof(reporting_control)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to change reporting mode\n", - __func__); - return; - } - - return; -} - -static void synaptics_rmi4_wakeup_gesture(struct synaptics_rmi4_data *rmi4_data, - bool enable) -{ - if (rmi4_data->f11_wakeup_gesture) - synaptics_rmi4_f11_wg(rmi4_data, enable); - else if (rmi4_data->f12_wakeup_gesture) - synaptics_rmi4_f12_wg(rmi4_data, enable); - - return; -} - -#ifdef CONFIG_FB -static void synaptics_rmi4_fb_notify_resume_work(struct work_struct *work) -{ - struct synaptics_rmi4_data *rmi4_data = - container_of(work, struct synaptics_rmi4_data, fb_notify_work); - synaptics_rmi4_resume(&(rmi4_data->input_dev->dev)); - rmi4_data->fb_ready = true; -} - -static int synaptics_rmi4_fb_notifier_cb(struct notifier_block *self, - unsigned long event, void *data) -{ - int *transition; - struct fb_event *evdata = data; - struct synaptics_rmi4_data *rmi4_data = - container_of(self, struct synaptics_rmi4_data, - fb_notifier); - - if (evdata && evdata->data && rmi4_data) { - if (rmi4_data->hw_if->board_data->resume_in_workqueue) { - if (event == FB_EARLY_EVENT_BLANK) { - synaptics_secure_touch_stop(rmi4_data, false); - } else if (event == FB_EVENT_BLANK) { - transition = evdata->data; - if (*transition == FB_BLANK_POWERDOWN) { - flush_work( - &(rmi4_data->fb_notify_work)); - synaptics_rmi4_suspend( - &rmi4_data->pdev->dev); - rmi4_data->fb_ready = false; - } else if (*transition == FB_BLANK_UNBLANK) { - schedule_work( - &(rmi4_data->fb_notify_work)); - } - } - } else { - if (event == FB_EARLY_EVENT_BLANK) { - synaptics_secure_touch_stop(rmi4_data, false); - } else if (event == FB_EVENT_BLANK) { - transition = evdata->data; - if (*transition == FB_BLANK_POWERDOWN) { - synaptics_rmi4_suspend( - &rmi4_data->pdev->dev); - rmi4_data->fb_ready = false; - } else if (*transition == FB_BLANK_UNBLANK) { - synaptics_rmi4_resume( - &rmi4_data->pdev->dev); - rmi4_data->fb_ready = true; - } - } - } - } - - return 0; -} -#endif - -#ifdef USE_EARLYSUSPEND -static void synaptics_rmi4_early_suspend(struct early_suspend *h) -{ - struct synaptics_rmi4_exp_fhandler *exp_fhandler; - struct synaptics_rmi4_data *rmi4_data = - container_of(h, struct synaptics_rmi4_data, - early_suspend); - - if (rmi4_data->stay_awake) - return; - - /* - * During early suspend/late resume, the driver doesn't access xPU/SMMU - * protected HW resources. So, there is no compelling need to block, - * but notifying the userspace that a power event has occurred is - * enough. Hence 'blocking' variable can be set to false. - */ - synaptics_secure_touch_stop(rmi4_data, false); - - if (rmi4_data->enable_wakeup_gesture) { - synaptics_rmi4_wakeup_gesture(rmi4_data, true); - enable_irq_wake(rmi4_data->irq); - goto exit; - } - - synaptics_rmi4_irq_enable(rmi4_data, false, false); - synaptics_rmi4_sleep_enable(rmi4_data, true); - synaptics_rmi4_free_fingers(rmi4_data); - -exit: - mutex_lock(&exp_data.mutex); - if (!list_empty(&exp_data.list)) { - list_for_each_entry(exp_fhandler, &exp_data.list, link) - if (exp_fhandler->exp_fn->early_suspend != NULL) - exp_fhandler->exp_fn->early_suspend(rmi4_data); - } - mutex_unlock(&exp_data.mutex); - - rmi4_data->suspend = true; - - return; -} - -static void synaptics_rmi4_late_resume(struct early_suspend *h) -{ -#ifdef FB_READY_RESET - int retval; -#endif - struct synaptics_rmi4_exp_fhandler *exp_fhandler; - struct synaptics_rmi4_data *rmi4_data = - container_of(h, struct synaptics_rmi4_data, - early_suspend); - - if (rmi4_data->stay_awake) - return; - - synaptics_secure_touch_stop(rmi4_data, false); - - if (rmi4_data->enable_wakeup_gesture) { - synaptics_rmi4_wakeup_gesture(rmi4_data, false); - disable_irq_wake(rmi4_data->irq); - goto exit; - } - - rmi4_data->current_page = MASK_8BIT; - - if (rmi4_data->suspend) { - synaptics_rmi4_sleep_enable(rmi4_data, false); - synaptics_rmi4_irq_enable(rmi4_data, true, false); - } - -exit: -#ifdef FB_READY_RESET - if (rmi4_data->suspend) { - retval = synaptics_rmi4_reset_device(rmi4_data, false); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to issue reset command\n", - __func__); - } - } -#endif - mutex_lock(&exp_data.mutex); - if (!list_empty(&exp_data.list)) { - list_for_each_entry(exp_fhandler, &exp_data.list, link) - if (exp_fhandler->exp_fn->late_resume != NULL) - exp_fhandler->exp_fn->late_resume(rmi4_data); - } - mutex_unlock(&exp_data.mutex); - - rmi4_data->suspend = false; - - return; -} -#endif - -static int synaptics_rmi4_suspend(struct device *dev) -{ - struct synaptics_rmi4_exp_fhandler *exp_fhandler; - struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); - int retval; - - if (rmi4_data->stay_awake) - return 0; - - synaptics_secure_touch_stop(rmi4_data, true); - - if (rmi4_data->enable_wakeup_gesture) { - synaptics_rmi4_wakeup_gesture(rmi4_data, true); - enable_irq_wake(rmi4_data->irq); - goto exit; - } - - if (!rmi4_data->suspend) { - synaptics_rmi4_irq_enable(rmi4_data, false, false); - synaptics_rmi4_sleep_enable(rmi4_data, true); - synaptics_rmi4_free_fingers(rmi4_data); - } - - if (rmi4_data->ts_pinctrl) { - retval = pinctrl_select_state(rmi4_data->ts_pinctrl, - rmi4_data->pinctrl_state_suspend); - if (retval < 0) - dev_err(dev, "Cannot get idle pinctrl state\n"); - goto err_pinctrl; - } -exit: - mutex_lock(&exp_data.mutex); - if (!list_empty(&exp_data.list)) { - list_for_each_entry(exp_fhandler, &exp_data.list, link) - if (exp_fhandler->exp_fn->suspend != NULL) - exp_fhandler->exp_fn->suspend(rmi4_data); - } - mutex_unlock(&exp_data.mutex); - - if (!rmi4_data->suspend) { - synaptics_rmi4_enable_reg(rmi4_data, false); - synaptics_rmi4_get_reg(rmi4_data, false); - } - rmi4_data->suspend = true; - - return 0; - -err_pinctrl: - synaptics_rmi4_sleep_enable(rmi4_data, false); - synaptics_rmi4_irq_enable(rmi4_data, true, false); - return retval; - -} - -static int synaptics_rmi4_resume(struct device *dev) -{ -#ifdef FB_READY_RESET - int retval; -#endif - struct synaptics_rmi4_exp_fhandler *exp_fhandler; - struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); - - if (rmi4_data->stay_awake) - return 0; - - synaptics_secure_touch_stop(rmi4_data, true); - - if (rmi4_data->enable_wakeup_gesture) { - synaptics_rmi4_wakeup_gesture(rmi4_data, false); - disable_irq_wake(rmi4_data->irq); - goto exit; - } - - rmi4_data->current_page = MASK_8BIT; - - if (rmi4_data->suspend) { - synaptics_rmi4_get_reg(rmi4_data, true); - synaptics_rmi4_enable_reg(rmi4_data, true); - } - - synaptics_rmi4_sleep_enable(rmi4_data, false); - synaptics_rmi4_irq_enable(rmi4_data, true, false); - if (rmi4_data->ts_pinctrl) { - retval = pinctrl_select_state(rmi4_data->ts_pinctrl, - rmi4_data->pinctrl_state_active); - if (retval < 0) - dev_err(dev, "Cannot get default pinctrl state\n"); - } - -exit: -#ifdef FB_READY_RESET - retval = synaptics_rmi4_reset_device(rmi4_data, false); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to issue reset command\n", - __func__); - } -#endif - mutex_lock(&exp_data.mutex); - if (!list_empty(&exp_data.list)) { - list_for_each_entry(exp_fhandler, &exp_data.list, link) - if (exp_fhandler->exp_fn->resume != NULL) - exp_fhandler->exp_fn->resume(rmi4_data); - } - mutex_unlock(&exp_data.mutex); - - rmi4_data->suspend = false; - - return 0; -} - -#ifdef CONFIG_PM -static const struct dev_pm_ops synaptics_rmi4_dev_pm_ops = { -#ifndef CONFIG_FB - .suspend = synaptics_rmi4_suspend, - .resume = synaptics_rmi4_resume, -#endif -}; -#endif - -static struct platform_driver synaptics_rmi4_driver = { - .driver = { - .name = PLATFORM_DRIVER_NAME, - .owner = THIS_MODULE, -#ifdef CONFIG_PM - .pm = &synaptics_rmi4_dev_pm_ops, -#endif - }, - .probe = synaptics_rmi4_probe, - .remove = synaptics_rmi4_remove, -}; - -static int __init synaptics_rmi4_init(void) -{ - int retval; - - retval = synaptics_rmi4_bus_init_v26(); - if (retval) - return retval; - - return platform_driver_register(&synaptics_rmi4_driver); -} - -static void __exit synaptics_rmi4_exit(void) -{ - platform_driver_unregister(&synaptics_rmi4_driver); - - synaptics_rmi4_bus_exit_v26(); - - return; -} - -module_init(synaptics_rmi4_init); -module_exit(synaptics_rmi4_exit); - -MODULE_AUTHOR("Synaptics, Inc."); -MODULE_DESCRIPTION("Synaptics DSX Touch Driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h deleted file mode 100644 index 7d92791afb25..000000000000 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h +++ /dev/null @@ -1,500 +0,0 @@ -/* - * Synaptics DSX touchscreen driver - * - * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved. - * - * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com> - * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com> - * 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 as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - * - * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS - * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, - * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS. - * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION - * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED - * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES - * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' - * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. - * DOLLARS. - */ - -#ifndef _SYNAPTICS_DSX_RMI4_H_ -#define _SYNAPTICS_DSX_RMI4_H_ - -#define SYNAPTICS_DS4 (1 << 0) -#define SYNAPTICS_DS5 (1 << 1) -#define SYNAPTICS_DSX_DRIVER_PRODUCT (SYNAPTICS_DS4 | SYNAPTICS_DS5) -#define SYNAPTICS_DSX_DRIVER_VERSION 0x2061 - -#include <linux/version.h> -#ifdef CONFIG_FB -#include <linux/notifier.h> -#include <linux/fb.h> -#endif -#ifdef CONFIG_HAS_EARLYSUSPEND -#include <linux/earlysuspend.h> -#endif - -#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26) -#include <linux/completion.h> -#include <linux/atomic.h> -#include <linux/pm_runtime.h> -#include <linux/clk.h> -#endif - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)) -#define KERNEL_ABOVE_2_6_38 -#endif - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) -#define KERNEL_ABOVE_3_6 -#endif - -#ifdef KERNEL_ABOVE_2_6_38 -#define sstrtoul(...) kstrtoul(__VA_ARGS__) -#else -#define sstrtoul(...) strict_strtoul(__VA_ARGS__) -#endif - -#define PDT_PROPS (0X00EF) -#define PDT_START (0x00E9) -#define PDT_END (0x00D0) -#define PDT_ENTRY_SIZE (0x0006) -#define PAGES_TO_SERVICE (10) -#define PAGE_SELECT_LEN (2) -#define ADDRESS_WORD_LEN (2) - -#define SYNAPTICS_RMI4_F01 (0x01) -#define SYNAPTICS_RMI4_F11 (0x11) -#define SYNAPTICS_RMI4_F12 (0x12) -#define SYNAPTICS_RMI4_F1A (0x1A) -#define SYNAPTICS_RMI4_F34 (0x34) -#define SYNAPTICS_RMI4_F35 (0x35) -#define SYNAPTICS_RMI4_F38 (0x38) -#define SYNAPTICS_RMI4_F51 (0x51) -#define SYNAPTICS_RMI4_F54 (0x54) -#define SYNAPTICS_RMI4_F55 (0x55) -#define SYNAPTICS_RMI4_FDB (0xDB) - -#define PRODUCT_INFO_SIZE 2 -#define PRODUCT_ID_SIZE 10 -#define BUILD_ID_SIZE 3 - -#define F12_FINGERS_TO_SUPPORT 10 -#define F12_NO_OBJECT_STATUS 0x00 -#define F12_FINGER_STATUS 0x01 -#define F12_ACTIVE_STYLUS_STATUS 0x02 -#define F12_PALM_STATUS 0x03 -#define F12_HOVERING_FINGER_STATUS 0x05 -#define F12_GLOVED_FINGER_STATUS 0x06 -#define F12_NARROW_OBJECT_STATUS 0x07 -#define F12_HAND_EDGE_STATUS 0x08 -#define F12_COVER_STATUS 0x0A -#define F12_STYLUS_STATUS 0x0B -#define F12_ERASER_STATUS 0x0C -#define F12_SMALL_OBJECT_STATUS 0x0D - -#define F12_GESTURE_DETECTION_LEN 5 - -#define MAX_NUMBER_OF_BUTTONS 4 -#define MAX_INTR_REGISTERS 4 - -#define MASK_16BIT 0xFFFF -#define MASK_8BIT 0xFF -#define MASK_7BIT 0x7F -#define MASK_6BIT 0x3F -#define MASK_5BIT 0x1F -#define MASK_4BIT 0x0F -#define MASK_3BIT 0x07 -#define MASK_2BIT 0x03 -#define MASK_1BIT 0x01 - -#define PINCTRL_STATE_ACTIVE "pmx_ts_active" -#define PINCTRL_STATE_SUSPEND "pmx_ts_suspend" -#define PINCTRL_STATE_RELEASE "pmx_ts_release" -enum exp_fn { - RMI_DEV = 0, - RMI_FW_UPDATER, - RMI_TEST_REPORTING, - RMI_PROXIMITY, - RMI_ACTIVE_PEN, - RMI_GESTURE, - RMI_VIDEO, - RMI_DEBUG, - RMI_LAST, -}; - -/* - * struct synaptics_rmi4_fn_desc - function descriptor fields in PDT entry - * @query_base_addr: base address for query registers - * @cmd_base_addr: base address for command registers - * @ctrl_base_addr: base address for control registers - * @data_base_addr: base address for data registers - * @intr_src_count: number of interrupt sources - * @fn_version: version of function - * @fn_number: function number - */ -struct synaptics_rmi4_fn_desc { - union { - struct { - unsigned char query_base_addr; - unsigned char cmd_base_addr; - unsigned char ctrl_base_addr; - unsigned char data_base_addr; - unsigned char intr_src_count:3; - unsigned char reserved_1:2; - unsigned char fn_version:2; - unsigned char reserved_2:1; - unsigned char fn_number; - } __packed; - unsigned char data[6]; - }; -}; - -/* - * synaptics_rmi4_fn_full_addr - full 16-bit base addresses - * @query_base: 16-bit base address for query registers - * @cmd_base: 16-bit base address for command registers - * @ctrl_base: 16-bit base address for control registers - * @data_base: 16-bit base address for data registers - */ -struct synaptics_rmi4_fn_full_addr { - unsigned short query_base; - unsigned short cmd_base; - unsigned short ctrl_base; - unsigned short data_base; -}; - -/* - * struct synaptics_rmi4_f11_extra_data - extra data of F$11 - * @data38_offset: offset to F11_2D_DATA38 register - */ -struct synaptics_rmi4_f11_extra_data { - unsigned char data38_offset; -}; - -/* - * struct synaptics_rmi4_f12_extra_data - extra data of F$12 - * @data1_offset: offset to F12_2D_DATA01 register - * @data4_offset: offset to F12_2D_DATA04 register - * @data15_offset: offset to F12_2D_DATA15 register - * @data15_size: size of F12_2D_DATA15 register - * @data15_data: buffer for reading F12_2D_DATA15 register - * @data23_offset: offset to F12_2D_DATA23 register - * @data23_size: size of F12_2D_DATA23 register - * @data23_data: buffer for reading F12_2D_DATA23 register - * @ctrl20_offset: offset to F12_2D_CTRL20 register - */ -struct synaptics_rmi4_f12_extra_data { - unsigned char data1_offset; - unsigned char data4_offset; - unsigned char data15_offset; - unsigned char data15_size; - unsigned char data15_data[(F12_FINGERS_TO_SUPPORT + 7) / 8]; - unsigned char data23_offset; - unsigned char data23_size; - unsigned char data23_data[F12_FINGERS_TO_SUPPORT]; - unsigned char ctrl20_offset; -}; - -/* - * struct synaptics_rmi4_fn - RMI function handler - * @fn_number: function number - * @num_of_data_sources: number of data sources - * @num_of_data_points: maximum number of fingers supported - * @intr_reg_num: index to associated interrupt register - * @intr_mask: interrupt mask - * @full_addr: full 16-bit base addresses of function registers - * @link: linked list for function handlers - * @data_size: size of private data - * @data: pointer to private data - * @extra: pointer to extra data - */ -struct synaptics_rmi4_fn { - unsigned char fn_number; - unsigned char num_of_data_sources; - unsigned char num_of_data_points; - unsigned char intr_reg_num; - unsigned char intr_mask; - struct synaptics_rmi4_fn_full_addr full_addr; - struct list_head link; - int data_size; - void *data; - void *extra; -}; - -/* - * struct synaptics_rmi4_device_info - device information - * @version_major: RMI protocol major version number - * @version_minor: RMI protocol minor version number - * @manufacturer_id: manufacturer ID - * @product_props: product properties - * @product_info: product information - * @product_id_string: product ID - * @build_id: firmware build ID - * @support_fn_list: linked list for function handlers - */ -struct synaptics_rmi4_device_info { - unsigned int version_major; - unsigned int version_minor; - unsigned char manufacturer_id; - unsigned char product_props; - unsigned char product_info[PRODUCT_INFO_SIZE]; - unsigned char product_id_string[PRODUCT_ID_SIZE + 1]; - unsigned char build_id[BUILD_ID_SIZE]; - struct list_head support_fn_list; -}; - -/* - * struct synaptics_rmi4_data - RMI4 device instance data - * @pdev: pointer to platform device - * @input_dev: pointer to associated input device - * @stylus_dev: pointer to associated stylus device - * @hw_if: pointer to hardware interface data - * @rmi4_mod_info: device information - * @board_prop_dir: /sys/board_properties directory for virtual key map file - * @pwr_reg: pointer to regulator for power control - * @bus_reg: pointer to regulator for bus pullup control - * @rmi4_reset_mutex: mutex for software reset - * @rmi4_report_mutex: mutex for input event reporting - * @rmi4_io_ctrl_mutex: mutex for communication interface I/O - * @rmi4_exp_init_mutex: mutex for expansion function module initialization - * @rb_work: work for rebuilding input device - * @rb_workqueue: workqueue for rebuilding input device - * @fb_notifier: framebuffer notifier client - * @reset_work: work for issuing reset after display framebuffer ready - * @reset_workqueue: workqueue for issuing reset after display framebuffer ready - * @early_suspend: early suspend power management - * @current_page: current RMI page for register access - * @button_0d_enabled: switch for enabling 0d button support - * @num_of_tx: number of Tx channels for 2D touch - * @num_of_rx: number of Rx channels for 2D touch - * @num_of_fingers: maximum number of fingers for 2D touch - * @max_touch_width: maximum touch width - * @report_enable: input data to report for F$12 - * @no_sleep_setting: default setting of NoSleep in F01_RMI_CTRL00 register - * @gesture_detection: detected gesture type and properties - * @intr_mask: interrupt enable mask - * @button_txrx_mapping: Tx Rx mapping of 0D buttons - * @num_of_intr_regs: number of interrupt registers - * @f01_query_base_addr: query base address for f$01 - * @f01_cmd_base_addr: command base address for f$01 - * @f01_ctrl_base_addr: control base address for f$01 - * @f01_data_base_addr: data base address for f$01 - * @firmware_id: firmware build ID - * @irq: attention interrupt - * @sensor_max_x: maximum x coordinate for 2D touch - * @sensor_max_y: maximum y coordinate for 2D touch - * @flash_prog_mode: flag to indicate flash programming mode status - * @irq_enabled: flag to indicate attention interrupt enable status - * @fingers_on_2d: flag to indicate presence of fingers in 2D area - * @suspend: flag to indicate whether in suspend state - * @sensor_sleep: flag to indicate sleep state of sensor - * @stay_awake: flag to indicate whether to stay awake during suspend - * @fb_ready: flag to indicate whether display framebuffer in ready state - * @f11_wakeup_gesture: flag to indicate support for wakeup gestures in F$11 - * @f12_wakeup_gesture: flag to indicate support for wakeup gestures in F$12 - * @enable_wakeup_gesture: flag to indicate usage of wakeup gestures - * @wedge_sensor: flag to indicate use of wedge sensor - * @report_pressure: flag to indicate reporting of pressure data - * @stylus_enable: flag to indicate reporting of stylus data - * @eraser_enable: flag to indicate reporting of eraser data - * @external_afe_buttons: flag to indicate presence of external AFE buttons - * @reset_device: pointer to device reset function - * @irq_enable: pointer to interrupt enable function - * @sleep_enable: pointer to sleep enable function - * @report_touch: pointer to touch reporting function - */ -struct synaptics_rmi4_data { - struct platform_device *pdev; - struct input_dev *input_dev; - struct input_dev *stylus_dev; - const struct synaptics_dsx_hw_interface *hw_if; - struct synaptics_rmi4_device_info rmi4_mod_info; - struct kobject *board_prop_dir; - struct regulator *pwr_reg; - struct regulator *bus_reg; - struct mutex rmi4_reset_mutex; - struct mutex rmi4_report_mutex; - struct mutex rmi4_io_ctrl_mutex; - struct mutex rmi4_exp_init_mutex; - struct delayed_work rb_work; - struct workqueue_struct *rb_workqueue; -#ifdef CONFIG_FB - struct work_struct fb_notify_work; - struct notifier_block fb_notifier; - struct work_struct reset_work; - struct workqueue_struct *reset_workqueue; -#endif -#ifdef CONFIG_HAS_EARLYSUSPEND - struct early_suspend early_suspend; -#endif - unsigned char current_page; - unsigned char button_0d_enabled; - unsigned char num_of_tx; - unsigned char num_of_rx; - unsigned char num_of_fingers; - unsigned char max_touch_width; - unsigned char report_enable; - unsigned char no_sleep_setting; - unsigned char gesture_detection[F12_GESTURE_DETECTION_LEN]; - unsigned char intr_mask[MAX_INTR_REGISTERS]; - unsigned char *button_txrx_mapping; - unsigned short num_of_intr_regs; - unsigned short f01_query_base_addr; - unsigned short f01_cmd_base_addr; - unsigned short f01_ctrl_base_addr; - unsigned short f01_data_base_addr; - unsigned int firmware_id; - int irq; - int sensor_max_x; - int sensor_max_y; - bool flash_prog_mode; - bool irq_enabled; - bool fingers_on_2d; - bool suspend; - bool sensor_sleep; - bool stay_awake; - bool fb_ready; - bool f11_wakeup_gesture; - bool f12_wakeup_gesture; - bool enable_wakeup_gesture; - bool wedge_sensor; - bool report_pressure; - bool stylus_enable; - bool eraser_enable; - bool external_afe_buttons; - int (*reset_device)(struct synaptics_rmi4_data *rmi4_data, - bool rebuild); - int (*irq_enable)(struct synaptics_rmi4_data *rmi4_data, bool enable, - bool attn_only); - void (*sleep_enable)(struct synaptics_rmi4_data *rmi4_data, - bool enable); - void (*report_touch)(struct synaptics_rmi4_data *rmi4_data, - struct synaptics_rmi4_fn *fhandler); - struct pinctrl *ts_pinctrl; - struct pinctrl_state *pinctrl_state_active; - struct pinctrl_state *pinctrl_state_suspend; - struct pinctrl_state *pinctrl_state_release; -#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26) - atomic_t st_enabled; - atomic_t st_pending_irqs; - struct completion st_powerdown; - struct completion st_irq_processed; - bool st_initialized; - struct clk *core_clk; - struct clk *iface_clk; -#endif -}; - -struct synaptics_dsx_bus_access { - unsigned char type; - int (*read)(struct synaptics_rmi4_data *rmi4_data, unsigned short addr, - unsigned char *data, unsigned short length); - int (*write)(struct synaptics_rmi4_data *rmi4_data, unsigned short addr, - unsigned char *data, unsigned short length); -#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26) - int (*get)(struct synaptics_rmi4_data *rmi4_data); - void (*put)(struct synaptics_rmi4_data *rmi4_data); -#endif -}; - -struct synaptics_dsx_hw_interface { - struct synaptics_dsx_board_data *board_data; - const struct synaptics_dsx_bus_access *bus_access; - int (*bl_hw_init)(struct synaptics_rmi4_data *rmi4_data); - int (*ui_hw_init)(struct synaptics_rmi4_data *rmi4_data); -}; - -struct synaptics_rmi4_exp_fn { - enum exp_fn fn_type; - int (*init)(struct synaptics_rmi4_data *rmi4_data); - void (*remove)(struct synaptics_rmi4_data *rmi4_data); - void (*reset)(struct synaptics_rmi4_data *rmi4_data); - void (*reinit)(struct synaptics_rmi4_data *rmi4_data); - void (*early_suspend)(struct synaptics_rmi4_data *rmi4_data); - void (*suspend)(struct synaptics_rmi4_data *rmi4_data); - void (*resume)(struct synaptics_rmi4_data *rmi4_data); - void (*late_resume)(struct synaptics_rmi4_data *rmi4_data); - void (*attn)(struct synaptics_rmi4_data *rmi4_data, - unsigned char intr_mask); -}; - -int synaptics_rmi4_bus_init_v26(void); - -void synaptics_rmi4_bus_exit_v26(void); - -void synaptics_rmi4_new_function(struct synaptics_rmi4_exp_fn *exp_fn_module, - bool insert); - -int synaptics_fw_updater(const unsigned char *fw_data); - -static inline int synaptics_rmi4_reg_read( - struct synaptics_rmi4_data *rmi4_data, - unsigned short addr, - unsigned char *data, - unsigned short len) -{ - return rmi4_data->hw_if->bus_access->read(rmi4_data, addr, data, len); -} - -static inline int synaptics_rmi4_reg_write( - struct synaptics_rmi4_data *rmi4_data, - unsigned short addr, - unsigned char *data, - unsigned short len) -{ - return rmi4_data->hw_if->bus_access->write(rmi4_data, addr, data, len); -} - -#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26) -static inline int synaptics_rmi4_bus_get(struct synaptics_rmi4_data *rmi4_data) -{ - return rmi4_data->hw_if->bus_access->get(rmi4_data); -} -static inline void synaptics_rmi4_bus_put(struct synaptics_rmi4_data *rmi4_data) -{ - rmi4_data->hw_if->bus_access->put(rmi4_data); -} -#endif - -static inline int secure_memcpy(unsigned char *dest, unsigned int dest_size, - const unsigned char *src, unsigned int src_size, - unsigned int count) -{ - if (dest == NULL || src == NULL) - return -EINVAL; - - if (count > dest_size || count > src_size) - return -EINVAL; - - memcpy((void *)dest, (const void *)src, count); - - return 0; -} - -static inline void batohs(unsigned short *dest, unsigned char *src) -{ - *dest = src[1] * 0x100 + src[0]; -} - -static inline void hstoba(unsigned char *dest, unsigned short src) -{ - dest[0] = src % 0x100; - dest[1] = src / 0x100; -} - -#endif diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c deleted file mode 100644 index 168318f85e53..000000000000 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c +++ /dev/null @@ -1,4440 +0,0 @@ -/* - * Synaptics DSX touchscreen driver - * - * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved. - * - * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com> - * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com> - * - * 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. - * - * 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. - * - * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS - * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, - * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS. - * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION - * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED - * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES - * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' - * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. - * DOLLARS. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/input.h> -#include <linux/firmware.h> -#include <linux/platform_device.h> -#include <linux/input/synaptics_dsx_v2_6.h> -#include "synaptics_dsx_core.h" - -#define FW_IMAGE_NAME "synaptics/startup_fw_update.img" -/* -#define DO_STARTUP_FW_UPDATE -*/ -/* -#ifdef DO_STARTUP_FW_UPDATE -#ifdef CONFIG_FB -#define WAIT_FOR_FB_READY -#define FB_READY_WAIT_MS 100 -#define FB_READY_TIMEOUT_S 30 -#endif -#endif -*/ -#define FORCE_UPDATE false -#define DO_LOCKDOWN false - -#define MAX_IMAGE_NAME_LEN 256 -#define MAX_FIRMWARE_ID_LEN 10 - -#define IMAGE_HEADER_VERSION_05 0x05 -#define IMAGE_HEADER_VERSION_06 0x06 -#define IMAGE_HEADER_VERSION_10 0x10 - -#define IMAGE_AREA_OFFSET 0x100 -#define LOCKDOWN_SIZE 0x50 - -#define V5V6_BOOTLOADER_ID_OFFSET 0 -#define V5V6_CONFIG_ID_SIZE 4 - -#define V5_PROPERTIES_OFFSET 2 -#define V5_BLOCK_SIZE_OFFSET 3 -#define V5_BLOCK_COUNT_OFFSET 5 -#define V5_BLOCK_NUMBER_OFFSET 0 -#define V5_BLOCK_DATA_OFFSET 2 - -#define V6_PROPERTIES_OFFSET 1 -#define V6_BLOCK_SIZE_OFFSET 2 -#define V6_BLOCK_COUNT_OFFSET 3 -#define V6_PROPERTIES_2_OFFSET 4 -#define V6_GUEST_CODE_BLOCK_COUNT_OFFSET 5 -#define V6_BLOCK_NUMBER_OFFSET 0 -#define V6_BLOCK_DATA_OFFSET 1 -#define V6_FLASH_COMMAND_OFFSET 2 -#define V6_FLASH_STATUS_OFFSET 3 - -#define V7_CONFIG_ID_SIZE 32 - -#define V7_FLASH_STATUS_OFFSET 0 -#define V7_PARTITION_ID_OFFSET 1 -#define V7_BLOCK_NUMBER_OFFSET 2 -#define V7_TRANSFER_LENGTH_OFFSET 3 -#define V7_COMMAND_OFFSET 4 -#define V7_PAYLOAD_OFFSET 5 - -#define V7_PARTITION_SUPPORT_BYTES 4 - -#define F35_ERROR_CODE_OFFSET 0 -#define F35_CHUNK_NUM_LSB_OFFSET 0 -#define F35_CHUNK_NUM_MSB_OFFSET 1 -#define F35_CHUNK_DATA_OFFSET 2 -#define F35_CHUNK_COMMAND_OFFSET 18 - -#define F35_CHUNK_SIZE 16 -#define F35_ERASE_ALL_WAIT_MS 3000 -#define F35_RESET_WAIT_MS 250 - -#define SLEEP_MODE_NORMAL (0x00) -#define SLEEP_MODE_SENSOR_SLEEP (0x01) -#define SLEEP_MODE_RESERVED0 (0x02) -#define SLEEP_MODE_RESERVED1 (0x03) - -#define ENABLE_WAIT_MS (1 * 1000) -#define WRITE_WAIT_MS (3 * 1000) -#define ERASE_WAIT_MS (5 * 1000) - -#define MIN_SLEEP_TIME_US 50 -#define MAX_SLEEP_TIME_US 100 - -#define INT_DISABLE_WAIT_MS 20 -#define ENTER_FLASH_PROG_WAIT_MS 20 - -static int fwu_do_reflash(void); - -static int fwu_recovery_check_status(void); - -static ssize_t fwu_sysfs_show_image(struct file *data_file, - struct kobject *kobj, struct bin_attribute *attributes, - char *buf, loff_t pos, size_t count); - -static ssize_t fwu_sysfs_store_image(struct file *data_file, - struct kobject *kobj, struct bin_attribute *attributes, - char *buf, loff_t pos, size_t count); - -static ssize_t fwu_sysfs_do_recovery_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t fwu_sysfs_do_reflash_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t fwu_sysfs_write_config_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t fwu_sysfs_read_config_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t fwu_sysfs_config_area_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t fwu_sysfs_image_name_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t fwu_sysfs_image_size_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t fwu_sysfs_block_size_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t fwu_sysfs_firmware_block_count_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t fwu_sysfs_configuration_block_count_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t fwu_sysfs_disp_config_block_count_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t fwu_sysfs_perm_config_block_count_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t fwu_sysfs_bl_config_block_count_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t fwu_sysfs_guest_code_block_count_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t fwu_sysfs_write_guest_code_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -enum f34_version { - F34_V0 = 0, - F34_V1, - F34_V2, -}; - -enum bl_version { - BL_V5 = 5, - BL_V6 = 6, - BL_V7 = 7, - BL_V8 = 8, -}; - -enum flash_area { - NONE = 0, - UI_FIRMWARE, - UI_CONFIG, -}; - -enum update_mode { - NORMAL = 1, - FORCE = 2, - LOCKDOWN = 8, -}; - -enum config_area { - UI_CONFIG_AREA = 0, - PM_CONFIG_AREA, - BL_CONFIG_AREA, - DP_CONFIG_AREA, - FLASH_CONFIG_AREA, -}; - -enum v7_status { - SUCCESS = 0x00, - DEVICE_NOT_IN_BOOTLOADER_MODE, - INVALID_PARTITION, - INVALID_COMMAND, - INVALID_BLOCK_OFFSET, - INVALID_TRANSFER, - NOT_ERASED, - FLASH_PROGRAMMING_KEY_INCORRECT, - BAD_PARTITION_TABLE, - CHECKSUM_FAILED, - FLASH_HARDWARE_FAILURE = 0x1f, -}; - -enum v7_partition_id { - BOOTLOADER_PARTITION = 0x01, - DEVICE_CONFIG_PARTITION, - FLASH_CONFIG_PARTITION, - MANUFACTURING_BLOCK_PARTITION, - GUEST_SERIALIZATION_PARTITION, - GLOBAL_PARAMETERS_PARTITION, - CORE_CODE_PARTITION, - CORE_CONFIG_PARTITION, - GUEST_CODE_PARTITION, - DISPLAY_CONFIG_PARTITION, -}; - -enum v7_flash_command { - CMD_V7_IDLE = 0x00, - CMD_V7_ENTER_BL, - CMD_V7_READ, - CMD_V7_WRITE, - CMD_V7_ERASE, - CMD_V7_ERASE_AP, - CMD_V7_SENSOR_ID, -}; - -enum v5v6_flash_command { - CMD_V5V6_IDLE = 0x0, - CMD_V5V6_WRITE_FW = 0x2, - CMD_V5V6_ERASE_ALL = 0x3, - CMD_V5V6_WRITE_LOCKDOWN = 0x4, - CMD_V5V6_READ_CONFIG = 0x5, - CMD_V5V6_WRITE_CONFIG = 0x6, - CMD_V5V6_ERASE_UI_CONFIG = 0x7, - CMD_V5V6_ERASE_BL_CONFIG = 0x9, - CMD_V5V6_ERASE_DISP_CONFIG = 0xa, - CMD_V5V6_ERASE_GUEST_CODE = 0xb, - CMD_V5V6_WRITE_GUEST_CODE = 0xc, - CMD_V5V6_ENABLE_FLASH_PROG = 0xf, -}; - -enum flash_command { - CMD_IDLE = 0, - CMD_WRITE_FW, - CMD_WRITE_CONFIG, - CMD_WRITE_LOCKDOWN, - CMD_WRITE_GUEST_CODE, - CMD_READ_CONFIG, - CMD_ERASE_ALL, - CMD_ERASE_UI_FIRMWARE, - CMD_ERASE_UI_CONFIG, - CMD_ERASE_BL_CONFIG, - CMD_ERASE_DISP_CONFIG, - CMD_ERASE_FLASH_CONFIG, - CMD_ERASE_GUEST_CODE, - CMD_ENABLE_FLASH_PROG, -}; - -enum f35_flash_command { - CMD_F35_IDLE = 0x0, - CMD_F35_RESERVED = 0x1, - CMD_F35_WRITE_CHUNK = 0x2, - CMD_F35_ERASE_ALL = 0x3, - CMD_F35_RESET = 0x10, -}; - -enum container_id { - TOP_LEVEL_CONTAINER = 0, - UI_CONTAINER, - UI_CONFIG_CONTAINER, - BL_CONTAINER, - BL_IMAGE_CONTAINER, - BL_CONFIG_CONTAINER, - BL_LOCKDOWN_INFO_CONTAINER, - PERMANENT_CONFIG_CONTAINER, - GUEST_CODE_CONTAINER, - BL_PROTOCOL_DESCRIPTOR_CONTAINER, - UI_PROTOCOL_DESCRIPTOR_CONTAINER, - RMI_SELF_DISCOVERY_CONTAINER, - RMI_PAGE_CONTENT_CONTAINER, - GENERAL_INFORMATION_CONTAINER, - DEVICE_CONFIG_CONTAINER, - FLASH_CONFIG_CONTAINER, - GUEST_SERIALIZATION_CONTAINER, - GLOBAL_PARAMETERS_CONTAINER, - CORE_CODE_CONTAINER, - CORE_CONFIG_CONTAINER, - DISPLAY_CONFIG_CONTAINER, -}; - -struct pdt_properties { - union { - struct { - unsigned char reserved_1:6; - unsigned char has_bsr:1; - unsigned char reserved_2:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct partition_table { - unsigned char partition_id:5; - unsigned char byte_0_reserved:3; - unsigned char byte_1_reserved; - unsigned char partition_length_7_0; - unsigned char partition_length_15_8; - unsigned char start_physical_address_7_0; - unsigned char start_physical_address_15_8; - unsigned char partition_properties_7_0; - unsigned char partition_properties_15_8; -} __packed; - -struct f01_device_control { - union { - struct { - unsigned char sleep_mode:2; - unsigned char nosleep:1; - unsigned char reserved:2; - unsigned char charger_connected:1; - unsigned char report_rate:1; - unsigned char configured:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f34_v7_query_0 { - union { - struct { - unsigned char subpacket_1_size:3; - unsigned char has_config_id:1; - unsigned char f34_query0_b4:1; - unsigned char has_thqa:1; - unsigned char f34_query0_b6__7:2; - } __packed; - unsigned char data[1]; - }; -}; - -struct f34_v7_query_1_7 { - union { - struct { - /* query 1 */ - unsigned char bl_minor_revision; - unsigned char bl_major_revision; - - /* query 2 */ - unsigned char bl_fw_id_7_0; - unsigned char bl_fw_id_15_8; - unsigned char bl_fw_id_23_16; - unsigned char bl_fw_id_31_24; - - /* query 3 */ - unsigned char minimum_write_size; - unsigned char block_size_7_0; - unsigned char block_size_15_8; - unsigned char flash_page_size_7_0; - unsigned char flash_page_size_15_8; - - /* query 4 */ - unsigned char adjustable_partition_area_size_7_0; - unsigned char adjustable_partition_area_size_15_8; - - /* query 5 */ - unsigned char flash_config_length_7_0; - unsigned char flash_config_length_15_8; - - /* query 6 */ - unsigned char payload_length_7_0; - unsigned char payload_length_15_8; - - /* query 7 */ - unsigned char f34_query7_b0:1; - unsigned char has_bootloader:1; - unsigned char has_device_config:1; - unsigned char has_flash_config:1; - unsigned char has_manufacturing_block:1; - unsigned char has_guest_serialization:1; - unsigned char has_global_parameters:1; - unsigned char has_core_code:1; - unsigned char has_core_config:1; - unsigned char has_guest_code:1; - unsigned char has_display_config:1; - unsigned char f34_query7_b11__15:5; - unsigned char f34_query7_b16__23; - unsigned char f34_query7_b24__31; - } __packed; - unsigned char data[21]; - }; -}; - -struct f34_v7_data0 { - union { - struct { - unsigned char operation_status:5; - unsigned char device_cfg_status:2; - unsigned char bl_mode:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f34_v7_data_1_5 { - union { - struct { - unsigned char partition_id:5; - unsigned char f34_data1_b5__7:3; - unsigned char block_offset_7_0; - unsigned char block_offset_15_8; - unsigned char transfer_length_7_0; - unsigned char transfer_length_15_8; - unsigned char command; - unsigned char payload_0; - unsigned char payload_1; - } __packed; - unsigned char data[8]; - }; -}; - -struct f34_v5v6_flash_properties { - union { - struct { - unsigned char reg_map:1; - unsigned char unlocked:1; - unsigned char has_config_id:1; - unsigned char has_pm_config:1; - unsigned char has_bl_config:1; - unsigned char has_disp_config:1; - unsigned char has_ctrl1:1; - unsigned char has_query4:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f34_v5v6_flash_properties_2 { - union { - struct { - unsigned char has_guest_code:1; - unsigned char reserved:7; - } __packed; - unsigned char data[1]; - }; -}; - -struct register_offset { - unsigned char properties; - unsigned char properties_2; - unsigned char block_size; - unsigned char block_count; - unsigned char gc_block_count; - unsigned char flash_status; - unsigned char partition_id; - unsigned char block_number; - unsigned char transfer_length; - unsigned char flash_cmd; - unsigned char payload; -}; - -struct block_count { - unsigned short ui_firmware; - unsigned short ui_config; - unsigned short dp_config; - unsigned short pm_config; - unsigned short fl_config; - unsigned short bl_image; - unsigned short bl_config; - unsigned short lockdown; - unsigned short guest_code; - unsigned short total_count; -}; - -struct physical_address { - unsigned short ui_firmware; - unsigned short ui_config; - unsigned short dp_config; - unsigned short fl_config; - unsigned short guest_code; -}; - -struct container_descriptor { - unsigned char content_checksum[4]; - unsigned char container_id[2]; - unsigned char minor_version; - unsigned char major_version; - unsigned char reserved_08; - unsigned char reserved_09; - unsigned char reserved_0a; - unsigned char reserved_0b; - unsigned char container_option_flags[4]; - unsigned char content_options_length[4]; - unsigned char content_options_address[4]; - unsigned char content_length[4]; - unsigned char content_address[4]; -}; - -struct image_header_10 { - unsigned char checksum[4]; - unsigned char reserved_04; - unsigned char reserved_05; - unsigned char minor_header_version; - unsigned char major_header_version; - unsigned char reserved_08; - unsigned char reserved_09; - unsigned char reserved_0a; - unsigned char reserved_0b; - unsigned char top_level_container_start_addr[4]; -}; - -struct image_header_05_06 { - /* 0x00 - 0x0f */ - unsigned char checksum[4]; - unsigned char reserved_04; - unsigned char reserved_05; - unsigned char options_firmware_id:1; - unsigned char options_bootloader:1; - unsigned char options_guest_code:1; - unsigned char options_tddi:1; - unsigned char options_reserved:4; - unsigned char header_version; - unsigned char firmware_size[4]; - unsigned char config_size[4]; - /* 0x10 - 0x1f */ - unsigned char product_id[PRODUCT_ID_SIZE]; - unsigned char package_id[2]; - unsigned char package_id_revision[2]; - unsigned char product_info[PRODUCT_INFO_SIZE]; - /* 0x20 - 0x2f */ - unsigned char bootloader_addr[4]; - unsigned char bootloader_size[4]; - unsigned char ui_addr[4]; - unsigned char ui_size[4]; - /* 0x30 - 0x3f */ - unsigned char ds_id[16]; - /* 0x40 - 0x4f */ - union { - struct { - unsigned char cstmr_product_id[PRODUCT_ID_SIZE]; - unsigned char reserved_4a_4f[6]; - }; - struct { - unsigned char dsp_cfg_addr[4]; - unsigned char dsp_cfg_size[4]; - unsigned char reserved_48_4f[8]; - }; - }; - /* 0x50 - 0x53 */ - unsigned char firmware_id[4]; -}; - -struct block_data { - unsigned int size; - const unsigned char *data; -}; - -struct image_metadata { - bool contains_firmware_id; - bool contains_bootloader; - bool contains_guest_code; - bool contains_disp_config; - bool contains_perm_config; - bool contains_flash_config; - unsigned int firmware_id; - unsigned int checksum; - unsigned int bootloader_size; - unsigned int disp_config_offset; - unsigned char bl_version; - unsigned char product_id[PRODUCT_ID_SIZE + 1]; - unsigned char cstmr_product_id[PRODUCT_ID_SIZE + 1]; - struct block_data bootloader; - struct block_data ui_firmware; - struct block_data ui_config; - struct block_data dp_config; - struct block_data pm_config; - struct block_data fl_config; - struct block_data bl_image; - struct block_data bl_config; - struct block_data lockdown; - struct block_data guest_code; - struct block_count blkcount; - struct physical_address phyaddr; -}; - -struct synaptics_rmi4_fwu_handle { - enum bl_version bl_version; - bool initialized; - bool in_bl_mode; - bool in_ub_mode; - bool force_update; - bool do_lockdown; - bool has_guest_code; - bool new_partition_table; - unsigned int data_pos; - unsigned char *ext_data_source; - unsigned char *read_config_buf; - unsigned char intr_mask; - unsigned char command; - unsigned char bootloader_id[2]; - unsigned char config_id[32]; - unsigned char flash_status; - unsigned char partitions; - unsigned short block_size; - unsigned short config_size; - unsigned short config_area; - unsigned short config_block_count; - unsigned short flash_config_length; - unsigned short payload_length; - unsigned short partition_table_bytes; - unsigned short read_config_buf_size; - const unsigned char *config_data; - const unsigned char *image; - unsigned char *image_name; - unsigned int image_size; - struct image_metadata img; - struct register_offset off; - struct block_count blkcount; - struct physical_address phyaddr; - struct f34_v5v6_flash_properties flash_properties; - struct synaptics_rmi4_fn_desc f34_fd; - struct synaptics_rmi4_fn_desc f35_fd; - struct synaptics_rmi4_data *rmi4_data; - struct workqueue_struct *fwu_workqueue; - struct work_struct fwu_work; -}; - -static struct bin_attribute dev_attr_data = { - .attr = { - .name = "data", - .mode = (S_IRUGO | S_IWUGO), - }, - .size = 0, - .read = fwu_sysfs_show_image, - .write = fwu_sysfs_store_image, -}; - -static struct device_attribute attrs[] = { - __ATTR(dorecovery, S_IWUSR | S_IWGRP, - NULL, - fwu_sysfs_do_recovery_store), - __ATTR(doreflash, S_IWUSR | S_IWGRP, - NULL, - fwu_sysfs_do_reflash_store), - __ATTR(writeconfig, S_IWUSR | S_IWGRP, - NULL, - fwu_sysfs_write_config_store), - __ATTR(readconfig, S_IWUSR | S_IWGRP, - NULL, - fwu_sysfs_read_config_store), - __ATTR(configarea, S_IWUSR | S_IWGRP, - NULL, - fwu_sysfs_config_area_store), - __ATTR(imagename, S_IWUSR | S_IWGRP, - NULL, - fwu_sysfs_image_name_store), - __ATTR(imagesize, S_IWUSR | S_IWGRP, - NULL, - fwu_sysfs_image_size_store), - __ATTR(blocksize, S_IRUGO, - fwu_sysfs_block_size_show, - NULL), - __ATTR(fwblockcount, S_IRUGO, - fwu_sysfs_firmware_block_count_show, - NULL), - __ATTR(configblockcount, S_IRUGO, - fwu_sysfs_configuration_block_count_show, - NULL), - __ATTR(dispconfigblockcount, S_IRUGO, - fwu_sysfs_disp_config_block_count_show, - NULL), - __ATTR(permconfigblockcount, S_IRUGO, - fwu_sysfs_perm_config_block_count_show, - NULL), - __ATTR(blconfigblockcount, S_IRUGO, - fwu_sysfs_bl_config_block_count_show, - NULL), - __ATTR(guestcodeblockcount, S_IRUGO, - fwu_sysfs_guest_code_block_count_show, - NULL), - __ATTR(writeguestcode, S_IWUSR | S_IWGRP, - NULL, - fwu_sysfs_write_guest_code_store), -}; - -static struct synaptics_rmi4_fwu_handle *fwu; - -DECLARE_COMPLETION(fwu_remove_complete); - -static unsigned int le_to_uint(const unsigned char *ptr) -{ - return (unsigned int)ptr[0] + - (unsigned int)ptr[1] * 0x100 + - (unsigned int)ptr[2] * 0x10000 + - (unsigned int)ptr[3] * 0x1000000; -} - -static int fwu_allocate_read_config_buf(unsigned int count) -{ - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - if (count > fwu->read_config_buf_size) { - kfree(fwu->read_config_buf); - fwu->read_config_buf = kzalloc(count, GFP_KERNEL); - if (!fwu->read_config_buf) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for fwu->read_config_buf\n", - __func__); - fwu->read_config_buf_size = 0; - return -ENOMEM; - } - fwu->read_config_buf_size = count; - } - - return 0; -} - -static void fwu_compare_partition_tables(void) -{ - if (fwu->phyaddr.ui_firmware != fwu->img.phyaddr.ui_firmware) { - fwu->new_partition_table = true; - return; - } - - if (fwu->phyaddr.ui_config != fwu->img.phyaddr.ui_config) { - fwu->new_partition_table = true; - return; - } - - if (fwu->flash_properties.has_disp_config) { - if (fwu->phyaddr.dp_config != fwu->img.phyaddr.dp_config) { - fwu->new_partition_table = true; - return; - } - } - - if (fwu->has_guest_code) { - if (fwu->phyaddr.guest_code != fwu->img.phyaddr.guest_code) { - fwu->new_partition_table = true; - return; - } - } - - fwu->new_partition_table = false; - - return; -} - -static void fwu_parse_partition_table(const unsigned char *partition_table, - struct block_count *blkcount, struct physical_address *phyaddr) -{ - unsigned char ii; - unsigned char index; - unsigned char offset; - unsigned short partition_length; - unsigned short physical_address; - struct partition_table *ptable; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - for (ii = 0; ii < fwu->partitions; ii++) { - index = ii * 8 + 2; - ptable = (struct partition_table *)&partition_table[index]; - partition_length = ptable->partition_length_15_8 << 8 | - ptable->partition_length_7_0; - physical_address = ptable->start_physical_address_15_8 << 8 | - ptable->start_physical_address_7_0; - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Partition entry %d:\n", - __func__, ii); - for (offset = 0; offset < 8; offset++) { - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: 0x%02x\n", - __func__, - partition_table[index + offset]); - } - switch (ptable->partition_id) { - case CORE_CODE_PARTITION: - blkcount->ui_firmware = partition_length; - phyaddr->ui_firmware = physical_address; - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Core code block count: %d\n", - __func__, blkcount->ui_firmware); - blkcount->total_count += partition_length; - break; - case CORE_CONFIG_PARTITION: - blkcount->ui_config = partition_length; - phyaddr->ui_config = physical_address; - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Core config block count: %d\n", - __func__, blkcount->ui_config); - blkcount->total_count += partition_length; - break; - case BOOTLOADER_PARTITION: - blkcount->bl_image = partition_length; - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Core config block count: %d\n", - __func__, blkcount->ui_config); - blkcount->total_count += partition_length; - break; - case DISPLAY_CONFIG_PARTITION: - blkcount->dp_config = partition_length; - phyaddr->dp_config = physical_address; - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Display config block count: %d\n", - __func__, blkcount->dp_config); - blkcount->total_count += partition_length; - break; - case FLASH_CONFIG_PARTITION: - blkcount->fl_config = partition_length; - phyaddr->fl_config = physical_address; - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Flash config block count: %d\n", - __func__, blkcount->fl_config); - blkcount->total_count += partition_length; - break; - case GUEST_CODE_PARTITION: - blkcount->guest_code = partition_length; - phyaddr->guest_code = physical_address; - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Guest code block count: %d\n", - __func__, blkcount->guest_code); - blkcount->total_count += partition_length; - break; - case GUEST_SERIALIZATION_PARTITION: - blkcount->pm_config = partition_length; - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Guest serialization block count: %d\n", - __func__, blkcount->pm_config); - blkcount->total_count += partition_length; - break; - case GLOBAL_PARAMETERS_PARTITION: - blkcount->bl_config = partition_length; - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Global parameters block count: %d\n", - __func__, blkcount->bl_config); - blkcount->total_count += partition_length; - break; - case DEVICE_CONFIG_PARTITION: - blkcount->lockdown = partition_length; - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Device config block count: %d\n", - __func__, blkcount->lockdown); - blkcount->total_count += partition_length; - break; - }; - } - - return; -} - -static void fwu_parse_image_header_10_bl_container(const unsigned char *image) -{ - unsigned char ii; - unsigned char num_of_containers; - unsigned int addr; - unsigned int container_id; - unsigned int length; - const unsigned char *content; - struct container_descriptor *descriptor; - - num_of_containers = (fwu->img.bootloader.size - 4) / 4; - - for (ii = 1; ii <= num_of_containers; ii++) { - addr = le_to_uint(fwu->img.bootloader.data + (ii * 4)); - descriptor = (struct container_descriptor *)(image + addr); - container_id = descriptor->container_id[0] | - descriptor->container_id[1] << 8; - content = image + le_to_uint(descriptor->content_address); - length = le_to_uint(descriptor->content_length); - switch (container_id) { - case BL_IMAGE_CONTAINER: - fwu->img.bl_image.data = content; - fwu->img.bl_image.size = length; - break; - case BL_CONFIG_CONTAINER: - case GLOBAL_PARAMETERS_CONTAINER: - fwu->img.bl_config.data = content; - fwu->img.bl_config.size = length; - break; - case BL_LOCKDOWN_INFO_CONTAINER: - case DEVICE_CONFIG_CONTAINER: - fwu->img.lockdown.data = content; - fwu->img.lockdown.size = length; - break; - default: - break; - }; - } - - return; -} - -static void fwu_parse_image_header_10(void) -{ - unsigned char ii; - unsigned char num_of_containers; - unsigned int addr; - unsigned int offset; - unsigned int container_id; - unsigned int length; - const unsigned char *image; - const unsigned char *content; - struct container_descriptor *descriptor; - struct image_header_10 *header; - - image = fwu->image; - header = (struct image_header_10 *)image; - - fwu->img.checksum = le_to_uint(header->checksum); - - /* address of top level container */ - offset = le_to_uint(header->top_level_container_start_addr); - descriptor = (struct container_descriptor *)(image + offset); - - /* address of top level container content */ - offset = le_to_uint(descriptor->content_address); - num_of_containers = le_to_uint(descriptor->content_length) / 4; - - for (ii = 0; ii < num_of_containers; ii++) { - addr = le_to_uint(image + offset); - offset += 4; - descriptor = (struct container_descriptor *)(image + addr); - container_id = descriptor->container_id[0] | - descriptor->container_id[1] << 8; - content = image + le_to_uint(descriptor->content_address); - length = le_to_uint(descriptor->content_length); - switch (container_id) { - case UI_CONTAINER: - case CORE_CODE_CONTAINER: - fwu->img.ui_firmware.data = content; - fwu->img.ui_firmware.size = length; - break; - case UI_CONFIG_CONTAINER: - case CORE_CONFIG_CONTAINER: - fwu->img.ui_config.data = content; - fwu->img.ui_config.size = length; - break; - case BL_CONTAINER: - fwu->img.bl_version = *content; - fwu->img.bootloader.data = content; - fwu->img.bootloader.size = length; - fwu_parse_image_header_10_bl_container(image); - break; - case GUEST_CODE_CONTAINER: - fwu->img.contains_guest_code = true; - fwu->img.guest_code.data = content; - fwu->img.guest_code.size = length; - break; - case DISPLAY_CONFIG_CONTAINER: - fwu->img.contains_disp_config = true; - fwu->img.dp_config.data = content; - fwu->img.dp_config.size = length; - break; - case PERMANENT_CONFIG_CONTAINER: - case GUEST_SERIALIZATION_CONTAINER: - fwu->img.contains_perm_config = true; - fwu->img.pm_config.data = content; - fwu->img.pm_config.size = length; - break; - case FLASH_CONFIG_CONTAINER: - fwu->img.contains_flash_config = true; - fwu->img.fl_config.data = content; - fwu->img.fl_config.size = length; - break; - case GENERAL_INFORMATION_CONTAINER: - fwu->img.contains_firmware_id = true; - fwu->img.firmware_id = le_to_uint(content + 4); - break; - default: - break; - } - } - - return; -} - -static void fwu_parse_image_header_05_06(void) -{ - int retval; - const unsigned char *image; - struct image_header_05_06 *header; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - image = fwu->image; - header = (struct image_header_05_06 *)image; - - fwu->img.checksum = le_to_uint(header->checksum); - - fwu->img.bl_version = header->header_version; - - fwu->img.contains_bootloader = header->options_bootloader; - if (fwu->img.contains_bootloader) - fwu->img.bootloader_size = le_to_uint(header->bootloader_size); - - fwu->img.ui_firmware.size = le_to_uint(header->firmware_size); - if (fwu->img.ui_firmware.size) { - fwu->img.ui_firmware.data = image + IMAGE_AREA_OFFSET; - if (fwu->img.contains_bootloader) - fwu->img.ui_firmware.data += fwu->img.bootloader_size; - } - - if ((fwu->img.bl_version == BL_V6) && header->options_tddi) - fwu->img.ui_firmware.data = image + IMAGE_AREA_OFFSET; - - fwu->img.ui_config.size = le_to_uint(header->config_size); - if (fwu->img.ui_config.size) { - fwu->img.ui_config.data = fwu->img.ui_firmware.data + - fwu->img.ui_firmware.size; - } - - if ((fwu->img.bl_version == BL_V5 && fwu->img.contains_bootloader) || - (fwu->img.bl_version == BL_V6 && header->options_tddi)) - fwu->img.contains_disp_config = true; - else - fwu->img.contains_disp_config = false; - - if (fwu->img.contains_disp_config) { - fwu->img.disp_config_offset = le_to_uint(header->dsp_cfg_addr); - fwu->img.dp_config.size = le_to_uint(header->dsp_cfg_size); - fwu->img.dp_config.data = image + fwu->img.disp_config_offset; - } else { - retval = secure_memcpy(fwu->img.cstmr_product_id, - sizeof(fwu->img.cstmr_product_id), - header->cstmr_product_id, - sizeof(header->cstmr_product_id), - PRODUCT_ID_SIZE); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to copy custom product ID string\n", - __func__); - } - fwu->img.cstmr_product_id[PRODUCT_ID_SIZE] = 0; - } - - fwu->img.contains_firmware_id = header->options_firmware_id; - if (fwu->img.contains_firmware_id) - fwu->img.firmware_id = le_to_uint(header->firmware_id); - - retval = secure_memcpy(fwu->img.product_id, - sizeof(fwu->img.product_id), - header->product_id, - sizeof(header->product_id), - PRODUCT_ID_SIZE); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to copy product ID string\n", - __func__); - } - fwu->img.product_id[PRODUCT_ID_SIZE] = 0; - - fwu->img.lockdown.size = LOCKDOWN_SIZE; - fwu->img.lockdown.data = image + IMAGE_AREA_OFFSET - LOCKDOWN_SIZE; - - return; -} - -static int fwu_parse_image_info(void) -{ - struct image_header_10 *header; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - header = (struct image_header_10 *)fwu->image; - - memset(&fwu->img, 0x00, sizeof(fwu->img)); - - switch (header->major_header_version) { - case IMAGE_HEADER_VERSION_10: - fwu_parse_image_header_10(); - break; - case IMAGE_HEADER_VERSION_05: - case IMAGE_HEADER_VERSION_06: - fwu_parse_image_header_05_06(); - break; - default: - dev_err(rmi4_data->pdev->dev.parent, - "%s: Unsupported image file format (0x%02x)\n", - __func__, header->major_header_version); - return -EINVAL; - } - - if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8) { - if (!fwu->img.contains_flash_config) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: No flash config found in firmware image\n", - __func__); - return -EINVAL; - } - - fwu_parse_partition_table(fwu->img.fl_config.data, - &fwu->img.blkcount, &fwu->img.phyaddr); - - fwu_compare_partition_tables(); - } else { - fwu->new_partition_table = false; - } - - return 0; -} - -static int fwu_read_flash_status(void) -{ - int retval; - unsigned char status; - unsigned char command; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - retval = synaptics_rmi4_reg_read(rmi4_data, - fwu->f34_fd.data_base_addr + fwu->off.flash_status, - &status, - sizeof(status)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read flash status\n", - __func__); - return retval; - } - - fwu->in_bl_mode = status >> 7; - - if (fwu->bl_version == BL_V5) - fwu->flash_status = (status >> 4) & MASK_3BIT; - else if (fwu->bl_version == BL_V6) - fwu->flash_status = status & MASK_3BIT; - else if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8) - fwu->flash_status = status & MASK_5BIT; - - if (fwu->flash_status != 0x00) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Flash status = %d, command = 0x%02x\n", - __func__, fwu->flash_status, fwu->command); - } - - retval = synaptics_rmi4_reg_read(rmi4_data, - fwu->f34_fd.data_base_addr + fwu->off.flash_cmd, - &command, - sizeof(command)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read flash command\n", - __func__); - return retval; - } - - if (fwu->bl_version == BL_V5) - fwu->command = command & MASK_4BIT; - else if (fwu->bl_version == BL_V6) - fwu->command = command & MASK_6BIT; - else if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8) - fwu->command = command; - - return 0; -} - -static int fwu_wait_for_idle(int timeout_ms, bool poll) -{ - int count = 0; - int timeout_count = ((timeout_ms * 1000) / MAX_SLEEP_TIME_US) + 1; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - do { - usleep_range(MIN_SLEEP_TIME_US, MAX_SLEEP_TIME_US); - - count++; - if (poll || (count == timeout_count)) - fwu_read_flash_status(); - - if ((fwu->command == CMD_IDLE) && (fwu->flash_status == 0x00)) - return 0; - } while (count < timeout_count); - - dev_err(rmi4_data->pdev->dev.parent, - "%s: Timed out waiting for idle status\n", - __func__); - - return -ETIMEDOUT; -} - -static int fwu_write_f34_v7_command_single_transaction(unsigned char cmd) -{ - int retval; - unsigned char base; - struct f34_v7_data_1_5 data_1_5; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - base = fwu->f34_fd.data_base_addr; - - memset(data_1_5.data, 0x00, sizeof(data_1_5.data)); - - switch (cmd) { - case CMD_ERASE_ALL: - data_1_5.partition_id = CORE_CODE_PARTITION; - data_1_5.command = CMD_V7_ERASE_AP; - break; - case CMD_ERASE_UI_FIRMWARE: - data_1_5.partition_id = CORE_CODE_PARTITION; - data_1_5.command = CMD_V7_ERASE; - break; - case CMD_ERASE_BL_CONFIG: - data_1_5.partition_id = GLOBAL_PARAMETERS_PARTITION; - data_1_5.command = CMD_V7_ERASE; - break; - case CMD_ERASE_UI_CONFIG: - data_1_5.partition_id = CORE_CONFIG_PARTITION; - data_1_5.command = CMD_V7_ERASE; - break; - case CMD_ERASE_DISP_CONFIG: - data_1_5.partition_id = DISPLAY_CONFIG_PARTITION; - data_1_5.command = CMD_V7_ERASE; - break; - case CMD_ERASE_FLASH_CONFIG: - data_1_5.partition_id = FLASH_CONFIG_PARTITION; - data_1_5.command = CMD_V7_ERASE; - break; - case CMD_ERASE_GUEST_CODE: - data_1_5.partition_id = GUEST_CODE_PARTITION; - data_1_5.command = CMD_V7_ERASE; - break; - case CMD_ENABLE_FLASH_PROG: - data_1_5.partition_id = BOOTLOADER_PARTITION; - data_1_5.command = CMD_V7_ENTER_BL; - break; - }; - - data_1_5.payload_0 = fwu->bootloader_id[0]; - data_1_5.payload_1 = fwu->bootloader_id[1]; - - retval = synaptics_rmi4_reg_write(rmi4_data, - base + fwu->off.partition_id, - data_1_5.data, - sizeof(data_1_5.data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write single transaction command\n", - __func__); - return retval; - } - - return 0; -} - -static int fwu_write_f34_v7_command(unsigned char cmd) -{ - int retval; - unsigned char base; - unsigned char command; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - base = fwu->f34_fd.data_base_addr; - - switch (cmd) { - case CMD_WRITE_FW: - case CMD_WRITE_CONFIG: - case CMD_WRITE_LOCKDOWN: - case CMD_WRITE_GUEST_CODE: - command = CMD_V7_WRITE; - break; - case CMD_READ_CONFIG: - command = CMD_V7_READ; - break; - case CMD_ERASE_ALL: - command = CMD_V7_ERASE_AP; - break; - case CMD_ERASE_UI_FIRMWARE: - case CMD_ERASE_BL_CONFIG: - case CMD_ERASE_UI_CONFIG: - case CMD_ERASE_DISP_CONFIG: - case CMD_ERASE_FLASH_CONFIG: - case CMD_ERASE_GUEST_CODE: - command = CMD_V7_ERASE; - break; - case CMD_ENABLE_FLASH_PROG: - command = CMD_V7_ENTER_BL; - break; - default: - dev_err(rmi4_data->pdev->dev.parent, - "%s: Invalid command 0x%02x\n", - __func__, cmd); - return -EINVAL; - }; - - fwu->command = command; - - switch (cmd) { - case CMD_ERASE_ALL: - case CMD_ERASE_UI_FIRMWARE: - case CMD_ERASE_BL_CONFIG: - case CMD_ERASE_UI_CONFIG: - case CMD_ERASE_DISP_CONFIG: - case CMD_ERASE_FLASH_CONFIG: - case CMD_ERASE_GUEST_CODE: - case CMD_ENABLE_FLASH_PROG: - retval = fwu_write_f34_v7_command_single_transaction(cmd); - if (retval < 0) - return retval; - else - return 0; - default: - break; - }; - - retval = synaptics_rmi4_reg_write(rmi4_data, - base + fwu->off.flash_cmd, - &command, - sizeof(command)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write flash command\n", - __func__); - return retval; - } - - return 0; -} - -static int fwu_write_f34_v5v6_command(unsigned char cmd) -{ - int retval; - unsigned char base; - unsigned char command; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - base = fwu->f34_fd.data_base_addr; - - switch (cmd) { - case CMD_IDLE: - command = CMD_V5V6_IDLE; - break; - case CMD_WRITE_FW: - command = CMD_V5V6_WRITE_FW; - break; - case CMD_WRITE_CONFIG: - command = CMD_V5V6_WRITE_CONFIG; - break; - case CMD_WRITE_LOCKDOWN: - command = CMD_V5V6_WRITE_LOCKDOWN; - break; - case CMD_WRITE_GUEST_CODE: - command = CMD_V5V6_WRITE_GUEST_CODE; - break; - case CMD_READ_CONFIG: - command = CMD_V5V6_READ_CONFIG; - break; - case CMD_ERASE_ALL: - command = CMD_V5V6_ERASE_ALL; - break; - case CMD_ERASE_UI_CONFIG: - command = CMD_V5V6_ERASE_UI_CONFIG; - break; - case CMD_ERASE_DISP_CONFIG: - command = CMD_V5V6_ERASE_DISP_CONFIG; - break; - case CMD_ERASE_GUEST_CODE: - command = CMD_V5V6_ERASE_GUEST_CODE; - break; - case CMD_ENABLE_FLASH_PROG: - command = CMD_V5V6_ENABLE_FLASH_PROG; - break; - default: - dev_err(rmi4_data->pdev->dev.parent, - "%s: Invalid command 0x%02x\n", - __func__, cmd); - return -EINVAL; - } - - switch (cmd) { - case CMD_ERASE_ALL: - case CMD_ERASE_UI_CONFIG: - case CMD_ERASE_DISP_CONFIG: - case CMD_ERASE_GUEST_CODE: - case CMD_ENABLE_FLASH_PROG: - retval = synaptics_rmi4_reg_write(rmi4_data, - base + fwu->off.payload, - fwu->bootloader_id, - sizeof(fwu->bootloader_id)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write bootloader ID\n", - __func__); - return retval; - } - break; - default: - break; - }; - - fwu->command = command; - - retval = synaptics_rmi4_reg_write(rmi4_data, - base + fwu->off.flash_cmd, - &command, - sizeof(command)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write command 0x%02x\n", - __func__, command); - return retval; - } - - return 0; -} - -static int fwu_write_f34_command(unsigned char cmd) -{ - int retval; - - if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8) - retval = fwu_write_f34_v7_command(cmd); - else - retval = fwu_write_f34_v5v6_command(cmd); - - return retval; -} - -static int fwu_write_f34_v7_partition_id(unsigned char cmd) -{ - int retval; - unsigned char base; - unsigned char partition; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - base = fwu->f34_fd.data_base_addr; - - switch (cmd) { - case CMD_WRITE_FW: - partition = CORE_CODE_PARTITION; - break; - case CMD_WRITE_CONFIG: - case CMD_READ_CONFIG: - if (fwu->config_area == UI_CONFIG_AREA) - partition = CORE_CONFIG_PARTITION; - else if (fwu->config_area == DP_CONFIG_AREA) - partition = DISPLAY_CONFIG_PARTITION; - else if (fwu->config_area == PM_CONFIG_AREA) - partition = GUEST_SERIALIZATION_PARTITION; - else if (fwu->config_area == BL_CONFIG_AREA) - partition = GLOBAL_PARAMETERS_PARTITION; - else if (fwu->config_area == FLASH_CONFIG_AREA) - partition = FLASH_CONFIG_PARTITION; - break; - case CMD_WRITE_LOCKDOWN: - partition = DEVICE_CONFIG_PARTITION; - break; - case CMD_WRITE_GUEST_CODE: - partition = GUEST_CODE_PARTITION; - break; - case CMD_ERASE_ALL: - partition = CORE_CODE_PARTITION; - break; - case CMD_ERASE_BL_CONFIG: - partition = GLOBAL_PARAMETERS_PARTITION; - break; - case CMD_ERASE_UI_CONFIG: - partition = CORE_CONFIG_PARTITION; - break; - case CMD_ERASE_DISP_CONFIG: - partition = DISPLAY_CONFIG_PARTITION; - break; - case CMD_ERASE_FLASH_CONFIG: - partition = FLASH_CONFIG_PARTITION; - break; - case CMD_ERASE_GUEST_CODE: - partition = GUEST_CODE_PARTITION; - break; - case CMD_ENABLE_FLASH_PROG: - partition = BOOTLOADER_PARTITION; - break; - default: - dev_err(rmi4_data->pdev->dev.parent, - "%s: Invalid command 0x%02x\n", - __func__, cmd); - return -EINVAL; - }; - - retval = synaptics_rmi4_reg_write(rmi4_data, - base + fwu->off.partition_id, - &partition, - sizeof(partition)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write partition ID\n", - __func__); - return retval; - } - - return 0; -} - -static int fwu_write_f34_partition_id(unsigned char cmd) -{ - int retval; - - if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8) - retval = fwu_write_f34_v7_partition_id(cmd); - else - retval = 0; - - return retval; -} - -static int fwu_read_f34_v7_partition_table(unsigned char *partition_table) -{ - int retval; - unsigned char base; - unsigned char length[2]; - unsigned short block_number = 0; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - base = fwu->f34_fd.data_base_addr; - - fwu->config_area = FLASH_CONFIG_AREA; - - retval = fwu_write_f34_partition_id(CMD_READ_CONFIG); - if (retval < 0) - return retval; - - retval = synaptics_rmi4_reg_write(rmi4_data, - base + fwu->off.block_number, - (unsigned char *)&block_number, - sizeof(block_number)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write block number\n", - __func__); - return retval; - } - - length[0] = (unsigned char)(fwu->flash_config_length & MASK_8BIT); - length[1] = (unsigned char)(fwu->flash_config_length >> 8); - - retval = synaptics_rmi4_reg_write(rmi4_data, - base + fwu->off.transfer_length, - length, - sizeof(length)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write transfer length\n", - __func__); - return retval; - } - - retval = fwu_write_f34_command(CMD_READ_CONFIG); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write command\n", - __func__); - return retval; - } - - retval = fwu_wait_for_idle(WRITE_WAIT_MS, true); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to wait for idle status\n", - __func__); - return retval; - } - - retval = synaptics_rmi4_reg_read(rmi4_data, - base + fwu->off.payload, - partition_table, - fwu->partition_table_bytes); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read block data\n", - __func__); - return retval; - } - - return 0; -} - -static int fwu_read_f34_v7_queries(void) -{ - int retval; - unsigned char ii; - unsigned char base; - unsigned char index; - unsigned char offset; - unsigned char *ptable; - struct f34_v7_query_0 query_0; - struct f34_v7_query_1_7 query_1_7; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - base = fwu->f34_fd.query_base_addr; - - retval = synaptics_rmi4_reg_read(rmi4_data, - base, - query_0.data, - sizeof(query_0.data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read query 0\n", - __func__); - return retval; - } - - offset = query_0.subpacket_1_size + 1; - - retval = synaptics_rmi4_reg_read(rmi4_data, - base + offset, - query_1_7.data, - sizeof(query_1_7.data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read queries 1 to 7\n", - __func__); - return retval; - } - - fwu->bootloader_id[0] = query_1_7.bl_minor_revision; - fwu->bootloader_id[1] = query_1_7.bl_major_revision; - - if (fwu->bootloader_id[1] == BL_V8) - fwu->bl_version = BL_V8; - - fwu->block_size = query_1_7.block_size_15_8 << 8 | - query_1_7.block_size_7_0; - - fwu->flash_config_length = query_1_7.flash_config_length_15_8 << 8 | - query_1_7.flash_config_length_7_0; - - fwu->payload_length = query_1_7.payload_length_15_8 << 8 | - query_1_7.payload_length_7_0; - - fwu->off.flash_status = V7_FLASH_STATUS_OFFSET; - fwu->off.partition_id = V7_PARTITION_ID_OFFSET; - fwu->off.block_number = V7_BLOCK_NUMBER_OFFSET; - fwu->off.transfer_length = V7_TRANSFER_LENGTH_OFFSET; - fwu->off.flash_cmd = V7_COMMAND_OFFSET; - fwu->off.payload = V7_PAYLOAD_OFFSET; - - index = sizeof(query_1_7.data) - V7_PARTITION_SUPPORT_BYTES; - - fwu->partitions = 0; - for (offset = 0; offset < V7_PARTITION_SUPPORT_BYTES; offset++) { - for (ii = 0; ii < 8; ii++) { - if (query_1_7.data[index + offset] & (1 << ii)) - fwu->partitions++; - } - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Supported partitions: 0x%02x\n", - __func__, query_1_7.data[index + offset]); - } - - fwu->partition_table_bytes = fwu->partitions * 8 + 2; - - ptable = kzalloc(fwu->partition_table_bytes, GFP_KERNEL); - if (!ptable) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for partition table\n", - __func__); - return -ENOMEM; - } - - retval = fwu_read_f34_v7_partition_table(ptable); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read partition table\n", - __func__); - kfree(ptable); - return retval; - } - - fwu_parse_partition_table(ptable, &fwu->blkcount, &fwu->phyaddr); - - if (fwu->blkcount.dp_config) - fwu->flash_properties.has_disp_config = 1; - else - fwu->flash_properties.has_disp_config = 0; - - if (fwu->blkcount.pm_config) - fwu->flash_properties.has_pm_config = 1; - else - fwu->flash_properties.has_pm_config = 0; - - if (fwu->blkcount.bl_config) - fwu->flash_properties.has_bl_config = 1; - else - fwu->flash_properties.has_bl_config = 0; - - if (fwu->blkcount.guest_code) - fwu->has_guest_code = 1; - else - fwu->has_guest_code = 0; - - kfree(ptable); - - return 0; -} - -static int fwu_read_f34_v5v6_queries(void) -{ - int retval; - unsigned char count; - unsigned char base; - unsigned char buf[10]; - struct f34_v5v6_flash_properties_2 properties_2; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - base = fwu->f34_fd.query_base_addr; - - retval = synaptics_rmi4_reg_read(rmi4_data, - base + V5V6_BOOTLOADER_ID_OFFSET, - fwu->bootloader_id, - sizeof(fwu->bootloader_id)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read bootloader ID\n", - __func__); - return retval; - } - - if (fwu->bl_version == BL_V5) { - fwu->off.properties = V5_PROPERTIES_OFFSET; - fwu->off.block_size = V5_BLOCK_SIZE_OFFSET; - fwu->off.block_count = V5_BLOCK_COUNT_OFFSET; - fwu->off.block_number = V5_BLOCK_NUMBER_OFFSET; - fwu->off.payload = V5_BLOCK_DATA_OFFSET; - } else if (fwu->bl_version == BL_V6) { - fwu->off.properties = V6_PROPERTIES_OFFSET; - fwu->off.properties_2 = V6_PROPERTIES_2_OFFSET; - fwu->off.block_size = V6_BLOCK_SIZE_OFFSET; - fwu->off.block_count = V6_BLOCK_COUNT_OFFSET; - fwu->off.gc_block_count = V6_GUEST_CODE_BLOCK_COUNT_OFFSET; - fwu->off.block_number = V6_BLOCK_NUMBER_OFFSET; - fwu->off.payload = V6_BLOCK_DATA_OFFSET; - } - - retval = synaptics_rmi4_reg_read(rmi4_data, - base + fwu->off.block_size, - buf, - 2); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read block size info\n", - __func__); - return retval; - } - - batohs(&fwu->block_size, &(buf[0])); - - if (fwu->bl_version == BL_V5) { - fwu->off.flash_cmd = fwu->off.payload + fwu->block_size; - fwu->off.flash_status = fwu->off.flash_cmd; - } else if (fwu->bl_version == BL_V6) { - fwu->off.flash_cmd = V6_FLASH_COMMAND_OFFSET; - fwu->off.flash_status = V6_FLASH_STATUS_OFFSET; - } - - retval = synaptics_rmi4_reg_read(rmi4_data, - base + fwu->off.properties, - fwu->flash_properties.data, - sizeof(fwu->flash_properties.data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read flash properties\n", - __func__); - return retval; - } - - count = 4; - - if (fwu->flash_properties.has_pm_config) - count += 2; - - if (fwu->flash_properties.has_bl_config) - count += 2; - - if (fwu->flash_properties.has_disp_config) - count += 2; - - retval = synaptics_rmi4_reg_read(rmi4_data, - base + fwu->off.block_count, - buf, - count); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read block count info\n", - __func__); - return retval; - } - - batohs(&fwu->blkcount.ui_firmware, &(buf[0])); - batohs(&fwu->blkcount.ui_config, &(buf[2])); - - count = 4; - - if (fwu->flash_properties.has_pm_config) { - batohs(&fwu->blkcount.pm_config, &(buf[count])); - count += 2; - } - - if (fwu->flash_properties.has_bl_config) { - batohs(&fwu->blkcount.bl_config, &(buf[count])); - count += 2; - } - - if (fwu->flash_properties.has_disp_config) - batohs(&fwu->blkcount.dp_config, &(buf[count])); - - fwu->has_guest_code = false; - - if (fwu->flash_properties.has_query4) { - retval = synaptics_rmi4_reg_read(rmi4_data, - base + fwu->off.properties_2, - properties_2.data, - sizeof(properties_2.data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read flash properties 2\n", - __func__); - return retval; - } - - if (properties_2.has_guest_code) { - retval = synaptics_rmi4_reg_read(rmi4_data, - base + fwu->off.gc_block_count, - buf, - 2); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read guest code block count\n", - __func__); - return retval; - } - - batohs(&fwu->blkcount.guest_code, &(buf[0])); - fwu->has_guest_code = true; - } - } - - return 0; -} - -static int fwu_read_f34_queries(void) -{ - int retval; - - memset(&fwu->blkcount, 0x00, sizeof(fwu->blkcount)); - memset(&fwu->phyaddr, 0x00, sizeof(fwu->phyaddr)); - - if (fwu->bl_version == BL_V7) - retval = fwu_read_f34_v7_queries(); - else - retval = fwu_read_f34_v5v6_queries(); - - return retval; -} - -static int fwu_write_f34_v7_blocks(unsigned char *block_ptr, - unsigned short block_cnt, unsigned char command) -{ - int retval; - unsigned char base; - unsigned char length[2]; - unsigned short transfer; - unsigned short max_transfer; - unsigned short remaining = block_cnt; - unsigned short block_number = 0; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - base = fwu->f34_fd.data_base_addr; - - retval = fwu_write_f34_partition_id(command); - if (retval < 0) - return retval; - - retval = synaptics_rmi4_reg_write(rmi4_data, - base + fwu->off.block_number, - (unsigned char *)&block_number, - sizeof(block_number)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write block number\n", - __func__); - return retval; - } - - if (fwu->payload_length > (PAGE_SIZE / fwu->block_size)) - max_transfer = PAGE_SIZE / fwu->block_size; - else - max_transfer = fwu->payload_length; - - do { - if (remaining / max_transfer) - transfer = max_transfer; - else - transfer = remaining; - - length[0] = (unsigned char)(transfer & MASK_8BIT); - length[1] = (unsigned char)(transfer >> 8); - - retval = synaptics_rmi4_reg_write(rmi4_data, - base + fwu->off.transfer_length, - length, - sizeof(length)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write transfer length (%d blocks remaining)\n", - __func__, remaining); - return retval; - } - - retval = fwu_write_f34_command(command); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write command (%d blocks remaining)\n", - __func__, remaining); - return retval; - } - - retval = synaptics_rmi4_reg_write(rmi4_data, - base + fwu->off.payload, - block_ptr, - transfer * fwu->block_size); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write block data (%d blocks remaining)\n", - __func__, remaining); - return retval; - } - - retval = fwu_wait_for_idle(WRITE_WAIT_MS, false); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to wait for idle status (%d blocks remaining)\n", - __func__, remaining); - return retval; - } - - block_ptr += (transfer * fwu->block_size); - remaining -= transfer; - } while (remaining); - - return 0; -} - -static int fwu_write_f34_v5v6_blocks(unsigned char *block_ptr, - unsigned short block_cnt, unsigned char command) -{ - int retval; - unsigned char base; - unsigned char block_number[] = {0, 0}; - unsigned short blk; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - base = fwu->f34_fd.data_base_addr; - - block_number[1] |= (fwu->config_area << 5); - - retval = synaptics_rmi4_reg_write(rmi4_data, - base + fwu->off.block_number, - block_number, - sizeof(block_number)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write block number\n", - __func__); - return retval; - } - - for (blk = 0; blk < block_cnt; blk++) { - retval = synaptics_rmi4_reg_write(rmi4_data, - base + fwu->off.payload, - block_ptr, - fwu->block_size); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write block data (block %d)\n", - __func__, blk); - return retval; - } - - retval = fwu_write_f34_command(command); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write command for block %d\n", - __func__, blk); - return retval; - } - - retval = fwu_wait_for_idle(WRITE_WAIT_MS, false); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to wait for idle status (block %d)\n", - __func__, blk); - return retval; - } - - block_ptr += fwu->block_size; - } - - return 0; -} - -static int fwu_write_f34_blocks(unsigned char *block_ptr, - unsigned short block_cnt, unsigned char cmd) -{ - int retval; - - if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8) - retval = fwu_write_f34_v7_blocks(block_ptr, block_cnt, cmd); - else - retval = fwu_write_f34_v5v6_blocks(block_ptr, block_cnt, cmd); - - return retval; -} - -static int fwu_read_f34_v7_blocks(unsigned short block_cnt, - unsigned char command) -{ - int retval; - unsigned char base; - unsigned char length[2]; - unsigned short transfer; - unsigned short max_transfer; - unsigned short remaining = block_cnt; - unsigned short block_number = 0; - unsigned short index = 0; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - base = fwu->f34_fd.data_base_addr; - - retval = fwu_write_f34_partition_id(command); - if (retval < 0) - return retval; - - retval = synaptics_rmi4_reg_write(rmi4_data, - base + fwu->off.block_number, - (unsigned char *)&block_number, - sizeof(block_number)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write block number\n", - __func__); - return retval; - } - - if (fwu->payload_length > (PAGE_SIZE / fwu->block_size)) - max_transfer = PAGE_SIZE / fwu->block_size; - else - max_transfer = fwu->payload_length; - - do { - if (remaining / max_transfer) - transfer = max_transfer; - else - transfer = remaining; - - length[0] = (unsigned char)(transfer & MASK_8BIT); - length[1] = (unsigned char)(transfer >> 8); - - retval = synaptics_rmi4_reg_write(rmi4_data, - base + fwu->off.transfer_length, - length, - sizeof(length)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write transfer length (%d blocks remaining)\n", - __func__, remaining); - return retval; - } - - retval = fwu_write_f34_command(command); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write command (%d blocks remaining)\n", - __func__, remaining); - return retval; - } - - retval = fwu_wait_for_idle(WRITE_WAIT_MS, false); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to wait for idle status (%d blocks remaining)\n", - __func__, remaining); - return retval; - } - - retval = synaptics_rmi4_reg_read(rmi4_data, - base + fwu->off.payload, - &fwu->read_config_buf[index], - transfer * fwu->block_size); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read block data (%d blocks remaining)\n", - __func__, remaining); - return retval; - } - - index += (transfer * fwu->block_size); - remaining -= transfer; - } while (remaining); - - return 0; -} - -static int fwu_read_f34_v5v6_blocks(unsigned short block_cnt, - unsigned char command) -{ - int retval; - unsigned char base; - unsigned char block_number[] = {0, 0}; - unsigned short blk; - unsigned short index = 0; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - base = fwu->f34_fd.data_base_addr; - - block_number[1] |= (fwu->config_area << 5); - - retval = synaptics_rmi4_reg_write(rmi4_data, - base + fwu->off.block_number, - block_number, - sizeof(block_number)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write block number\n", - __func__); - return retval; - } - - for (blk = 0; blk < block_cnt; blk++) { - retval = fwu_write_f34_command(command); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write read config command\n", - __func__); - return retval; - } - - retval = fwu_wait_for_idle(WRITE_WAIT_MS, false); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to wait for idle status\n", - __func__); - return retval; - } - - retval = synaptics_rmi4_reg_read(rmi4_data, - base + fwu->off.payload, - &fwu->read_config_buf[index], - fwu->block_size); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read block data (block %d)\n", - __func__, blk); - return retval; - } - - index += fwu->block_size; - } - - return 0; -} - -static int fwu_read_f34_blocks(unsigned short block_cnt, unsigned char cmd) -{ - int retval; - - if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8) - retval = fwu_read_f34_v7_blocks(block_cnt, cmd); - else - retval = fwu_read_f34_v5v6_blocks(block_cnt, cmd); - - return retval; -} - -static int fwu_get_image_firmware_id(unsigned int *fw_id) -{ - int retval; - unsigned char index = 0; - char *strptr; - char *firmware_id; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - if (fwu->img.contains_firmware_id) { - *fw_id = fwu->img.firmware_id; - } else { - strptr = strnstr(fwu->image_name, "PR", MAX_IMAGE_NAME_LEN); - if (!strptr) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: No valid PR number (PRxxxxxxx) found in image file name (%s)\n", - __func__, fwu->image_name); - return -EINVAL; - } - - strptr += 2; - firmware_id = kzalloc(MAX_FIRMWARE_ID_LEN, GFP_KERNEL); - if (!firmware_id) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for firmware_id\n", - __func__); - return -ENOMEM; - } - while ((index < MAX_FIRMWARE_ID_LEN - 1) && strptr[index] >= '0' - && strptr[index] <= '9') { - firmware_id[index] = strptr[index]; - index++; - } - firmware_id[index] = '\0'; - - retval = sstrtoul(firmware_id, 10, (unsigned long *)fw_id); - kfree(firmware_id); - if (retval) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to obtain image firmware ID\n", - __func__); - return -EINVAL; - } - } - - return 0; -} - -static int fwu_get_device_config_id(void) -{ - int retval; - unsigned char config_id_size; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8) - config_id_size = V7_CONFIG_ID_SIZE; - else - config_id_size = V5V6_CONFIG_ID_SIZE; - - retval = synaptics_rmi4_reg_read(rmi4_data, - fwu->f34_fd.ctrl_base_addr, - fwu->config_id, - config_id_size); - if (retval < 0) - return retval; - - return 0; -} - -static enum flash_area fwu_go_nogo(void) -{ - int retval; - enum flash_area flash_area = NONE; - unsigned char ii; - unsigned char config_id_size; - unsigned int device_fw_id; - unsigned int image_fw_id; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - if (fwu->force_update) { - flash_area = UI_FIRMWARE; - goto exit; - } - - /* Update both UI and config if device is in bootloader mode */ - if (fwu->in_bl_mode) { - flash_area = UI_FIRMWARE; - goto exit; - } - - /* Get device firmware ID */ - device_fw_id = rmi4_data->firmware_id; - dev_info(rmi4_data->pdev->dev.parent, - "%s: Device firmware ID = %d\n", - __func__, device_fw_id); - - /* Get image firmware ID */ - retval = fwu_get_image_firmware_id(&image_fw_id); - if (retval < 0) { - flash_area = NONE; - goto exit; - } - dev_info(rmi4_data->pdev->dev.parent, - "%s: Image firmware ID = %d\n", - __func__, image_fw_id); - - if (image_fw_id > device_fw_id) { - flash_area = UI_FIRMWARE; - goto exit; - } else if (image_fw_id < device_fw_id) { - dev_info(rmi4_data->pdev->dev.parent, - "%s: Image firmware ID older than device firmware ID\n", - __func__); - flash_area = NONE; - goto exit; - } - - /* Get device config ID */ - retval = fwu_get_device_config_id(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read device config ID\n", - __func__); - flash_area = NONE; - goto exit; - } - - if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8) - config_id_size = V7_CONFIG_ID_SIZE; - else - config_id_size = V5V6_CONFIG_ID_SIZE; - - for (ii = 0; ii < config_id_size; ii++) { - if (fwu->img.ui_config.data[ii] > fwu->config_id[ii]) { - flash_area = UI_CONFIG; - goto exit; - } else if (fwu->img.ui_config.data[ii] < fwu->config_id[ii]) { - flash_area = NONE; - goto exit; - } - } - - flash_area = NONE; - -exit: - if (flash_area == NONE) { - dev_info(rmi4_data->pdev->dev.parent, - "%s: No need to do reflash\n", - __func__); - } else { - dev_info(rmi4_data->pdev->dev.parent, - "%s: Updating %s\n", - __func__, - flash_area == UI_FIRMWARE ? - "UI firmware and config" : - "UI config only"); - } - - return flash_area; -} - -static int fwu_scan_pdt(void) -{ - int retval; - unsigned char ii; - unsigned char intr_count = 0; - unsigned char intr_off; - unsigned char intr_src; - unsigned short addr; - bool f01found = false; - bool f34found = false; - bool f35found = false; - struct synaptics_rmi4_fn_desc rmi_fd; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - fwu->in_ub_mode = false; - - for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) { - retval = synaptics_rmi4_reg_read(rmi4_data, - addr, - (unsigned char *)&rmi_fd, - sizeof(rmi_fd)); - if (retval < 0) - return retval; - - if (rmi_fd.fn_number) { - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Found F%02x\n", - __func__, rmi_fd.fn_number); - switch (rmi_fd.fn_number) { - case SYNAPTICS_RMI4_F01: - f01found = true; - - rmi4_data->f01_query_base_addr = - rmi_fd.query_base_addr; - rmi4_data->f01_ctrl_base_addr = - rmi_fd.ctrl_base_addr; - rmi4_data->f01_data_base_addr = - rmi_fd.data_base_addr; - rmi4_data->f01_cmd_base_addr = - rmi_fd.cmd_base_addr; - break; - case SYNAPTICS_RMI4_F34: - f34found = true; - fwu->f34_fd.query_base_addr = - rmi_fd.query_base_addr; - fwu->f34_fd.ctrl_base_addr = - rmi_fd.ctrl_base_addr; - fwu->f34_fd.data_base_addr = - rmi_fd.data_base_addr; - - switch (rmi_fd.fn_version) { - case F34_V0: - fwu->bl_version = BL_V5; - break; - case F34_V1: - fwu->bl_version = BL_V6; - break; - case F34_V2: - fwu->bl_version = BL_V7; - break; - default: - dev_err(rmi4_data->pdev->dev.parent, - "%s: Unrecognized F34 version\n", - __func__); - return -EINVAL; - } - - fwu->intr_mask = 0; - intr_src = rmi_fd.intr_src_count; - intr_off = intr_count % 8; - for (ii = intr_off; - ii < (intr_src + intr_off); - ii++) { - fwu->intr_mask |= 1 << ii; - } - break; - case SYNAPTICS_RMI4_F35: - f35found = true; - fwu->f35_fd.query_base_addr = - rmi_fd.query_base_addr; - fwu->f35_fd.ctrl_base_addr = - rmi_fd.ctrl_base_addr; - fwu->f35_fd.data_base_addr = - rmi_fd.data_base_addr; - break; - } - } else { - break; - } - - intr_count += rmi_fd.intr_src_count; - } - - if (!f01found || !f34found) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to find both F01 and F34\n", - __func__); - if (!f35found) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to find F35\n", - __func__); - return -EINVAL; - } else { - fwu->in_ub_mode = true; - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: In microbootloader mode\n", - __func__); - fwu_recovery_check_status(); - return 0; - } - } - - rmi4_data->intr_mask[0] |= fwu->intr_mask; - - addr = rmi4_data->f01_ctrl_base_addr + 1; - - retval = synaptics_rmi4_reg_write(rmi4_data, - addr, - &(rmi4_data->intr_mask[0]), - sizeof(rmi4_data->intr_mask[0])); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to set interrupt enable bit\n", - __func__); - return retval; - } - - return 0; -} - -static int fwu_enter_flash_prog(void) -{ - int retval; - struct f01_device_control f01_device_control; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - retval = fwu_read_flash_status(); - if (retval < 0) - return retval; - - if (fwu->in_bl_mode) - return 0; - - retval = rmi4_data->irq_enable(rmi4_data, false, true); - if (retval < 0) - return retval; - - msleep(INT_DISABLE_WAIT_MS); - - retval = fwu_write_f34_command(CMD_ENABLE_FLASH_PROG); - if (retval < 0) - return retval; - - retval = fwu_wait_for_idle(ENABLE_WAIT_MS, false); - if (retval < 0) - return retval; - - if (!fwu->in_bl_mode) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: BL mode not entered\n", - __func__); - return -EINVAL; - } - - if (rmi4_data->hw_if->bl_hw_init) { - retval = rmi4_data->hw_if->bl_hw_init(rmi4_data); - if (retval < 0) - return retval; - } - - retval = fwu_scan_pdt(); - if (retval < 0) - return retval; - - retval = fwu_read_f34_queries(); - if (retval < 0) - return retval; - - retval = synaptics_rmi4_reg_read(rmi4_data, - rmi4_data->f01_ctrl_base_addr, - f01_device_control.data, - sizeof(f01_device_control.data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read F01 device control\n", - __func__); - return retval; - } - - f01_device_control.nosleep = true; - f01_device_control.sleep_mode = SLEEP_MODE_NORMAL; - - retval = synaptics_rmi4_reg_write(rmi4_data, - rmi4_data->f01_ctrl_base_addr, - f01_device_control.data, - sizeof(f01_device_control.data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write F01 device control\n", - __func__); - return retval; - } - - msleep(ENTER_FLASH_PROG_WAIT_MS); - - return retval; -} - -static int fwu_check_ui_firmware_size(void) -{ - unsigned short block_count; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - block_count = fwu->img.ui_firmware.size / fwu->block_size; - - if (block_count != fwu->blkcount.ui_firmware) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: UI firmware size mismatch\n", - __func__); - return -EINVAL; - } - - return 0; -} - -static int fwu_check_ui_configuration_size(void) -{ - unsigned short block_count; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - block_count = fwu->img.ui_config.size / fwu->block_size; - - if (block_count != fwu->blkcount.ui_config) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: UI configuration size mismatch\n", - __func__); - return -EINVAL; - } - - return 0; -} - -static int fwu_check_dp_configuration_size(void) -{ - unsigned short block_count; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - block_count = fwu->img.dp_config.size / fwu->block_size; - - if (block_count != fwu->blkcount.dp_config) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Display configuration size mismatch\n", - __func__); - return -EINVAL; - } - - return 0; -} - -static int fwu_check_pm_configuration_size(void) -{ - unsigned short block_count; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - block_count = fwu->img.pm_config.size / fwu->block_size; - - if (block_count != fwu->blkcount.pm_config) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Permanent configuration size mismatch\n", - __func__); - return -EINVAL; - } - - return 0; -} - -static int fwu_check_bl_configuration_size(void) -{ - unsigned short block_count; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - block_count = fwu->img.bl_config.size / fwu->block_size; - - if (block_count != fwu->blkcount.bl_config) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Bootloader configuration size mismatch\n", - __func__); - return -EINVAL; - } - - return 0; -} - -static int fwu_check_guest_code_size(void) -{ - unsigned short block_count; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - block_count = fwu->img.guest_code.size / fwu->block_size; - if (block_count != fwu->blkcount.guest_code) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Guest code size mismatch\n", - __func__); - return -EINVAL; - } - - return 0; -} - -static int fwu_write_firmware(void) -{ - unsigned short firmware_block_count; - - firmware_block_count = fwu->img.ui_firmware.size / fwu->block_size; - - return fwu_write_f34_blocks((unsigned char *)fwu->img.ui_firmware.data, - firmware_block_count, CMD_WRITE_FW); -} - -static int fwu_erase_configuration(void) -{ - int retval; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - switch (fwu->config_area) { - case UI_CONFIG_AREA: - retval = fwu_write_f34_command(CMD_ERASE_UI_CONFIG); - if (retval < 0) - return retval; - break; - case DP_CONFIG_AREA: - retval = fwu_write_f34_command(CMD_ERASE_DISP_CONFIG); - if (retval < 0) - return retval; - break; - case BL_CONFIG_AREA: - retval = fwu_write_f34_command(CMD_ERASE_BL_CONFIG); - if (retval < 0) - return retval; - break; - } - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Erase command written\n", - __func__); - - retval = fwu_wait_for_idle(ERASE_WAIT_MS, false); - if (retval < 0) - return retval; - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Idle status detected\n", - __func__); - - return retval; -} - -static int fwu_erase_guest_code(void) -{ - int retval; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - retval = fwu_write_f34_command(CMD_ERASE_GUEST_CODE); - if (retval < 0) - return retval; - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Erase command written\n", - __func__); - - retval = fwu_wait_for_idle(ERASE_WAIT_MS, false); - if (retval < 0) - return retval; - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Idle status detected\n", - __func__); - - return 0; -} - -static int fwu_erase_all(void) -{ - int retval; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - if (fwu->bl_version == BL_V7) { - retval = fwu_write_f34_command(CMD_ERASE_UI_FIRMWARE); - if (retval < 0) - return retval; - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Erase command written\n", - __func__); - - retval = fwu_wait_for_idle(ERASE_WAIT_MS, false); - if (retval < 0) - return retval; - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Idle status detected\n", - __func__); - - fwu->config_area = UI_CONFIG_AREA; - retval = fwu_erase_configuration(); - if (retval < 0) - return retval; - } else { - retval = fwu_write_f34_command(CMD_ERASE_ALL); - if (retval < 0) - return retval; - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Erase all command written\n", - __func__); - - retval = fwu_wait_for_idle(ERASE_WAIT_MS, false); - if (!(fwu->bl_version == BL_V8 && - fwu->flash_status == BAD_PARTITION_TABLE)) { - if (retval < 0) - return retval; - } - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Idle status detected\n", - __func__); - - if (fwu->bl_version == BL_V8) - return 0; - } - - if (fwu->flash_properties.has_disp_config && - fwu->img.contains_disp_config) { - fwu->config_area = DP_CONFIG_AREA; - retval = fwu_erase_configuration(); - if (retval < 0) - return retval; - } - - if (fwu->has_guest_code && fwu->img.contains_guest_code) { - retval = fwu_erase_guest_code(); - if (retval < 0) - return retval; - } - - return 0; -} - -static int fwu_write_configuration(void) -{ - return fwu_write_f34_blocks((unsigned char *)fwu->config_data, - fwu->config_block_count, CMD_WRITE_CONFIG); -} - -static int fwu_write_ui_configuration(void) -{ - fwu->config_area = UI_CONFIG_AREA; - fwu->config_data = fwu->img.ui_config.data; - fwu->config_size = fwu->img.ui_config.size; - fwu->config_block_count = fwu->config_size / fwu->block_size; - - return fwu_write_configuration(); -} - -static int fwu_write_dp_configuration(void) -{ - fwu->config_area = DP_CONFIG_AREA; - fwu->config_data = fwu->img.dp_config.data; - fwu->config_size = fwu->img.dp_config.size; - fwu->config_block_count = fwu->config_size / fwu->block_size; - - return fwu_write_configuration(); -} - -static int fwu_write_pm_configuration(void) -{ - fwu->config_area = PM_CONFIG_AREA; - fwu->config_data = fwu->img.pm_config.data; - fwu->config_size = fwu->img.pm_config.size; - fwu->config_block_count = fwu->config_size / fwu->block_size; - - return fwu_write_configuration(); -} - -static int fwu_write_flash_configuration(void) -{ - int retval; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - fwu->config_area = FLASH_CONFIG_AREA; - fwu->config_data = fwu->img.fl_config.data; - fwu->config_size = fwu->img.fl_config.size; - fwu->config_block_count = fwu->config_size / fwu->block_size; - - if (fwu->config_block_count != fwu->blkcount.fl_config) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Flash configuration size mismatch\n", - __func__); - return -EINVAL; - } - - retval = fwu_write_f34_command(CMD_ERASE_FLASH_CONFIG); - if (retval < 0) - return retval; - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Erase flash configuration command written\n", - __func__); - - retval = fwu_wait_for_idle(ERASE_WAIT_MS, false); - if (retval < 0) - return retval; - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Idle status detected\n", - __func__); - - retval = fwu_write_configuration(); - if (retval < 0) - return retval; - - rmi4_data->reset_device(rmi4_data, false); - - return 0; -} - -static int fwu_write_guest_code(void) -{ - int retval; - unsigned short guest_code_block_count; - - guest_code_block_count = fwu->img.guest_code.size / fwu->block_size; - - retval = fwu_write_f34_blocks((unsigned char *)fwu->img.guest_code.data, - guest_code_block_count, CMD_WRITE_GUEST_CODE); - if (retval < 0) - return retval; - - return 0; -} - -static int fwu_write_lockdown(void) -{ - unsigned short lockdown_block_count; - - lockdown_block_count = fwu->img.lockdown.size / fwu->block_size; - - return fwu_write_f34_blocks((unsigned char *)fwu->img.lockdown.data, - lockdown_block_count, CMD_WRITE_LOCKDOWN); -} - -static int fwu_write_partition_table_v8(void) -{ - int retval; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - fwu->config_area = FLASH_CONFIG_AREA; - fwu->config_data = fwu->img.fl_config.data; - fwu->config_size = fwu->img.fl_config.size; - fwu->config_block_count = fwu->config_size / fwu->block_size; - - if (fwu->config_block_count != fwu->blkcount.fl_config) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Flash configuration size mismatch\n", - __func__); - return -EINVAL; - } - - retval = fwu_write_configuration(); - if (retval < 0) - return retval; - - rmi4_data->reset_device(rmi4_data, false); - - return 0; -} - -static int fwu_write_partition_table_v7(void) -{ - int retval; - unsigned short block_count; - - block_count = fwu->blkcount.bl_config; - fwu->config_area = BL_CONFIG_AREA; - fwu->config_size = fwu->block_size * block_count; - - retval = fwu_allocate_read_config_buf(fwu->config_size); - if (retval < 0) - return retval; - - retval = fwu_read_f34_blocks(block_count, CMD_READ_CONFIG); - if (retval < 0) - return retval; - - retval = fwu_erase_configuration(); - if (retval < 0) - return retval; - - retval = fwu_write_flash_configuration(); - if (retval < 0) - return retval; - - fwu->config_area = BL_CONFIG_AREA; - fwu->config_data = fwu->read_config_buf; - fwu->config_size = fwu->img.bl_config.size; - fwu->config_block_count = fwu->config_size / fwu->block_size; - - retval = fwu_write_configuration(); - if (retval < 0) - return retval; - - return 0; -} - -static int fwu_do_reflash(void) -{ - int retval; - - if (!fwu->new_partition_table) { - retval = fwu_check_ui_firmware_size(); - if (retval < 0) - return retval; - - retval = fwu_check_ui_configuration_size(); - if (retval < 0) - return retval; - - if (fwu->flash_properties.has_disp_config && - fwu->img.contains_disp_config) { - retval = fwu_check_dp_configuration_size(); - if (retval < 0) - return retval; - } - - if (fwu->has_guest_code && fwu->img.contains_guest_code) { - retval = fwu_check_guest_code_size(); - if (retval < 0) - return retval; - } - } else if (fwu->bl_version == BL_V7) { - retval = fwu_check_bl_configuration_size(); - if (retval < 0) - return retval; - } - - retval = fwu_erase_all(); - if (retval < 0) - return retval; - - if (fwu->bl_version == BL_V7 && fwu->new_partition_table) { - retval = fwu_write_partition_table_v7(); - if (retval < 0) - return retval; - pr_notice("%s: Partition table programmed\n", __func__); - } else if (fwu->bl_version == BL_V8) { - retval = fwu_write_partition_table_v8(); - if (retval < 0) - return retval; - pr_notice("%s: Partition table programmed\n", __func__); - } - - retval = fwu_write_firmware(); - if (retval < 0) - return retval; - pr_notice("%s: Firmware programmed\n", __func__); - - fwu->config_area = UI_CONFIG_AREA; - retval = fwu_write_ui_configuration(); - if (retval < 0) - return retval; - pr_notice("%s: Configuration programmed\n", __func__); - - if (fwu->flash_properties.has_disp_config && - fwu->img.contains_disp_config) { - retval = fwu_write_dp_configuration(); - if (retval < 0) - return retval; - pr_notice("%s: Display configuration programmed\n", __func__); - } - - if (fwu->has_guest_code && fwu->img.contains_guest_code) { - retval = fwu_write_guest_code(); - if (retval < 0) - return retval; - pr_notice("%s: Guest code programmed\n", __func__); - } - - return retval; -} - -static int fwu_do_read_config(void) -{ - int retval; - unsigned short block_count; - unsigned short config_area; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - switch (fwu->config_area) { - case UI_CONFIG_AREA: - block_count = fwu->blkcount.ui_config; - break; - case DP_CONFIG_AREA: - if (!fwu->flash_properties.has_disp_config) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Display configuration not supported\n", - __func__); - return -EINVAL; - } - block_count = fwu->blkcount.dp_config; - break; - case PM_CONFIG_AREA: - if (!fwu->flash_properties.has_pm_config) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Permanent configuration not supported\n", - __func__); - return -EINVAL; - } - block_count = fwu->blkcount.pm_config; - break; - case BL_CONFIG_AREA: - if (!fwu->flash_properties.has_bl_config) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Bootloader configuration not supported\n", - __func__); - return -EINVAL; - } - block_count = fwu->blkcount.bl_config; - break; - default: - dev_err(rmi4_data->pdev->dev.parent, - "%s: Invalid config area\n", - __func__); - return -EINVAL; - } - - if (block_count == 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Invalid block count\n", - __func__); - return -EINVAL; - } - - mutex_lock(&rmi4_data->rmi4_exp_init_mutex); - - config_area = fwu->config_area; - - retval = fwu_enter_flash_prog(); - if (retval < 0) - goto exit; - - fwu->config_area = config_area; - - fwu->config_size = fwu->block_size * block_count; - - retval = fwu_allocate_read_config_buf(fwu->config_size); - if (retval < 0) - goto exit; - - retval = fwu_read_f34_blocks(block_count, CMD_READ_CONFIG); - -exit: - rmi4_data->reset_device(rmi4_data, false); - - mutex_unlock(&rmi4_data->rmi4_exp_init_mutex); - - return retval; -} - -static int fwu_do_lockdown_v7(void) -{ - int retval; - struct f34_v7_data0 status; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - retval = fwu_enter_flash_prog(); - if (retval < 0) - return retval; - - retval = synaptics_rmi4_reg_read(rmi4_data, - fwu->f34_fd.data_base_addr + fwu->off.flash_status, - status.data, - sizeof(status.data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read flash status\n", - __func__); - return retval; - } - - if (status.device_cfg_status == 2) { - dev_info(rmi4_data->pdev->dev.parent, - "%s: Device already locked down\n", - __func__); - return 0; - } - - retval = fwu_write_lockdown(); - if (retval < 0) - return retval; - - pr_notice("%s: Lockdown programmed\n", __func__); - - return retval; -} - -static int fwu_do_lockdown_v5v6(void) -{ - int retval; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - retval = fwu_enter_flash_prog(); - if (retval < 0) - return retval; - - retval = synaptics_rmi4_reg_read(rmi4_data, - fwu->f34_fd.query_base_addr + fwu->off.properties, - fwu->flash_properties.data, - sizeof(fwu->flash_properties.data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read flash properties\n", - __func__); - return retval; - } - - if (fwu->flash_properties.unlocked == 0) { - dev_info(rmi4_data->pdev->dev.parent, - "%s: Device already locked down\n", - __func__); - return 0; - } - - retval = fwu_write_lockdown(); - if (retval < 0) - return retval; - - pr_notice("%s: Lockdown programmed\n", __func__); - - return retval; -} - -static int fwu_start_write_guest_code(void) -{ - int retval; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - retval = fwu_parse_image_info(); - if (retval < 0) - return -EINVAL; - - if (!fwu->has_guest_code) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Guest code not supported\n", - __func__); - return -EINVAL; - } - - if (!fwu->img.contains_guest_code) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: No guest code in firmware image\n", - __func__); - return -EINVAL; - } - - if (rmi4_data->sensor_sleep) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Sensor sleeping\n", - __func__); - return -ENODEV; - } - - rmi4_data->stay_awake = true; - - mutex_lock(&rmi4_data->rmi4_exp_init_mutex); - - pr_notice("%s: Start of write guest code process\n", __func__); - - retval = fwu_enter_flash_prog(); - if (retval < 0) - goto exit; - - retval = fwu_check_guest_code_size(); - if (retval < 0) - goto exit; - - retval = fwu_erase_guest_code(); - if (retval < 0) - goto exit; - - retval = fwu_write_guest_code(); - if (retval < 0) - goto exit; - - pr_notice("%s: Guest code programmed\n", __func__); - -exit: - rmi4_data->reset_device(rmi4_data, false); - - pr_notice("%s: End of write guest code process\n", __func__); - - mutex_unlock(&rmi4_data->rmi4_exp_init_mutex); - - rmi4_data->stay_awake = false; - - return retval; -} - -static int fwu_start_write_config(void) -{ - int retval; - unsigned short config_area; - unsigned int device_fw_id; - unsigned int image_fw_id; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - retval = fwu_parse_image_info(); - if (retval < 0) - return -EINVAL; - - switch (fwu->config_area) { - case UI_CONFIG_AREA: - device_fw_id = rmi4_data->firmware_id; - retval = fwu_get_image_firmware_id(&image_fw_id); - if (retval < 0) - return retval; - if (device_fw_id != image_fw_id) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Device and image firmware IDs don't match\n", - __func__); - return -EINVAL; - } - retval = fwu_check_ui_configuration_size(); - if (retval < 0) - return retval; - break; - case DP_CONFIG_AREA: - if (!fwu->flash_properties.has_disp_config) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Display configuration not supported\n", - __func__); - return -EINVAL; - } - if (!fwu->img.contains_disp_config) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: No display configuration in firmware image\n", - __func__); - return -EINVAL; - } - retval = fwu_check_dp_configuration_size(); - if (retval < 0) - return retval; - break; - case PM_CONFIG_AREA: - if (!fwu->flash_properties.has_pm_config) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Permanent configuration not supported\n", - __func__); - return -EINVAL; - } - if (!fwu->img.contains_perm_config) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: No permanent configuration in firmware image\n", - __func__); - return -EINVAL; - } - retval = fwu_check_pm_configuration_size(); - if (retval < 0) - return retval; - break; - default: - dev_err(rmi4_data->pdev->dev.parent, - "%s: Configuration not supported\n", - __func__); - return -EINVAL; - } - - if (rmi4_data->sensor_sleep) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Sensor sleeping\n", - __func__); - return -ENODEV; - } - - rmi4_data->stay_awake = true; - - mutex_lock(&rmi4_data->rmi4_exp_init_mutex); - - pr_notice("%s: Start of write config process\n", __func__); - - config_area = fwu->config_area; - - retval = fwu_enter_flash_prog(); - if (retval < 0) - goto exit; - - fwu->config_area = config_area; - - if (fwu->config_area != PM_CONFIG_AREA) { - retval = fwu_erase_configuration(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to erase config\n", - __func__); - goto exit; - } - } - - switch (fwu->config_area) { - case UI_CONFIG_AREA: - retval = fwu_write_ui_configuration(); - if (retval < 0) - goto exit; - break; - case DP_CONFIG_AREA: - retval = fwu_write_dp_configuration(); - if (retval < 0) - goto exit; - break; - case PM_CONFIG_AREA: - retval = fwu_write_pm_configuration(); - if (retval < 0) - goto exit; - break; - } - - pr_notice("%s: Config written\n", __func__); - -exit: - switch (fwu->config_area) { - case UI_CONFIG_AREA: - rmi4_data->reset_device(rmi4_data, true); - break; - case DP_CONFIG_AREA: - case PM_CONFIG_AREA: - rmi4_data->reset_device(rmi4_data, false); - break; - } - - pr_notice("%s: End of write config process\n", __func__); - - mutex_unlock(&rmi4_data->rmi4_exp_init_mutex); - - rmi4_data->stay_awake = false; - - return retval; -} - -static int fwu_start_reflash(void) -{ - int retval = 0; - enum flash_area flash_area; - const struct firmware *fw_entry = NULL; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - if (rmi4_data->sensor_sleep) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Sensor sleeping\n", - __func__); - return -ENODEV; - } - - rmi4_data->stay_awake = true; - - mutex_lock(&rmi4_data->rmi4_exp_init_mutex); - - pr_notice("%s: Start of reflash process\n", __func__); - - if (fwu->image == NULL) { - retval = secure_memcpy(fwu->image_name, MAX_IMAGE_NAME_LEN, - FW_IMAGE_NAME, sizeof(FW_IMAGE_NAME), - sizeof(FW_IMAGE_NAME)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to copy image file name\n", - __func__); - goto exit; - } - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Requesting firmware image %s\n", - __func__, fwu->image_name); - - retval = request_firmware(&fw_entry, fwu->image_name, - rmi4_data->pdev->dev.parent); - if (retval != 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Firmware image %s not available\n", - __func__, fwu->image_name); - retval = -EINVAL; - goto exit; - } - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Firmware image size = %d\n", - __func__, (unsigned int)fw_entry->size); - - fwu->image = fw_entry->data; - } - - retval = fwu_parse_image_info(); - if (retval < 0) - goto exit; - - if (fwu->blkcount.total_count != fwu->img.blkcount.total_count) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Flash size mismatch\n", - __func__); - retval = -EINVAL; - goto exit; - } - - if (fwu->bl_version != fwu->img.bl_version) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Bootloader version mismatch\n", - __func__); - retval = -EINVAL; - goto exit; - } - - if (!fwu->force_update && fwu->new_partition_table) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Partition table mismatch\n", - __func__); - retval = -EINVAL; - goto exit; - } - - retval = fwu_read_flash_status(); - if (retval < 0) - goto exit; - - if (fwu->in_bl_mode) { - dev_info(rmi4_data->pdev->dev.parent, - "%s: Device in bootloader mode\n", - __func__); - } - - flash_area = fwu_go_nogo(); - - if (flash_area != NONE) { - retval = fwu_enter_flash_prog(); - if (retval < 0) { - rmi4_data->reset_device(rmi4_data, false); - goto exit; - } - } - - switch (flash_area) { - case UI_FIRMWARE: - retval = fwu_do_reflash(); - rmi4_data->reset_device(rmi4_data, true); - break; - case UI_CONFIG: - retval = fwu_check_ui_configuration_size(); - if (retval < 0) - break; - fwu->config_area = UI_CONFIG_AREA; - retval = fwu_erase_configuration(); - if (retval < 0) - break; - retval = fwu_write_ui_configuration(); - rmi4_data->reset_device(rmi4_data, true); - break; - case NONE: - default: - rmi4_data->reset_device(rmi4_data, false); - break; - } - - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to do reflash\n", - __func__); - goto exit; - } - - if (fwu->do_lockdown && (fwu->img.lockdown.data != NULL)) { - switch (fwu->bl_version) { - case BL_V5: - case BL_V6: - retval = fwu_do_lockdown_v5v6(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to do lockdown\n", - __func__); - } - rmi4_data->reset_device(rmi4_data, false); - break; - case BL_V7: - case BL_V8: - retval = fwu_do_lockdown_v7(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to do lockdown\n", - __func__); - } - rmi4_data->reset_device(rmi4_data, false); - break; - default: - break; - } - } - -exit: - if (fw_entry) - release_firmware(fw_entry); - - pr_notice("%s: End of reflash process\n", __func__); - - mutex_unlock(&rmi4_data->rmi4_exp_init_mutex); - - rmi4_data->stay_awake = false; - - return retval; -} - -static int fwu_recovery_check_status(void) -{ - int retval; - unsigned char base; - unsigned char status; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - base = fwu->f35_fd.data_base_addr; - - retval = synaptics_rmi4_reg_read(rmi4_data, - base + F35_ERROR_CODE_OFFSET, - &status, - 1); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read status\n", - __func__); - return retval; - } - - status = status & MASK_7BIT; - - if (status != 0x00) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Recovery mode status = %d\n", - __func__, status); - return -EINVAL; - } - - return 0; -} - -static int fwu_recovery_erase_all(void) -{ - int retval; - unsigned char base; - unsigned char command = CMD_F35_ERASE_ALL; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - base = fwu->f35_fd.ctrl_base_addr; - - retval = synaptics_rmi4_reg_write(rmi4_data, - base + F35_CHUNK_COMMAND_OFFSET, - &command, - sizeof(command)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to issue erase all command\n", - __func__); - return retval; - } - - msleep(F35_ERASE_ALL_WAIT_MS); - - retval = fwu_recovery_check_status(); - if (retval < 0) - return retval; - - return 0; -} - -static int fwu_recovery_write_chunk(void) -{ - int retval; - unsigned char base; - unsigned char chunk_number[] = {0, 0}; - unsigned char chunk_spare; - unsigned char chunk_size; - unsigned char buf[F35_CHUNK_SIZE + 1]; - unsigned short chunk; - unsigned short chunk_total; - unsigned short bytes_written = 0; - unsigned char *chunk_ptr = (unsigned char *)fwu->image; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - base = fwu->f35_fd.ctrl_base_addr; - - retval = synaptics_rmi4_reg_write(rmi4_data, - base + F35_CHUNK_NUM_LSB_OFFSET, - chunk_number, - sizeof(chunk_number)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write chunk number\n", - __func__); - return retval; - } - - buf[sizeof(buf) - 1] = CMD_F35_WRITE_CHUNK; - - chunk_total = fwu->image_size / F35_CHUNK_SIZE; - chunk_spare = fwu->image_size % F35_CHUNK_SIZE; - if (chunk_spare) - chunk_total++; - - for (chunk = 0; chunk < chunk_total; chunk++) { - if (chunk_spare && chunk == chunk_total - 1) - chunk_size = chunk_spare; - else - chunk_size = F35_CHUNK_SIZE; - - memset(buf, 0x00, F35_CHUNK_SIZE); - secure_memcpy(buf, sizeof(buf), chunk_ptr, - fwu->image_size - bytes_written, - chunk_size); - - retval = synaptics_rmi4_reg_write(rmi4_data, - base + F35_CHUNK_DATA_OFFSET, - buf, - sizeof(buf)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write chunk data (chunk %d)\n", - __func__, chunk); - return retval; - } - chunk_ptr += chunk_size; - bytes_written += chunk_size; - } - - retval = fwu_recovery_check_status(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write chunk data\n", - __func__); - return retval; - } - - return 0; -} - -static int fwu_recovery_reset(void) -{ - int retval; - unsigned char base; - unsigned char command = CMD_F35_RESET; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - base = fwu->f35_fd.ctrl_base_addr; - - retval = synaptics_rmi4_reg_write(rmi4_data, - base + F35_CHUNK_COMMAND_OFFSET, - &command, - sizeof(command)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to issue reset command\n", - __func__); - return retval; - } - - msleep(F35_RESET_WAIT_MS); - - return 0; -} - -static int fwu_start_recovery(void) -{ - int retval; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - if (rmi4_data->sensor_sleep) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Sensor sleeping\n", - __func__); - return -ENODEV; - } - - rmi4_data->stay_awake = true; - - mutex_lock(&rmi4_data->rmi4_exp_init_mutex); - - pr_notice("%s: Start of recovery process\n", __func__); - - retval = rmi4_data->irq_enable(rmi4_data, false, false); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to disable interrupt\n", - __func__); - goto exit; - } - - retval = fwu_recovery_erase_all(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to do erase all in recovery mode\n", - __func__); - goto exit; - } - - pr_notice("%s: External flash erased\n", __func__); - - retval = fwu_recovery_write_chunk(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write chunk data in recovery mode\n", - __func__); - goto exit; - } - - pr_notice("%s: Chunk data programmed\n", __func__); - - retval = fwu_recovery_reset(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to reset device in recovery mode\n", - __func__); - goto exit; - } - - pr_notice("%s: Recovery mode reset issued\n", __func__); - - rmi4_data->reset_device(rmi4_data, true); - - retval = 0; - -exit: - pr_notice("%s: End of recovery process\n", __func__); - - mutex_unlock(&rmi4_data->rmi4_exp_init_mutex); - - rmi4_data->stay_awake = false; - - return retval; -} - -int synaptics_fw_updater(const unsigned char *fw_data) -{ - int retval; - - if (!fwu) - return -ENODEV; - - if (!fwu->initialized) - return -ENODEV; - - if (fwu->in_ub_mode) - return -ENODEV; - - fwu->image = fw_data; - - retval = fwu_start_reflash(); - - fwu->image = NULL; - - return retval; -} -EXPORT_SYMBOL(synaptics_fw_updater); - -#ifdef DO_STARTUP_FW_UPDATE -static void fwu_startup_fw_update_work(struct work_struct *work) -{ - static unsigned char do_once = 1; -#ifdef WAIT_FOR_FB_READY - unsigned int timeout; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; -#endif - - if (!do_once) - return; - do_once = 0; - -#ifdef WAIT_FOR_FB_READY - timeout = FB_READY_TIMEOUT_S * 1000 / FB_READY_WAIT_MS + 1; - - while (!rmi4_data->fb_ready) { - msleep(FB_READY_WAIT_MS); - timeout--; - if (timeout == 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Timed out waiting for FB ready\n", - __func__); - return; - } - } -#endif - - synaptics_fw_updater(NULL); - - return; -} -#endif - -static ssize_t fwu_sysfs_show_image(struct file *data_file, - struct kobject *kobj, struct bin_attribute *attributes, - char *buf, loff_t pos, size_t count) -{ - int retval; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - if (count < fwu->config_size) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Not enough space (%d bytes) in buffer\n", - __func__, (unsigned int)count); - return -EINVAL; - } - - retval = secure_memcpy(buf, count, fwu->read_config_buf, - fwu->read_config_buf_size, fwu->config_size); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to copy config data\n", - __func__); - return retval; - } - - return fwu->config_size; -} - -static ssize_t fwu_sysfs_store_image(struct file *data_file, - struct kobject *kobj, struct bin_attribute *attributes, - char *buf, loff_t pos, size_t count) -{ - int retval; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - retval = secure_memcpy(&fwu->ext_data_source[fwu->data_pos], - fwu->image_size - fwu->data_pos, buf, count, count); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to copy image data\n", - __func__); - return retval; - } - - fwu->data_pos += count; - - return count; -} - -static ssize_t fwu_sysfs_do_recovery_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned int input; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - if (sscanf(buf, "%u", &input) != 1) { - retval = -EINVAL; - goto exit; - } - - if (!fwu->in_ub_mode) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Not in microbootloader mode\n", - __func__); - retval = -EINVAL; - goto exit; - } - - if (!fwu->ext_data_source) - return -EINVAL; - else - fwu->image = fwu->ext_data_source; - - retval = fwu_start_recovery(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to do recovery\n", - __func__); - goto exit; - } - - retval = count; - -exit: - kfree(fwu->ext_data_source); - fwu->ext_data_source = NULL; - fwu->image = NULL; - return retval; -} - -static ssize_t fwu_sysfs_do_reflash_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned int input; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - if (sscanf(buf, "%u", &input) != 1) { - retval = -EINVAL; - goto exit; - } - - if (fwu->in_ub_mode) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: In microbootloader mode\n", - __func__); - retval = -EINVAL; - goto exit; - } - - if (!fwu->ext_data_source) - return -EINVAL; - else - fwu->image = fwu->ext_data_source; - - if (input & LOCKDOWN) { - fwu->do_lockdown = true; - input &= ~LOCKDOWN; - } - - if ((input != NORMAL) && (input != FORCE)) { - retval = -EINVAL; - goto exit; - } - - if (input == FORCE) - fwu->force_update = true; - - retval = synaptics_fw_updater(fwu->image); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to do reflash\n", - __func__); - goto exit; - } - - retval = count; - -exit: - kfree(fwu->ext_data_source); - fwu->ext_data_source = NULL; - fwu->image = NULL; - fwu->force_update = FORCE_UPDATE; - fwu->do_lockdown = DO_LOCKDOWN; - return retval; -} - -static ssize_t fwu_sysfs_write_config_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned int input; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - if (sscanf(buf, "%u", &input) != 1) { - retval = -EINVAL; - goto exit; - } - - if (input != 1) { - retval = -EINVAL; - goto exit; - } - - if (fwu->in_ub_mode) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: In microbootloader mode\n", - __func__); - retval = -EINVAL; - goto exit; - } - - if (!fwu->ext_data_source) - return -EINVAL; - else - fwu->image = fwu->ext_data_source; - - retval = fwu_start_write_config(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write config\n", - __func__); - goto exit; - } - - retval = count; - -exit: - kfree(fwu->ext_data_source); - fwu->ext_data_source = NULL; - fwu->image = NULL; - return retval; -} - -static ssize_t fwu_sysfs_read_config_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned int input; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - if (sscanf(buf, "%u", &input) != 1) - return -EINVAL; - - if (input != 1) - return -EINVAL; - - if (fwu->in_ub_mode) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: In microbootloader mode\n", - __func__); - return -EINVAL; - } - - retval = fwu_do_read_config(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read config\n", - __func__); - return retval; - } - - return count; -} - -static ssize_t fwu_sysfs_config_area_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned long config_area; - - retval = sstrtoul(buf, 10, &config_area); - if (retval) - return retval; - - fwu->config_area = config_area; - - return count; -} - -static ssize_t fwu_sysfs_image_name_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - retval = secure_memcpy(fwu->image_name, MAX_IMAGE_NAME_LEN, - buf, count, count); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to copy image file name\n", - __func__); - return retval; - } - - return count; -} - -static ssize_t fwu_sysfs_image_size_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned long size; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - retval = sstrtoul(buf, 10, &size); - if (retval) - return retval; - - fwu->image_size = size; - fwu->data_pos = 0; - - kfree(fwu->ext_data_source); - fwu->ext_data_source = kzalloc(fwu->image_size, GFP_KERNEL); - if (!fwu->ext_data_source) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for image data\n", - __func__); - return -ENOMEM; - } - - return count; -} - -static ssize_t fwu_sysfs_block_size_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%u\n", fwu->block_size); -} - -static ssize_t fwu_sysfs_firmware_block_count_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%u\n", fwu->blkcount.ui_firmware); -} - -static ssize_t fwu_sysfs_configuration_block_count_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%u\n", fwu->blkcount.ui_config); -} - -static ssize_t fwu_sysfs_disp_config_block_count_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%u\n", fwu->blkcount.dp_config); -} - -static ssize_t fwu_sysfs_perm_config_block_count_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%u\n", fwu->blkcount.pm_config); -} - -static ssize_t fwu_sysfs_bl_config_block_count_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%u\n", fwu->blkcount.bl_config); -} - -static ssize_t fwu_sysfs_guest_code_block_count_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%u\n", fwu->blkcount.guest_code); -} - -static ssize_t fwu_sysfs_write_guest_code_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned int input; - struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; - - if (sscanf(buf, "%u", &input) != 1) { - retval = -EINVAL; - goto exit; - } - - if (input != 1) { - retval = -EINVAL; - goto exit; - } - - if (fwu->in_ub_mode) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: In microbootloader mode\n", - __func__); - retval = -EINVAL; - goto exit; - } - - if (!fwu->ext_data_source) - return -EINVAL; - else - fwu->image = fwu->ext_data_source; - - retval = fwu_start_write_guest_code(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write guest code\n", - __func__); - goto exit; - } - - retval = count; - -exit: - kfree(fwu->ext_data_source); - fwu->ext_data_source = NULL; - fwu->image = NULL; - return retval; -} - -static void synaptics_rmi4_fwu_attn(struct synaptics_rmi4_data *rmi4_data, - unsigned char intr_mask) -{ - if (!fwu) - return; - - if (fwu->intr_mask & intr_mask) - fwu_read_flash_status(); - - return; -} - -static int synaptics_rmi4_fwu_init(struct synaptics_rmi4_data *rmi4_data) -{ - int retval; - unsigned char attr_count; - struct pdt_properties pdt_props; - - if (fwu) { - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Handle already exists\n", - __func__); - return 0; - } - - fwu = kzalloc(sizeof(*fwu), GFP_KERNEL); - if (!fwu) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for fwu\n", - __func__); - retval = -ENOMEM; - goto exit; - } - - fwu->image_name = kzalloc(MAX_IMAGE_NAME_LEN, GFP_KERNEL); - if (!fwu->image_name) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for image name\n", - __func__); - retval = -ENOMEM; - goto exit_free_fwu; - } - - fwu->rmi4_data = rmi4_data; - - retval = synaptics_rmi4_reg_read(rmi4_data, - PDT_PROPS, - pdt_props.data, - sizeof(pdt_props.data)); - if (retval < 0) { - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Failed to read PDT properties, assuming 0x00\n", - __func__); - } else if (pdt_props.has_bsr) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Reflash for LTS not currently supported\n", - __func__); - retval = -ENODEV; - goto exit_free_mem; - } - - retval = fwu_scan_pdt(); - if (retval < 0) - goto exit_free_mem; - - if (!fwu->in_ub_mode) { - retval = fwu_read_f34_queries(); - if (retval < 0) - goto exit_free_mem; - - retval = fwu_get_device_config_id(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read device config ID\n", - __func__); - goto exit_free_mem; - } - } - - fwu->force_update = FORCE_UPDATE; - fwu->do_lockdown = DO_LOCKDOWN; - fwu->initialized = true; - - retval = sysfs_create_bin_file(&rmi4_data->input_dev->dev.kobj, - &dev_attr_data); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create sysfs bin file\n", - __func__); - goto exit_free_mem; - } - - for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { - retval = sysfs_create_file(&rmi4_data->input_dev->dev.kobj, - &attrs[attr_count].attr); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create sysfs attributes\n", - __func__); - retval = -ENODEV; - goto exit_remove_attrs; - } - } - -#ifdef DO_STARTUP_FW_UPDATE - fwu->fwu_workqueue = create_singlethread_workqueue("fwu_workqueue"); - INIT_WORK(&fwu->fwu_work, fwu_startup_fw_update_work); - queue_work(fwu->fwu_workqueue, - &fwu->fwu_work); -#endif - - return 0; - -exit_remove_attrs: - for (attr_count--; attr_count >= 0; attr_count--) { - sysfs_remove_file(&rmi4_data->input_dev->dev.kobj, - &attrs[attr_count].attr); - } - - sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data); - -exit_free_mem: - kfree(fwu->image_name); - -exit_free_fwu: - kfree(fwu); - fwu = NULL; - -exit: - return retval; -} - -static void synaptics_rmi4_fwu_remove(struct synaptics_rmi4_data *rmi4_data) -{ - unsigned char attr_count; - - if (!fwu) - goto exit; - -#ifdef DO_STARTUP_FW_UPDATE - cancel_work_sync(&fwu->fwu_work); - flush_workqueue(fwu->fwu_workqueue); - destroy_workqueue(fwu->fwu_workqueue); -#endif - - for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { - sysfs_remove_file(&rmi4_data->input_dev->dev.kobj, - &attrs[attr_count].attr); - } - - sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data); - - kfree(fwu->read_config_buf); - kfree(fwu->image_name); - kfree(fwu); - fwu = NULL; - -exit: - complete(&fwu_remove_complete); - - return; -} - -static void synaptics_rmi4_fwu_reset(struct synaptics_rmi4_data *rmi4_data) -{ - int retval; - - if (!fwu) { - synaptics_rmi4_fwu_init(rmi4_data); - return; - } - - retval = fwu_scan_pdt(); - if (retval < 0) - return; - - if (!fwu->in_ub_mode) - fwu_read_f34_queries(); - - return; -} - -static struct synaptics_rmi4_exp_fn fwu_module = { - .fn_type = RMI_FW_UPDATER, - .init = synaptics_rmi4_fwu_init, - .remove = synaptics_rmi4_fwu_remove, - .reset = synaptics_rmi4_fwu_reset, - .reinit = NULL, - .early_suspend = NULL, - .suspend = NULL, - .resume = NULL, - .late_resume = NULL, - .attn = synaptics_rmi4_fwu_attn, -}; - -static int __init rmi4_fw_update_module_init(void) -{ - synaptics_rmi4_new_function(&fwu_module, true); - - return 0; -} - -static void __exit rmi4_fw_update_module_exit(void) -{ - synaptics_rmi4_new_function(&fwu_module, false); - - wait_for_completion(&fwu_remove_complete); - - return; -} - -module_init(rmi4_fw_update_module_init); -module_exit(rmi4_fw_update_module_exit); - -MODULE_AUTHOR("Synaptics, Inc."); -MODULE_DESCRIPTION("Synaptics DSX FW Update Module"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_gesture.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_gesture.c deleted file mode 100644 index de8656389cad..000000000000 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_gesture.c +++ /dev/null @@ -1,2308 +0,0 @@ -/* - * Synaptics DSX touchscreen driver - * - * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved. - * - * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com> - * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com> - * - * 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. - * - * 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. - * - * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS - * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, - * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS. - * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION - * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED - * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES - * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' - * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. - * DOLLARS. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/input.h> -#include <linux/platform_device.h> -#include <linux/input/synaptics_dsx_v2_6.h> -#include "synaptics_dsx_core.h" - -#define GESTURE_PHYS_NAME "synaptics_dsx/gesture" - -#define TUNING_SYSFS_DIR_NAME "tuning" - -#define STORE_GESTURES -#ifdef STORE_GESTURES -#define GESTURES_TO_STORE 10 -#endif - -#define CTRL23_FINGER_REPORT_ENABLE_BIT 0 -#define CTRL27_UDG_ENABLE_BIT 4 -#define WAKEUP_GESTURE_MODE 0x02 - -static ssize_t udg_sysfs_engine_enable_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t udg_sysfs_detection_enable_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t udg_sysfs_detection_score_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t udg_sysfs_detection_index_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t udg_sysfs_registration_enable_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t udg_sysfs_registration_begin_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t udg_sysfs_registration_status_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t udg_sysfs_template_size_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t udg_sysfs_template_max_index_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t udg_sysfs_template_detection_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t udg_sysfs_template_index_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t udg_sysfs_template_valid_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t udg_sysfs_template_valid_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t udg_sysfs_template_clear_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t udg_sysfs_trace_size_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t udg_sysfs_template_data_show(struct file *data_file, - struct kobject *kobj, struct bin_attribute *attributes, - char *buf, loff_t pos, size_t count); - -static ssize_t udg_sysfs_template_data_store(struct file *data_file, - struct kobject *kobj, struct bin_attribute *attributes, - char *buf, loff_t pos, size_t count); - -static ssize_t udg_sysfs_trace_data_show(struct file *data_file, - struct kobject *kobj, struct bin_attribute *attributes, - char *buf, loff_t pos, size_t count); - -static ssize_t udg_sysfs_template_displacement_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t udg_sysfs_template_displacement_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t udg_sysfs_rotation_invariance_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t udg_sysfs_rotation_invariance_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t udg_sysfs_scale_invariance_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t udg_sysfs_scale_invariance_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t udg_sysfs_threshold_factor_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t udg_sysfs_threshold_factor_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t udg_sysfs_match_metric_threshold_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t udg_sysfs_match_metric_threshold_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t udg_sysfs_max_inter_stroke_time_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t udg_sysfs_max_inter_stroke_time_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static int udg_read_tuning_params(void); - -static int udg_write_tuning_params(void); - -static int udg_detection_enable(bool enable); - -static int udg_engine_enable(bool enable); - -static int udg_set_index(unsigned char index); - -#ifdef STORE_GESTURES -static int udg_read_valid_data(void); -static int udg_write_valid_data(void); -static int udg_read_template_data(unsigned char index); -static int udg_write_template_data(void); -#endif - -enum gesture_type { - DETECTION = 0x0f, - REGISTRATION = 0x10, -}; - -struct udg_tuning { - union { - struct { - unsigned char maximum_number_of_templates; - unsigned char template_size; - unsigned char template_disp_lsb; - unsigned char template_disp_msb; - unsigned char rotation_inv_lsb; - unsigned char rotation_inv_msb; - unsigned char scale_inv_lsb; - unsigned char scale_inv_msb; - unsigned char thres_factor_lsb; - unsigned char thres_factor_msb; - unsigned char metric_thres_lsb; - unsigned char metric_thres_msb; - unsigned char inter_stroke_lsb; - unsigned char inter_stroke_msb; - } __packed; - unsigned char data[14]; - }; -}; - -struct udg_addr { - unsigned short data_4; - unsigned short ctrl_18; - unsigned short ctrl_20; - unsigned short ctrl_23; - unsigned short ctrl_27; - unsigned short ctrl_41; - unsigned short trace_x; - unsigned short trace_y; - unsigned short trace_segment; - unsigned short template_helper; - unsigned short template_data; - unsigned short template_flags; -}; - -struct synaptics_rmi4_f12_query_0 { - union { - struct { - struct { - unsigned char has_register_descriptors:1; - unsigned char has_closed_cover:1; - unsigned char has_fast_glove_detect:1; - unsigned char has_dribble:1; - unsigned char has_4p4_jitter_filter_strength:1; - unsigned char f12_query0_s0_b5__7:3; - } __packed; - struct { - unsigned char max_num_templates:4; - unsigned char f12_query0_s1_b4__7:4; - unsigned char template_size_lsb; - unsigned char template_size_msb; - } __packed; - }; - unsigned char data[4]; - }; -}; - -struct synaptics_rmi4_f12_query_5 { - union { - struct { - unsigned char size_of_query6; - struct { - unsigned char ctrl0_is_present:1; - unsigned char ctrl1_is_present:1; - unsigned char ctrl2_is_present:1; - unsigned char ctrl3_is_present:1; - unsigned char ctrl4_is_present:1; - unsigned char ctrl5_is_present:1; - unsigned char ctrl6_is_present:1; - unsigned char ctrl7_is_present:1; - } __packed; - struct { - unsigned char ctrl8_is_present:1; - unsigned char ctrl9_is_present:1; - unsigned char ctrl10_is_present:1; - unsigned char ctrl11_is_present:1; - unsigned char ctrl12_is_present:1; - unsigned char ctrl13_is_present:1; - unsigned char ctrl14_is_present:1; - unsigned char ctrl15_is_present:1; - } __packed; - struct { - unsigned char ctrl16_is_present:1; - unsigned char ctrl17_is_present:1; - unsigned char ctrl18_is_present:1; - unsigned char ctrl19_is_present:1; - unsigned char ctrl20_is_present:1; - unsigned char ctrl21_is_present:1; - unsigned char ctrl22_is_present:1; - unsigned char ctrl23_is_present:1; - } __packed; - struct { - unsigned char ctrl24_is_present:1; - unsigned char ctrl25_is_present:1; - unsigned char ctrl26_is_present:1; - unsigned char ctrl27_is_present:1; - unsigned char ctrl28_is_present:1; - unsigned char ctrl29_is_present:1; - unsigned char ctrl30_is_present:1; - unsigned char ctrl31_is_present:1; - } __packed; - struct { - unsigned char ctrl32_is_present:1; - unsigned char ctrl33_is_present:1; - unsigned char ctrl34_is_present:1; - unsigned char ctrl35_is_present:1; - unsigned char ctrl36_is_present:1; - unsigned char ctrl37_is_present:1; - unsigned char ctrl38_is_present:1; - unsigned char ctrl39_is_present:1; - } __packed; - struct { - unsigned char ctrl40_is_present:1; - unsigned char ctrl41_is_present:1; - unsigned char ctrl42_is_present:1; - unsigned char ctrl43_is_present:1; - unsigned char ctrl44_is_present:1; - unsigned char ctrl45_is_present:1; - unsigned char ctrl46_is_present:1; - unsigned char ctrl47_is_present:1; - } __packed; - }; - unsigned char data[7]; - }; -}; - -struct synaptics_rmi4_f12_query_8 { - union { - struct { - unsigned char size_of_query9; - struct { - unsigned char data0_is_present:1; - unsigned char data1_is_present:1; - unsigned char data2_is_present:1; - unsigned char data3_is_present:1; - unsigned char data4_is_present:1; - unsigned char data5_is_present:1; - unsigned char data6_is_present:1; - unsigned char data7_is_present:1; - } __packed; - struct { - unsigned char data8_is_present:1; - unsigned char data9_is_present:1; - unsigned char data10_is_present:1; - unsigned char data11_is_present:1; - unsigned char data12_is_present:1; - unsigned char data13_is_present:1; - unsigned char data14_is_present:1; - unsigned char data15_is_present:1; - } __packed; - struct { - unsigned char data16_is_present:1; - unsigned char data17_is_present:1; - unsigned char data18_is_present:1; - unsigned char data19_is_present:1; - unsigned char data20_is_present:1; - unsigned char data21_is_present:1; - unsigned char data22_is_present:1; - unsigned char data23_is_present:1; - } __packed; - }; - unsigned char data[4]; - }; -}; - -struct synaptics_rmi4_f12_control_41 { - union { - struct { - unsigned char enable_registration:1; - unsigned char template_index:4; - unsigned char begin:1; - unsigned char f12_ctrl41_b6__7:2; - } __packed; - unsigned char data[1]; - }; -}; - -struct synaptics_rmi4_udg_handle { - atomic_t attn_event; - unsigned char intr_mask; - unsigned char report_flags; - unsigned char object_type_enable1; - unsigned char object_type_enable2; - unsigned char trace_size; - unsigned char template_index; - unsigned char max_num_templates; - unsigned char detection_score; - unsigned char detection_index; - unsigned char detection_status; - unsigned char registration_status; - unsigned char *ctrl_buf; - unsigned char *trace_data_buf; - unsigned char *template_data_buf; -#ifdef STORE_GESTURES - unsigned char gestures_to_store; - unsigned char *storage_buf; - unsigned char valid_buf[2]; -#endif - unsigned short trace_data_buf_size; - unsigned short template_size; - unsigned short template_data_size; - unsigned short query_base_addr; - unsigned short control_base_addr; - unsigned short data_base_addr; - unsigned short command_base_addr; - unsigned short ctrl_18_sub10_off; - unsigned short ctrl_20_sub1_off; - unsigned short ctrl_23_sub3_off; - unsigned short ctrl_27_sub5_off; - struct input_dev *udg_dev; - struct kobject *tuning_dir; - struct udg_addr addr; - struct udg_tuning tuning; - struct synaptics_rmi4_data *rmi4_data; -}; - -static struct device_attribute attrs[] = { - __ATTR(engine_enable, S_IWUGO, - NULL, - udg_sysfs_engine_enable_store), - __ATTR(detection_enable, S_IWUGO, - NULL, - udg_sysfs_detection_enable_store), - __ATTR(detection_score, S_IRUGO, - udg_sysfs_detection_score_show, - NULL), - __ATTR(detection_index, S_IRUGO, - udg_sysfs_detection_index_show, - NULL), - __ATTR(registration_enable, S_IWUGO, - NULL, - udg_sysfs_registration_enable_store), - __ATTR(registration_begin, S_IWUGO, - NULL, - udg_sysfs_registration_begin_store), - __ATTR(registration_status, S_IRUGO, - udg_sysfs_registration_status_show, - NULL), - __ATTR(template_size, S_IRUGO, - udg_sysfs_template_size_show, - NULL), - __ATTR(template_max_index, S_IRUGO, - udg_sysfs_template_max_index_show, - NULL), - __ATTR(template_detection, S_IRUGO, - udg_sysfs_template_detection_show, - NULL), - __ATTR(template_index, S_IWUGO, - NULL, - udg_sysfs_template_index_store), - __ATTR(template_valid, (S_IRUGO | S_IWUGO), - udg_sysfs_template_valid_show, - udg_sysfs_template_valid_store), - __ATTR(template_clear, S_IWUGO, - NULL, - udg_sysfs_template_clear_store), - __ATTR(trace_size, S_IRUGO, - udg_sysfs_trace_size_show, - NULL), -}; - -static struct bin_attribute template_data = { - .attr = { - .name = "template_data", - .mode = (S_IRUGO | S_IWUGO), - }, - .size = 0, - .read = udg_sysfs_template_data_show, - .write = udg_sysfs_template_data_store, -}; - -static struct bin_attribute trace_data = { - .attr = { - .name = "trace_data", - .mode = S_IRUGO, - }, - .size = 0, - .read = udg_sysfs_trace_data_show, - .write = NULL, -}; - -static struct device_attribute params[] = { - __ATTR(template_displacement, (S_IRUGO | S_IWUGO), - udg_sysfs_template_displacement_show, - udg_sysfs_template_displacement_store), - __ATTR(rotation_invariance, (S_IRUGO | S_IWUGO), - udg_sysfs_rotation_invariance_show, - udg_sysfs_rotation_invariance_store), - __ATTR(scale_invariance, (S_IRUGO | S_IWUGO), - udg_sysfs_scale_invariance_show, - udg_sysfs_scale_invariance_store), - __ATTR(threshold_factor, (S_IRUGO | S_IWUGO), - udg_sysfs_threshold_factor_show, - udg_sysfs_threshold_factor_store), - __ATTR(match_metric_threshold, (S_IRUGO | S_IWUGO), - udg_sysfs_match_metric_threshold_show, - udg_sysfs_match_metric_threshold_store), - __ATTR(max_inter_stroke_time, (S_IRUGO | S_IWUGO), - udg_sysfs_max_inter_stroke_time_show, - udg_sysfs_max_inter_stroke_time_store), -}; - -static struct synaptics_rmi4_udg_handle *udg; - -static unsigned char ctrl_18_sub_size[] = {10, 10, 10, 2, 3, 4, 3, 3, 1, 1}; -static unsigned char ctrl_20_sub_size[] = {2}; -static unsigned char ctrl_23_sub_size[] = {1, 1, 1}; -static unsigned char ctrl_27_sub_size[] = {1, 5, 2, 1, 7}; - -DECLARE_COMPLETION(udg_remove_complete); - -static ssize_t udg_sysfs_engine_enable_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - bool enable; - unsigned int input; - - if (sscanf(buf, "%u", &input) != 1) - return -EINVAL; - - if (input == 1) - enable = true; - else if (input == 0) - enable = false; - else - return -EINVAL; - - retval = udg_engine_enable(enable); - if (retval < 0) - return retval; - - return count; -} - -static ssize_t udg_sysfs_detection_enable_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - bool enable; - unsigned int input; - - if (sscanf(buf, "%u", &input) != 1) - return -EINVAL; - - if (input == 1) - enable = true; - else if (input == 0) - enable = false; - else - return -EINVAL; - - udg->detection_status = 0; - - retval = udg_detection_enable(enable); - if (retval < 0) - return retval; - - return count; -} - -static ssize_t udg_sysfs_detection_score_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%u\n", udg->detection_score); -} - -static ssize_t udg_sysfs_detection_index_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%u\n", udg->detection_index); -} - -static ssize_t udg_sysfs_registration_enable_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - bool enable; - unsigned int input; - struct synaptics_rmi4_f12_control_41 control_41; - struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data; - - if (sscanf(buf, "%u", &input) != 1) - return -EINVAL; - - if (input == 1) - enable = true; - else if (input == 0) - enable = false; - else - return -EINVAL; - - if (enable) { - retval = synaptics_rmi4_reg_read(rmi4_data, - udg->addr.ctrl_23, - udg->ctrl_buf, - udg->ctrl_23_sub3_off + 1); - if (retval < 0) - return retval; - - udg->ctrl_buf[0] = 0; - udg->ctrl_buf[0] |= (1 << CTRL23_FINGER_REPORT_ENABLE_BIT); - if (udg->ctrl_23_sub3_off) - udg->ctrl_buf[udg->ctrl_23_sub3_off] = 0; - - retval = synaptics_rmi4_reg_write(rmi4_data, - udg->addr.ctrl_23, - udg->ctrl_buf, - udg->ctrl_23_sub3_off + 1); - if (retval < 0) - return retval; - } else { - retval = synaptics_rmi4_reg_read(rmi4_data, - udg->addr.ctrl_23, - udg->ctrl_buf, - udg->ctrl_23_sub3_off + 1); - if (retval < 0) - return retval; - - udg->ctrl_buf[0] = udg->object_type_enable1; - if (udg->ctrl_23_sub3_off) { - udg->ctrl_buf[udg->ctrl_23_sub3_off] = - udg->object_type_enable2; - } - - retval = synaptics_rmi4_reg_write(rmi4_data, - udg->addr.ctrl_23, - udg->ctrl_buf, - udg->ctrl_23_sub3_off + 1); - if (retval < 0) - return retval; - } - - retval = synaptics_rmi4_reg_read(rmi4_data, - udg->addr.ctrl_41, - control_41.data, - sizeof(control_41.data)); - if (retval < 0) - return retval; - - control_41.enable_registration = enable ? 1 : 0; - - retval = synaptics_rmi4_reg_write(rmi4_data, - udg->addr.ctrl_41, - control_41.data, - sizeof(control_41.data)); - if (retval < 0) - return retval; - - return count; -} - -static ssize_t udg_sysfs_registration_begin_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - bool begin; - unsigned int input; - struct synaptics_rmi4_f12_control_41 control_41; - struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data; - - if (sscanf(buf, "%u", &input) != 1) - return -EINVAL; - - if (input == 1) - begin = true; - else if (input == 0) - begin = false; - else - return -EINVAL; - - retval = synaptics_rmi4_reg_read(rmi4_data, - udg->addr.ctrl_41, - control_41.data, - sizeof(control_41.data)); - if (retval < 0) - return retval; - - control_41.begin = begin ? 1 : 0; - - retval = synaptics_rmi4_reg_write(rmi4_data, - udg->addr.ctrl_41, - control_41.data, - sizeof(control_41.data)); - if (retval < 0) - return retval; - - return count; -} - -static ssize_t udg_sysfs_registration_status_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "0x%02x\n", udg->registration_status); -} - -static ssize_t udg_sysfs_template_size_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%u\n", udg->template_size); -} - -static ssize_t udg_sysfs_template_max_index_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%u\n", udg->max_num_templates - 1); -} - -static ssize_t udg_sysfs_template_detection_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int retval; - int attn_event; - unsigned char detection_status; - struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data; - - attn_event = atomic_read(&udg->attn_event); - atomic_set(&udg->attn_event, 0); - - if (attn_event == 0) - return snprintf(buf, PAGE_SIZE, "0\n"); - - if (udg->detection_status == 0) { - retval = synaptics_rmi4_reg_read(rmi4_data, - udg->addr.data_4, - rmi4_data->gesture_detection, - sizeof(rmi4_data->gesture_detection)); - if (retval < 0) - return retval; - - udg->detection_status = rmi4_data->gesture_detection[0]; - } - - detection_status = udg->detection_status; - udg->detection_status = 0; - - switch (detection_status) { - case DETECTION: - udg->detection_score = rmi4_data->gesture_detection[1]; - udg->detection_index = rmi4_data->gesture_detection[4]; - udg->trace_size = rmi4_data->gesture_detection[3]; - break; - case REGISTRATION: - udg->registration_status = rmi4_data->gesture_detection[1]; - udg->trace_size = rmi4_data->gesture_detection[3]; - break; - default: - return snprintf(buf, PAGE_SIZE, "0\n"); - } - - return snprintf(buf, PAGE_SIZE, "0x%02x\n", detection_status); -} - -static ssize_t udg_sysfs_template_index_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned long index; - - retval = sstrtoul(buf, 10, &index); - if (retval) - return retval; - - retval = udg_set_index((unsigned char)index); - if (retval < 0) - return retval; - - return count; -} - -static ssize_t udg_sysfs_template_valid_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int retval; - unsigned char valid; - unsigned char offset; - unsigned char byte_num; - unsigned char template_flags[2]; - struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data; - - byte_num = udg->template_index / 8; - offset = udg->template_index % 8; - - retval = synaptics_rmi4_reg_read(rmi4_data, - udg->addr.template_flags, - template_flags, - sizeof(template_flags)); - if (retval < 0) - return retval; - - valid = (template_flags[byte_num] & (1 << offset)) >> offset; - - return snprintf(buf, PAGE_SIZE, "%u\n", valid); -} - -static ssize_t udg_sysfs_template_valid_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned long valid; - unsigned char offset; - unsigned char byte_num; - unsigned char template_flags[2]; - struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data; - - retval = sstrtoul(buf, 10, &valid); - if (retval) - return retval; - - if (valid > 0) - valid = 1; - - byte_num = udg->template_index / 8; - offset = udg->template_index % 8; - - retval = synaptics_rmi4_reg_read(rmi4_data, - udg->addr.template_flags, - template_flags, - sizeof(template_flags)); - if (retval < 0) - return retval; - - if (valid) - template_flags[byte_num] |= (1 << offset); - else - template_flags[byte_num] &= ~(1 << offset); - - retval = synaptics_rmi4_reg_write(rmi4_data, - udg->addr.template_flags, - template_flags, - sizeof(template_flags)); - if (retval < 0) - return retval; - -#ifdef STORE_GESTURES - udg_read_valid_data(); -#endif - - return count; -} - -static ssize_t udg_sysfs_template_clear_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned int input; - const char cmd[] = {'0', 0}; - struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data; - - if (sscanf(buf, "%u", &input) != 1) - return -EINVAL; - - if (input != 1) - return -EINVAL; - - memset(udg->template_data_buf, 0x00, udg->template_data_size); - - retval = synaptics_rmi4_reg_write(rmi4_data, - udg->addr.template_data, - udg->template_data_buf, - udg->template_data_size); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to clear template data\n", - __func__); - return retval; - } - - retval = udg_sysfs_template_valid_store(dev, attr, cmd, 1); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to clear valid bit\n", - __func__); - return retval; - } - -#ifdef STORE_GESTURES - udg_read_template_data(udg->template_index); - udg_read_valid_data(); -#endif - - return count; -} - -static ssize_t udg_sysfs_trace_size_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%u\n", udg->trace_size); -} - -static ssize_t udg_sysfs_trace_data_show(struct file *data_file, - struct kobject *kobj, struct bin_attribute *attributes, - char *buf, loff_t pos, size_t count) -{ - int retval; - unsigned short index = 0; - unsigned short trace_data_size; - struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data; - - trace_data_size = udg->trace_size * 5; - - if (trace_data_size == 0) - return -EINVAL; - - if (count < trace_data_size) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Not enough space (%d bytes) in buffer\n", - __func__, (unsigned int)count); - return -EINVAL; - } - - if (udg->trace_data_buf_size < trace_data_size) { - if (udg->trace_data_buf_size) - kfree(udg->trace_data_buf); - udg->trace_data_buf = kzalloc(trace_data_size, GFP_KERNEL); - if (!udg->trace_data_buf) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for trace data buffer\n", - __func__); - udg->trace_data_buf_size = 0; - return -ENOMEM; - } - udg->trace_data_buf_size = trace_data_size; - } - - retval = synaptics_rmi4_reg_read(rmi4_data, - udg->addr.trace_x, - &udg->trace_data_buf[index], - udg->trace_size * 2); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read trace X data\n", - __func__); - return retval; - } else { - index += udg->trace_size * 2; - } - - retval = synaptics_rmi4_reg_read(rmi4_data, - udg->addr.trace_y, - &udg->trace_data_buf[index], - udg->trace_size * 2); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read trace Y data\n", - __func__); - return retval; - } else { - index += udg->trace_size * 2; - } - - retval = synaptics_rmi4_reg_read(rmi4_data, - udg->addr.trace_segment, - &udg->trace_data_buf[index], - udg->trace_size); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read trace segment data\n", - __func__); - return retval; - } - - retval = secure_memcpy(buf, count, udg->trace_data_buf, - udg->trace_data_buf_size, trace_data_size); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to copy trace data\n", - __func__); - return retval; - } - - return trace_data_size; -} - -static ssize_t udg_sysfs_template_data_show(struct file *data_file, - struct kobject *kobj, struct bin_attribute *attributes, - char *buf, loff_t pos, size_t count) -{ - int retval; - struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data; - - if (count < udg->template_data_size) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Not enough space (%d bytes) in buffer\n", - __func__, (unsigned int)count); - return -EINVAL; - } - - retval = synaptics_rmi4_reg_read(rmi4_data, - udg->addr.template_data, - udg->template_data_buf, - udg->template_data_size); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read template data\n", - __func__); - return retval; - } - - retval = secure_memcpy(buf, count, udg->template_data_buf, - udg->template_data_size, udg->template_data_size); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to copy template data\n", - __func__); - return retval; - } - -#ifdef STORE_GESTURES - udg_read_template_data(udg->template_index); - udg_read_valid_data(); -#endif - - return udg->template_data_size; -} - -static ssize_t udg_sysfs_template_data_store(struct file *data_file, - struct kobject *kobj, struct bin_attribute *attributes, - char *buf, loff_t pos, size_t count) -{ - int retval; - struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data; - - retval = secure_memcpy(udg->template_data_buf, udg->template_data_size, - buf, count, count); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to copy template data\n", - __func__); - return retval; - } - - retval = synaptics_rmi4_reg_write(rmi4_data, - udg->addr.template_data, - udg->template_data_buf, - count); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write template data\n", - __func__); - return retval; - } - -#ifdef STORE_GESTURES - udg_read_template_data(udg->template_index); - udg_read_valid_data(); -#endif - - return count; -} - -static ssize_t udg_sysfs_template_displacement_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int retval; - unsigned short template_displacement; - - retval = udg_read_tuning_params(); - if (retval < 0) - return retval; - - template_displacement = - ((unsigned short)udg->tuning.template_disp_lsb << 0) | - ((unsigned short)udg->tuning.template_disp_msb << 8); - - return snprintf(buf, PAGE_SIZE, "%u\n", template_displacement); -} - -static ssize_t udg_sysfs_template_displacement_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned long input; - - retval = sstrtoul(buf, 10, &input); - if (retval) - return retval; - - retval = udg_read_tuning_params(); - if (retval < 0) - return retval; - - udg->tuning.template_disp_lsb = (unsigned char)(input >> 0); - udg->tuning.template_disp_msb = (unsigned char)(input >> 8); - - retval = udg_write_tuning_params(); - if (retval < 0) - return retval; - - return count; -} - -static ssize_t udg_sysfs_rotation_invariance_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int retval; - unsigned short rotation_invariance; - - retval = udg_read_tuning_params(); - if (retval < 0) - return retval; - - rotation_invariance = - ((unsigned short)udg->tuning.rotation_inv_lsb << 0) | - ((unsigned short)udg->tuning.rotation_inv_msb << 8); - - return snprintf(buf, PAGE_SIZE, "%u\n", rotation_invariance); -} - -static ssize_t udg_sysfs_rotation_invariance_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned long input; - - retval = sstrtoul(buf, 10, &input); - if (retval) - return retval; - - retval = udg_read_tuning_params(); - if (retval < 0) - return retval; - - udg->tuning.rotation_inv_lsb = (unsigned char)(input >> 0); - udg->tuning.rotation_inv_msb = (unsigned char)(input >> 8); - - retval = udg_write_tuning_params(); - if (retval < 0) - return retval; - - return count; -} - -static ssize_t udg_sysfs_scale_invariance_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int retval; - unsigned short scale_invariance; - - retval = udg_read_tuning_params(); - if (retval < 0) - return retval; - - scale_invariance = - ((unsigned short)udg->tuning.scale_inv_lsb << 0) | - ((unsigned short)udg->tuning.scale_inv_msb << 8); - - return snprintf(buf, PAGE_SIZE, "%u\n", scale_invariance); -} - -static ssize_t udg_sysfs_scale_invariance_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned long input; - - retval = sstrtoul(buf, 10, &input); - if (retval) - return retval; - - retval = udg_read_tuning_params(); - if (retval < 0) - return retval; - - udg->tuning.scale_inv_lsb = (unsigned char)(input >> 0); - udg->tuning.scale_inv_msb = (unsigned char)(input >> 8); - - retval = udg_write_tuning_params(); - if (retval < 0) - return retval; - - return count; -} - -static ssize_t udg_sysfs_threshold_factor_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int retval; - unsigned short threshold_factor; - - retval = udg_read_tuning_params(); - if (retval < 0) - return retval; - - threshold_factor = - ((unsigned short)udg->tuning.thres_factor_lsb << 0) | - ((unsigned short)udg->tuning.thres_factor_msb << 8); - - return snprintf(buf, PAGE_SIZE, "%u\n", threshold_factor); -} - -static ssize_t udg_sysfs_threshold_factor_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned long input; - - retval = sstrtoul(buf, 10, &input); - if (retval) - return retval; - - retval = udg_read_tuning_params(); - if (retval < 0) - return retval; - - udg->tuning.thres_factor_lsb = (unsigned char)(input >> 0); - udg->tuning.thres_factor_msb = (unsigned char)(input >> 8); - - retval = udg_write_tuning_params(); - if (retval < 0) - return retval; - - return count; -} - -static ssize_t udg_sysfs_match_metric_threshold_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int retval; - unsigned short match_metric_threshold; - - retval = udg_read_tuning_params(); - if (retval < 0) - return retval; - - match_metric_threshold = - ((unsigned short)udg->tuning.metric_thres_lsb << 0) | - ((unsigned short)udg->tuning.metric_thres_msb << 8); - - return snprintf(buf, PAGE_SIZE, "%u\n", match_metric_threshold); -} - -static ssize_t udg_sysfs_match_metric_threshold_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned long input; - - retval = sstrtoul(buf, 10, &input); - if (retval) - return retval; - - retval = udg_read_tuning_params(); - if (retval < 0) - return retval; - - udg->tuning.metric_thres_lsb = (unsigned char)(input >> 0); - udg->tuning.metric_thres_msb = (unsigned char)(input >> 8); - - retval = udg_write_tuning_params(); - if (retval < 0) - return retval; - - return count; -} - -static ssize_t udg_sysfs_max_inter_stroke_time_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int retval; - unsigned short max_inter_stroke_time; - - retval = udg_read_tuning_params(); - if (retval < 0) - return retval; - - max_inter_stroke_time = - ((unsigned short)udg->tuning.inter_stroke_lsb << 0) | - ((unsigned short)udg->tuning.inter_stroke_msb << 8); - - return snprintf(buf, PAGE_SIZE, "%u\n", max_inter_stroke_time); -} - -static ssize_t udg_sysfs_max_inter_stroke_time_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned long input; - - retval = sstrtoul(buf, 10, &input); - if (retval) - return retval; - - retval = udg_read_tuning_params(); - if (retval < 0) - return retval; - - udg->tuning.inter_stroke_lsb = (unsigned char)(input >> 0); - udg->tuning.inter_stroke_msb = (unsigned char)(input >> 8); - - retval = udg_write_tuning_params(); - if (retval < 0) - return retval; - - return count; -} - -static int udg_ctrl_subpacket(unsigned char ctrlreg, - unsigned char subpacket, - struct synaptics_rmi4_f12_query_5 *query_5) -{ - int retval; - unsigned char cnt; - unsigned char regnum; - unsigned char bitnum; - unsigned char q5_index; - unsigned char q6_index; - unsigned char offset; - unsigned char max_ctrlreg; - unsigned char *query_6; - struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data; - - max_ctrlreg = (sizeof(query_5->data) - 1) * 8 - 1; - - if (ctrlreg > max_ctrlreg) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Control register number (%d) over limit\n", - __func__, ctrlreg); - return -EINVAL; - } - - q5_index = ctrlreg / 8 + 1; - bitnum = ctrlreg % 8; - if ((query_5->data[q5_index] & (1 << bitnum)) == 0x00) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Control %d is not present\n", - __func__, ctrlreg); - return -EINVAL; - } - - query_6 = kmalloc(query_5->size_of_query6, GFP_KERNEL); - if (!query_6) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for query 6\n", - __func__); - return -ENOMEM; - } - - retval = synaptics_rmi4_reg_read(rmi4_data, - udg->query_base_addr + 6, - query_6, - query_5->size_of_query6); - if (retval < 0) - goto exit; - - q6_index = 0; - - for (regnum = 0; regnum < ctrlreg; regnum++) { - q5_index = regnum / 8 + 1; - bitnum = regnum % 8; - if ((query_5->data[q5_index] & (1 << bitnum)) == 0x00) - continue; - - if (query_6[q6_index] == 0x00) - q6_index += 3; - else - q6_index++; - - while (query_6[q6_index] & ~MASK_7BIT) - q6_index++; - - q6_index++; - } - - cnt = 0; - q6_index++; - offset = subpacket / 7; - bitnum = subpacket % 7; - - do { - if (cnt == offset) { - if (query_6[q6_index + cnt] & (1 << bitnum)) - retval = 1; - else - retval = 0; - goto exit; - } - cnt++; - } while (query_6[q6_index + cnt - 1] & ~MASK_7BIT); - - retval = 0; - -exit: - kfree(query_6); - - return retval; -} - -static int udg_read_tuning_params(void) -{ - int retval; - struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data; - - retval = synaptics_rmi4_reg_read(rmi4_data, - udg->addr.ctrl_18, - udg->ctrl_buf, - udg->ctrl_18_sub10_off + sizeof(struct udg_tuning)); - if (retval < 0) - return retval; - - secure_memcpy(udg->tuning.data, - sizeof(udg->tuning.data), - (unsigned char *)&udg->ctrl_buf[udg->ctrl_18_sub10_off], - sizeof(struct udg_tuning), - sizeof(struct udg_tuning)); - - return 0; -} - -static int udg_write_tuning_params(void) -{ - int retval; - struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data; - - secure_memcpy((unsigned char *)&udg->ctrl_buf[udg->ctrl_18_sub10_off], - sizeof(struct udg_tuning), - udg->tuning.data, - sizeof(udg->tuning.data), - sizeof(struct udg_tuning)); - - retval = synaptics_rmi4_reg_write(rmi4_data, - udg->addr.ctrl_18, - udg->ctrl_buf, - udg->ctrl_18_sub10_off + sizeof(struct udg_tuning)); - if (retval < 0) - return retval; - - return 0; -} - -static int udg_detection_enable(bool enable) -{ - int retval; - struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data; - - retval = synaptics_rmi4_reg_read(rmi4_data, - udg->addr.ctrl_20, - udg->ctrl_buf, - udg->ctrl_20_sub1_off + 1); - if (retval < 0) - return retval; - - if (enable) - udg->ctrl_buf[udg->ctrl_20_sub1_off] = WAKEUP_GESTURE_MODE; - else - udg->ctrl_buf[udg->ctrl_20_sub1_off] = udg->report_flags; - - retval = synaptics_rmi4_reg_write(rmi4_data, - udg->addr.ctrl_20, - udg->ctrl_buf, - udg->ctrl_20_sub1_off + 1); - if (retval < 0) - return retval; - - return 0; -} - -static int udg_engine_enable(bool enable) -{ - int retval; - struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data; - - if (enable) { - retval = synaptics_rmi4_reg_read(rmi4_data, - udg->addr.ctrl_27, - udg->ctrl_buf, - udg->ctrl_27_sub5_off + 1); - if (retval < 0) - return retval; - - udg->ctrl_buf[udg->ctrl_27_sub5_off] |= - (1 << CTRL27_UDG_ENABLE_BIT); - - retval = synaptics_rmi4_reg_write(rmi4_data, - udg->addr.ctrl_27, - udg->ctrl_buf, - udg->ctrl_27_sub5_off + 1); - if (retval < 0) - return retval; - } else { - retval = synaptics_rmi4_reg_read(rmi4_data, - udg->addr.ctrl_27, - udg->ctrl_buf, - udg->ctrl_27_sub5_off + 1); - if (retval < 0) - return retval; - - udg->ctrl_buf[udg->ctrl_27_sub5_off] &= - ~(1 << CTRL27_UDG_ENABLE_BIT); - - retval = synaptics_rmi4_reg_write(rmi4_data, - udg->addr.ctrl_27, - udg->ctrl_buf, - udg->ctrl_27_sub5_off + 1); - if (retval < 0) - return retval; - } - - return 0; -} - -static void udg_report(void) -{ - int retval; - struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data; - - atomic_set(&udg->attn_event, 1); - - if (rmi4_data->suspend) { - if (rmi4_data->gesture_detection[0] == 0) { - retval = synaptics_rmi4_reg_read(rmi4_data, - udg->addr.data_4, - rmi4_data->gesture_detection, - sizeof(rmi4_data->gesture_detection)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read gesture detection\n", - __func__); - return; - } - } - - udg->detection_status = rmi4_data->gesture_detection[0]; - rmi4_data->gesture_detection[0] = 0; - - if (udg->detection_status == DETECTION) { - input_report_key(udg->udg_dev, KEY_WAKEUP, 1); - input_sync(udg->udg_dev); - input_report_key(udg->udg_dev, KEY_WAKEUP, 0); - input_sync(udg->udg_dev); - rmi4_data->suspend = false; - } - } - - return; -} - -static int udg_set_index(unsigned char index) -{ - int retval; - struct synaptics_rmi4_f12_control_41 control_41; - struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data; - - if (index >= udg->max_num_templates) - return -EINVAL; - - udg->template_index = index; - - retval = synaptics_rmi4_reg_read(rmi4_data, - udg->addr.ctrl_41, - control_41.data, - sizeof(control_41.data)); - if (retval < 0) - return retval; - - control_41.template_index = udg->template_index; - - retval = synaptics_rmi4_reg_write(rmi4_data, - udg->addr.ctrl_41, - control_41.data, - sizeof(control_41.data)); - if (retval < 0) - return retval; - - return 0; -} - -#ifdef STORE_GESTURES -static int udg_read_valid_data(void) -{ - int retval; - struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data; - - retval = synaptics_rmi4_reg_read(rmi4_data, - udg->addr.template_flags, - udg->valid_buf, - sizeof(udg->valid_buf)); - if (retval < 0) - return retval; - - return 0; -} - -static int udg_write_valid_data(void) -{ - int retval; - struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data; - - retval = synaptics_rmi4_reg_write(rmi4_data, - udg->addr.template_flags, - udg->valid_buf, - sizeof(udg->valid_buf)); - if (retval < 0) - return retval; - - return 0; -} - -static int udg_read_template_data(unsigned char index) -{ - int retval; - unsigned char *storage; - struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data; - - udg_set_index(index); - storage = &(udg->storage_buf[index * udg->template_data_size]); - - retval = synaptics_rmi4_reg_read(rmi4_data, - udg->addr.template_data, - storage, - udg->template_data_size); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read template data\n", - __func__); - return retval; - } - - return 0; -} - -static int udg_write_template_data(void) -{ - int retval; - unsigned char ii; - unsigned char *storage; - struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data; - - for (ii = 0; ii < udg->gestures_to_store; ii++) { - udg_set_index(ii); - storage = &(udg->storage_buf[ii * udg->template_data_size]); - - retval = synaptics_rmi4_reg_write(rmi4_data, - udg->addr.template_data, - storage, - udg->template_data_size); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write template data\n", - __func__); - return retval; - } - } - - return 0; -} -#endif - -static int udg_reg_init(void) -{ - int retval; - unsigned char ii; - unsigned char data_offset; - unsigned char size_of_query; - unsigned char ctrl_18_offset; - unsigned char ctrl_20_offset; - unsigned char ctrl_23_offset; - unsigned char ctrl_27_offset; - unsigned char ctrl_41_offset; - struct synaptics_rmi4_f12_query_0 query_0; - struct synaptics_rmi4_f12_query_5 query_5; - struct synaptics_rmi4_f12_query_8 query_8; - struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data; - - retval = synaptics_rmi4_reg_read(rmi4_data, - udg->query_base_addr + 7, - &size_of_query, - sizeof(size_of_query)); - if (retval < 0) - return retval; - - if (size_of_query < 4) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: User defined gesture support unavailable (missing data registers)\n", - __func__); - retval = -ENODEV; - return retval; - } - - retval = synaptics_rmi4_reg_read(rmi4_data, - udg->query_base_addr + 8, - query_8.data, - sizeof(query_8.data)); - if (retval < 0) - return retval; - - if ((query_8.data16_is_present) && - (query_8.data17_is_present) && - (query_8.data18_is_present) && - (query_8.data19_is_present) && - (query_8.data20_is_present) && - (query_8.data21_is_present)) { - data_offset = query_8.data0_is_present + - query_8.data1_is_present + - query_8.data2_is_present + - query_8.data3_is_present; - udg->addr.data_4 = udg->data_base_addr + data_offset; - data_offset = data_offset + - query_8.data4_is_present + - query_8.data5_is_present + - query_8.data6_is_present + - query_8.data7_is_present + - query_8.data8_is_present + - query_8.data9_is_present + - query_8.data10_is_present + - query_8.data11_is_present + - query_8.data12_is_present + - query_8.data13_is_present + - query_8.data14_is_present + - query_8.data15_is_present; - udg->addr.trace_x = udg->data_base_addr + data_offset; - udg->addr.trace_y = udg->addr.trace_x + 1; - udg->addr.trace_segment = udg->addr.trace_y + 1; - udg->addr.template_helper = udg->addr.trace_segment + 1; - udg->addr.template_data = udg->addr.template_helper + 1; - udg->addr.template_flags = udg->addr.template_data + 1; - } else { - dev_err(rmi4_data->pdev->dev.parent, - "%s: User defined gesture support unavailable (missing data registers)\n", - __func__); - retval = -ENODEV; - return retval; - } - - retval = synaptics_rmi4_reg_read(rmi4_data, - udg->query_base_addr + 4, - &size_of_query, - sizeof(size_of_query)); - if (retval < 0) - return retval; - - if (size_of_query < 7) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: User defined gesture support unavailable (missing control registers)\n", - __func__); - retval = -ENODEV; - return retval; - } - - retval = synaptics_rmi4_reg_read(rmi4_data, - udg->query_base_addr + 5, - query_5.data, - sizeof(query_5.data)); - if (retval < 0) - return retval; - - ctrl_18_offset = query_5.ctrl0_is_present + - query_5.ctrl1_is_present + - query_5.ctrl2_is_present + - query_5.ctrl3_is_present + - query_5.ctrl4_is_present + - query_5.ctrl5_is_present + - query_5.ctrl6_is_present + - query_5.ctrl7_is_present + - query_5.ctrl8_is_present + - query_5.ctrl9_is_present + - query_5.ctrl10_is_present + - query_5.ctrl11_is_present + - query_5.ctrl12_is_present + - query_5.ctrl13_is_present + - query_5.ctrl14_is_present + - query_5.ctrl15_is_present + - query_5.ctrl16_is_present + - query_5.ctrl17_is_present; - - ctrl_20_offset = ctrl_18_offset + - query_5.ctrl18_is_present + - query_5.ctrl19_is_present; - - ctrl_23_offset = ctrl_20_offset + - query_5.ctrl20_is_present + - query_5.ctrl21_is_present + - query_5.ctrl22_is_present; - - ctrl_27_offset = ctrl_23_offset+ - query_5.ctrl23_is_present + - query_5.ctrl24_is_present + - query_5.ctrl25_is_present + - query_5.ctrl26_is_present; - - ctrl_41_offset = ctrl_27_offset+ - query_5.ctrl27_is_present + - query_5.ctrl28_is_present + - query_5.ctrl29_is_present + - query_5.ctrl30_is_present + - query_5.ctrl31_is_present + - query_5.ctrl32_is_present + - query_5.ctrl33_is_present + - query_5.ctrl34_is_present + - query_5.ctrl35_is_present + - query_5.ctrl36_is_present + - query_5.ctrl37_is_present + - query_5.ctrl38_is_present + - query_5.ctrl39_is_present + - query_5.ctrl40_is_present; - - udg->addr.ctrl_18 = udg->control_base_addr + ctrl_18_offset; - udg->addr.ctrl_20 = udg->control_base_addr + ctrl_20_offset; - udg->addr.ctrl_23 = udg->control_base_addr + ctrl_23_offset; - udg->addr.ctrl_27 = udg->control_base_addr + ctrl_27_offset; - udg->addr.ctrl_41 = udg->control_base_addr + ctrl_41_offset; - - udg->ctrl_18_sub10_off = 0; - for (ii = 0; ii < 10; ii++) { - retval = udg_ctrl_subpacket(18, ii, &query_5); - if (retval == 1) - udg->ctrl_18_sub10_off += ctrl_18_sub_size[ii]; - else if (retval < 0) - return retval; - } - - udg->ctrl_20_sub1_off = 0; - for (ii = 0; ii < 1; ii++) { - retval = udg_ctrl_subpacket(20, ii, &query_5); - if (retval == 1) - udg->ctrl_20_sub1_off += ctrl_20_sub_size[ii]; - else if (retval < 0) - return retval; - } - - udg->ctrl_23_sub3_off = 0; - for (ii = 0; ii < 3; ii++) { - retval = udg_ctrl_subpacket(23, ii, &query_5); - if (retval == 1) - udg->ctrl_23_sub3_off += ctrl_23_sub_size[ii]; - else if (retval < 0) - return retval; - } - - retval = udg_ctrl_subpacket(23, 3, &query_5); - if (retval == 0) - udg->ctrl_23_sub3_off = 0; - else if (retval < 0) - return retval; - - udg->ctrl_27_sub5_off = 0; - for (ii = 0; ii < 5; ii++) { - retval = udg_ctrl_subpacket(27, ii, &query_5); - if (retval == 1) - udg->ctrl_27_sub5_off += ctrl_27_sub_size[ii]; - else if (retval < 0) - return retval; - } - - retval = synaptics_rmi4_reg_read(rmi4_data, - udg->query_base_addr + 0, - query_0.data, - sizeof(query_0.data)); - if (retval < 0) - return retval; - - udg->max_num_templates = query_0.max_num_templates; - udg->template_size = - ((unsigned short)query_0.template_size_lsb << 0) | - ((unsigned short)query_0.template_size_msb << 8); - udg->template_data_size = udg->template_size * 4 * 2 + 4 + 1; - -#ifdef STORE_GESTURES - udg->gestures_to_store = udg->max_num_templates; - if (GESTURES_TO_STORE < udg->gestures_to_store) - udg->gestures_to_store = GESTURES_TO_STORE; -#endif - - retval = synaptics_rmi4_reg_read(rmi4_data, - udg->addr.ctrl_20, - udg->ctrl_buf, - udg->ctrl_20_sub1_off + 1); - if (retval < 0) - return retval; - - udg->report_flags = udg->ctrl_buf[udg->ctrl_20_sub1_off]; - - retval = synaptics_rmi4_reg_read(rmi4_data, - udg->addr.ctrl_23, - udg->ctrl_buf, - udg->ctrl_23_sub3_off + 1); - if (retval < 0) - return retval; - - udg->object_type_enable1 = udg->ctrl_buf[0]; - if (udg->ctrl_23_sub3_off) - udg->object_type_enable2 = udg->ctrl_buf[udg->ctrl_23_sub3_off]; - - return retval; -} - -static int udg_scan_pdt(void) -{ - int retval; - unsigned char ii; - unsigned char page; - unsigned char intr_count = 0; - unsigned char intr_off; - unsigned char intr_src; - unsigned short addr; - struct synaptics_rmi4_fn_desc fd; - struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data; - - for (page = 0; page < PAGES_TO_SERVICE; page++) { - for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) { - addr |= (page << 8); - - retval = synaptics_rmi4_reg_read(rmi4_data, - addr, - (unsigned char *)&fd, - sizeof(fd)); - if (retval < 0) - return retval; - - addr &= ~(MASK_8BIT << 8); - - if (fd.fn_number) { - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Found F%02x\n", - __func__, fd.fn_number); - switch (fd.fn_number) { - case SYNAPTICS_RMI4_F12: - goto f12_found; - break; - } - } else { - break; - } - - intr_count += fd.intr_src_count; - } - } - - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to find F12\n", - __func__); - return -EINVAL; - -f12_found: - udg->query_base_addr = fd.query_base_addr | (page << 8); - udg->control_base_addr = fd.ctrl_base_addr | (page << 8); - udg->data_base_addr = fd.data_base_addr | (page << 8); - udg->command_base_addr = fd.cmd_base_addr | (page << 8); - - retval = udg_reg_init(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to initialize user defined gesture registers\n", - __func__); - return retval; - } - - udg->intr_mask = 0; - intr_src = fd.intr_src_count; - intr_off = intr_count % 8; - for (ii = intr_off; - ii < (intr_src + intr_off); - ii++) { - udg->intr_mask |= 1 << ii; - } - - rmi4_data->intr_mask[0] |= udg->intr_mask; - - addr = rmi4_data->f01_ctrl_base_addr + 1; - - retval = synaptics_rmi4_reg_write(rmi4_data, - addr, - &rmi4_data->intr_mask[0], - sizeof(rmi4_data->intr_mask[0])); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to set interrupt enable bit\n", - __func__); - return retval; - } - - return 0; -} - -static void synaptics_rmi4_udg_attn(struct synaptics_rmi4_data *rmi4_data, - unsigned char intr_mask) -{ - if (!udg) - return; - - if (udg->intr_mask & intr_mask) - udg_report(); - - return; -} - -static int synaptics_rmi4_udg_init(struct synaptics_rmi4_data *rmi4_data) -{ - int retval; - unsigned char ii; - unsigned char size; - unsigned char attr_count; - unsigned char param_count; - - if (udg) { - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Handle already exists\n", - __func__); - return 0; - } - - udg = kzalloc(sizeof(*udg), GFP_KERNEL); - if (!udg) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for udg\n", - __func__); - retval = -ENOMEM; - goto exit; - } - - size = 0; - for (ii = 0; ii < sizeof(ctrl_18_sub_size); ii++) - size += ctrl_18_sub_size[ii]; - size += sizeof(struct udg_tuning); - udg->ctrl_buf = kzalloc(size, GFP_KERNEL); - if (!udg->ctrl_buf) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for ctrl_buf\n", - __func__); - retval = -ENOMEM; - goto exit_free_udg; - } - - udg->rmi4_data = rmi4_data; - - retval = udg_scan_pdt(); - if (retval < 0) - goto exit_free_ctrl_buf; - - udg->template_data_buf = kzalloc(udg->template_data_size, GFP_KERNEL); - if (!udg->template_data_buf) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for template_data_buf\n", - __func__); - retval = -ENOMEM; - goto exit_free_ctrl_buf; - } - -#ifdef STORE_GESTURES - udg->storage_buf = kzalloc( - udg->template_data_size * udg->gestures_to_store, - GFP_KERNEL); - if (!udg->storage_buf) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for storage_buf\n", - __func__); - kfree(udg->template_data_buf); - retval = -ENOMEM; - goto exit_free_ctrl_buf; - } -#endif - - udg->udg_dev = input_allocate_device(); - if (udg->udg_dev == NULL) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to allocate gesture device\n", - __func__); - retval = -ENOMEM; - goto exit_free_template_data_buf; - } - - udg->udg_dev->name = GESTURE_DRIVER_NAME; - udg->udg_dev->phys = GESTURE_PHYS_NAME; - udg->udg_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT; - udg->udg_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION; - udg->udg_dev->dev.parent = rmi4_data->pdev->dev.parent; - input_set_drvdata(udg->udg_dev, rmi4_data); - - set_bit(EV_KEY, udg->udg_dev->evbit); - set_bit(KEY_WAKEUP, udg->udg_dev->keybit); - input_set_capability(udg->udg_dev, EV_KEY, KEY_WAKEUP); - - retval = input_register_device(udg->udg_dev); - if (retval) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to register gesture device\n", - __func__); - input_free_device(udg->udg_dev); - goto exit_free_template_data_buf; - } - - udg->tuning_dir = kobject_create_and_add(TUNING_SYSFS_DIR_NAME, - &udg->udg_dev->dev.kobj); - if (!udg->tuning_dir) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create tuning sysfs directory\n", - __func__); - goto exit_unregister_input_device; - } - - retval = sysfs_create_bin_file(&udg->udg_dev->dev.kobj, &template_data); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create template data bin file\n", - __func__); - goto exit_remove_sysfs_directory; - } - - retval = sysfs_create_bin_file(&udg->udg_dev->dev.kobj, &trace_data); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create trace data bin file\n", - __func__); - goto exit_remove_bin_file; - } - - for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { - retval = sysfs_create_file(&udg->udg_dev->dev.kobj, - &attrs[attr_count].attr); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create sysfs attributes\n", - __func__); - retval = -ENODEV; - goto exit_remove_attrs; - } - } - - for (param_count = 0; param_count < ARRAY_SIZE(params); param_count++) { - retval = sysfs_create_file(udg->tuning_dir, - ¶ms[param_count].attr); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create tuning parameters\n", - __func__); - retval = -ENODEV; - goto exit_remove_params; - } - } - - retval = udg_engine_enable(true); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to enable gesture engine\n", - __func__); - goto exit_remove_params; - } - - return 0; - -exit_remove_params: - for (param_count--; param_count >= 0; param_count--) { - sysfs_remove_file(udg->tuning_dir, - ¶ms[param_count].attr); - } - -exit_remove_attrs: - for (attr_count--; attr_count >= 0; attr_count--) { - sysfs_remove_file(&udg->udg_dev->dev.kobj, - &attrs[attr_count].attr); - } - - sysfs_remove_bin_file(&udg->udg_dev->dev.kobj, &trace_data); - -exit_remove_bin_file: - sysfs_remove_bin_file(&udg->udg_dev->dev.kobj, &template_data); - -exit_remove_sysfs_directory: - kobject_put(udg->tuning_dir); - -exit_unregister_input_device: - input_unregister_device(udg->udg_dev); - -exit_free_template_data_buf: -#ifdef STORE_GESTURES - kfree(udg->storage_buf); -#endif - kfree(udg->template_data_buf); - -exit_free_ctrl_buf: - kfree(udg->ctrl_buf); - -exit_free_udg: - kfree(udg); - udg = NULL; - -exit: - return retval; -} - -static void synaptics_rmi4_udg_remove(struct synaptics_rmi4_data *rmi4_data) -{ - unsigned char count; - - if (!udg) - goto exit; - - for (count = 0; count < ARRAY_SIZE(params); count++) { - sysfs_remove_file(udg->tuning_dir, - ¶ms[count].attr); - } - - for (count = 0; count < ARRAY_SIZE(attrs); count++) { - sysfs_remove_file(&udg->udg_dev->dev.kobj, - &attrs[count].attr); - } - - sysfs_remove_bin_file(&udg->udg_dev->dev.kobj, &trace_data); - sysfs_remove_bin_file(&udg->udg_dev->dev.kobj, &template_data); - kobject_put(udg->tuning_dir); - - input_unregister_device(udg->udg_dev); -#ifdef STORE_GESTURES - kfree(udg->storage_buf); -#endif - kfree(udg->template_data_buf); - kfree(udg->trace_data_buf); - kfree(udg->ctrl_buf); - kfree(udg); - udg = NULL; - -exit: - complete(&udg_remove_complete); - - return; -} - -static void synaptics_rmi4_udg_reset(struct synaptics_rmi4_data *rmi4_data) -{ - if (!udg) { - synaptics_rmi4_udg_init(rmi4_data); - return; - } - - udg_scan_pdt(); - udg_engine_enable(true); -#ifdef STORE_GESTURES - udg_write_template_data(); - udg_write_valid_data(); -#endif - - return; -} - -static void synaptics_rmi4_udg_reinit(struct synaptics_rmi4_data *rmi4_data) -{ - if (!udg) - return; - - udg_engine_enable(true); -#ifdef STORE_GESTURES - udg_write_template_data(); - udg_write_valid_data(); -#endif - - return; -} - -static void synaptics_rmi4_udg_e_suspend(struct synaptics_rmi4_data *rmi4_data) -{ - if (!udg) - return; - - rmi4_data->sleep_enable(rmi4_data, false); - rmi4_data->irq_enable(rmi4_data, true, false); - enable_irq_wake(rmi4_data->irq); - - udg_engine_enable(true); - udg_detection_enable(true); - - return; -} - -static void synaptics_rmi4_udg_suspend(struct synaptics_rmi4_data *rmi4_data) -{ - if (!udg) - return; - - rmi4_data->sleep_enable(rmi4_data, false); - rmi4_data->irq_enable(rmi4_data, true, false); - enable_irq_wake(rmi4_data->irq); - - udg_engine_enable(true); - udg_detection_enable(true); - - return; -} - -static void synaptics_rmi4_udg_resume(struct synaptics_rmi4_data *rmi4_data) -{ - if (!udg) - return; - - disable_irq_wake(rmi4_data->irq); - udg_detection_enable(false); - - return; -} - -static void synaptics_rmi4_udg_l_resume(struct synaptics_rmi4_data *rmi4_data) -{ - if (!udg) - return; - - disable_irq_wake(rmi4_data->irq); - udg_detection_enable(false); - - return; -} - -static struct synaptics_rmi4_exp_fn gesture_module = { - .fn_type = RMI_GESTURE, - .init = synaptics_rmi4_udg_init, - .remove = synaptics_rmi4_udg_remove, - .reset = synaptics_rmi4_udg_reset, - .reinit = synaptics_rmi4_udg_reinit, - .early_suspend = synaptics_rmi4_udg_e_suspend, - .suspend = synaptics_rmi4_udg_suspend, - .resume = synaptics_rmi4_udg_resume, - .late_resume = synaptics_rmi4_udg_l_resume, - .attn = synaptics_rmi4_udg_attn, -}; - -static int __init rmi4_gesture_module_init(void) -{ - synaptics_rmi4_new_function(&gesture_module, true); - - return 0; -} - -static void __exit rmi4_gesture_module_exit(void) -{ - synaptics_rmi4_new_function(&gesture_module, false); - - wait_for_completion(&udg_remove_complete); - - return; -} - -module_init(rmi4_gesture_module_init); -module_exit(rmi4_gesture_module_exit); - -MODULE_AUTHOR("Synaptics, Inc."); -MODULE_DESCRIPTION("Synaptics DSX User Defined Gesture Module"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c deleted file mode 100644 index 563ce16885b3..000000000000 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c +++ /dev/null @@ -1,712 +0,0 @@ -/* - * Synaptics DSX touchscreen driver - * - * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved. - * - * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com> - * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com> - * 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 as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - * - * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS - * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, - * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS. - * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION - * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED - * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES - * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' - * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. - * DOLLARS. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/i2c.h> -#include <linux/delay.h> -#include <linux/input.h> -#include <linux/types.h> -#include <linux/of_gpio.h> -#include <linux/platform_device.h> -#include <linux/input/synaptics_dsx_v2_6.h> -#include "synaptics_dsx_core.h" - -#define SYN_I2C_RETRY_TIMES 10 - -/* -#define I2C_BURST_LIMIT 255 -*/ -/* -#define XFER_MSGS_LIMIT 8 -*/ - -static unsigned char *wr_buf; - -static struct synaptics_dsx_hw_interface hw_if; - -static struct platform_device *synaptics_dsx_i2c_device; - -#ifdef CONFIG_OF -static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata) -{ - int retval; - u32 value; - const char *name; - struct property *prop; - struct device_node *np = dev->of_node; - - bdata->irq_gpio = of_get_named_gpio_flags(np, - "synaptics,irq-gpio", 0, - (enum of_gpio_flags *)&bdata->irq_flags); - - retval = of_property_read_u32(np, "synaptics,irq-on-state", - &value); - if (retval < 0) - bdata->irq_on_state = 0; - else - bdata->irq_on_state = value; - - bdata->resume_in_workqueue = of_property_read_bool(np, - "synaptics,resume-in-workqueue"); - - retval = of_property_read_string(np, "synaptics,pwr-reg-name", &name); - if (retval < 0) - bdata->pwr_reg_name = NULL; - else - bdata->pwr_reg_name = name; - - retval = of_property_read_string(np, "synaptics,bus-reg-name", &name); - if (retval < 0) - bdata->bus_reg_name = NULL; - else - bdata->bus_reg_name = name; - - prop = of_find_property(np, "synaptics,power-gpio", NULL); - if (prop && prop->length) { - bdata->power_gpio = of_get_named_gpio_flags(np, - "synaptics,power-gpio", 0, NULL); - retval = of_property_read_u32(np, "synaptics,power-on-state", - &value); - if (retval < 0) { - dev_err(dev, "%s: Unable to read synaptics,power-on-state property\n", - __func__); - return retval; - } else { - bdata->power_on_state = value; - } - } else { - bdata->power_gpio = -1; - } - - prop = of_find_property(np, "synaptics,power-delay-ms", NULL); - if (prop && prop->length) { - retval = of_property_read_u32(np, "synaptics,power-delay-ms", - &value); - if (retval < 0) { - dev_err(dev, "%s: Unable to read synaptics,power-delay-ms property\n", - __func__); - return retval; - } else { - bdata->power_delay_ms = value; - } - } else { - bdata->power_delay_ms = 0; - } - - prop = of_find_property(np, "synaptics,reset-gpio", NULL); - if (prop && prop->length) { - bdata->reset_gpio = of_get_named_gpio_flags(np, - "synaptics,reset-gpio", 0, NULL); - retval = of_property_read_u32(np, "synaptics,reset-on-state", - &value); - if (retval < 0) { - dev_err(dev, "%s: Unable to read synaptics,reset-on-state property\n", - __func__); - return retval; - } else { - bdata->reset_on_state = value; - } - retval = of_property_read_u32(np, "synaptics,reset-active-ms", - &value); - if (retval < 0) { - dev_err(dev, "%s: Unable to read synaptics,reset-active-ms property\n", - __func__); - return retval; - } else { - bdata->reset_active_ms = value; - } - } else { - bdata->reset_gpio = -1; - } - - prop = of_find_property(np, "synaptics,reset-delay-ms", NULL); - if (prop && prop->length) { - retval = of_property_read_u32(np, "synaptics,reset-delay-ms", - &value); - if (retval < 0) { - dev_err(dev, "%s: Unable to read synaptics,reset-delay-ms property\n", - __func__); - return retval; - } else { - bdata->reset_delay_ms = value; - } - } else { - bdata->reset_delay_ms = 0; - } - - prop = of_find_property(np, "synaptics,max-y-for-2d", NULL); - if (prop && prop->length) { - retval = of_property_read_u32(np, "synaptics,max-y-for-2d", - &value); - if (retval < 0) { - dev_err(dev, "%s: Unable to read synaptics,max-y-for-2d property\n", - __func__); - return retval; - } else { - bdata->max_y_for_2d = value; - } - } else { - bdata->max_y_for_2d = -1; - } - - prop = of_find_property(np, "synaptics,swap-axes", NULL); - bdata->swap_axes = prop > 0 ? true : false; - - prop = of_find_property(np, "synaptics,x-flip", NULL); - bdata->x_flip = prop > 0 ? true : false; - - prop = of_find_property(np, "synaptics,y-flip", NULL); - bdata->y_flip = prop > 0 ? true : false; - - prop = of_find_property(np, "synaptics,ub-i2c-addr", NULL); - if (prop && prop->length) { - retval = of_property_read_u32(np, "synaptics,ub-i2c-addr", - &value); - if (retval < 0) { - dev_err(dev, "%s: Unable to read synaptics,ub-i2c-addr property\n", - __func__); - return retval; - } else { - bdata->ub_i2c_addr = (unsigned short)value; - } - } else { - bdata->ub_i2c_addr = -1; - } - - prop = of_find_property(np, "synaptics,cap-button-codes", NULL); - if (prop && prop->length) { - bdata->cap_button_map->map = devm_kzalloc(dev, - prop->length, - GFP_KERNEL); - if (!bdata->cap_button_map->map) - return -ENOMEM; - bdata->cap_button_map->nbuttons = prop->length / sizeof(u32); - retval = of_property_read_u32_array(np, - "synaptics,cap-button-codes", - bdata->cap_button_map->map, - bdata->cap_button_map->nbuttons); - if (retval < 0) { - bdata->cap_button_map->nbuttons = 0; - bdata->cap_button_map->map = NULL; - } - } else { - bdata->cap_button_map->nbuttons = 0; - bdata->cap_button_map->map = NULL; - } - - prop = of_find_property(np, "synaptics,vir-button-codes", NULL); - if (prop && prop->length) { - bdata->vir_button_map->map = devm_kzalloc(dev, - prop->length, - GFP_KERNEL); - if (!bdata->vir_button_map->map) - return -ENOMEM; - bdata->vir_button_map->nbuttons = prop->length / sizeof(u32); - bdata->vir_button_map->nbuttons /= 5; - retval = of_property_read_u32_array(np, - "synaptics,vir-button-codes", - bdata->vir_button_map->map, - bdata->vir_button_map->nbuttons * 5); - if (retval < 0) { - bdata->vir_button_map->nbuttons = 0; - bdata->vir_button_map->map = NULL; - } - } else { - bdata->vir_button_map->nbuttons = 0; - bdata->vir_button_map->map = NULL; - } - - return 0; -} -#endif - -static int synaptics_rmi4_i2c_alloc_buf(struct synaptics_rmi4_data *rmi4_data, - unsigned int count) -{ - static unsigned int buf_size; - - if (count > buf_size) { - if (buf_size) - kfree(wr_buf); - wr_buf = kzalloc(count, GFP_KERNEL); - if (!wr_buf) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for buffer\n", - __func__); - buf_size = 0; - return -ENOMEM; - } - buf_size = count; - } - - return 0; -} - -static void synaptics_rmi4_i2c_check_addr(struct synaptics_rmi4_data *rmi4_data, - struct i2c_client *i2c) -{ - if (hw_if.board_data->ub_i2c_addr == -1) - return; - - if (hw_if.board_data->i2c_addr == i2c->addr) - hw_if.board_data->i2c_addr = hw_if.board_data->ub_i2c_addr; - else - hw_if.board_data->i2c_addr = i2c->addr; - - return; -} - -static int synaptics_rmi4_i2c_set_page(struct synaptics_rmi4_data *rmi4_data, - unsigned short addr) -{ - int retval = 0; - unsigned char retry; - unsigned char buf[PAGE_SELECT_LEN]; - unsigned char page; - struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent); - struct i2c_msg msg[1]; - - msg[0].addr = hw_if.board_data->i2c_addr; - msg[0].flags = 0; - msg[0].len = PAGE_SELECT_LEN; - msg[0].buf = buf; - - page = ((addr >> 8) & MASK_8BIT); - buf[0] = MASK_8BIT; - buf[1] = page; - - if (page != rmi4_data->current_page) { - for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) { - if (i2c_transfer(i2c->adapter, msg, 1) == 1) { - rmi4_data->current_page = page; - retval = PAGE_SELECT_LEN; - break; - } - dev_err(rmi4_data->pdev->dev.parent, - "%s: I2C retry %d\n", - __func__, retry + 1); - msleep(20); - - if (retry == SYN_I2C_RETRY_TIMES / 2) { - synaptics_rmi4_i2c_check_addr(rmi4_data, i2c); - msg[0].addr = hw_if.board_data->i2c_addr; - } - } - } else { - retval = PAGE_SELECT_LEN; - } - - return retval; -} - -static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data, - unsigned short addr, unsigned char *data, unsigned short length) -{ - int retval; - unsigned char retry; - unsigned char buf; -#ifdef I2C_BURST_LIMIT - unsigned char ii; - unsigned char rd_msgs = ((length - 1) / I2C_BURST_LIMIT) + 1; -#else - unsigned char rd_msgs = 1; -#endif - unsigned char index = 0; - unsigned char xfer_msgs; - unsigned char remaining_msgs; - unsigned short i2c_addr; - unsigned short data_offset = 0; - unsigned short remaining_length = length; - struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent); - struct i2c_adapter *adap = i2c->adapter; - struct i2c_msg msg[rd_msgs + 1]; - - mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex); - - retval = synaptics_rmi4_i2c_set_page(rmi4_data, addr); - if (retval != PAGE_SELECT_LEN) { - retval = -EIO; - goto exit; - } - - msg[0].addr = hw_if.board_data->i2c_addr; - msg[0].flags = 0; - msg[0].len = 1; - msg[0].buf = &buf; - -#ifdef I2C_BURST_LIMIT - for (ii = 0; ii < (rd_msgs - 1); ii++) { - msg[ii + 1].addr = hw_if.board_data->i2c_addr; - msg[ii + 1].flags = I2C_M_RD; - msg[ii + 1].len = I2C_BURST_LIMIT; - msg[ii + 1].buf = &data[data_offset]; - data_offset += I2C_BURST_LIMIT; - remaining_length -= I2C_BURST_LIMIT; - } -#endif - - msg[rd_msgs].addr = hw_if.board_data->i2c_addr; - msg[rd_msgs].flags = I2C_M_RD; - msg[rd_msgs].len = remaining_length; - msg[rd_msgs].buf = &data[data_offset]; - - buf = addr & MASK_8BIT; - - remaining_msgs = rd_msgs + 1; - - while (remaining_msgs) { -#ifdef XFER_MSGS_LIMIT - if (remaining_msgs > XFER_MSGS_LIMIT) - xfer_msgs = XFER_MSGS_LIMIT; - else - xfer_msgs = remaining_msgs; -#else - xfer_msgs = remaining_msgs; -#endif - for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) { - retval = i2c_transfer(adap, &msg[index], xfer_msgs); - if (retval == xfer_msgs) - break; - - dev_err(rmi4_data->pdev->dev.parent, - "%s: I2C retry %d\n", - __func__, retry + 1); - msleep(20); - - if (retry == SYN_I2C_RETRY_TIMES / 2) { - synaptics_rmi4_i2c_check_addr(rmi4_data, i2c); - i2c_addr = hw_if.board_data->i2c_addr; - msg[0].addr = i2c_addr; -#ifdef I2C_BURST_LIMIT - for (ii = 0; ii < (rd_msgs - 1); ii++) - msg[ii + 1].addr = i2c_addr; -#endif - msg[rd_msgs].addr = i2c_addr; - } - } - - if (retry == SYN_I2C_RETRY_TIMES) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: I2C read over retry limit\n", - __func__); - retval = -EIO; - goto exit; - } - - remaining_msgs -= xfer_msgs; - index += xfer_msgs; - } - - retval = length; - -exit: - mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex); - - return retval; -} - -static int synaptics_rmi4_i2c_write(struct synaptics_rmi4_data *rmi4_data, - unsigned short addr, unsigned char *data, unsigned short length) -{ - int retval; - unsigned char retry; - struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent); - struct i2c_msg msg[1]; - - mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex); - - retval = synaptics_rmi4_i2c_alloc_buf(rmi4_data, length + 1); - if (retval < 0) - goto exit; - - retval = synaptics_rmi4_i2c_set_page(rmi4_data, addr); - if (retval != PAGE_SELECT_LEN) { - retval = -EIO; - goto exit; - } - - msg[0].addr = hw_if.board_data->i2c_addr; - msg[0].flags = 0; - msg[0].len = length + 1; - msg[0].buf = wr_buf; - - wr_buf[0] = addr & MASK_8BIT; - retval = secure_memcpy(&wr_buf[1], length, &data[0], length, length); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to copy data\n", - __func__); - goto exit; - } - - for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) { - if (i2c_transfer(i2c->adapter, msg, 1) == 1) { - retval = length; - break; - } - dev_err(rmi4_data->pdev->dev.parent, - "%s: I2C retry %d\n", - __func__, retry + 1); - msleep(20); - - if (retry == SYN_I2C_RETRY_TIMES / 2) { - synaptics_rmi4_i2c_check_addr(rmi4_data, i2c); - msg[0].addr = hw_if.board_data->i2c_addr; - } - } - - if (retry == SYN_I2C_RETRY_TIMES) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: I2C write over retry limit\n", - __func__); - retval = -EIO; - } - -exit: - mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex); - - return retval; -} - -#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26) -static int synaptics_rmi4_clk_prepare_enable( - struct synaptics_rmi4_data *rmi4_data) -{ - int ret; - - ret = clk_prepare_enable(rmi4_data->iface_clk); - if (ret) { - dev_err(rmi4_data->pdev->dev.parent, - "error on clk_prepare_enable(iface_clk):%d\n", ret); - return ret; - } - - ret = clk_prepare_enable(rmi4_data->core_clk); - if (ret) { - clk_disable_unprepare(rmi4_data->iface_clk); - dev_err(rmi4_data->pdev->dev.parent, - "error clk_prepare_enable(core_clk):%d\n", ret); - } - return ret; -} - -static void synaptics_rmi4_clk_disable_unprepare( - struct synaptics_rmi4_data *rmi4_data) -{ - clk_disable_unprepare(rmi4_data->core_clk); - clk_disable_unprepare(rmi4_data->iface_clk); -} - -static int synaptics_rmi4_i2c_get(struct synaptics_rmi4_data *rmi4_data) -{ - int retval; - struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent); - - mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex); - retval = pm_runtime_get_sync(i2c->adapter->dev.parent); - if (retval >= 0 && rmi4_data->core_clk != NULL && - rmi4_data->iface_clk != NULL) { - retval = synaptics_rmi4_clk_prepare_enable(rmi4_data); - if (retval) - pm_runtime_put_sync(i2c->adapter->dev.parent); - } - mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex); - - return retval; -} - -static void synaptics_rmi4_i2c_put(struct synaptics_rmi4_data *rmi4_data) -{ - struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent); - - mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex); - if (rmi4_data->core_clk != NULL && rmi4_data->iface_clk != NULL) - synaptics_rmi4_clk_disable_unprepare(rmi4_data); - pm_runtime_put_sync(i2c->adapter->dev.parent); - mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex); -} -#endif - -static struct synaptics_dsx_bus_access bus_access = { - .type = BUS_I2C, - .read = synaptics_rmi4_i2c_read, - .write = synaptics_rmi4_i2c_write, -#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26) - .get = synaptics_rmi4_i2c_get, - .put = synaptics_rmi4_i2c_put, -#endif -}; - -static void synaptics_rmi4_i2c_dev_release(struct device *dev) -{ - kfree(synaptics_dsx_i2c_device); - - return; -} - -static int synaptics_rmi4_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *dev_id) -{ - int retval; - - if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_BYTE_DATA)) { - dev_err(&client->dev, - "%s: SMBus byte data commands not supported by host\n", - __func__); - return -EIO; - } - - synaptics_dsx_i2c_device = kzalloc( - sizeof(struct platform_device), - GFP_KERNEL); - if (!synaptics_dsx_i2c_device) { - dev_err(&client->dev, - "%s: Failed to allocate memory for synaptics_dsx_i2c_device\n", - __func__); - return -ENOMEM; - } - -#ifdef CONFIG_OF - if (client->dev.of_node) { - hw_if.board_data = devm_kzalloc(&client->dev, - sizeof(struct synaptics_dsx_board_data), - GFP_KERNEL); - if (!hw_if.board_data) { - dev_err(&client->dev, - "%s: Failed to allocate memory for board data\n", - __func__); - return -ENOMEM; - } - hw_if.board_data->cap_button_map = devm_kzalloc(&client->dev, - sizeof(struct synaptics_dsx_button_map), - GFP_KERNEL); - if (!hw_if.board_data->cap_button_map) { - dev_err(&client->dev, - "%s: Failed to allocate memory for 0D button map\n", - __func__); - return -ENOMEM; - } - hw_if.board_data->vir_button_map = devm_kzalloc(&client->dev, - sizeof(struct synaptics_dsx_button_map), - GFP_KERNEL); - if (!hw_if.board_data->vir_button_map) { - dev_err(&client->dev, - "%s: Failed to allocate memory for virtual button map\n", - __func__); - return -ENOMEM; - } - parse_dt(&client->dev, hw_if.board_data); - } -#else - hw_if.board_data = client->dev.platform_data; -#endif - - hw_if.bus_access = &bus_access; - hw_if.board_data->i2c_addr = client->addr; - - synaptics_dsx_i2c_device->name = PLATFORM_DRIVER_NAME; - synaptics_dsx_i2c_device->id = 0; - synaptics_dsx_i2c_device->num_resources = 0; - synaptics_dsx_i2c_device->dev.parent = &client->dev; - synaptics_dsx_i2c_device->dev.platform_data = &hw_if; - synaptics_dsx_i2c_device->dev.release = synaptics_rmi4_i2c_dev_release; - - retval = platform_device_register(synaptics_dsx_i2c_device); - if (retval) { - dev_err(&client->dev, - "%s: Failed to register platform device\n", - __func__); - return -ENODEV; - } - - return 0; -} - -static int synaptics_rmi4_i2c_remove(struct i2c_client *client) -{ - platform_device_unregister(synaptics_dsx_i2c_device); - - return 0; -} - -static const struct i2c_device_id synaptics_rmi4_id_table[] = { - {I2C_DRIVER_NAME, 0}, - {}, -}; -MODULE_DEVICE_TABLE(i2c, synaptics_rmi4_id_table); - -#ifdef CONFIG_OF -static struct of_device_id synaptics_rmi4_of_match_table[] = { - { - .compatible = "synaptics,dsx-i2c", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, synaptics_rmi4_of_match_table); -#else -#define synaptics_rmi4_of_match_table NULL -#endif - -static struct i2c_driver synaptics_rmi4_i2c_driver = { - .driver = { - .name = I2C_DRIVER_NAME, - .owner = THIS_MODULE, - .of_match_table = synaptics_rmi4_of_match_table, - }, - .probe = synaptics_rmi4_i2c_probe, - .remove = synaptics_rmi4_i2c_remove, - .id_table = synaptics_rmi4_id_table, -}; - -int synaptics_rmi4_bus_init_v26(void) -{ - return i2c_add_driver(&synaptics_rmi4_i2c_driver); -} -EXPORT_SYMBOL(synaptics_rmi4_bus_init_v26); - -void synaptics_rmi4_bus_exit_v26(void) -{ - kfree(wr_buf); - - i2c_del_driver(&synaptics_rmi4_i2c_driver); - - return; -} -EXPORT_SYMBOL(synaptics_rmi4_bus_exit_v26); - -MODULE_AUTHOR("Synaptics, Inc."); -MODULE_DESCRIPTION("Synaptics DSX I2C Bus Support Module"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_proximity.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_proximity.c deleted file mode 100644 index d9e27c306af5..000000000000 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_proximity.c +++ /dev/null @@ -1,692 +0,0 @@ -/* - * Synaptics DSX touchscreen driver - * - * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved. - * - * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com> - * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com> - * - * 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. - * - * 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. - * - * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS - * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, - * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS. - * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION - * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED - * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES - * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' - * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. - * DOLLARS. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/input.h> -#include <linux/platform_device.h> -#include <linux/input/synaptics_dsx_v2_6.h> -#include "synaptics_dsx_core.h" - -#define PROX_PHYS_NAME "synaptics_dsx/proximity" - -#define HOVER_Z_MAX (255) - -#define HOVERING_FINGER_EN (1 << 4) - -static ssize_t synaptics_rmi4_hover_finger_en_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t synaptics_rmi4_hover_finger_en_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static struct device_attribute attrs[] = { - __ATTR(hover_finger_en, (S_IRUGO | S_IWUGO), - synaptics_rmi4_hover_finger_en_show, - synaptics_rmi4_hover_finger_en_store), -}; - -struct synaptics_rmi4_f12_query_5 { - union { - struct { - unsigned char size_of_query6; - struct { - unsigned char ctrl0_is_present:1; - unsigned char ctrl1_is_present:1; - unsigned char ctrl2_is_present:1; - unsigned char ctrl3_is_present:1; - unsigned char ctrl4_is_present:1; - unsigned char ctrl5_is_present:1; - unsigned char ctrl6_is_present:1; - unsigned char ctrl7_is_present:1; - } __packed; - struct { - unsigned char ctrl8_is_present:1; - unsigned char ctrl9_is_present:1; - unsigned char ctrl10_is_present:1; - unsigned char ctrl11_is_present:1; - unsigned char ctrl12_is_present:1; - unsigned char ctrl13_is_present:1; - unsigned char ctrl14_is_present:1; - unsigned char ctrl15_is_present:1; - } __packed; - struct { - unsigned char ctrl16_is_present:1; - unsigned char ctrl17_is_present:1; - unsigned char ctrl18_is_present:1; - unsigned char ctrl19_is_present:1; - unsigned char ctrl20_is_present:1; - unsigned char ctrl21_is_present:1; - unsigned char ctrl22_is_present:1; - unsigned char ctrl23_is_present:1; - } __packed; - }; - unsigned char data[4]; - }; -}; - -struct synaptics_rmi4_f12_query_8 { - union { - struct { - unsigned char size_of_query9; - struct { - unsigned char data0_is_present:1; - unsigned char data1_is_present:1; - unsigned char data2_is_present:1; - unsigned char data3_is_present:1; - unsigned char data4_is_present:1; - unsigned char data5_is_present:1; - unsigned char data6_is_present:1; - unsigned char data7_is_present:1; - } __packed; - }; - unsigned char data[2]; - }; -}; - -struct prox_finger_data { - union { - struct { - unsigned char object_type_and_status; - unsigned char x_lsb; - unsigned char x_msb; - unsigned char y_lsb; - unsigned char y_msb; - unsigned char z; - } __packed; - unsigned char proximity_data[6]; - }; -}; - -struct synaptics_rmi4_prox_handle { - bool hover_finger_present; - bool hover_finger_en; - unsigned char intr_mask; - unsigned short query_base_addr; - unsigned short control_base_addr; - unsigned short data_base_addr; - unsigned short command_base_addr; - unsigned short hover_finger_en_addr; - unsigned short hover_finger_data_addr; - struct input_dev *prox_dev; - struct prox_finger_data *finger_data; - struct synaptics_rmi4_data *rmi4_data; -}; - -static struct synaptics_rmi4_prox_handle *prox; - -DECLARE_COMPLETION(prox_remove_complete); - -static void prox_hover_finger_lift(void) -{ - input_report_key(prox->prox_dev, BTN_TOUCH, 0); - input_report_key(prox->prox_dev, BTN_TOOL_FINGER, 0); - input_sync(prox->prox_dev); - prox->hover_finger_present = false; - - return; -} - -static void prox_hover_finger_report(void) -{ - int retval; - int x; - int y; - int z; - struct prox_finger_data *data; - struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data; - - data = prox->finger_data; - - retval = synaptics_rmi4_reg_read(rmi4_data, - prox->hover_finger_data_addr, - data->proximity_data, - sizeof(data->proximity_data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read hovering finger data\n", - __func__); - return; - } - - if (data->object_type_and_status != F12_HOVERING_FINGER_STATUS) { - if (prox->hover_finger_present) - prox_hover_finger_lift(); - - return; - } - - x = (data->x_msb << 8) | (data->x_lsb); - y = (data->y_msb << 8) | (data->y_lsb); - z = HOVER_Z_MAX - data->z; - - input_report_key(prox->prox_dev, BTN_TOUCH, 0); - input_report_key(prox->prox_dev, BTN_TOOL_FINGER, 1); - input_report_abs(prox->prox_dev, ABS_X, x); - input_report_abs(prox->prox_dev, ABS_Y, y); - input_report_abs(prox->prox_dev, ABS_DISTANCE, z); - - input_sync(prox->prox_dev); - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: x = %d y = %d z = %d\n", - __func__, x, y, z); - - prox->hover_finger_present = true; - - return; -} - -static int prox_set_hover_finger_en(void) -{ - int retval; - unsigned char object_report_enable; - struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data; - - retval = synaptics_rmi4_reg_read(rmi4_data, - prox->hover_finger_en_addr, - &object_report_enable, - sizeof(object_report_enable)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read from object report enable register\n", - __func__); - return retval; - } - - if (prox->hover_finger_en) - object_report_enable |= HOVERING_FINGER_EN; - else - object_report_enable &= ~HOVERING_FINGER_EN; - - retval = synaptics_rmi4_reg_write(rmi4_data, - prox->hover_finger_en_addr, - &object_report_enable, - sizeof(object_report_enable)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write to object report enable register\n", - __func__); - return retval; - } - - return 0; -} - -static void prox_set_params(void) -{ - input_set_abs_params(prox->prox_dev, ABS_X, 0, - prox->rmi4_data->sensor_max_x, 0, 0); - input_set_abs_params(prox->prox_dev, ABS_Y, 0, - prox->rmi4_data->sensor_max_y, 0, 0); - input_set_abs_params(prox->prox_dev, ABS_DISTANCE, 0, - HOVER_Z_MAX, 0, 0); - - return; -} - -static int prox_reg_init(void) -{ - int retval; - unsigned char ctrl_23_offset; - unsigned char data_1_offset; - struct synaptics_rmi4_f12_query_5 query_5; - struct synaptics_rmi4_f12_query_8 query_8; - struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data; - - retval = synaptics_rmi4_reg_read(rmi4_data, - prox->query_base_addr + 5, - query_5.data, - sizeof(query_5.data)); - if (retval < 0) - return retval; - - ctrl_23_offset = query_5.ctrl0_is_present + - query_5.ctrl1_is_present + - query_5.ctrl2_is_present + - query_5.ctrl3_is_present + - query_5.ctrl4_is_present + - query_5.ctrl5_is_present + - query_5.ctrl6_is_present + - query_5.ctrl7_is_present + - query_5.ctrl8_is_present + - query_5.ctrl9_is_present + - query_5.ctrl10_is_present + - query_5.ctrl11_is_present + - query_5.ctrl12_is_present + - query_5.ctrl13_is_present + - query_5.ctrl14_is_present + - query_5.ctrl15_is_present + - query_5.ctrl16_is_present + - query_5.ctrl17_is_present + - query_5.ctrl18_is_present + - query_5.ctrl19_is_present + - query_5.ctrl20_is_present + - query_5.ctrl21_is_present + - query_5.ctrl22_is_present; - - prox->hover_finger_en_addr = prox->control_base_addr + ctrl_23_offset; - - retval = synaptics_rmi4_reg_read(rmi4_data, - prox->query_base_addr + 8, - query_8.data, - sizeof(query_8.data)); - if (retval < 0) - return retval; - - data_1_offset = query_8.data0_is_present; - prox->hover_finger_data_addr = prox->data_base_addr + data_1_offset; - - return retval; -} - -static int prox_scan_pdt(void) -{ - int retval; - unsigned char ii; - unsigned char page; - unsigned char intr_count = 0; - unsigned char intr_off; - unsigned char intr_src; - unsigned short addr; - struct synaptics_rmi4_fn_desc fd; - struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data; - - for (page = 0; page < PAGES_TO_SERVICE; page++) { - for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) { - addr |= (page << 8); - - retval = synaptics_rmi4_reg_read(rmi4_data, - addr, - (unsigned char *)&fd, - sizeof(fd)); - if (retval < 0) - return retval; - - addr &= ~(MASK_8BIT << 8); - - if (fd.fn_number) { - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Found F%02x\n", - __func__, fd.fn_number); - switch (fd.fn_number) { - case SYNAPTICS_RMI4_F12: - goto f12_found; - break; - } - } else { - break; - } - - intr_count += fd.intr_src_count; - } - } - - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to find F12\n", - __func__); - return -EINVAL; - -f12_found: - prox->query_base_addr = fd.query_base_addr | (page << 8); - prox->control_base_addr = fd.ctrl_base_addr | (page << 8); - prox->data_base_addr = fd.data_base_addr | (page << 8); - prox->command_base_addr = fd.cmd_base_addr | (page << 8); - - retval = prox_reg_init(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to initialize proximity registers\n", - __func__); - return retval; - } - - prox->intr_mask = 0; - intr_src = fd.intr_src_count; - intr_off = intr_count % 8; - for (ii = intr_off; - ii < (intr_src + intr_off); - ii++) { - prox->intr_mask |= 1 << ii; - } - - rmi4_data->intr_mask[0] |= prox->intr_mask; - - addr = rmi4_data->f01_ctrl_base_addr + 1; - - retval = synaptics_rmi4_reg_write(rmi4_data, - addr, - &(rmi4_data->intr_mask[0]), - sizeof(rmi4_data->intr_mask[0])); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to set interrupt enable bit\n", - __func__); - return retval; - } - - return 0; -} - -static ssize_t synaptics_rmi4_hover_finger_en_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - if (!prox) - return -ENODEV; - - return snprintf(buf, PAGE_SIZE, "%u\n", - prox->hover_finger_en); -} - -static ssize_t synaptics_rmi4_hover_finger_en_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned int input; - struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data; - - if (!prox) - return -ENODEV; - - if (sscanf(buf, "%x", &input) != 1) - return -EINVAL; - - if (input == 1) - prox->hover_finger_en = true; - else if (input == 0) - prox->hover_finger_en = false; - else - return -EINVAL; - - retval = prox_set_hover_finger_en(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to change hovering finger enable setting\n", - __func__); - return retval; - } - - return count; -} - -int synaptics_rmi4_prox_hover_finger_en(bool enable) -{ - int retval; - - if (!prox) - return -ENODEV; - - prox->hover_finger_en = enable; - - retval = prox_set_hover_finger_en(); - if (retval < 0) - return retval; - - return 0; -} -EXPORT_SYMBOL(synaptics_rmi4_prox_hover_finger_en); - -static void synaptics_rmi4_prox_attn(struct synaptics_rmi4_data *rmi4_data, - unsigned char intr_mask) -{ - if (!prox) - return; - - if (prox->intr_mask & intr_mask) - prox_hover_finger_report(); - - return; -} - -static int synaptics_rmi4_prox_init(struct synaptics_rmi4_data *rmi4_data) -{ - int retval; - unsigned char attr_count; - - if (prox) { - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Handle already exists\n", - __func__); - return 0; - } - - prox = kzalloc(sizeof(*prox), GFP_KERNEL); - if (!prox) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for prox\n", - __func__); - retval = -ENOMEM; - goto exit; - } - - prox->finger_data = kzalloc(sizeof(*(prox->finger_data)), GFP_KERNEL); - if (!prox->finger_data) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for finger_data\n", - __func__); - retval = -ENOMEM; - goto exit_free_prox; - } - - prox->rmi4_data = rmi4_data; - - retval = prox_scan_pdt(); - if (retval < 0) - goto exit_free_finger_data; - - prox->hover_finger_en = true; - - retval = prox_set_hover_finger_en(); - if (retval < 0) - return retval; - - prox->prox_dev = input_allocate_device(); - if (prox->prox_dev == NULL) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to allocate proximity device\n", - __func__); - retval = -ENOMEM; - goto exit_free_finger_data; - } - - prox->prox_dev->name = PROXIMITY_DRIVER_NAME; - prox->prox_dev->phys = PROX_PHYS_NAME; - prox->prox_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT; - prox->prox_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION; - prox->prox_dev->dev.parent = rmi4_data->pdev->dev.parent; - input_set_drvdata(prox->prox_dev, rmi4_data); - - set_bit(EV_KEY, prox->prox_dev->evbit); - set_bit(EV_ABS, prox->prox_dev->evbit); - set_bit(BTN_TOUCH, prox->prox_dev->keybit); - set_bit(BTN_TOOL_FINGER, prox->prox_dev->keybit); -#ifdef INPUT_PROP_DIRECT - set_bit(INPUT_PROP_DIRECT, prox->prox_dev->propbit); -#endif - - prox_set_params(); - - retval = input_register_device(prox->prox_dev); - if (retval) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to register proximity device\n", - __func__); - goto exit_free_input_device; - } - - for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { - retval = sysfs_create_file(&rmi4_data->input_dev->dev.kobj, - &attrs[attr_count].attr); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create sysfs attributes\n", - __func__); - goto exit_free_sysfs; - } - } - - return 0; - -exit_free_sysfs: - for (attr_count--; attr_count >= 0; attr_count--) { - sysfs_remove_file(&rmi4_data->input_dev->dev.kobj, - &attrs[attr_count].attr); - } - - input_unregister_device(prox->prox_dev); - prox->prox_dev = NULL; - -exit_free_input_device: - if (prox->prox_dev) - input_free_device(prox->prox_dev); - -exit_free_finger_data: - kfree(prox->finger_data); - -exit_free_prox: - kfree(prox); - prox = NULL; - -exit: - return retval; -} - -static void synaptics_rmi4_prox_remove(struct synaptics_rmi4_data *rmi4_data) -{ - unsigned char attr_count; - - if (!prox) - goto exit; - - for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { - sysfs_remove_file(&rmi4_data->input_dev->dev.kobj, - &attrs[attr_count].attr); - } - - input_unregister_device(prox->prox_dev); - kfree(prox->finger_data); - kfree(prox); - prox = NULL; - -exit: - complete(&prox_remove_complete); - - return; -} - -static void synaptics_rmi4_prox_reset(struct synaptics_rmi4_data *rmi4_data) -{ - if (!prox) { - synaptics_rmi4_prox_init(rmi4_data); - return; - } - - prox_hover_finger_lift(); - - prox_scan_pdt(); - - prox_set_hover_finger_en(); - - return; -} - -static void synaptics_rmi4_prox_reinit(struct synaptics_rmi4_data *rmi4_data) -{ - if (!prox) - return; - - prox_hover_finger_lift(); - - prox_set_hover_finger_en(); - - return; -} - -static void synaptics_rmi4_prox_e_suspend(struct synaptics_rmi4_data *rmi4_data) -{ - if (!prox) - return; - - prox_hover_finger_lift(); - - return; -} - -static void synaptics_rmi4_prox_suspend(struct synaptics_rmi4_data *rmi4_data) -{ - if (!prox) - return; - - prox_hover_finger_lift(); - - return; -} - -static struct synaptics_rmi4_exp_fn proximity_module = { - .fn_type = RMI_PROXIMITY, - .init = synaptics_rmi4_prox_init, - .remove = synaptics_rmi4_prox_remove, - .reset = synaptics_rmi4_prox_reset, - .reinit = synaptics_rmi4_prox_reinit, - .early_suspend = synaptics_rmi4_prox_e_suspend, - .suspend = synaptics_rmi4_prox_suspend, - .resume = NULL, - .late_resume = NULL, - .attn = synaptics_rmi4_prox_attn, -}; - -static int __init rmi4_proximity_module_init(void) -{ - synaptics_rmi4_new_function(&proximity_module, true); - - return 0; -} - -static void __exit rmi4_proximity_module_exit(void) -{ - synaptics_rmi4_new_function(&proximity_module, false); - - wait_for_completion(&prox_remove_complete); - - return; -} - -module_init(rmi4_proximity_module_init); -module_exit(rmi4_proximity_module_exit); - -MODULE_AUTHOR("Synaptics, Inc."); -MODULE_DESCRIPTION("Synaptics DSX Proximity Module"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_rmi_dev.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_rmi_dev.c deleted file mode 100644 index 111b26c7b759..000000000000 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_rmi_dev.c +++ /dev/null @@ -1,1058 +0,0 @@ -/* - * Synaptics DSX touchscreen driver - * - * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved. - * - * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com> - * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com> - * - * 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. - * - * 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. - * - * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS - * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, - * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS. - * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION - * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED - * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES - * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' - * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. - * DOLLARS. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/input.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/gpio.h> -#include <linux/uaccess.h> -#include <linux/cdev.h> -#include <linux/platform_device.h> -#include <linux/input/synaptics_dsx_v2_6.h> -#include "synaptics_dsx_core.h" - -#define CHAR_DEVICE_NAME "rmi" -#define DEVICE_CLASS_NAME "rmidev" -#define SYSFS_FOLDER_NAME "rmidev" -#define DEV_NUMBER 1 -#define REG_ADDR_LIMIT 0xFFFF - -static ssize_t rmidev_sysfs_data_show(struct file *data_file, - struct kobject *kobj, struct bin_attribute *attributes, - char *buf, loff_t pos, size_t count); - -static ssize_t rmidev_sysfs_data_store(struct file *data_file, - struct kobject *kobj, struct bin_attribute *attributes, - char *buf, loff_t pos, size_t count); - -static ssize_t rmidev_sysfs_open_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t rmidev_sysfs_release_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t rmidev_sysfs_attn_state_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t rmidev_sysfs_pid_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t rmidev_sysfs_pid_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t rmidev_sysfs_term_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t rmidev_sysfs_intr_mask_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t rmidev_sysfs_intr_mask_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t rmidev_sysfs_concurrent_show(struct device *dev, - struct device_attribute *attr, char *buf); - -static ssize_t rmidev_sysfs_concurrent_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -struct rmidev_handle { - dev_t dev_no; - pid_t pid; - unsigned char intr_mask; - unsigned char *tmpbuf; - unsigned int tmpbuf_size; - struct device dev; - struct synaptics_rmi4_data *rmi4_data; - struct kobject *sysfs_dir; - struct siginfo interrupt_signal; - struct siginfo terminate_signal; - struct task_struct *task; - void *data; - bool irq_enabled; - bool concurrent; -}; - -struct rmidev_data { - int ref_count; - struct cdev main_dev; - struct class *device_class; - struct mutex file_mutex; - struct rmidev_handle *rmi_dev; -}; - -static struct bin_attribute attr_data = { - .attr = { - .name = "data", - .mode = (S_IRUGO | S_IWUSR), - }, - .size = 0, - .read = rmidev_sysfs_data_show, - .write = rmidev_sysfs_data_store, -}; - -static struct device_attribute attrs[] = { - __ATTR(open, S_IWUSR | S_IWGRP, - NULL, - rmidev_sysfs_open_store), - __ATTR(release, S_IWUSR | S_IWGRP, - NULL, - rmidev_sysfs_release_store), - __ATTR(attn_state, S_IRUGO, - rmidev_sysfs_attn_state_show, - NULL), - __ATTR(pid, S_IRUGO | S_IRUGO | S_IWUSR | S_IWGRP, - rmidev_sysfs_pid_show, - rmidev_sysfs_pid_store), - __ATTR(term, S_IWUSR | S_IWGRP, - NULL, - rmidev_sysfs_term_store), - __ATTR(intr_mask, S_IRUGO, - rmidev_sysfs_intr_mask_show, - rmidev_sysfs_intr_mask_store), - __ATTR(concurrent, S_IRUGO, - rmidev_sysfs_concurrent_show, - rmidev_sysfs_concurrent_store), -}; - -static int rmidev_major_num; - -static struct class *rmidev_device_class; - -static struct rmidev_handle *rmidev; - -DECLARE_COMPLETION(rmidev_remove_complete_v26); - -static irqreturn_t rmidev_sysfs_irq(int irq, void *data) -{ - struct synaptics_rmi4_data *rmi4_data = data; - - sysfs_notify(&rmi4_data->input_dev->dev.kobj, - SYSFS_FOLDER_NAME, "attn_state"); - - return IRQ_HANDLED; -} - -static int rmidev_sysfs_irq_enable(struct synaptics_rmi4_data *rmi4_data, - bool enable) -{ - int retval = 0; - unsigned char intr_status[MAX_INTR_REGISTERS]; - unsigned long irq_flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | - IRQF_ONESHOT; - - if (enable) { - if (rmidev->irq_enabled) - return retval; - - /* Clear interrupts first */ - retval = synaptics_rmi4_reg_read(rmi4_data, - rmi4_data->f01_data_base_addr + 1, - intr_status, - rmi4_data->num_of_intr_regs); - if (retval < 0) - return retval; - - retval = request_threaded_irq(rmi4_data->irq, NULL, - rmidev_sysfs_irq, irq_flags, - PLATFORM_DRIVER_NAME, rmi4_data); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create irq thread\n", - __func__); - return retval; - } - - rmidev->irq_enabled = true; - } else { - if (rmidev->irq_enabled) { - disable_irq(rmi4_data->irq); - free_irq(rmi4_data->irq, rmi4_data); - rmidev->irq_enabled = false; - } - } - - return retval; -} - -static ssize_t rmidev_sysfs_data_show(struct file *data_file, - struct kobject *kobj, struct bin_attribute *attributes, - char *buf, loff_t pos, size_t count) -{ - int retval; - unsigned char intr_status = 0; - unsigned int length = (unsigned int)count; - unsigned short address = (unsigned short)pos; - struct synaptics_rmi4_fn *fhandler; - struct synaptics_rmi4_device_info *rmi; - struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data; - - rmi = &(rmi4_data->rmi4_mod_info); - - if (length > (REG_ADDR_LIMIT - address)) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Out of register map limit\n", - __func__); - return -EINVAL; - } - - if (length) { - retval = synaptics_rmi4_reg_read(rmi4_data, - address, - (unsigned char *)buf, - length); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read data\n", - __func__); - return retval; - } - } else { - return -EINVAL; - } - - if (!rmidev->concurrent) - goto exit; - - if (address != rmi4_data->f01_data_base_addr) - goto exit; - - if (length <= 1) - goto exit; - - intr_status = buf[1]; - - if (!list_empty(&rmi->support_fn_list)) { - list_for_each_entry(fhandler, &rmi->support_fn_list, link) { - if (fhandler->num_of_data_sources) { - if (fhandler->intr_mask & intr_status) { - rmi4_data->report_touch(rmi4_data, - fhandler); - } - } - } - } - -exit: - return length; -} - -static ssize_t rmidev_sysfs_data_store(struct file *data_file, - struct kobject *kobj, struct bin_attribute *attributes, - char *buf, loff_t pos, size_t count) -{ - int retval; - unsigned int length = (unsigned int)count; - unsigned short address = (unsigned short)pos; - struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data; - - if (length > (REG_ADDR_LIMIT - address)) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Out of register map limit\n", - __func__); - return -EINVAL; - } - - if (length) { - retval = synaptics_rmi4_reg_write(rmi4_data, - address, - (unsigned char *)buf, - length); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write data\n", - __func__); - return retval; - } - } else { - return -EINVAL; - } - - return length; -} - -static ssize_t rmidev_sysfs_open_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - unsigned int input; - struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data; - - if (sscanf(buf, "%u", &input) != 1) - return -EINVAL; - - if (input != 1) - return -EINVAL; - - if (rmi4_data->sensor_sleep) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Sensor sleeping\n", - __func__); - return -ENODEV; - } - - rmi4_data->stay_awake = true; - - rmi4_data->irq_enable(rmi4_data, false, false); - rmidev_sysfs_irq_enable(rmi4_data, true); - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Attention interrupt disabled\n", - __func__); - - return count; -} - -static ssize_t rmidev_sysfs_release_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - unsigned int input; - struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data; - - if (sscanf(buf, "%u", &input) != 1) - return -EINVAL; - - if (input != 1) - return -EINVAL; - - rmidev_sysfs_irq_enable(rmi4_data, false); - rmi4_data->irq_enable(rmi4_data, true, false); - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Attention interrupt enabled\n", - __func__); - - rmi4_data->reset_device(rmi4_data, false); - - rmi4_data->stay_awake = false; - - return count; -} - -static ssize_t rmidev_sysfs_attn_state_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int attn_state; - struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data; - const struct synaptics_dsx_board_data *bdata = - rmi4_data->hw_if->board_data; - - attn_state = gpio_get_value(bdata->irq_gpio); - - return snprintf(buf, PAGE_SIZE, "%u\n", attn_state); -} - -static ssize_t rmidev_sysfs_pid_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%u\n", rmidev->pid); -} - -static ssize_t rmidev_sysfs_pid_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - unsigned int input; - struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data; - - if (sscanf(buf, "%u", &input) != 1) - return -EINVAL; - - rmidev->pid = input; - - if (rmidev->pid) { - rmidev->task = pid_task(find_vpid(rmidev->pid), PIDTYPE_PID); - if (!rmidev->task) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to locate PID of data logging tool\n", - __func__); - return -EINVAL; - } - } - - return count; -} - -static ssize_t rmidev_sysfs_term_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - unsigned int input; - - if (sscanf(buf, "%u", &input) != 1) - return -EINVAL; - - if (input != 1) - return -EINVAL; - - if (rmidev->pid) - send_sig_info(SIGTERM, &rmidev->terminate_signal, rmidev->task); - - return count; -} - -static ssize_t rmidev_sysfs_intr_mask_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "0x%02x\n", rmidev->intr_mask); -} - -static ssize_t rmidev_sysfs_intr_mask_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - unsigned int input; - - if (sscanf(buf, "%u", &input) != 1) - return -EINVAL; - - rmidev->intr_mask = (unsigned char)input; - - return count; -} - -static ssize_t rmidev_sysfs_concurrent_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", rmidev->concurrent); -} - -static ssize_t rmidev_sysfs_concurrent_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - unsigned int input; - - if (sscanf(buf, "%u", &input) != 1) - return -EINVAL; - - rmidev->concurrent = input > 0 ? true : false; - - return count; -} - -static int rmidev_allocate_buffer(int count) -{ - if (count + 1 > rmidev->tmpbuf_size) { - if (rmidev->tmpbuf_size) - kfree(rmidev->tmpbuf); - rmidev->tmpbuf = kzalloc(count + 1, GFP_KERNEL); - if (!rmidev->tmpbuf) { - dev_err(rmidev->rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for buffer\n", - __func__); - rmidev->tmpbuf_size = 0; - return -ENOMEM; - } - rmidev->tmpbuf_size = count + 1; - } - - return 0; -} - -/* - * rmidev_llseek - set register address to access for RMI device - * - * @filp: pointer to file structure - * @off: - * if whence == SEEK_SET, - * off: 16-bit RMI register address - * if whence == SEEK_CUR, - * off: offset from current position - * if whence == SEEK_END, - * off: offset from end position (0xFFFF) - * @whence: SEEK_SET, SEEK_CUR, or SEEK_END - */ -static loff_t rmidev_llseek(struct file *filp, loff_t off, int whence) -{ - loff_t newpos; - struct rmidev_data *dev_data = filp->private_data; - struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data; - - if (IS_ERR(dev_data)) { - pr_err("%s: Pointer of char device data is invalid", __func__); - return -EBADF; - } - - mutex_lock(&(dev_data->file_mutex)); - - switch (whence) { - case SEEK_SET: - newpos = off; - break; - case SEEK_CUR: - newpos = filp->f_pos + off; - break; - case SEEK_END: - newpos = REG_ADDR_LIMIT + off; - break; - default: - newpos = -EINVAL; - goto clean_up; - } - - if (newpos < 0 || newpos > REG_ADDR_LIMIT) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: New position 0x%04x is invalid\n", - __func__, (unsigned int)newpos); - newpos = -EINVAL; - goto clean_up; - } - - filp->f_pos = newpos; - -clean_up: - mutex_unlock(&(dev_data->file_mutex)); - - return newpos; -} - -/* - * rmidev_read: read register data from RMI device - * - * @filp: pointer to file structure - * @buf: pointer to user space buffer - * @count: number of bytes to read - * @f_pos: starting RMI register address - */ -static ssize_t rmidev_read(struct file *filp, char __user *buf, - size_t count, loff_t *f_pos) -{ - ssize_t retval; - unsigned char intr_status = 0; - unsigned short address; - struct rmidev_data *dev_data = filp->private_data; - struct synaptics_rmi4_fn *fhandler; - struct synaptics_rmi4_device_info *rmi; - struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data; - - rmi = &(rmi4_data->rmi4_mod_info); - - if (IS_ERR(dev_data)) { - pr_err("%s: Pointer of char device data is invalid", __func__); - return -EBADF; - } - - if (count == 0) - return 0; - - if (count > (REG_ADDR_LIMIT - *f_pos)) - count = REG_ADDR_LIMIT - *f_pos; - - address = (unsigned short)(*f_pos); - - rmidev_allocate_buffer(count); - - mutex_lock(&(dev_data->file_mutex)); - - retval = synaptics_rmi4_reg_read(rmidev->rmi4_data, - *f_pos, - rmidev->tmpbuf, - count); - if (retval < 0) - goto clean_up; - - if (copy_to_user(buf, rmidev->tmpbuf, count)) - retval = -EFAULT; - else - *f_pos += retval; - - if (!rmidev->concurrent) - goto clean_up; - - if (address != rmi4_data->f01_data_base_addr) - goto clean_up; - - if (count <= 1) - goto clean_up; - - intr_status = rmidev->tmpbuf[1]; - - if (!list_empty(&rmi->support_fn_list)) { - list_for_each_entry(fhandler, &rmi->support_fn_list, link) { - if (fhandler->num_of_data_sources) { - if (fhandler->intr_mask & intr_status) { - rmi4_data->report_touch(rmi4_data, - fhandler); - } - } - } - } - -clean_up: - mutex_unlock(&(dev_data->file_mutex)); - - return retval; -} - -/* - * rmidev_write: write register data to RMI device - * - * @filp: pointer to file structure - * @buf: pointer to user space buffer - * @count: number of bytes to write - * @f_pos: starting RMI register address - */ -static ssize_t rmidev_write(struct file *filp, const char __user *buf, - size_t count, loff_t *f_pos) -{ - ssize_t retval; - struct rmidev_data *dev_data = filp->private_data; - - if (IS_ERR(dev_data)) { - pr_err("%s: Pointer of char device data is invalid", __func__); - return -EBADF; - } - - if (count == 0) - return 0; - - if (count > (REG_ADDR_LIMIT - *f_pos)) - count = REG_ADDR_LIMIT - *f_pos; - - rmidev_allocate_buffer(count); - - if (copy_from_user(rmidev->tmpbuf, buf, count)) - return -EFAULT; - - mutex_lock(&(dev_data->file_mutex)); - - retval = synaptics_rmi4_reg_write(rmidev->rmi4_data, - *f_pos, - rmidev->tmpbuf, - count); - if (retval >= 0) - *f_pos += retval; - - mutex_unlock(&(dev_data->file_mutex)); - - return retval; -} - -static int rmidev_open(struct inode *inp, struct file *filp) -{ - int retval = 0; - struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data; - struct rmidev_data *dev_data = - container_of(inp->i_cdev, struct rmidev_data, main_dev); - - if (!dev_data) - return -EACCES; - - if (rmi4_data->sensor_sleep) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Sensor sleeping\n", - __func__); - return -ENODEV; - } - - rmi4_data->stay_awake = true; - - filp->private_data = dev_data; - - mutex_lock(&(dev_data->file_mutex)); - - rmi4_data->irq_enable(rmi4_data, false, false); - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Attention interrupt disabled\n", - __func__); - - if (dev_data->ref_count < 1) - dev_data->ref_count++; - else - retval = -EACCES; - - mutex_unlock(&(dev_data->file_mutex)); - - return retval; -} - -static int rmidev_release(struct inode *inp, struct file *filp) -{ - struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data; - struct rmidev_data *dev_data = - container_of(inp->i_cdev, struct rmidev_data, main_dev); - - if (!dev_data) - return -EACCES; - - mutex_lock(&(dev_data->file_mutex)); - - dev_data->ref_count--; - if (dev_data->ref_count < 0) - dev_data->ref_count = 0; - - rmi4_data->irq_enable(rmi4_data, true, false); - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Attention interrupt enabled\n", - __func__); - - mutex_unlock(&(dev_data->file_mutex)); - - rmi4_data->reset_device(rmi4_data, false); - - rmi4_data->stay_awake = false; - - return 0; -} - -static const struct file_operations rmidev_fops = { - .owner = THIS_MODULE, - .llseek = rmidev_llseek, - .read = rmidev_read, - .write = rmidev_write, - .open = rmidev_open, - .release = rmidev_release, -}; - -static void rmidev_device_cleanup(struct rmidev_data *dev_data) -{ - dev_t devno; - struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data; - - if (dev_data) { - devno = dev_data->main_dev.dev; - - if (dev_data->device_class) - device_destroy(dev_data->device_class, devno); - - cdev_del(&dev_data->main_dev); - - unregister_chrdev_region(devno, 1); - - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: rmidev device removed\n", - __func__); - } - - return; -} - -static char *rmi_char_devnode(struct device *dev, umode_t *mode) -{ - if (!mode) - return NULL; - - *mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); - - return kasprintf(GFP_KERNEL, "rmi/%s", dev_name(dev)); -} - -static int rmidev_create_device_class(void) -{ - if (rmidev_device_class != NULL) - return 0; - - rmidev_device_class = class_create(THIS_MODULE, DEVICE_CLASS_NAME); - - if (IS_ERR(rmidev_device_class)) { - pr_err("%s: Failed to create /dev/%s\n", - __func__, CHAR_DEVICE_NAME); - return -ENODEV; - } - - rmidev_device_class->devnode = rmi_char_devnode; - - return 0; -} - -static void rmidev_attn(struct synaptics_rmi4_data *rmi4_data, - unsigned char intr_mask) -{ - if (!rmidev) - return; - - if (rmidev->pid && (rmidev->intr_mask & intr_mask)) - send_sig_info(SIGIO, &rmidev->interrupt_signal, rmidev->task); - - return; -} - -static int rmidev_init_device(struct synaptics_rmi4_data *rmi4_data) -{ - int retval; - dev_t dev_no; - unsigned char attr_count; - struct rmidev_data *dev_data; - struct device *device_ptr; - const struct synaptics_dsx_board_data *bdata = - rmi4_data->hw_if->board_data; - - if (rmidev) { - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Handle already exists\n", - __func__); - return 0; - } - - rmidev = kzalloc(sizeof(*rmidev), GFP_KERNEL); - if (!rmidev) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for rmidev\n", - __func__); - retval = -ENOMEM; - goto err_rmidev; - } - - rmidev->rmi4_data = rmi4_data; - - memset(&rmidev->interrupt_signal, 0, sizeof(rmidev->interrupt_signal)); - rmidev->interrupt_signal.si_signo = SIGIO; - rmidev->interrupt_signal.si_code = SI_USER; - - memset(&rmidev->terminate_signal, 0, sizeof(rmidev->terminate_signal)); - rmidev->terminate_signal.si_signo = SIGTERM; - rmidev->terminate_signal.si_code = SI_USER; - - retval = rmidev_create_device_class(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create device class\n", - __func__); - goto err_device_class; - } - - if (rmidev_major_num) { - dev_no = MKDEV(rmidev_major_num, DEV_NUMBER); - retval = register_chrdev_region(dev_no, 1, CHAR_DEVICE_NAME); - } else { - retval = alloc_chrdev_region(&dev_no, 0, 1, CHAR_DEVICE_NAME); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to allocate char device region\n", - __func__); - goto err_device_region; - } - - rmidev_major_num = MAJOR(dev_no); - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Major number of rmidev = %d\n", - __func__, rmidev_major_num); - } - - dev_data = kzalloc(sizeof(*dev_data), GFP_KERNEL); - if (!dev_data) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for dev_data\n", - __func__); - retval = -ENOMEM; - goto err_dev_data; - } - - mutex_init(&dev_data->file_mutex); - dev_data->rmi_dev = rmidev; - rmidev->data = dev_data; - - cdev_init(&dev_data->main_dev, &rmidev_fops); - - retval = cdev_add(&dev_data->main_dev, dev_no, 1); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to add rmi char device\n", - __func__); - goto err_char_device; - } - - dev_set_name(&rmidev->dev, "rmidev%d", MINOR(dev_no)); - dev_data->device_class = rmidev_device_class; - - device_ptr = device_create(dev_data->device_class, NULL, dev_no, - NULL, CHAR_DEVICE_NAME"%d", MINOR(dev_no)); - if (IS_ERR(device_ptr)) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create rmi char device\n", - __func__); - retval = -ENODEV; - goto err_char_device; - } - - retval = gpio_export(bdata->irq_gpio, false); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to export attention gpio\n", - __func__); - } else { - retval = gpio_export_link(&(rmi4_data->input_dev->dev), - "attn", bdata->irq_gpio); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s Failed to create gpio symlink\n", - __func__); - } else { - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Exported attention gpio %d\n", - __func__, bdata->irq_gpio); - } - } - - rmidev->sysfs_dir = kobject_create_and_add(SYSFS_FOLDER_NAME, - &rmi4_data->input_dev->dev.kobj); - if (!rmidev->sysfs_dir) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create sysfs directory\n", - __func__); - retval = -ENODEV; - goto err_sysfs_dir; - } - - retval = sysfs_create_bin_file(rmidev->sysfs_dir, - &attr_data); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create sysfs bin file\n", - __func__); - goto err_sysfs_bin; - } - - for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { - retval = sysfs_create_file(rmidev->sysfs_dir, - &attrs[attr_count].attr); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create sysfs attributes\n", - __func__); - retval = -ENODEV; - goto err_sysfs_attrs; - } - } - - return 0; - -err_sysfs_attrs: - for (attr_count--; attr_count >= 0; attr_count--) - sysfs_remove_file(rmidev->sysfs_dir, &attrs[attr_count].attr); - - sysfs_remove_bin_file(rmidev->sysfs_dir, &attr_data); - -err_sysfs_bin: - kobject_put(rmidev->sysfs_dir); - -err_sysfs_dir: -err_char_device: - rmidev_device_cleanup(dev_data); - kfree(dev_data); - -err_dev_data: - unregister_chrdev_region(dev_no, 1); - -err_device_region: - if (rmidev_device_class != NULL) { - class_destroy(rmidev_device_class); - rmidev_device_class = NULL; - } - -err_device_class: - kfree(rmidev); - rmidev = NULL; - -err_rmidev: - return retval; -} - -static void rmidev_remove_device(struct synaptics_rmi4_data *rmi4_data) -{ - unsigned char attr_count; - struct rmidev_data *dev_data; - const struct synaptics_dsx_board_data *bdata = - rmi4_data->hw_if->board_data; - - if (!rmidev) - goto exit; - - for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) - sysfs_remove_file(rmidev->sysfs_dir, &attrs[attr_count].attr); - - sysfs_remove_bin_file(rmidev->sysfs_dir, &attr_data); - - kobject_put(rmidev->sysfs_dir); - - gpio_unexport(bdata->irq_gpio); - - dev_data = rmidev->data; - if (dev_data) { - rmidev_device_cleanup(dev_data); - kfree(dev_data); - } - - unregister_chrdev_region(rmidev->dev_no, 1); - - if (rmidev_device_class != NULL) { - class_destroy(rmidev_device_class); - rmidev_device_class = NULL; - } - - kfree(rmidev->tmpbuf); - - kfree(rmidev); - rmidev = NULL; - -exit: - complete(&rmidev_remove_complete_v26); - - return; -} - -static struct synaptics_rmi4_exp_fn rmidev_module = { - .fn_type = RMI_DEV, - .init = rmidev_init_device, - .remove = rmidev_remove_device, - .reset = NULL, - .reinit = NULL, - .early_suspend = NULL, - .suspend = NULL, - .resume = NULL, - .late_resume = NULL, - .attn = rmidev_attn, -}; - -static int __init rmidev_module_init(void) -{ - synaptics_rmi4_new_function(&rmidev_module, true); - - return 0; -} - -static void __exit rmidev_module_exit(void) -{ - synaptics_rmi4_new_function(&rmidev_module, false); - - wait_for_completion(&rmidev_remove_complete_v26); - - return; -} - -module_init(rmidev_module_init); -module_exit(rmidev_module_exit); - -MODULE_AUTHOR("Synaptics, Inc."); -MODULE_DESCRIPTION("Synaptics DSX RMI Dev Module"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_rmi_hid_i2c.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_rmi_hid_i2c.c deleted file mode 100644 index 7e02487ece5a..000000000000 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_rmi_hid_i2c.c +++ /dev/null @@ -1,1006 +0,0 @@ -/* - * Synaptics DSX touchscreen driver - * - * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved. - * - * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com> - * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com> - * - * 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. - * - * 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. - * - * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS - * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, - * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS. - * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION - * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED - * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES - * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' - * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. - * DOLLARS. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/i2c.h> -#include <linux/delay.h> -#include <linux/input.h> -#include <linux/gpio.h> -#include <linux/types.h> -#include <linux/of_gpio.h> -#include <linux/platform_device.h> -#include <linux/input/synaptics_dsx_v2_6.h> -#include "synaptics_dsx_core.h" - -#define SYN_I2C_RETRY_TIMES 10 - -#define REPORT_ID_GET_BLOB 0x07 -#define REPORT_ID_WRITE 0x09 -#define REPORT_ID_READ_ADDRESS 0x0a -#define REPORT_ID_READ_DATA 0x0b -#define REPORT_ID_SET_RMI_MODE 0x0f - -#define PREFIX_USAGE_PAGE_1BYTE 0x05 -#define PREFIX_USAGE_PAGE_2BYTES 0x06 -#define PREFIX_USAGE 0x09 -#define PREFIX_REPORT_ID 0x85 -#define PREFIX_REPORT_COUNT_1BYTE 0x95 -#define PREFIX_REPORT_COUNT_2BYTES 0x96 - -#define USAGE_GET_BLOB 0xc5 -#define USAGE_WRITE 0x02 -#define USAGE_READ_ADDRESS 0x03 -#define USAGE_READ_DATA 0x04 -#define USAGE_SET_MODE 0x06 - -#define FEATURE_REPORT_TYPE 0x03 - -#define VENDOR_DEFINED_PAGE 0xff00 - -#define BLOB_REPORT_SIZE 256 - -#define RESET_COMMAND 0x01 -#define GET_REPORT_COMMAND 0x02 -#define SET_REPORT_COMMAND 0x03 -#define SET_POWER_COMMAND 0x08 - -#define FINGER_MODE 0x00 -#define RMI_MODE 0x02 - -struct hid_report_info { - unsigned char get_blob_id; - unsigned char write_id; - unsigned char read_addr_id; - unsigned char read_data_id; - unsigned char set_mode_id; - unsigned int blob_size; -}; - -static struct hid_report_info hid_report; - -struct hid_device_descriptor { - unsigned short device_descriptor_length; - unsigned short format_version; - unsigned short report_descriptor_length; - unsigned short report_descriptor_index; - unsigned short input_register_index; - unsigned short input_report_max_length; - unsigned short output_register_index; - unsigned short output_report_max_length; - unsigned short command_register_index; - unsigned short data_register_index; - unsigned short vendor_id; - unsigned short product_id; - unsigned short version_id; - unsigned int reserved; -}; - -static struct hid_device_descriptor hid_dd; - -struct i2c_rw_buffer { - unsigned char *read; - unsigned char *write; - unsigned short read_size; - unsigned short write_size; -}; - -static struct i2c_rw_buffer buffer; - -#ifdef CONFIG_OF -static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata) -{ - int retval; - u32 value; - const char *name; - struct property *prop; - struct device_node *np = dev->of_node; - - bdata->irq_gpio = of_get_named_gpio_flags(np, - "synaptics,irq-gpio", 0, - (enum of_gpio_flags *)&bdata->irq_flags); - - retval = of_property_read_u32(np, "synaptics,irq-on-state", - &value); - if (retval < 0) - bdata->irq_on_state = 0; - else - bdata->irq_on_state = value; - - retval = of_property_read_string(np, "synaptics,pwr-reg-name", &name); - if (retval < 0) - bdata->pwr_reg_name = NULL; - else - bdata->pwr_reg_name = name; - - retval = of_property_read_string(np, "synaptics,bus-reg-name", &name); - if (retval < 0) - bdata->bus_reg_name = NULL; - else - bdata->bus_reg_name = name; - - prop = of_find_property(np, "synaptics,power-gpio", NULL); - if (prop && prop->length) { - bdata->power_gpio = of_get_named_gpio_flags(np, - "synaptics,power-gpio", 0, NULL); - retval = of_property_read_u32(np, "synaptics,power-on-state", - &value); - if (retval < 0) { - dev_err(dev, "%s: Unable to read synaptics,power-on-state property\n", - __func__); - return retval; - } else { - bdata->power_on_state = value; - } - } else { - bdata->power_gpio = -1; - } - - prop = of_find_property(np, "synaptics,power-delay-ms", NULL); - if (prop && prop->length) { - retval = of_property_read_u32(np, "synaptics,power-delay-ms", - &value); - if (retval < 0) { - dev_err(dev, "%s: Unable to read synaptics,power-delay-ms property\n", - __func__); - return retval; - } else { - bdata->power_delay_ms = value; - } - } else { - bdata->power_delay_ms = 0; - } - - prop = of_find_property(np, "synaptics,reset-gpio", NULL); - if (prop && prop->length) { - bdata->reset_gpio = of_get_named_gpio_flags(np, - "synaptics,reset-gpio", 0, NULL); - retval = of_property_read_u32(np, "synaptics,reset-on-state", - &value); - if (retval < 0) { - dev_err(dev, "%s: Unable to read synaptics,reset-on-state property\n", - __func__); - return retval; - } else { - bdata->reset_on_state = value; - } - retval = of_property_read_u32(np, "synaptics,reset-active-ms", - &value); - if (retval < 0) { - dev_err(dev, "%s: Unable to read synaptics,reset-active-ms property\n", - __func__); - return retval; - } else { - bdata->reset_active_ms = value; - } - } else { - bdata->reset_gpio = -1; - } - - prop = of_find_property(np, "synaptics,reset-delay-ms", NULL); - if (prop && prop->length) { - retval = of_property_read_u32(np, "synaptics,reset-delay-ms", - &value); - if (retval < 0) { - dev_err(dev, "%s: Unable to read synaptics,reset-delay-ms property\n", - __func__); - return retval; - } else { - bdata->reset_delay_ms = value; - } - } else { - bdata->reset_delay_ms = 0; - } - - prop = of_find_property(np, "synaptics,dev-dscrptr-addr", NULL); - if (prop && prop->length) { - retval = of_property_read_u32(np, "synaptics,dev-dscrptr-addr", - &value); - if (retval < 0) { - dev_err(dev, "%s: Unable to read synaptics,dev-dscrptr-addr property\n", - __func__); - return retval; - } else { - bdata->device_descriptor_addr = (unsigned short)value; - } - } else { - bdata->device_descriptor_addr = 0; - } - - prop = of_find_property(np, "synaptics,max-y-for-2d", NULL); - if (prop && prop->length) { - retval = of_property_read_u32(np, "synaptics,max-y-for-2d", - &value); - if (retval < 0) { - dev_err(dev, "%s: Unable to read synaptics,max-y-for-2d property\n", - __func__); - return retval; - } else { - bdata->max_y_for_2d = value; - } - } else { - bdata->max_y_for_2d = -1; - } - - prop = of_find_property(np, "synaptics,swap-axes", NULL); - bdata->swap_axes = prop > 0 ? true : false; - - prop = of_find_property(np, "synaptics,x-flip", NULL); - bdata->x_flip = prop > 0 ? true : false; - - prop = of_find_property(np, "synaptics,y-flip", NULL); - bdata->y_flip = prop > 0 ? true : false; - - prop = of_find_property(np, "synaptics,ub-i2c-addr", NULL); - if (prop && prop->length) { - retval = of_property_read_u32(np, "synaptics,ub-i2c-addr", - &value); - if (retval < 0) { - dev_err(dev, "%s: Unable to read synaptics,ub-i2c-addr property\n", - __func__); - return retval; - } else { - bdata->ub_i2c_addr = (unsigned short)value; - } - } else { - bdata->ub_i2c_addr = -1; - } - - prop = of_find_property(np, "synaptics,cap-button-codes", NULL); - if (prop && prop->length) { - bdata->cap_button_map->map = devm_kzalloc(dev, - prop->length, - GFP_KERNEL); - if (!bdata->cap_button_map->map) - return -ENOMEM; - bdata->cap_button_map->nbuttons = prop->length / sizeof(u32); - retval = of_property_read_u32_array(np, - "synaptics,cap-button-codes", - bdata->cap_button_map->map, - bdata->cap_button_map->nbuttons); - if (retval < 0) { - bdata->cap_button_map->nbuttons = 0; - bdata->cap_button_map->map = NULL; - } - } else { - bdata->cap_button_map->nbuttons = 0; - bdata->cap_button_map->map = NULL; - } - - prop = of_find_property(np, "synaptics,vir-button-codes", NULL); - if (prop && prop->length) { - bdata->vir_button_map->map = devm_kzalloc(dev, - prop->length, - GFP_KERNEL); - if (!bdata->vir_button_map->map) - return -ENOMEM; - bdata->vir_button_map->nbuttons = prop->length / sizeof(u32); - bdata->vir_button_map->nbuttons /= 5; - retval = of_property_read_u32_array(np, - "synaptics,vir-button-codes", - bdata->vir_button_map->map, - bdata->vir_button_map->nbuttons * 5); - if (retval < 0) { - bdata->vir_button_map->nbuttons = 0; - bdata->vir_button_map->map = NULL; - } - } else { - bdata->vir_button_map->nbuttons = 0; - bdata->vir_button_map->map = NULL; - } - - return 0; -} -#endif - -static int do_i2c_transfer(struct i2c_client *client, struct i2c_msg *msg) -{ - unsigned char retry; - - for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) { - if (i2c_transfer(client->adapter, msg, 1) == 1) - break; - dev_err(&client->dev, - "%s: I2C retry %d\n", - __func__, retry + 1); - msleep(20); - } - - if (retry == SYN_I2C_RETRY_TIMES) { - dev_err(&client->dev, - "%s: I2C transfer over retry limit\n", - __func__); - return -EIO; - } - - return 0; -} - -static int check_buffer(unsigned char **buffer, unsigned short *buffer_size, - unsigned short length) -{ - if (*buffer_size < length) { - if (*buffer_size) - kfree(*buffer); - *buffer = kzalloc(length, GFP_KERNEL); - if (!(*buffer)) - return -ENOMEM; - *buffer_size = length; - } - - return 0; -} - -static int generic_read(struct i2c_client *client, unsigned short length) -{ - int retval; - struct i2c_msg msg[] = { - { - .addr = client->addr, - .flags = I2C_M_RD, - .len = length, - } - }; - - check_buffer(&buffer.read, &buffer.read_size, length); - msg[0].buf = buffer.read; - - retval = do_i2c_transfer(client, msg); - - return retval; -} - -static int generic_write(struct i2c_client *client, unsigned short length) -{ - int retval; - struct i2c_msg msg[] = { - { - .addr = client->addr, - .flags = 0, - .len = length, - .buf = buffer.write, - } - }; - - retval = do_i2c_transfer(client, msg); - - return retval; -} - -static void traverse_report_descriptor(unsigned int *index) -{ - unsigned char size; - unsigned char *buf = buffer.read; - - size = buf[*index] & MASK_2BIT; - switch (size) { - case 0: /* 0 bytes */ - *index += 1; - break; - case 1: /* 1 byte */ - *index += 2; - break; - case 2: /* 2 bytes */ - *index += 3; - break; - case 3: /* 4 bytes */ - *index += 5; - break; - default: - break; - } - - return; -} - -static void find_blob_size(unsigned int index) -{ - unsigned int ii = index; - unsigned char *buf = buffer.read; - - while (ii < hid_dd.report_descriptor_length) { - if (buf[ii] == PREFIX_REPORT_COUNT_1BYTE) { - hid_report.blob_size = buf[ii + 1]; - return; - } else if (buf[ii] == PREFIX_REPORT_COUNT_2BYTES) { - hid_report.blob_size = buf[ii + 1] | (buf[ii + 2] << 8); - return; - } - traverse_report_descriptor(&ii); - } - - return; -} - -static void find_reports(unsigned int index) -{ - unsigned int ii = index; - unsigned char *buf = buffer.read; - static unsigned int report_id_index; - static unsigned char report_id; - static unsigned short usage_page; - - if (buf[ii] == PREFIX_REPORT_ID) { - report_id = buf[ii + 1]; - report_id_index = ii; - return; - } - - if (buf[ii] == PREFIX_USAGE_PAGE_1BYTE) { - usage_page = buf[ii + 1]; - return; - } else if (buf[ii] == PREFIX_USAGE_PAGE_2BYTES) { - usage_page = buf[ii + 1] | (buf[ii + 2] << 8); - return; - } - - if ((usage_page == VENDOR_DEFINED_PAGE) && (buf[ii] == PREFIX_USAGE)) { - switch (buf[ii + 1]) { - case USAGE_GET_BLOB: - hid_report.get_blob_id = report_id; - find_blob_size(report_id_index); - break; - case USAGE_WRITE: - hid_report.write_id = report_id; - break; - case USAGE_READ_ADDRESS: - hid_report.read_addr_id = report_id; - break; - case USAGE_READ_DATA: - hid_report.read_data_id = report_id; - break; - case USAGE_SET_MODE: - hid_report.set_mode_id = report_id; - break; - default: - break; - } - } - - return; -} - -static int parse_report_descriptor(struct synaptics_rmi4_data *rmi4_data) -{ - int retval; - unsigned int ii = 0; - unsigned char *buf; - struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent); - - buffer.write[0] = hid_dd.report_descriptor_index & MASK_8BIT; - buffer.write[1] = hid_dd.report_descriptor_index >> 8; - retval = generic_write(i2c, 2); - if (retval < 0) - return retval; - retval = generic_read(i2c, hid_dd.report_descriptor_length); - if (retval < 0) - return retval; - - buf = buffer.read; - - hid_report.get_blob_id = REPORT_ID_GET_BLOB; - hid_report.write_id = REPORT_ID_WRITE; - hid_report.read_addr_id = REPORT_ID_READ_ADDRESS; - hid_report.read_data_id = REPORT_ID_READ_DATA; - hid_report.set_mode_id = REPORT_ID_SET_RMI_MODE; - hid_report.blob_size = BLOB_REPORT_SIZE; - - while (ii < hid_dd.report_descriptor_length) { - find_reports(ii); - traverse_report_descriptor(&ii); - } - - return 0; -} - -static int switch_to_rmi(struct synaptics_rmi4_data *rmi4_data) -{ - int retval; - struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent); - - mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex); - - check_buffer(&buffer.write, &buffer.write_size, 11); - - /* set rmi mode */ - buffer.write[0] = hid_dd.command_register_index & MASK_8BIT; - buffer.write[1] = hid_dd.command_register_index >> 8; - buffer.write[2] = (FEATURE_REPORT_TYPE << 4) | hid_report.set_mode_id; - buffer.write[3] = SET_REPORT_COMMAND; - buffer.write[4] = hid_report.set_mode_id; - buffer.write[5] = hid_dd.data_register_index & MASK_8BIT; - buffer.write[6] = hid_dd.data_register_index >> 8; - buffer.write[7] = 0x04; - buffer.write[8] = 0x00; - buffer.write[9] = hid_report.set_mode_id; - buffer.write[10] = RMI_MODE; - - retval = generic_write(i2c, 11); - - mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex); - - return retval; -} - -static int check_report_mode(struct synaptics_rmi4_data *rmi4_data) -{ - int retval; - unsigned short report_size; - struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent); - - mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex); - - check_buffer(&buffer.write, &buffer.write_size, 7); - - buffer.write[0] = hid_dd.command_register_index & MASK_8BIT; - buffer.write[1] = hid_dd.command_register_index >> 8; - buffer.write[2] = (FEATURE_REPORT_TYPE << 4) | hid_report.set_mode_id; - buffer.write[3] = GET_REPORT_COMMAND; - buffer.write[4] = hid_report.set_mode_id; - buffer.write[5] = hid_dd.data_register_index & MASK_8BIT; - buffer.write[6] = hid_dd.data_register_index >> 8; - - retval = generic_write(i2c, 7); - if (retval < 0) - goto exit; - - retval = generic_read(i2c, 2); - if (retval < 0) - goto exit; - - report_size = (buffer.read[1] << 8) | buffer.read[0]; - - retval = generic_write(i2c, 7); - if (retval < 0) - goto exit; - - retval = generic_read(i2c, report_size); - if (retval < 0) - goto exit; - - retval = buffer.read[3]; - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Report mode = %d\n", - __func__, retval); - -exit: - mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex); - - return retval; -} - -static int hid_i2c_init(struct synaptics_rmi4_data *rmi4_data) -{ - int retval; - struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent); - const struct synaptics_dsx_board_data *bdata = - rmi4_data->hw_if->board_data; - - mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex); - - check_buffer(&buffer.write, &buffer.write_size, 6); - - /* read device descriptor */ - buffer.write[0] = bdata->device_descriptor_addr & MASK_8BIT; - buffer.write[1] = bdata->device_descriptor_addr >> 8; - retval = generic_write(i2c, 2); - if (retval < 0) - goto exit; - retval = generic_read(i2c, sizeof(hid_dd)); - if (retval < 0) - goto exit; - retval = secure_memcpy((unsigned char *)&hid_dd, - sizeof(struct hid_device_descriptor), - buffer.read, - buffer.read_size, - sizeof(hid_dd)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to copy device descriptor data\n", - __func__); - goto exit; - } - - retval = parse_report_descriptor(rmi4_data); - if (retval < 0) - goto exit; - - /* set power */ - buffer.write[0] = hid_dd.command_register_index & MASK_8BIT; - buffer.write[1] = hid_dd.command_register_index >> 8; - buffer.write[2] = 0x00; - buffer.write[3] = SET_POWER_COMMAND; - retval = generic_write(i2c, 4); - if (retval < 0) - goto exit; - - /* reset */ - buffer.write[0] = hid_dd.command_register_index & MASK_8BIT; - buffer.write[1] = hid_dd.command_register_index >> 8; - buffer.write[2] = 0x00; - buffer.write[3] = RESET_COMMAND; - retval = generic_write(i2c, 4); - if (retval < 0) - goto exit; - - while (gpio_get_value(bdata->irq_gpio)) - msleep(20); - - retval = generic_read(i2c, hid_dd.input_report_max_length); - if (retval < 0) - goto exit; - - /* get blob */ - buffer.write[0] = hid_dd.command_register_index & MASK_8BIT; - buffer.write[1] = hid_dd.command_register_index >> 8; - buffer.write[2] = (FEATURE_REPORT_TYPE << 4) | hid_report.get_blob_id; - buffer.write[3] = 0x02; - buffer.write[4] = hid_dd.data_register_index & MASK_8BIT; - buffer.write[5] = hid_dd.data_register_index >> 8; - - retval = generic_write(i2c, 6); - if (retval < 0) - goto exit; - - msleep(20); - - retval = generic_read(i2c, hid_report.blob_size + 3); - if (retval < 0) - goto exit; - -exit: - mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex); - - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to initialize HID/I2C interface\n", - __func__); - return retval; - } - - retval = switch_to_rmi(rmi4_data); - - return retval; -} - -static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data, - unsigned short addr, unsigned char *data, unsigned short length) -{ - int retval; - unsigned char retry; - unsigned char recover = 1; - unsigned short report_length; - struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent); - struct i2c_msg msg[] = { - { - .addr = i2c->addr, - .flags = 0, - .len = hid_dd.output_report_max_length + 2, - }, - { - .addr = i2c->addr, - .flags = I2C_M_RD, - .len = length + 4, - }, - }; - -recover: - mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex); - - check_buffer(&buffer.write, &buffer.write_size, - hid_dd.output_report_max_length + 2); - msg[0].buf = buffer.write; - buffer.write[0] = hid_dd.output_register_index & MASK_8BIT; - buffer.write[1] = hid_dd.output_register_index >> 8; - buffer.write[2] = hid_dd.output_report_max_length & MASK_8BIT; - buffer.write[3] = hid_dd.output_report_max_length >> 8; - buffer.write[4] = hid_report.read_addr_id; - buffer.write[5] = 0x00; - buffer.write[6] = addr & MASK_8BIT; - buffer.write[7] = addr >> 8; - buffer.write[8] = length & MASK_8BIT; - buffer.write[9] = length >> 8; - - check_buffer(&buffer.read, &buffer.read_size, length + 4); - msg[1].buf = buffer.read; - - retval = do_i2c_transfer(i2c, &msg[0]); - if (retval != 0) - goto exit; - - retry = 0; - do { - retval = do_i2c_transfer(i2c, &msg[1]); - if (retval == 0) - retval = length; - else - goto exit; - - report_length = (buffer.read[1] << 8) | buffer.read[0]; - if (report_length == hid_dd.input_report_max_length) { - retval = secure_memcpy(&data[0], length, - &buffer.read[4], buffer.read_size - 4, - length); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to copy data\n", - __func__); - } else { - retval = length; - } - goto exit; - } - - msleep(20); - retry++; - } while (retry < SYN_I2C_RETRY_TIMES); - - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to receive read report\n", - __func__); - retval = -EIO; - -exit: - mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex); - - if ((retval != length) && (recover == 1)) { - recover = 0; - if (check_report_mode(rmi4_data) != RMI_MODE) { - retval = hid_i2c_init(rmi4_data); - if (retval == 0) - goto recover; - } - } - - return retval; -} - -static int synaptics_rmi4_i2c_write(struct synaptics_rmi4_data *rmi4_data, - unsigned short addr, unsigned char *data, unsigned short length) -{ - int retval; - unsigned char recover = 1; - unsigned char msg_length; - struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent); - struct i2c_msg msg[] = { - { - .addr = i2c->addr, - .flags = 0, - } - }; - - if ((length + 10) < (hid_dd.output_report_max_length + 2)) - msg_length = hid_dd.output_report_max_length + 2; - else - msg_length = length + 10; - -recover: - mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex); - - check_buffer(&buffer.write, &buffer.write_size, msg_length); - msg[0].len = msg_length; - msg[0].buf = buffer.write; - buffer.write[0] = hid_dd.output_register_index & MASK_8BIT; - buffer.write[1] = hid_dd.output_register_index >> 8; - buffer.write[2] = hid_dd.output_report_max_length & MASK_8BIT; - buffer.write[3] = hid_dd.output_report_max_length >> 8; - buffer.write[4] = hid_report.write_id; - buffer.write[5] = 0x00; - buffer.write[6] = addr & MASK_8BIT; - buffer.write[7] = addr >> 8; - buffer.write[8] = length & MASK_8BIT; - buffer.write[9] = length >> 8; - retval = secure_memcpy(&buffer.write[10], buffer.write_size - 10, - &data[0], length, length); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to copy data\n", - __func__); - } else { - retval = do_i2c_transfer(i2c, msg); - if (retval == 0) - retval = length; - } - - mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex); - - if ((retval != length) && (recover == 1)) { - recover = 0; - if (check_report_mode(rmi4_data) != RMI_MODE) { - retval = hid_i2c_init(rmi4_data); - if (retval == 0) - goto recover; - } - } - - return retval; -} - -static struct synaptics_dsx_bus_access bus_access = { - .type = BUS_I2C, - .read = synaptics_rmi4_i2c_read, - .write = synaptics_rmi4_i2c_write, -}; - -static struct synaptics_dsx_hw_interface hw_if; - -static struct platform_device *synaptics_dsx_i2c_device; - -static void synaptics_rmi4_i2c_dev_release(struct device *dev) -{ - kfree(synaptics_dsx_i2c_device); - - return; -} - -static int synaptics_rmi4_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *dev_id) -{ - int retval; - - if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_BYTE_DATA)) { - dev_err(&client->dev, - "%s: SMBus byte data commands not supported by host\n", - __func__); - return -EIO; - } - - synaptics_dsx_i2c_device = kzalloc( - sizeof(struct platform_device), - GFP_KERNEL); - if (!synaptics_dsx_i2c_device) { - dev_err(&client->dev, - "%s: Failed to allocate memory for synaptics_dsx_i2c_device\n", - __func__); - return -ENOMEM; - } - -#ifdef CONFIG_OF - if (client->dev.of_node) { - hw_if.board_data = devm_kzalloc(&client->dev, - sizeof(struct synaptics_dsx_board_data), - GFP_KERNEL); - if (!hw_if.board_data) { - dev_err(&client->dev, - "%s: Failed to allocate memory for board data\n", - __func__); - return -ENOMEM; - } - hw_if.board_data->cap_button_map = devm_kzalloc(&client->dev, - sizeof(struct synaptics_dsx_button_map), - GFP_KERNEL); - if (!hw_if.board_data->cap_button_map) { - dev_err(&client->dev, - "%s: Failed to allocate memory for 0D button map\n", - __func__); - return -ENOMEM; - } - hw_if.board_data->vir_button_map = devm_kzalloc(&client->dev, - sizeof(struct synaptics_dsx_button_map), - GFP_KERNEL); - if (!hw_if.board_data->vir_button_map) { - dev_err(&client->dev, - "%s: Failed to allocate memory for virtual button map\n", - __func__); - return -ENOMEM; - } - parse_dt(&client->dev, hw_if.board_data); - } -#else - hw_if.board_data = client->dev.platform_data; -#endif - - hw_if.bus_access = &bus_access; - hw_if.bl_hw_init = switch_to_rmi; - hw_if.ui_hw_init = hid_i2c_init; - - synaptics_dsx_i2c_device->name = PLATFORM_DRIVER_NAME; - synaptics_dsx_i2c_device->id = 0; - synaptics_dsx_i2c_device->num_resources = 0; - synaptics_dsx_i2c_device->dev.parent = &client->dev; - synaptics_dsx_i2c_device->dev.platform_data = &hw_if; - synaptics_dsx_i2c_device->dev.release = synaptics_rmi4_i2c_dev_release; - - retval = platform_device_register(synaptics_dsx_i2c_device); - if (retval) { - dev_err(&client->dev, - "%s: Failed to register platform device\n", - __func__); - return -ENODEV; - } - - return 0; -} - -static int synaptics_rmi4_i2c_remove(struct i2c_client *client) -{ - if (buffer.read_size) - kfree(buffer.read); - - if (buffer.write_size) - kfree(buffer.write); - - platform_device_unregister(synaptics_dsx_i2c_device); - - return 0; -} - -static const struct i2c_device_id synaptics_rmi4_id_table[] = { - {I2C_DRIVER_NAME, 0}, - {}, -}; -MODULE_DEVICE_TABLE(i2c, synaptics_rmi4_id_table); - -#ifdef CONFIG_OF -static struct of_device_id synaptics_rmi4_of_match_table[] = { - { - .compatible = "synaptics,dsx-rmi-hid-i2c", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, synaptics_rmi4_of_match_table); -#else -#define synaptics_rmi4_of_match_table NULL -#endif - -static struct i2c_driver synaptics_rmi4_i2c_driver = { - .driver = { - .name = I2C_DRIVER_NAME, - .owner = THIS_MODULE, - .of_match_table = synaptics_rmi4_of_match_table, - }, - .probe = synaptics_rmi4_i2c_probe, - .remove = synaptics_rmi4_i2c_remove, - .id_table = synaptics_rmi4_id_table, -}; - -int synaptics_rmi4_bus_init_v26(void) -{ - return i2c_add_driver(&synaptics_rmi4_i2c_driver); -} -EXPORT_SYMBOL(synaptics_rmi4_bus_init_v26); - -void synaptics_rmi4_bus_exit_v26(void) -{ - i2c_del_driver(&synaptics_rmi4_i2c_driver); - - return; -} -EXPORT_SYMBOL(synaptics_rmi4_bus_exit_v26); - -MODULE_AUTHOR("Synaptics, Inc."); -MODULE_DESCRIPTION("Synaptics DSX I2C Bus Support Module"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_spi.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_spi.c deleted file mode 100644 index 382a3dd029d7..000000000000 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_spi.c +++ /dev/null @@ -1,634 +0,0 @@ -/* - * Synaptics DSX touchscreen driver - * - * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved. - * - * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com> - * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com> - * - * 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. - * - * 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. - * - * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS - * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, - * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS. - * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION - * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED - * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES - * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' - * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. - * DOLLARS. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/spi/spi.h> -#include <linux/delay.h> -#include <linux/input.h> -#include <linux/types.h> -#include <linux/of_gpio.h> -#include <linux/platform_device.h> -#include <linux/input/synaptics_dsx_v2_6.h> -#include "synaptics_dsx_core.h" - -#define SPI_READ 0x80 -#define SPI_WRITE 0x00 - -#ifdef CONFIG_OF -static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata) -{ - int retval; - u32 value; - const char *name; - struct property *prop; - struct device_node *np = dev->of_node; - - bdata->irq_gpio = of_get_named_gpio_flags(np, - "synaptics,irq-gpio", 0, - (enum of_gpio_flags *)&bdata->irq_flags); - - retval = of_property_read_u32(np, "synaptics,irq-on-state", - &value); - if (retval < 0) - bdata->irq_on_state = 0; - else - bdata->irq_on_state = value; - - retval = of_property_read_string(np, "synaptics,pwr-reg-name", &name); - if (retval < 0) - bdata->pwr_reg_name = NULL; - else - bdata->pwr_reg_name = name; - - retval = of_property_read_string(np, "synaptics,bus-reg-name", &name); - if (retval < 0) - bdata->bus_reg_name = NULL; - else - bdata->bus_reg_name = name; - - prop = of_find_property(np, "synaptics,power-gpio", NULL); - if (prop && prop->length) { - bdata->power_gpio = of_get_named_gpio_flags(np, - "synaptics,power-gpio", 0, NULL); - retval = of_property_read_u32(np, "synaptics,power-on-state", - &value); - if (retval < 0) { - dev_err(dev, "%s: Unable to read synaptics,power-on-state property\n", - __func__); - return retval; - } else { - bdata->power_on_state = value; - } - } else { - bdata->power_gpio = -1; - } - - prop = of_find_property(np, "synaptics,power-delay-ms", NULL); - if (prop && prop->length) { - retval = of_property_read_u32(np, "synaptics,power-delay-ms", - &value); - if (retval < 0) { - dev_err(dev, "%s: Unable to read synaptics,power-delay-ms property\n", - __func__); - return retval; - } else { - bdata->power_delay_ms = value; - } - } else { - bdata->power_delay_ms = 0; - } - - prop = of_find_property(np, "synaptics,reset-gpio", NULL); - if (prop && prop->length) { - bdata->reset_gpio = of_get_named_gpio_flags(np, - "synaptics,reset-gpio", 0, NULL); - retval = of_property_read_u32(np, "synaptics,reset-on-state", - &value); - if (retval < 0) { - dev_err(dev, "%s: Unable to read synaptics,reset-on-state property\n", - __func__); - return retval; - } else { - bdata->reset_on_state = value; - } - retval = of_property_read_u32(np, "synaptics,reset-active-ms", - &value); - if (retval < 0) { - dev_err(dev, "%s: Unable to read synaptics,reset-active-ms property\n", - __func__); - return retval; - } else { - bdata->reset_active_ms = value; - } - } else { - bdata->reset_gpio = -1; - } - - prop = of_find_property(np, "synaptics,reset-delay-ms", NULL); - if (prop && prop->length) { - retval = of_property_read_u32(np, "synaptics,reset-delay-ms", - &value); - if (retval < 0) { - dev_err(dev, "%s: Unable to read synaptics,reset-delay-ms property\n", - __func__); - return retval; - } else { - bdata->reset_delay_ms = value; - } - } else { - bdata->reset_delay_ms = 0; - } - - prop = of_find_property(np, "synaptics,byte-delay-us", NULL); - if (prop && prop->length) { - retval = of_property_read_u32(np, "synaptics,byte-delay-us", - &value); - if (retval < 0) { - dev_err(dev, "%s: Unable to read synaptics,byte-delay-us property\n", - __func__); - return retval; - } else { - bdata->byte_delay_us = value; - } - } else { - bdata->byte_delay_us = 0; - } - - prop = of_find_property(np, "synaptics,block-delay-us", NULL); - if (prop && prop->length) { - retval = of_property_read_u32(np, "synaptics,block-delay-us", - &value); - if (retval < 0) { - dev_err(dev, "%s: Unable to read synaptics,block-delay-us property\n", - __func__); - return retval; - } else { - bdata->block_delay_us = value; - } - } else { - bdata->block_delay_us = 0; - } - - prop = of_find_property(np, "synaptics,max-y-for-2d", NULL); - if (prop && prop->length) { - retval = of_property_read_u32(np, "synaptics,max-y-for-2d", - &value); - if (retval < 0) { - dev_err(dev, "%s: Unable to read synaptics,max-y-for-2d property\n", - __func__); - return retval; - } else { - bdata->max_y_for_2d = value; - } - } else { - bdata->max_y_for_2d = -1; - } - - prop = of_find_property(np, "synaptics,swap-axes", NULL); - bdata->swap_axes = prop > 0 ? true : false; - - prop = of_find_property(np, "synaptics,x-flip", NULL); - bdata->x_flip = prop > 0 ? true : false; - - prop = of_find_property(np, "synaptics,y-flip", NULL); - bdata->y_flip = prop > 0 ? true : false; - - prop = of_find_property(np, "synaptics,ub-i2c-addr", NULL); - if (prop && prop->length) { - retval = of_property_read_u32(np, "synaptics,ub-i2c-addr", - &value); - if (retval < 0) { - dev_err(dev, "%s: Unable to read synaptics,ub-i2c-addr property\n", - __func__); - return retval; - } else { - bdata->ub_i2c_addr = (unsigned short)value; - } - } else { - bdata->ub_i2c_addr = -1; - } - - prop = of_find_property(np, "synaptics,cap-button-codes", NULL); - if (prop && prop->length) { - bdata->cap_button_map->map = devm_kzalloc(dev, - prop->length, - GFP_KERNEL); - if (!bdata->cap_button_map->map) - return -ENOMEM; - bdata->cap_button_map->nbuttons = prop->length / sizeof(u32); - retval = of_property_read_u32_array(np, - "synaptics,cap-button-codes", - bdata->cap_button_map->map, - bdata->cap_button_map->nbuttons); - if (retval < 0) { - bdata->cap_button_map->nbuttons = 0; - bdata->cap_button_map->map = NULL; - } - } else { - bdata->cap_button_map->nbuttons = 0; - bdata->cap_button_map->map = NULL; - } - - prop = of_find_property(np, "synaptics,vir-button-codes", NULL); - if (prop && prop->length) { - bdata->vir_button_map->map = devm_kzalloc(dev, - prop->length, - GFP_KERNEL); - if (!bdata->vir_button_map->map) - return -ENOMEM; - bdata->vir_button_map->nbuttons = prop->length / sizeof(u32); - bdata->vir_button_map->nbuttons /= 5; - retval = of_property_read_u32_array(np, - "synaptics,vir-button-codes", - bdata->vir_button_map->map, - bdata->vir_button_map->nbuttons * 5); - if (retval < 0) { - bdata->vir_button_map->nbuttons = 0; - bdata->vir_button_map->map = NULL; - } - } else { - bdata->vir_button_map->nbuttons = 0; - bdata->vir_button_map->map = NULL; - } - - return 0; -} -#endif - -static int synaptics_rmi4_spi_set_page(struct synaptics_rmi4_data *rmi4_data, - unsigned short addr) -{ - int retval; - unsigned int index; - unsigned int xfer_count = PAGE_SELECT_LEN + 1; - unsigned char txbuf[xfer_count]; - unsigned char page; - struct spi_message msg; - struct spi_transfer xfers[xfer_count]; - struct spi_device *spi = to_spi_device(rmi4_data->pdev->dev.parent); - const struct synaptics_dsx_board_data *bdata = - rmi4_data->hw_if->board_data; - - page = ((addr >> 8) & ~MASK_7BIT); - if (page != rmi4_data->current_page) { - spi_message_init(&msg); - - txbuf[0] = SPI_WRITE; - txbuf[1] = MASK_8BIT; - txbuf[2] = page; - - for (index = 0; index < xfer_count; index++) { - memset(&xfers[index], 0, sizeof(struct spi_transfer)); - xfers[index].len = 1; - xfers[index].delay_usecs = bdata->byte_delay_us; - xfers[index].tx_buf = &txbuf[index]; - spi_message_add_tail(&xfers[index], &msg); - } - - if (bdata->block_delay_us) - xfers[index - 1].delay_usecs = bdata->block_delay_us; - - retval = spi_sync(spi, &msg); - if (retval == 0) { - rmi4_data->current_page = page; - retval = PAGE_SELECT_LEN; - } else { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to complete SPI transfer, error = %d\n", - __func__, retval); - } - } else { - retval = PAGE_SELECT_LEN; - } - - return retval; -} - -static int synaptics_rmi4_spi_read(struct synaptics_rmi4_data *rmi4_data, - unsigned short addr, unsigned char *data, unsigned short length) -{ - int retval; - unsigned int index; - unsigned int xfer_count = length + ADDRESS_WORD_LEN; - unsigned char txbuf[ADDRESS_WORD_LEN]; - unsigned char *rxbuf = NULL; - struct spi_message msg; - struct spi_transfer *xfers = NULL; - struct spi_device *spi = to_spi_device(rmi4_data->pdev->dev.parent); - const struct synaptics_dsx_board_data *bdata = - rmi4_data->hw_if->board_data; - - spi_message_init(&msg); - - xfers = kcalloc(xfer_count, sizeof(struct spi_transfer), GFP_KERNEL); - if (!xfers) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to allocate memory for xfers\n", - __func__); - retval = -ENOMEM; - goto exit; - } - - txbuf[0] = (addr >> 8) | SPI_READ; - txbuf[1] = addr & MASK_8BIT; - - rxbuf = kmalloc(length, GFP_KERNEL); - if (!rxbuf) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to allocate memory for rxbuf\n", - __func__); - retval = -ENOMEM; - goto exit; - } - - mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex); - - retval = synaptics_rmi4_spi_set_page(rmi4_data, addr); - if (retval != PAGE_SELECT_LEN) { - mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex); - retval = -EIO; - goto exit; - } - - for (index = 0; index < xfer_count; index++) { - xfers[index].len = 1; - xfers[index].delay_usecs = bdata->byte_delay_us; - if (index < ADDRESS_WORD_LEN) - xfers[index].tx_buf = &txbuf[index]; - else - xfers[index].rx_buf = &rxbuf[index - ADDRESS_WORD_LEN]; - spi_message_add_tail(&xfers[index], &msg); - } - - if (bdata->block_delay_us) - xfers[index - 1].delay_usecs = bdata->block_delay_us; - - retval = spi_sync(spi, &msg); - if (retval == 0) { - retval = secure_memcpy(data, length, rxbuf, length, length); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to copy data\n", - __func__); - } else { - retval = length; - } - } else { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to complete SPI transfer, error = %d\n", - __func__, retval); - } - - mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex); - -exit: - kfree(rxbuf); - kfree(xfers); - - return retval; -} - -static int synaptics_rmi4_spi_write(struct synaptics_rmi4_data *rmi4_data, - unsigned short addr, unsigned char *data, unsigned short length) -{ - int retval; - unsigned int index; - unsigned int xfer_count = length + ADDRESS_WORD_LEN; - unsigned char *txbuf = NULL; - struct spi_message msg; - struct spi_transfer *xfers = NULL; - struct spi_device *spi = to_spi_device(rmi4_data->pdev->dev.parent); - const struct synaptics_dsx_board_data *bdata = - rmi4_data->hw_if->board_data; - - spi_message_init(&msg); - - xfers = kcalloc(xfer_count, sizeof(struct spi_transfer), GFP_KERNEL); - if (!xfers) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to allocate memory for xfers\n", - __func__); - retval = -ENOMEM; - goto exit; - } - - txbuf = kmalloc(xfer_count, GFP_KERNEL); - if (!txbuf) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to allocate memory for txbuf\n", - __func__); - retval = -ENOMEM; - goto exit; - } - - txbuf[0] = (addr >> 8) & ~SPI_READ; - txbuf[1] = addr & MASK_8BIT; - retval = secure_memcpy(&txbuf[ADDRESS_WORD_LEN], - xfer_count - ADDRESS_WORD_LEN, data, length, length); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to copy data\n", - __func__); - goto exit; - } - - mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex); - - retval = synaptics_rmi4_spi_set_page(rmi4_data, addr); - if (retval != PAGE_SELECT_LEN) { - mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex); - retval = -EIO; - goto exit; - } - - for (index = 0; index < xfer_count; index++) { - xfers[index].len = 1; - xfers[index].delay_usecs = bdata->byte_delay_us; - xfers[index].tx_buf = &txbuf[index]; - spi_message_add_tail(&xfers[index], &msg); - } - - if (bdata->block_delay_us) - xfers[index - 1].delay_usecs = bdata->block_delay_us; - - retval = spi_sync(spi, &msg); - if (retval == 0) { - retval = length; - } else { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to complete SPI transfer, error = %d\n", - __func__, retval); - } - - mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex); - -exit: - kfree(txbuf); - kfree(xfers); - - return retval; -} - -static struct synaptics_dsx_bus_access bus_access = { - .type = BUS_SPI, - .read = synaptics_rmi4_spi_read, - .write = synaptics_rmi4_spi_write, -}; - -static struct synaptics_dsx_hw_interface hw_if; - -static struct platform_device *synaptics_dsx_spi_device; - -static void synaptics_rmi4_spi_dev_release(struct device *dev) -{ - kfree(synaptics_dsx_spi_device); - - return; -} - -static int synaptics_rmi4_spi_probe(struct spi_device *spi) -{ - int retval; - - if (spi->master->flags & SPI_MASTER_HALF_DUPLEX) { - dev_err(&spi->dev, - "%s: Full duplex not supported by host\n", - __func__); - return -EIO; - } - - synaptics_dsx_spi_device = kzalloc( - sizeof(struct platform_device), - GFP_KERNEL); - if (!synaptics_dsx_spi_device) { - dev_err(&spi->dev, - "%s: Failed to allocate memory for synaptics_dsx_spi_device\n", - __func__); - return -ENOMEM; - } - -#ifdef CONFIG_OF - if (spi->dev.of_node) { - hw_if.board_data = devm_kzalloc(&spi->dev, - sizeof(struct synaptics_dsx_board_data), - GFP_KERNEL); - if (!hw_if.board_data) { - dev_err(&spi->dev, - "%s: Failed to allocate memory for board data\n", - __func__); - return -ENOMEM; - } - hw_if.board_data->cap_button_map = devm_kzalloc(&spi->dev, - sizeof(struct synaptics_dsx_button_map), - GFP_KERNEL); - if (!hw_if.board_data->cap_button_map) { - dev_err(&spi->dev, - "%s: Failed to allocate memory for 0D button map\n", - __func__); - return -ENOMEM; - } - hw_if.board_data->vir_button_map = devm_kzalloc(&spi->dev, - sizeof(struct synaptics_dsx_button_map), - GFP_KERNEL); - if (!hw_if.board_data->vir_button_map) { - dev_err(&spi->dev, - "%s: Failed to allocate memory for virtual button map\n", - __func__); - return -ENOMEM; - } - parse_dt(&spi->dev, hw_if.board_data); - } -#else - hw_if.board_data = spi->dev.platform_data; -#endif - - hw_if.bus_access = &bus_access; - - spi->bits_per_word = 8; - spi->mode = SPI_MODE_3; - - retval = spi_setup(spi); - if (retval < 0) { - dev_err(&spi->dev, - "%s: Failed to perform SPI setup\n", - __func__); - return retval; - } - - synaptics_dsx_spi_device->name = PLATFORM_DRIVER_NAME; - synaptics_dsx_spi_device->id = 0; - synaptics_dsx_spi_device->num_resources = 0; - synaptics_dsx_spi_device->dev.parent = &spi->dev; - synaptics_dsx_spi_device->dev.platform_data = &hw_if; - synaptics_dsx_spi_device->dev.release = synaptics_rmi4_spi_dev_release; - - retval = platform_device_register(synaptics_dsx_spi_device); - if (retval) { - dev_err(&spi->dev, - "%s: Failed to register platform device\n", - __func__); - return -ENODEV; - } - - return 0; -} - -static int synaptics_rmi4_spi_remove(struct spi_device *spi) -{ - platform_device_unregister(synaptics_dsx_spi_device); - - return 0; -} - -#ifdef CONFIG_OF -static struct of_device_id synaptics_rmi4_of_match_table[] = { - { - .compatible = "synaptics,dsx-spi", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, synaptics_rmi4_of_match_table); -#else -#define synaptics_rmi4_of_match_table NULL -#endif - -static struct spi_driver synaptics_rmi4_spi_driver = { - .driver = { - .name = SPI_DRIVER_NAME, - .owner = THIS_MODULE, - .of_match_table = synaptics_rmi4_of_match_table, - }, - .probe = synaptics_rmi4_spi_probe, - .remove = synaptics_rmi4_spi_remove, -}; - - -int synaptics_rmi4_bus_init_v26(void) -{ - return spi_register_driver(&synaptics_rmi4_spi_driver); -} -EXPORT_SYMBOL(synaptics_rmi4_bus_init_v26); - -void synaptics_rmi4_bus_exit_v26(void) -{ - spi_unregister_driver(&synaptics_rmi4_spi_driver); - - return; -} -EXPORT_SYMBOL(synaptics_rmi4_bus_exit_v26); - -MODULE_AUTHOR("Synaptics, Inc."); -MODULE_DESCRIPTION("Synaptics DSX SPI Bus Support Module"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_test_reporting.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_test_reporting.c deleted file mode 100644 index d42b23e46d0a..000000000000 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_test_reporting.c +++ /dev/null @@ -1,4162 +0,0 @@ -/* - * Synaptics DSX touchscreen driver - * - * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved. - * - * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com> - * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com> - * - * 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. - * - * 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. - * - * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS - * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, - * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS. - * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION - * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED - * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES - * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' - * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. - * DOLLARS. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/input.h> -#include <linux/ctype.h> -#include <linux/hrtimer.h> -#include <linux/platform_device.h> -#include <linux/input/synaptics_dsx_v2_6.h> -#include "synaptics_dsx_core.h" - -#define SYSFS_FOLDER_NAME "f54" - -#define GET_REPORT_TIMEOUT_S 3 -#define CALIBRATION_TIMEOUT_S 10 -#define COMMAND_TIMEOUT_100MS 20 - -#define NO_SLEEP_OFF (0 << 2) -#define NO_SLEEP_ON (1 << 2) - -#define STATUS_IDLE 0 -#define STATUS_BUSY 1 -#define STATUS_ERROR 2 - -#define REPORT_INDEX_OFFSET 1 -#define REPORT_DATA_OFFSET 3 - -#define SENSOR_RX_MAPPING_OFFSET 1 -#define SENSOR_TX_MAPPING_OFFSET 2 - -#define COMMAND_GET_REPORT 1 -#define COMMAND_FORCE_CAL 2 -#define COMMAND_FORCE_UPDATE 4 - -#define CONTROL_NO_AUTO_CAL 1 - -#define CONTROL_0_SIZE 1 -#define CONTROL_1_SIZE 1 -#define CONTROL_2_SIZE 2 -#define CONTROL_3_SIZE 1 -#define CONTROL_4_6_SIZE 3 -#define CONTROL_7_SIZE 1 -#define CONTROL_8_9_SIZE 3 -#define CONTROL_10_SIZE 1 -#define CONTROL_11_SIZE 2 -#define CONTROL_12_13_SIZE 2 -#define CONTROL_14_SIZE 1 -#define CONTROL_15_SIZE 1 -#define CONTROL_16_SIZE 1 -#define CONTROL_17_SIZE 1 -#define CONTROL_18_SIZE 1 -#define CONTROL_19_SIZE 1 -#define CONTROL_20_SIZE 1 -#define CONTROL_21_SIZE 2 -#define CONTROL_22_26_SIZE 7 -#define CONTROL_27_SIZE 1 -#define CONTROL_28_SIZE 2 -#define CONTROL_29_SIZE 1 -#define CONTROL_30_SIZE 1 -#define CONTROL_31_SIZE 1 -#define CONTROL_32_35_SIZE 8 -#define CONTROL_36_SIZE 1 -#define CONTROL_37_SIZE 1 -#define CONTROL_38_SIZE 1 -#define CONTROL_39_SIZE 1 -#define CONTROL_40_SIZE 1 -#define CONTROL_41_SIZE 1 -#define CONTROL_42_SIZE 2 -#define CONTROL_43_54_SIZE 13 -#define CONTROL_55_56_SIZE 2 -#define CONTROL_57_SIZE 1 -#define CONTROL_58_SIZE 1 -#define CONTROL_59_SIZE 2 -#define CONTROL_60_62_SIZE 3 -#define CONTROL_63_SIZE 1 -#define CONTROL_64_67_SIZE 4 -#define CONTROL_68_73_SIZE 8 -#define CONTROL_74_SIZE 2 -#define CONTROL_75_SIZE 1 -#define CONTROL_76_SIZE 1 -#define CONTROL_77_78_SIZE 2 -#define CONTROL_79_83_SIZE 5 -#define CONTROL_84_85_SIZE 2 -#define CONTROL_86_SIZE 1 -#define CONTROL_87_SIZE 1 -#define CONTROL_88_SIZE 1 -#define CONTROL_89_SIZE 1 -#define CONTROL_90_SIZE 1 -#define CONTROL_91_SIZE 1 -#define CONTROL_92_SIZE 1 -#define CONTROL_93_SIZE 1 -#define CONTROL_94_SIZE 1 -#define CONTROL_95_SIZE 1 -#define CONTROL_96_SIZE 1 -#define CONTROL_97_SIZE 1 -#define CONTROL_98_SIZE 1 -#define CONTROL_99_SIZE 1 -#define CONTROL_100_SIZE 1 -#define CONTROL_101_SIZE 1 -#define CONTROL_102_SIZE 1 -#define CONTROL_103_SIZE 1 -#define CONTROL_104_SIZE 1 -#define CONTROL_105_SIZE 1 -#define CONTROL_106_SIZE 1 -#define CONTROL_107_SIZE 1 -#define CONTROL_108_SIZE 1 -#define CONTROL_109_SIZE 1 -#define CONTROL_110_SIZE 1 -#define CONTROL_111_SIZE 1 -#define CONTROL_112_SIZE 1 -#define CONTROL_113_SIZE 1 -#define CONTROL_114_SIZE 1 -#define CONTROL_115_SIZE 1 -#define CONTROL_116_SIZE 1 -#define CONTROL_117_SIZE 1 -#define CONTROL_118_SIZE 1 -#define CONTROL_119_SIZE 1 -#define CONTROL_120_SIZE 1 -#define CONTROL_121_SIZE 1 -#define CONTROL_122_SIZE 1 -#define CONTROL_123_SIZE 1 -#define CONTROL_124_SIZE 1 -#define CONTROL_125_SIZE 1 -#define CONTROL_126_SIZE 1 -#define CONTROL_127_SIZE 1 -#define CONTROL_128_SIZE 1 -#define CONTROL_129_SIZE 1 -#define CONTROL_130_SIZE 1 -#define CONTROL_131_SIZE 1 -#define CONTROL_132_SIZE 1 -#define CONTROL_133_SIZE 1 -#define CONTROL_134_SIZE 1 -#define CONTROL_135_SIZE 1 -#define CONTROL_136_SIZE 1 -#define CONTROL_137_SIZE 1 -#define CONTROL_138_SIZE 1 -#define CONTROL_139_SIZE 1 -#define CONTROL_140_SIZE 1 -#define CONTROL_141_SIZE 1 -#define CONTROL_142_SIZE 1 -#define CONTROL_143_SIZE 1 -#define CONTROL_144_SIZE 1 -#define CONTROL_145_SIZE 1 -#define CONTROL_146_SIZE 1 -#define CONTROL_147_SIZE 1 -#define CONTROL_148_SIZE 1 -#define CONTROL_149_SIZE 1 -#define CONTROL_163_SIZE 1 -#define CONTROL_165_SIZE 1 -#define CONTROL_167_SIZE 1 -#define CONTROL_176_SIZE 1 -#define CONTROL_179_SIZE 1 -#define CONTROL_188_SIZE 1 - -#define HIGH_RESISTANCE_DATA_SIZE 6 -#define FULL_RAW_CAP_MIN_MAX_DATA_SIZE 4 -#define TRX_OPEN_SHORT_DATA_SIZE 7 - -#define concat(a, b) a##b - -#define attrify(propname) (&dev_attr_##propname.attr) - -#define show_prototype(propname)\ -static ssize_t concat(test_sysfs, _##propname##_show)(\ - struct device *dev,\ - struct device_attribute *attr,\ - char *buf); - -#define store_prototype(propname)\ -static ssize_t concat(test_sysfs, _##propname##_store)(\ - struct device *dev,\ - struct device_attribute *attr,\ - const char *buf, size_t count); - -#define show_store_prototype(propname)\ -static ssize_t concat(test_sysfs, _##propname##_show)(\ - struct device *dev,\ - struct device_attribute *attr,\ - char *buf);\ -\ -static ssize_t concat(test_sysfs, _##propname##_store)(\ - struct device *dev,\ - struct device_attribute *attr,\ - const char *buf, size_t count);\ -\ -static struct device_attribute dev_attr_##propname =\ - __ATTR(propname, (S_IRUGO | S_IWUGO),\ - concat(test_sysfs, _##propname##_show),\ - concat(test_sysfs, _##propname##_store)); - -#define disable_cbc(ctrl_num)\ -do {\ - retval = synaptics_rmi4_reg_read(rmi4_data,\ - f54->control.ctrl_num->address,\ - f54->control.ctrl_num->data,\ - sizeof(f54->control.ctrl_num->data));\ - if (retval < 0) {\ - dev_err(rmi4_data->pdev->dev.parent,\ - "%s: Failed to disable CBC (" #ctrl_num ")\n",\ - __func__);\ - return retval;\ - } \ - f54->control.ctrl_num->cbc_tx_carrier_selection = 0;\ - retval = synaptics_rmi4_reg_write(rmi4_data,\ - f54->control.ctrl_num->address,\ - f54->control.ctrl_num->data,\ - sizeof(f54->control.ctrl_num->data));\ - if (retval < 0) {\ - dev_err(rmi4_data->pdev->dev.parent,\ - "%s: Failed to disable CBC (" #ctrl_num ")\n",\ - __func__);\ - return retval;\ - } \ -} while (0) - -enum f54_report_types { - F54_8BIT_IMAGE = 1, - F54_16BIT_IMAGE = 2, - F54_RAW_16BIT_IMAGE = 3, - F54_HIGH_RESISTANCE = 4, - F54_TX_TO_TX_SHORTS = 5, - F54_RX_TO_RX_SHORTS_1 = 7, - F54_TRUE_BASELINE = 9, - F54_FULL_RAW_CAP_MIN_MAX = 13, - F54_RX_OPENS_1 = 14, - F54_TX_OPENS = 15, - F54_TX_TO_GND_SHORTS = 16, - F54_RX_TO_RX_SHORTS_2 = 17, - F54_RX_OPENS_2 = 18, - F54_FULL_RAW_CAP = 19, - F54_FULL_RAW_CAP_NO_RX_COUPLING = 20, - F54_SENSOR_SPEED = 22, - F54_ADC_RANGE = 23, - F54_TRX_OPENS = 24, - F54_TRX_TO_GND_SHORTS = 25, - F54_TRX_SHORTS = 26, - F54_ABS_RAW_CAP = 38, - F54_ABS_DELTA_CAP = 40, - F54_ABS_HYBRID_DELTA_CAP = 59, - F54_ABS_HYBRID_RAW_CAP = 63, - F54_AMP_FULL_RAW_CAP = 78, - F54_AMP_RAW_ADC = 83, - INVALID_REPORT_TYPE = -1, -}; - -enum f54_afe_cal { - F54_AFE_CAL, - F54_AFE_IS_CAL, -}; - -struct f54_query { - union { - struct { - /* query 0 */ - unsigned char num_of_rx_electrodes; - - /* query 1 */ - unsigned char num_of_tx_electrodes; - - /* query 2 */ - unsigned char f54_query2_b0__1:2; - unsigned char has_baseline:1; - unsigned char has_image8:1; - unsigned char f54_query2_b4__5:2; - unsigned char has_image16:1; - unsigned char f54_query2_b7:1; - - /* queries 3.0 and 3.1 */ - unsigned short clock_rate; - - /* query 4 */ - unsigned char touch_controller_family; - - /* query 5 */ - unsigned char has_pixel_touch_threshold_adjustment:1; - unsigned char f54_query5_b1__7:7; - - /* query 6 */ - unsigned char has_sensor_assignment:1; - unsigned char has_interference_metric:1; - unsigned char has_sense_frequency_control:1; - unsigned char has_firmware_noise_mitigation:1; - unsigned char has_ctrl11:1; - unsigned char has_two_byte_report_rate:1; - unsigned char has_one_byte_report_rate:1; - unsigned char has_relaxation_control:1; - - /* query 7 */ - unsigned char curve_compensation_mode:2; - unsigned char f54_query7_b2__7:6; - - /* query 8 */ - unsigned char f54_query8_b0:1; - unsigned char has_iir_filter:1; - unsigned char has_cmn_removal:1; - unsigned char has_cmn_maximum:1; - unsigned char has_touch_hysteresis:1; - unsigned char has_edge_compensation:1; - unsigned char has_per_frequency_noise_control:1; - unsigned char has_enhanced_stretch:1; - - /* query 9 */ - unsigned char has_force_fast_relaxation:1; - unsigned char has_multi_metric_state_machine:1; - unsigned char has_signal_clarity:1; - unsigned char has_variance_metric:1; - unsigned char has_0d_relaxation_control:1; - unsigned char has_0d_acquisition_control:1; - unsigned char has_status:1; - unsigned char has_slew_metric:1; - - /* query 10 */ - unsigned char has_h_blank:1; - unsigned char has_v_blank:1; - unsigned char has_long_h_blank:1; - unsigned char has_startup_fast_relaxation:1; - unsigned char has_esd_control:1; - unsigned char has_noise_mitigation2:1; - unsigned char has_noise_state:1; - unsigned char has_energy_ratio_relaxation:1; - - /* query 11 */ - unsigned char has_excessive_noise_reporting:1; - unsigned char has_slew_option:1; - unsigned char has_two_overhead_bursts:1; - unsigned char has_query13:1; - unsigned char has_one_overhead_burst:1; - unsigned char f54_query11_b5:1; - unsigned char has_ctrl88:1; - unsigned char has_query15:1; - - /* query 12 */ - unsigned char number_of_sensing_frequencies:4; - unsigned char f54_query12_b4__7:4; - } __packed; - unsigned char data[14]; - }; -}; - -struct f54_query_13 { - union { - struct { - unsigned char has_ctrl86:1; - unsigned char has_ctrl87:1; - unsigned char has_ctrl87_sub0:1; - unsigned char has_ctrl87_sub1:1; - unsigned char has_ctrl87_sub2:1; - unsigned char has_cidim:1; - unsigned char has_noise_mitigation_enhancement:1; - unsigned char has_rail_im:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f54_query_15 { - union { - struct { - unsigned char has_ctrl90:1; - unsigned char has_transmit_strength:1; - unsigned char has_ctrl87_sub3:1; - unsigned char has_query16:1; - unsigned char has_query20:1; - unsigned char has_query21:1; - unsigned char has_query22:1; - unsigned char has_query25:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f54_query_16 { - union { - struct { - unsigned char has_query17:1; - unsigned char has_data17:1; - unsigned char has_ctrl92:1; - unsigned char has_ctrl93:1; - unsigned char has_ctrl94_query18:1; - unsigned char has_ctrl95_query19:1; - unsigned char has_ctrl99:1; - unsigned char has_ctrl100:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f54_query_21 { - union { - struct { - unsigned char has_abs_rx:1; - unsigned char has_abs_tx:1; - unsigned char has_ctrl91:1; - unsigned char has_ctrl96:1; - unsigned char has_ctrl97:1; - unsigned char has_ctrl98:1; - unsigned char has_data19:1; - unsigned char has_query24_data18:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f54_query_22 { - union { - struct { - unsigned char has_packed_image:1; - unsigned char has_ctrl101:1; - unsigned char has_dynamic_sense_display_ratio:1; - unsigned char has_query23:1; - unsigned char has_ctrl103_query26:1; - unsigned char has_ctrl104:1; - unsigned char has_ctrl105:1; - unsigned char has_query28:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f54_query_23 { - union { - struct { - unsigned char has_ctrl102:1; - unsigned char has_ctrl102_sub1:1; - unsigned char has_ctrl102_sub2:1; - unsigned char has_ctrl102_sub4:1; - unsigned char has_ctrl102_sub5:1; - unsigned char has_ctrl102_sub9:1; - unsigned char has_ctrl102_sub10:1; - unsigned char has_ctrl102_sub11:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f54_query_25 { - union { - struct { - unsigned char has_ctrl106:1; - unsigned char has_ctrl102_sub12:1; - unsigned char has_ctrl107:1; - unsigned char has_ctrl108:1; - unsigned char has_ctrl109:1; - unsigned char has_data20:1; - unsigned char f54_query25_b6:1; - unsigned char has_query27:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f54_query_27 { - union { - struct { - unsigned char has_ctrl110:1; - unsigned char has_data21:1; - unsigned char has_ctrl111:1; - unsigned char has_ctrl112:1; - unsigned char has_ctrl113:1; - unsigned char has_data22:1; - unsigned char has_ctrl114:1; - unsigned char has_query29:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f54_query_29 { - union { - struct { - unsigned char has_ctrl115:1; - unsigned char has_ground_ring_options:1; - unsigned char has_lost_bursts_tuning:1; - unsigned char has_aux_exvcom2_select:1; - unsigned char has_ctrl116:1; - unsigned char has_data23:1; - unsigned char has_ctrl117:1; - unsigned char has_query30:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f54_query_30 { - union { - struct { - unsigned char has_ctrl118:1; - unsigned char has_ctrl119:1; - unsigned char has_ctrl120:1; - unsigned char has_ctrl121:1; - unsigned char has_ctrl122_query31:1; - unsigned char has_ctrl123:1; - unsigned char f54_query30_b6:1; - unsigned char has_query32:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f54_query_32 { - union { - struct { - unsigned char has_ctrl125:1; - unsigned char has_ctrl126:1; - unsigned char has_ctrl127:1; - unsigned char has_abs_charge_pump_disable:1; - unsigned char has_query33:1; - unsigned char has_data24:1; - unsigned char has_query34:1; - unsigned char has_query35:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f54_query_33 { - union { - struct { - unsigned char f54_query33_b0:1; - unsigned char f54_query33_b1:1; - unsigned char f54_query33_b2:1; - unsigned char f54_query33_b3:1; - unsigned char has_ctrl132:1; - unsigned char has_ctrl133:1; - unsigned char has_ctrl134:1; - unsigned char has_query36:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f54_query_35 { - union { - struct { - unsigned char has_data25:1; - unsigned char f54_query35_b1:1; - unsigned char f54_query35_b2:1; - unsigned char has_ctrl137:1; - unsigned char has_ctrl138:1; - unsigned char has_ctrl139:1; - unsigned char has_data26:1; - unsigned char has_ctrl140:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f54_query_36 { - union { - struct { - unsigned char f54_query36_b0:1; - unsigned char has_ctrl142:1; - unsigned char has_query37:1; - unsigned char has_ctrl143:1; - unsigned char has_ctrl144:1; - unsigned char has_ctrl145:1; - unsigned char has_ctrl146:1; - unsigned char has_query38:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f54_query_38 { - union { - struct { - unsigned char has_ctrl147:1; - unsigned char has_ctrl148:1; - unsigned char has_ctrl149:1; - unsigned char f54_query38_b3__6:4; - unsigned char has_query39:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f54_query_39 { - union { - struct { - unsigned char f54_query39_b0__6:7; - unsigned char has_query40:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f54_query_40 { - union { - struct { - unsigned char f54_query40_b0:1; - unsigned char has_ctrl163_query41:1; - unsigned char f54_query40_b2:1; - unsigned char has_ctrl165_query42:1; - unsigned char f54_query40_b4:1; - unsigned char has_ctrl167:1; - unsigned char f54_query40_b6:1; - unsigned char has_query43:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f54_query_43 { - union { - struct { - unsigned char f54_query43_b0__6:7; - unsigned char has_query46:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f54_query_46 { - union { - struct { - unsigned char has_ctrl176:1; - unsigned char f54_query46_b1:1; - unsigned char has_ctrl179:1; - unsigned char f54_query46_b3:1; - unsigned char has_data27:1; - unsigned char has_data28:1; - unsigned char f54_query46_b6:1; - unsigned char has_query47:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f54_query_47 { - union { - struct { - unsigned char f54_query47_b0__6:7; - unsigned char has_query49:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f54_query_49 { - union { - struct { - unsigned char f54_query49_b0__1:2; - unsigned char has_ctrl188:1; - unsigned char has_data31:1; - unsigned char f54_query49_b4__6:3; - unsigned char has_query50:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f54_query_50 { - union { - struct { - unsigned char f54_query50_b0__6:7; - unsigned char has_query51:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f54_query_51 { - union { - struct { - unsigned char f54_query51_b0__4:5; - unsigned char has_query53_query54_ctrl198:1; - unsigned char f54_query51_b6__7:2; - } __packed; - unsigned char data[1]; - }; -}; - -struct f54_data_31 { - union { - struct { - unsigned char is_calibration_crc:1; - unsigned char calibration_crc:1; - unsigned char short_test_row_number:5; - } __packed; - struct { - unsigned char data[1]; - unsigned short address; - } __packed; - }; -}; - -struct f54_control_7 { - union { - struct { - unsigned char cbc_cap:3; - unsigned char cbc_polarity:1; - unsigned char cbc_tx_carrier_selection:1; - unsigned char f54_ctrl7_b5__7:3; - } __packed; - struct { - unsigned char data[1]; - unsigned short address; - } __packed; - }; -}; - -struct f54_control_41 { - union { - struct { - unsigned char no_signal_clarity:1; - unsigned char f54_ctrl41_b1__7:7; - } __packed; - struct { - unsigned char data[1]; - unsigned short address; - } __packed; - }; -}; - -struct f54_control_57 { - union { - struct { - unsigned char cbc_cap:3; - unsigned char cbc_polarity:1; - unsigned char cbc_tx_carrier_selection:1; - unsigned char f54_ctrl57_b5__7:3; - } __packed; - struct { - unsigned char data[1]; - unsigned short address; - } __packed; - }; -}; - -struct f54_control_86 { - union { - struct { - unsigned char enable_high_noise_state:1; - unsigned char dynamic_sense_display_ratio:2; - unsigned char f54_ctrl86_b3__7:5; - } __packed; - struct { - unsigned char data[1]; - unsigned short address; - } __packed; - }; -}; - -struct f54_control_88 { - union { - struct { - unsigned char tx_low_reference_polarity:1; - unsigned char tx_high_reference_polarity:1; - unsigned char abs_low_reference_polarity:1; - unsigned char abs_polarity:1; - unsigned char cbc_polarity:1; - unsigned char cbc_tx_carrier_selection:1; - unsigned char charge_pump_enable:1; - unsigned char cbc_abs_auto_servo:1; - } __packed; - struct { - unsigned char data[1]; - unsigned short address; - } __packed; - }; -}; - -struct f54_control_110 { - union { - struct { - unsigned char active_stylus_rx_feedback_cap; - unsigned char active_stylus_rx_feedback_cap_reference; - unsigned char active_stylus_low_reference; - unsigned char active_stylus_high_reference; - unsigned char active_stylus_gain_control; - unsigned char active_stylus_gain_control_reference; - unsigned char active_stylus_timing_mode; - unsigned char active_stylus_discovery_bursts; - unsigned char active_stylus_detection_bursts; - unsigned char active_stylus_discovery_noise_multiplier; - unsigned char active_stylus_detection_envelope_min; - unsigned char active_stylus_detection_envelope_max; - unsigned char active_stylus_lose_count; - } __packed; - struct { - unsigned char data[13]; - unsigned short address; - } __packed; - }; -}; - -struct f54_control_149 { - union { - struct { - unsigned char trans_cbc_global_cap_enable:1; - unsigned char f54_ctrl149_b1__7:7; - } __packed; - struct { - unsigned char data[1]; - unsigned short address; - } __packed; - }; -}; - -struct f54_control_188 { - union { - struct { - unsigned char start_calibration:1; - unsigned char start_is_calibration:1; - unsigned char frequency:2; - unsigned char start_production_test:1; - unsigned char short_test_calibration:1; - unsigned char f54_ctrl188_b7:1; - } __packed; - struct { - unsigned char data[1]; - unsigned short address; - } __packed; - }; -}; - -struct f54_control { - struct f54_control_7 *reg_7; - struct f54_control_41 *reg_41; - struct f54_control_57 *reg_57; - struct f54_control_86 *reg_86; - struct f54_control_88 *reg_88; - struct f54_control_110 *reg_110; - struct f54_control_149 *reg_149; - struct f54_control_188 *reg_188; -}; - -struct synaptics_rmi4_f54_handle { - bool no_auto_cal; - bool skip_preparation; - unsigned char status; - unsigned char intr_mask; - unsigned char intr_reg_num; - unsigned char tx_assigned; - unsigned char rx_assigned; - unsigned char *report_data; - unsigned short query_base_addr; - unsigned short control_base_addr; - unsigned short data_base_addr; - unsigned short command_base_addr; - unsigned short fifoindex; - unsigned int report_size; - unsigned int data_buffer_size; - unsigned int data_pos; - enum f54_report_types report_type; - struct f54_query query; - struct f54_query_13 query_13; - struct f54_query_15 query_15; - struct f54_query_16 query_16; - struct f54_query_21 query_21; - struct f54_query_22 query_22; - struct f54_query_23 query_23; - struct f54_query_25 query_25; - struct f54_query_27 query_27; - struct f54_query_29 query_29; - struct f54_query_30 query_30; - struct f54_query_32 query_32; - struct f54_query_33 query_33; - struct f54_query_35 query_35; - struct f54_query_36 query_36; - struct f54_query_38 query_38; - struct f54_query_39 query_39; - struct f54_query_40 query_40; - struct f54_query_43 query_43; - struct f54_query_46 query_46; - struct f54_query_47 query_47; - struct f54_query_49 query_49; - struct f54_query_50 query_50; - struct f54_query_51 query_51; - struct f54_data_31 data_31; - struct f54_control control; - struct mutex status_mutex; - struct kobject *sysfs_dir; - struct hrtimer watchdog; - struct work_struct timeout_work; - struct work_struct test_report_work; - struct workqueue_struct *test_report_workqueue; - struct synaptics_rmi4_data *rmi4_data; -}; - -struct f55_query { - union { - struct { - /* query 0 */ - unsigned char num_of_rx_electrodes; - - /* query 1 */ - unsigned char num_of_tx_electrodes; - - /* query 2 */ - unsigned char has_sensor_assignment:1; - unsigned char has_edge_compensation:1; - unsigned char curve_compensation_mode:2; - unsigned char has_ctrl6:1; - unsigned char has_alternate_transmitter_assignment:1; - unsigned char has_single_layer_multi_touch:1; - unsigned char has_query5:1; - } __packed; - unsigned char data[3]; - }; -}; - -struct f55_query_3 { - union { - struct { - unsigned char has_ctrl8:1; - unsigned char has_ctrl9:1; - unsigned char has_oncell_pattern_support:1; - unsigned char has_data0:1; - unsigned char has_single_wide_pattern_support:1; - unsigned char has_mirrored_tx_pattern_support:1; - unsigned char has_discrete_pattern_support:1; - unsigned char has_query9:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f55_query_5 { - union { - struct { - unsigned char has_corner_compensation:1; - unsigned char has_ctrl12:1; - unsigned char has_trx_configuration:1; - unsigned char has_ctrl13:1; - unsigned char f55_query5_b4:1; - unsigned char has_ctrl14:1; - unsigned char has_basis_function:1; - unsigned char has_query17:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f55_query_17 { - union { - struct { - unsigned char f55_query17_b0:1; - unsigned char has_ctrl16:1; - unsigned char f55_query17_b2:1; - unsigned char has_ctrl17:1; - unsigned char f55_query17_b4__6:3; - unsigned char has_query18:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f55_query_18 { - union { - struct { - unsigned char f55_query18_b0__6:7; - unsigned char has_query22:1; - } __packed; - unsigned char data[1]; - }; -}; - -struct f55_query_22 { - union { - struct { - unsigned char f55_query22_b0:1; - unsigned char has_query23:1; - unsigned char has_guard_disable:1; - unsigned char has_ctrl30:1; - unsigned char f55_query22_b4__7:4; - } __packed; - unsigned char data[1]; - }; -}; - -struct f55_query_23 { - union { - struct { - unsigned char amp_sensor_enabled:1; - unsigned char image_transposed:1; - unsigned char first_column_at_left_side:1; - unsigned char size_of_column2mux:5; - } __packed; - unsigned char data[1]; - }; -}; - -struct synaptics_rmi4_f55_handle { - bool amp_sensor; - unsigned char size_of_column2mux; - unsigned char *tx_assignment; - unsigned char *rx_assignment; - unsigned short query_base_addr; - unsigned short control_base_addr; - unsigned short data_base_addr; - unsigned short command_base_addr; - struct f55_query query; - struct f55_query_3 query_3; - struct f55_query_5 query_5; - struct f55_query_17 query_17; - struct f55_query_18 query_18; - struct f55_query_22 query_22; - struct f55_query_23 query_23; -}; - -show_prototype(num_of_mapped_tx) -show_prototype(num_of_mapped_rx) -show_prototype(tx_mapping) -show_prototype(rx_mapping) -show_prototype(report_size) -show_prototype(status) -store_prototype(do_preparation) -store_prototype(force_cal) -store_prototype(get_report) -store_prototype(resume_touch) -store_prototype(do_afe_calibration) -show_store_prototype(report_type) -show_store_prototype(fifoindex) -show_store_prototype(no_auto_cal) -show_store_prototype(read_report) - -static struct attribute *attrs[] = { - attrify(num_of_mapped_tx), - attrify(num_of_mapped_rx), - attrify(tx_mapping), - attrify(rx_mapping), - attrify(report_size), - attrify(status), - attrify(do_preparation), - attrify(force_cal), - attrify(get_report), - attrify(resume_touch), - attrify(do_afe_calibration), - attrify(report_type), - attrify(fifoindex), - attrify(no_auto_cal), - attrify(read_report), - NULL, -}; - -static struct attribute_group attr_group = { - .attrs = attrs, -}; - -static ssize_t test_sysfs_data_read(struct file *data_file, - struct kobject *kobj, struct bin_attribute *attributes, - char *buf, loff_t pos, size_t count); - -static struct bin_attribute test_report_data = { - .attr = { - .name = "report_data", - .mode = S_IRUGO, - }, - .size = 0, - .read = test_sysfs_data_read, -}; - -static struct synaptics_rmi4_f54_handle *f54; -static struct synaptics_rmi4_f55_handle *f55; - -DECLARE_COMPLETION(test_remove_complete); - -static bool test_report_type_valid(enum f54_report_types report_type) -{ - switch (report_type) { - case F54_8BIT_IMAGE: - case F54_16BIT_IMAGE: - case F54_RAW_16BIT_IMAGE: - case F54_HIGH_RESISTANCE: - case F54_TX_TO_TX_SHORTS: - case F54_RX_TO_RX_SHORTS_1: - case F54_TRUE_BASELINE: - case F54_FULL_RAW_CAP_MIN_MAX: - case F54_RX_OPENS_1: - case F54_TX_OPENS: - case F54_TX_TO_GND_SHORTS: - case F54_RX_TO_RX_SHORTS_2: - case F54_RX_OPENS_2: - case F54_FULL_RAW_CAP: - case F54_FULL_RAW_CAP_NO_RX_COUPLING: - case F54_SENSOR_SPEED: - case F54_ADC_RANGE: - case F54_TRX_OPENS: - case F54_TRX_TO_GND_SHORTS: - case F54_TRX_SHORTS: - case F54_ABS_RAW_CAP: - case F54_ABS_DELTA_CAP: - case F54_ABS_HYBRID_DELTA_CAP: - case F54_ABS_HYBRID_RAW_CAP: - case F54_AMP_FULL_RAW_CAP: - case F54_AMP_RAW_ADC: - return true; - break; - default: - f54->report_type = INVALID_REPORT_TYPE; - f54->report_size = 0; - return false; - } -} - -static void test_set_report_size(void) -{ - int retval; - unsigned char tx = f54->tx_assigned; - unsigned char rx = f54->rx_assigned; - struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; - - switch (f54->report_type) { - case F54_8BIT_IMAGE: - f54->report_size = tx * rx; - break; - case F54_16BIT_IMAGE: - case F54_RAW_16BIT_IMAGE: - case F54_TRUE_BASELINE: - case F54_FULL_RAW_CAP: - case F54_FULL_RAW_CAP_NO_RX_COUPLING: - case F54_SENSOR_SPEED: - case F54_AMP_FULL_RAW_CAP: - case F54_AMP_RAW_ADC: - f54->report_size = 2 * tx * rx; - break; - case F54_HIGH_RESISTANCE: - f54->report_size = HIGH_RESISTANCE_DATA_SIZE; - break; - case F54_TX_TO_TX_SHORTS: - case F54_TX_OPENS: - case F54_TX_TO_GND_SHORTS: - f54->report_size = (tx + 7) / 8; - break; - case F54_RX_TO_RX_SHORTS_1: - case F54_RX_OPENS_1: - if (rx < tx) - f54->report_size = 2 * rx * rx; - else - f54->report_size = 2 * tx * rx; - break; - case F54_FULL_RAW_CAP_MIN_MAX: - f54->report_size = FULL_RAW_CAP_MIN_MAX_DATA_SIZE; - break; - case F54_RX_TO_RX_SHORTS_2: - case F54_RX_OPENS_2: - if (rx <= tx) - f54->report_size = 0; - else - f54->report_size = 2 * rx * (rx - tx); - break; - case F54_ADC_RANGE: - if (f54->query.has_signal_clarity) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->control.reg_41->address, - f54->control.reg_41->data, - sizeof(f54->control.reg_41->data)); - if (retval < 0) { - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Failed to read control reg_41\n", - __func__); - f54->report_size = 0; - break; - } - if (!f54->control.reg_41->no_signal_clarity) { - if (tx % 4) - tx += 4 - (tx % 4); - } - } - f54->report_size = 2 * tx * rx; - break; - case F54_TRX_OPENS: - case F54_TRX_TO_GND_SHORTS: - case F54_TRX_SHORTS: - f54->report_size = TRX_OPEN_SHORT_DATA_SIZE; - break; - case F54_ABS_RAW_CAP: - case F54_ABS_DELTA_CAP: - case F54_ABS_HYBRID_DELTA_CAP: - case F54_ABS_HYBRID_RAW_CAP: - f54->report_size = 4 * (tx + rx); - break; - default: - f54->report_size = 0; - } - - return; -} - -static int test_set_interrupt(bool set) -{ - int retval; - unsigned char ii; - unsigned char zero = 0x00; - unsigned char *intr_mask; - unsigned short f01_ctrl_reg; - struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; - - intr_mask = rmi4_data->intr_mask; - f01_ctrl_reg = rmi4_data->f01_ctrl_base_addr + 1 + f54->intr_reg_num; - - if (!set) { - retval = synaptics_rmi4_reg_write(rmi4_data, - f01_ctrl_reg, - &zero, - sizeof(zero)); - if (retval < 0) - return retval; - } - - for (ii = 0; ii < rmi4_data->num_of_intr_regs; ii++) { - if (intr_mask[ii] != 0x00) { - f01_ctrl_reg = rmi4_data->f01_ctrl_base_addr + 1 + ii; - if (set) { - retval = synaptics_rmi4_reg_write(rmi4_data, - f01_ctrl_reg, - &zero, - sizeof(zero)); - if (retval < 0) - return retval; - } else { - retval = synaptics_rmi4_reg_write(rmi4_data, - f01_ctrl_reg, - &(intr_mask[ii]), - sizeof(intr_mask[ii])); - if (retval < 0) - return retval; - } - } - } - - f01_ctrl_reg = rmi4_data->f01_ctrl_base_addr + 1 + f54->intr_reg_num; - - if (set) { - retval = synaptics_rmi4_reg_write(rmi4_data, - f01_ctrl_reg, - &f54->intr_mask, - 1); - if (retval < 0) - return retval; - } - - return 0; -} - -static int test_wait_for_command_completion(void) -{ - int retval; - unsigned char value; - unsigned char timeout_count; - struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; - - timeout_count = 0; - do { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->command_base_addr, - &value, - sizeof(value)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read command register\n", - __func__); - return retval; - } - - if (value == 0x00) - break; - - msleep(100); - timeout_count++; - } while (timeout_count < COMMAND_TIMEOUT_100MS); - - if (timeout_count == COMMAND_TIMEOUT_100MS) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Timed out waiting for command completion\n", - __func__); - return -ETIMEDOUT; - } - - return 0; -} - -static int test_do_command(unsigned char command) -{ - int retval; - struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; - - retval = synaptics_rmi4_reg_write(rmi4_data, - f54->command_base_addr, - &command, - sizeof(command)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write command\n", - __func__); - return retval; - } - - retval = test_wait_for_command_completion(); - if (retval < 0) - return retval; - - return 0; -} - -static int test_do_preparation(void) -{ - int retval; - unsigned char value; - unsigned char zero = 0x00; - unsigned char device_ctrl; - struct f54_control_86 reg_86; - struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; - - retval = synaptics_rmi4_reg_read(rmi4_data, - rmi4_data->f01_ctrl_base_addr, - &device_ctrl, - sizeof(device_ctrl)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to set no sleep\n", - __func__); - return retval; - } - - device_ctrl |= NO_SLEEP_ON; - - retval = synaptics_rmi4_reg_write(rmi4_data, - rmi4_data->f01_ctrl_base_addr, - &device_ctrl, - sizeof(device_ctrl)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to set no sleep\n", - __func__); - return retval; - } - - if ((f54->query.has_query13) && - (f54->query_13.has_ctrl86)) { - reg_86.data[0] = f54->control.reg_86->data[0]; - reg_86.dynamic_sense_display_ratio = 1; - retval = synaptics_rmi4_reg_write(rmi4_data, - f54->control.reg_86->address, - reg_86.data, - sizeof(reg_86.data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to set sense display ratio\n", - __func__); - return retval; - } - } - - if (f54->skip_preparation) - return 0; - - switch (f54->report_type) { - case F54_16BIT_IMAGE: - case F54_RAW_16BIT_IMAGE: - case F54_SENSOR_SPEED: - case F54_ADC_RANGE: - case F54_ABS_RAW_CAP: - case F54_ABS_DELTA_CAP: - case F54_ABS_HYBRID_DELTA_CAP: - case F54_ABS_HYBRID_RAW_CAP: - break; - case F54_AMP_RAW_ADC: - if (f54->query_49.has_ctrl188) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->control.reg_188->address, - f54->control.reg_188->data, - sizeof(f54->control.reg_188->data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to set start production test\n", - __func__); - return retval; - } - f54->control.reg_188->start_production_test = 1; - retval = synaptics_rmi4_reg_write(rmi4_data, - f54->control.reg_188->address, - f54->control.reg_188->data, - sizeof(f54->control.reg_188->data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to set start production test\n", - __func__); - return retval; - } - } - break; - default: - if (f54->query.touch_controller_family == 1) - disable_cbc(reg_7); - else if (f54->query.has_ctrl88) - disable_cbc(reg_88); - - if (f54->query.has_0d_acquisition_control) - disable_cbc(reg_57); - - if ((f54->query.has_query15) && - (f54->query_15.has_query25) && - (f54->query_25.has_query27) && - (f54->query_27.has_query29) && - (f54->query_29.has_query30) && - (f54->query_30.has_query32) && - (f54->query_32.has_query33) && - (f54->query_33.has_query36) && - (f54->query_36.has_query38) && - (f54->query_38.has_ctrl149)) { - retval = synaptics_rmi4_reg_write(rmi4_data, - f54->control.reg_149->address, - &zero, - sizeof(f54->control.reg_149->data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to disable global CBC\n", - __func__); - return retval; - } - } - - if (f54->query.has_signal_clarity) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->control.reg_41->address, - &value, - sizeof(f54->control.reg_41->data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to disable signal clarity\n", - __func__); - return retval; - } - value |= 0x01; - retval = synaptics_rmi4_reg_write(rmi4_data, - f54->control.reg_41->address, - &value, - sizeof(f54->control.reg_41->data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to disable signal clarity\n", - __func__); - return retval; - } - } - - retval = test_do_command(COMMAND_FORCE_UPDATE); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to do force update\n", - __func__); - return retval; - } - - retval = test_do_command(COMMAND_FORCE_CAL); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to do force cal\n", - __func__); - return retval; - } - } - - return 0; -} - -static int test_do_afe_calibration(enum f54_afe_cal mode) -{ - int retval; - unsigned char timeout = CALIBRATION_TIMEOUT_S; - unsigned char timeout_count = 0; - struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; - - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->control.reg_188->address, - f54->control.reg_188->data, - sizeof(f54->control.reg_188->data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to start calibration\n", - __func__); - return retval; - } - - if (mode == F54_AFE_CAL) - f54->control.reg_188->start_calibration = 1; - else if (mode == F54_AFE_IS_CAL) - f54->control.reg_188->start_is_calibration = 1; - - retval = synaptics_rmi4_reg_write(rmi4_data, - f54->control.reg_188->address, - f54->control.reg_188->data, - sizeof(f54->control.reg_188->data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to start calibration\n", - __func__); - return retval; - } - - do { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->control.reg_188->address, - f54->control.reg_188->data, - sizeof(f54->control.reg_188->data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to complete calibration\n", - __func__); - return retval; - } - - if (mode == F54_AFE_CAL) { - if (!f54->control.reg_188->start_calibration) - break; - } else if (mode == F54_AFE_IS_CAL) { - if (!f54->control.reg_188->start_is_calibration) - break; - } - - if (timeout_count == timeout) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Timed out waiting for calibration completion\n", - __func__); - return -EBUSY; - } - - timeout_count++; - msleep(1000); - } while (true); - - /* check CRC */ - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->data_31.address, - f54->data_31.data, - sizeof(f54->data_31.data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read calibration CRC\n", - __func__); - return retval; - } - - if (mode == F54_AFE_CAL) { - if (f54->data_31.calibration_crc == 0) - return 0; - } else if (mode == F54_AFE_IS_CAL) { - if (f54->data_31.is_calibration_crc == 0) - return 0; - } - - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read calibration CRC\n", - __func__); - - return -EINVAL; -} - -static int test_check_for_idle_status(void) -{ - int retval; - struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; - - switch (f54->status) { - case STATUS_IDLE: - retval = 0; - break; - case STATUS_BUSY: - dev_err(rmi4_data->pdev->dev.parent, - "%s: Status busy\n", - __func__); - retval = -EINVAL; - break; - case STATUS_ERROR: - dev_err(rmi4_data->pdev->dev.parent, - "%s: Status error\n", - __func__); - retval = -EINVAL; - break; - default: - dev_err(rmi4_data->pdev->dev.parent, - "%s: Invalid status (%d)\n", - __func__, f54->status); - retval = -EINVAL; - } - - return retval; -} - -static void test_timeout_work(struct work_struct *work) -{ - int retval; - unsigned char command; - struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; - - mutex_lock(&f54->status_mutex); - - if (f54->status == STATUS_BUSY) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->command_base_addr, - &command, - sizeof(command)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read command register\n", - __func__); - } else if (command & COMMAND_GET_REPORT) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Report type not supported by FW\n", - __func__); - } else { - queue_work(f54->test_report_workqueue, - &f54->test_report_work); - goto exit; - } - f54->status = STATUS_ERROR; - f54->report_size = 0; - } - -exit: - mutex_unlock(&f54->status_mutex); - - return; -} - -static enum hrtimer_restart test_get_report_timeout(struct hrtimer *timer) -{ - schedule_work(&(f54->timeout_work)); - - return HRTIMER_NORESTART; -} - -static ssize_t test_sysfs_num_of_mapped_tx_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%u\n", f54->tx_assigned); -} - -static ssize_t test_sysfs_num_of_mapped_rx_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%u\n", f54->rx_assigned); -} - -static ssize_t test_sysfs_tx_mapping_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int cnt; - int count = 0; - unsigned char ii; - unsigned char tx_num; - unsigned char tx_electrodes = f54->query.num_of_tx_electrodes; - - if (!f55) - return -EINVAL; - - for (ii = 0; ii < tx_electrodes; ii++) { - tx_num = f55->tx_assignment[ii]; - if (tx_num == 0xff) - cnt = snprintf(buf, PAGE_SIZE - count, "xx "); - else - cnt = snprintf(buf, PAGE_SIZE - count, "%02u ", tx_num); - buf += cnt; - count += cnt; - } - - snprintf(buf, PAGE_SIZE - count, "\n"); - count++; - - return count; -} - -static ssize_t test_sysfs_rx_mapping_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int cnt; - int count = 0; - unsigned char ii; - unsigned char rx_num; - unsigned char rx_electrodes = f54->query.num_of_rx_electrodes; - - if (!f55) - return -EINVAL; - - for (ii = 0; ii < rx_electrodes; ii++) { - rx_num = f55->rx_assignment[ii]; - if (rx_num == 0xff) - cnt = snprintf(buf, PAGE_SIZE - count, "xx "); - else - cnt = snprintf(buf, PAGE_SIZE - count, "%02u ", rx_num); - buf += cnt; - count += cnt; - } - - snprintf(buf, PAGE_SIZE - count, "\n"); - count++; - - return count; -} - -static ssize_t test_sysfs_report_size_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%u\n", f54->report_size); -} - -static ssize_t test_sysfs_status_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int retval; - - mutex_lock(&f54->status_mutex); - - retval = snprintf(buf, PAGE_SIZE, "%u\n", f54->status); - - mutex_unlock(&f54->status_mutex); - - return retval; -} - -static ssize_t test_sysfs_do_preparation_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned long setting; - struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; - - retval = sstrtoul(buf, 10, &setting); - if (retval) - return retval; - - if (setting != 1) - return -EINVAL; - - mutex_lock(&f54->status_mutex); - - retval = test_check_for_idle_status(); - if (retval < 0) - goto exit; - - retval = test_do_preparation(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to do preparation\n", - __func__); - goto exit; - } - - retval = count; - -exit: - mutex_unlock(&f54->status_mutex); - - return retval; -} - -static ssize_t test_sysfs_force_cal_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned long setting; - struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; - - retval = sstrtoul(buf, 10, &setting); - if (retval) - return retval; - - if (setting != 1) - return -EINVAL; - - mutex_lock(&f54->status_mutex); - - retval = test_check_for_idle_status(); - if (retval < 0) - goto exit; - - retval = test_do_command(COMMAND_FORCE_CAL); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to do force cal\n", - __func__); - goto exit; - } - - retval = count; - -exit: - mutex_unlock(&f54->status_mutex); - - return retval; -} - -static ssize_t test_sysfs_get_report_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned char command; - unsigned long setting; - struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; - - retval = sstrtoul(buf, 10, &setting); - if (retval) - return retval; - - if (setting != 1) - return -EINVAL; - - mutex_lock(&f54->status_mutex); - - retval = test_check_for_idle_status(); - if (retval < 0) - goto exit; - - if (!test_report_type_valid(f54->report_type)) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Invalid report type\n", - __func__); - retval = -EINVAL; - goto exit; - } - - test_set_interrupt(true); - - command = (unsigned char)COMMAND_GET_REPORT; - - retval = synaptics_rmi4_reg_write(rmi4_data, - f54->command_base_addr, - &command, - sizeof(command)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write get report command\n", - __func__); - goto exit; - } - - f54->status = STATUS_BUSY; - f54->report_size = 0; - f54->data_pos = 0; - - hrtimer_start(&f54->watchdog, - ktime_set(GET_REPORT_TIMEOUT_S, 0), - HRTIMER_MODE_REL); - - retval = count; - -exit: - mutex_unlock(&f54->status_mutex); - - return retval; -} - -static ssize_t test_sysfs_resume_touch_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned char device_ctrl; - unsigned long setting; - struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; - - retval = sstrtoul(buf, 10, &setting); - if (retval) - return retval; - - if (setting != 1) - return -EINVAL; - - retval = synaptics_rmi4_reg_read(rmi4_data, - rmi4_data->f01_ctrl_base_addr, - &device_ctrl, - sizeof(device_ctrl)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to restore no sleep setting\n", - __func__); - return retval; - } - - device_ctrl = device_ctrl & ~NO_SLEEP_ON; - device_ctrl |= rmi4_data->no_sleep_setting; - - retval = synaptics_rmi4_reg_write(rmi4_data, - rmi4_data->f01_ctrl_base_addr, - &device_ctrl, - sizeof(device_ctrl)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to restore no sleep setting\n", - __func__); - return retval; - } - - if ((f54->query.has_query13) && - (f54->query_13.has_ctrl86)) { - retval = synaptics_rmi4_reg_write(rmi4_data, - f54->control.reg_86->address, - f54->control.reg_86->data, - sizeof(f54->control.reg_86->data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to restore sense display ratio\n", - __func__); - return retval; - } - } - - test_set_interrupt(false); - - if (f54->skip_preparation) - return count; - - switch (f54->report_type) { - case F54_16BIT_IMAGE: - case F54_RAW_16BIT_IMAGE: - case F54_SENSOR_SPEED: - case F54_ADC_RANGE: - case F54_ABS_RAW_CAP: - case F54_ABS_DELTA_CAP: - case F54_ABS_HYBRID_DELTA_CAP: - case F54_ABS_HYBRID_RAW_CAP: - break; - case F54_AMP_RAW_ADC: - if (f54->query_49.has_ctrl188) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->control.reg_188->address, - f54->control.reg_188->data, - sizeof(f54->control.reg_188->data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to set start production test\n", - __func__); - return retval; - } - f54->control.reg_188->start_production_test = 0; - retval = synaptics_rmi4_reg_write(rmi4_data, - f54->control.reg_188->address, - f54->control.reg_188->data, - sizeof(f54->control.reg_188->data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to set start production test\n", - __func__); - return retval; - } - } - break; - default: - rmi4_data->reset_device(rmi4_data, false); - } - - return count; -} - -static ssize_t test_sysfs_do_afe_calibration_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned long setting; - struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; - - retval = sstrtoul(buf, 10, &setting); - if (retval) - return retval; - - if (!f54->query_49.has_ctrl188) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: F54_ANALOG_Ctrl188 not found\n", - __func__); - return -EINVAL; - } - - if (setting == 0 || setting == 1) - retval = test_do_afe_calibration((enum f54_afe_cal)setting); - else - return -EINVAL; - - if (retval) - return retval; - else - return count; -} - -static ssize_t test_sysfs_report_type_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%u\n", f54->report_type); -} - -static ssize_t test_sysfs_report_type_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned char data; - unsigned long setting; - struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; - - retval = sstrtoul(buf, 10, &setting); - if (retval) - return retval; - - mutex_lock(&f54->status_mutex); - - retval = test_check_for_idle_status(); - if (retval < 0) - goto exit; - - if (!test_report_type_valid((enum f54_report_types)setting)) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Report type not supported by driver\n", - __func__); - retval = -EINVAL; - goto exit; - } - - f54->report_type = (enum f54_report_types)setting; - data = (unsigned char)setting; - retval = synaptics_rmi4_reg_write(rmi4_data, - f54->data_base_addr, - &data, - sizeof(data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write report type\n", - __func__); - goto exit; - } - - retval = count; - -exit: - mutex_unlock(&f54->status_mutex); - - return retval; -} - -static ssize_t test_sysfs_fifoindex_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int retval; - unsigned char data[2]; - struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; - - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->data_base_addr + REPORT_INDEX_OFFSET, - data, - sizeof(data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read report index\n", - __func__); - return retval; - } - - batohs(&f54->fifoindex, data); - - return snprintf(buf, PAGE_SIZE, "%u\n", f54->fifoindex); -} - -static ssize_t test_sysfs_fifoindex_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned char data[2]; - unsigned long setting; - struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; - - retval = sstrtoul(buf, 10, &setting); - if (retval) - return retval; - - f54->fifoindex = setting; - - hstoba(data, (unsigned short)setting); - - retval = synaptics_rmi4_reg_write(rmi4_data, - f54->data_base_addr + REPORT_INDEX_OFFSET, - data, - sizeof(data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write report index\n", - __func__); - return retval; - } - - return count; -} - -static ssize_t test_sysfs_no_auto_cal_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%u\n", f54->no_auto_cal); -} - -static ssize_t test_sysfs_no_auto_cal_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned char data; - unsigned long setting; - struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; - - retval = sstrtoul(buf, 10, &setting); - if (retval) - return retval; - - if (setting > 1) - return -EINVAL; - - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->control_base_addr, - &data, - sizeof(data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read no auto cal setting\n", - __func__); - return retval; - } - - if (setting) - data |= CONTROL_NO_AUTO_CAL; - else - data &= ~CONTROL_NO_AUTO_CAL; - - retval = synaptics_rmi4_reg_write(rmi4_data, - f54->control_base_addr, - &data, - sizeof(data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write no auto cal setting\n", - __func__); - return retval; - } - - f54->no_auto_cal = (setting == 1); - - return count; -} - -static ssize_t test_sysfs_read_report_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - unsigned int ii; - unsigned int jj; - int cnt; - int count = 0; - int tx_num = f54->tx_assigned; - int rx_num = f54->rx_assigned; - char *report_data_8; - short *report_data_16; - int *report_data_32; - unsigned short *report_data_u16; - unsigned int *report_data_u32; - - switch (f54->report_type) { - case F54_8BIT_IMAGE: - report_data_8 = (char *)f54->report_data; - for (ii = 0; ii < f54->report_size; ii++) { - cnt = snprintf(buf, PAGE_SIZE - count, "%03d: %d\n", - ii, *report_data_8); - report_data_8++; - buf += cnt; - count += cnt; - } - break; - case F54_AMP_RAW_ADC: - report_data_u16 = (unsigned short *)f54->report_data; - cnt = snprintf(buf, PAGE_SIZE - count, "tx = %d\nrx = %d\n", - tx_num, rx_num); - buf += cnt; - count += cnt; - - for (ii = 0; ii < tx_num; ii++) { - for (jj = 0; jj < (rx_num - 1); jj++) { - cnt = snprintf(buf, PAGE_SIZE - count, "%-4d ", - *report_data_u16); - report_data_u16++; - buf += cnt; - count += cnt; - } - cnt = snprintf(buf, PAGE_SIZE - count, "%-4d\n", - *report_data_u16); - report_data_u16++; - buf += cnt; - count += cnt; - } - break; - case F54_16BIT_IMAGE: - case F54_RAW_16BIT_IMAGE: - case F54_TRUE_BASELINE: - case F54_FULL_RAW_CAP: - case F54_FULL_RAW_CAP_NO_RX_COUPLING: - case F54_SENSOR_SPEED: - case F54_AMP_FULL_RAW_CAP: - report_data_16 = (short *)f54->report_data; - cnt = snprintf(buf, PAGE_SIZE - count, "tx = %d\nrx = %d\n", - tx_num, rx_num); - buf += cnt; - count += cnt; - - for (ii = 0; ii < tx_num; ii++) { - for (jj = 0; jj < (rx_num - 1); jj++) { - cnt = snprintf(buf, PAGE_SIZE - count, "%-4d ", - *report_data_16); - report_data_16++; - buf += cnt; - count += cnt; - } - cnt = snprintf(buf, PAGE_SIZE - count, "%-4d\n", - *report_data_16); - report_data_16++; - buf += cnt; - count += cnt; - } - break; - case F54_HIGH_RESISTANCE: - case F54_FULL_RAW_CAP_MIN_MAX: - report_data_16 = (short *)f54->report_data; - for (ii = 0; ii < f54->report_size; ii += 2) { - cnt = snprintf(buf, PAGE_SIZE - count, "%03d: %d\n", - ii / 2, *report_data_16); - report_data_16++; - buf += cnt; - count += cnt; - } - break; - case F54_ABS_RAW_CAP: - report_data_u32 = (unsigned int *)f54->report_data; - cnt = snprintf(buf, PAGE_SIZE - count, "rx "); - buf += cnt; - count += cnt; - for (ii = 0; ii < rx_num; ii++) { - cnt = snprintf(buf, PAGE_SIZE - count, " %2d", ii); - buf += cnt; - count += cnt; - } - cnt = snprintf(buf, PAGE_SIZE - count, "\n"); - buf += cnt; - count += cnt; - - cnt = snprintf(buf, PAGE_SIZE - count, " "); - buf += cnt; - count += cnt; - for (ii = 0; ii < rx_num; ii++) { - cnt = snprintf(buf, PAGE_SIZE - count, " %5u", - *report_data_u32); - report_data_u32++; - buf += cnt; - count += cnt; - } - cnt = snprintf(buf, PAGE_SIZE - count, "\n"); - buf += cnt; - count += cnt; - - cnt = snprintf(buf, PAGE_SIZE - count, "tx "); - buf += cnt; - count += cnt; - for (ii = 0; ii < tx_num; ii++) { - cnt = snprintf(buf, PAGE_SIZE - count, " %2d", ii); - buf += cnt; - count += cnt; - } - cnt = snprintf(buf, PAGE_SIZE - count, "\n"); - buf += cnt; - count += cnt; - - cnt = snprintf(buf, PAGE_SIZE - count, " "); - buf += cnt; - count += cnt; - for (ii = 0; ii < tx_num; ii++) { - cnt = snprintf(buf, PAGE_SIZE - count, " %5u", - *report_data_u32); - report_data_u32++; - buf += cnt; - count += cnt; - } - cnt = snprintf(buf, PAGE_SIZE - count, "\n"); - buf += cnt; - count += cnt; - break; - case F54_ABS_DELTA_CAP: - case F54_ABS_HYBRID_DELTA_CAP: - case F54_ABS_HYBRID_RAW_CAP: - report_data_32 = (int *)f54->report_data; - cnt = snprintf(buf, PAGE_SIZE - count, "rx "); - buf += cnt; - count += cnt; - for (ii = 0; ii < rx_num; ii++) { - cnt = snprintf(buf, PAGE_SIZE - count, " %2d", ii); - buf += cnt; - count += cnt; - } - cnt = snprintf(buf, PAGE_SIZE - count, "\n"); - buf += cnt; - count += cnt; - - cnt = snprintf(buf, PAGE_SIZE - count, " "); - buf += cnt; - count += cnt; - for (ii = 0; ii < rx_num; ii++) { - cnt = snprintf(buf, PAGE_SIZE - count, " %5d", - *report_data_32); - report_data_32++; - buf += cnt; - count += cnt; - } - cnt = snprintf(buf, PAGE_SIZE - count, "\n"); - buf += cnt; - count += cnt; - - cnt = snprintf(buf, PAGE_SIZE - count, "tx "); - buf += cnt; - count += cnt; - for (ii = 0; ii < tx_num; ii++) { - cnt = snprintf(buf, PAGE_SIZE - count, " %2d", ii); - buf += cnt; - count += cnt; - } - cnt = snprintf(buf, PAGE_SIZE - count, "\n"); - buf += cnt; - count += cnt; - - cnt = snprintf(buf, PAGE_SIZE - count, " "); - buf += cnt; - count += cnt; - for (ii = 0; ii < tx_num; ii++) { - cnt = snprintf(buf, PAGE_SIZE - count, " %5d", - *report_data_32); - report_data_32++; - buf += cnt; - count += cnt; - } - cnt = snprintf(buf, PAGE_SIZE - count, "\n"); - buf += cnt; - count += cnt; - break; - default: - for (ii = 0; ii < f54->report_size; ii++) { - cnt = snprintf(buf, PAGE_SIZE - count, "%03d: 0x%02x\n", - ii, f54->report_data[ii]); - buf += cnt; - count += cnt; - } - } - - snprintf(buf, PAGE_SIZE - count, "\n"); - count++; - - return count; -} - -static ssize_t test_sysfs_read_report_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned char timeout = GET_REPORT_TIMEOUT_S * 10; - unsigned char timeout_count; - const char cmd[] = {'1', 0}; - struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; - - retval = test_sysfs_report_type_store(dev, attr, buf, count); - if (retval < 0) - goto exit; - - retval = test_sysfs_do_preparation_store(dev, attr, cmd, 1); - if (retval < 0) - goto exit; - - retval = test_sysfs_get_report_store(dev, attr, cmd, 1); - if (retval < 0) - goto exit; - - timeout_count = 0; - do { - if (f54->status != STATUS_BUSY) - break; - msleep(100); - timeout_count++; - } while (timeout_count < timeout); - - if ((f54->status != STATUS_IDLE) || (f54->report_size == 0)) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read report\n", - __func__); - retval = -EINVAL; - goto exit; - } - - retval = test_sysfs_resume_touch_store(dev, attr, cmd, 1); - if (retval < 0) - goto exit; - - return count; - -exit: - rmi4_data->reset_device(rmi4_data, false); - - return retval; -} - -static ssize_t test_sysfs_data_read(struct file *data_file, - struct kobject *kobj, struct bin_attribute *attributes, - char *buf, loff_t pos, size_t count) -{ - int retval; - unsigned int read_size; - struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; - - mutex_lock(&f54->status_mutex); - - retval = test_check_for_idle_status(); - if (retval < 0) - goto exit; - - if (!f54->report_data) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Report type %d data not available\n", - __func__, f54->report_type); - retval = -EINVAL; - goto exit; - } - - if ((f54->data_pos + count) > f54->report_size) - read_size = f54->report_size - f54->data_pos; - else - read_size = min_t(unsigned int, count, f54->report_size); - - retval = secure_memcpy(buf, count, f54->report_data + f54->data_pos, - f54->data_buffer_size - f54->data_pos, read_size); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to copy report data\n", - __func__); - goto exit; - } - f54->data_pos += read_size; - retval = read_size; - -exit: - mutex_unlock(&f54->status_mutex); - - return retval; -} - -static void test_report_work(struct work_struct *work) -{ - int retval; - unsigned char report_index[2]; - struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; - - mutex_lock(&f54->status_mutex); - - if (f54->status != STATUS_BUSY) { - retval = STATUS_ERROR; - goto exit; - } - - retval = test_wait_for_command_completion(); - if (retval < 0) { - retval = STATUS_ERROR; - goto exit; - } - - test_set_report_size(); - if (f54->report_size == 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Report data size = 0\n", - __func__); - retval = STATUS_ERROR; - goto exit; - } - - if (f54->data_buffer_size < f54->report_size) { - if (f54->data_buffer_size) - kfree(f54->report_data); - f54->report_data = kzalloc(f54->report_size, GFP_KERNEL); - if (!f54->report_data) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for data buffer\n", - __func__); - f54->data_buffer_size = 0; - retval = STATUS_ERROR; - goto exit; - } - f54->data_buffer_size = f54->report_size; - } - - report_index[0] = 0; - report_index[1] = 0; - - retval = synaptics_rmi4_reg_write(rmi4_data, - f54->data_base_addr + REPORT_INDEX_OFFSET, - report_index, - sizeof(report_index)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to write report data index\n", - __func__); - retval = STATUS_ERROR; - goto exit; - } - - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->data_base_addr + REPORT_DATA_OFFSET, - f54->report_data, - f54->report_size); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read report data\n", - __func__); - retval = STATUS_ERROR; - goto exit; - } - - retval = STATUS_IDLE; - -exit: - mutex_unlock(&f54->status_mutex); - - if (retval == STATUS_ERROR) - f54->report_size = 0; - - f54->status = retval; - - return; -} - -static void test_remove_sysfs(void) -{ - sysfs_remove_group(f54->sysfs_dir, &attr_group); - sysfs_remove_bin_file(f54->sysfs_dir, &test_report_data); - kobject_put(f54->sysfs_dir); - - return; -} - -static int test_set_sysfs(void) -{ - int retval; - struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; - - f54->sysfs_dir = kobject_create_and_add(SYSFS_FOLDER_NAME, - &rmi4_data->input_dev->dev.kobj); - if (!f54->sysfs_dir) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create sysfs directory\n", - __func__); - goto exit_directory; - } - - retval = sysfs_create_bin_file(f54->sysfs_dir, &test_report_data); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create sysfs bin file\n", - __func__); - goto exit_bin_file; - } - - retval = sysfs_create_group(f54->sysfs_dir, &attr_group); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create sysfs attributes\n", - __func__); - goto exit_attributes; - } - - return 0; - -exit_attributes: - sysfs_remove_group(f54->sysfs_dir, &attr_group); - sysfs_remove_bin_file(f54->sysfs_dir, &test_report_data); - -exit_bin_file: - kobject_put(f54->sysfs_dir); - -exit_directory: - return -ENODEV; -} - -static void test_free_control_mem(void) -{ - struct f54_control control = f54->control; - - kfree(control.reg_7); - kfree(control.reg_41); - kfree(control.reg_57); - kfree(control.reg_86); - kfree(control.reg_88); - kfree(control.reg_110); - kfree(control.reg_149); - kfree(control.reg_188); - - return; -} - -static void test_set_data(void) -{ - unsigned short reg_addr; - - reg_addr = f54->data_base_addr + REPORT_DATA_OFFSET + 1; - - /* data 4 */ - if (f54->query.has_sense_frequency_control) - reg_addr++; - - /* data 5 reserved */ - - /* data 6 */ - if (f54->query.has_interference_metric) - reg_addr += 2; - - /* data 7 */ - if (f54->query.has_one_byte_report_rate | - f54->query.has_two_byte_report_rate) - reg_addr++; - if (f54->query.has_two_byte_report_rate) - reg_addr++; - - /* data 8 */ - if (f54->query.has_variance_metric) - reg_addr += 2; - - /* data 9 */ - if (f54->query.has_multi_metric_state_machine) - reg_addr += 2; - - /* data 10 */ - if (f54->query.has_multi_metric_state_machine | - f54->query.has_noise_state) - reg_addr++; - - /* data 11 */ - if (f54->query.has_status) - reg_addr++; - - /* data 12 */ - if (f54->query.has_slew_metric) - reg_addr += 2; - - /* data 13 */ - if (f54->query.has_multi_metric_state_machine) - reg_addr += 2; - - /* data 14 */ - if (f54->query_13.has_cidim) - reg_addr++; - - /* data 15 */ - if (f54->query_13.has_rail_im) - reg_addr++; - - /* data 16 */ - if (f54->query_13.has_noise_mitigation_enhancement) - reg_addr++; - - /* data 17 */ - if (f54->query_16.has_data17) - reg_addr++; - - /* data 18 */ - if (f54->query_21.has_query24_data18) - reg_addr++; - - /* data 19 */ - if (f54->query_21.has_data19) - reg_addr++; - - /* data_20 */ - if (f54->query_25.has_ctrl109) - reg_addr++; - - /* data 21 */ - if (f54->query_27.has_data21) - reg_addr++; - - /* data 22 */ - if (f54->query_27.has_data22) - reg_addr++; - - /* data 23 */ - if (f54->query_29.has_data23) - reg_addr++; - - /* data 24 */ - if (f54->query_32.has_data24) - reg_addr++; - - /* data 25 */ - if (f54->query_35.has_data25) - reg_addr++; - - /* data 26 */ - if (f54->query_35.has_data26) - reg_addr++; - - /* data 27 */ - if (f54->query_46.has_data27) - reg_addr++; - - /* data 28 */ - if (f54->query_46.has_data28) - reg_addr++; - - /* data 29 30 reserved */ - - /* data 31 */ - if (f54->query_49.has_data31) { - f54->data_31.address = reg_addr; - reg_addr++; - } - - return; -} - -static int test_set_controls(void) -{ - int retval; - unsigned char length; - unsigned char num_of_sensing_freqs; - unsigned short reg_addr = f54->control_base_addr; - struct f54_control *control = &f54->control; - struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; - - num_of_sensing_freqs = f54->query.number_of_sensing_frequencies; - - /* control 0 */ - reg_addr += CONTROL_0_SIZE; - - /* control 1 */ - if ((f54->query.touch_controller_family == 0) || - (f54->query.touch_controller_family == 1)) - reg_addr += CONTROL_1_SIZE; - - /* control 2 */ - reg_addr += CONTROL_2_SIZE; - - /* control 3 */ - if (f54->query.has_pixel_touch_threshold_adjustment) - reg_addr += CONTROL_3_SIZE; - - /* controls 4 5 6 */ - if ((f54->query.touch_controller_family == 0) || - (f54->query.touch_controller_family == 1)) - reg_addr += CONTROL_4_6_SIZE; - - /* control 7 */ - if (f54->query.touch_controller_family == 1) { - control->reg_7 = kzalloc(sizeof(*(control->reg_7)), - GFP_KERNEL); - if (!control->reg_7) - goto exit_no_mem; - control->reg_7->address = reg_addr; - reg_addr += CONTROL_7_SIZE; - } - - /* controls 8 9 */ - if ((f54->query.touch_controller_family == 0) || - (f54->query.touch_controller_family == 1)) - reg_addr += CONTROL_8_9_SIZE; - - /* control 10 */ - if (f54->query.has_interference_metric) - reg_addr += CONTROL_10_SIZE; - - /* control 11 */ - if (f54->query.has_ctrl11) - reg_addr += CONTROL_11_SIZE; - - /* controls 12 13 */ - if (f54->query.has_relaxation_control) - reg_addr += CONTROL_12_13_SIZE; - - /* controls 14 15 16 */ - if (f54->query.has_sensor_assignment) { - reg_addr += CONTROL_14_SIZE; - reg_addr += CONTROL_15_SIZE * f54->query.num_of_rx_electrodes; - reg_addr += CONTROL_16_SIZE * f54->query.num_of_tx_electrodes; - } - - /* controls 17 18 19 */ - if (f54->query.has_sense_frequency_control) { - reg_addr += CONTROL_17_SIZE * num_of_sensing_freqs; - reg_addr += CONTROL_18_SIZE * num_of_sensing_freqs; - reg_addr += CONTROL_19_SIZE * num_of_sensing_freqs; - } - - /* control 20 */ - reg_addr += CONTROL_20_SIZE; - - /* control 21 */ - if (f54->query.has_sense_frequency_control) - reg_addr += CONTROL_21_SIZE; - - /* controls 22 23 24 25 26 */ - if (f54->query.has_firmware_noise_mitigation) - reg_addr += CONTROL_22_26_SIZE; - - /* control 27 */ - if (f54->query.has_iir_filter) - reg_addr += CONTROL_27_SIZE; - - /* control 28 */ - if (f54->query.has_firmware_noise_mitigation) - reg_addr += CONTROL_28_SIZE; - - /* control 29 */ - if (f54->query.has_cmn_removal) - reg_addr += CONTROL_29_SIZE; - - /* control 30 */ - if (f54->query.has_cmn_maximum) - reg_addr += CONTROL_30_SIZE; - - /* control 31 */ - if (f54->query.has_touch_hysteresis) - reg_addr += CONTROL_31_SIZE; - - /* controls 32 33 34 35 */ - if (f54->query.has_edge_compensation) - reg_addr += CONTROL_32_35_SIZE; - - /* control 36 */ - if ((f54->query.curve_compensation_mode == 1) || - (f54->query.curve_compensation_mode == 2)) { - if (f54->query.curve_compensation_mode == 1) { - length = max(f54->query.num_of_rx_electrodes, - f54->query.num_of_tx_electrodes); - } else if (f54->query.curve_compensation_mode == 2) { - length = f54->query.num_of_rx_electrodes; - } - reg_addr += CONTROL_36_SIZE * length; - } - - /* control 37 */ - if (f54->query.curve_compensation_mode == 2) - reg_addr += CONTROL_37_SIZE * f54->query.num_of_tx_electrodes; - - /* controls 38 39 40 */ - if (f54->query.has_per_frequency_noise_control) { - reg_addr += CONTROL_38_SIZE * num_of_sensing_freqs; - reg_addr += CONTROL_39_SIZE * num_of_sensing_freqs; - reg_addr += CONTROL_40_SIZE * num_of_sensing_freqs; - } - - /* control 41 */ - if (f54->query.has_signal_clarity) { - control->reg_41 = kzalloc(sizeof(*(control->reg_41)), - GFP_KERNEL); - if (!control->reg_41) - goto exit_no_mem; - control->reg_41->address = reg_addr; - reg_addr += CONTROL_41_SIZE; - } - - /* control 42 */ - if (f54->query.has_variance_metric) - reg_addr += CONTROL_42_SIZE; - - /* controls 43 44 45 46 47 48 49 50 51 52 53 54 */ - if (f54->query.has_multi_metric_state_machine) - reg_addr += CONTROL_43_54_SIZE; - - /* controls 55 56 */ - if (f54->query.has_0d_relaxation_control) - reg_addr += CONTROL_55_56_SIZE; - - /* control 57 */ - if (f54->query.has_0d_acquisition_control) { - control->reg_57 = kzalloc(sizeof(*(control->reg_57)), - GFP_KERNEL); - if (!control->reg_57) - goto exit_no_mem; - control->reg_57->address = reg_addr; - reg_addr += CONTROL_57_SIZE; - } - - /* control 58 */ - if (f54->query.has_0d_acquisition_control) - reg_addr += CONTROL_58_SIZE; - - /* control 59 */ - if (f54->query.has_h_blank) - reg_addr += CONTROL_59_SIZE; - - /* controls 60 61 62 */ - if ((f54->query.has_h_blank) || - (f54->query.has_v_blank) || - (f54->query.has_long_h_blank)) - reg_addr += CONTROL_60_62_SIZE; - - /* control 63 */ - if ((f54->query.has_h_blank) || - (f54->query.has_v_blank) || - (f54->query.has_long_h_blank) || - (f54->query.has_slew_metric) || - (f54->query.has_slew_option) || - (f54->query.has_noise_mitigation2)) - reg_addr += CONTROL_63_SIZE; - - /* controls 64 65 66 67 */ - if (f54->query.has_h_blank) - reg_addr += CONTROL_64_67_SIZE * 7; - else if ((f54->query.has_v_blank) || - (f54->query.has_long_h_blank)) - reg_addr += CONTROL_64_67_SIZE; - - /* controls 68 69 70 71 72 73 */ - if ((f54->query.has_h_blank) || - (f54->query.has_v_blank) || - (f54->query.has_long_h_blank)) - reg_addr += CONTROL_68_73_SIZE; - - /* control 74 */ - if (f54->query.has_slew_metric) - reg_addr += CONTROL_74_SIZE; - - /* control 75 */ - if (f54->query.has_enhanced_stretch) - reg_addr += CONTROL_75_SIZE * num_of_sensing_freqs; - - /* control 76 */ - if (f54->query.has_startup_fast_relaxation) - reg_addr += CONTROL_76_SIZE; - - /* controls 77 78 */ - if (f54->query.has_esd_control) - reg_addr += CONTROL_77_78_SIZE; - - /* controls 79 80 81 82 83 */ - if (f54->query.has_noise_mitigation2) - reg_addr += CONTROL_79_83_SIZE; - - /* controls 84 85 */ - if (f54->query.has_energy_ratio_relaxation) - reg_addr += CONTROL_84_85_SIZE; - - /* control 86 */ - if (f54->query_13.has_ctrl86) { - control->reg_86 = kzalloc(sizeof(*(control->reg_86)), - GFP_KERNEL); - if (!control->reg_86) - goto exit_no_mem; - control->reg_86->address = reg_addr; - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->control.reg_86->address, - f54->control.reg_86->data, - sizeof(f54->control.reg_86->data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read sense display ratio\n", - __func__); - return retval; - } - reg_addr += CONTROL_86_SIZE; - } - - /* control 87 */ - if (f54->query_13.has_ctrl87) - reg_addr += CONTROL_87_SIZE; - - /* control 88 */ - if (f54->query.has_ctrl88) { - control->reg_88 = kzalloc(sizeof(*(control->reg_88)), - GFP_KERNEL); - if (!control->reg_88) - goto exit_no_mem; - control->reg_88->address = reg_addr; - reg_addr += CONTROL_88_SIZE; - } - - /* control 89 */ - if (f54->query_13.has_cidim || - f54->query_13.has_noise_mitigation_enhancement || - f54->query_13.has_rail_im) - reg_addr += CONTROL_89_SIZE; - - /* control 90 */ - if (f54->query_15.has_ctrl90) - reg_addr += CONTROL_90_SIZE; - - /* control 91 */ - if (f54->query_21.has_ctrl91) - reg_addr += CONTROL_91_SIZE; - - /* control 92 */ - if (f54->query_16.has_ctrl92) - reg_addr += CONTROL_92_SIZE; - - /* control 93 */ - if (f54->query_16.has_ctrl93) - reg_addr += CONTROL_93_SIZE; - - /* control 94 */ - if (f54->query_16.has_ctrl94_query18) - reg_addr += CONTROL_94_SIZE; - - /* control 95 */ - if (f54->query_16.has_ctrl95_query19) - reg_addr += CONTROL_95_SIZE; - - /* control 96 */ - if (f54->query_21.has_ctrl96) - reg_addr += CONTROL_96_SIZE; - - /* control 97 */ - if (f54->query_21.has_ctrl97) - reg_addr += CONTROL_97_SIZE; - - /* control 98 */ - if (f54->query_21.has_ctrl98) - reg_addr += CONTROL_98_SIZE; - - /* control 99 */ - if (f54->query.touch_controller_family == 2) - reg_addr += CONTROL_99_SIZE; - - /* control 100 */ - if (f54->query_16.has_ctrl100) - reg_addr += CONTROL_100_SIZE; - - /* control 101 */ - if (f54->query_22.has_ctrl101) - reg_addr += CONTROL_101_SIZE; - - - /* control 102 */ - if (f54->query_23.has_ctrl102) - reg_addr += CONTROL_102_SIZE; - - /* control 103 */ - if (f54->query_22.has_ctrl103_query26) { - f54->skip_preparation = true; - reg_addr += CONTROL_103_SIZE; - } - - /* control 104 */ - if (f54->query_22.has_ctrl104) - reg_addr += CONTROL_104_SIZE; - - /* control 105 */ - if (f54->query_22.has_ctrl105) - reg_addr += CONTROL_105_SIZE; - - /* control 106 */ - if (f54->query_25.has_ctrl106) - reg_addr += CONTROL_106_SIZE; - - /* control 107 */ - if (f54->query_25.has_ctrl107) - reg_addr += CONTROL_107_SIZE; - - /* control 108 */ - if (f54->query_25.has_ctrl108) - reg_addr += CONTROL_108_SIZE; - - /* control 109 */ - if (f54->query_25.has_ctrl109) - reg_addr += CONTROL_109_SIZE; - - /* control 110 */ - if (f54->query_27.has_ctrl110) { - control->reg_110 = kzalloc(sizeof(*(control->reg_110)), - GFP_KERNEL); - if (!control->reg_110) - goto exit_no_mem; - control->reg_110->address = reg_addr; - reg_addr += CONTROL_110_SIZE; - } - - /* control 111 */ - if (f54->query_27.has_ctrl111) - reg_addr += CONTROL_111_SIZE; - - /* control 112 */ - if (f54->query_27.has_ctrl112) - reg_addr += CONTROL_112_SIZE; - - /* control 113 */ - if (f54->query_27.has_ctrl113) - reg_addr += CONTROL_113_SIZE; - - /* control 114 */ - if (f54->query_27.has_ctrl114) - reg_addr += CONTROL_114_SIZE; - - /* control 115 */ - if (f54->query_29.has_ctrl115) - reg_addr += CONTROL_115_SIZE; - - /* control 116 */ - if (f54->query_29.has_ctrl116) - reg_addr += CONTROL_116_SIZE; - - /* control 117 */ - if (f54->query_29.has_ctrl117) - reg_addr += CONTROL_117_SIZE; - - /* control 118 */ - if (f54->query_30.has_ctrl118) - reg_addr += CONTROL_118_SIZE; - - /* control 119 */ - if (f54->query_30.has_ctrl119) - reg_addr += CONTROL_119_SIZE; - - /* control 120 */ - if (f54->query_30.has_ctrl120) - reg_addr += CONTROL_120_SIZE; - - /* control 121 */ - if (f54->query_30.has_ctrl121) - reg_addr += CONTROL_121_SIZE; - - /* control 122 */ - if (f54->query_30.has_ctrl122_query31) - reg_addr += CONTROL_122_SIZE; - - /* control 123 */ - if (f54->query_30.has_ctrl123) - reg_addr += CONTROL_123_SIZE; - - /* control 124 reserved */ - - /* control 125 */ - if (f54->query_32.has_ctrl125) - reg_addr += CONTROL_125_SIZE; - - /* control 126 */ - if (f54->query_32.has_ctrl126) - reg_addr += CONTROL_126_SIZE; - - /* control 127 */ - if (f54->query_32.has_ctrl127) - reg_addr += CONTROL_127_SIZE; - - /* controls 128 129 130 131 reserved */ - - /* control 132 */ - if (f54->query_33.has_ctrl132) - reg_addr += CONTROL_132_SIZE; - - /* control 133 */ - if (f54->query_33.has_ctrl133) - reg_addr += CONTROL_133_SIZE; - - /* control 134 */ - if (f54->query_33.has_ctrl134) - reg_addr += CONTROL_134_SIZE; - - /* controls 135 136 reserved */ - - /* control 137 */ - if (f54->query_35.has_ctrl137) - reg_addr += CONTROL_137_SIZE; - - /* control 138 */ - if (f54->query_35.has_ctrl138) - reg_addr += CONTROL_138_SIZE; - - /* control 139 */ - if (f54->query_35.has_ctrl139) - reg_addr += CONTROL_139_SIZE; - - /* control 140 */ - if (f54->query_35.has_ctrl140) - reg_addr += CONTROL_140_SIZE; - - /* control 141 reserved */ - - /* control 142 */ - if (f54->query_36.has_ctrl142) - reg_addr += CONTROL_142_SIZE; - - /* control 143 */ - if (f54->query_36.has_ctrl143) - reg_addr += CONTROL_143_SIZE; - - /* control 144 */ - if (f54->query_36.has_ctrl144) - reg_addr += CONTROL_144_SIZE; - - /* control 145 */ - if (f54->query_36.has_ctrl145) - reg_addr += CONTROL_145_SIZE; - - /* control 146 */ - if (f54->query_36.has_ctrl146) - reg_addr += CONTROL_146_SIZE; - - /* control 147 */ - if (f54->query_38.has_ctrl147) - reg_addr += CONTROL_147_SIZE; - - /* control 148 */ - if (f54->query_38.has_ctrl148) - reg_addr += CONTROL_148_SIZE; - - /* control 149 */ - if (f54->query_38.has_ctrl149) { - control->reg_149 = kzalloc(sizeof(*(control->reg_149)), - GFP_KERNEL); - if (!control->reg_149) - goto exit_no_mem; - control->reg_149->address = reg_addr; - reg_addr += CONTROL_149_SIZE; - } - - /* controls 150 to 162 reserved */ - - /* control 163 */ - if (f54->query_40.has_ctrl163_query41) - reg_addr += CONTROL_163_SIZE; - - /* control 164 reserved */ - - /* control 165 */ - if (f54->query_40.has_ctrl165_query42) - reg_addr += CONTROL_165_SIZE; - - /* control 166 reserved */ - - /* control 167 */ - if (f54->query_40.has_ctrl167) - reg_addr += CONTROL_167_SIZE; - - /* controls 168 to 175 reserved */ - - /* control 176 */ - if (f54->query_46.has_ctrl176) - reg_addr += CONTROL_176_SIZE; - - /* controls 177 178 reserved */ - - /* control 179 */ - if (f54->query_46.has_ctrl179) - reg_addr += CONTROL_179_SIZE; - - /* controls 180 to 187 reserved */ - - /* control 188 */ - if (f54->query_49.has_ctrl188) { - control->reg_188 = kzalloc(sizeof(*(control->reg_188)), - GFP_KERNEL); - if (!control->reg_188) - goto exit_no_mem; - control->reg_188->address = reg_addr; - reg_addr += CONTROL_188_SIZE; - } - - return 0; - -exit_no_mem: - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for control registers\n", - __func__); - return -ENOMEM; -} - -static int test_set_queries(void) -{ - int retval; - unsigned char offset; - struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; - - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->query_base_addr, - f54->query.data, - sizeof(f54->query.data)); - if (retval < 0) - return retval; - - offset = sizeof(f54->query.data); - - /* query 12 */ - if (f54->query.has_sense_frequency_control == 0) - offset -= 1; - - /* query 13 */ - if (f54->query.has_query13) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->query_base_addr + offset, - f54->query_13.data, - sizeof(f54->query_13.data)); - if (retval < 0) - return retval; - offset += 1; - } - - /* query 14 */ - if (f54->query_13.has_ctrl87) - offset += 1; - - /* query 15 */ - if (f54->query.has_query15) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->query_base_addr + offset, - f54->query_15.data, - sizeof(f54->query_15.data)); - if (retval < 0) - return retval; - offset += 1; - } - - /* query 16 */ - if (f54->query_15.has_query16) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->query_base_addr + offset, - f54->query_16.data, - sizeof(f54->query_16.data)); - if (retval < 0) - return retval; - offset += 1; - } - - /* query 17 */ - if (f54->query_16.has_query17) - offset += 1; - - /* query 18 */ - if (f54->query_16.has_ctrl94_query18) - offset += 1; - - /* query 19 */ - if (f54->query_16.has_ctrl95_query19) - offset += 1; - - /* query 20 */ - if (f54->query_15.has_query20) - offset += 1; - - /* query 21 */ - if (f54->query_15.has_query21) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->query_base_addr + offset, - f54->query_21.data, - sizeof(f54->query_21.data)); - if (retval < 0) - return retval; - offset += 1; - } - - /* query 22 */ - if (f54->query_15.has_query22) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->query_base_addr + offset, - f54->query_22.data, - sizeof(f54->query_22.data)); - if (retval < 0) - return retval; - offset += 1; - } - - /* query 23 */ - if (f54->query_22.has_query23) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->query_base_addr + offset, - f54->query_23.data, - sizeof(f54->query_23.data)); - if (retval < 0) - return retval; - offset += 1; - } - - /* query 24 */ - if (f54->query_21.has_query24_data18) - offset += 1; - - /* query 25 */ - if (f54->query_15.has_query25) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->query_base_addr + offset, - f54->query_25.data, - sizeof(f54->query_25.data)); - if (retval < 0) - return retval; - offset += 1; - } - - /* query 26 */ - if (f54->query_22.has_ctrl103_query26) - offset += 1; - - /* query 27 */ - if (f54->query_25.has_query27) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->query_base_addr + offset, - f54->query_27.data, - sizeof(f54->query_27.data)); - if (retval < 0) - return retval; - offset += 1; - } - - /* query 28 */ - if (f54->query_22.has_query28) - offset += 1; - - /* query 29 */ - if (f54->query_27.has_query29) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->query_base_addr + offset, - f54->query_29.data, - sizeof(f54->query_29.data)); - if (retval < 0) - return retval; - offset += 1; - } - - /* query 30 */ - if (f54->query_29.has_query30) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->query_base_addr + offset, - f54->query_30.data, - sizeof(f54->query_30.data)); - if (retval < 0) - return retval; - offset += 1; - } - - /* query 31 */ - if (f54->query_30.has_ctrl122_query31) - offset += 1; - - /* query 32 */ - if (f54->query_30.has_query32) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->query_base_addr + offset, - f54->query_32.data, - sizeof(f54->query_32.data)); - if (retval < 0) - return retval; - offset += 1; - } - - /* query 33 */ - if (f54->query_32.has_query33) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->query_base_addr + offset, - f54->query_33.data, - sizeof(f54->query_33.data)); - if (retval < 0) - return retval; - offset += 1; - } - - /* query 34 */ - if (f54->query_32.has_query34) - offset += 1; - - /* query 35 */ - if (f54->query_32.has_query35) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->query_base_addr + offset, - f54->query_35.data, - sizeof(f54->query_35.data)); - if (retval < 0) - return retval; - offset += 1; - } - - /* query 36 */ - if (f54->query_33.has_query36) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->query_base_addr + offset, - f54->query_36.data, - sizeof(f54->query_36.data)); - if (retval < 0) - return retval; - offset += 1; - } - - /* query 37 */ - if (f54->query_36.has_query37) - offset += 1; - - /* query 38 */ - if (f54->query_36.has_query38) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->query_base_addr + offset, - f54->query_38.data, - sizeof(f54->query_38.data)); - if (retval < 0) - return retval; - offset += 1; - } - - /* query 39 */ - if (f54->query_38.has_query39) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->query_base_addr + offset, - f54->query_39.data, - sizeof(f54->query_39.data)); - if (retval < 0) - return retval; - offset += 1; - } - - /* query 40 */ - if (f54->query_39.has_query40) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->query_base_addr + offset, - f54->query_40.data, - sizeof(f54->query_40.data)); - if (retval < 0) - return retval; - offset += 1; - } - - /* query 41 */ - if (f54->query_40.has_ctrl163_query41) - offset += 1; - - /* query 42 */ - if (f54->query_40.has_ctrl165_query42) - offset += 1; - - /* query 43 */ - if (f54->query_40.has_query43) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->query_base_addr + offset, - f54->query_43.data, - sizeof(f54->query_43.data)); - if (retval < 0) - return retval; - offset += 1; - } - - /* queries 44 45 reserved */ - - /* query 46 */ - if (f54->query_43.has_query46) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->query_base_addr + offset, - f54->query_46.data, - sizeof(f54->query_46.data)); - if (retval < 0) - return retval; - offset += 1; - } - - /* query 47 */ - if (f54->query_46.has_query47) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->query_base_addr + offset, - f54->query_47.data, - sizeof(f54->query_47.data)); - if (retval < 0) - return retval; - offset += 1; - } - - /* query 48 reserved */ - - /* query 49 */ - if (f54->query_47.has_query49) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->query_base_addr + offset, - f54->query_49.data, - sizeof(f54->query_49.data)); - if (retval < 0) - return retval; - offset += 1; - } - - /* query 50 */ - if (f54->query_49.has_query50) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->query_base_addr + offset, - f54->query_50.data, - sizeof(f54->query_50.data)); - if (retval < 0) - return retval; - offset += 1; - } - - /* query 51 */ - if (f54->query_50.has_query51) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f54->query_base_addr + offset, - f54->query_51.data, - sizeof(f54->query_51.data)); - if (retval < 0) - return retval; - offset += 1; - } - - return 0; -} - -static void test_f54_set_regs(struct synaptics_rmi4_data *rmi4_data, - struct synaptics_rmi4_fn_desc *fd, - unsigned int intr_count, - unsigned char page) -{ - unsigned char ii; - unsigned char intr_offset; - - f54->query_base_addr = fd->query_base_addr | (page << 8); - f54->control_base_addr = fd->ctrl_base_addr | (page << 8); - f54->data_base_addr = fd->data_base_addr | (page << 8); - f54->command_base_addr = fd->cmd_base_addr | (page << 8); - - f54->intr_reg_num = (intr_count + 7) / 8; - if (f54->intr_reg_num != 0) - f54->intr_reg_num -= 1; - - f54->intr_mask = 0; - intr_offset = intr_count % 8; - for (ii = intr_offset; - ii < (fd->intr_src_count + intr_offset); - ii++) { - f54->intr_mask |= 1 << ii; - } - - return; -} - -static int test_f55_set_queries(void) -{ - int retval; - unsigned char offset; - struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; - - retval = synaptics_rmi4_reg_read(rmi4_data, - f55->query_base_addr, - f55->query.data, - sizeof(f55->query.data)); - if (retval < 0) - return retval; - - offset = sizeof(f55->query.data); - - /* query 3 */ - if (f55->query.has_single_layer_multi_touch) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f55->query_base_addr + offset, - f55->query_3.data, - sizeof(f55->query_3.data)); - if (retval < 0) - return retval; - offset += 1; - } - - /* query 4 */ - if ((f55->query.has_single_layer_multi_touch) && - (f55->query_3.has_ctrl9)) - offset += 1; - - /* query 5 */ - if (f55->query.has_query5) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f55->query_base_addr + offset, - f55->query_5.data, - sizeof(f55->query_5.data)); - if (retval < 0) - return retval; - offset += 1; - } - - /* queries 6 7 */ - if (f55->query.curve_compensation_mode == 0x3) - offset += 2; - - /* query 8 */ - if ((f55->query.has_single_layer_multi_touch) && - f55->query_3.has_ctrl8) - offset += 1; - - /* query 9 */ - if ((f55->query.has_single_layer_multi_touch) && - f55->query_3.has_query9) - offset += 1; - - /* queries 10 11 12 13 14 15 16 */ - if ((f55->query.has_query5) && (f55->query_5.has_basis_function)) - offset += 7; - - /* query 17 */ - if ((f55->query.has_query5) && (f55->query_5.has_query17)) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f55->query_base_addr + offset, - f55->query_17.data, - sizeof(f55->query_17.data)); - if (retval < 0) - return retval; - offset += 1; - } - - /* query 18 */ - if ((f55->query.has_query5) && - (f55->query_5.has_query17) && - (f55->query_17.has_query18)) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f55->query_base_addr + offset, - f55->query_18.data, - sizeof(f55->query_18.data)); - if (retval < 0) - return retval; - offset += 1; - } - - /* query 22 */ - if ((f55->query.has_query5) && - (f55->query_5.has_query17) && - (f55->query_17.has_query18) && - (f55->query_18.has_query22)) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f55->query_base_addr + offset, - f55->query_22.data, - sizeof(f55->query_22.data)); - if (retval < 0) - return retval; - offset += 1; - } - - /* query 23 */ - if ((f55->query.has_query5) && - (f55->query_5.has_query17) && - (f55->query_17.has_query18) && - (f55->query_18.has_query22) && - (f55->query_22.has_query23)) { - retval = synaptics_rmi4_reg_read(rmi4_data, - f55->query_base_addr + offset, - f55->query_23.data, - sizeof(f55->query_23.data)); - if (retval < 0) - return retval; - offset += 1; - - f55->amp_sensor = f55->query_23.amp_sensor_enabled; - f55->size_of_column2mux = f55->query_23.size_of_column2mux; - } - - return 0; -} - -static void test_f55_init(struct synaptics_rmi4_data *rmi4_data) -{ - int retval; - unsigned char ii; - unsigned char rx_electrodes = f54->query.num_of_rx_electrodes; - unsigned char tx_electrodes = f54->query.num_of_tx_electrodes; - - retval = test_f55_set_queries(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read f55 query registers\n", - __func__); - return; - } - - if (!f55->query.has_sensor_assignment) - return; - - f55->tx_assignment = kzalloc(tx_electrodes, GFP_KERNEL); - f55->rx_assignment = kzalloc(rx_electrodes, GFP_KERNEL); - - retval = synaptics_rmi4_reg_read(rmi4_data, - f55->control_base_addr + SENSOR_TX_MAPPING_OFFSET, - f55->tx_assignment, - tx_electrodes); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read f55 tx assignment\n", - __func__); - return; - } - - retval = synaptics_rmi4_reg_read(rmi4_data, - f55->control_base_addr + SENSOR_RX_MAPPING_OFFSET, - f55->rx_assignment, - rx_electrodes); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read f55 rx assignment\n", - __func__); - return; - } - - f54->tx_assigned = 0; - for (ii = 0; ii < tx_electrodes; ii++) { - if (f55->tx_assignment[ii] != 0xff) - f54->tx_assigned++; - } - - f54->rx_assigned = 0; - for (ii = 0; ii < rx_electrodes; ii++) { - if (f55->rx_assignment[ii] != 0xff) - f54->rx_assigned++; - } - - if (f55->amp_sensor) { - f54->tx_assigned = f55->size_of_column2mux; - f54->rx_assigned /= 2; - } - - return; -} - -static void test_f55_set_regs(struct synaptics_rmi4_data *rmi4_data, - struct synaptics_rmi4_fn_desc *fd, - unsigned char page) -{ - f55 = kzalloc(sizeof(*f55), GFP_KERNEL); - if (!f55) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for f55\n", - __func__); - return; - } - - f55->query_base_addr = fd->query_base_addr | (page << 8); - f55->control_base_addr = fd->ctrl_base_addr | (page << 8); - f55->data_base_addr = fd->data_base_addr | (page << 8); - f55->command_base_addr = fd->cmd_base_addr | (page << 8); - - return; -} - -static int test_scan_pdt(void) -{ - int retval; - unsigned char intr_count = 0; - unsigned char page; - unsigned short addr; - bool f54found = false; - bool f55found = false; - struct synaptics_rmi4_fn_desc rmi_fd; - struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; - - for (page = 0; page < PAGES_TO_SERVICE; page++) { - for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) { - addr |= (page << 8); - - retval = synaptics_rmi4_reg_read(rmi4_data, - addr, - (unsigned char *)&rmi_fd, - sizeof(rmi_fd)); - if (retval < 0) - return retval; - - addr &= ~(MASK_8BIT << 8); - - if (!rmi_fd.fn_number) - break; - - switch (rmi_fd.fn_number) { - case SYNAPTICS_RMI4_F54: - test_f54_set_regs(rmi4_data, - &rmi_fd, intr_count, page); - f54found = true; - break; - case SYNAPTICS_RMI4_F55: - test_f55_set_regs(rmi4_data, - &rmi_fd, page); - f55found = true; - break; - default: - break; - } - - if (f54found && f55found) - goto pdt_done; - - intr_count += rmi_fd.intr_src_count; - } - } - - if (!f54found) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to find F54\n", - __func__); - return -EINVAL; - } - -pdt_done: - return 0; -} - -static void synaptics_rmi4_test_attn(struct synaptics_rmi4_data *rmi4_data, - unsigned char intr_mask) -{ - if (!f54) - return; - - if (f54->intr_mask & intr_mask) - queue_work(f54->test_report_workqueue, &f54->test_report_work); - - return; -} - -static int synaptics_rmi4_test_init(struct synaptics_rmi4_data *rmi4_data) -{ - int retval; - - if (f54) { - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Handle already exists\n", - __func__); - return 0; - } - - f54 = kzalloc(sizeof(*f54), GFP_KERNEL); - if (!f54) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for f54\n", - __func__); - retval = -ENOMEM; - goto exit; - } - - f54->rmi4_data = rmi4_data; - - f55 = NULL; - - retval = test_scan_pdt(); - if (retval < 0) - goto exit_free_mem; - - retval = test_set_queries(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read f54 query registers\n", - __func__); - goto exit_free_mem; - } - - f54->tx_assigned = f54->query.num_of_tx_electrodes; - f54->rx_assigned = f54->query.num_of_rx_electrodes; - - retval = test_set_controls(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to set up f54 control registers\n", - __func__); - goto exit_free_control; - } - - test_set_data(); - - if (f55) - test_f55_init(rmi4_data); - - if (rmi4_data->external_afe_buttons) - f54->tx_assigned++; - - retval = test_set_sysfs(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create sysfs entries\n", - __func__); - goto exit_sysfs; - } - - f54->test_report_workqueue = - create_singlethread_workqueue("test_report_workqueue"); - INIT_WORK(&f54->test_report_work, test_report_work); - - hrtimer_init(&f54->watchdog, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - f54->watchdog.function = test_get_report_timeout; - INIT_WORK(&f54->timeout_work, test_timeout_work); - - mutex_init(&f54->status_mutex); - f54->status = STATUS_IDLE; - - return 0; - -exit_sysfs: - if (f55) { - kfree(f55->tx_assignment); - kfree(f55->rx_assignment); - } - -exit_free_control: - test_free_control_mem(); - -exit_free_mem: - kfree(f55); - f55 = NULL; - kfree(f54); - f54 = NULL; - -exit: - return retval; -} - -static void synaptics_rmi4_test_remove(struct synaptics_rmi4_data *rmi4_data) -{ - if (!f54) - goto exit; - - hrtimer_cancel(&f54->watchdog); - - cancel_work_sync(&f54->test_report_work); - flush_workqueue(f54->test_report_workqueue); - destroy_workqueue(f54->test_report_workqueue); - - test_remove_sysfs(); - - if (f55) { - kfree(f55->tx_assignment); - kfree(f55->rx_assignment); - } - - test_free_control_mem(); - - if (f54->data_buffer_size) - kfree(f54->report_data); - - kfree(f55); - f55 = NULL; - - kfree(f54); - f54 = NULL; - -exit: - complete(&test_remove_complete); - - return; -} - -static void synaptics_rmi4_test_reset(struct synaptics_rmi4_data *rmi4_data) -{ - int retval; - - if (!f54) { - synaptics_rmi4_test_init(rmi4_data); - return; - } - - if (f55) { - kfree(f55->tx_assignment); - kfree(f55->rx_assignment); - } - - test_free_control_mem(); - - kfree(f55); - f55 = NULL; - - retval = test_scan_pdt(); - if (retval < 0) - goto exit_free_mem; - - retval = test_set_queries(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to read f54 query registers\n", - __func__); - goto exit_free_mem; - } - - f54->tx_assigned = f54->query.num_of_tx_electrodes; - f54->rx_assigned = f54->query.num_of_rx_electrodes; - - retval = test_set_controls(); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to set up f54 control registers\n", - __func__); - goto exit_free_control; - } - - test_set_data(); - - if (f55) - test_f55_init(rmi4_data); - - if (rmi4_data->external_afe_buttons) - f54->tx_assigned++; - - f54->status = STATUS_IDLE; - - return; - -exit_free_control: - test_free_control_mem(); - -exit_free_mem: - hrtimer_cancel(&f54->watchdog); - - cancel_work_sync(&f54->test_report_work); - flush_workqueue(f54->test_report_workqueue); - destroy_workqueue(f54->test_report_workqueue); - - test_remove_sysfs(); - - if (f54->data_buffer_size) - kfree(f54->report_data); - - kfree(f55); - f55 = NULL; - - kfree(f54); - f54 = NULL; - - return; -} - -static struct synaptics_rmi4_exp_fn test_module = { - .fn_type = RMI_TEST_REPORTING, - .init = synaptics_rmi4_test_init, - .remove = synaptics_rmi4_test_remove, - .reset = synaptics_rmi4_test_reset, - .reinit = NULL, - .early_suspend = NULL, - .suspend = NULL, - .resume = NULL, - .late_resume = NULL, - .attn = synaptics_rmi4_test_attn, -}; - -static int __init rmi4_test_module_init(void) -{ - synaptics_rmi4_new_function(&test_module, true); - - return 0; -} - -static void __exit rmi4_test_module_exit(void) -{ - synaptics_rmi4_new_function(&test_module, false); - - wait_for_completion(&test_remove_complete); - - return; -} - -module_init(rmi4_test_module_init); -module_exit(rmi4_test_module_exit); - -MODULE_AUTHOR("Synaptics, Inc."); -MODULE_DESCRIPTION("Synaptics DSX Test Reporting Module"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_video.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_video.c deleted file mode 100644 index 847dc4dd3049..000000000000 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_video.c +++ /dev/null @@ -1,416 +0,0 @@ -/* - * Synaptics DSX touchscreen driver - * - * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved. - * - * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com> - * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com> - * - * 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. - * - * 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. - * - * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS - * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, - * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS. - * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION - * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED - * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES - * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' - * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. - * DOLLARS. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/input.h> -#include <linux/platform_device.h> -#include <linux/input/synaptics_dsx_v2_6.h> -#include "synaptics_dsx_core.h" - -#define SYSFS_FOLDER_NAME "video" - -/* -#define RMI_DCS_SUSPEND_RESUME -*/ - -static ssize_t video_sysfs_dcs_write_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static ssize_t video_sysfs_param_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); - -static int video_send_dcs_command(unsigned char command_opcode); - -struct f38_command { - union { - struct { - unsigned char command_opcode; - unsigned char register_access:1; - unsigned char gamma_page:1; - unsigned char f38_control1_b2__7:6; - unsigned char parameter_field_1; - unsigned char parameter_field_2; - unsigned char parameter_field_3; - unsigned char parameter_field_4; - unsigned char send_to_dcs:1; - unsigned char f38_command6_b1__7:7; - } __packed; - unsigned char data[7]; - }; -}; - -struct synaptics_rmi4_video_handle { - unsigned char param; - unsigned short query_base_addr; - unsigned short control_base_addr; - unsigned short data_base_addr; - unsigned short command_base_addr; - struct synaptics_rmi4_data *rmi4_data; - struct kobject *sysfs_dir; -}; - -#ifdef RMI_DCS_SUSPEND_RESUME -struct dcs_command { - unsigned char command; - unsigned int wait_time; -}; - -static struct dcs_command suspend_sequence[] = { - { - .command = 0x28, - .wait_time = 200, - }, - { - .command = 0x10, - .wait_time = 200, - }, -}; - -static struct dcs_command resume_sequence[] = { - { - .command = 0x11, - .wait_time = 200, - }, - { - .command = 0x29, - .wait_time = 200, - }, -}; -#endif - -static struct device_attribute attrs[] = { - __ATTR(dcs_write, S_IWUGO, - NULL, - video_sysfs_dcs_write_store), - __ATTR(param, S_IWUGO, - NULL, - video_sysfs_param_store), -}; - -static struct synaptics_rmi4_video_handle *video; - -DECLARE_COMPLETION(video_remove_complete); - -static ssize_t video_sysfs_dcs_write_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int retval; - unsigned int input; - - if (sscanf(buf, "%x", &input) != 1) - return -EINVAL; - - retval = video_send_dcs_command((unsigned char)input); - if (retval < 0) - return retval; - - return count; -} - -static ssize_t video_sysfs_param_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - unsigned int input; - - if (sscanf(buf, "%x", &input) != 1) - return -EINVAL; - - video->param = (unsigned char)input; - - return count; -} - -static int video_send_dcs_command(unsigned char command_opcode) -{ - int retval; - struct f38_command command; - struct synaptics_rmi4_data *rmi4_data = video->rmi4_data; - - memset(&command, 0x00, sizeof(command)); - - command.command_opcode = command_opcode; - command.parameter_field_1 = video->param; - command.send_to_dcs = 1; - - video->param = 0; - - retval = synaptics_rmi4_reg_write(rmi4_data, - video->command_base_addr, - command.data, - sizeof(command.data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to send DCS command\n", - __func__); - return retval; - } - - return 0; -} - -static int video_scan_pdt(void) -{ - int retval; - unsigned char page; - unsigned short addr; - bool f38_found = false; - struct synaptics_rmi4_fn_desc rmi_fd; - struct synaptics_rmi4_data *rmi4_data = video->rmi4_data; - - for (page = 0; page < PAGES_TO_SERVICE; page++) { - for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) { - addr |= (page << 8); - - retval = synaptics_rmi4_reg_read(rmi4_data, - addr, - (unsigned char *)&rmi_fd, - sizeof(rmi_fd)); - if (retval < 0) - return retval; - - addr &= ~(MASK_8BIT << 8); - - if (!rmi_fd.fn_number) - break; - - if (rmi_fd.fn_number == SYNAPTICS_RMI4_F38) { - f38_found = true; - goto f38_found; - } - } - } - - if (!f38_found) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to find F38\n", - __func__); - return -EINVAL; - } - -f38_found: - video->query_base_addr = rmi_fd.query_base_addr | (page << 8); - video->control_base_addr = rmi_fd.ctrl_base_addr | (page << 8); - video->data_base_addr = rmi_fd.data_base_addr | (page << 8); - video->command_base_addr = rmi_fd.cmd_base_addr | (page << 8); - - return 0; -} - -static int synaptics_rmi4_video_init(struct synaptics_rmi4_data *rmi4_data) -{ - int retval; - unsigned char attr_count; - - if (video) { - dev_dbg(rmi4_data->pdev->dev.parent, - "%s: Handle already exists\n", - __func__); - return 0; - } - - video = kzalloc(sizeof(*video), GFP_KERNEL); - if (!video) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to alloc mem for video\n", - __func__); - retval = -ENOMEM; - goto exit; - } - - video->rmi4_data = rmi4_data; - - retval = video_scan_pdt(); - if (retval < 0) { - retval = 0; - goto exit_scan_pdt; - } - - video->sysfs_dir = kobject_create_and_add(SYSFS_FOLDER_NAME, - &rmi4_data->input_dev->dev.kobj); - if (!video->sysfs_dir) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create sysfs directory\n", - __func__); - retval = -ENODEV; - goto exit_sysfs_dir; - } - - for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { - retval = sysfs_create_file(video->sysfs_dir, - &attrs[attr_count].attr); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to create sysfs attributes\n", - __func__); - retval = -ENODEV; - goto exit_sysfs_attrs; - } - } - - return 0; - -exit_sysfs_attrs: - for (attr_count--; attr_count >= 0; attr_count--) - sysfs_remove_file(video->sysfs_dir, &attrs[attr_count].attr); - - kobject_put(video->sysfs_dir); - -exit_sysfs_dir: -exit_scan_pdt: - kfree(video); - video = NULL; - -exit: - return retval; -} - -static void synaptics_rmi4_video_remove(struct synaptics_rmi4_data *rmi4_data) -{ - unsigned char attr_count; - - if (!video) - goto exit; - - for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) - sysfs_remove_file(video->sysfs_dir, &attrs[attr_count].attr); - - kobject_put(video->sysfs_dir); - - kfree(video); - video = NULL; - -exit: - complete(&video_remove_complete); - - return; -} - -static void synaptics_rmi4_video_reset(struct synaptics_rmi4_data *rmi4_data) -{ - if (!video) - synaptics_rmi4_video_init(rmi4_data); - - return; -} - -#ifdef RMI_DCS_SUSPEND_RESUME -static void synaptics_rmi4_video_suspend(struct synaptics_rmi4_data *rmi4_data) -{ - int retval; - unsigned char ii; - unsigned char command; - unsigned char num_of_cmds; - - if (!video) - return; - - num_of_cmds = ARRAY_SIZE(suspend_sequence); - - for (ii = 0; ii < num_of_cmds; ii++) { - command = suspend_sequence[ii].command; - retval = video_send_dcs_command(command); - if (retval < 0) - return; - msleep(suspend_sequence[ii].wait_time); - } - - return; -} - -static void synaptics_rmi4_video_resume(struct synaptics_rmi4_data *rmi4_data) -{ - int retval; - unsigned char ii; - unsigned char command; - unsigned char num_of_cmds; - - if (!video) - return; - - num_of_cmds = ARRAY_SIZE(resume_sequence); - - for (ii = 0; ii < num_of_cmds; ii++) { - command = resume_sequence[ii].command; - retval = video_send_dcs_command(command); - if (retval < 0) - return; - msleep(resume_sequence[ii].wait_time); - } - - return; -} -#endif - -static struct synaptics_rmi4_exp_fn video_module = { - .fn_type = RMI_VIDEO, - .init = synaptics_rmi4_video_init, - .remove = synaptics_rmi4_video_remove, - .reset = synaptics_rmi4_video_reset, - .reinit = NULL, - .early_suspend = NULL, -#ifdef RMI_DCS_SUSPEND_RESUME - .suspend = synaptics_rmi4_video_suspend, - .resume = synaptics_rmi4_video_resume, -#else - .suspend = NULL, - .resume = NULL, -#endif - .late_resume = NULL, - .attn = NULL, -}; - -static int __init rmi4_video_module_init(void) -{ - synaptics_rmi4_new_function(&video_module, true); - - return 0; -} - -static void __exit rmi4_video_module_exit(void) -{ - synaptics_rmi4_new_function(&video_module, false); - - wait_for_completion(&video_remove_complete); - - return; -} - -module_init(rmi4_video_module_init); -module_exit(rmi4_video_module_exit); - -MODULE_AUTHOR("Synaptics, Inc."); -MODULE_DESCRIPTION("Synaptics DSX Video Module"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c index 54d395d5e78d..4c28e0922c84 100644 --- a/drivers/leds/leds-qpnp-flash-v2.c +++ b/drivers/leds/leds-qpnp-flash-v2.c @@ -175,9 +175,7 @@ enum { struct flash_node_data { struct platform_device *pdev; struct led_classdev cdev; - struct pinctrl *pinctrl; - struct pinctrl_state *gpio_state_active; - struct pinctrl_state *gpio_state_suspend; + struct pinctrl *strobe_pinctrl; struct pinctrl_state *hw_strobe_state_active; struct pinctrl_state *hw_strobe_state_suspend; int hw_strobe_gpio; @@ -198,6 +196,9 @@ struct flash_node_data { struct flash_switch_data { struct platform_device *pdev; struct regulator *vreg; + struct pinctrl *led_en_pinctrl; + struct pinctrl_state *gpio_state_active; + struct pinctrl_state *gpio_state_suspend; struct led_classdev cdev; int led_mask; bool regulator_on; @@ -509,7 +510,7 @@ static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led) if (led->pdata->led1n2_iclamp_low_ma) { val = CURRENT_MA_TO_REG_VAL(led->pdata->led1n2_iclamp_low_ma, - led->fnode[0].ires_ua); + led->fnode[LED1].ires_ua); rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_LED1N2_ICLAMP_LOW(led->base), FLASH_LED_CURRENT_MASK, val); @@ -519,7 +520,7 @@ static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led) if (led->pdata->led1n2_iclamp_mid_ma) { val = CURRENT_MA_TO_REG_VAL(led->pdata->led1n2_iclamp_mid_ma, - led->fnode[0].ires_ua); + led->fnode[LED1].ires_ua); rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_LED1N2_ICLAMP_MID(led->base), FLASH_LED_CURRENT_MASK, val); @@ -529,7 +530,7 @@ static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led) if (led->pdata->led3_iclamp_low_ma) { val = CURRENT_MA_TO_REG_VAL(led->pdata->led3_iclamp_low_ma, - led->fnode[3].ires_ua); + led->fnode[LED3].ires_ua); rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_LED3_ICLAMP_LOW(led->base), FLASH_LED_CURRENT_MASK, val); @@ -539,7 +540,7 @@ static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led) if (led->pdata->led3_iclamp_mid_ma) { val = CURRENT_MA_TO_REG_VAL(led->pdata->led3_iclamp_mid_ma, - led->fnode[3].ires_ua); + led->fnode[LED3].ires_ua); rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_LED3_ICLAMP_MID(led->base), FLASH_LED_CURRENT_MASK, val); @@ -570,9 +571,9 @@ static int qpnp_flash_led_hw_strobe_enable(struct flash_node_data *fnode, if (gpio_is_valid(fnode->hw_strobe_gpio)) { gpio_set_value(fnode->hw_strobe_gpio, on ? 1 : 0); - } else if (fnode->hw_strobe_state_active && + } else if (fnode->strobe_pinctrl && fnode->hw_strobe_state_active && fnode->hw_strobe_state_suspend) { - rc = pinctrl_select_state(fnode->pinctrl, + rc = pinctrl_select_state(fnode->strobe_pinctrl, on ? fnode->hw_strobe_state_active : fnode->hw_strobe_state_suspend); if (rc < 0) { @@ -948,15 +949,6 @@ static int qpnp_flash_led_switch_disable(struct flash_switch_data *snode) led->fnode[i].led_on = false; - if (led->fnode[i].pinctrl) { - rc = pinctrl_select_state(led->fnode[i].pinctrl, - led->fnode[i].gpio_state_suspend); - if (rc < 0) { - pr_err("failed to disable GPIO, rc=%d\n", rc); - return rc; - } - } - if (led->fnode[i].trigger & FLASH_LED_HW_SW_STROBE_SEL_BIT) { rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i], led->pdata->hw_strobe_option, false); @@ -968,6 +960,17 @@ static int qpnp_flash_led_switch_disable(struct flash_switch_data *snode) } } + if (snode->led_en_pinctrl) { + pr_debug("Selecting suspend state for %s\n", snode->cdev.name); + rc = pinctrl_select_state(snode->led_en_pinctrl, + snode->gpio_state_suspend); + if (rc < 0) { + pr_err("failed to select pinctrl suspend state rc=%d\n", + rc); + return rc; + } + } + snode->enabled = false; return 0; } @@ -1038,15 +1041,6 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on) val |= FLASH_LED_ENABLE << led->fnode[i].id; - if (led->fnode[i].pinctrl) { - rc = pinctrl_select_state(led->fnode[i].pinctrl, - led->fnode[i].gpio_state_active); - if (rc < 0) { - pr_err("failed to enable GPIO rc=%d\n", rc); - return rc; - } - } - if (led->fnode[i].trigger & FLASH_LED_HW_SW_STROBE_SEL_BIT) { rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i], led->pdata->hw_strobe_option, true); @@ -1058,6 +1052,17 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on) } } + if (snode->led_en_pinctrl) { + pr_debug("Selecting active state for %s\n", snode->cdev.name); + rc = pinctrl_select_state(snode->led_en_pinctrl, + snode->gpio_state_active); + if (rc < 0) { + pr_err("failed to select pinctrl active state rc=%d\n", + rc); + return rc; + } + } + if (led->enable == 0) { rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_MOD_CTRL(led->base), @@ -1460,6 +1465,20 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, } fnode->trigger = (strobe_sel << 2) | (edge_trigger << 1) | active_high; + rc = led_classdev_register(&led->pdev->dev, &fnode->cdev); + if (rc < 0) { + pr_err("Unable to register led node %d\n", fnode->id); + return rc; + } + + fnode->cdev.dev->of_node = node; + fnode->strobe_pinctrl = devm_pinctrl_get(fnode->cdev.dev); + if (IS_ERR_OR_NULL(fnode->strobe_pinctrl)) { + pr_debug("No pinctrl defined for %s, err=%ld\n", + fnode->cdev.name, PTR_ERR(fnode->strobe_pinctrl)); + fnode->strobe_pinctrl = NULL; + } + if (fnode->trigger & FLASH_LED_HW_SW_STROBE_SEL_BIT) { if (of_find_property(node, "qcom,hw-strobe-gpio", NULL)) { fnode->hw_strobe_gpio = of_get_named_gpio(node, @@ -1469,11 +1488,11 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, return fnode->hw_strobe_gpio; } gpio_direction_output(fnode->hw_strobe_gpio, 0); - } else { + } else if (fnode->strobe_pinctrl) { fnode->hw_strobe_gpio = -1; fnode->hw_strobe_state_active = - pinctrl_lookup_state(fnode->pinctrl, - "strobe_enable"); + pinctrl_lookup_state(fnode->strobe_pinctrl, + "strobe_enable"); if (IS_ERR_OR_NULL(fnode->hw_strobe_state_active)) { pr_err("No active pin for hardware strobe, rc=%ld\n", PTR_ERR(fnode->hw_strobe_state_active)); @@ -1481,8 +1500,8 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, } fnode->hw_strobe_state_suspend = - pinctrl_lookup_state(fnode->pinctrl, - "strobe_disable"); + pinctrl_lookup_state(fnode->strobe_pinctrl, + "strobe_disable"); if (IS_ERR_OR_NULL(fnode->hw_strobe_state_suspend)) { pr_err("No suspend pin for hardware strobe, rc=%ld\n", PTR_ERR(fnode->hw_strobe_state_suspend) @@ -1492,38 +1511,6 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, } } - rc = led_classdev_register(&led->pdev->dev, &fnode->cdev); - if (rc < 0) { - pr_err("Unable to register led node %d\n", fnode->id); - return rc; - } - - fnode->cdev.dev->of_node = node; - - fnode->pinctrl = devm_pinctrl_get(fnode->cdev.dev); - if (IS_ERR_OR_NULL(fnode->pinctrl)) { - pr_debug("No pinctrl defined\n"); - fnode->pinctrl = NULL; - } else { - fnode->gpio_state_active = - pinctrl_lookup_state(fnode->pinctrl, "led_enable"); - if (IS_ERR_OR_NULL(fnode->gpio_state_active)) { - pr_err("Cannot lookup LED active state\n"); - devm_pinctrl_put(fnode->pinctrl); - fnode->pinctrl = NULL; - return PTR_ERR(fnode->gpio_state_active); - } - - fnode->gpio_state_suspend = - pinctrl_lookup_state(fnode->pinctrl, "led_disable"); - if (IS_ERR_OR_NULL(fnode->gpio_state_suspend)) { - pr_err("Cannot lookup LED disable state\n"); - devm_pinctrl_put(fnode->pinctrl); - fnode->pinctrl = NULL; - return PTR_ERR(fnode->gpio_state_suspend); - } - } - return 0; } @@ -1588,6 +1575,36 @@ static int qpnp_flash_led_parse_and_register_switch(struct qpnp_flash_led *led, } snode->cdev.dev->of_node = node; + + snode->led_en_pinctrl = devm_pinctrl_get(snode->cdev.dev); + if (IS_ERR_OR_NULL(snode->led_en_pinctrl)) { + pr_debug("No pinctrl defined for %s, err=%ld\n", + snode->cdev.name, PTR_ERR(snode->led_en_pinctrl)); + snode->led_en_pinctrl = NULL; + } + + if (snode->led_en_pinctrl) { + snode->gpio_state_active = + pinctrl_lookup_state(snode->led_en_pinctrl, + "led_enable"); + if (IS_ERR_OR_NULL(snode->gpio_state_active)) { + pr_err("Cannot lookup LED active state\n"); + devm_pinctrl_put(snode->led_en_pinctrl); + snode->led_en_pinctrl = NULL; + return PTR_ERR(snode->gpio_state_active); + } + + snode->gpio_state_suspend = + pinctrl_lookup_state(snode->led_en_pinctrl, + "led_disable"); + if (IS_ERR_OR_NULL(snode->gpio_state_suspend)) { + pr_err("Cannot lookup LED disable state\n"); + devm_pinctrl_put(snode->led_en_pinctrl); + snode->led_en_pinctrl = NULL; + return PTR_ERR(snode->gpio_state_suspend); + } + } + return 0; } @@ -2094,22 +2111,24 @@ static int qpnp_flash_led_probe(struct platform_device *pdev) if (!strcmp("flash", temp_string) || !strcmp("torch", temp_string)) { rc = qpnp_flash_led_parse_each_led_dt(led, - &led->fnode[i++], temp); + &led->fnode[i], temp); if (rc < 0) { pr_err("Unable to parse flash node %d rc=%d\n", i, rc); goto error_led_register; } + i++; } if (!strcmp("switch", temp_string)) { rc = qpnp_flash_led_parse_and_register_switch(led, - &led->snode[j++], temp); + &led->snode[j], temp); if (rc < 0) { pr_err("Unable to parse and register switch node, rc=%d\n", rc); goto error_switch_register; } + j++; } } diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c index f2f3388b41c1..737433209c2b 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c @@ -509,6 +509,14 @@ static int vfe_probe(struct platform_device *pdev) for (i = 0; i < (MSM_ISP_STATS_MAX * MAX_VFE); i++) spin_lock_init(&(vfe_common_data.stats_streams[i].lock)); + for (i = 0; i <= MAX_VFE; i++) { + INIT_LIST_HEAD(&vfe_common_data.tasklets[i].tasklet_q); + tasklet_init(&vfe_common_data.tasklets[i].tasklet, + msm_isp_do_tasklet, + (unsigned long)(&vfe_common_data.tasklets[i])); + spin_lock_init(&vfe_common_data.tasklets[i].tasklet_lock); + } + of_property_read_u32(pdev->dev.of_node, "num_child", &vfe_parent_dev->num_hw_sd); @@ -615,10 +623,6 @@ int vfe_hw_probe(struct platform_device *pdev) goto probe_fail3; } - INIT_LIST_HEAD(&vfe_dev->tasklet_q); - tasklet_init(&vfe_dev->vfe_tasklet, - msm_isp_do_tasklet, (unsigned long)vfe_dev); - v4l2_subdev_init(&vfe_dev->subdev.sd, &msm_vfe_v4l2_subdev_ops); vfe_dev->subdev.sd.internal_ops = &msm_vfe_subdev_internal_ops; @@ -631,7 +635,6 @@ int vfe_hw_probe(struct platform_device *pdev) platform_set_drvdata(pdev, &vfe_dev->subdev.sd); mutex_init(&vfe_dev->realtime_mutex); mutex_init(&vfe_dev->core_mutex); - spin_lock_init(&vfe_dev->tasklet_lock); spin_lock_init(&vfe_dev->shared_data_lock); spin_lock_init(&vfe_dev->reg_update_lock); spin_lock_init(&req_history_lock); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h index 45c2dd588bc9..139a4c9b49ee 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h @@ -596,6 +596,7 @@ struct msm_vfe_tasklet_queue_cmd { uint32_t vfeInterruptStatus1; struct msm_isp_timestamp ts; uint8_t cmd_used; + struct vfe_device *vfe_dev; }; #define MSM_VFE_TASKLETQ_SIZE 200 @@ -720,6 +721,15 @@ struct msm_vfe_irq_dump { tasklet_debug[MAX_VFE_IRQ_DEBUG_DUMP_SIZE]; }; +struct msm_vfe_tasklet { + spinlock_t tasklet_lock; + uint8_t taskletq_idx; + struct list_head tasklet_q; + struct tasklet_struct tasklet; + struct msm_vfe_tasklet_queue_cmd + tasklet_queue_cmd[MSM_VFE_TASKLETQ_SIZE]; +}; + struct msm_vfe_common_dev_data { spinlock_t common_dev_data_lock; struct dual_vfe_resource *dual_vfe_res; @@ -729,6 +739,7 @@ struct msm_vfe_common_dev_data { struct mutex vfe_common_mutex; /* Irq debug Info */ struct msm_vfe_irq_dump vfe_irq_dump; + struct msm_vfe_tasklet tasklets[MAX_VFE + 1]; }; struct msm_vfe_common_subdev { @@ -781,15 +792,9 @@ struct vfe_device { struct mutex core_mutex; spinlock_t shared_data_lock; spinlock_t reg_update_lock; - spinlock_t tasklet_lock; /* Tasklet info */ atomic_t irq_cnt; - uint8_t taskletq_idx; - struct list_head tasklet_q; - struct tasklet_struct vfe_tasklet; - struct msm_vfe_tasklet_queue_cmd - tasklet_queue_cmd[MSM_VFE_TASKLETQ_SIZE]; /* Data structures */ struct msm_vfe_hardware_info *hw_info; @@ -802,7 +807,6 @@ struct vfe_device { /* State variables */ uint32_t vfe_hw_version; - int vfe_clk_idx; uint32_t vfe_open_cnt; uint8_t vt_enable; uint32_t vfe_ub_policy; @@ -819,7 +823,6 @@ struct vfe_device { struct msm_isp_statistics *stats; uint64_t msm_isp_last_overflow_ab; uint64_t msm_isp_last_overflow_ib; - uint32_t msm_isp_vfe_clk_rate; struct msm_isp_ub_info *ub_info; uint32_t isp_sof_debug; uint32_t isp_raw0_debug; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c index 9c74695a6e32..a66ca7e93537 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c @@ -281,9 +281,11 @@ int msm_isp47_ahb_clk_cfg(struct vfe_device *vfe_dev, vfe_dev->hw_info->vfe_ops.platform_ops.get_clk_rates(vfe_dev, &clk_rates); - if (vfe_dev->msm_isp_vfe_clk_rate <= clk_rates.svs_rate) + if (vfe_dev->vfe_clk_info[vfe_dev->hw_info->vfe_clk_idx].clk_rate <= + clk_rates.svs_rate) src_clk_vote = CAM_AHB_SVS_VOTE; - else if (vfe_dev->msm_isp_vfe_clk_rate <= clk_rates.nominal_rate) + else if (vfe_dev->vfe_clk_info[vfe_dev->hw_info->vfe_clk_idx].clk_rate + <= clk_rates.nominal_rate) src_clk_vote = CAM_AHB_NOMINAL_VOTE; else src_clk_vote = CAM_AHB_TURBO_VOTE; @@ -365,7 +367,8 @@ void msm_vfe47_release_hardware(struct vfe_device *vfe_dev) vfe_dev->irq0_mask, vfe_dev->irq1_mask, MSM_ISP_IRQ_SET); msm_camera_enable_irq(vfe_dev->vfe_irq, 0); - tasklet_kill(&vfe_dev->vfe_tasklet); + tasklet_kill(&(vfe_dev->common_data->tasklets[vfe_dev->pdev->id]. + tasklet)); msm_isp_flush_tasklet(vfe_dev); vfe_dev->common_data->dual_vfe_res->vfe_base[vfe_dev->pdev->id] = NULL; @@ -1400,7 +1403,7 @@ void msm_vfe47_cfg_camif(struct vfe_device *vfe_dev, if (subsample_period && subsample_pattern) { val = msm_camera_io_r(vfe_dev->vfe_base + 0x494); val &= 0xFFFFE0FF; - val = (subsample_period - 1) << 8; + val |= (subsample_period - 1) << 8; msm_camera_io_w(val, vfe_dev->vfe_base + 0x494); ISP_DBG("%s:camif PERIOD %x PATTERN %x\n", __func__, subsample_period, subsample_pattern); @@ -2595,17 +2598,19 @@ int msm_vfe47_set_clk_rate(struct vfe_device *vfe_dev, long *rate) long clk_rate, prev_clk_rate; clk_rate = clk_round_rate(vfe_dev->vfe_clk[clk_idx], *rate); - if (vfe_dev->msm_isp_vfe_clk_rate == clk_rate) + if (vfe_dev->vfe_clk_info[clk_idx].clk_rate == clk_rate) return rc; - prev_clk_rate = vfe_dev->msm_isp_vfe_clk_rate; - vfe_dev->msm_isp_vfe_clk_rate = clk_rate; + prev_clk_rate = + vfe_dev->vfe_clk_info[clk_idx].clk_rate; + vfe_dev->vfe_clk_info[clk_idx].clk_rate = + clk_rate; /* * if cx_ipeak is supported vote first so that dsp throttling is * reduced before we go to turbo */ if ((vfe_dev->vfe_cx_ipeak) && - (vfe_dev->msm_isp_vfe_clk_rate >= + (vfe_dev->vfe_clk_info[clk_idx].clk_rate >= vfe_dev->vfe_clk_rates[MSM_VFE_CLK_RATE_NOMINAL] [vfe_dev->hw_info->vfe_clk_idx]) && prev_clk_rate < @@ -2628,7 +2633,7 @@ int msm_vfe47_set_clk_rate(struct vfe_device *vfe_dev, long *rate) * if voting done earlier */ if ((vfe_dev->vfe_cx_ipeak) && - (vfe_dev->msm_isp_vfe_clk_rate < + (vfe_dev->vfe_clk_info[clk_idx].clk_rate < vfe_dev->vfe_clk_rates[MSM_VFE_CLK_RATE_NOMINAL] [vfe_dev->hw_info->vfe_clk_idx]) && prev_clk_rate >= diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c index b44b7573e0e6..ebd3a32281d7 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c @@ -1136,7 +1136,8 @@ static void msm_isp_calculate_bandwidth( axi_data = &vfe_dev->axi_data; if (stream_info->stream_src < RDI_INTF_0) { stream_info->bandwidth[i] = - (vfe_dev->msm_isp_vfe_clk_rate / + (vfe_dev->vfe_clk_info[ + vfe_dev->hw_info->vfe_clk_idx].clk_rate / axi_data->src_info[VFE_PIX_0].width) * stream_info->max_width[i]; stream_info->bandwidth[i] = @@ -1149,7 +1150,9 @@ static void msm_isp_calculate_bandwidth( stream_info->output_format); if (rdi < VFE_SRC_MAX) { stream_info->bandwidth[i] = - (vfe_dev->msm_isp_vfe_clk_rate / 8) * bpp; + (vfe_dev->vfe_clk_info[ + vfe_dev->hw_info->vfe_clk_idx].clk_rate / + 8) * bpp; } else { pr_err("%s: Invalid rdi interface\n", __func__); } diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c index f4e81c02208c..765bf6521759 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c @@ -166,7 +166,8 @@ void msm_isp_util_get_bandwidth_stats(struct vfe_device *vfe_dev, stats->isp_cpp_ib = isp_bandwidth_mgr.client_info[ISP_CPP].ib; stats->last_overflow_ab = vfe_dev->msm_isp_last_overflow_ab; stats->last_overflow_ib = vfe_dev->msm_isp_last_overflow_ib; - stats->vfe_clk_rate = vfe_dev->msm_isp_vfe_clk_rate; + stats->vfe_clk_rate = vfe_dev->vfe_clk_info[ + vfe_dev->hw_info->vfe_clk_idx].clk_rate; stats->cpp_clk_rate = msm_isp_cpp_clk_rate; } @@ -538,7 +539,8 @@ int msm_isp_cfg_input(struct vfe_device *vfe_dev, void *arg) * Only set rate to higher, do not lower higher * rate needed by another input */ - if (pixel_clock > vfe_dev->msm_isp_vfe_clk_rate) { + if (pixel_clock > vfe_dev->vfe_clk_info[ + vfe_dev->hw_info->vfe_clk_idx].clk_rate) { rc = vfe_dev->hw_info->vfe_ops.platform_ops.set_clk_rate( vfe_dev, &pixel_clock); @@ -2056,13 +2058,19 @@ static void msm_isp_enqueue_tasklet_cmd(struct vfe_device *vfe_dev, { unsigned long flags; struct msm_vfe_tasklet_queue_cmd *queue_cmd = NULL; + struct msm_vfe_tasklet *tasklet; - spin_lock_irqsave(&vfe_dev->tasklet_lock, flags); - queue_cmd = &vfe_dev->tasklet_queue_cmd[vfe_dev->taskletq_idx]; + if (vfe_dev->is_split) + tasklet = &vfe_dev->common_data->tasklets[MAX_VFE]; + else + tasklet = &vfe_dev->common_data->tasklets[vfe_dev->pdev->id]; + + spin_lock_irqsave(&tasklet->tasklet_lock, flags); + queue_cmd = &tasklet->tasklet_queue_cmd[tasklet->taskletq_idx]; if (queue_cmd->cmd_used) { - ISP_DBG("%s: Tasklet queue overflow: %d\n", + pr_err("%s: Tasklet queue overflow: %d\n", __func__, vfe_dev->pdev->id); - list_del(&queue_cmd->list); + return; } else { atomic_add(1, &vfe_dev->irq_cnt); } @@ -2071,11 +2079,13 @@ static void msm_isp_enqueue_tasklet_cmd(struct vfe_device *vfe_dev, msm_isp_get_timestamp(&queue_cmd->ts, vfe_dev); queue_cmd->cmd_used = 1; - vfe_dev->taskletq_idx = (vfe_dev->taskletq_idx + 1) % + queue_cmd->vfe_dev = vfe_dev; + + tasklet->taskletq_idx = (tasklet->taskletq_idx + 1) % MSM_VFE_TASKLETQ_SIZE; - list_add_tail(&queue_cmd->list, &vfe_dev->tasklet_q); - spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags); - tasklet_schedule(&vfe_dev->vfe_tasklet); + list_add_tail(&queue_cmd->list, &tasklet->tasklet_q); + spin_unlock_irqrestore(&tasklet->tasklet_lock, flags); + tasklet_schedule(&tasklet->tasklet); } irqreturn_t msm_isp_process_irq(int irq_num, void *data) @@ -2127,39 +2137,39 @@ irqreturn_t msm_isp_process_irq(int irq_num, void *data) void msm_isp_do_tasklet(unsigned long data) { unsigned long flags; - struct vfe_device *vfe_dev = (struct vfe_device *) data; - struct msm_vfe_irq_ops *irq_ops = &vfe_dev->hw_info->vfe_ops.irq_ops; + struct msm_vfe_tasklet *tasklet = (struct msm_vfe_tasklet *)data; + struct vfe_device *vfe_dev; + struct msm_vfe_irq_ops *irq_ops; struct msm_vfe_tasklet_queue_cmd *queue_cmd; struct msm_isp_timestamp ts; uint32_t irq_status0, irq_status1; - if (vfe_dev->vfe_base == NULL || vfe_dev->vfe_open_cnt == 0) { - ISP_DBG("%s: VFE%d open cnt = %d, device closed(base = %pK)\n", - __func__, vfe_dev->pdev->id, vfe_dev->vfe_open_cnt, - vfe_dev->vfe_base); - return; - } - - while (atomic_read(&vfe_dev->irq_cnt)) { - spin_lock_irqsave(&vfe_dev->tasklet_lock, flags); - queue_cmd = list_first_entry_or_null(&vfe_dev->tasklet_q, - struct msm_vfe_tasklet_queue_cmd, list); + while (1) { + spin_lock_irqsave(&tasklet->tasklet_lock, flags); + queue_cmd = list_first_entry_or_null(&tasklet->tasklet_q, + struct msm_vfe_tasklet_queue_cmd, list); if (!queue_cmd) { - atomic_set(&vfe_dev->irq_cnt, 0); - spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags); - return; + spin_unlock_irqrestore(&tasklet->tasklet_lock, flags); + break; } - atomic_sub(1, &vfe_dev->irq_cnt); - list_del(&queue_cmd->list); + list_del_init(&queue_cmd->list); + vfe_dev = queue_cmd->vfe_dev; queue_cmd->cmd_used = 0; + queue_cmd->vfe_dev = NULL; irq_status0 = queue_cmd->vfeInterruptStatus0; irq_status1 = queue_cmd->vfeInterruptStatus1; ts = queue_cmd->ts; - spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags); + spin_unlock_irqrestore(&tasklet->tasklet_lock, flags); + if (vfe_dev->vfe_open_cnt == 0) { + pr_err("%s: VFE%d open cnt = %d, irq %x/%x\n", + __func__, vfe_dev->pdev->id, vfe_dev->vfe_open_cnt, + irq_status0, irq_status1); + continue; + } + atomic_sub(1, &vfe_dev->irq_cnt); msm_isp_prepare_tasklet_debug_info(vfe_dev, irq_status0, irq_status1, ts); - ISP_DBG("%s: vfe_id %d status0: 0x%x status1: 0x%x\n", - __func__, vfe_dev->pdev->id, irq_status0, irq_status1); + irq_ops = &vfe_dev->hw_info->vfe_ops.irq_ops; irq_ops->process_reset_irq(vfe_dev, irq_status0, irq_status1); irq_ops->process_halt_irq(vfe_dev, @@ -2300,7 +2310,6 @@ int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) sizeof(vfe_dev->fetch_engine_info)); vfe_dev->axi_data.hw_info = vfe_dev->hw_info->axi_hw_info; vfe_dev->axi_data.enable_frameid_recovery = 0; - vfe_dev->taskletq_idx = 0; vfe_dev->vt_enable = 0; vfe_dev->reg_update_requested = 0; /* Register page fault handler */ @@ -2365,15 +2374,14 @@ int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) update_camif_state(vfe_dev, DISABLE_CAMIF_IMMEDIATELY); vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, 0, 0); - /* after regular hw stop, reduce open cnt */ - vfe_dev->vfe_open_cnt--; - /* put scratch buf in all the wm */ for (wm = 0; wm < vfe_dev->axi_data.hw_info->num_wm; wm++) { msm_isp_cfg_wm_scratch(vfe_dev, wm, VFE_PING_FLAG); msm_isp_cfg_wm_scratch(vfe_dev, wm, VFE_PONG_FLAG); } vfe_dev->hw_info->vfe_ops.core_ops.release_hw(vfe_dev); + /* after regular hw stop, reduce open cnt */ + vfe_dev->vfe_open_cnt--; vfe_dev->buf_mgr->ops->buf_mgr_deinit(vfe_dev->buf_mgr); if (vfe_dev->vt_enable) { msm_isp_end_avtimer(); @@ -2390,22 +2398,27 @@ int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) void msm_isp_flush_tasklet(struct vfe_device *vfe_dev) { unsigned long flags; - struct msm_vfe_tasklet_queue_cmd *queue_cmd; + int i; + struct msm_vfe_tasklet_queue_cmd *queue_cmd, *q_cmd_next; + struct msm_vfe_tasklet *tasklet; - spin_lock_irqsave(&vfe_dev->tasklet_lock, flags); - while (atomic_read(&vfe_dev->irq_cnt)) { - queue_cmd = list_first_entry(&vfe_dev->tasklet_q, - struct msm_vfe_tasklet_queue_cmd, list); - if (!queue_cmd) { - atomic_set(&vfe_dev->irq_cnt, 0); - break; + for (i = 0; i <= MAX_VFE; i++) { + if (i != vfe_dev->pdev->id && + i != MAX_VFE) + continue; + tasklet = &vfe_dev->common_data->tasklets[i]; + spin_lock_irqsave(&tasklet->tasklet_lock, flags); + list_for_each_entry_safe(queue_cmd, q_cmd_next, + &tasklet->tasklet_q, list) { + if (queue_cmd->vfe_dev != vfe_dev) + continue; + list_del_init(&queue_cmd->list); + queue_cmd->cmd_used = 0; } - atomic_sub(1, &vfe_dev->irq_cnt); - list_del(&queue_cmd->list); - queue_cmd->cmd_used = 0; + spin_unlock_irqrestore(&tasklet->tasklet_lock, flags); + tasklet_kill(&tasklet->tasklet); } - spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags); - tasklet_kill(&vfe_dev->vfe_tasklet); + atomic_set(&vfe_dev->irq_cnt, 0); return; } diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index 24eb8fff905b..953780e3c220 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -2587,6 +2587,12 @@ static int try_set_ext_ctrl(struct msm_vidc_inst *inst, int rc = 0, i = 0, fourcc = 0; struct v4l2_ext_control *ext_control; struct v4l2_control control; + u32 old_mode = 0; + bool mode_changed = false; + enum mode { + PRIMARY = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY, + SECONDARY = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY + }; if (!inst || !inst->core || !ctrl) { dprintk(VIDC_ERR, @@ -2595,19 +2601,21 @@ static int try_set_ext_ctrl(struct msm_vidc_inst *inst, } ext_control = ctrl->controls; - control.id = - V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE; + control.id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE; + old_mode = msm_comm_g_ctrl_for_id(inst, control.id); for (i = 0; i < ctrl->count; i++) { switch (ext_control[i].id) { case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE: control.value = ext_control[i].value; - rc = msm_comm_s_ctrl(inst, &control); if (rc) dprintk(VIDC_ERR, "%s Failed setting stream output mode : %d\n", __func__, rc); + + if (old_mode == SECONDARY && control.value == PRIMARY) + mode_changed = true; break; case V4L2_CID_MPEG_VIDC_VIDEO_DPB_COLOR_FORMAT: switch (ext_control[i].value) { @@ -2620,6 +2628,24 @@ static int try_set_ext_ctrl(struct msm_vidc_inst *inst, "%s Release output buffers failed\n", __func__); } + /* Update buffer reqmt for split to comb mode */ + if (mode_changed) { + fourcc = + inst->fmts[CAPTURE_PORT].fourcc; + msm_comm_set_color_format(inst, + HAL_BUFFER_OUTPUT, fourcc); + if (rc) { + dprintk(VIDC_ERR, + "%s Failed setting output color format : %d\n", + __func__, rc); + break; + } + rc = msm_comm_try_get_bufreqs(inst); + if (rc) + dprintk(VIDC_ERR, + "%s Failed to get buffer requirements : %d\n", + __func__, rc); + } break; case V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_UBWC: case V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_TP10_UBWC: diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index 8b459e4da618..7b28e80979f2 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -902,7 +902,7 @@ static int wait_for_sess_signal_receipt(struct msm_vidc_inst *inst, dprintk(VIDC_ERR, "sess resp timeout can potentially crash the system\n"); msm_comm_print_debug_info(inst); - BUG_ON(inst->core->resources.debug_timeout); + BUG_ON(msm_vidc_debug_timeout); msm_comm_kill_session(inst); rc = -EIO; } else { @@ -1748,7 +1748,7 @@ static void handle_sys_error(enum hal_command_response cmd, void *data) msm_comm_print_inst_info(inst); mutex_unlock(&core->lock); - BUG_ON(core->resources.debug_timeout); + BUG_ON(msm_vidc_debug_timeout); } void msm_comm_session_clean(struct msm_vidc_inst *inst) @@ -2543,7 +2543,7 @@ static int msm_comm_session_abort(struct msm_vidc_inst *inst) "ABORT timeout can potentially crash the system\n"); msm_comm_print_debug_info(inst); - BUG_ON(inst->core->resources.debug_timeout); + BUG_ON(msm_vidc_debug_timeout); rc = -EBUSY; } else { rc = 0; @@ -2645,7 +2645,7 @@ int msm_comm_check_core_init(struct msm_vidc_core *core) msm_comm_print_debug_info(inst); mutex_lock(&core->lock); - BUG_ON(core->resources.debug_timeout); + BUG_ON(msm_vidc_debug_timeout); rc = -EIO; goto exit; } else { @@ -4110,10 +4110,9 @@ int msm_comm_try_get_prop(struct msm_vidc_inst *inst, enum hal_property ptype, call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data); dprintk(VIDC_ERR, "SESS_PROP timeout can potentially crash the system\n"); - if (inst->core->resources.debug_timeout) - msm_comm_print_debug_info(inst); + msm_comm_print_debug_info(inst); - BUG_ON(inst->core->resources.debug_timeout); + BUG_ON(msm_vidc_debug_timeout); msm_comm_kill_session(inst); rc = -ETIMEDOUT; goto exit; diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c index a65e22c66e30..4cc977e568ee 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c @@ -1123,7 +1123,7 @@ int read_platform_resources_from_dt( res->debug_timeout = of_property_read_bool(pdev->dev.of_node, "qcom,debug-timeout"); - res->debug_timeout |= msm_vidc_debug_timeout; + msm_vidc_debug_timeout |= res->debug_timeout; of_property_read_u32(pdev->dev.of_node, "qcom,pm-qos-latency-us", &res->pm_qos_latency_us); diff --git a/drivers/mfd/wcd934x-regmap.c b/drivers/mfd/wcd934x-regmap.c index fbaf05e58aff..e8ba1495de2b 100644 --- a/drivers/mfd/wcd934x-regmap.c +++ b/drivers/mfd/wcd934x-regmap.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1926,6 +1926,19 @@ static bool wcd934x_is_volatile_register(struct device *dev, unsigned int reg) case WCD934X_ANA_MBHC_ELECT: case WCD934X_ANA_MBHC_ZDET: case WCD934X_ANA_MICB2: + case WCD934X_CODEC_RPM_CLK_MCLK_CFG: + case WCD934X_CLK_SYS_MCLK_PRG: + case WCD934X_CHIP_TIER_CTRL_EFUSE_CTL: + case WCD934X_ANA_BIAS: + case WCD934X_ANA_BUCK_CTL: + case WCD934X_ANA_RCO: + case WCD934X_CDC_CLK_RST_CTRL_MCLK_CONTROL: + case WCD934X_CODEC_RPM_CLK_GATE: + case WCD934X_BIAS_VBG_FINE_ADJ: + case WCD934X_CODEC_CPR_SVS_CX_VDD: + case WCD934X_CODEC_CPR_SVS2_CX_VDD: + case WCD934X_CDC_TOP_TOP_CFG1: + case WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL: return true; } diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 5d6c44b00bc2..e9f1a19dfe3f 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -2189,6 +2189,17 @@ static int mmc_blk_err_check(struct mmc_card *card, int need_retune = card->host->need_retune; int ecc_err = 0, gen_err = 0; + if (card->host->sdr104_wa && mmc_card_sd(card) && + (card->host->ios.timing == MMC_TIMING_UHS_SDR104) && + !card->sdr104_blocked && + (brq->data.error == -EILSEQ || + brq->data.error == -EIO || + brq->data.error == -ETIMEDOUT || + brq->cmd.error == -EILSEQ || + brq->cmd.error == -EIO || + brq->cmd.error == -ETIMEDOUT)) + card->err_in_sdr104 = true; + /* * sbc.error indicates a problem with the set block count * command. No data will have been transferred. @@ -3645,6 +3656,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) struct mmc_async_req *areq; const u8 packed_nr = 2; u8 reqs = 0; + bool reset = false; #ifdef CONFIG_MMC_SIMULATE_MAX_SPEED unsigned long waitfor = jiffies; #endif @@ -3690,6 +3702,26 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) type = rq_data_dir(req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE; mmc_queue_bounce_post(mq_rq); + if (card->err_in_sdr104) { + /* + * Data CRC/timeout errors will manifest as CMD/DATA + * ERR. But we'd like to retry these too. + * Moreover, no harm done if this fails too for multiple + * times, we anyway reduce the bus-speed and retry the + * same request. + * If that fails too, we don't override this status. + */ + if (status == MMC_BLK_ABORT || + status == MMC_BLK_CMD_ERR || + status == MMC_BLK_DATA_ERR || + status == MMC_BLK_RETRY) + /* reset on all of these errors and retry */ + reset = true; + + status = MMC_BLK_RETRY; + card->err_in_sdr104 = false; + } + switch (status) { case MMC_BLK_SUCCESS: case MMC_BLK_PARTIAL: @@ -3730,8 +3762,32 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) break; case MMC_BLK_RETRY: retune_retry_done = brq->retune_retry_done; - if (retry++ < MMC_BLK_MAX_RETRIES) + if (retry++ < MMC_BLK_MAX_RETRIES) { break; + } else if (reset) { + reset = false; + /* + * If we exhaust all the retries due to + * CRC/timeout errors in SDR140 mode with UHS SD + * cards, re-configure the card in SDR50 + * bus-speed mode. + * All subsequent re-init of this card will be + * in SDR50 mode, unless it is removed and + * re-inserted. When new UHS SD cards are + * inserted, it may start at SDR104 mode if + * supported by the card. + */ + pr_err("%s: blocked SDR104, lower the bus-speed (SDR50 / DDR50)\n", + req->rq_disk->disk_name); + mmc_host_clear_sdr104(card->host); + mmc_suspend_clk_scaling(card->host); + mmc_blk_reset(md, card->host, type); + /* SDR104 mode is blocked from now on */ + card->sdr104_blocked = true; + /* retry 5 times again */ + retry = 0; + break; + } /* Fall through */ case MMC_BLK_ABORT: if (!mmc_blk_reset(md, card->host, type) && diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index ec6075ec5767..311f6d639d06 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -428,7 +428,6 @@ void mmc_remove_card(struct mmc_card *card) } kfree(card->wr_pack_stats.packing_events); - kfree(card->cached_ext_csd); put_device(&card->dev); } diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 5396e1d00178..41f0935440fd 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2126,6 +2126,7 @@ int mmc_try_claim_host(struct mmc_host *host, unsigned int delay_ms) int claimed_host = 0; unsigned long flags; int retry_cnt = delay_ms/10; + bool pm = false; do { spin_lock_irqsave(&host->lock, flags); @@ -2134,11 +2135,17 @@ int mmc_try_claim_host(struct mmc_host *host, unsigned int delay_ms) host->claimer = current; host->claim_cnt += 1; claimed_host = 1; + if (host->claim_cnt == 1) + pm = true; } spin_unlock_irqrestore(&host->lock, flags); if (!claimed_host) mmc_delay(10); } while (!claimed_host && retry_cnt--); + + if (pm) + pm_runtime_get_sync(mmc_dev(host)); + if (host->ops->enable && claimed_host && host->claim_cnt == 1) host->ops->enable(host); return claimed_host; @@ -4033,6 +4040,10 @@ int _mmc_detect_card_removed(struct mmc_host *host) if (ret) { mmc_card_set_removed(host->card); + if (host->card->sdr104_blocked) { + mmc_host_set_sdr104(host); + host->card->sdr104_blocked = false; + } pr_debug("%s: card remove detected\n", mmc_hostname(host)); } diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 1116544eebc1..c66187299598 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -80,7 +80,6 @@ void mmc_init_context_info(struct mmc_host *host); extern bool mmc_can_scale_clk(struct mmc_host *host); extern int mmc_init_clk_scaling(struct mmc_host *host); -extern int mmc_suspend_clk_scaling(struct mmc_host *host); extern int mmc_resume_clk_scaling(struct mmc_host *host); extern int mmc_exit_clk_scaling(struct mmc_host *host); extern unsigned long mmc_get_max_frequency(struct mmc_host *host); diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 542f1733d0dd..5ab09b4ae868 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -722,7 +722,6 @@ static int mmc_read_ext_csd(struct mmc_card *card) return err; } - card->cached_ext_csd = ext_csd; err = mmc_decode_ext_csd(card, ext_csd); kfree(ext_csd); return err; diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index ec5ce79e84e7..5b4d5d74fe55 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -433,26 +433,26 @@ static void sd_update_bus_speed_mode(struct mmc_card *card) if ((card->host->caps & MMC_CAP_UHS_SDR104) && (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104) && (card->host->f_max > UHS_SDR104_MIN_DTR)) { - card->sd_bus_speed = UHS_SDR104_BUS_SPEED; - } else if ((card->host->caps & MMC_CAP_UHS_DDR50) && - (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50) && - (card->host->f_max > UHS_DDR50_MIN_DTR)) { - card->sd_bus_speed = UHS_DDR50_BUS_SPEED; + card->sd_bus_speed = UHS_SDR104_BUS_SPEED; } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR50) && (card->host->f_max > UHS_SDR50_MIN_DTR)) { - card->sd_bus_speed = UHS_SDR50_BUS_SPEED; + card->sd_bus_speed = UHS_SDR50_BUS_SPEED; + } else if ((card->host->caps & MMC_CAP_UHS_DDR50) && + (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50) && + (card->host->f_max > UHS_DDR50_MIN_DTR)) { + card->sd_bus_speed = UHS_DDR50_BUS_SPEED; } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) && (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25) && (card->host->f_max > UHS_SDR25_MIN_DTR)) { - card->sd_bus_speed = UHS_SDR25_BUS_SPEED; + card->sd_bus_speed = UHS_SDR25_BUS_SPEED; } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR12)) { - card->sd_bus_speed = UHS_SDR12_BUS_SPEED; + card->sd_bus_speed = UHS_SDR12_BUS_SPEED; } } @@ -1285,6 +1285,8 @@ static int _mmc_sd_resume(struct mmc_host *host) #endif mmc_card_clr_suspended(host->card); + if (host->card->sdr104_blocked) + goto out; err = mmc_resume_clk_scaling(host); if (err) { pr_err("%s: %s: fail to resume clock scaling (%d)\n", diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 2eaac11ec8ba..987d61bdda2d 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -1960,6 +1960,8 @@ struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev, if (of_get_property(np, "qcom,core_3_0v_support", NULL)) pdata->core_3_0v_support = true; + pdata->sdr104_wa = of_property_read_bool(np, "qcom,sdr104-wa"); + return pdata; out: return NULL; @@ -4579,6 +4581,7 @@ static int sdhci_msm_probe(struct platform_device *pdev) if (msm_host->pdata->nonhotplug) msm_host->mmc->caps2 |= MMC_CAP2_NONHOTPLUG; + msm_host->mmc->sdr104_wa = msm_host->pdata->sdr104_wa; /* Initialize ICE if present */ if (msm_host->ice.pdev) { diff --git a/drivers/mmc/host/sdhci-msm.h b/drivers/mmc/host/sdhci-msm.h index 2e4f2179378e..92f61708001e 100644 --- a/drivers/mmc/host/sdhci-msm.h +++ b/drivers/mmc/host/sdhci-msm.h @@ -153,6 +153,7 @@ struct sdhci_msm_pltfm_data { u32 ice_clk_min; struct sdhci_msm_pm_qos_data pm_qos_data; bool core_3_0v_support; + bool sdr104_wa; }; struct sdhci_msm_bus_vote { diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 44633dc5d2be..40a34c283955 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3083,7 +3083,10 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) mmc_hostname(host->mmc), intmask, host->data->error, ktime_to_ms(ktime_sub( ktime_get(), host->data_start_time))); - sdhci_dumpregs(host); + + if (!host->mmc->sdr104_wa || + (host->mmc->ios.timing != MMC_TIMING_UHS_SDR104)) + sdhci_dumpregs(host); } sdhci_finish_data(host); } else { diff --git a/drivers/net/ethernet/msm/msm_rmnet_mhi.c b/drivers/net/ethernet/msm/msm_rmnet_mhi.c index bf6502e27bdd..015cb99d445b 100644 --- a/drivers/net/ethernet/msm/msm_rmnet_mhi.c +++ b/drivers/net/ethernet/msm/msm_rmnet_mhi.c @@ -35,6 +35,7 @@ #define MHI_NAPI_WEIGHT_VALUE 12 #define WATCHDOG_TIMEOUT (30 * HZ) #define RMNET_IPC_LOG_PAGES (100) +#define IRQ_MASKED_BIT (0) enum DBG_LVL { MSG_VERBOSE = 0x1, @@ -100,14 +101,15 @@ struct rmnet_mhi_private { u32 mhi_enabled; struct platform_device *pdev; struct net_device *dev; - atomic_t irq_masked_cntr; + unsigned long flags; + int wake_count; spinlock_t out_chan_full_lock; /* tx queue lock */ - atomic_t pending_data; struct sk_buff *frag_skb; struct work_struct alloc_work; /* lock to queue hardware and internal queue */ spinlock_t alloc_lock; void *rmnet_ipc_log; + rwlock_t pm_lock; /* state change lock */ struct debug_params debug; struct dentry *dentry; }; @@ -130,12 +132,12 @@ static int rmnet_mhi_process_fragment(struct rmnet_mhi_private *rmnet_mhi_ptr, rmnet_mhi_ptr->frag_skb = NULL; return -ENOMEM; } - kfree_skb(rmnet_mhi_ptr->frag_skb); + dev_kfree_skb_any(rmnet_mhi_ptr->frag_skb); rmnet_mhi_ptr->frag_skb = temp_skb; memcpy(skb_put(rmnet_mhi_ptr->frag_skb, skb->len), skb->data, skb->len); - kfree_skb(skb); + dev_kfree_skb_any(skb); if (!frag) { /* Last fragmented piece was received, ship it */ netif_receive_skb(rmnet_mhi_ptr->frag_skb); @@ -196,7 +198,6 @@ static int rmnet_alloc_rx(struct rmnet_mhi_private *rmnet_mhi_ptr, { u32 cur_mru = rmnet_mhi_ptr->mru; struct mhi_skb_priv *skb_priv; - unsigned long flags; int ret; struct sk_buff *skb; @@ -215,7 +216,7 @@ static int rmnet_alloc_rx(struct rmnet_mhi_private *rmnet_mhi_ptr, skb_priv->dma_addr = 0; /* These steps must be in atomic context */ - spin_lock_irqsave(&rmnet_mhi_ptr->alloc_lock, flags); + spin_lock_bh(&rmnet_mhi_ptr->alloc_lock); /* It's possible by the time alloc_skb (GFP_KERNEL) * returns we already called rmnet_alloc_rx @@ -224,14 +225,22 @@ static int rmnet_alloc_rx(struct rmnet_mhi_private *rmnet_mhi_ptr, */ if (unlikely(atomic_read(&rmnet_mhi_ptr->rx_pool_len) >= rmnet_mhi_ptr->rx_buffers_max)) { - spin_unlock_irqrestore(&rmnet_mhi_ptr->alloc_lock, - flags); + spin_unlock_bh(&rmnet_mhi_ptr->alloc_lock); dev_kfree_skb_any(skb); return 0; } - ret = mhi_queue_xfer( - rmnet_mhi_ptr->rx_client_handle, + read_lock_bh(&rmnet_mhi_ptr->pm_lock); + if (unlikely(!rmnet_mhi_ptr->mhi_enabled)) { + rmnet_log(rmnet_mhi_ptr, MSG_INFO, + "!interface is disabled\n"); + dev_kfree_skb_any(skb); + read_unlock_bh(&rmnet_mhi_ptr->pm_lock); + spin_unlock_bh(&rmnet_mhi_ptr->alloc_lock); + return -EIO; + } + + ret = mhi_queue_xfer(rmnet_mhi_ptr->rx_client_handle, skb->data, skb_priv->dma_size, MHI_EOT); @@ -239,14 +248,15 @@ static int rmnet_alloc_rx(struct rmnet_mhi_private *rmnet_mhi_ptr, rmnet_log(rmnet_mhi_ptr, MSG_CRITICAL, "mhi_queue_xfer failed, error %d", ret); - spin_unlock_irqrestore(&rmnet_mhi_ptr->alloc_lock, - flags); + read_unlock_bh(&rmnet_mhi_ptr->pm_lock); + spin_unlock_bh(&rmnet_mhi_ptr->alloc_lock); dev_kfree_skb_any(skb); return ret; } skb_queue_tail(&rmnet_mhi_ptr->rx_buffers, skb); atomic_inc(&rmnet_mhi_ptr->rx_pool_len); - spin_unlock_irqrestore(&rmnet_mhi_ptr->alloc_lock, flags); + read_unlock_bh(&rmnet_mhi_ptr->pm_lock); + spin_unlock_bh(&rmnet_mhi_ptr->alloc_lock); } return 0; @@ -258,13 +268,25 @@ static void rmnet_mhi_alloc_work(struct work_struct *work) struct rmnet_mhi_private, alloc_work); int ret; + /* sleep about 1 sec and retry, that should be enough time + * for system to reclaim freed memory back. + */ + const int sleep_ms = 1000; + int retry = 60; rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Entered\n"); - ret = rmnet_alloc_rx(rmnet_mhi_ptr, - rmnet_mhi_ptr->allocation_flags); + do { + ret = rmnet_alloc_rx(rmnet_mhi_ptr, + rmnet_mhi_ptr->allocation_flags); + /* sleep and try again */ + if (ret == -ENOMEM) { + msleep(sleep_ms); + retry--; + } + } while (ret == -ENOMEM && retry); - WARN_ON(ret == -ENOMEM); - rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Exit\n"); + rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Exit with status:%d retry:%d\n", + ret, retry); } static int rmnet_mhi_poll(struct napi_struct *napi, int budget) @@ -281,6 +303,12 @@ static int rmnet_mhi_poll(struct napi_struct *napi, int budget) rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Entered\n"); + read_lock_bh(&rmnet_mhi_ptr->pm_lock); + if (unlikely(!rmnet_mhi_ptr->mhi_enabled)) { + rmnet_log(rmnet_mhi_ptr, MSG_INFO, "interface is disabled!\n"); + read_unlock_bh(&rmnet_mhi_ptr->pm_lock); + return 0; + } while (received_packets < budget) { struct mhi_result *result = mhi_poll(rmnet_mhi_ptr->rx_client_handle); @@ -338,77 +366,50 @@ static int rmnet_mhi_poll(struct napi_struct *napi, int budget) dev->stats.rx_bytes += result->bytes_xferd; } /* while (received_packets < budget) or any other error */ + read_unlock_bh(&rmnet_mhi_ptr->pm_lock); /* Queue new buffers */ res = rmnet_alloc_rx(rmnet_mhi_ptr, GFP_ATOMIC); - if (res == -ENOMEM) { - rmnet_log(rmnet_mhi_ptr, - MSG_INFO, - "out of mem, queuing bg worker\n"); - rmnet_mhi_ptr->alloc_fail++; - schedule_work(&rmnet_mhi_ptr->alloc_work); - } - napi_complete(napi); + read_lock_bh(&rmnet_mhi_ptr->pm_lock); + if (likely(rmnet_mhi_ptr->mhi_enabled)) { + if (res == -ENOMEM) { + rmnet_log(rmnet_mhi_ptr, MSG_INFO, + "out of mem, queuing bg worker\n"); + rmnet_mhi_ptr->alloc_fail++; + schedule_work(&rmnet_mhi_ptr->alloc_work); + } + + napi_complete(napi); - /* We got a NULL descriptor back */ - if (should_reschedule == false) { - if (atomic_read(&rmnet_mhi_ptr->irq_masked_cntr)) { - atomic_dec(&rmnet_mhi_ptr->irq_masked_cntr); - mhi_unmask_irq(rmnet_mhi_ptr->rx_client_handle); + /* We got a NULL descriptor back */ + if (!should_reschedule) { + if (test_and_clear_bit(IRQ_MASKED_BIT, + &rmnet_mhi_ptr->flags)) + mhi_unmask_irq(rmnet_mhi_ptr->rx_client_handle); mhi_set_lpm(rmnet_mhi_ptr->rx_client_handle, true); + rmnet_mhi_ptr->wake_count--; + } else { + if (received_packets == budget) + rmnet_mhi_ptr->debug.rx_napi_budget_overflow++; + napi_reschedule(napi); } - } else { - if (received_packets == budget) - rmnet_mhi_ptr->debug.rx_napi_budget_overflow++; - napi_reschedule(napi); - } - rmnet_mhi_ptr->debug.rx_napi_skb_burst_min = - min((u64)received_packets, - rmnet_mhi_ptr->debug.rx_napi_skb_burst_min); + rmnet_mhi_ptr->debug.rx_napi_skb_burst_min = + min((u64)received_packets, + rmnet_mhi_ptr->debug.rx_napi_skb_burst_min); - rmnet_mhi_ptr->debug.rx_napi_skb_burst_max = - max((u64)received_packets, - rmnet_mhi_ptr->debug.rx_napi_skb_burst_max); + rmnet_mhi_ptr->debug.rx_napi_skb_burst_max = + max((u64)received_packets, + rmnet_mhi_ptr->debug.rx_napi_skb_burst_max); + } + read_unlock_bh(&rmnet_mhi_ptr->pm_lock); rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Exited, polled %d pkts\n", received_packets); return received_packets; } -void rmnet_mhi_clean_buffers(struct net_device *dev) -{ - struct rmnet_mhi_private *rmnet_mhi_ptr = - *(struct rmnet_mhi_private **)netdev_priv(dev); - - rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Entered\n"); - /* Clean TX buffers */ - rmnet_mhi_internal_clean_unmap_buffers(dev, - &rmnet_mhi_ptr->tx_buffers, - DMA_TO_DEVICE); - - /* Clean RX buffers */ - rmnet_mhi_internal_clean_unmap_buffers(dev, - &rmnet_mhi_ptr->rx_buffers, - DMA_FROM_DEVICE); - rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Exited\n"); -} - -static int rmnet_mhi_disable_channels(struct rmnet_mhi_private *rmnet_mhi_ptr) -{ - rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Closing MHI TX channel\n"); - mhi_close_channel(rmnet_mhi_ptr->tx_client_handle); - rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Closing MHI RX channel\n"); - mhi_close_channel(rmnet_mhi_ptr->rx_client_handle); - rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Clearing Pending TX buffers.\n"); - rmnet_mhi_clean_buffers(rmnet_mhi_ptr->dev); - rmnet_mhi_ptr->tx_client_handle = NULL; - rmnet_mhi_ptr->rx_client_handle = NULL; - - return 0; -} - static int rmnet_mhi_init_inbound(struct rmnet_mhi_private *rmnet_mhi_ptr) { int res; @@ -431,7 +432,7 @@ static void rmnet_mhi_tx_cb(struct mhi_result *result) struct net_device *dev; struct rmnet_mhi_private *rmnet_mhi_ptr; unsigned long burst_counter = 0; - unsigned long flags; + unsigned long flags, pm_flags; rmnet_mhi_ptr = result->user_data; dev = rmnet_mhi_ptr->dev; @@ -451,10 +452,10 @@ static void rmnet_mhi_tx_cb(struct mhi_result *result) break; } else { if (skb->data == result->buf_addr) { - kfree_skb(skb); + dev_kfree_skb_any(skb); break; } - kfree_skb(skb); + dev_kfree_skb_any(skb); burst_counter++; /* Update statistics */ @@ -477,10 +478,15 @@ static void rmnet_mhi_tx_cb(struct mhi_result *result) rmnet_mhi_ptr->debug.tx_cb_skb_free_burst_max); /* In case we couldn't write again, now we can! */ - spin_lock_irqsave(&rmnet_mhi_ptr->out_chan_full_lock, flags); - rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Waking up queue\n"); - netif_wake_queue(dev); - spin_unlock_irqrestore(&rmnet_mhi_ptr->out_chan_full_lock, flags); + read_lock_irqsave(&rmnet_mhi_ptr->pm_lock, pm_flags); + if (likely(rmnet_mhi_ptr->mhi_enabled)) { + spin_lock_irqsave(&rmnet_mhi_ptr->out_chan_full_lock, flags); + rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Waking up queue\n"); + netif_wake_queue(dev); + spin_unlock_irqrestore(&rmnet_mhi_ptr->out_chan_full_lock, + flags); + } + read_unlock_irqrestore(&rmnet_mhi_ptr->pm_lock, pm_flags); rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Exited\n"); } @@ -488,20 +494,27 @@ static void rmnet_mhi_rx_cb(struct mhi_result *result) { struct net_device *dev; struct rmnet_mhi_private *rmnet_mhi_ptr; + unsigned long flags; + rmnet_mhi_ptr = result->user_data; dev = rmnet_mhi_ptr->dev; rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Entered\n"); rmnet_mhi_ptr->debug.rx_interrupts_count++; - - if (napi_schedule_prep(&(rmnet_mhi_ptr->napi))) { - mhi_mask_irq(rmnet_mhi_ptr->rx_client_handle); - atomic_inc(&rmnet_mhi_ptr->irq_masked_cntr); - mhi_set_lpm(rmnet_mhi_ptr->rx_client_handle, false); - __napi_schedule(&(rmnet_mhi_ptr->napi)); - } else { - rmnet_mhi_ptr->debug.rx_interrupts_in_masked_irq++; + read_lock_irqsave(&rmnet_mhi_ptr->pm_lock, flags); + if (likely(rmnet_mhi_ptr->mhi_enabled)) { + if (napi_schedule_prep(&rmnet_mhi_ptr->napi)) { + if (!test_and_set_bit(IRQ_MASKED_BIT, + &rmnet_mhi_ptr->flags)) + mhi_mask_irq(rmnet_mhi_ptr->rx_client_handle); + mhi_set_lpm(rmnet_mhi_ptr->rx_client_handle, false); + rmnet_mhi_ptr->wake_count++; + __napi_schedule(&rmnet_mhi_ptr->napi); + } else { + rmnet_mhi_ptr->debug.rx_interrupts_in_masked_irq++; + } } + read_unlock_irqrestore(&rmnet_mhi_ptr->pm_lock, flags); rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Exited\n"); } @@ -510,8 +523,7 @@ static int rmnet_mhi_open(struct net_device *dev) struct rmnet_mhi_private *rmnet_mhi_ptr = *(struct rmnet_mhi_private **)netdev_priv(dev); - rmnet_log(rmnet_mhi_ptr, - MSG_INFO, + rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Opened net dev interface for MHI chans %d and %d\n", rmnet_mhi_ptr->tx_channel, rmnet_mhi_ptr->rx_channel); @@ -527,43 +539,35 @@ static int rmnet_mhi_open(struct net_device *dev) /* Poll to check if any buffers are accumulated in the * transport buffers */ - if (napi_schedule_prep(&(rmnet_mhi_ptr->napi))) { - mhi_mask_irq(rmnet_mhi_ptr->rx_client_handle); - atomic_inc(&rmnet_mhi_ptr->irq_masked_cntr); - mhi_set_lpm(rmnet_mhi_ptr->rx_client_handle, false); - __napi_schedule(&(rmnet_mhi_ptr->napi)); - } else { - rmnet_mhi_ptr->debug.rx_interrupts_in_masked_irq++; + read_lock_bh(&rmnet_mhi_ptr->pm_lock); + if (likely(rmnet_mhi_ptr->mhi_enabled)) { + if (napi_schedule_prep(&rmnet_mhi_ptr->napi)) { + if (!test_and_set_bit(IRQ_MASKED_BIT, + &rmnet_mhi_ptr->flags)) { + mhi_mask_irq(rmnet_mhi_ptr->rx_client_handle); + } + mhi_set_lpm(rmnet_mhi_ptr->rx_client_handle, false); + rmnet_mhi_ptr->wake_count++; + __napi_schedule(&rmnet_mhi_ptr->napi); + } else { + rmnet_mhi_ptr->debug.rx_interrupts_in_masked_irq++; + } } + read_unlock_bh(&rmnet_mhi_ptr->pm_lock); return 0; } -static int rmnet_mhi_disable_iface(struct rmnet_mhi_private *rmnet_mhi_ptr) -{ - rmnet_mhi_ptr->rx_enabled = 0; - rmnet_mhi_ptr->tx_enabled = 0; - rmnet_mhi_ptr->mhi_enabled = 0; - if (rmnet_mhi_ptr->dev != 0) { - netif_stop_queue(rmnet_mhi_ptr->dev); - netif_napi_del(&(rmnet_mhi_ptr->napi)); - rmnet_mhi_disable_channels(rmnet_mhi_ptr); - unregister_netdev(rmnet_mhi_ptr->dev); - free_netdev(rmnet_mhi_ptr->dev); - rmnet_mhi_ptr->dev = 0; - } - return 0; -} - static int rmnet_mhi_disable(struct rmnet_mhi_private *rmnet_mhi_ptr) { - rmnet_mhi_ptr->mhi_enabled = 0; - rmnet_mhi_disable_iface(rmnet_mhi_ptr); napi_disable(&(rmnet_mhi_ptr->napi)); - if (atomic_read(&rmnet_mhi_ptr->irq_masked_cntr)) { + rmnet_mhi_ptr->rx_enabled = 0; + rmnet_mhi_internal_clean_unmap_buffers(rmnet_mhi_ptr->dev, + &rmnet_mhi_ptr->rx_buffers, + DMA_FROM_DEVICE); + if (test_and_clear_bit(IRQ_MASKED_BIT, &rmnet_mhi_ptr->flags)) mhi_unmask_irq(rmnet_mhi_ptr->rx_client_handle); - atomic_dec(&rmnet_mhi_ptr->irq_masked_cntr); - } + return 0; } @@ -574,11 +578,9 @@ static int rmnet_mhi_stop(struct net_device *dev) netif_stop_queue(dev); rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Entered\n"); - if (atomic_read(&rmnet_mhi_ptr->irq_masked_cntr)) { + if (test_and_clear_bit(IRQ_MASKED_BIT, &rmnet_mhi_ptr->flags)) { mhi_unmask_irq(rmnet_mhi_ptr->rx_client_handle); - atomic_dec(&rmnet_mhi_ptr->irq_masked_cntr); - rmnet_log(rmnet_mhi_ptr, - MSG_ERROR, + rmnet_log(rmnet_mhi_ptr, MSG_ERROR, "IRQ was masked, unmasking...\n"); } rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Exited\n"); @@ -605,14 +607,23 @@ static int rmnet_mhi_xmit(struct sk_buff *skb, struct net_device *dev) unsigned long flags; struct mhi_skb_priv *tx_priv; - rmnet_log(rmnet_mhi_ptr, - MSG_VERBOSE, - "Entered chan %d\n", - rmnet_mhi_ptr->tx_channel); + rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, + "Entered chan %d\n", rmnet_mhi_ptr->tx_channel); tx_priv = (struct mhi_skb_priv *)(skb->cb); tx_priv->dma_size = skb->len; tx_priv->dma_addr = 0; + read_lock_bh(&rmnet_mhi_ptr->pm_lock); + if (unlikely(!rmnet_mhi_ptr->mhi_enabled)) { + /* Only reason interface could be disabled and we get data + * is due to an SSR. We do not want to stop the queue and + * return error. instead we will flush all the uplink packets + * and return successful + */ + res = NETDEV_TX_OK; + dev_kfree_skb_any(skb); + goto mhi_xmit_exit; + } if (mhi_get_free_desc(rmnet_mhi_ptr->tx_client_handle) <= 0) { rmnet_log(rmnet_mhi_ptr, @@ -624,7 +635,8 @@ static int rmnet_mhi_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); spin_unlock_irqrestore(&rmnet_mhi_ptr->out_chan_full_lock, flags); - return NETDEV_TX_BUSY; + res = NETDEV_TX_BUSY; + goto mhi_xmit_exit; } res = mhi_queue_xfer(rmnet_mhi_ptr->tx_client_handle, skb->data, @@ -641,15 +653,17 @@ static int rmnet_mhi_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); spin_unlock_irqrestore(&rmnet_mhi_ptr->out_chan_full_lock, flags); - return NETDEV_TX_BUSY; + res = NETDEV_TX_BUSY; + goto mhi_xmit_exit; } - + res = NETDEV_TX_OK; skb_queue_tail(&(rmnet_mhi_ptr->tx_buffers), skb); dev->trans_start = jiffies; rmnet_mhi_ptr->debug.tx_queued_packets_count++; - +mhi_xmit_exit: + read_unlock_bh(&rmnet_mhi_ptr->pm_lock); rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Exited\n"); - return NETDEV_TX_OK; + return res; } static int rmnet_mhi_ioctl_extended(struct net_device *dev, struct ifreq *ifr) @@ -698,16 +712,19 @@ static int rmnet_mhi_ioctl_extended(struct net_device *dev, struct ifreq *ifr) sizeof(ext_cmd.u.if_name)); break; case RMNET_IOCTL_SET_SLEEP_STATE: + read_lock_bh(&rmnet_mhi_ptr->pm_lock); if (rmnet_mhi_ptr->mhi_enabled && rmnet_mhi_ptr->tx_client_handle != NULL) { + rmnet_mhi_ptr->wake_count += (ext_cmd.u.data) ? -1 : 1; mhi_set_lpm(rmnet_mhi_ptr->tx_client_handle, ext_cmd.u.data); } else { - rmnet_log(rmnet_mhi_ptr, - MSG_ERROR, + rmnet_log(rmnet_mhi_ptr, MSG_ERROR, "Cannot set LPM value, MHI is not up.\n"); + read_unlock_bh(&rmnet_mhi_ptr->pm_lock); return -ENODEV; } + read_unlock_bh(&rmnet_mhi_ptr->pm_lock); break; default: rc = -EINVAL; @@ -832,9 +849,8 @@ static int rmnet_mhi_enable_iface(struct rmnet_mhi_private *rmnet_mhi_ptr) "Failed to start TX chan ret %d\n", r); goto mhi_tx_chan_start_fail; - } else { - rmnet_mhi_ptr->tx_enabled = 1; } + client_handle = rmnet_mhi_ptr->tx_client_handle; } if (rmnet_mhi_ptr->rx_client_handle != NULL) { @@ -848,8 +864,6 @@ static int rmnet_mhi_enable_iface(struct rmnet_mhi_private *rmnet_mhi_ptr) "Failed to start RX chan ret %d\n", r); goto mhi_rx_chan_start_fail; - } else { - rmnet_mhi_ptr->rx_enabled = 1; } /* Both tx & rx client handle contain same device info */ client_handle = rmnet_mhi_ptr->rx_client_handle; @@ -860,62 +874,64 @@ static int rmnet_mhi_enable_iface(struct rmnet_mhi_private *rmnet_mhi_ptr) goto net_dev_alloc_fail; } - snprintf(ifalias, - sizeof(ifalias), - "%s_%04x_%02u.%02u.%02u_%u", - rmnet_mhi_ptr->interface_name, - client_handle->dev_id, - client_handle->domain, - client_handle->bus, - client_handle->slot, - rmnet_mhi_ptr->dev_id); - - snprintf(ifname, sizeof(ifname), "%s%%d", - rmnet_mhi_ptr->interface_name); - rtnl_lock(); - rmnet_mhi_ptr->dev = - alloc_netdev(sizeof(struct rmnet_mhi_private *), - ifname, NET_NAME_PREDICTABLE, rmnet_mhi_setup); if (!rmnet_mhi_ptr->dev) { - rmnet_log(rmnet_mhi_ptr, - MSG_CRITICAL, - "Network device allocation failed\n"); - ret = -ENOMEM; - goto net_dev_alloc_fail; + snprintf(ifalias, sizeof(ifalias), + "%s_%04x_%02u.%02u.%02u_%u", + rmnet_mhi_ptr->interface_name, + client_handle->dev_id, + client_handle->domain, + client_handle->bus, + client_handle->slot, + rmnet_mhi_ptr->dev_id); + + snprintf(ifname, sizeof(ifname), "%s%%d", + rmnet_mhi_ptr->interface_name); + + rtnl_lock(); + rmnet_mhi_ptr->dev = alloc_netdev( + sizeof(struct rmnet_mhi_private *), + ifname, NET_NAME_PREDICTABLE, rmnet_mhi_setup); + + if (!rmnet_mhi_ptr->dev) { + rmnet_log(rmnet_mhi_ptr, MSG_CRITICAL, + "Network device allocation failed\n"); + ret = -ENOMEM; + goto net_dev_alloc_fail; + } + SET_NETDEV_DEV(rmnet_mhi_ptr->dev, &rmnet_mhi_ptr->pdev->dev); + dev_set_alias(rmnet_mhi_ptr->dev, ifalias, strlen(ifalias)); + rmnet_mhi_ctxt = netdev_priv(rmnet_mhi_ptr->dev); + rtnl_unlock(); + *rmnet_mhi_ctxt = rmnet_mhi_ptr; + + ret = dma_set_mask(&rmnet_mhi_ptr->dev->dev, MHI_DMA_MASK); + if (ret) + rmnet_mhi_ptr->allocation_flags = GFP_KERNEL; + else + rmnet_mhi_ptr->allocation_flags = GFP_DMA; + + netif_napi_add(rmnet_mhi_ptr->dev, &rmnet_mhi_ptr->napi, + rmnet_mhi_poll, MHI_NAPI_WEIGHT_VALUE); + + ret = register_netdev(rmnet_mhi_ptr->dev); + if (ret) { + rmnet_log(rmnet_mhi_ptr, MSG_CRITICAL, + "Network device registration failed\n"); + goto net_dev_reg_fail; + } } - SET_NETDEV_DEV(rmnet_mhi_ptr->dev, &rmnet_mhi_ptr->pdev->dev); - dev_set_alias(rmnet_mhi_ptr->dev, ifalias, strlen(ifalias)); - rmnet_mhi_ctxt = netdev_priv(rmnet_mhi_ptr->dev); - rtnl_unlock(); - *rmnet_mhi_ctxt = rmnet_mhi_ptr; - - ret = dma_set_mask(&(rmnet_mhi_ptr->dev->dev), - MHI_DMA_MASK); - if (ret) - rmnet_mhi_ptr->allocation_flags = GFP_KERNEL; - else - rmnet_mhi_ptr->allocation_flags = GFP_DMA; + + write_lock_irq(&rmnet_mhi_ptr->pm_lock); + rmnet_mhi_ptr->mhi_enabled = 1; + write_unlock_irq(&rmnet_mhi_ptr->pm_lock); r = rmnet_mhi_init_inbound(rmnet_mhi_ptr); if (r) { - rmnet_log(rmnet_mhi_ptr, - MSG_CRITICAL, - "Failed to init inbound ret %d\n", - r); + rmnet_log(rmnet_mhi_ptr, MSG_INFO, + "Failed to init inbound ret %d\n", r); } - netif_napi_add(rmnet_mhi_ptr->dev, &(rmnet_mhi_ptr->napi), - rmnet_mhi_poll, MHI_NAPI_WEIGHT_VALUE); - - rmnet_mhi_ptr->mhi_enabled = 1; - ret = register_netdev(rmnet_mhi_ptr->dev); - if (ret) { - rmnet_log(rmnet_mhi_ptr, - MSG_CRITICAL, - "Network device registration failed\n"); - goto net_dev_reg_fail; - } napi_enable(&(rmnet_mhi_ptr->napi)); rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Exited.\n"); @@ -951,25 +967,47 @@ static void rmnet_mhi_cb(struct mhi_cb_info *cb_info) switch (cb_info->cb_reason) { case MHI_CB_MHI_DISABLED: - rmnet_log(rmnet_mhi_ptr, - MSG_CRITICAL, - "Got MHI_DISABLED notification. Stopping stack\n"); - if (rmnet_mhi_ptr->mhi_enabled) { - rmnet_mhi_ptr->mhi_enabled = 0; - /* Ensure MHI is disabled before other mem ops */ - wmb(); - while (atomic_read(&rmnet_mhi_ptr->pending_data)) { - rmnet_log(rmnet_mhi_ptr, - MSG_CRITICAL, - "Waiting for channels to stop.\n"); - msleep(25); - } + case MHI_CB_MHI_SHUTDOWN: + case MHI_CB_SYS_ERROR: + rmnet_log(rmnet_mhi_ptr, MSG_INFO, + "Got MHI_SYS_ERROR notification. Stopping stack\n"); + + /* Disable interface on first notification. Long + * as we set mhi_enabled = 0, we gurantee rest of + * driver will not touch any critical data. + */ + write_lock_irq(&rmnet_mhi_ptr->pm_lock); + rmnet_mhi_ptr->mhi_enabled = 0; + write_unlock_irq(&rmnet_mhi_ptr->pm_lock); + + if (cb_info->chan == rmnet_mhi_ptr->rx_channel) { + rmnet_log(rmnet_mhi_ptr, MSG_INFO, + "Receive MHI_DISABLE notification for rx path\n"); rmnet_mhi_disable(rmnet_mhi_ptr); + } else { + rmnet_log(rmnet_mhi_ptr, MSG_INFO, + "Receive MHI_DISABLE notification for tx path\n"); + rmnet_mhi_ptr->tx_enabled = 0; + rmnet_mhi_internal_clean_unmap_buffers + (rmnet_mhi_ptr->dev, &rmnet_mhi_ptr->tx_buffers, + DMA_TO_DEVICE); + } + + /* Remove all votes disabling low power mode */ + if (!rmnet_mhi_ptr->tx_enabled && !rmnet_mhi_ptr->rx_enabled) { + struct mhi_client_handle *handle = + rmnet_mhi_ptr->rx_client_handle; + + if (!handle) + handle = rmnet_mhi_ptr->tx_client_handle; + while (rmnet_mhi_ptr->wake_count) { + mhi_set_lpm(handle, true); + rmnet_mhi_ptr->wake_count--; + } } break; case MHI_CB_MHI_ENABLED: - rmnet_log(rmnet_mhi_ptr, - MSG_CRITICAL, + rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Got MHI_ENABLED notification. Starting stack\n"); if (cb_info->chan == rmnet_mhi_ptr->rx_channel) rmnet_mhi_ptr->rx_enabled = 1; @@ -998,16 +1036,10 @@ static void rmnet_mhi_cb(struct mhi_cb_info *cb_info) } break; case MHI_CB_XFER: - atomic_inc(&rmnet_mhi_ptr->pending_data); - /* Flush pending data is set before any other mem operations */ - wmb(); - if (rmnet_mhi_ptr->mhi_enabled) { - if (cb_info->chan == rmnet_mhi_ptr->rx_channel) - rmnet_mhi_rx_cb(cb_info->result); - else - rmnet_mhi_tx_cb(cb_info->result); - } - atomic_dec(&rmnet_mhi_ptr->pending_data); + if (cb_info->chan == rmnet_mhi_ptr->rx_channel) + rmnet_mhi_rx_cb(cb_info->result); + else + rmnet_mhi_tx_cb(cb_info->result); break; default: break; @@ -1172,6 +1204,7 @@ static int rmnet_mhi_probe(struct platform_device *pdev) return -ENOMEM; rmnet_mhi_ptr->pdev = pdev; spin_lock_init(&rmnet_mhi_ptr->out_chan_full_lock); + rwlock_init(&rmnet_mhi_ptr->pm_lock); rc = of_property_read_u32(pdev->dev.of_node, "qcom,mhi-mru", diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile index 5fe8bc184868..27a6c75682c4 100644 --- a/drivers/net/wireless/ath/ath10k/Makefile +++ b/drivers/net/wireless/ath/ath10k/Makefile @@ -27,6 +27,7 @@ ath10k_pci-y += pci.o \ obj-$(CONFIG_ATH10K_TARGET_SNOC) += ath10k_snoc.o ath10k_snoc-y += snoc.o \ qmi.o \ + wcn3990_qmi_service_v01.o \ ce.o ath10k_pci-$(CONFIG_ATH10K_AHB) += ahb.o diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c index 7b5fc52d269a..7d20f087da71 100644 --- a/drivers/net/wireless/ath/ath10k/qmi.c +++ b/drivers/net/wireless/ath/ath10k/qmi.c @@ -12,10 +12,14 @@ #include <soc/qcom/subsystem_notif.h> #include <soc/qcom/subsystem_restart.h> #include <soc/qcom/service-notifier.h> +#include <soc/qcom/msm_qmi_interface.h> +#include <soc/qcom/service-locator.h> #include "core.h" #include "qmi.h" #include "snoc.h" -#include <soc/qcom/icnss.h> +#include "wcn3990_qmi_service_v01.h" + +static DECLARE_WAIT_QUEUE_HEAD(ath10k_fw_ready_wait_event); static int ath10k_snoc_service_notifier_notify(struct notifier_block *nb, @@ -228,3 +232,634 @@ int ath10k_snoc_modem_ssr_unregister_notifier(struct ath10k *ar) return 0; } +static char * +ath10k_snoc_driver_event_to_str(enum ath10k_snoc_driver_event_type type) +{ + switch (type) { + case ATH10K_SNOC_DRIVER_EVENT_SERVER_ARRIVE: + return "SERVER_ARRIVE"; + case ATH10K_SNOC_DRIVER_EVENT_SERVER_EXIT: + return "SERVER_EXIT"; + case ATH10K_SNOC_DRIVER_EVENT_FW_READY_IND: + return "FW_READY"; + case ATH10K_SNOC_DRIVER_EVENT_MAX: + return "EVENT_MAX"; + } + + return "UNKNOWN"; +}; + +static int +ath10k_snoc_driver_event_post(enum ath10k_snoc_driver_event_type type, + u32 flags, void *data) +{ + int ret = 0; + int i = 0; + struct ath10k *ar = (struct ath10k *)data; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "Posting event: %s type: %d\n", + ath10k_snoc_driver_event_to_str(type), type); + + if (type >= ATH10K_SNOC_DRIVER_EVENT_MAX) { + ath10k_err(ar, "Invalid Event type: %d, can't post", type); + return -EINVAL; + } + + spin_lock_bh(&qmi_cfg->event_lock); + + for (i = 0; i < ATH10K_SNOC_DRIVER_EVENT_MAX; i++) { + if (atomic_read(&qmi_cfg->qmi_ev_list[i].event_handled)) { + qmi_cfg->qmi_ev_list[i].type = type; + qmi_cfg->qmi_ev_list[i].data = data; + init_completion(&qmi_cfg->qmi_ev_list[i].complete); + qmi_cfg->qmi_ev_list[i].ret = + ATH10K_SNOC_EVENT_PENDING; + qmi_cfg->qmi_ev_list[i].sync = + !!(flags & ATH10K_SNOC_EVENT_SYNC); + atomic_set(&qmi_cfg->qmi_ev_list[i].event_handled, 0); + list_add_tail(&qmi_cfg->qmi_ev_list[i].list, + &qmi_cfg->event_list); + break; + } + } + + if (i >= ATH10K_SNOC_DRIVER_EVENT_MAX) + i = ATH10K_SNOC_DRIVER_EVENT_SERVER_ARRIVE; + + spin_unlock_bh(&qmi_cfg->event_lock); + + queue_work(qmi_cfg->event_wq, &qmi_cfg->event_work); + + if (!(flags & ATH10K_SNOC_EVENT_SYNC)) + goto out; + + if (flags & ATH10K_SNOC_EVENT_UNINTERRUPTIBLE) + wait_for_completion(&qmi_cfg->qmi_ev_list[i].complete); + else + ret = wait_for_completion_interruptible( + &qmi_cfg->qmi_ev_list[i].complete); + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "Completed event: %s(%d)\n", + ath10k_snoc_driver_event_to_str(type), type); + + spin_lock_bh(&qmi_cfg->event_lock); + if (ret == -ERESTARTSYS && + qmi_cfg->qmi_ev_list[i].ret == ATH10K_SNOC_EVENT_PENDING) { + qmi_cfg->qmi_ev_list[i].sync = false; + atomic_set(&qmi_cfg->qmi_ev_list[i].event_handled, 1); + spin_unlock_bh(&qmi_cfg->event_lock); + ret = -EINTR; + goto out; + } + spin_unlock_bh(&qmi_cfg->event_lock); + +out: + return ret; +} + +static int +ath10k_snoc_wlan_mode_send_sync_msg(struct ath10k *ar, + enum wlfw_driver_mode_enum_v01 mode) +{ + int ret; + struct wlfw_wlan_mode_req_msg_v01 req; + struct wlfw_wlan_mode_resp_msg_v01 resp; + struct msg_desc req_desc, resp_desc; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg; + + if (!qmi_cfg || !qmi_cfg->wlfw_clnt) + return -ENODEV; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, + "Sending Mode request, mode: %d\n", mode); + + memset(&req, 0, sizeof(req)); + memset(&resp, 0, sizeof(resp)); + + req.mode = mode; + req.hw_debug_valid = 1; + req.hw_debug = 0; + + req_desc.max_msg_len = WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN; + req_desc.msg_id = QMI_WLFW_WLAN_MODE_REQ_V01; + req_desc.ei_array = wlfw_wlan_mode_req_msg_v01_ei; + + resp_desc.max_msg_len = WLFW_WLAN_MODE_RESP_MSG_V01_MAX_MSG_LEN; + resp_desc.msg_id = QMI_WLFW_WLAN_MODE_RESP_V01; + resp_desc.ei_array = wlfw_wlan_mode_resp_msg_v01_ei; + + ret = qmi_send_req_wait(qmi_cfg->wlfw_clnt, + &req_desc, &req, sizeof(req), + &resp_desc, &resp, sizeof(resp), + WLFW_TIMEOUT_MS); + if (ret < 0) { + ath10k_err(ar, "Send mode req failed, mode: %d ret: %d\n", + mode, ret); + return ret; + } + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ath10k_err(ar, "QMI mode request rejected:"); + ath10k_err(ar, "mode:%d result:%d error:%d\n", + mode, resp.resp.result, resp.resp.error); + ret = resp.resp.result; + return ret; + } + + ath10k_dbg(ar, ATH10K_DBG_SNOC, + "wlan Mode request send success, mode: %d\n", mode); + return 0; +} + +static int +ath10k_snoc_wlan_cfg_send_sync_msg(struct ath10k *ar, + struct wlfw_wlan_cfg_req_msg_v01 *data) +{ + int ret; + struct wlfw_wlan_cfg_req_msg_v01 req; + struct wlfw_wlan_cfg_resp_msg_v01 resp; + struct msg_desc req_desc, resp_desc; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg; + + if (!qmi_cfg || !qmi_cfg->wlfw_clnt) + return -ENODEV; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "Sending config request\n"); + + memset(&req, 0, sizeof(req)); + memset(&resp, 0, sizeof(resp)); + memcpy(&req, data, sizeof(req)); + + req_desc.max_msg_len = WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN; + req_desc.msg_id = QMI_WLFW_WLAN_CFG_REQ_V01; + req_desc.ei_array = wlfw_wlan_cfg_req_msg_v01_ei; + + resp_desc.max_msg_len = WLFW_WLAN_CFG_RESP_MSG_V01_MAX_MSG_LEN; + resp_desc.msg_id = QMI_WLFW_WLAN_CFG_RESP_V01; + resp_desc.ei_array = wlfw_wlan_cfg_resp_msg_v01_ei; + + ret = qmi_send_req_wait(qmi_cfg->wlfw_clnt, + &req_desc, &req, sizeof(req), + &resp_desc, &resp, sizeof(resp), + WLFW_TIMEOUT_MS); + if (ret < 0) { + ath10k_err(ar, "Send config req failed %d\n", ret); + return ret; + } + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ath10k_err(ar, "QMI config request rejected:"); + ath10k_err(ar, "result:%d error:%d\n", + resp.resp.result, resp.resp.error); + ret = resp.resp.result; + return ret; + } + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "wlan config request success..\n"); + return 0; +} + +int ath10k_snoc_qmi_wlan_enable(struct ath10k *ar, + struct ath10k_wlan_enable_cfg *config, + enum ath10k_driver_mode mode, + const char *host_version) +{ + struct wlfw_wlan_cfg_req_msg_v01 req; + u32 i; + int ret; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, + "Mode: %d, config: %p, host_version: %s\n", + mode, config, host_version); + + memset(&req, 0, sizeof(req)); + if (!config || !host_version) { + ath10k_err(ar, "WLAN_EN Config Invalid:%p: host_version:%p\n", + config, host_version); + ret = -EINVAL; + return ret; + } + + wait_event_timeout(ath10k_fw_ready_wait_event, + (atomic_read(&qmi_cfg->fw_ready) && + atomic_read(&qmi_cfg->server_connected)), + msecs_to_jiffies(ATH10K_SNOC_WLAN_FW_READY_TIMEOUT)); + + req.host_version_valid = 1; + strlcpy(req.host_version, host_version, + QMI_WLFW_MAX_STR_LEN_V01 + 1); + + req.tgt_cfg_valid = 1; + if (config->num_ce_tgt_cfg > QMI_WLFW_MAX_NUM_CE_V01) + req.tgt_cfg_len = QMI_WLFW_MAX_NUM_CE_V01; + else + req.tgt_cfg_len = config->num_ce_tgt_cfg; + for (i = 0; i < req.tgt_cfg_len; i++) { + req.tgt_cfg[i].pipe_num = config->ce_tgt_cfg[i].pipe_num; + req.tgt_cfg[i].pipe_dir = config->ce_tgt_cfg[i].pipe_dir; + req.tgt_cfg[i].nentries = config->ce_tgt_cfg[i].nentries; + req.tgt_cfg[i].nbytes_max = config->ce_tgt_cfg[i].nbytes_max; + req.tgt_cfg[i].flags = config->ce_tgt_cfg[i].flags; + } + + req.svc_cfg_valid = 1; + if (config->num_ce_svc_pipe_cfg > QMI_WLFW_MAX_NUM_SVC_V01) + req.svc_cfg_len = QMI_WLFW_MAX_NUM_SVC_V01; + else + req.svc_cfg_len = config->num_ce_svc_pipe_cfg; + for (i = 0; i < req.svc_cfg_len; i++) { + req.svc_cfg[i].service_id = config->ce_svc_cfg[i].service_id; + req.svc_cfg[i].pipe_dir = config->ce_svc_cfg[i].pipe_dir; + req.svc_cfg[i].pipe_num = config->ce_svc_cfg[i].pipe_num; + } + + req.shadow_reg_valid = 1; + if (config->num_shadow_reg_cfg > + QMI_WLFW_MAX_NUM_SHADOW_REG_V01) + req.shadow_reg_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V01; + else + req.shadow_reg_len = config->num_shadow_reg_cfg; + + memcpy(req.shadow_reg, config->shadow_reg_cfg, + sizeof(struct wlfw_shadow_reg_cfg_s_v01) * req.shadow_reg_len); + + ret = ath10k_snoc_wlan_cfg_send_sync_msg(ar, &req); + if (ret) { + ath10k_err(ar, "WLAN config send failed\n"); + return ret; + } + + ret = ath10k_snoc_wlan_mode_send_sync_msg(ar, mode); + if (ret) { + ath10k_err(ar, "WLAN mode send failed\n"); + return ret; + } + + return 0; +} + +int ath10k_snoc_qmi_wlan_disable(struct ath10k *ar) +{ + return ath10k_snoc_wlan_mode_send_sync_msg(ar, QMI_WLFW_OFF_V01); +} + +static int ath10k_snoc_ind_register_send_sync_msg(struct ath10k *ar) +{ + int ret; + struct wlfw_ind_register_req_msg_v01 req; + struct wlfw_ind_register_resp_msg_v01 resp; + struct msg_desc req_desc, resp_desc; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, + "Sending indication register message,\n"); + + memset(&req, 0, sizeof(req)); + memset(&resp, 0, sizeof(resp)); + + req.client_id_valid = 1; + req.client_id = WLFW_CLIENT_ID; + req.fw_ready_enable_valid = 1; + req.fw_ready_enable = 1; + req.msa_ready_enable_valid = 1; + req.msa_ready_enable = 1; + + req_desc.max_msg_len = WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN; + req_desc.msg_id = QMI_WLFW_IND_REGISTER_REQ_V01; + req_desc.ei_array = wlfw_ind_register_req_msg_v01_ei; + + resp_desc.max_msg_len = WLFW_IND_REGISTER_RESP_MSG_V01_MAX_MSG_LEN; + resp_desc.msg_id = QMI_WLFW_IND_REGISTER_RESP_V01; + resp_desc.ei_array = wlfw_ind_register_resp_msg_v01_ei; + + ret = qmi_send_req_wait(qmi_cfg->wlfw_clnt, + &req_desc, &req, sizeof(req), + &resp_desc, &resp, sizeof(resp), + WLFW_TIMEOUT_MS); + if (ret < 0) { + ath10k_err(ar, "Send indication register req failed %d\n", ret); + return ret; + } + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ath10k_err(ar, "QMI indication register request rejected:"); + ath10k_err(ar, "resut:%d error:%d\n", + resp.resp.result, resp.resp.error); + ret = resp.resp.result; + return ret; + } + + return 0; +} + +static void ath10k_snoc_qmi_wlfw_clnt_notify_work(struct work_struct *work) +{ + int ret; + struct ath10k_snoc_qmi_config *qmi_cfg = + container_of(work, struct ath10k_snoc_qmi_config, + qmi_recv_msg_work); + struct ath10k_snoc *ar_snoc = + container_of(qmi_cfg, struct ath10k_snoc, qmi_cfg); + struct ath10k *ar = ar_snoc->ar; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, + "Receiving Event in work queue context\n"); + + do { + } while ((ret = qmi_recv_msg(qmi_cfg->wlfw_clnt)) == 0); + + if (ret != -ENOMSG) + ath10k_err(ar, "Error receiving message: %d\n", ret); + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "Receiving Event completed\n"); +} + +static void +ath10k_snoc_qmi_wlfw_clnt_notify(struct qmi_handle *handle, + enum qmi_event_type event, + void *notify_priv) +{ + struct ath10k_snoc_qmi_config *qmi_cfg = + (struct ath10k_snoc_qmi_config *)notify_priv; + struct ath10k_snoc *ar_snoc = + container_of(qmi_cfg, struct ath10k_snoc, qmi_cfg); + struct ath10k *ar = ar_snoc->ar; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "QMI client notify: %d\n", event); + + if (!qmi_cfg || !qmi_cfg->wlfw_clnt) + return; + + switch (event) { + case QMI_RECV_MSG: + schedule_work(&qmi_cfg->qmi_recv_msg_work); + break; + default: + ath10k_dbg(ar, ATH10K_DBG_SNOC, "Unknown Event: %d\n", event); + break; + } +} + +static void +ath10k_snoc_qmi_wlfw_clnt_ind(struct qmi_handle *handle, + unsigned int msg_id, void *msg, + unsigned int msg_len, void *ind_cb_priv) +{ + struct ath10k_snoc_qmi_config *qmi_cfg = + (struct ath10k_snoc_qmi_config *)ind_cb_priv; + struct ath10k_snoc *ar_snoc = + container_of(qmi_cfg, struct ath10k_snoc, qmi_cfg); + struct ath10k *ar = ar_snoc->ar; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, + "Received Ind 0x%x, msg_len: %d\n", msg_id, msg_len); + switch (msg_id) { + case QMI_WLFW_FW_READY_IND_V01: + ath10k_snoc_driver_event_post( + ATH10K_SNOC_DRIVER_EVENT_FW_READY_IND, 0, ar); + break; + case QMI_WLFW_MSA_READY_IND_V01: + qmi_cfg->msa_ready = true; + ath10k_dbg(ar, ATH10K_DBG_SNOC, + "Received MSA Ready, ind = 0x%x\n", msg_id); + break; + default: + ath10k_err(ar, "Invalid msg_id 0x%x\n", msg_id); + break; + } +} + +static int ath10k_snoc_driver_event_server_arrive(struct ath10k *ar) +{ + int ret = 0; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg; + + if (!qmi_cfg) + return -ENODEV; + + qmi_cfg->wlfw_clnt = qmi_handle_create( + ath10k_snoc_qmi_wlfw_clnt_notify, qmi_cfg); + if (!qmi_cfg->wlfw_clnt) { + ath10k_dbg(ar, ATH10K_DBG_SNOC, + "QMI client handle create failed\n"); + return -ENOMEM; + } + + ret = qmi_connect_to_service(qmi_cfg->wlfw_clnt, + WLFW_SERVICE_ID_V01, + WLFW_SERVICE_VERS_V01, + WLFW_SERVICE_INS_ID_V01); + if (ret < 0) { + ath10k_err(ar, "QMI WLAN Service not found : %d\n", ret); + goto err_qmi_config; + } + + ret = qmi_register_ind_cb(qmi_cfg->wlfw_clnt, + ath10k_snoc_qmi_wlfw_clnt_ind, qmi_cfg); + if (ret < 0) { + ath10k_err(ar, "Failed to register indication callback: %d\n", + ret); + goto err_qmi_config; + } + + ret = ath10k_snoc_ind_register_send_sync_msg(ar); + if (ret) { + ath10k_err(ar, "Failed to config qmi ind register\n"); + goto err_qmi_config; + } + + atomic_set(&qmi_cfg->server_connected, 1); + wake_up_all(&ath10k_fw_ready_wait_event); + ath10k_dbg(ar, ATH10K_DBG_SNOC, + "QMI Server Arrive Configuration Success\n"); + return 0; + +err_qmi_config: + qmi_handle_destroy(qmi_cfg->wlfw_clnt); + qmi_cfg->wlfw_clnt = NULL; + return ret; +} + +static int ath10k_snoc_driver_event_server_exit(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "QMI Server Exit event received\n"); + atomic_set(&qmi_cfg->fw_ready, 0); + qmi_cfg->msa_ready = false; + atomic_set(&qmi_cfg->server_connected, 0); + return 0; +} + +static int ath10k_snoc_driver_event_fw_ready_ind(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "FW Ready event received.\n"); + atomic_set(&qmi_cfg->fw_ready, 1); + wake_up_all(&ath10k_fw_ready_wait_event); + + return 0; +} + +static void ath10k_snoc_driver_event_work(struct work_struct *work) +{ + struct ath10k_snoc_qmi_driver_event *event; + int ret; + struct ath10k_snoc_qmi_config *qmi_cfg = + container_of(work, struct ath10k_snoc_qmi_config, event_work); + struct ath10k_snoc *ar_snoc = + container_of(qmi_cfg, struct ath10k_snoc, qmi_cfg); + struct ath10k *ar = ar_snoc->ar; + + spin_lock_bh(&qmi_cfg->event_lock); + + while (!list_empty(&qmi_cfg->event_list)) { + event = list_first_entry(&qmi_cfg->event_list, + struct ath10k_snoc_qmi_driver_event, + list); + list_del(&event->list); + spin_unlock_bh(&qmi_cfg->event_lock); + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "Processing event: %s%s(%d)\n", + ath10k_snoc_driver_event_to_str(event->type), + event->sync ? "-sync" : "", event->type); + + switch (event->type) { + case ATH10K_SNOC_DRIVER_EVENT_SERVER_ARRIVE: + ret = ath10k_snoc_driver_event_server_arrive(ar); + break; + case ATH10K_SNOC_DRIVER_EVENT_SERVER_EXIT: + ret = ath10k_snoc_driver_event_server_exit(ar); + break; + case ATH10K_SNOC_DRIVER_EVENT_FW_READY_IND: + ret = ath10k_snoc_driver_event_fw_ready_ind(ar); + break; + default: + ath10k_err(ar, "Invalid Event type: %d", event->type); + kfree(event); + continue; + } + + atomic_set(&event->event_handled, 1); + ath10k_dbg(ar, ATH10K_DBG_SNOC, + "Event Processed: %s%s(%d), ret: %d\n", + ath10k_snoc_driver_event_to_str(event->type), + event->sync ? "-sync" : "", event->type, ret); + spin_lock_bh(&qmi_cfg->event_lock); + if (event->sync) { + event->ret = ret; + complete(&event->complete); + continue; + } + spin_unlock_bh(&qmi_cfg->event_lock); + spin_lock_bh(&qmi_cfg->event_lock); + } + + spin_unlock_bh(&qmi_cfg->event_lock); +} + +static int +ath10k_snoc_qmi_wlfw_clnt_svc_event_notify(struct notifier_block *this, + unsigned long code, + void *_cmd) +{ + int ret = 0; + struct ath10k_snoc_qmi_config *qmi_cfg = + container_of(this, struct ath10k_snoc_qmi_config, wlfw_clnt_nb); + struct ath10k_snoc *ar_snoc = + container_of(qmi_cfg, struct ath10k_snoc, qmi_cfg); + struct ath10k *ar = ar_snoc->ar; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "Event Notify: code: %ld", code); + + switch (code) { + case QMI_SERVER_ARRIVE: + ret = ath10k_snoc_driver_event_post( + ATH10K_SNOC_DRIVER_EVENT_SERVER_ARRIVE, 0, ar); + break; + case QMI_SERVER_EXIT: + ret = ath10k_snoc_driver_event_post( + ATH10K_SNOC_DRIVER_EVENT_SERVER_EXIT, 0, ar); + break; + default: + ath10k_err(ar, "Invalid code: %ld", code); + break; + } + + return ret; +} + +int ath10k_snoc_start_qmi_service(struct ath10k *ar) +{ + int ret; + int i; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg; + + qmi_cfg->event_wq = alloc_workqueue("ath10k_snoc_driver_event", + WQ_UNBOUND, 1); + if (!qmi_cfg->event_wq) { + ath10k_err(ar, "Workqueue creation failed\n"); + return -EFAULT; + } + + spin_lock_init(&qmi_cfg->event_lock); + atomic_set(&qmi_cfg->fw_ready, 0); + atomic_set(&qmi_cfg->server_connected, 0); + + INIT_WORK(&qmi_cfg->event_work, ath10k_snoc_driver_event_work); + INIT_WORK(&qmi_cfg->qmi_recv_msg_work, + ath10k_snoc_qmi_wlfw_clnt_notify_work); + INIT_LIST_HEAD(&qmi_cfg->event_list); + + for (i = 0; i < ATH10K_SNOC_DRIVER_EVENT_MAX; i++) + atomic_set(&qmi_cfg->qmi_ev_list[i].event_handled, 1); + + qmi_cfg->wlfw_clnt_nb.notifier_call = + ath10k_snoc_qmi_wlfw_clnt_svc_event_notify; + ret = qmi_svc_event_notifier_register(WLFW_SERVICE_ID_V01, + WLFW_SERVICE_VERS_V01, + WLFW_SERVICE_INS_ID_V01, + &qmi_cfg->wlfw_clnt_nb); + if (ret < 0) { + ath10k_err(ar, "Notifier register failed: %d\n", ret); + ret = -EFAULT; + goto out_destroy_wq; + } + + atomic_set(&qmi_cfg->fw_ready, 1); + ath10k_dbg(ar, ATH10K_DBG_SNOC, "QMI service started successfully\n"); + return 0; + +out_destroy_wq: + destroy_workqueue(qmi_cfg->event_wq); + return ret; +} + +void ath10k_snoc_stop_qmi_service(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "Removing QMI service..\n"); + + qmi_svc_event_notifier_unregister(WLFW_SERVICE_ID_V01, + WLFW_SERVICE_VERS_V01, + WLFW_SERVICE_INS_ID_V01, + &qmi_cfg->wlfw_clnt_nb); + + wake_up_all(&ath10k_fw_ready_wait_event); + destroy_workqueue(qmi_cfg->event_wq); + qmi_cfg = NULL; +} diff --git a/drivers/net/wireless/ath/ath10k/qmi.h b/drivers/net/wireless/ath/ath10k/qmi.h index f8ba3288753b..c8bc26bb96b2 100644 --- a/drivers/net/wireless/ath/ath10k/qmi.h +++ b/drivers/net/wireless/ath/ath10k/qmi.h @@ -11,9 +11,146 @@ */ #ifndef _QMI_H_ #define _QMI_H_ + +#define ATH10K_SNOC_EVENT_PENDING 2989 +#define ATH10K_SNOC_EVENT_SYNC BIT(0) +#define ATH10K_SNOC_EVENT_UNINTERRUPTIBLE BIT(1) +#define ATH10K_SNOC_WLAN_FW_READY_TIMEOUT 8000 + +#define WLFW_SERVICE_INS_ID_V01 0 +#define WLFW_CLIENT_ID 0x4b4e454c +#define WLFW_TIMEOUT_MS 20000 + +enum ath10k_snoc_driver_event_type { + ATH10K_SNOC_DRIVER_EVENT_SERVER_ARRIVE, + ATH10K_SNOC_DRIVER_EVENT_SERVER_EXIT, + ATH10K_SNOC_DRIVER_EVENT_FW_READY_IND, + ATH10K_SNOC_DRIVER_EVENT_MAX, +}; + +/* enum ath10k_driver_mode: ath10k driver mode + * @ATH10K_MISSION: mission mode + * @ATH10K_FTM: ftm mode + * @ATH10K_EPPING: epping mode + * @ATH10K_OFF: off mode + */ +enum ath10k_driver_mode { + ATH10K_MISSION, + ATH10K_FTM, + ATH10K_EPPING, + ATH10K_OFF +}; + +/* struct ath10k_ce_tgt_pipe_cfg: target pipe configuration + * @pipe_num: pipe number + * @pipe_dir: pipe direction + * @nentries: entries in pipe + * @nbytes_max: pipe max size + * @flags: pipe flags + * @reserved: reserved + */ +struct ath10k_ce_tgt_pipe_cfg { + u32 pipe_num; + u32 pipe_dir; + u32 nentries; + u32 nbytes_max; + u32 flags; + u32 reserved; +}; + +/* struct ath10k_ce_svc_pipe_cfg: service pipe configuration + * @service_id: target version + * @pipe_dir: pipe direction + * @pipe_num: pipe number + */ +struct ath10k_ce_svc_pipe_cfg { + u32 service_id; + u32 pipe_dir; + u32 pipe_num; +}; + +/* struct ath10k_shadow_reg_cfg: shadow register configuration + * @ce_id: copy engine id + * @reg_offset: offset to copy engine + */ +struct ath10k_shadow_reg_cfg { + u16 ce_id; + u16 reg_offset; +}; + +/* struct ath10k_wlan_enable_cfg: wlan enable configuration + * @num_ce_tgt_cfg: no of ce target configuration + * @ce_tgt_cfg: target ce configuration + * @num_ce_svc_pipe_cfg: no of ce service configuration + * @ce_svc_cfg: ce service configuration + * @num_shadow_reg_cfg: no of shadow registers + * @shadow_reg_cfg: shadow register configuration + */ +struct ath10k_wlan_enable_cfg { + u32 num_ce_tgt_cfg; + struct ath10k_ce_tgt_pipe_cfg *ce_tgt_cfg; + u32 num_ce_svc_pipe_cfg; + struct ath10k_ce_svc_pipe_cfg *ce_svc_cfg; + u32 num_shadow_reg_cfg; + struct ath10k_shadow_reg_cfg *shadow_reg_cfg; +}; + +/* struct ath10k_snoc_qmi_driver_event: qmi driver event + * event_handled: event handled by event work handler + * sync: event synced + * ret: event received return value + * list: list to queue qmi event for process + * type: driver event type + * complete: completion for event handle complete + * data: encapsulate driver data for event handler callback + */ +struct ath10k_snoc_qmi_driver_event { + atomic_t event_handled; + bool sync; + int ret; + struct list_head list; + enum ath10k_snoc_driver_event_type type; + struct completion complete; + void *data; +}; + +/* struct ath10k_snoc_qmi_config: qmi service configuration + * fw_ready: wlan firmware ready for wlan operation + * msa_ready: wlan firmware msa memory ready for board data download + * server_connected: qmi server connected + * event_work: QMI event work + * event_list: QMI event list + * qmi_recv_msg_work: QMI message receive work + * event_wq: QMI event work queue + * wlfw_clnt_nb: WLAN firmware indication callback + * wlfw_clnt: QMI notifier handler for wlan firmware + * qmi_ev_list: QMI event list + * event_lock: spinlock for qmi event work queue + */ +struct ath10k_snoc_qmi_config { + atomic_t fw_ready; + bool msa_ready; + atomic_t server_connected; + struct work_struct event_work; + struct list_head event_list; + struct work_struct qmi_recv_msg_work; + struct workqueue_struct *event_wq; + struct notifier_block wlfw_clnt_nb; + struct qmi_handle *wlfw_clnt; + struct ath10k_snoc_qmi_driver_event + qmi_ev_list[ATH10K_SNOC_DRIVER_EVENT_MAX]; + spinlock_t event_lock; /* spinlock for qmi event work queue */ +}; + int ath10k_snoc_pd_restart_enable(struct ath10k *ar); int ath10k_snoc_modem_ssr_register_notifier(struct ath10k *ar); int ath10k_snoc_modem_ssr_unregister_notifier(struct ath10k *ar); int ath10k_snoc_pdr_unregister_notifier(struct ath10k *ar); - +int ath10k_snoc_start_qmi_service(struct ath10k *ar); +void ath10k_snoc_stop_qmi_service(struct ath10k *ar); +int ath10k_snoc_qmi_wlan_enable(struct ath10k *ar, + struct ath10k_wlan_enable_cfg *config, + enum ath10k_driver_mode mode, + const char *host_version); +int ath10k_snoc_qmi_wlan_disable(struct ath10k *ar); #endif diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 89042dcf70a0..add0a7cd9edb 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -17,7 +17,6 @@ #include <linux/interrupt.h> #include <linux/spinlock.h> #include <linux/bitops.h> - #include "core.h" #include "debug.h" #include "hif.h" @@ -25,10 +24,11 @@ #include "ce.h" #include "snoc.h" #include "qmi.h" -#include <soc/qcom/icnss.h> #include <linux/of.h> #include <linux/platform_device.h> + #define WCN3990_MAX_IRQ 12 + const char *ce_name[WCN3990_MAX_IRQ] = { "WLAN_CE_0", "WLAN_CE_1", @@ -957,7 +957,7 @@ static void ath10k_snoc_hif_power_down(struct ath10k *ar) { ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power down\n"); msleep(SNOC_HIF_POWER_DOWN_DELAY); - icnss_wlan_disable(ICNSS_OFF); + ath10k_snoc_qmi_wlan_disable(ar); } int ath10k_snoc_get_ce_id(struct ath10k *ar, int irq) @@ -1061,7 +1061,7 @@ static int ath10k_snoc_get_soc_info(struct ath10k *ar) static int ath10k_snoc_wlan_enable(struct ath10k *ar) { - struct icnss_wlan_enable_cfg cfg; + struct ath10k_wlan_enable_cfg cfg; int pipe_num; struct ath10k_ce_tgt_pipe_cfg tgt_cfg[CE_COUNT_MAX]; @@ -1080,19 +1080,20 @@ static int ath10k_snoc_wlan_enable(struct ath10k *ar) } cfg.num_ce_tgt_cfg = sizeof(target_ce_config_wlan) / - sizeof(struct ce_tgt_pipe_cfg); - cfg.ce_tgt_cfg = (struct ce_tgt_pipe_cfg *) + sizeof(struct ath10k_ce_tgt_pipe_cfg); + cfg.ce_tgt_cfg = (struct ath10k_ce_tgt_pipe_cfg *) &tgt_cfg; cfg.num_ce_svc_pipe_cfg = sizeof(target_service_to_ce_map_wlan) / - sizeof(struct ce_svc_pipe_cfg); - cfg.ce_svc_cfg = (struct ce_svc_pipe_cfg *) + sizeof(struct ath10k_ce_svc_pipe_cfg); + cfg.ce_svc_cfg = (struct ath10k_ce_svc_pipe_cfg *) &target_service_to_ce_map_wlan; cfg.num_shadow_reg_cfg = sizeof(target_shadow_reg_cfg_map) / - sizeof(struct icnss_shadow_reg_cfg); - cfg.shadow_reg_cfg = (struct icnss_shadow_reg_cfg *) + sizeof(struct ath10k_shadow_reg_cfg); + cfg.shadow_reg_cfg = (struct ath10k_shadow_reg_cfg *) &target_shadow_reg_cfg_map; - return icnss_wlan_enable(&cfg, ICNSS_MISSION, "5.1.0.26N"); + return ath10k_snoc_qmi_wlan_enable(ar, &cfg, + ATH10K_MISSION, "5.1.0.26N"); } static int ath10k_snoc_bus_configure(struct ath10k *ar) @@ -1245,6 +1246,12 @@ static int ath10k_snoc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ar); ar_snoc->ar = ar; + ret = ath10k_snoc_start_qmi_service(ar); + if (ret) { + ath10k_err(ar, "failed to start QMI service: %d\n", ret); + goto err_core_destroy; + } + spin_lock_init(&ar_snoc->opaque_ctx.ce_lock); ar_snoc->opaque_ctx.bus_ops = &ath10k_snoc_bus_ops; ath10k_snoc_resource_init(ar); @@ -1325,6 +1332,7 @@ static int ath10k_snoc_remove(struct platform_device *pdev) ath10k_snoc_free_irq(ar); ath10k_snoc_release_resource(ar); ath10k_snoc_free_pipes(ar); + ath10k_snoc_stop_qmi_service(ar); ath10k_core_destroy(ar); ath10k_dbg(ar, ATH10K_DBG_SNOC, "%s:WCN3990 removed\n", __func__); @@ -1352,10 +1360,6 @@ static int __init ath10k_snoc_init(void) { int ret; - if (!icnss_is_fw_ready()) { - pr_err("failed to get fw ready indication\n"); - return -EAGAIN; - } ret = platform_driver_register(&ath10k_snoc_driver); if (ret) pr_err("failed to register ath10k snoc driver: %d\n", diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h index c62519b2a340..99ae157885bb 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.h +++ b/drivers/net/wireless/ath/ath10k/snoc.h @@ -16,6 +16,7 @@ #include "hw.h" #include "ce.h" #include "pci.h" +#include "qmi.h" #include <soc/qcom/service-locator.h> #define ATH10K_SNOC_RX_POST_RETRY_MS 50 #define CE_POLL_PIPE 4 @@ -143,60 +144,7 @@ struct ath10k_snoc { int total_domains; struct notifier_block get_service_nb; atomic_t fw_crashed; -}; - -/* struct ath10k_ce_tgt_pipe_cfg: target pipe configuration - * @pipe_num: pipe number - * @pipe_dir: pipe direction - * @nentries: entries in pipe - * @nbytes_max: pipe max size - * @flags: pipe flags - * @reserved: reserved - */ -struct ath10k_ce_tgt_pipe_cfg { - u32 pipe_num; - u32 pipe_dir; - u32 nentries; - u32 nbytes_max; - u32 flags; - u32 reserved; -}; - -/* struct ath10k_ce_svc_pipe_cfg: service pipe configuration - * @service_id: target version - * @pipe_dir: pipe direction - * @pipe_num: pipe number - */ -struct ath10k_ce_svc_pipe_cfg { - u32 service_id; - u32 pipe_dir; - u32 pipe_num; -}; - -/* struct ath10k_shadow_reg_cfg: shadow register configuration - * @ce_id: copy engine id - * @reg_offset: offset to copy engine - */ -struct ath10k_shadow_reg_cfg { - u16 ce_id; - u16 reg_offset; -}; - -/* struct ath10k_wlan_enable_cfg: wlan enable configuration - * @num_ce_tgt_cfg: no of ce target configuration - * @ce_tgt_cfg: target ce configuration - * @num_ce_svc_pipe_cfg: no of ce service configuration - * @ce_svc_cfg: ce service configuration - * @num_shadow_reg_cfg: no of shadow registers - * @shadow_reg_cfg: shadow register configuration - */ -struct ath10k_wlan_enable_cfg { - u32 num_ce_tgt_cfg; - struct ath10k_ce_tgt_pipe_cfg *ce_tgt_cfg; - u32 num_ce_svc_pipe_cfg; - struct ath10k_ce_svc_pipe_cfg *ce_svc_cfg; - u32 num_shadow_reg_cfg; - struct ath10k_shadow_reg_cfg *shadow_reg_cfg; + struct ath10k_snoc_qmi_config qmi_cfg; }; struct ath10k_event_pd_down_data { @@ -204,19 +152,6 @@ struct ath10k_event_pd_down_data { bool fw_rejuvenate; }; -/* enum ath10k_driver_mode: ath10k driver mode - * @ATH10K_MISSION: mission mode - * @ATH10K_FTM: ftm mode - * @ATH10K_EPPING: epping mode - * @ATH10K_OFF: off mode - */ -enum ath10k_driver_mode { - ATH10K_MISSION, - ATH10K_FTM, - ATH10K_EPPING, - ATH10K_OFF -}; - static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar) { return (struct ath10k_snoc *)ar->drv_priv; diff --git a/drivers/net/wireless/ath/ath10k/wcn3990_qmi_service_v01.c b/drivers/net/wireless/ath/ath10k/wcn3990_qmi_service_v01.c new file mode 100644 index 000000000000..7d6cf8b23814 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/wcn3990_qmi_service_v01.c @@ -0,0 +1,2091 @@ + /* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include <linux/qmi_encdec.h> + +#include <soc/qcom/msm_qmi_interface.h> + +#include "wcn3990_qmi_service_v01.h" + +static struct elem_info wlfw_ce_tgt_pipe_cfg_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01, + pipe_num), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_pipedir_enum_v01), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01, + pipe_dir), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01, + nentries), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01, + nbytes_max), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01, + flags), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +static struct elem_info wlfw_ce_svc_pipe_cfg_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_ce_svc_pipe_cfg_s_v01, + service_id), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_pipedir_enum_v01), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_ce_svc_pipe_cfg_s_v01, + pipe_dir), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_ce_svc_pipe_cfg_s_v01, + pipe_num), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +static struct elem_info wlfw_shadow_reg_cfg_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint16_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_shadow_reg_cfg_s_v01, + id), + }, + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint16_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_shadow_reg_cfg_s_v01, + offset), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +static struct elem_info wlfw_shadow_reg_v2_cfg_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_shadow_reg_v2_cfg_s_v01, + addr), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +static struct elem_info wlfw_memory_region_info_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint64_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_memory_region_info_s_v01, + region_addr), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_memory_region_info_s_v01, + size), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_memory_region_info_s_v01, + secure_flag), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +static struct elem_info wlfw_rf_chip_info_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_rf_chip_info_s_v01, + chip_id), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_rf_chip_info_s_v01, + chip_family), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +static struct elem_info wlfw_rf_board_info_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_rf_board_info_s_v01, + board_id), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +static struct elem_info wlfw_soc_info_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_soc_info_s_v01, + soc_id), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +static struct elem_info wlfw_fw_version_info_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_fw_version_info_s_v01, + fw_version), + }, + { + .data_type = QMI_STRING, + .elem_len = QMI_WLFW_MAX_TIMESTAMP_LEN_V01 + 1, + .elem_size = sizeof(char), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_fw_version_info_s_v01, + fw_build_timestamp), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_ind_register_req_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + fw_ready_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + fw_ready_enable), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + initiate_cal_download_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + initiate_cal_download_enable), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + initiate_cal_update_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + initiate_cal_update_enable), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + msa_ready_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + msa_ready_enable), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + pin_connect_result_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + pin_connect_result_enable), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + client_id_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + client_id), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x16, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + request_mem_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x16, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + request_mem_enable), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x17, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + fw_mem_ready_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x17, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + fw_mem_ready_enable), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x18, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + cold_boot_cal_done_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x18, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + cold_boot_cal_done_enable), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x19, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + rejuvenate_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x19, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + rejuvenate_enable), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_ind_register_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof( + struct wlfw_ind_register_resp_msg_v01, + resp), + .ei_array = get_qmi_response_type_v01_ei(), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof( + struct wlfw_ind_register_resp_msg_v01, + fw_status_valid), + }, + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint64_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof( + struct wlfw_ind_register_resp_msg_v01, + fw_status), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_fw_ready_ind_msg_v01_ei[] = { + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_msa_ready_ind_msg_v01_ei[] = { + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_pin_connect_result_ind_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof( + struct wlfw_pin_connect_result_ind_msg_v01, + pwr_pin_result_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof( + struct wlfw_pin_connect_result_ind_msg_v01, + pwr_pin_result), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof( + struct wlfw_pin_connect_result_ind_msg_v01, + phy_io_pin_result_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof( + struct wlfw_pin_connect_result_ind_msg_v01, + phy_io_pin_result), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof( + struct wlfw_pin_connect_result_ind_msg_v01, + rf_pin_result_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof( + struct wlfw_pin_connect_result_ind_msg_v01, + rf_pin_result), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_wlan_mode_req_msg_v01_ei[] = { + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_driver_mode_enum_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_wlan_mode_req_msg_v01, + mode), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_wlan_mode_req_msg_v01, + hw_debug_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_wlan_mode_req_msg_v01, + hw_debug), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_wlan_mode_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_wlan_mode_resp_msg_v01, + resp), + .ei_array = get_qmi_response_type_v01_ei(), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_wlan_cfg_req_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + host_version_valid), + }, + { + .data_type = QMI_STRING, + .elem_len = QMI_WLFW_MAX_STR_LEN_V01 + 1, + .elem_size = sizeof(char), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + host_version), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + tgt_cfg_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + tgt_cfg_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_WLFW_MAX_NUM_CE_V01, + .elem_size = sizeof(struct wlfw_ce_tgt_pipe_cfg_s_v01), + .is_array = VAR_LEN_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + tgt_cfg), + .ei_array = wlfw_ce_tgt_pipe_cfg_s_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + svc_cfg_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + svc_cfg_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_WLFW_MAX_NUM_SVC_V01, + .elem_size = sizeof(struct wlfw_ce_svc_pipe_cfg_s_v01), + .is_array = VAR_LEN_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + svc_cfg), + .ei_array = wlfw_ce_svc_pipe_cfg_s_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + shadow_reg_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + shadow_reg_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V01, + .elem_size = sizeof(struct wlfw_shadow_reg_cfg_s_v01), + .is_array = VAR_LEN_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + shadow_reg), + .ei_array = wlfw_shadow_reg_cfg_s_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + shadow_reg_v2_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + shadow_reg_v2_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01, + .elem_size = sizeof(struct wlfw_shadow_reg_v2_cfg_s_v01), + .is_array = VAR_LEN_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + shadow_reg_v2), + .ei_array = wlfw_shadow_reg_v2_cfg_s_v01_ei, + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_wlan_cfg_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_wlan_cfg_resp_msg_v01, + resp), + .ei_array = get_qmi_response_type_v01_ei(), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_cap_req_msg_v01_ei[] = { + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_cap_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + resp), + .ei_array = get_qmi_response_type_v01_ei(), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + chip_info_valid), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct wlfw_rf_chip_info_s_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + chip_info), + .ei_array = wlfw_rf_chip_info_s_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + board_info_valid), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct wlfw_rf_board_info_s_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + board_info), + .ei_array = wlfw_rf_board_info_s_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + soc_info_valid), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct wlfw_soc_info_s_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + soc_info), + .ei_array = wlfw_soc_info_s_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + fw_version_info_valid), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct wlfw_fw_version_info_s_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + fw_version_info), + .ei_array = wlfw_fw_version_info_s_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + fw_build_id_valid), + }, + { + .data_type = QMI_STRING, + .elem_len = QMI_WLFW_MAX_BUILD_ID_LEN_V01 + 1, + .elem_size = sizeof(char), + .is_array = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + fw_build_id), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_bdf_download_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + valid), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + file_id_valid), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + file_id), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + total_size_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + total_size), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + seg_id_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + seg_id), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + data_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(uint16_t), + .is_array = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + data_len), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01, + .elem_size = sizeof(uint8_t), + .is_array = VAR_LEN_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + data), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + end_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + end), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_bdf_download_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof( + struct wlfw_bdf_download_resp_msg_v01, + resp), + .ei_array = get_qmi_response_type_v01_ei(), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_cal_report_req_msg_v01_ei[] = { + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_cal_report_req_msg_v01, + meta_data_len), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = QMI_WLFW_MAX_NUM_CAL_V01, + .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), + .is_array = VAR_LEN_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_cal_report_req_msg_v01, + meta_data), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_cal_report_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_cal_report_resp_msg_v01, + resp), + .ei_array = get_qmi_response_type_v01_ei(), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_initiate_cal_download_ind_msg_v01_ei[] = { + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof( + struct wlfw_initiate_cal_download_ind_msg_v01, + cal_id), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_cal_download_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + valid), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + file_id_valid), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + file_id), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + total_size_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + total_size), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + seg_id_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + seg_id), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + data_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(uint16_t), + .is_array = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + data_len), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01, + .elem_size = sizeof(uint8_t), + .is_array = VAR_LEN_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + data), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + end_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + end), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_cal_download_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof( + struct wlfw_cal_download_resp_msg_v01, + resp), + .ei_array = get_qmi_response_type_v01_ei(), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_initiate_cal_update_ind_msg_v01_ei[] = { + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof( + struct wlfw_initiate_cal_update_ind_msg_v01, + cal_id), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof( + struct wlfw_initiate_cal_update_ind_msg_v01, + total_size), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_cal_update_req_msg_v01_ei[] = { + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_cal_update_req_msg_v01, + cal_id), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_cal_update_req_msg_v01, + seg_id), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_cal_update_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + resp), + .ei_array = get_qmi_response_type_v01_ei(), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + file_id_valid), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + file_id), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + total_size_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + total_size), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + seg_id_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + seg_id), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + data_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(uint16_t), + .is_array = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + data_len), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01, + .elem_size = sizeof(uint8_t), + .is_array = VAR_LEN_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + data), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + end_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + end), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_msa_info_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint64_t), + .is_array = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_msa_info_req_msg_v01, + msa_addr), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_msa_info_req_msg_v01, + size), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_msa_info_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_msa_info_resp_msg_v01, + resp), + .ei_array = get_qmi_response_type_v01_ei(), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x03, + .offset = offsetof(struct wlfw_msa_info_resp_msg_v01, + mem_region_info_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01, + .elem_size = sizeof(struct wlfw_memory_region_info_s_v01), + .is_array = VAR_LEN_ARRAY, + .tlv_type = 0x03, + .offset = offsetof(struct wlfw_msa_info_resp_msg_v01, + mem_region_info), + .ei_array = wlfw_memory_region_info_s_v01_ei, + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_msa_ready_req_msg_v01_ei[] = { + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_msa_ready_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_msa_ready_resp_msg_v01, + resp), + .ei_array = get_qmi_response_type_v01_ei(), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_ini_req_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_ini_req_msg_v01, + enablefwlog_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_ini_req_msg_v01, + enablefwlog), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_ini_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_ini_resp_msg_v01, + resp), + .ei_array = get_qmi_response_type_v01_ei(), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_athdiag_read_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_athdiag_read_req_msg_v01, + offset), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_athdiag_read_req_msg_v01, + mem_type), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x03, + .offset = offsetof(struct wlfw_athdiag_read_req_msg_v01, + data_len), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_athdiag_read_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof( + struct wlfw_athdiag_read_resp_msg_v01, + resp), + .ei_array = get_qmi_response_type_v01_ei(), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof( + struct wlfw_athdiag_read_resp_msg_v01, + data_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(uint16_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof( + struct wlfw_athdiag_read_resp_msg_v01, + data_len), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01, + .elem_size = sizeof(uint8_t), + .is_array = VAR_LEN_ARRAY, + .tlv_type = 0x10, + .offset = offsetof( + struct wlfw_athdiag_read_resp_msg_v01, + data), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_athdiag_write_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof( + struct wlfw_athdiag_write_req_msg_v01, + offset), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof( + struct wlfw_athdiag_write_req_msg_v01, + mem_type), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(uint16_t), + .is_array = NO_ARRAY, + .tlv_type = 0x03, + .offset = offsetof( + struct wlfw_athdiag_write_req_msg_v01, + data_len), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01, + .elem_size = sizeof(uint8_t), + .is_array = VAR_LEN_ARRAY, + .tlv_type = 0x03, + .offset = offsetof( + struct wlfw_athdiag_write_req_msg_v01, + data), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_athdiag_write_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof( + struct wlfw_athdiag_write_resp_msg_v01, + resp), + .ei_array = get_qmi_response_type_v01_ei(), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_vbatt_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint64_t), + .is_array = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_vbatt_req_msg_v01, + voltage_uv), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_vbatt_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_vbatt_resp_msg_v01, + resp), + .ei_array = get_qmi_response_type_v01_ei(), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_mac_addr_req_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_mac_addr_req_msg_v01, + mac_addr_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = QMI_WLFW_MAC_ADDR_SIZE_V01, + .elem_size = sizeof(uint8_t), + .is_array = STATIC_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_mac_addr_req_msg_v01, + mac_addr), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_mac_addr_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_mac_addr_resp_msg_v01, + resp), + .ei_array = get_qmi_response_type_v01_ei(), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_host_cap_req_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + daemon_support_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + daemon_support), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_host_cap_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_host_cap_resp_msg_v01, + resp), + .ei_array = get_qmi_response_type_v01_ei(), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_request_mem_ind_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_request_mem_ind_msg_v01, + size), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_respond_mem_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint64_t), + .is_array = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_respond_mem_req_msg_v01, + addr), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_respond_mem_req_msg_v01, + size), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_respond_mem_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_respond_mem_resp_msg_v01, + resp), + .ei_array = get_qmi_response_type_v01_ei(), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_fw_mem_ready_ind_msg_v01_ei[] = { + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_cold_boot_cal_done_ind_msg_v01_ei[] = { + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_rejuvenate_ind_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, + cause_for_rejuvenation_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, + cause_for_rejuvenation), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, + requesting_sub_system_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, + requesting_sub_system), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, + line_number_valid), + }, + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint16_t), + .is_array = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, + line_number), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, + function_name_valid), + }, + { + .data_type = QMI_STRING, + .elem_len = QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1, + .elem_size = sizeof(char), + .is_array = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, + function_name), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_rejuvenate_ack_req_msg_v01_ei[] = { + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_rejuvenate_ack_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof( + struct wlfw_rejuvenate_ack_resp_msg_v01, + resp), + .ei_array = get_qmi_response_type_v01_ei(), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_dynamic_feature_mask_req_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct + wlfw_dynamic_feature_mask_req_msg_v01, + mask_valid), + }, + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint64_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof( + struct wlfw_dynamic_feature_mask_req_msg_v01, + mask), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_dynamic_feature_mask_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof( + struct wlfw_dynamic_feature_mask_resp_msg_v01, + resp), + .ei_array = get_qmi_response_type_v01_ei(), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof( + struct wlfw_dynamic_feature_mask_resp_msg_v01, + prev_mask_valid), + }, + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint64_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof( + struct wlfw_dynamic_feature_mask_resp_msg_v01, + prev_mask), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof( + struct wlfw_dynamic_feature_mask_resp_msg_v01, + curr_mask_valid), + }, + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint64_t), + .is_array = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof( + struct wlfw_dynamic_feature_mask_resp_msg_v01, + curr_mask), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + diff --git a/drivers/net/wireless/ath/ath10k/wcn3990_qmi_service_v01.h b/drivers/net/wireless/ath/ath10k/wcn3990_qmi_service_v01.h new file mode 100644 index 000000000000..21513b8f6200 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/wcn3990_qmi_service_v01.h @@ -0,0 +1,619 @@ + /* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef WLAN_FIRMWARE_SERVICE_V01_H +#define WLAN_FIRMWARE_SERVICE_V01_H + +#define WLFW_SERVICE_ID_V01 0x45 +#define WLFW_SERVICE_VERS_V01 0x01 + +#define QMI_WLFW_BDF_DOWNLOAD_REQ_V01 0x0025 +#define QMI_WLFW_FW_MEM_READY_IND_V01 0x0037 +#define QMI_WLFW_INITIATE_CAL_UPDATE_IND_V01 0x002A +#define QMI_WLFW_HOST_CAP_REQ_V01 0x0034 +#define QMI_WLFW_DYNAMIC_FEATURE_MASK_RESP_V01 0x003B +#define QMI_WLFW_CAP_REQ_V01 0x0024 +#define QMI_WLFW_CAL_REPORT_REQ_V01 0x0026 +#define QMI_WLFW_CAL_UPDATE_RESP_V01 0x0029 +#define QMI_WLFW_CAL_DOWNLOAD_RESP_V01 0x0027 +#define QMI_WLFW_INI_RESP_V01 0x002F +#define QMI_WLFW_CAL_REPORT_RESP_V01 0x0026 +#define QMI_WLFW_MAC_ADDR_RESP_V01 0x0033 +#define QMI_WLFW_INITIATE_CAL_DOWNLOAD_IND_V01 0x0028 +#define QMI_WLFW_HOST_CAP_RESP_V01 0x0034 +#define QMI_WLFW_MSA_READY_IND_V01 0x002B +#define QMI_WLFW_ATHDIAG_WRITE_RESP_V01 0x0031 +#define QMI_WLFW_WLAN_MODE_REQ_V01 0x0022 +#define QMI_WLFW_IND_REGISTER_REQ_V01 0x0020 +#define QMI_WLFW_WLAN_CFG_RESP_V01 0x0023 +#define QMI_WLFW_COLD_BOOT_CAL_DONE_IND_V01 0x0038 +#define QMI_WLFW_REQUEST_MEM_IND_V01 0x0035 +#define QMI_WLFW_REJUVENATE_IND_V01 0x0039 +#define QMI_WLFW_DYNAMIC_FEATURE_MASK_REQ_V01 0x003B +#define QMI_WLFW_ATHDIAG_WRITE_REQ_V01 0x0031 +#define QMI_WLFW_WLAN_MODE_RESP_V01 0x0022 +#define QMI_WLFW_RESPOND_MEM_REQ_V01 0x0036 +#define QMI_WLFW_PIN_CONNECT_RESULT_IND_V01 0x002C +#define QMI_WLFW_FW_READY_IND_V01 0x0021 +#define QMI_WLFW_MSA_READY_RESP_V01 0x002E +#define QMI_WLFW_CAL_UPDATE_REQ_V01 0x0029 +#define QMI_WLFW_INI_REQ_V01 0x002F +#define QMI_WLFW_BDF_DOWNLOAD_RESP_V01 0x0025 +#define QMI_WLFW_REJUVENATE_ACK_RESP_V01 0x003A +#define QMI_WLFW_MSA_INFO_RESP_V01 0x002D +#define QMI_WLFW_MSA_READY_REQ_V01 0x002E +#define QMI_WLFW_CAP_RESP_V01 0x0024 +#define QMI_WLFW_REJUVENATE_ACK_REQ_V01 0x003A +#define QMI_WLFW_ATHDIAG_READ_RESP_V01 0x0030 +#define QMI_WLFW_VBATT_REQ_V01 0x0032 +#define QMI_WLFW_MAC_ADDR_REQ_V01 0x0033 +#define QMI_WLFW_RESPOND_MEM_RESP_V01 0x0036 +#define QMI_WLFW_VBATT_RESP_V01 0x0032 +#define QMI_WLFW_MSA_INFO_REQ_V01 0x002D +#define QMI_WLFW_CAL_DOWNLOAD_REQ_V01 0x0027 +#define QMI_WLFW_ATHDIAG_READ_REQ_V01 0x0030 +#define QMI_WLFW_WLAN_CFG_REQ_V01 0x0023 +#define QMI_WLFW_IND_REGISTER_RESP_V01 0x0020 + +#define QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01 2 +#define QMI_WLFW_MAX_NUM_CAL_V01 5 +#define QMI_WLFW_MAX_DATA_SIZE_V01 6144 +#define QMI_WLFW_FUNCTION_NAME_LEN_V01 128 +#define QMI_WLFW_MAX_NUM_CE_V01 12 +#define QMI_WLFW_MAX_TIMESTAMP_LEN_V01 32 +#define QMI_WLFW_MAX_BUILD_ID_LEN_V01 128 +#define QMI_WLFW_MAX_STR_LEN_V01 16 +#define QMI_WLFW_MAX_NUM_SHADOW_REG_V01 24 +#define QMI_WLFW_MAC_ADDR_SIZE_V01 6 +#define QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01 36 +#define QMI_WLFW_MAX_NUM_SVC_V01 24 + +enum wlfw_driver_mode_enum_v01 { + WLFW_DRIVER_MODE_ENUM_MIN_VAL_V01 = INT_MIN, + QMI_WLFW_MISSION_V01 = 0, + QMI_WLFW_FTM_V01 = 1, + QMI_WLFW_EPPING_V01 = 2, + QMI_WLFW_WALTEST_V01 = 3, + QMI_WLFW_OFF_V01 = 4, + QMI_WLFW_CCPM_V01 = 5, + QMI_WLFW_QVIT_V01 = 6, + QMI_WLFW_CALIBRATION_V01 = 7, + WLFW_DRIVER_MODE_ENUM_MAX_VAL_V01 = INT_MAX, +}; + +enum wlfw_cal_temp_id_enum_v01 { + WLFW_CAL_TEMP_ID_ENUM_MIN_VAL_V01 = INT_MIN, + QMI_WLFW_CAL_TEMP_IDX_0_V01 = 0, + QMI_WLFW_CAL_TEMP_IDX_1_V01 = 1, + QMI_WLFW_CAL_TEMP_IDX_2_V01 = 2, + QMI_WLFW_CAL_TEMP_IDX_3_V01 = 3, + QMI_WLFW_CAL_TEMP_IDX_4_V01 = 4, + WLFW_CAL_TEMP_ID_ENUM_MAX_VAL_V01 = INT_MAX, +}; + +enum wlfw_pipedir_enum_v01 { + WLFW_PIPEDIR_ENUM_MIN_VAL_V01 = INT_MIN, + QMI_WLFW_PIPEDIR_NONE_V01 = 0, + QMI_WLFW_PIPEDIR_IN_V01 = 1, + QMI_WLFW_PIPEDIR_OUT_V01 = 2, + QMI_WLFW_PIPEDIR_INOUT_V01 = 3, + WLFW_PIPEDIR_ENUM_MAX_VAL_V01 = INT_MAX, +}; + +#define QMI_WLFW_CE_ATTR_FLAGS_V01 ((uint32_t)0x00) +#define QMI_WLFW_CE_ATTR_NO_SNOOP_V01 ((uint32_t)0x01) +#define QMI_WLFW_CE_ATTR_BYTE_SWAP_DATA_V01 ((uint32_t)0x02) +#define QMI_WLFW_CE_ATTR_SWIZZLE_DESCRIPTORS_V01 ((uint32_t)0x04) +#define QMI_WLFW_CE_ATTR_DISABLE_INTR_V01 ((uint32_t)0x08) +#define QMI_WLFW_CE_ATTR_ENABLE_POLL_V01 ((uint32_t)0x10) + +#define QMI_WLFW_ALREADY_REGISTERED_V01 ((uint64_t)0x01ULL) +#define QMI_WLFW_FW_READY_V01 ((uint64_t)0x02ULL) +#define QMI_WLFW_MSA_READY_V01 ((uint64_t)0x04ULL) +#define QMI_WLFW_FW_MEM_READY_V01 ((uint64_t)0x08ULL) + +#define QMI_WLFW_FW_REJUVENATE_V01 ((uint64_t)0x01ULL) + +struct wlfw_ce_tgt_pipe_cfg_s_v01 { + u32 pipe_num; + enum wlfw_pipedir_enum_v01 pipe_dir; + u32 nentries; + u32 nbytes_max; + u32 flags; +}; + +struct wlfw_ce_svc_pipe_cfg_s_v01 { + u32 service_id; + enum wlfw_pipedir_enum_v01 pipe_dir; + u32 pipe_num; +}; + +struct wlfw_shadow_reg_cfg_s_v01 { + u16 id; + u16 offset; +}; + +struct wlfw_shadow_reg_v2_cfg_s_v01 { + u32 addr; +}; + +struct wlfw_memory_region_info_s_v01 { + u64 region_addr; + u32 size; + u8 secure_flag; +}; + +struct wlfw_rf_chip_info_s_v01 { + u32 chip_id; + u32 chip_family; +}; + +struct wlfw_rf_board_info_s_v01 { + u32 board_id; +}; + +struct wlfw_soc_info_s_v01 { + u32 soc_id; +}; + +struct wlfw_fw_version_info_s_v01 { + u32 fw_version; + char fw_build_timestamp[QMI_WLFW_MAX_TIMESTAMP_LEN_V01 + 1]; +}; + +struct wlfw_ind_register_req_msg_v01 { + u8 fw_ready_enable_valid; + u8 fw_ready_enable; + u8 initiate_cal_download_enable_valid; + u8 initiate_cal_download_enable; + u8 initiate_cal_update_enable_valid; + u8 initiate_cal_update_enable; + u8 msa_ready_enable_valid; + u8 msa_ready_enable; + u8 pin_connect_result_enable_valid; + u8 pin_connect_result_enable; + u8 client_id_valid; + u32 client_id; + u8 request_mem_enable_valid; + u8 request_mem_enable; + u8 fw_mem_ready_enable_valid; + u8 fw_mem_ready_enable; + u8 cold_boot_cal_done_enable_valid; + u8 cold_boot_cal_done_enable; + u8 rejuvenate_enable_valid; + u32 rejuvenate_enable; +}; + +#define WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN 46 +extern struct elem_info wlfw_ind_register_req_msg_v01_ei[]; + +struct wlfw_ind_register_resp_msg_v01 { + struct qmi_response_type_v01 resp; + u8 fw_status_valid; + u64 fw_status; +}; + +#define WLFW_IND_REGISTER_RESP_MSG_V01_MAX_MSG_LEN 18 +extern struct elem_info wlfw_ind_register_resp_msg_v01_ei[]; + +struct wlfw_fw_ready_ind_msg_v01 { + char placeholder; +}; + +#define WLFW_FW_READY_IND_MSG_V01_MAX_MSG_LEN 0 +extern struct elem_info wlfw_fw_ready_ind_msg_v01_ei[]; + +struct wlfw_msa_ready_ind_msg_v01 { + char placeholder; +}; + +#define WLFW_MSA_READY_IND_MSG_V01_MAX_MSG_LEN 0 +extern struct elem_info wlfw_msa_ready_ind_msg_v01_ei[]; + +struct wlfw_pin_connect_result_ind_msg_v01 { + u8 pwr_pin_result_valid; + u32 pwr_pin_result; + u8 phy_io_pin_result_valid; + u32 phy_io_pin_result; + u8 rf_pin_result_valid; + u32 rf_pin_result; +}; + +#define WLFW_PIN_CONNECT_RESULT_IND_MSG_V01_MAX_MSG_LEN 21 +extern struct elem_info wlfw_pin_connect_result_ind_msg_v01_ei[]; + +struct wlfw_wlan_mode_req_msg_v01 { + enum wlfw_driver_mode_enum_v01 mode; + u8 hw_debug_valid; + u8 hw_debug; +}; + +#define WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN 11 +extern struct elem_info wlfw_wlan_mode_req_msg_v01_ei[]; + +struct wlfw_wlan_mode_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_WLAN_MODE_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct elem_info wlfw_wlan_mode_resp_msg_v01_ei[]; + +struct wlfw_wlan_cfg_req_msg_v01 { + u8 host_version_valid; + char host_version[QMI_WLFW_MAX_STR_LEN_V01 + 1]; + u8 tgt_cfg_valid; + u32 tgt_cfg_len; + struct wlfw_ce_tgt_pipe_cfg_s_v01 tgt_cfg[QMI_WLFW_MAX_NUM_CE_V01]; + u8 svc_cfg_valid; + u32 svc_cfg_len; + struct wlfw_ce_svc_pipe_cfg_s_v01 svc_cfg[QMI_WLFW_MAX_NUM_SVC_V01]; + u8 shadow_reg_valid; + u32 shadow_reg_len; + struct wlfw_shadow_reg_cfg_s_v01 + shadow_reg[QMI_WLFW_MAX_NUM_SHADOW_REG_V01]; + u8 shadow_reg_v2_valid; + u32 shadow_reg_v2_len; + struct wlfw_shadow_reg_v2_cfg_s_v01 + shadow_reg_v2[QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01]; +}; + +#define WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN 803 +extern struct elem_info wlfw_wlan_cfg_req_msg_v01_ei[]; + +struct wlfw_wlan_cfg_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_WLAN_CFG_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct elem_info wlfw_wlan_cfg_resp_msg_v01_ei[]; + +struct wlfw_cap_req_msg_v01 { + char placeholder; +}; + +#define WLFW_CAP_REQ_MSG_V01_MAX_MSG_LEN 0 +extern struct elem_info wlfw_cap_req_msg_v01_ei[]; + +struct wlfw_cap_resp_msg_v01 { + struct qmi_response_type_v01 resp; + u8 chip_info_valid; + struct wlfw_rf_chip_info_s_v01 chip_info; + u8 board_info_valid; + struct wlfw_rf_board_info_s_v01 board_info; + u8 soc_info_valid; + struct wlfw_soc_info_s_v01 soc_info; + u8 fw_version_info_valid; + struct wlfw_fw_version_info_s_v01 fw_version_info; + u8 fw_build_id_valid; + char fw_build_id[QMI_WLFW_MAX_BUILD_ID_LEN_V01 + 1]; +}; + +#define WLFW_CAP_RESP_MSG_V01_MAX_MSG_LEN 203 +extern struct elem_info wlfw_cap_resp_msg_v01_ei[]; + +struct wlfw_bdf_download_req_msg_v01 { + u8 valid; + u8 file_id_valid; + enum wlfw_cal_temp_id_enum_v01 file_id; + u8 total_size_valid; + u32 total_size; + u8 seg_id_valid; + u32 seg_id; + u8 data_valid; + u32 data_len; + u8 data[QMI_WLFW_MAX_DATA_SIZE_V01]; + u8 end_valid; + u8 end; +}; + +#define WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN 6178 +extern struct elem_info wlfw_bdf_download_req_msg_v01_ei[]; + +struct wlfw_bdf_download_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_BDF_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct elem_info wlfw_bdf_download_resp_msg_v01_ei[]; + +struct wlfw_cal_report_req_msg_v01 { + u32 meta_data_len; + enum wlfw_cal_temp_id_enum_v01 meta_data[QMI_WLFW_MAX_NUM_CAL_V01]; +}; + +#define WLFW_CAL_REPORT_REQ_MSG_V01_MAX_MSG_LEN 24 +extern struct elem_info wlfw_cal_report_req_msg_v01_ei[]; + +struct wlfw_cal_report_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_CAL_REPORT_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct elem_info wlfw_cal_report_resp_msg_v01_ei[]; + +struct wlfw_initiate_cal_download_ind_msg_v01 { + enum wlfw_cal_temp_id_enum_v01 cal_id; +}; + +#define WLFW_INITIATE_CAL_DOWNLOAD_IND_MSG_V01_MAX_MSG_LEN 7 +extern struct elem_info wlfw_initiate_cal_download_ind_msg_v01_ei[]; + +struct wlfw_cal_download_req_msg_v01 { + u8 valid; + u8 file_id_valid; + enum wlfw_cal_temp_id_enum_v01 file_id; + u8 total_size_valid; + u32 total_size; + u8 seg_id_valid; + u32 seg_id; + u8 data_valid; + u32 data_len; + u8 data[QMI_WLFW_MAX_DATA_SIZE_V01]; + u8 end_valid; + u8 end; +}; + +#define WLFW_CAL_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN 6178 +extern struct elem_info wlfw_cal_download_req_msg_v01_ei[]; + +struct wlfw_cal_download_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_CAL_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct elem_info wlfw_cal_download_resp_msg_v01_ei[]; + +struct wlfw_initiate_cal_update_ind_msg_v01 { + enum wlfw_cal_temp_id_enum_v01 cal_id; + u32 total_size; +}; + +#define WLFW_INITIATE_CAL_UPDATE_IND_MSG_V01_MAX_MSG_LEN 14 +extern struct elem_info wlfw_initiate_cal_update_ind_msg_v01_ei[]; + +struct wlfw_cal_update_req_msg_v01 { + enum wlfw_cal_temp_id_enum_v01 cal_id; + u32 seg_id; +}; + +#define WLFW_CAL_UPDATE_REQ_MSG_V01_MAX_MSG_LEN 14 +extern struct elem_info wlfw_cal_update_req_msg_v01_ei[]; + +struct wlfw_cal_update_resp_msg_v01 { + struct qmi_response_type_v01 resp; + u8 file_id_valid; + enum wlfw_cal_temp_id_enum_v01 file_id; + u8 total_size_valid; + u32 total_size; + u8 seg_id_valid; + u32 seg_id; + u8 data_valid; + u32 data_len; + u8 data[QMI_WLFW_MAX_DATA_SIZE_V01]; + u8 end_valid; + u8 end; +}; + +#define WLFW_CAL_UPDATE_RESP_MSG_V01_MAX_MSG_LEN 6181 +extern struct elem_info wlfw_cal_update_resp_msg_v01_ei[]; + +struct wlfw_msa_info_req_msg_v01 { + u64 msa_addr; + u32 size; +}; + +#define WLFW_MSA_INFO_REQ_MSG_V01_MAX_MSG_LEN 18 +extern struct elem_info wlfw_msa_info_req_msg_v01_ei[]; + +struct wlfw_msa_info_resp_msg_v01 { + struct qmi_response_type_v01 resp; + u32 mem_region_info_len; + struct wlfw_memory_region_info_s_v01 + mem_region_info[QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01]; +}; + +#define WLFW_MSA_INFO_RESP_MSG_V01_MAX_MSG_LEN 37 +extern struct elem_info wlfw_msa_info_resp_msg_v01_ei[]; + +struct wlfw_msa_ready_req_msg_v01 { + char placeholder; +}; + +#define WLFW_MSA_READY_REQ_MSG_V01_MAX_MSG_LEN 0 +extern struct elem_info wlfw_msa_ready_req_msg_v01_ei[]; + +struct wlfw_msa_ready_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_MSA_READY_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct elem_info wlfw_msa_ready_resp_msg_v01_ei[]; + +struct wlfw_ini_req_msg_v01 { + u8 enablefwlog_valid; + u8 enablefwlog; +}; + +#define WLFW_INI_REQ_MSG_V01_MAX_MSG_LEN 4 +extern struct elem_info wlfw_ini_req_msg_v01_ei[]; + +struct wlfw_ini_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_INI_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct elem_info wlfw_ini_resp_msg_v01_ei[]; + +struct wlfw_athdiag_read_req_msg_v01 { + u32 offset; + u32 mem_type; + u32 data_len; +}; + +#define WLFW_ATHDIAG_READ_REQ_MSG_V01_MAX_MSG_LEN 21 +extern struct elem_info wlfw_athdiag_read_req_msg_v01_ei[]; + +struct wlfw_athdiag_read_resp_msg_v01 { + struct qmi_response_type_v01 resp; + u8 data_valid; + u32 data_len; + u8 data[QMI_WLFW_MAX_DATA_SIZE_V01]; +}; + +#define WLFW_ATHDIAG_READ_RESP_MSG_V01_MAX_MSG_LEN 6156 +extern struct elem_info wlfw_athdiag_read_resp_msg_v01_ei[]; + +struct wlfw_athdiag_write_req_msg_v01 { + u32 offset; + u32 mem_type; + u32 data_len; + u8 data[QMI_WLFW_MAX_DATA_SIZE_V01]; +}; + +#define WLFW_ATHDIAG_WRITE_REQ_MSG_V01_MAX_MSG_LEN 6163 +extern struct elem_info wlfw_athdiag_write_req_msg_v01_ei[]; + +struct wlfw_athdiag_write_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_ATHDIAG_WRITE_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct elem_info wlfw_athdiag_write_resp_msg_v01_ei[]; + +struct wlfw_vbatt_req_msg_v01 { + u64 voltage_uv; +}; + +#define WLFW_VBATT_REQ_MSG_V01_MAX_MSG_LEN 11 +extern struct elem_info wlfw_vbatt_req_msg_v01_ei[]; + +struct wlfw_vbatt_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_VBATT_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct elem_info wlfw_vbatt_resp_msg_v01_ei[]; + +struct wlfw_mac_addr_req_msg_v01 { + u8 mac_addr_valid; + u8 mac_addr[QMI_WLFW_MAC_ADDR_SIZE_V01]; +}; + +#define WLFW_MAC_ADDR_REQ_MSG_V01_MAX_MSG_LEN 9 +extern struct elem_info wlfw_mac_addr_req_msg_v01_ei[]; + +struct wlfw_mac_addr_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_MAC_ADDR_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct elem_info wlfw_mac_addr_resp_msg_v01_ei[]; + +struct wlfw_host_cap_req_msg_v01 { + u8 daemon_support_valid; + u8 daemon_support; +}; + +#define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 4 +extern struct elem_info wlfw_host_cap_req_msg_v01_ei[]; + +struct wlfw_host_cap_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_HOST_CAP_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct elem_info wlfw_host_cap_resp_msg_v01_ei[]; + +struct wlfw_request_mem_ind_msg_v01 { + u32 size; +}; + +#define WLFW_REQUEST_MEM_IND_MSG_V01_MAX_MSG_LEN 7 +extern struct elem_info wlfw_request_mem_ind_msg_v01_ei[]; + +struct wlfw_respond_mem_req_msg_v01 { + u64 addr; + u32 size; +}; + +#define WLFW_RESPOND_MEM_REQ_MSG_V01_MAX_MSG_LEN 18 +extern struct elem_info wlfw_respond_mem_req_msg_v01_ei[]; + +struct wlfw_respond_mem_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_RESPOND_MEM_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct elem_info wlfw_respond_mem_resp_msg_v01_ei[]; + +struct wlfw_fw_mem_ready_ind_msg_v01 { + char placeholder; +}; + +#define WLFW_FW_MEM_READY_IND_MSG_V01_MAX_MSG_LEN 0 +extern struct elem_info wlfw_fw_mem_ready_ind_msg_v01_ei[]; + +struct wlfw_cold_boot_cal_done_ind_msg_v01 { + char placeholder; +}; + +#define WLFW_COLD_BOOT_CAL_DONE_IND_MSG_V01_MAX_MSG_LEN 0 +extern struct elem_info wlfw_cold_boot_cal_done_ind_msg_v01_ei[]; + +struct wlfw_rejuvenate_ind_msg_v01 { + u8 cause_for_rejuvenation_valid; + u8 cause_for_rejuvenation; + u8 requesting_sub_system_valid; + u8 requesting_sub_system; + u8 line_number_valid; + u16 line_number; + u8 function_name_valid; + char function_name[QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1]; +}; + +#define WLFW_REJUVENATE_IND_MSG_V01_MAX_MSG_LEN 144 +extern struct elem_info wlfw_rejuvenate_ind_msg_v01_ei[]; + +struct wlfw_rejuvenate_ack_req_msg_v01 { + char placeholder; +}; + +#define WLFW_REJUVENATE_ACK_REQ_MSG_V01_MAX_MSG_LEN 0 +extern struct elem_info wlfw_rejuvenate_ack_req_msg_v01_ei[]; + +struct wlfw_rejuvenate_ack_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_REJUVENATE_ACK_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct elem_info wlfw_rejuvenate_ack_resp_msg_v01_ei[]; + +struct wlfw_dynamic_feature_mask_req_msg_v01 { + u8 mask_valid; + u64 mask; +}; + +#define WLFW_DYNAMIC_FEATURE_MASK_REQ_MSG_V01_MAX_MSG_LEN 11 +extern struct elem_info wlfw_dynamic_feature_mask_req_msg_v01_ei[]; + +struct wlfw_dynamic_feature_mask_resp_msg_v01 { + struct qmi_response_type_v01 resp; + u8 prev_mask_valid; + u64 prev_mask; + u8 curr_mask_valid; + u64 curr_mask; +}; + +#define WLFW_DYNAMIC_FEATURE_MASK_RESP_MSG_V01_MAX_MSG_LEN 29 +extern struct elem_info wlfw_dynamic_feature_mask_resp_msg_v01_ei[]; + +#endif diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 923fe470360c..6b8bdfbca8ca 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -501,9 +501,9 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, for (i = 0; i < request->n_ssids; i++) { wil_dbg_misc(wil, "SSID[%d]", i); - print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET, - request->ssids[i].ssid, - request->ssids[i].ssid_len); + wil_hex_dump_misc("SSID ", DUMP_PREFIX_OFFSET, 16, 1, + request->ssids[i].ssid, + request->ssids[i].ssid_len, true); } if (request->n_ssids) @@ -540,8 +540,8 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, } if (request->ie_len) - print_hex_dump_bytes("Scan IE ", DUMP_PREFIX_OFFSET, - request->ie, request->ie_len); + wil_hex_dump_misc("Scan IE ", DUMP_PREFIX_OFFSET, 16, 1, + request->ie, request->ie_len, true); else wil_dbg_misc(wil, "Scan has no IE's\n"); @@ -847,7 +847,8 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, */ wil_dbg_misc(wil, "mgmt_tx\n"); - print_hex_dump_bytes("mgmt tx frame ", DUMP_PREFIX_OFFSET, buf, len); + wil_hex_dump_misc("mgmt tx frame ", DUMP_PREFIX_OFFSET, 16, 1, buf, + len, true); cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL); if (!cmd) { @@ -1180,18 +1181,18 @@ static int _wil_cfg80211_merge_extra_ies(const u8 *ies1, u16 ies1_len, static void wil_print_bcon_data(struct cfg80211_beacon_data *b) { - print_hex_dump_bytes("head ", DUMP_PREFIX_OFFSET, - b->head, b->head_len); - print_hex_dump_bytes("tail ", DUMP_PREFIX_OFFSET, - b->tail, b->tail_len); - print_hex_dump_bytes("BCON IE ", DUMP_PREFIX_OFFSET, - b->beacon_ies, b->beacon_ies_len); - print_hex_dump_bytes("PROBE ", DUMP_PREFIX_OFFSET, - b->probe_resp, b->probe_resp_len); - print_hex_dump_bytes("PROBE IE ", DUMP_PREFIX_OFFSET, - b->proberesp_ies, b->proberesp_ies_len); - print_hex_dump_bytes("ASSOC IE ", DUMP_PREFIX_OFFSET, - b->assocresp_ies, b->assocresp_ies_len); + wil_hex_dump_misc("head ", DUMP_PREFIX_OFFSET, 16, 1, + b->head, b->head_len, true); + wil_hex_dump_misc("tail ", DUMP_PREFIX_OFFSET, 16, 1, + b->tail, b->tail_len, true); + wil_hex_dump_misc("BCON IE ", DUMP_PREFIX_OFFSET, 16, 1, + b->beacon_ies, b->beacon_ies_len, true); + wil_hex_dump_misc("PROBE ", DUMP_PREFIX_OFFSET, 16, 1, + b->probe_resp, b->probe_resp_len, true); + wil_hex_dump_misc("PROBE IE ", DUMP_PREFIX_OFFSET, 16, 1, + b->proberesp_ies, b->proberesp_ies_len, true); + wil_hex_dump_misc("ASSOC IE ", DUMP_PREFIX_OFFSET, 16, 1, + b->assocresp_ies, b->assocresp_ies_len, true); } /* internal functions for device reset and starting AP */ @@ -1387,8 +1388,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, wil_dbg_misc(wil, "BI %d DTIM %d\n", info->beacon_interval, info->dtim_period); wil_dbg_misc(wil, "PBSS %d\n", info->pbss); - print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET, - info->ssid, info->ssid_len); + wil_hex_dump_misc("SSID ", DUMP_PREFIX_OFFSET, 16, 1, + info->ssid, info->ssid_len, true); wil_print_bcon_data(bcon); wil_print_crypto(wil, crypto); diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index dc22a29349cb..4a299f238c54 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -524,9 +524,8 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf, if (!buf) return -ENOMEM; - wil_memcpy_fromio_halp_vote(wil_blob->wil, buf, - (const volatile void __iomem *) - wil_blob->blob.data + pos, count); + wil_memcpy_fromio_32(buf, (const void __iomem *) + wil_blob->blob.data + pos, count); ret = copy_to_user(user_buf, buf, count); kfree(buf); diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 01a27335ec34..5a743e150cad 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -141,14 +141,6 @@ void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src, } } -void wil_memcpy_fromio_halp_vote(struct wil6210_priv *wil, void *dst, - const volatile void __iomem *src, size_t count) -{ - wil_halp_vote(wil); - wil_memcpy_fromio_32(dst, src, count); - wil_halp_unvote(wil); -} - void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, size_t count) { @@ -167,15 +159,6 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, } } -void wil_memcpy_toio_halp_vote(struct wil6210_priv *wil, - volatile void __iomem *dst, - const void *src, size_t count) -{ - wil_halp_vote(wil); - wil_memcpy_toio_32(dst, src, count); - wil_halp_unvote(wil); -} - static void wil_disconnect_cid(struct wil6210_priv *wil, int cid, u16 reason_code, bool from_event) __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) @@ -1181,6 +1164,7 @@ void wil_halp_vote(struct wil6210_priv *wil) wil->halp.ref_cnt); if (++wil->halp.ref_cnt == 1) { + reinit_completion(&wil->halp.comp); wil6210_set_halp(wil); rc = wait_for_completion_timeout(&wil->halp.comp, to_jiffies); if (!rc) { diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c index 7260bef314a4..2ae4fe85cc8c 100644 --- a/drivers/net/wireless/ath/wil6210/pm.c +++ b/drivers/net/wireless/ath/wil6210/pm.c @@ -71,6 +71,11 @@ int wil_suspend(struct wil6210_priv *wil, bool is_runtime) wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system"); + if (test_bit(wil_status_suspended, wil->status)) { + wil_dbg_pm(wil, "trying to suspend while suspended\n"); + return 0; + } + /* if netif up, hardware is alive, shut it down */ if (ndev->flags & IFF_UP) { rc = wil_down(wil); @@ -86,10 +91,14 @@ int wil_suspend(struct wil6210_priv *wil, bool is_runtime) if (wil->platform_ops.suspend) { rc = wil->platform_ops.suspend(wil->platform_handle); - if (rc) + if (rc) { wil_enable_irq(wil); + goto out; + } } + set_bit(wil_status_suspended, wil->status); + out: wil_dbg_pm(wil, "suspend: %s => %d\n", is_runtime ? "runtime" : "system", rc); @@ -117,10 +126,13 @@ int wil_resume(struct wil6210_priv *wil, bool is_runtime) /* if netif up, bring hardware up * During open(), IFF_UP set after actual device method - * invocation. This prevent recursive call to wil_up() + * invocation. This prevent recursive call to wil_up(). + * wil_status_suspended will be cleared in wil_reset */ if (ndev->flags & IFF_UP) rc = wil_up(wil); + else + clear_bit(wil_status_suspended, wil->status); out: wil_dbg_pm(wil, "resume: %s => %d\n", diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index f64323b03a3b..93703c059bb1 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -417,6 +417,7 @@ enum { /* for wil6210_priv.status */ wil_status_irqen, /* FIXME: interrupts enabled - for debug */ wil_status_napi_en, /* NAPI enabled protected by wil->mutex */ wil_status_resetting, /* reset in progress */ + wil_status_suspended, /* suspend completed, device is suspended */ wil_status_last /* keep last */ }; @@ -777,6 +778,12 @@ static inline void wil_c(struct wil6210_priv *wil, u32 reg, u32 val) print_hex_dump_debug("DBG[ WMI]" prefix_str,\ prefix_type, rowsize, \ groupsize, buf, len, ascii) + +#define wil_hex_dump_misc(prefix_str, prefix_type, rowsize, \ + groupsize, buf, len, ascii) \ + print_hex_dump_debug("DBG[MISC]" prefix_str,\ + prefix_type, rowsize, \ + groupsize, buf, len, ascii) #else /* defined(CONFIG_DYNAMIC_DEBUG) */ static inline void wil_hex_dump_txrx(const char *prefix_str, int prefix_type, int rowsize, @@ -789,18 +796,18 @@ void wil_hex_dump_wmi(const char *prefix_str, int prefix_type, int rowsize, int groupsize, const void *buf, size_t len, bool ascii) { } + +static inline +void wil_hex_dump_misc(const char *prefix_str, int prefix_type, int rowsize, + int groupsize, const void *buf, size_t len, bool ascii) +{ +} #endif /* defined(CONFIG_DYNAMIC_DEBUG) */ void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src, size_t count); void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, size_t count); -void wil_memcpy_fromio_halp_vote(struct wil6210_priv *wil, void *dst, - const volatile void __iomem *src, - size_t count); -void wil_memcpy_toio_halp_vote(struct wil6210_priv *wil, - volatile void __iomem *dst, - const void *src, size_t count); void *wil_if_alloc(struct device *dev); void wil_if_free(struct wil6210_priv *wil); diff --git a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c index 913f756f9520..e93416ebd343 100644 --- a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c +++ b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c @@ -11,10 +11,15 @@ */ #include <linux/module.h> #include <linux/slab.h> +#include <linux/seq_file.h> #include <linux/err.h> #include <linux/stacktrace.h> #include <linux/wcnss_wlan.h> #include <linux/spinlock.h> +#include <linux/debugfs.h> +#ifdef CONFIG_WCNSS_SKB_PRE_ALLOC +#include <linux/skbuff.h> +#endif static DEFINE_SPINLOCK(alloc_lock); @@ -22,6 +27,11 @@ static DEFINE_SPINLOCK(alloc_lock); #define WCNSS_MAX_STACK_TRACE 64 #endif +#define PRE_ALLOC_DEBUGFS_DIR "cnss-prealloc" +#define PRE_ALLOC_DEBUGFS_FILE_OBJ "status" + +static struct dentry *debug_base; + struct wcnss_prealloc { int occupied; unsigned int size; @@ -216,6 +226,8 @@ void wcnss_prealloc_check_memory_leak(void) } } +#else +void wcnss_prealloc_check_memory_leak(void) {} #endif int wcnss_pre_alloc_reset(void) @@ -233,14 +245,89 @@ int wcnss_pre_alloc_reset(void) return n; } +int prealloc_memory_stats_show(struct seq_file *fp, void *data) +{ + int i = 0; + int used_slots = 0, free_slots = 0; + unsigned int tsize = 0, tused = 0, size = 0; + + seq_puts(fp, "\nSlot_Size(Kb)\t\t[Used : Free]\n"); + for (i = 0; i < ARRAY_SIZE(wcnss_allocs); i++) { + tsize += wcnss_allocs[i].size; + if (size != wcnss_allocs[i].size) { + if (size) { + seq_printf( + fp, "[%d : %d]\n", + used_slots, free_slots); + } + + size = wcnss_allocs[i].size; + used_slots = 0; + free_slots = 0; + seq_printf(fp, "%d Kb\t\t\t", size / 1024); + } + + if (wcnss_allocs[i].occupied) { + tused += wcnss_allocs[i].size; + ++used_slots; + } else { + ++free_slots; + } + } + seq_printf(fp, "[%d : %d]\n", used_slots, free_slots); + + /* Convert byte to Kb */ + if (tsize) + tsize = tsize / 1024; + if (tused) + tused = tused / 1024; + seq_printf(fp, "\nMemory Status:\nTotal Memory: %dKb\n", tsize); + seq_printf(fp, "Used: %dKb\nFree: %dKb\n", tused, tsize - tused); + + return 0; +} + +int prealloc_memory_stats_open(struct inode *inode, struct file *file) +{ + return single_open(file, prealloc_memory_stats_show, NULL); +} + +static const struct file_operations prealloc_memory_stats_fops = { + .owner = THIS_MODULE, + .open = prealloc_memory_stats_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int __init wcnss_pre_alloc_init(void) { - return wcnss_prealloc_init(); + int ret; + + ret = wcnss_prealloc_init(); + if (ret) { + pr_err("%s: Failed to init the prealloc pool\n", __func__); + return ret; + } + + debug_base = debugfs_create_dir(PRE_ALLOC_DEBUGFS_DIR, NULL); + if (IS_ERR_OR_NULL(debug_base)) { + pr_err("%s: Failed to create debugfs dir\n", __func__); + } else if (IS_ERR_OR_NULL(debugfs_create_file( + PRE_ALLOC_DEBUGFS_FILE_OBJ, + 0644, debug_base, NULL, + &prealloc_memory_stats_fops))) { + pr_err("%s: Failed to create debugfs file\n", __func__); + debugfs_remove_recursive(debug_base); + } + + return ret; } static void __exit wcnss_pre_alloc_exit(void) { wcnss_prealloc_deinit(); + debugfs_remove_recursive(debug_base); } module_init(wcnss_pre_alloc_init); diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c index eade4f85632a..121c994e6033 100644 --- a/drivers/pci/host/pci-msm.c +++ b/drivers/pci/host/pci-msm.c @@ -24,6 +24,7 @@ #include <linux/kernel.h> #include <linux/of_pci.h> #include <linux/pci.h> +#include <linux/iommu.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include <linux/regulator/rpm-smd-regulator.h> @@ -480,6 +481,11 @@ enum msm_pcie_link_status { MSM_PCIE_LINK_DISABLED }; +enum msm_pcie_boot_option { + MSM_PCIE_NO_PROBE_ENUMERATION = BIT(0), + MSM_PCIE_NO_WAKE_ENUMERATION = BIT(1) +}; + /* gpio info structure */ struct msm_pcie_gpio_info_t { char *name; @@ -628,7 +634,7 @@ struct msm_pcie_dev_t { uint32_t perst_delay_us_max; uint32_t tlp_rd_size; bool linkdown_panic; - bool ep_wakeirq; + uint32_t boot_option; uint32_t rc_idx; uint32_t phy_ver; @@ -1946,8 +1952,8 @@ static void msm_pcie_show_status(struct msm_pcie_dev_t *dev) dev->aer_enable ? "" : "not"); PCIE_DBG_FS(dev, "ext_ref_clk is %d\n", dev->ext_ref_clk); - PCIE_DBG_FS(dev, "ep_wakeirq is %d\n", - dev->ep_wakeirq); + PCIE_DBG_FS(dev, "boot_option is 0x%x\n", + dev->boot_option); PCIE_DBG_FS(dev, "phy_ver is %d\n", dev->phy_ver); PCIE_DBG_FS(dev, "drv_ready is %d\n", @@ -2562,7 +2568,7 @@ static struct dentry *dfile_linkdown_panic; static struct dentry *dfile_wr_offset; static struct dentry *dfile_wr_mask; static struct dentry *dfile_wr_value; -static struct dentry *dfile_ep_wakeirq; +static struct dentry *dfile_boot_option; static struct dentry *dfile_aer_enable; static struct dentry *dfile_corr_counter_limit; @@ -2831,13 +2837,13 @@ const struct file_operations msm_pcie_wr_value_ops = { .write = msm_pcie_set_wr_value, }; -static ssize_t msm_pcie_set_ep_wakeirq(struct file *file, +static ssize_t msm_pcie_set_boot_option(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { unsigned long ret; char str[MAX_MSG_LEN]; - u32 new_ep_wakeirq = 0; + u32 new_boot_option = 0; int i; memset(str, 0, sizeof(str)); @@ -2846,33 +2852,33 @@ static ssize_t msm_pcie_set_ep_wakeirq(struct file *file, return -EFAULT; for (i = 0; i < sizeof(str) && (str[i] >= '0') && (str[i] <= '9'); ++i) - new_ep_wakeirq = (new_ep_wakeirq * 10) + (str[i] - '0'); + new_boot_option = (new_boot_option * 10) + (str[i] - '0'); - if (new_ep_wakeirq <= 1) { + if (new_boot_option <= 1) { for (i = 0; i < MAX_RC_NUM; i++) { if (!rc_sel) { - msm_pcie_dev[0].ep_wakeirq = new_ep_wakeirq; + msm_pcie_dev[0].boot_option = new_boot_option; PCIE_DBG_FS(&msm_pcie_dev[0], - "PCIe: RC0: ep_wakeirq is now %d\n", - msm_pcie_dev[0].ep_wakeirq); + "PCIe: RC0: boot_option is now 0x%x\n", + msm_pcie_dev[0].boot_option); break; } else if (rc_sel & (1 << i)) { - msm_pcie_dev[i].ep_wakeirq = new_ep_wakeirq; + msm_pcie_dev[i].boot_option = new_boot_option; PCIE_DBG_FS(&msm_pcie_dev[i], - "PCIe: RC%d: ep_wakeirq is now %d\n", - i, msm_pcie_dev[i].ep_wakeirq); + "PCIe: RC%d: boot_option is now 0x%x\n", + i, msm_pcie_dev[i].boot_option); } } } else { - pr_err("PCIe: Invalid input for ep_wakeirq: %d. Please enter 0 or 1.\n", - new_ep_wakeirq); + pr_err("PCIe: Invalid input for boot_option: 0x%x.\n", + new_boot_option); } return count; } -const struct file_operations msm_pcie_ep_wakeirq_ops = { - .write = msm_pcie_set_ep_wakeirq, +const struct file_operations msm_pcie_boot_option_ops = { + .write = msm_pcie_set_boot_option, }; static ssize_t msm_pcie_set_aer_enable(struct file *file, @@ -3025,12 +3031,12 @@ static void msm_pcie_debugfs_init(void) goto wr_value_error; } - dfile_ep_wakeirq = debugfs_create_file("ep_wakeirq", 0664, + dfile_boot_option = debugfs_create_file("boot_option", 0664, dent_msm_pcie, 0, - &msm_pcie_ep_wakeirq_ops); - if (!dfile_ep_wakeirq || IS_ERR(dfile_ep_wakeirq)) { - pr_err("PCIe: fail to create the file for debug_fs ep_wakeirq.\n"); - goto ep_wakeirq_error; + &msm_pcie_boot_option_ops); + if (!dfile_boot_option || IS_ERR(dfile_boot_option)) { + pr_err("PCIe: fail to create the file for debug_fs boot_option.\n"); + goto boot_option_error; } dfile_aer_enable = debugfs_create_file("aer_enable", 0664, @@ -3053,8 +3059,8 @@ static void msm_pcie_debugfs_init(void) corr_counter_limit_error: debugfs_remove(dfile_aer_enable); aer_enable_error: - debugfs_remove(dfile_ep_wakeirq); -ep_wakeirq_error: + debugfs_remove(dfile_boot_option); +boot_option_error: debugfs_remove(dfile_wr_value); wr_value_error: debugfs_remove(dfile_wr_mask); @@ -3081,7 +3087,7 @@ static void msm_pcie_debugfs_exit(void) debugfs_remove(dfile_wr_offset); debugfs_remove(dfile_wr_mask); debugfs_remove(dfile_wr_value); - debugfs_remove(dfile_ep_wakeirq); + debugfs_remove(dfile_boot_option); debugfs_remove(dfile_aer_enable); debugfs_remove(dfile_corr_counter_limit); } @@ -3312,7 +3318,7 @@ static inline int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper, word_offset = where & ~0x3; byte_offset = where & 0x3; - mask = (~0 >> (8 * (4 - size))) << (8 * byte_offset); + mask = ((u32)~0 >> (8 * (4 - size))) << (8 * byte_offset); if (rc || !dev->enumerated) { config_base = rc ? dev->dm_core : dev->conf; @@ -3347,12 +3353,17 @@ static inline int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper, writel_relaxed(wr_val, config_base + word_offset); wmb(); /* ensure config data is written to hardware register */ - if (rd_val == PCIE_LINK_DOWN) - PCIE_ERR(dev, - "Read of RC%d %d:0x%02x + 0x%04x[%d] is all FFs\n", - rc_idx, bus->number, devfn, where, size); - else if (dev->shadow_en) - msm_pcie_save_shadow(dev, word_offset, wr_val, bdf, rc); + if (dev->shadow_en) { + if (rd_val == PCIE_LINK_DOWN && + (readl_relaxed(config_base) == PCIE_LINK_DOWN)) + PCIE_ERR(dev, + "Read of RC%d %d:0x%02x + 0x%04x[%d] is all FFs\n", + rc_idx, bus->number, devfn, + where, size); + else + msm_pcie_save_shadow(dev, word_offset, wr_val, + bdf, rc); + } PCIE_DBG3(dev, "RC%d %d:0x%02x + 0x%04x[%d] <- 0x%08x; rd 0x%08x val 0x%08x\n", @@ -5410,14 +5421,10 @@ static irqreturn_t handle_wake_irq(int irq, void *data) PCIE_DBG2(dev, "PCIe WAKE is asserted by Endpoint of RC%d\n", dev->rc_idx); - if (!dev->enumerated) { - PCIE_DBG(dev, "Start enumeating RC%d\n", dev->rc_idx); - if (dev->ep_wakeirq) - schedule_work(&dev->handle_wake_work); - else - PCIE_DBG(dev, - "wake irq is received but ep_wakeirq is not supported for RC%d.\n", - dev->rc_idx); + if (!dev->enumerated && !(dev->boot_option & + MSM_PCIE_NO_WAKE_ENUMERATION)) { + PCIE_DBG(dev, "Start enumerating RC%d\n", dev->rc_idx); + schedule_work(&dev->handle_wake_work); } else { PCIE_DBG2(dev, "Wake up RC%d\n", dev->rc_idx); __pm_stay_awake(&dev->ws); @@ -5573,34 +5580,84 @@ static irqreturn_t handle_global_irq(int irq, void *data) return IRQ_HANDLED; } -void msm_pcie_destroy_irq(unsigned int irq, struct msm_pcie_dev_t *pcie_dev) +static void msm_pcie_unmap_qgic_addr(struct msm_pcie_dev_t *dev, + struct pci_dev *pdev) { - int pos, i; + struct iommu_domain *domain = iommu_get_domain_for_dev(&pdev->dev); + int bypass_en = 0; + + if (!domain) { + PCIE_DBG(dev, + "PCIe: RC%d: client does not have an iommu domain\n", + dev->rc_idx); + return; + } + + iommu_domain_get_attr(domain, DOMAIN_ATTR_S1_BYPASS, &bypass_en); + if (!bypass_en) { + int ret; + phys_addr_t pcie_base_addr = + dev->res[MSM_PCIE_RES_DM_CORE].resource->start; + dma_addr_t iova = rounddown(pcie_base_addr, PAGE_SIZE); + + ret = iommu_unmap(domain, iova, PAGE_SIZE); + if (ret != PAGE_SIZE) + PCIE_ERR(dev, + "PCIe: RC%d: failed to unmap QGIC address. ret = %d\n", + dev->rc_idx, ret); + } +} + +void msm_pcie_destroy_irq(unsigned int irq) +{ + int pos; + struct pci_dev *pdev = irq_get_chip_data(irq); + struct msi_desc *entry = irq_get_msi_desc(irq); + struct msi_desc *firstentry; struct msm_pcie_dev_t *dev; + u32 nvec; + int firstirq; - if (pcie_dev) - dev = pcie_dev; - else - dev = irq_get_chip_data(irq); + if (!pdev) { + pr_err("PCIe: pci device is null. IRQ:%d\n", irq); + return; + } + dev = PCIE_BUS_PRIV_DATA(pdev->bus); if (!dev) { - pr_err("PCIe: device is null. IRQ:%d\n", irq); + pr_err("PCIe: could not find RC. IRQ:%d\n", irq); + return; + } + + if (!entry) { + PCIE_ERR(dev, "PCIe: RC%d: msi desc is null. IRQ:%d\n", + dev->rc_idx, irq); + return; + } + + firstentry = first_pci_msi_entry(pdev); + if (!firstentry) { + PCIE_ERR(dev, + "PCIe: RC%d: firstentry msi desc is null. IRQ:%d\n", + dev->rc_idx, irq); return; } + firstirq = firstentry->irq; + nvec = (1 << entry->msi_attrib.multiple); + if (dev->msi_gicm_addr) { PCIE_DBG(dev, "destroy QGIC based irq %d\n", irq); - for (i = 0; i < MSM_PCIE_MAX_MSI; i++) - if (irq == dev->msi[i].num) - break; - if (i == MSM_PCIE_MAX_MSI) { + if (irq < firstirq || irq > firstirq + nvec - 1) { PCIE_ERR(dev, "Could not find irq: %d in RC%d MSI table\n", irq, dev->rc_idx); return; } else { - pos = i; + if (irq == firstirq + nvec - 1) + msm_pcie_unmap_qgic_addr(dev, pdev); + pos = irq - firstirq; } } else { PCIE_DBG(dev, "destroy default MSI irq %d\n", irq); @@ -5620,7 +5677,7 @@ void msm_pcie_destroy_irq(unsigned int irq, struct msm_pcie_dev_t *pcie_dev) void arch_teardown_msi_irq(unsigned int irq) { PCIE_GEN_DBG("irq %d deallocated\n", irq); - msm_pcie_destroy_irq(irq, NULL); + msm_pcie_destroy_irq(irq); } void arch_teardown_msi_irqs(struct pci_dev *dev) @@ -5639,7 +5696,7 @@ void arch_teardown_msi_irqs(struct pci_dev *dev) continue; nvec = 1 << entry->msi_attrib.multiple; for (i = 0; i < nvec; i++) - msm_pcie_destroy_irq(entry->irq + i, pcie_dev); + arch_teardown_msi_irq(entry->irq + i); } } @@ -5701,6 +5758,7 @@ static int arch_setup_msi_irq_default(struct pci_dev *pdev, PCIE_DBG(dev, "irq %d allocated\n", irq); + irq_set_chip_data(irq, pdev); irq_set_msi_desc(irq, desc); /* write msi vector and data */ @@ -5748,10 +5806,64 @@ again: return irq; } +static int msm_pcie_map_qgic_addr(struct msm_pcie_dev_t *dev, + struct pci_dev *pdev, + struct msi_msg *msg) +{ + struct iommu_domain *domain = iommu_get_domain_for_dev(&pdev->dev); + int ret, bypass_en = 0; + dma_addr_t iova; + phys_addr_t pcie_base_addr, gicm_db_offset; + + msg->address_hi = 0; + msg->address_lo = dev->msi_gicm_addr; + + if (!domain) { + PCIE_DBG(dev, + "PCIe: RC%d: client does not have an iommu domain\n", + dev->rc_idx); + return 0; + } + + iommu_domain_get_attr(domain, DOMAIN_ATTR_S1_BYPASS, &bypass_en); + + PCIE_DBG(dev, + "PCIe: RC%d: Stage 1 is %s for endpoint: %04x:%02x\n", + dev->rc_idx, bypass_en ? "bypass" : "enabled", + pdev->bus->number, pdev->devfn); + + if (bypass_en) + return 0; + + gicm_db_offset = dev->msi_gicm_addr - + rounddown(dev->msi_gicm_addr, PAGE_SIZE); + /* + * Use PCIe DBI address as the IOVA since client cannot + * use this address for their IOMMU mapping. This will + * prevent any conflicts between PCIe host and + * client's mapping. + */ + pcie_base_addr = dev->res[MSM_PCIE_RES_DM_CORE].resource->start; + iova = rounddown(pcie_base_addr, PAGE_SIZE); + + ret = iommu_map(domain, iova, rounddown(dev->msi_gicm_addr, PAGE_SIZE), + PAGE_SIZE, IOMMU_READ | IOMMU_WRITE); + if (ret < 0) { + PCIE_ERR(dev, + "PCIe: RC%d: ret: %d: Could not do iommu map for QGIC address\n", + dev->rc_idx, ret); + return -ENOMEM; + } + + msg->address_lo = iova + gicm_db_offset; + + return 0; +} + static int arch_setup_msi_irq_qgic(struct pci_dev *pdev, struct msi_desc *desc, int nvec) { - int irq, index, firstirq = 0; + int irq, index, ret, firstirq = 0; struct msi_msg msg; struct msm_pcie_dev_t *dev = PCIE_BUS_PRIV_DATA(pdev->bus); @@ -5768,12 +5880,16 @@ static int arch_setup_msi_irq_qgic(struct pci_dev *pdev, firstirq = irq; irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING); + irq_set_chip_data(irq, pdev); } /* write msi vector and data */ irq_set_msi_desc(firstirq, desc); - msg.address_hi = 0; - msg.address_lo = dev->msi_gicm_addr; + + ret = msm_pcie_map_qgic_addr(dev, pdev, &msg); + if (ret) + return ret; + msg.data = dev->msi_gicm_base + (firstirq - dev->msi[0].num); write_msi_msg(firstirq, &msg); @@ -5845,7 +5961,6 @@ static int msm_pcie_msi_map(struct irq_domain *domain, unsigned int irq, irq_hw_number_t hwirq) { irq_set_chip_and_handler (irq, &pcie_msi_chip, handle_simple_irq); - irq_set_chip_data(irq, domain->host_data); return 0; } @@ -6091,12 +6206,12 @@ static int msm_pcie_probe(struct platform_device *pdev) msm_pcie_dev[rc_idx].rc_idx, msm_pcie_dev[rc_idx].smmu_sid_base); - msm_pcie_dev[rc_idx].ep_wakeirq = - of_property_read_bool((&pdev->dev)->of_node, - "qcom,ep-wakeirq"); + msm_pcie_dev[rc_idx].boot_option = 0; + ret = of_property_read_u32((&pdev->dev)->of_node, "qcom,boot-option", + &msm_pcie_dev[rc_idx].boot_option); PCIE_DBG(&msm_pcie_dev[rc_idx], - "PCIe: EP of RC%d does %s assert wake when it is up.\n", - rc_idx, msm_pcie_dev[rc_idx].ep_wakeirq ? "" : "not"); + "PCIe: RC%d boot option is 0x%x.\n", + rc_idx, msm_pcie_dev[rc_idx].boot_option); msm_pcie_dev[rc_idx].phy_ver = 1; ret = of_property_read_u32((&pdev->dev)->of_node, @@ -6375,9 +6490,10 @@ static int msm_pcie_probe(struct platform_device *pdev) msm_pcie_dev[rc_idx].drv_ready = true; - if (msm_pcie_dev[rc_idx].ep_wakeirq) { + if (msm_pcie_dev[rc_idx].boot_option & + MSM_PCIE_NO_PROBE_ENUMERATION) { PCIE_DBG(&msm_pcie_dev[rc_idx], - "PCIe: RC%d will be enumerated upon WAKE signal from Endpoint.\n", + "PCIe: RC%d will be enumerated by client or endpoint.\n", rc_idx); mutex_unlock(&pcie_drv.drv_lock); return 0; diff --git a/drivers/pinctrl/qcom/pinctrl-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpi.c index 4ca5d5fa0531..3fe41ee4c3c1 100644 --- a/drivers/pinctrl/qcom/pinctrl-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-lpi.c @@ -408,13 +408,19 @@ static void lpi_gpio_set(struct gpio_chip *chip, unsigned pin, int value) static int lpi_notifier_service_cb(struct notifier_block *this, unsigned long opcode, void *ptr) { + static bool initial_boot = true; + pr_debug("%s: Service opcode 0x%lx\n", __func__, opcode); switch (opcode) { case AUDIO_NOTIFIER_SERVICE_DOWN: + if (initial_boot) + break; lpi_dev_up = false; break; case AUDIO_NOTIFIER_SERVICE_UP: + if (initial_boot) + initial_boot = false; lpi_dev_up = true; break; default: diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index c2902beaa0b8..08bffc344429 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -2824,10 +2824,8 @@ static int msm_gsi_probe(struct platform_device *pdev) gsi_ctx->ipc_logbuf = ipc_log_context_create(GSI_IPC_LOG_PAGES, "gsi", 0); - if (gsi_ctx->ipc_logbuf == NULL) { - GSIERR("failed to get ipc_logbuf\n"); - return -ENOMEM; - } + if (gsi_ctx->ipc_logbuf == NULL) + GSIERR("failed to create IPC log, continue...\n"); gsi_ctx->dev = dev; init_completion(&gsi_ctx->gen_ee_cmd_compl); diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c index 553480660722..100bbd582a5e 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c @@ -3848,11 +3848,8 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p, } ipa_ctx->logbuf = ipc_log_context_create(IPA_IPC_LOG_PAGES, "ipa", 0); - if (ipa_ctx->logbuf == NULL) { - IPAERR("failed to get logbuf\n"); - result = -ENOMEM; - goto fail_logbuf; - } + if (ipa_ctx->logbuf == NULL) + IPAERR("failed to create IPC log, continue...\n"); ipa_ctx->pdev = ipa_dev; ipa_ctx->uc_pdev = ipa_dev; @@ -4390,8 +4387,8 @@ fail_bus_reg: fail_bind: kfree(ipa_ctx->ctrl); fail_mem_ctrl: - ipc_log_context_destroy(ipa_ctx->logbuf); -fail_logbuf: + if (ipa_ctx->logbuf) + ipc_log_context_destroy(ipa_ctx->logbuf); kfree(ipa_ctx); ipa_ctx = NULL; fail_mem_ctx: diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index aa681d3eacaa..ddff50834f03 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -2253,7 +2253,8 @@ static int ipa3_q6_set_ex_path_to_apps(void) reg_write.pipeline_clear_options = IPAHAL_HPS_CLEAR; reg_write.offset = - ipahal_get_reg_ofst(IPA_ENDP_STATUS_n); + ipahal_get_reg_n_ofst(IPA_ENDP_STATUS_n, + ep_idx); ipahal_get_status_ep_valmask( ipa3_get_ep_mapping(IPA_CLIENT_APPS_LAN_CONS), &valmask); @@ -4263,11 +4264,8 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, } ipa3_ctx->logbuf = ipc_log_context_create(IPA_IPC_LOG_PAGES, "ipa", 0); - if (ipa3_ctx->logbuf == NULL) { - IPAERR("failed to get logbuf\n"); - result = -ENOMEM; - goto fail_logbuf; - } + if (ipa3_ctx->logbuf == NULL) + IPAERR("failed to create IPC log, continue...\n"); ipa3_ctx->pdev = ipa_dev; ipa3_ctx->uc_pdev = ipa_dev; @@ -4768,8 +4766,8 @@ fail_bind: fail_mem_ctrl: kfree(ipa3_ctx->ipa_tz_unlock_reg); fail_tz_unlock_reg: - ipc_log_context_destroy(ipa3_ctx->logbuf); -fail_logbuf: + if (ipa3_ctx->logbuf) + ipc_log_context_destroy(ipa3_ctx->logbuf); kfree(ipa3_ctx); ipa3_ctx = NULL; fail_mem_ctx: diff --git a/drivers/platform/msm/mhi/mhi.h b/drivers/platform/msm/mhi/mhi.h index 4bce96102525..60e02fcb5e4b 100644 --- a/drivers/platform/msm/mhi/mhi.h +++ b/drivers/platform/msm/mhi/mhi.h @@ -95,9 +95,12 @@ struct bhi_ctxt_t { u32 poll_timeout; /* BHI/E vector table */ bool manage_boot; /* fw download done by MHI host */ + bool support_rddm; struct work_struct fw_load_work; struct firmware_info firmware_info; struct bhie_vec_table fw_table; + struct bhie_vec_table rddm_table; + size_t rddm_size; }; enum MHI_CHAN_DIR { @@ -140,12 +143,6 @@ enum MHI_CHAIN { MHI_TRE_CHAIN_reserved = 0x80000000 }; -enum MHI_EVENT_RING_STATE { - MHI_EVENT_RING_UINIT = 0x0, - MHI_EVENT_RING_INIT = 0x1, - MHI_EVENT_RING_reserved = 0x80000000 -}; - enum MHI_STATE { MHI_STATE_RESET = 0x0, MHI_STATE_READY = 0x1, @@ -154,9 +151,8 @@ enum MHI_STATE { MHI_STATE_M2 = 0x4, MHI_STATE_M3 = 0x5, MHI_STATE_BHI = 0x7, - MHI_STATE_SYS_ERR = 0x8, - MHI_STATE_LIMIT = 0x9, - MHI_STATE_reserved = 0x80000000 + MHI_STATE_SYS_ERR = 0xFF, + MHI_STATE_LIMIT, }; enum MHI_BRSTMODE { @@ -168,22 +164,36 @@ enum MHI_BRSTMODE { }; enum MHI_PM_STATE { - MHI_PM_DISABLE = 0x0, /* MHI is not enabled */ - MHI_PM_POR = 0x1, /* Power On Reset State */ - MHI_PM_M0 = 0x2, - MHI_PM_M1 = 0x4, - MHI_PM_M1_M2_TRANSITION = 0x8, /* Register access not allowed */ - MHI_PM_M2 = 0x10, - MHI_PM_M3_ENTER = 0x20, - MHI_PM_M3 = 0x40, - MHI_PM_M3_EXIT = 0x80, + MHI_PM_DISABLE = BIT(0), /* MHI is not enabled */ + MHI_PM_POR = BIT(1), /* Power On Reset State */ + MHI_PM_M0 = BIT(2), + MHI_PM_M1 = BIT(3), + MHI_PM_M1_M2_TRANSITION = BIT(4), /* Register access not allowed */ + MHI_PM_M2 = BIT(5), + MHI_PM_M3_ENTER = BIT(6), + MHI_PM_M3 = BIT(7), + MHI_PM_M3_EXIT = BIT(8), + MHI_PM_SYS_ERR_DETECT = BIT(9), + MHI_PM_SYS_ERR_PROCESS = BIT(10), + MHI_PM_SHUTDOWN_PROCESS = BIT(11), + MHI_PM_LD_ERR_FATAL_DETECT = BIT(12), /* Link not accessible */ + MHI_PM_SSR_PENDING = BIT(13) +}; + +struct mhi_pm_transitions { + enum MHI_PM_STATE from_state; + u32 to_states; }; #define MHI_DB_ACCESS_VALID(pm_state) (pm_state & (MHI_PM_M0 | MHI_PM_M1)) #define MHI_WAKE_DB_ACCESS_VALID(pm_state) (pm_state & (MHI_PM_M0 | \ MHI_PM_M1 | MHI_PM_M2)) -#define MHI_REG_ACCESS_VALID(pm_state) ((pm_state > MHI_PM_DISABLE) && \ - (pm_state < MHI_PM_M3_EXIT)) +#define MHI_REG_ACCESS_VALID(pm_state) ((pm_state & (MHI_PM_POR | MHI_PM_M0 | \ + MHI_PM_M1 | MHI_PM_M2 | MHI_PM_M3_ENTER | MHI_PM_M3_EXIT | \ + MHI_PM_SYS_ERR_DETECT | MHI_PM_SYS_ERR_PROCESS | \ + MHI_PM_SHUTDOWN_PROCESS))) +#define MHI_EVENT_ACCESS_INVALID(pm_state) (pm_state == MHI_PM_DISABLE || \ + pm_state >= MHI_PM_SYS_ERR_DETECT) struct __packed mhi_event_ctxt { u32 mhi_intmodt; u32 mhi_event_er_type; @@ -239,7 +249,6 @@ enum MHI_PKT_TYPE { MHI_PKT_TYPE_TX_EVENT = 0x22, MHI_PKT_TYPE_EE_EVENT = 0x40, MHI_PKT_TYPE_STALE_EVENT, /* Internal event */ - MHI_PKT_TYPE_SYS_ERR_EVENT = 0xFF, }; struct __packed mhi_tx_pkt { @@ -393,7 +402,8 @@ enum STATE_TRANSITION { STATE_TRANSITION_LINK_DOWN, STATE_TRANSITION_WAKE, STATE_TRANSITION_BHIE, - STATE_TRANSITION_SYS_ERR, + STATE_TRANSITION_RDDM, + STATE_TRANSITION_SYS_ERR = MHI_STATE_SYS_ERR, STATE_TRANSITION_MAX }; @@ -402,7 +412,8 @@ enum MHI_EXEC_ENV { MHI_EXEC_ENV_SBL = 0x1, MHI_EXEC_ENV_AMSS = 0x2, MHI_EXEC_ENV_BHIE = 0x3, - MHI_EXEC_ENV_reserved = 0x80000000 + MHI_EXEC_ENV_RDDM = 0x4, + MHI_EXEC_ENV_DISABLE_TRANSITION, /* local EE, not related to mhi spec */ }; struct mhi_chan_info { @@ -480,7 +491,7 @@ struct mhi_counters { }; struct mhi_flags { - u32 mhi_initialized; + bool mhi_initialized; u32 link_up; bool bb_required; }; @@ -546,6 +557,7 @@ struct mhi_device_ctxt { struct mhi_event_ring_cfg *ev_ring_props; struct work_struct st_thread_worker; struct work_struct process_m1_worker; + struct work_struct process_sys_err_worker; struct mhi_wait_queues mhi_ev_wq; struct dev_mmio_info mmio_info; @@ -587,7 +599,8 @@ struct mhi_device_ctxt { void (*assert_wake)(struct mhi_device_ctxt *mhi_dev_ctxt, bool force_set); void (*deassert_wake)(struct mhi_device_ctxt *mhi_dev_ctxt); - + void (*status_cb)(enum MHI_CB_REASON, void *priv); + void *priv_data; /* private data for bus master */ struct completion cmd_complete; }; @@ -612,7 +625,6 @@ struct mhi_event_ring_cfg { */ u32 priority; enum MHI_RING_CLASS class; - enum MHI_EVENT_RING_STATE state; irqreturn_t (*mhi_handler_ptr)(int , void *); }; #define MHI_EV_PRIORITY_TASKLET (1) @@ -673,13 +685,12 @@ enum MHI_EVENT_CCS get_cmd_pkt(struct mhi_device_ctxt *mhi_dev_ctxt, union mhi_cmd_pkt **cmd_pkt, u32 event_index); int parse_cmd_event(struct mhi_device_ctxt *ctxt, union mhi_event_pkt *event, u32 event_index); -int mhi_test_for_device_ready( - struct mhi_device_ctxt *mhi_dev_ctxt); -int mhi_test_for_device_reset( - struct mhi_device_ctxt *mhi_dev_ctxt); +int mhi_test_for_device_ready(struct mhi_device_ctxt *mhi_dev_ctxt); +int mhi_test_for_device_reset(struct mhi_device_ctxt *mhi_dev_ctxt); int validate_ring_el_addr(struct mhi_ring *ring, uintptr_t addr); int validate_ev_el_addr(struct mhi_ring *ring, uintptr_t addr); void mhi_state_change_worker(struct work_struct *work); +void mhi_sys_err_worker(struct work_struct *work); int mhi_init_state_transition(struct mhi_device_ctxt *mhi_dev_ctxt, enum STATE_TRANSITION new_state); int mhi_wait_for_mdm(struct mhi_device_ctxt *mhi_dev_ctxt); @@ -709,7 +720,7 @@ int mhi_reg_notifiers(struct mhi_device_ctxt *mhi_dev_ctxt); int mhi_cpu_notifier_cb(struct notifier_block *nfb, unsigned long action, void *hcpu); int init_mhi_base_state(struct mhi_device_ctxt *mhi_dev_ctxt); -int mhi_turn_off_pcie_link(struct mhi_device_ctxt *mhi_dev_ctxt); +int mhi_turn_off_pcie_link(struct mhi_device_ctxt *mhi_dev_ctxt, bool graceful); int mhi_turn_on_pcie_link(struct mhi_device_ctxt *mhi_dev_ctxt); int mhi_initiate_m0(struct mhi_device_ctxt *mhi_dev_ctxt); int mhi_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt); @@ -757,5 +768,13 @@ void mhi_ev_task(unsigned long data); void process_event_ring(struct work_struct *work); int process_m0_transition(struct mhi_device_ctxt *mhi_dev_ctxt); int process_m3_transition(struct mhi_device_ctxt *mhi_dev_ctxt); +enum MHI_PM_STATE __must_check mhi_tryset_pm_state(struct mhi_device_ctxt *, + enum MHI_PM_STATE); +void mhi_reset_chan(struct mhi_device_ctxt *mhi_dev_ctxt, int chan); +void free_tre_ring(struct mhi_device_ctxt *mhi_dev_ctxt, int chan); +void process_disable_transition(enum MHI_PM_STATE transition_state, + struct mhi_device_ctxt *mhi_dev_ctxt); +bool mhi_in_sys_err(struct mhi_device_ctxt *mhi_dev_ctxt); +void bhi_exit(struct mhi_device_ctxt *mhi_dev_ctxt); #endif diff --git a/drivers/platform/msm/mhi/mhi_bhi.c b/drivers/platform/msm/mhi/mhi_bhi.c index 0cc8967757ec..3bc8205b5f0f 100644 --- a/drivers/platform/msm/mhi/mhi_bhi.c +++ b/drivers/platform/msm/mhi/mhi_bhi.c @@ -137,17 +137,36 @@ static int bhi_alloc_pbl_xfer(struct mhi_device_ctxt *mhi_dev_ctxt, return 0; } -/* Load firmware via bhie protocol */ -static int bhi_load_bhie_firmware(struct mhi_device_ctxt *mhi_dev_ctxt) +/* transfer firmware or ramdump via bhie protocol */ +static int bhi_bhie_transfer(struct mhi_device_ctxt *mhi_dev_ctxt, + struct bhie_vec_table *vec_table, + bool tx_vec_table) { struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt; - struct bhie_vec_table *fw_table = &bhi_ctxt->fw_table; + /* last element is the vector table */ const struct bhie_mem_info *bhie_mem_info = - &fw_table->bhie_mem_info[fw_table->segment_count - 1]; + &vec_table->bhie_mem_info[vec_table->segment_count - 1]; u32 val; - const u32 tx_sequence = fw_table->sequence++; + const u32 tx_sequence = vec_table->sequence++; unsigned long timeout; rwlock_t *pm_xfer_lock = &mhi_dev_ctxt->pm_xfer_lock; + unsigned bhie_vecaddr_high_offs, bhie_vecaddr_low_offs, + bhie_vecsize_offs, bhie_vecdb_offs, + bhie_vecstatus_offs; + + if (tx_vec_table) { + bhie_vecaddr_high_offs = BHIE_TXVECADDR_HIGH_OFFS; + bhie_vecaddr_low_offs = BHIE_TXVECADDR_LOW_OFFS; + bhie_vecsize_offs = BHIE_TXVECSIZE_OFFS; + bhie_vecdb_offs = BHIE_TXVECDB_OFFS; + bhie_vecstatus_offs = BHIE_TXVECSTATUS_OFFS; + } else { + bhie_vecaddr_high_offs = BHIE_RXVECADDR_HIGH_OFFS; + bhie_vecaddr_low_offs = BHIE_RXVECADDR_LOW_OFFS; + bhie_vecsize_offs = BHIE_RXVECSIZE_OFFS; + bhie_vecdb_offs = BHIE_RXVECDB_OFFS; + bhie_vecstatus_offs = BHIE_RXVECSTATUS_OFFS; + } /* Program TX/RX Vector table */ read_lock_bh(pm_xfer_lock); @@ -157,27 +176,17 @@ static int bhi_load_bhie_firmware(struct mhi_device_ctxt *mhi_dev_ctxt) } val = HIGH_WORD(bhie_mem_info->phys_addr); - mhi_reg_write(mhi_dev_ctxt, - bhi_ctxt->bhi_base, - BHIE_TXVECADDR_HIGH_OFFS, - val); + mhi_reg_write(mhi_dev_ctxt, bhi_ctxt->bhi_base, + bhie_vecaddr_high_offs, val); val = LOW_WORD(bhie_mem_info->phys_addr); - mhi_reg_write(mhi_dev_ctxt, - bhi_ctxt->bhi_base, - BHIE_TXVECADDR_LOW_OFFS, - val); + mhi_reg_write(mhi_dev_ctxt, bhi_ctxt->bhi_base, + bhie_vecaddr_low_offs, val); val = (u32)bhie_mem_info->size; - mhi_reg_write(mhi_dev_ctxt, - bhi_ctxt->bhi_base, - BHIE_TXVECSIZE_OFFS, - val); + mhi_reg_write(mhi_dev_ctxt, bhi_ctxt->bhi_base, bhie_vecsize_offs, val); /* Ring DB to begin Xfer */ - mhi_reg_write_field(mhi_dev_ctxt, - bhi_ctxt->bhi_base, - BHIE_TXVECDB_OFFS, - BHIE_TXVECDB_SEQNUM_BMSK, - BHIE_TXVECDB_SEQNUM_SHFT, + mhi_reg_write_field(mhi_dev_ctxt, bhi_ctxt->bhi_base, bhie_vecdb_offs, + BHIE_TXVECDB_SEQNUM_BMSK, BHIE_TXVECDB_SEQNUM_SHFT, tx_sequence); read_unlock_bh(pm_xfer_lock); @@ -190,10 +199,10 @@ static int bhi_load_bhie_firmware(struct mhi_device_ctxt *mhi_dev_ctxt) read_unlock_bh(pm_xfer_lock); return -EIO; } - val = mhi_reg_read(bhi_ctxt->bhi_base, BHIE_TXVECSTATUS_OFFS); + val = mhi_reg_read(bhi_ctxt->bhi_base, bhie_vecstatus_offs); read_unlock_bh(pm_xfer_lock); mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, - "TXVEC_STATUS:0x%x\n", val); + "%sVEC_STATUS:0x%x\n", tx_vec_table ? "TX" : "RX", val); current_seq = (val & BHIE_TXVECSTATUS_SEQNUM_BMSK) >> BHIE_TXVECSTATUS_SEQNUM_SHFT; status = (val & BHIE_TXVECSTATUS_STATUS_BMSK) >> @@ -201,17 +210,60 @@ static int bhi_load_bhie_firmware(struct mhi_device_ctxt *mhi_dev_ctxt) if ((status == BHIE_TXVECSTATUS_STATUS_XFER_COMPL) && (current_seq == tx_sequence)) { mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, - "Image transfer complete\n"); + "%s transfer complete\n", + tx_vec_table ? "image" : "rddm"); return 0; } msleep(BHI_POLL_SLEEP_TIME_MS); } mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, - "Error xfering image via BHIE\n"); + "Error xfer %s via BHIE\n", tx_vec_table ? "image" : "rddm"); return -EIO; } +static int bhi_rddm_graceful(struct mhi_device_ctxt *mhi_dev_ctxt) +{ + int ret; + struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt; + struct bhie_vec_table *rddm_table = &bhi_ctxt->rddm_table; + enum MHI_EXEC_ENV exec_env = mhi_dev_ctxt->dev_exec_env; + + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Entered with pm_state:0x%x exec_env:0x%x mhi_state:%s\n", + mhi_dev_ctxt->mhi_pm_state, exec_env, + TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); + + if (exec_env != MHI_EXEC_ENV_RDDM) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Not in RDDM exec env, exec_env:0x%x\n", exec_env); + return -EIO; + } + + ret = bhi_bhie_transfer(mhi_dev_ctxt, rddm_table, false); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "rddm transfer status:%d\n", ret); + return ret; +} + +/* collect ramdump from device using bhie protocol */ +int bhi_rddm(struct mhi_device_ctxt *mhi_dev_ctxt, bool in_panic) +{ + struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt; + struct bhie_vec_table *rddm_table = &bhi_ctxt->rddm_table; + + if (!rddm_table->bhie_mem_info) { + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "RDDM table == NULL\n"); + return -ENOMEM; + } + + if (!in_panic) + return bhi_rddm_graceful(mhi_dev_ctxt); + + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "RDDM collection in panic not yet supported\n"); + return -EINVAL; +} + static int bhi_load_firmware(struct mhi_device_ctxt *mhi_dev_ctxt) { struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt; @@ -425,7 +477,8 @@ void bhi_firmware_download(struct work_struct *work) return; } - ret = bhi_load_bhie_firmware(mhi_dev_ctxt); + ret = bhi_bhie_transfer(mhi_dev_ctxt, &mhi_dev_ctxt->bhi_ctxt.fw_table, + true); if (ret) { mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to Load amss firmware\n"); @@ -437,6 +490,7 @@ int bhi_probe(struct mhi_device_ctxt *mhi_dev_ctxt) struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt; struct firmware_info *fw_info = &bhi_ctxt->firmware_info; struct bhie_vec_table *fw_table = &bhi_ctxt->fw_table; + struct bhie_vec_table *rddm_table = &bhi_ctxt->rddm_table; const struct firmware *firmware; struct scatterlist *itr; int ret, i; @@ -503,7 +557,75 @@ int bhi_probe(struct mhi_device_ctxt *mhi_dev_ctxt) fw_table->sequence++; release_firmware(firmware); + /* allocate memory and setup rddm table */ + if (bhi_ctxt->support_rddm) { + ret = bhi_alloc_bhie_xfer(mhi_dev_ctxt, bhi_ctxt->rddm_size, + rddm_table); + if (!ret) { + for (i = 0, itr = &rddm_table->sg_list[1]; + i < rddm_table->segment_count - 1; i++, itr++) { + size_t size = rddm_table->bhie_mem_info[i].size; + + rddm_table->bhi_vec_entry[i].phys_addr = + rddm_table->bhie_mem_info[i].phys_addr; + rddm_table->bhi_vec_entry[i].size = size; + sg_set_buf(itr, rddm_table-> + bhie_mem_info[i].aligned, size); + sg_dma_address(itr) = + rddm_table->bhie_mem_info[i].phys_addr; + sg_dma_len(itr) = size; + } + rddm_table->sequence++; + } else { + /* out of memory for rddm, not fatal error */ + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Could not successfully allocate mem for rddm\n"); + } + } + /* Schedule a worker thread and wait for BHI Event */ schedule_work(&bhi_ctxt->fw_load_work); return 0; } + +void bhi_exit(struct mhi_device_ctxt *mhi_dev_ctxt) +{ + struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt; + struct bhie_vec_table *fw_table = &bhi_ctxt->fw_table; + struct bhie_vec_table *rddm_table = &bhi_ctxt->rddm_table; + struct device *dev = &mhi_dev_ctxt->plat_dev->dev; + struct bhie_mem_info *bhie_mem_info; + int i; + + if (bhi_ctxt->manage_boot == false) + return; + + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "freeing firmware and rddm memory\n"); + + /* free memory allocated for firmware */ + kfree(fw_table->sg_list); + fw_table->sg_list = NULL; + bhie_mem_info = fw_table->bhie_mem_info; + for (i = 0; i < fw_table->segment_count; i++, bhie_mem_info++) + dma_free_coherent(dev, bhie_mem_info->alloc_size, + bhie_mem_info->pre_aligned, + bhie_mem_info->dma_handle); + fw_table->bhie_mem_info = NULL; + /* vector table is the last entry in bhie_mem_info */ + fw_table->bhi_vec_entry = NULL; + + if (!rddm_table->bhie_mem_info) + return; + + /* free memory allocated for rddm */ + kfree(rddm_table->sg_list); + rddm_table->sg_list = NULL; + bhie_mem_info = rddm_table->bhie_mem_info; + for (i = 0; i < rddm_table->segment_count; i++, bhie_mem_info++) + dma_free_coherent(dev, bhie_mem_info->alloc_size, + bhie_mem_info->pre_aligned, + bhie_mem_info->dma_handle); + rddm_table->bhie_mem_info = NULL; + rddm_table->bhi_vec_entry = NULL; +} diff --git a/drivers/platform/msm/mhi/mhi_bhi.h b/drivers/platform/msm/mhi/mhi_bhi.h index 15137ba5dfdf..8f7b3d69347c 100644 --- a/drivers/platform/msm/mhi/mhi_bhi.h +++ b/drivers/platform/msm/mhi/mhi_bhi.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, 2016 The Linux Foundation. All rights reserved. +/* Copyright (c) 2014, 2016-2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -90,5 +90,6 @@ int bhi_probe(struct mhi_device_ctxt *mhi_dev_ctxt); void bhi_firmware_download(struct work_struct *work); +int bhi_rddm(struct mhi_device_ctxt *mhi_dev_ctxt, bool in_panic); #endif diff --git a/drivers/platform/msm/mhi/mhi_event.c b/drivers/platform/msm/mhi/mhi_event.c index ae677bae63dc..ea324339eac7 100644 --- a/drivers/platform/msm/mhi/mhi_event.c +++ b/drivers/platform/msm/mhi/mhi_event.c @@ -226,8 +226,7 @@ int init_local_ev_ring_by_type(struct mhi_device_ctxt *mhi_dev_ctxt, mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Entered\n"); for (i = 0; i < mhi_dev_ctxt->mmio_info.nr_event_rings; i++) { if (GET_EV_PROPS(EV_TYPE, - mhi_dev_ctxt->ev_ring_props[i].flags) == type && - !mhi_dev_ctxt->ev_ring_props[i].state) { + mhi_dev_ctxt->ev_ring_props[i].flags) == type) { ret_val = mhi_init_local_event_ring(mhi_dev_ctxt, mhi_dev_ctxt->ev_ring_props[i].nr_desc, i); @@ -292,7 +291,6 @@ int mhi_init_local_event_ring(struct mhi_device_ctxt *mhi_dev_ctxt, break; } } - mhi_dev_ctxt->ev_ring_props[ring_index].state = MHI_EVENT_RING_INIT; spin_unlock_irqrestore(lock, flags); return ret_val; } @@ -309,6 +307,7 @@ void mhi_reset_ev_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt, &mhi_dev_ctxt->dev_space.ring_ctxt.ec_list[index]; local_ev_ctxt = &mhi_dev_ctxt->mhi_local_event_ctxt[index]; + spin_lock_irq(&local_ev_ctxt->ring_lock); ev_ctxt->mhi_event_read_ptr = ev_ctxt->mhi_event_ring_base_addr; ev_ctxt->mhi_event_write_ptr = ev_ctxt->mhi_event_ring_base_addr; local_ev_ctxt->rp = local_ev_ctxt->base; @@ -317,6 +316,5 @@ void mhi_reset_ev_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt, ev_ctxt = &mhi_dev_ctxt->dev_space.ring_ctxt.ec_list[index]; ev_ctxt->mhi_event_read_ptr = ev_ctxt->mhi_event_ring_base_addr; ev_ctxt->mhi_event_write_ptr = ev_ctxt->mhi_event_ring_base_addr; - /* Flush writes to MMIO */ - wmb(); + spin_unlock_irq(&local_ev_ctxt->ring_lock); } diff --git a/drivers/platform/msm/mhi/mhi_iface.c b/drivers/platform/msm/mhi/mhi_iface.c index f1c562974816..64a09a2f9fbb 100644 --- a/drivers/platform/msm/mhi/mhi_iface.c +++ b/drivers/platform/msm/mhi/mhi_iface.c @@ -189,6 +189,7 @@ static int mhi_pci_probe(struct pci_dev *pcie_device, mhi_dev_ctxt->mhi_pm_state = MHI_PM_DISABLE; INIT_WORK(&mhi_dev_ctxt->process_m1_worker, process_m1_transition); INIT_WORK(&mhi_dev_ctxt->st_thread_worker, mhi_state_change_worker); + INIT_WORK(&mhi_dev_ctxt->process_sys_err_worker, mhi_sys_err_worker); mutex_init(&mhi_dev_ctxt->pm_lock); rwlock_init(&mhi_dev_ctxt->pm_xfer_lock); spin_lock_init(&mhi_dev_ctxt->dev_wake_lock); diff --git a/drivers/platform/msm/mhi/mhi_isr.c b/drivers/platform/msm/mhi/mhi_isr.c index 9aa9aeb7e646..70e4393f2f59 100644 --- a/drivers/platform/msm/mhi/mhi_isr.c +++ b/drivers/platform/msm/mhi/mhi_isr.c @@ -23,16 +23,18 @@ static int mhi_process_event_ring( union mhi_event_pkt *local_rp = NULL; union mhi_event_pkt *device_rp = NULL; union mhi_event_pkt event_to_process; - int ret_val = 0; + int count = 0; struct mhi_event_ctxt *ev_ctxt = NULL; unsigned long flags; struct mhi_ring *local_ev_ctxt = &mhi_dev_ctxt->mhi_local_event_ctxt[ev_index]; - mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "enter ev_index:%u\n", ev_index); + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Enter ev_index:%u\n", ev_index); read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock); - if (unlikely(mhi_dev_ctxt->mhi_pm_state == MHI_PM_DISABLE)) { - mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Invalid MHI PM State\n"); + if (unlikely(MHI_EVENT_ACCESS_INVALID(mhi_dev_ctxt->mhi_pm_state))) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "No event access, PM_STATE:0x%x\n", + mhi_dev_ctxt->mhi_pm_state); read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); return -EIO; } @@ -98,6 +100,7 @@ static int mhi_process_event_ring( { u32 chan; struct mhi_ring *ring; + unsigned long flags; __pm_stay_awake(&mhi_dev_ctxt->w_lock); chan = MHI_EV_READ_CHID(EV_CHID, &event_to_process); @@ -107,12 +110,12 @@ static int mhi_process_event_ring( break; } ring = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan]; - spin_lock_bh(&ring->ring_lock); + spin_lock_irqsave(&ring->ring_lock, flags); if (ring->ch_state == MHI_CHAN_STATE_ENABLED) parse_xfer_event(mhi_dev_ctxt, &event_to_process, ev_index); - spin_unlock_bh(&ring->ring_lock); + spin_unlock_irqrestore(&ring->ring_lock, flags); __pm_relax(&mhi_dev_ctxt->w_lock); event_quota--; break; @@ -136,18 +139,41 @@ static int mhi_process_event_ring( mhi_dev_ctxt->mhi_state = mhi_get_m_state(mhi_dev_ctxt); if (mhi_dev_ctxt->mhi_state == MHI_STATE_M1) { - mhi_dev_ctxt->mhi_pm_state = MHI_PM_M1; - mhi_dev_ctxt->counters.m0_m1++; - schedule_work(&mhi_dev_ctxt-> - process_m1_worker); + enum MHI_PM_STATE state; + + state = mhi_tryset_pm_state + (mhi_dev_ctxt, MHI_PM_M1); + if (state == MHI_PM_M1) { + mhi_dev_ctxt->counters.m0_m1++; + schedule_work + (&mhi_dev_ctxt-> + process_m1_worker); + } } write_unlock_irqrestore(&mhi_dev_ctxt-> - pm_xfer_lock, - flags); + pm_xfer_lock, flags); break; case STATE_TRANSITION_M3: process_m3_transition(mhi_dev_ctxt); break; + case STATE_TRANSITION_SYS_ERR: + { + enum MHI_PM_STATE new_state; + unsigned long flags; + + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "MHI System Error Detected\n"); + write_lock_irqsave(&mhi_dev_ctxt->pm_xfer_lock, + flags); + new_state = mhi_tryset_pm_state + (mhi_dev_ctxt, MHI_PM_SYS_ERR_DETECT); + write_unlock_irqrestore + (&mhi_dev_ctxt->pm_xfer_lock, flags); + if (new_state == MHI_PM_SYS_ERR_DETECT) + schedule_work(&mhi_dev_ctxt-> + process_sys_err_worker); + break; + } default: mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Unsupported STE received ring 0x%x State:%s\n", @@ -158,28 +184,36 @@ static int mhi_process_event_ring( } case MHI_PKT_TYPE_EE_EVENT: { - enum STATE_TRANSITION new_state; + enum STATE_TRANSITION new_state = 0; + enum MHI_EXEC_ENV event = + MHI_READ_EXEC_ENV(&event_to_process); mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, - "MHI EEE received ring 0x%x\n", ev_index); + "MHI EE received ring 0x%x event:0x%x\n", + ev_index, event); __pm_stay_awake(&mhi_dev_ctxt->w_lock); __pm_relax(&mhi_dev_ctxt->w_lock); - switch (MHI_READ_EXEC_ENV(&event_to_process)) { + switch (event) { case MHI_EXEC_ENV_SBL: new_state = STATE_TRANSITION_SBL; - mhi_init_state_transition(mhi_dev_ctxt, - new_state); break; case MHI_EXEC_ENV_AMSS: new_state = STATE_TRANSITION_AMSS; - mhi_init_state_transition(mhi_dev_ctxt, - new_state); break; case MHI_EXEC_ENV_BHIE: new_state = STATE_TRANSITION_BHIE; + break; + case MHI_EXEC_ENV_RDDM: + new_state = STATE_TRANSITION_RDDM; + break; + default: + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Invalid EE Event 0x%x received\n", + event); + } + if (new_state) mhi_init_state_transition(mhi_dev_ctxt, new_state); - } break; } case MHI_PKT_TYPE_STALE_EVENT: @@ -187,11 +221,6 @@ static int mhi_process_event_ring( "Stale Event received for chan:%u\n", MHI_EV_READ_CHID(EV_CHID, local_rp)); break; - case MHI_PKT_TYPE_SYS_ERR_EVENT: - mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, - "MHI System Error Detected. Triggering Reset\n"); - BUG(); - break; default: mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Unsupported packet type code 0x%x\n", @@ -207,13 +236,13 @@ static int mhi_process_event_ring( ev_index, ev_ctxt->mhi_event_read_ptr); spin_unlock_irqrestore(&local_ev_ctxt->ring_lock, flags); - ret_val = 0; + count++; } read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock); mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt); read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "exit ev_index:%u\n", ev_index); - return ret_val; + return count; } void mhi_ev_task(unsigned long data) @@ -222,10 +251,40 @@ void mhi_ev_task(unsigned long data) struct mhi_device_ctxt *mhi_dev_ctxt = mhi_ring->mhi_dev_ctxt; int ev_index = mhi_ring->index; + const int CTRL_EV = 0; /* event ring for ctrl events */ + int ret; mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Enter\n"); + /* Process event ring */ - mhi_process_event_ring(mhi_dev_ctxt, ev_index, U32_MAX); + ret = mhi_process_event_ring(mhi_dev_ctxt, ev_index, U32_MAX); + /* + * If we received MSI for primary event ring with no events to process + * check status register to see if device enter SYSERR status + */ + if (ev_index == CTRL_EV && !ret) { + bool in_sys_err = false; + unsigned long flags; + enum MHI_PM_STATE new_state; + + read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock); + if (MHI_REG_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state)) + in_sys_err = mhi_in_sys_err(mhi_dev_ctxt); + read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); + + if (in_sys_err) { + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "MHI System Error Detected\n"); + write_lock_irqsave(&mhi_dev_ctxt->pm_xfer_lock, flags); + new_state = mhi_tryset_pm_state(mhi_dev_ctxt, + MHI_PM_SYS_ERR_DETECT); + write_unlock_irqrestore(&mhi_dev_ctxt->pm_xfer_lock, + flags); + if (new_state == MHI_PM_SYS_ERR_DETECT) + schedule_work(&mhi_dev_ctxt-> + process_sys_err_worker); + } + } enable_irq(MSI_TO_IRQ(mhi_dev_ctxt, ev_index)); mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Exit\n"); @@ -258,7 +317,7 @@ struct mhi_result *mhi_poll(struct mhi_client_handle *client_handle) ret_val = mhi_process_event_ring(client_config->mhi_dev_ctxt, client_config->event_ring_index, 1); - if (ret_val) + if (ret_val < 0) mhi_log(client_config->mhi_dev_ctxt, MHI_MSG_INFO, "NAPI failed to process event ring\n"); return &(client_config->result); diff --git a/drivers/platform/msm/mhi/mhi_main.c b/drivers/platform/msm/mhi/mhi_main.c index 644004672cd2..46baf7332900 100644 --- a/drivers/platform/msm/mhi/mhi_main.c +++ b/drivers/platform/msm/mhi/mhi_main.c @@ -30,11 +30,6 @@ #include "mhi_bhi.h" #include "mhi_trace.h" -static int reset_chan_cmd(struct mhi_device_ctxt *mhi_dev_ctxt, - union mhi_cmd_pkt *cmd_pkt); -static void disable_bb_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt, - struct mhi_ring *bb_ctxt); - static int enable_bb_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt, struct mhi_ring *bb_ctxt, int nr_el, @@ -306,6 +301,47 @@ static int populate_tre_ring(struct mhi_client_config *client_config) return 0; } +void mhi_notify_client(struct mhi_client_handle *client_handle, + enum MHI_CB_REASON reason) +{ + struct mhi_cb_info cb_info = {0}; + struct mhi_result result = {0}; + struct mhi_client_config *client_config; + + cb_info.result = NULL; + cb_info.cb_reason = reason; + + if (client_handle == NULL) + return; + + client_config = client_handle->client_config; + + if (client_config->client_info.mhi_client_cb) { + result.user_data = client_config->user_data; + cb_info.chan = client_config->chan_info.chan_nr; + cb_info.result = &result; + mhi_log(client_config->mhi_dev_ctxt, MHI_MSG_INFO, + "Calling back for chan %d, reason %d\n", + cb_info.chan, + reason); + client_config->client_info.mhi_client_cb(&cb_info); + } +} + +void mhi_notify_clients(struct mhi_device_ctxt *mhi_dev_ctxt, + enum MHI_CB_REASON reason) +{ + int i; + struct mhi_client_handle *client_handle = NULL; + + for (i = 0; i < MHI_MAX_CHANNELS; ++i) { + if (VALID_CHAN_NR(i)) { + client_handle = mhi_dev_ctxt->client_handle_list[i]; + mhi_notify_client(client_handle, reason); + } + } +} + int mhi_open_channel(struct mhi_client_handle *client_handle) { int ret_val = 0; @@ -389,10 +425,10 @@ int mhi_open_channel(struct mhi_client_handle *client_handle) ret_val = 0; } - spin_lock(&cfg->event_lock); + spin_lock_irq(&cfg->event_lock); cmd_event_pkt = cfg->cmd_event_pkt; cmd_pkt = cfg->cmd_pkt; - spin_unlock(&cfg->event_lock); + spin_unlock_irq(&cfg->event_lock); ev_code = MHI_EV_READ_CODE(EV_TRB_CODE, ((union mhi_event_pkt *)&cmd_event_pkt)); @@ -628,10 +664,7 @@ void mhi_close_channel(struct mhi_client_handle *client_handle) } error_completion: - ret_val = reset_chan_cmd(mhi_dev_ctxt, &cmd_pkt); - if (ret_val) - mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, - "Error resetting cmd ret:%d\n", ret_val); + mhi_reset_chan(mhi_dev_ctxt, chan); read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock); mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt); @@ -1391,11 +1424,8 @@ int recycle_trb_and_ring(struct mhi_device_ctxt *mhi_dev_ctxt, } -static int reset_chan_cmd(struct mhi_device_ctxt *mhi_dev_ctxt, - union mhi_cmd_pkt *cmd_pkt) +void mhi_reset_chan(struct mhi_device_ctxt *mhi_dev_ctxt, int chan) { - u32 chan = 0; - int ret_val = 0; struct mhi_ring *local_chan_ctxt; struct mhi_ring *ev_ring; struct mhi_chan_ctxt *chan_ctxt; @@ -1405,14 +1435,6 @@ static int reset_chan_cmd(struct mhi_device_ctxt *mhi_dev_ctxt, union mhi_event_pkt *local_rp = NULL; union mhi_event_pkt *device_rp = NULL; - MHI_TRB_GET_INFO(CMD_TRB_CHID, cmd_pkt, chan); - - if (!VALID_CHAN_NR(chan)) { - mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, - "Bad channel number for CCE\n"); - return -EINVAL; - } - local_chan_ctxt = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan]; chan_ctxt = &mhi_dev_ctxt->dev_space.ring_ctxt.cc_list[chan]; ev_ring = &mhi_dev_ctxt-> @@ -1420,7 +1442,7 @@ static int reset_chan_cmd(struct mhi_device_ctxt *mhi_dev_ctxt, ev_ctxt = &mhi_dev_ctxt-> dev_space.ring_ctxt.ec_list[chan_ctxt->mhi_event_ring_index]; mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, - "Processed cmd reset event\n"); + "Marking all events for chan:%d as stale\n", chan); /* Clear all stale events related to Channel */ spin_lock_irqsave(&ev_ring->ring_lock, flags); @@ -1483,7 +1505,6 @@ static int reset_chan_cmd(struct mhi_device_ctxt *mhi_dev_ctxt, chan_ctxt->mhi_trb_write_ptr = chan_ctxt->mhi_trb_ring_base_addr; mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Reset complete.\n"); - return ret_val; } enum MHI_EVENT_CCS get_cmd_pkt(struct mhi_device_ctxt *mhi_dev_ctxt, @@ -1510,11 +1531,11 @@ int mhi_poll_inbound(struct mhi_client_handle *client_handle, struct mhi_tx_pkt *pending_trb = 0; struct mhi_device_ctxt *mhi_dev_ctxt = NULL; struct mhi_ring *local_chan_ctxt = NULL; - struct mhi_chan_cfg *cfg; struct mhi_ring *bb_ctxt = NULL; struct mhi_buf_info *bb = NULL; struct mhi_client_config *client_config; - int chan = 0, r = 0; + int chan = 0, r = -EIO; + unsigned long flags; if (!client_handle || !result) return -EINVAL; @@ -1525,36 +1546,38 @@ int mhi_poll_inbound(struct mhi_client_handle *client_handle, chan = client_config->chan_info.chan_nr; local_chan_ctxt = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan]; - cfg = &mhi_dev_ctxt->mhi_chan_cfg[chan]; bb_ctxt = &mhi_dev_ctxt->chan_bb_list[chan]; - mutex_lock(&cfg->chan_lock); - if (bb_ctxt->rp != bb_ctxt->ack_rp) { - pending_trb = (struct mhi_tx_pkt *)(local_chan_ctxt->ack_rp); - result->flags = pending_trb->info; - bb = bb_ctxt->ack_rp; - if (bb->bb_active) { - mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, - "Bounce buffer active chan %d, copying data\n", - chan); + spin_lock_irqsave(&local_chan_ctxt->ring_lock, flags); + if (local_chan_ctxt->ch_state == MHI_CHAN_STATE_ENABLED) { + if (bb_ctxt->rp != bb_ctxt->ack_rp) { + pending_trb = + (struct mhi_tx_pkt *)(local_chan_ctxt->ack_rp); + result->flags = pending_trb->info; + bb = bb_ctxt->ack_rp; + if (bb->bb_active) { + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, + "Bounce buffer active chan %d, copying data\n", + chan); + } + result->buf_addr = bb->client_buf; + result->bytes_xferd = bb->filled_size; + result->transaction_status = 0; + r = delete_element(local_chan_ctxt, + &local_chan_ctxt->ack_rp, + &local_chan_ctxt->rp, NULL); + WARN_ON(r); + r = delete_element(bb_ctxt, + &bb_ctxt->ack_rp, + &bb_ctxt->rp, NULL); + WARN_ON(r); + } else { + result->buf_addr = 0; + result->bytes_xferd = 0; + r = -ENODATA; } - result->buf_addr = bb->client_buf; - result->bytes_xferd = bb->filled_size; - result->transaction_status = 0; - r = delete_element(local_chan_ctxt, - &local_chan_ctxt->ack_rp, - &local_chan_ctxt->rp, NULL); - BUG_ON(r); - r = delete_element(bb_ctxt, - &bb_ctxt->ack_rp, - &bb_ctxt->rp, NULL); - BUG_ON(r); - } else { - result->buf_addr = 0; - result->bytes_xferd = 0; - r = -ENODATA; } - mutex_unlock(&cfg->chan_lock); + spin_unlock_irqrestore(&local_chan_ctxt->ring_lock, flags); mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Exited Result: Buf addr: 0x%p Bytes xfed 0x%zx chan %d\n", result->buf_addr, result->bytes_xferd, chan); @@ -1647,9 +1670,10 @@ void mhi_assert_device_wake(struct mhi_device_ctxt *mhi_dev_ctxt, if (unlikely(force_set)) { spin_lock_irqsave(&mhi_dev_ctxt->dev_wake_lock, flags); atomic_inc(&mhi_dev_ctxt->counters.device_wake); - mhi_write_db(mhi_dev_ctxt, - mhi_dev_ctxt->mmio_info.chan_db_addr, - MHI_DEV_WAKE_DB, 1); + if (MHI_WAKE_DB_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state)) + mhi_write_db(mhi_dev_ctxt, + mhi_dev_ctxt->mmio_info.chan_db_addr, + MHI_DEV_WAKE_DB, 1); spin_unlock_irqrestore(&mhi_dev_ctxt->dev_wake_lock, flags); } else { if (likely(atomic_add_unless(&mhi_dev_ctxt-> @@ -1744,7 +1768,7 @@ EXPORT_SYMBOL(mhi_deregister_channel); int mhi_register_device(struct mhi_device *mhi_device, const char *node_name, - unsigned long user_data) + void *user_data) { const struct device_node *of_node; struct mhi_device_ctxt *mhi_dev_ctxt = NULL, *itr; @@ -1793,6 +1817,7 @@ int mhi_register_device(struct mhi_device *mhi_device, mhi_dev_ctxt->mhi_pm_state = MHI_PM_DISABLE; INIT_WORK(&mhi_dev_ctxt->process_m1_worker, process_m1_transition); INIT_WORK(&mhi_dev_ctxt->st_thread_worker, mhi_state_change_worker); + INIT_WORK(&mhi_dev_ctxt->process_sys_err_worker, mhi_sys_err_worker); mutex_init(&mhi_dev_ctxt->pm_lock); rwlock_init(&mhi_dev_ctxt->pm_xfer_lock); spin_lock_init(&mhi_dev_ctxt->dev_wake_lock); @@ -1828,11 +1853,15 @@ int mhi_register_device(struct mhi_device *mhi_device, if (!core_info->bar0_base || !core_info->irq_base) return -EINVAL; + if (mhi_device->support_rddm && !mhi_device->rddm_size) + return -EINVAL; mhi_dev_ctxt->bus_master_rt_get = mhi_device->pm_runtime_get; - mhi_dev_ctxt->bus_master_rt_put = mhi_device->pm_runtime_noidle; - if (!mhi_dev_ctxt->bus_master_rt_get || - !mhi_dev_ctxt->bus_master_rt_put) + mhi_dev_ctxt->bus_master_rt_put = mhi_device->pm_runtime_put_noidle; + mhi_dev_ctxt->status_cb = mhi_device->status_cb; + mhi_dev_ctxt->priv_data = user_data; + if (!mhi_dev_ctxt->bus_master_rt_get || !mhi_dev_ctxt->bus_master_rt_put + || !mhi_dev_ctxt->status_cb) return -EINVAL; ret = mhi_ctxt_init(mhi_dev_ctxt); @@ -1849,12 +1878,44 @@ int mhi_register_device(struct mhi_device *mhi_device, mhi_dev_ctxt->runtime_get = mhi_slave_mode_runtime_get; mhi_dev_ctxt->runtime_put = mhi_slave_mode_runtime_put; mhi_device->mhi_dev_ctxt = mhi_dev_ctxt; - mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exit success\n"); + /* Store RDDM information */ + if (mhi_device->support_rddm) { + mhi_dev_ctxt->bhi_ctxt.support_rddm = true; + mhi_dev_ctxt->bhi_ctxt.rddm_size = mhi_device->rddm_size; + + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Device support rddm of size:0x%lx bytes\n", + mhi_dev_ctxt->bhi_ctxt.rddm_size); + } + + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exit success\n"); return 0; } EXPORT_SYMBOL(mhi_register_device); +int mhi_xfer_rddm(struct mhi_device *mhi_device, enum mhi_rddm_segment seg, + struct scatterlist **sg_list) +{ + struct mhi_device_ctxt *mhi_dev_ctxt = mhi_device->mhi_dev_ctxt; + struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt; + int segments = 0; + + *sg_list = NULL; + switch (seg) { + case MHI_RDDM_FW_SEGMENT: + *sg_list = bhi_ctxt->fw_table.sg_list; + segments = bhi_ctxt->fw_table.segment_count; + break; + case MHI_RDDM_RD_SEGMENT: + *sg_list = bhi_ctxt->rddm_table.sg_list; + segments = bhi_ctxt->rddm_table.segment_count; + break; + } + return segments; +} +EXPORT_SYMBOL(mhi_xfer_rddm); + void mhi_process_db_brstmode(struct mhi_device_ctxt *mhi_dev_ctxt, void __iomem *io_addr, uintptr_t chan, diff --git a/drivers/platform/msm/mhi/mhi_pm.c b/drivers/platform/msm/mhi/mhi_pm.c index d7a4f7aa93ef..caa34eadf8ea 100644 --- a/drivers/platform/msm/mhi/mhi_pm.c +++ b/drivers/platform/msm/mhi/mhi_pm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -62,6 +62,7 @@ static int mhi_pm_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt, bool force_m3) { int r = 0; + enum MHI_PM_STATE new_state; read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock); mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, @@ -79,13 +80,20 @@ static int mhi_pm_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt, } if (unlikely(atomic_read(&mhi_dev_ctxt->counters.device_wake) && - force_m3 == false)){ - mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, - "Busy, Aborting M3\n"); + force_m3 == false)) { + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Busy, Aborting M3\n"); read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); return -EBUSY; } + if (unlikely(!MHI_REG_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state))) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Error, no register access, PM_STATE:0x%x\n", + mhi_dev_ctxt->mhi_pm_state); + read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); + return -EIO; + } + mhi_dev_ctxt->assert_wake(mhi_dev_ctxt, false); read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock); r = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.m0_event, @@ -93,7 +101,7 @@ static int mhi_pm_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt, mhi_dev_ctxt->mhi_state == MHI_STATE_M1, msecs_to_jiffies(MHI_MAX_RESUME_TIMEOUT)); if (!r) { - mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to get M0||M1 event, timeout, current state:%s\n", TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); return -EIO; @@ -102,7 +110,14 @@ static int mhi_pm_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt, mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Allowing M3 State\n"); write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt); - mhi_dev_ctxt->mhi_pm_state = MHI_PM_M3_ENTER; + new_state = mhi_tryset_pm_state(mhi_dev_ctxt, MHI_PM_M3_ENTER); + if (unlikely(new_state != MHI_PM_M3_ENTER)) { + write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Error setting PM_STATE from 0x%x to 0x%x\n", + new_state, MHI_PM_M3_ENTER); + return -EIO; + } mhi_set_m_state(mhi_dev_ctxt, MHI_STATE_M3); write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Waiting for M3 completion.\n"); @@ -110,7 +125,7 @@ static int mhi_pm_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt, mhi_dev_ctxt->mhi_state == MHI_STATE_M3, msecs_to_jiffies(MHI_MAX_SUSPEND_TIMEOUT)); if (!r) { - mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to get M3 event, timeout, current state:%s\n", TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); return -EIO; @@ -122,6 +137,7 @@ static int mhi_pm_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt, static int mhi_pm_initiate_m0(struct mhi_device_ctxt *mhi_dev_ctxt) { int r; + enum MHI_PM_STATE cur_state; mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Entered with State:0x%x %s\n", @@ -129,11 +145,16 @@ static int mhi_pm_initiate_m0(struct mhi_device_ctxt *mhi_dev_ctxt) TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); - mhi_dev_ctxt->mhi_pm_state = MHI_PM_M3_EXIT; - write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); + cur_state = mhi_tryset_pm_state(mhi_dev_ctxt, MHI_PM_M3_EXIT); + if (unlikely(cur_state != MHI_PM_M3_EXIT)) { + write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Error setting PM_STATE from 0x%x to 0x%x\n", + cur_state, MHI_PM_M3_EXIT); + return -EAGAIN; + } /* Set and wait for M0 Event */ - write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); mhi_set_m_state(mhi_dev_ctxt, MHI_STATE_M0); write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); r = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.m0_event, @@ -164,7 +185,7 @@ int mhi_runtime_suspend(struct device *dev) mutex_unlock(&mhi_dev_ctxt->pm_lock); return r; } - r = mhi_turn_off_pcie_link(mhi_dev_ctxt); + r = mhi_turn_off_pcie_link(mhi_dev_ctxt, true); if (r) { mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Failed to Turn off link ret:%d\n", r); @@ -294,6 +315,21 @@ unlock_pm_lock: return ret_val; } +static void mhi_pm_slave_mode_power_off(struct mhi_device_ctxt *mhi_dev_ctxt) +{ + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Entered with pm_state:0x%x MHI_STATE:%s\n", + mhi_dev_ctxt->mhi_pm_state, + TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); + + if (mhi_dev_ctxt->mhi_pm_state == MHI_PM_DISABLE) { + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "MHI already in disabled state\n"); + return; + } + process_disable_transition(MHI_PM_SHUTDOWN_PROCESS, mhi_dev_ctxt); +} + static int mhi_pm_slave_mode_suspend(struct mhi_device_ctxt *mhi_dev_ctxt) { int r; @@ -367,7 +403,7 @@ ssize_t sysfs_init_m3(struct device *dev, struct device_attribute *attr, return count; } -int mhi_turn_off_pcie_link(struct mhi_device_ctxt *mhi_dev_ctxt) +int mhi_turn_off_pcie_link(struct mhi_device_ctxt *mhi_dev_ctxt, bool graceful) { struct pci_dev *pcie_dev; int r = 0; @@ -376,22 +412,23 @@ int mhi_turn_off_pcie_link(struct mhi_device_ctxt *mhi_dev_ctxt) pcie_dev = mhi_dev_ctxt->pcie_device; if (0 == mhi_dev_ctxt->flags.link_up) { - mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Link already marked as down, nothing to do\n"); goto exit; } - r = pci_save_state(pcie_dev); - if (r) { - mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, - "Failed to save pcie state ret: %d\n", r); - } - mhi_dev_ctxt->core.pcie_state = pci_store_saved_state(pcie_dev); - pci_disable_device(pcie_dev); - r = pci_set_power_state(pcie_dev, PCI_D3hot); - if (r) { - mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, - "Failed to set pcie power state to D3hot ret:%d\n", r); + if (graceful) { + r = pci_save_state(pcie_dev); + if (r) + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, + "Failed to save pcie state ret: %d\n", r); + mhi_dev_ctxt->core.pcie_state = pci_store_saved_state(pcie_dev); + pci_disable_device(pcie_dev); + r = pci_set_power_state(pcie_dev, PCI_D3hot); + if (r) + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, + "Failed to set pcie power state to D3hot ret:%d\n", + r); } r = msm_pcie_pm_control(MSM_PCIE_SUSPEND, @@ -430,21 +467,26 @@ int mhi_turn_on_pcie_link(struct mhi_device_ctxt *mhi_dev_ctxt) mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, "Could not set bus frequency ret: %d\n", r); - r = msm_pcie_pm_control(MSM_PCIE_RESUME, - pcie_dev->bus->number, - pcie_dev, - NULL, - 0); + r = msm_pcie_pm_control(MSM_PCIE_RESUME, pcie_dev->bus->number, + pcie_dev, NULL, 0); if (r) { mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, "Failed to resume pcie bus ret %d\n", r); goto exit; } + r = pci_set_power_state(pcie_dev, PCI_D0); + if (r) { + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Failed to set PCI_D0 state ret:%d\n", r); + goto exit; + } r = pci_enable_device(pcie_dev); - if (r) - mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, + if (r) { + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Failed to enable device ret:%d\n", r); + goto exit; + } pci_load_and_free_saved_state(pcie_dev, &mhi_dev_ctxt->core.pcie_state); @@ -457,6 +499,44 @@ exit: return r; } +void mhi_link_state_cb(struct msm_pcie_notify *notify) +{ + struct mhi_device_ctxt *mhi_dev_ctxt = NULL; + + if (!notify || !notify->data) { + pr_err("%s: incomplete handle received\n", __func__); + return; + } + + mhi_dev_ctxt = notify->data; + switch (notify->event) { + case MSM_PCIE_EVENT_LINKDOWN: + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Received MSM_PCIE_EVENT_LINKDOWN\n"); + break; + case MSM_PCIE_EVENT_LINKUP: + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Received MSM_PCIE_EVENT_LINKUP\n"); + mhi_dev_ctxt->counters.link_up_cntr++; + break; + case MSM_PCIE_EVENT_WAKEUP: + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Received MSM_PCIE_EVENT_WAKE\n"); + __pm_stay_awake(&mhi_dev_ctxt->w_lock); + __pm_relax(&mhi_dev_ctxt->w_lock); + + if (mhi_dev_ctxt->flags.mhi_initialized) { + mhi_dev_ctxt->runtime_get(mhi_dev_ctxt); + mhi_dev_ctxt->runtime_put(mhi_dev_ctxt); + } + break; + default: + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Received bad link event\n"); + return; + } +} + int mhi_pm_control_device(struct mhi_device *mhi_device, enum mhi_dev_ctrl ctrl) { @@ -477,9 +557,34 @@ int mhi_pm_control_device(struct mhi_device *mhi_device, return mhi_pm_slave_mode_suspend(mhi_dev_ctxt); case MHI_DEV_CTRL_RESUME: return mhi_pm_slave_mode_resume(mhi_dev_ctxt); - default: + case MHI_DEV_CTRL_POWER_OFF: + mhi_pm_slave_mode_power_off(mhi_dev_ctxt); + break; + case MHI_DEV_CTRL_RDDM: + return bhi_rddm(mhi_dev_ctxt, false); + case MHI_DEV_CTRL_DE_INIT: + if (mhi_dev_ctxt->mhi_pm_state != MHI_PM_DISABLE) + process_disable_transition(MHI_PM_SHUTDOWN_PROCESS, + mhi_dev_ctxt); + bhi_exit(mhi_dev_ctxt); + break; + case MHI_DEV_CTRL_NOTIFY_LINK_ERROR: + { + enum MHI_PM_STATE cur_state; + + write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); + cur_state = mhi_tryset_pm_state(mhi_dev_ctxt, + MHI_PM_LD_ERR_FATAL_DETECT); + write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); + if (unlikely(cur_state != MHI_PM_LD_ERR_FATAL_DETECT)) + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Failed to transition to state 0x%x from 0x%x\n", + MHI_PM_LD_ERR_FATAL_DETECT, cur_state); break; } - return -EINVAL; + default: + return -EINVAL; + } + return 0; } EXPORT_SYMBOL(mhi_pm_control_device); diff --git a/drivers/platform/msm/mhi/mhi_ssr.c b/drivers/platform/msm/mhi/mhi_ssr.c index 22481dede21a..9f18b1e7ef85 100644 --- a/drivers/platform/msm/mhi/mhi_ssr.c +++ b/drivers/platform/msm/mhi/mhi_ssr.c @@ -13,12 +13,8 @@ #include <linux/pm_runtime.h> #include <mhi_sys.h> #include <mhi.h> -#include <mhi_bhi.h> -#include <mhi_hwio.h> - #include <soc/qcom/subsystem_restart.h> #include <soc/qcom/subsystem_notif.h> - #include <linux/esoc_client.h> static int mhi_ssr_notify_cb(struct notifier_block *nb, @@ -26,35 +22,45 @@ static int mhi_ssr_notify_cb(struct notifier_block *nb, { struct mhi_device_ctxt *mhi_dev_ctxt = container_of(nb, struct mhi_device_ctxt, mhi_ssr_nb); + enum MHI_PM_STATE cur_state; + struct notif_data *notif_data = (struct notif_data *)data; + bool crashed = notif_data->crashed; + + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Received ESOC notifcation:%lu crashed:%d\n", action, crashed); switch (action) { - case SUBSYS_BEFORE_POWERUP: - mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, - "Received Subsystem event BEFORE_POWERUP\n"); - break; - case SUBSYS_AFTER_POWERUP: - mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, - "Received Subsystem event AFTER_POWERUP\n"); - break; - case SUBSYS_POWERUP_FAILURE: - mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, - "Received Subsystem event POWERUP_FAILURE\n"); - break; case SUBSYS_BEFORE_SHUTDOWN: - mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, - "Received Subsystem event BEFORE_SHUTDOWN\n"); + /* + * update internal states only, we'll clean up MHI context + * after device shutdown completely. + */ + write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); + cur_state = mhi_tryset_pm_state(mhi_dev_ctxt, + MHI_PM_LD_ERR_FATAL_DETECT); + write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); + if (unlikely(cur_state != MHI_PM_LD_ERR_FATAL_DETECT)) + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Failed to transition to state 0x%x from 0x%x\n", + MHI_PM_LD_ERR_FATAL_DETECT, cur_state); break; case SUBSYS_AFTER_SHUTDOWN: - mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, - "Received Subsystem event AFTER_SHUTDOWN\n"); - break; - case SUBSYS_RAMDUMP_NOTIFICATION: - mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, - "Received Subsystem event RAMDUMP\n"); + if (mhi_dev_ctxt->mhi_pm_state != MHI_PM_DISABLE) + process_disable_transition(MHI_PM_SHUTDOWN_PROCESS, + mhi_dev_ctxt); + mutex_lock(&mhi_dev_ctxt->pm_lock); + write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); + cur_state = mhi_tryset_pm_state(mhi_dev_ctxt, + MHI_PM_SSR_PENDING); + write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); + mutex_unlock(&mhi_dev_ctxt->pm_lock); + if (unlikely(cur_state != MHI_PM_SSR_PENDING)) + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Failed to transition to state 0x%x from 0x%x\n", + MHI_PM_SSR_PENDING, cur_state); break; default: mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, - "Received ESOC notifcation %d, NOT handling\n", - (int)action); + "Not handling esoc notification:%lu\n", action); break; } return NOTIFY_OK; @@ -91,128 +97,242 @@ int mhi_esoc_register(struct mhi_device_ctxt *mhi_dev_ctxt) return ret_val; } -void mhi_notify_client(struct mhi_client_handle *client_handle, - enum MHI_CB_REASON reason) +/* handles sys_err, and shutdown transition */ +void process_disable_transition(enum MHI_PM_STATE transition_state, + struct mhi_device_ctxt *mhi_dev_ctxt) { - struct mhi_cb_info cb_info = {0}; - struct mhi_result result = {0}; - struct mhi_client_config *client_config; + enum MHI_PM_STATE cur_state, prev_state; + struct mhi_client_handle *client_handle; + struct mhi_ring *ch_ring, *bb_ring, *cmd_ring; + struct mhi_cmd_ctxt *cmd_ctxt; + struct mhi_chan_cfg *chan_cfg; + rwlock_t *pm_xfer_lock = &mhi_dev_ctxt->pm_xfer_lock; + enum MHI_CB_REASON reason; + u32 timeout = mhi_dev_ctxt->poll_reset_timeout_ms; + int i; + int ret; + + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Enter with pm_state:0x%x MHI_STATE:%s transition_state:0x%x\n", + mhi_dev_ctxt->mhi_pm_state, + TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state), + transition_state); - cb_info.result = NULL; - cb_info.cb_reason = reason; + mutex_lock(&mhi_dev_ctxt->pm_lock); + write_lock_irq(pm_xfer_lock); + prev_state = mhi_dev_ctxt->mhi_pm_state; + cur_state = mhi_tryset_pm_state(mhi_dev_ctxt, transition_state); + if (cur_state == transition_state) { + mhi_dev_ctxt->dev_exec_env = MHI_EXEC_ENV_DISABLE_TRANSITION; + mhi_dev_ctxt->flags.mhi_initialized = false; + } + write_unlock_irq(pm_xfer_lock); - if (client_handle == NULL) + /* Not handling sys_err, could be middle of shut down */ + if (unlikely(cur_state != transition_state)) { + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Failed to transition to state 0x%x from 0x%x\n", + transition_state, cur_state); + mutex_unlock(&mhi_dev_ctxt->pm_lock); return; + } - client_config = client_handle->client_config; - - if (client_config->client_info.mhi_client_cb) { - result.user_data = client_config->user_data; - cb_info.chan = client_config->chan_info.chan_nr; - cb_info.result = &result; - mhi_log(client_config->mhi_dev_ctxt, MHI_MSG_INFO, - "Calling back for chan %d, reason %d\n", - cb_info.chan, - reason); - client_config->client_info.mhi_client_cb(&cb_info); + /* + * If we're shutting down trigger device into MHI reset + * so we can gurantee device will not access host DDR + * during reset + */ + if (cur_state == MHI_PM_SHUTDOWN_PROCESS && + MHI_REG_ACCESS_VALID(prev_state)) { + read_lock_bh(pm_xfer_lock); + mhi_set_m_state(mhi_dev_ctxt, MHI_STATE_RESET); + read_unlock_bh(pm_xfer_lock); + mhi_test_for_device_reset(mhi_dev_ctxt); } -} -void mhi_notify_clients(struct mhi_device_ctxt *mhi_dev_ctxt, - enum MHI_CB_REASON reason) -{ - int i; - struct mhi_client_handle *client_handle = NULL; + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Waiting for all pending event ring processing to complete\n"); + for (i = 0; i < mhi_dev_ctxt->mmio_info.nr_event_rings; i++) { + tasklet_kill(&mhi_dev_ctxt->mhi_local_event_ctxt[i].ev_task); + flush_work(&mhi_dev_ctxt->mhi_local_event_ctxt[i].ev_worker); + } + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Notifying all clients and resetting channels\n"); - for (i = 0; i < MHI_MAX_CHANNELS; ++i) { - if (VALID_CHAN_NR(i)) { - client_handle = mhi_dev_ctxt->client_handle_list[i]; + if (cur_state == MHI_PM_SHUTDOWN_PROCESS) + reason = MHI_CB_MHI_SHUTDOWN; + else + reason = MHI_CB_SYS_ERROR; + ch_ring = mhi_dev_ctxt->mhi_local_chan_ctxt; + chan_cfg = mhi_dev_ctxt->mhi_chan_cfg; + bb_ring = mhi_dev_ctxt->chan_bb_list; + for (i = 0; i < MHI_MAX_CHANNELS; + i++, ch_ring++, chan_cfg++, bb_ring++) { + enum MHI_CHAN_STATE ch_state; + + client_handle = mhi_dev_ctxt->client_handle_list[i]; + if (client_handle) mhi_notify_client(client_handle, reason); + + mutex_lock(&chan_cfg->chan_lock); + spin_lock_irq(&ch_ring->ring_lock); + ch_state = ch_ring->ch_state; + ch_ring->ch_state = MHI_CHAN_STATE_DISABLED; + spin_unlock_irq(&ch_ring->ring_lock); + + /* Reset channel and free ring */ + if (ch_state == MHI_CHAN_STATE_ENABLED) { + mhi_reset_chan(mhi_dev_ctxt, i); + free_tre_ring(mhi_dev_ctxt, i); + bb_ring->rp = bb_ring->base; + bb_ring->wp = bb_ring->base; + bb_ring->ack_rp = bb_ring->base; } + mutex_unlock(&chan_cfg->chan_lock); } -} + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Finished notifying clients\n"); -int set_mhi_base_state(struct mhi_device_ctxt *mhi_dev_ctxt) -{ - u32 pcie_word_val = 0; - int r = 0; + /* Release lock and wait for all pending threads to complete */ + mutex_unlock(&mhi_dev_ctxt->pm_lock); + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Waiting for all pending threads to complete\n"); + complete(&mhi_dev_ctxt->cmd_complete); + flush_work(&mhi_dev_ctxt->process_m1_worker); + flush_work(&mhi_dev_ctxt->st_thread_worker); + if (mhi_dev_ctxt->bhi_ctxt.manage_boot) + flush_work(&mhi_dev_ctxt->bhi_ctxt.fw_load_work); + if (cur_state == MHI_PM_SHUTDOWN_PROCESS) + flush_work(&mhi_dev_ctxt->process_sys_err_worker); - mhi_dev_ctxt->bhi_ctxt.bhi_base = mhi_dev_ctxt->core.bar0_base; - pcie_word_val = mhi_reg_read(mhi_dev_ctxt->bhi_ctxt.bhi_base, BHIOFF); + mutex_lock(&mhi_dev_ctxt->pm_lock); - /* confirm it's a valid reading */ - if (unlikely(pcie_word_val == U32_MAX)) { - mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, - "Invalid BHI Offset:0x%x\n", pcie_word_val); - return -EIO; - } - mhi_dev_ctxt->bhi_ctxt.bhi_base += pcie_word_val; - pcie_word_val = mhi_reg_read(mhi_dev_ctxt->bhi_ctxt.bhi_base, - BHI_EXECENV); - mhi_dev_ctxt->dev_exec_env = pcie_word_val; - if (pcie_word_val == MHI_EXEC_ENV_AMSS) { - mhi_dev_ctxt->base_state = STATE_TRANSITION_RESET; - } else if (pcie_word_val == MHI_EXEC_ENV_PBL) { - mhi_dev_ctxt->base_state = STATE_TRANSITION_BHI; - } else { - mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, - "Invalid EXEC_ENV: 0x%x\n", - pcie_word_val); - r = -EIO; + /* + * Shutdown has higher priority than sys_err and can be called + * middle of sys error, check current state to confirm state + * was not changed. + */ + if (mhi_dev_ctxt->mhi_pm_state != cur_state) { + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "PM State transitioned to 0x%x while processing 0x%x\n", + mhi_dev_ctxt->mhi_pm_state, transition_state); + mutex_unlock(&mhi_dev_ctxt->pm_lock); + return; } - mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, - "EXEC_ENV: %d Base state %d\n", - pcie_word_val, mhi_dev_ctxt->base_state); - return r; -} -void mhi_link_state_cb(struct msm_pcie_notify *notify) -{ - struct mhi_device_ctxt *mhi_dev_ctxt = NULL; + /* Check all counts to make sure 0 */ + WARN_ON(atomic_read(&mhi_dev_ctxt->counters.device_wake)); + WARN_ON(atomic_read(&mhi_dev_ctxt->counters.outbound_acks)); + if (mhi_dev_ctxt->core.pci_master) + WARN_ON(atomic_read(&mhi_dev_ctxt->pcie_device->dev. + power.usage_count)); - if (!notify || !notify->data) { - pr_err("%s: incomplete handle received\n", __func__); - return; + /* Reset Event rings and CMD rings */ + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Resetting ev ctxt and cmd ctxt\n"); + + cmd_ring = mhi_dev_ctxt->mhi_local_cmd_ctxt; + cmd_ctxt = mhi_dev_ctxt->dev_space.ring_ctxt.cmd_ctxt; + for (i = 0; i < NR_OF_CMD_RINGS; i++, cmd_ring++) { + cmd_ring->rp = cmd_ring->base; + cmd_ring->wp = cmd_ring->base; + cmd_ctxt->mhi_cmd_ring_read_ptr = + cmd_ctxt->mhi_cmd_ring_base_addr; + cmd_ctxt->mhi_cmd_ring_write_ptr = + cmd_ctxt->mhi_cmd_ring_base_addr; } + for (i = 0; i < mhi_dev_ctxt->mmio_info.nr_event_rings; i++) + mhi_reset_ev_ctxt(mhi_dev_ctxt, i); - mhi_dev_ctxt = notify->data; - switch (notify->event) { - case MSM_PCIE_EVENT_LINKDOWN: - mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, - "Received MSM_PCIE_EVENT_LINKDOWN\n"); - break; - case MSM_PCIE_EVENT_LINKUP: - mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, - "Received MSM_PCIE_EVENT_LINKUP\n"); - mhi_dev_ctxt->counters.link_up_cntr++; - break; - case MSM_PCIE_EVENT_WAKEUP: - mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, - "Received MSM_PCIE_EVENT_WAKE\n"); - __pm_stay_awake(&mhi_dev_ctxt->w_lock); - __pm_relax(&mhi_dev_ctxt->w_lock); + /* + * If we're the bus master disable runtime suspend + * we will enable it back again during AMSS transition + */ + if (mhi_dev_ctxt->core.pci_master) + pm_runtime_forbid(&mhi_dev_ctxt->pcie_device->dev); + + if (cur_state == MHI_PM_SYS_ERR_PROCESS) { + bool trigger_reset = false; - if (mhi_dev_ctxt->flags.mhi_initialized) { - mhi_dev_ctxt->runtime_get(mhi_dev_ctxt); - mhi_dev_ctxt->runtime_put(mhi_dev_ctxt); - } - break; - default: mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, - "Received bad link event\n"); - return; + "Triggering device reset\n"); + reinit_completion(&mhi_dev_ctxt->cmd_complete); + write_lock_irq(pm_xfer_lock); + /* Link can go down while processing SYS_ERR */ + if (MHI_REG_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state)) { + mhi_set_m_state(mhi_dev_ctxt, MHI_STATE_RESET); + mhi_init_state_transition(mhi_dev_ctxt, + STATE_TRANSITION_RESET); + trigger_reset = true; } + write_unlock_irq(pm_xfer_lock); + + if (trigger_reset) { + /* + * Keep the MHI state in Active (M0) state until host + * enter AMSS/RDDM state. Otherwise modem would error + * fatal if host try to enter M1 before reaching + * AMSS\RDDM state. + */ + read_lock_bh(pm_xfer_lock); + mhi_assert_device_wake(mhi_dev_ctxt, false); + read_unlock_bh(pm_xfer_lock); + + /* Wait till we enter AMSS/RDDM Exec env.*/ + ret = wait_for_completion_timeout + (&mhi_dev_ctxt->cmd_complete, + msecs_to_jiffies(timeout)); + if (!ret || (mhi_dev_ctxt->dev_exec_env != + MHI_EXEC_ENV_AMSS && + mhi_dev_ctxt->dev_exec_env != + MHI_EXEC_ENV_RDDM)) { + + /* + * device did not reset properly, notify bus + * master + */ + if (!mhi_dev_ctxt->core.pci_master) { + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Notifying bus master Sys Error Status\n"); + mhi_dev_ctxt->status_cb( + MHI_CB_SYS_ERROR, + mhi_dev_ctxt->priv_data); + } + mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt); + } + } + } else { + write_lock_irq(pm_xfer_lock); + cur_state = mhi_tryset_pm_state(mhi_dev_ctxt, MHI_PM_DISABLE); + write_unlock_irq(pm_xfer_lock); + if (unlikely(cur_state != MHI_PM_DISABLE)) + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Error transition from state:0x%x to 0x%x\n", + cur_state, MHI_PM_DISABLE); + + if (mhi_dev_ctxt->core.pci_master && + cur_state == MHI_PM_DISABLE) + mhi_turn_off_pcie_link(mhi_dev_ctxt, + MHI_REG_ACCESS_VALID(prev_state)); + } + + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Exit with pm_state:0x%x exec_env:0x%x mhi_state:%s\n", + mhi_dev_ctxt->mhi_pm_state, mhi_dev_ctxt->dev_exec_env, + TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); + + mutex_unlock(&mhi_dev_ctxt->pm_lock); } -int init_mhi_base_state(struct mhi_device_ctxt *mhi_dev_ctxt) +void mhi_sys_err_worker(struct work_struct *work) { - int r = 0; + struct mhi_device_ctxt *mhi_dev_ctxt = + container_of(work, struct mhi_device_ctxt, + process_sys_err_worker); - r = mhi_init_state_transition(mhi_dev_ctxt, mhi_dev_ctxt->base_state); - if (r) { - mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, - "Failed to start state change event, to %d\n", - mhi_dev_ctxt->base_state); - } - return r; + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Enter with pm_state:0x%x MHI_STATE:%s\n", + mhi_dev_ctxt->mhi_pm_state, + TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); + + process_disable_transition(MHI_PM_SYS_ERR_PROCESS, mhi_dev_ctxt); } diff --git a/drivers/platform/msm/mhi/mhi_states.c b/drivers/platform/msm/mhi/mhi_states.c index a4da6c21b50d..c0c23c4e0756 100644 --- a/drivers/platform/msm/mhi/mhi_states.c +++ b/drivers/platform/msm/mhi/mhi_states.c @@ -13,6 +13,7 @@ #include "mhi_sys.h" #include "mhi_hwio.h" #include "mhi_trace.h" +#include "mhi_bhi.h" #include <linux/platform_device.h> #include <linux/pm_runtime.h> @@ -33,6 +34,7 @@ const char *state_transition_str(enum STATE_TRANSITION state) [STATE_TRANSITION_LINK_DOWN] = "LINK_DOWN", [STATE_TRANSITION_WAKE] = "WAKE", [STATE_TRANSITION_BHIE] = "BHIE", + [STATE_TRANSITION_RDDM] = "RDDM", [STATE_TRANSITION_SYS_ERR] = "SYS_ERR", }; @@ -40,6 +42,53 @@ const char *state_transition_str(enum STATE_TRANSITION state) mhi_states_transition_str[state] : "Invalid"; } +int set_mhi_base_state(struct mhi_device_ctxt *mhi_dev_ctxt) +{ + u32 pcie_word_val = 0; + int r = 0; + + mhi_dev_ctxt->bhi_ctxt.bhi_base = mhi_dev_ctxt->core.bar0_base; + pcie_word_val = mhi_reg_read(mhi_dev_ctxt->bhi_ctxt.bhi_base, BHIOFF); + + /* confirm it's a valid reading */ + if (unlikely(pcie_word_val == U32_MAX)) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Invalid BHI Offset:0x%x\n", pcie_word_val); + return -EIO; + } + mhi_dev_ctxt->bhi_ctxt.bhi_base += pcie_word_val; + pcie_word_val = mhi_reg_read(mhi_dev_ctxt->bhi_ctxt.bhi_base, + BHI_EXECENV); + mhi_dev_ctxt->dev_exec_env = pcie_word_val; + if (pcie_word_val == MHI_EXEC_ENV_AMSS) { + mhi_dev_ctxt->base_state = STATE_TRANSITION_RESET; + } else if (pcie_word_val == MHI_EXEC_ENV_PBL) { + mhi_dev_ctxt->base_state = STATE_TRANSITION_BHI; + } else { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Invalid EXEC_ENV: 0x%x\n", + pcie_word_val); + r = -EIO; + } + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "EXEC_ENV: %d Base state %d\n", + pcie_word_val, mhi_dev_ctxt->base_state); + return r; +} + +int init_mhi_base_state(struct mhi_device_ctxt *mhi_dev_ctxt) +{ + int r = 0; + + r = mhi_init_state_transition(mhi_dev_ctxt, mhi_dev_ctxt->base_state); + if (r) { + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, + "Failed to start state change event, to %d\n", + mhi_dev_ctxt->base_state); + } + return r; +} + enum MHI_STATE mhi_get_m_state(struct mhi_device_ctxt *mhi_dev_ctxt) { u32 state = mhi_reg_read_field(mhi_dev_ctxt->mmio_info.mmio_addr, @@ -47,7 +96,16 @@ enum MHI_STATE mhi_get_m_state(struct mhi_device_ctxt *mhi_dev_ctxt) MHISTATUS_MHISTATE_MASK, MHISTATUS_MHISTATE_SHIFT); - return (state >= MHI_STATE_LIMIT) ? MHI_STATE_LIMIT : state; + return state; +} + +bool mhi_in_sys_err(struct mhi_device_ctxt *mhi_dev_ctxt) +{ + u32 state = mhi_reg_read_field(mhi_dev_ctxt->mmio_info.mmio_addr, + MHISTATUS, MHISTATUS_SYSERR_MASK, + MHISTATUS_SYSERR_SHIFT); + + return (state) ? true : false; } void mhi_set_m_state(struct mhi_device_ctxt *mhi_dev_ctxt, @@ -69,6 +127,140 @@ void mhi_set_m_state(struct mhi_device_ctxt *mhi_dev_ctxt, mhi_reg_read(mhi_dev_ctxt->mmio_info.mmio_addr, MHICTRL); } +/* + * Not all MHI states transitions are sync transitions. Linkdown, SSR, and + * shutdown can happen anytime asynchronously. This function will transition to + * new state only if it's a valid transitions. + * + * Priority increase as we go down, example while in any states from L0, start + * state from L1, L2, or L3 can be set. Notable exception to this rule is state + * DISABLE. From DISABLE state we can transition to only POR or SSR_PENDING + * state. Also for example while in L2 state, user cannot jump back to L1 or + * L0 states. + * Valid transitions: + * L0: DISABLE <--> POR + * DISABLE <--> SSR_PENDING + * POR <--> POR + * POR -> M0 -> M1 -> M1_M2 -> M2 --> M0 + * M1_M2 -> M0 (Device can trigger it) + * M0 -> M3_ENTER -> M3 -> M3_EXIT --> M0 + * M1 -> M3_ENTER --> M3 + * L1: SYS_ERR_DETECT -> SYS_ERR_PROCESS --> POR + * L2: SHUTDOWN_PROCESS -> DISABLE -> SSR_PENDING (via SSR Notification only) + * L3: LD_ERR_FATAL_DETECT -> SHUTDOWN_PROCESS + */ +static const struct mhi_pm_transitions const mhi_state_transitions[] = { + /* L0 States */ + { + MHI_PM_DISABLE, + MHI_PM_POR | MHI_PM_SSR_PENDING + }, + { + MHI_PM_POR, + MHI_PM_POR | MHI_PM_DISABLE | MHI_PM_M0 | + MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | + MHI_PM_LD_ERR_FATAL_DETECT + }, + { + MHI_PM_M0, + MHI_PM_M1 | MHI_PM_M3_ENTER | MHI_PM_SYS_ERR_DETECT | + MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT + }, + { + MHI_PM_M1, + MHI_PM_M1_M2_TRANSITION | MHI_PM_M3_ENTER | + MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | + MHI_PM_LD_ERR_FATAL_DETECT + }, + { + MHI_PM_M1_M2_TRANSITION, + MHI_PM_M2 | MHI_PM_M0 | MHI_PM_SYS_ERR_DETECT | + MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT + }, + { + MHI_PM_M2, + MHI_PM_M0 | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | + MHI_PM_LD_ERR_FATAL_DETECT + }, + { + MHI_PM_M3_ENTER, + MHI_PM_M3 | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | + MHI_PM_LD_ERR_FATAL_DETECT + }, + { + MHI_PM_M3, + MHI_PM_M3_EXIT | MHI_PM_SYS_ERR_DETECT | + MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT + }, + { + MHI_PM_M3_EXIT, + MHI_PM_M0 | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | + MHI_PM_LD_ERR_FATAL_DETECT + }, + /* L1 States */ + { + MHI_PM_SYS_ERR_DETECT, + MHI_PM_SYS_ERR_PROCESS | MHI_PM_SHUTDOWN_PROCESS | + MHI_PM_LD_ERR_FATAL_DETECT + }, + { + MHI_PM_SYS_ERR_PROCESS, + MHI_PM_POR | MHI_PM_SHUTDOWN_PROCESS | + MHI_PM_LD_ERR_FATAL_DETECT + }, + /* L2 States */ + { + MHI_PM_SHUTDOWN_PROCESS, + MHI_PM_DISABLE | MHI_PM_LD_ERR_FATAL_DETECT + }, + /* L3 States */ + { + MHI_PM_LD_ERR_FATAL_DETECT, + MHI_PM_SHUTDOWN_PROCESS + }, + /* From SSR notification only */ + { + MHI_PM_SSR_PENDING, + MHI_PM_DISABLE + } +}; + +enum MHI_PM_STATE __must_check mhi_tryset_pm_state( + struct mhi_device_ctxt *mhi_dev_ctxt, + enum MHI_PM_STATE state) +{ + unsigned long cur_state = mhi_dev_ctxt->mhi_pm_state; + int index = find_last_bit(&cur_state, 32); + + if (unlikely(index >= ARRAY_SIZE(mhi_state_transitions))) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "cur_state:0x%lx out side of mhi_state_transitions\n", + cur_state); + return cur_state; + } + + if (unlikely(mhi_state_transitions[index].from_state != cur_state)) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "index:%u cur_state:0x%lx != actual_state: 0x%x\n", + index, cur_state, + mhi_state_transitions[index].from_state); + return cur_state; + } + + if (unlikely(!(mhi_state_transitions[index].to_states & state))) { + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Not allowing pm state transition from:0x%lx to:0x%x state\n", + cur_state, state); + return cur_state; + } + + mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, + "Transition to pm state from:0x%lx to:0x%x\n", + cur_state, state); + mhi_dev_ctxt->mhi_pm_state = state; + return mhi_dev_ctxt->mhi_pm_state; +} + static void conditional_chan_db_write( struct mhi_device_ctxt *mhi_dev_ctxt, u32 chan) { @@ -158,20 +350,10 @@ static void ring_all_ev_dbs(struct mhi_device_ctxt *mhi_dev_ctxt) } } -static int process_bhie_transition(struct mhi_device_ctxt *mhi_dev_ctxt, - enum STATE_TRANSITION cur_work_item) -{ - mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Entered\n"); - mhi_dev_ctxt->dev_exec_env = MHI_EXEC_ENV_BHIE; - wake_up(mhi_dev_ctxt->mhi_ev_wq.bhi_event); - mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exited\n"); - - return 0; -} - int process_m0_transition(struct mhi_device_ctxt *mhi_dev_ctxt) { unsigned long flags; + enum MHI_PM_STATE cur_state; mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Entered With State %s\n", @@ -190,8 +372,14 @@ int process_m0_transition(struct mhi_device_ctxt *mhi_dev_ctxt) write_lock_irqsave(&mhi_dev_ctxt->pm_xfer_lock, flags); mhi_dev_ctxt->mhi_state = MHI_STATE_M0; - mhi_dev_ctxt->mhi_pm_state = MHI_PM_M0; + cur_state = mhi_tryset_pm_state(mhi_dev_ctxt, MHI_PM_M0); write_unlock_irqrestore(&mhi_dev_ctxt->pm_xfer_lock, flags); + if (unlikely(cur_state != MHI_PM_M0)) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Failed to transition to state 0x%x from 0x%x\n", + MHI_PM_M0, cur_state); + return -EIO; + } read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock); mhi_dev_ctxt->assert_wake(mhi_dev_ctxt, true); @@ -212,6 +400,7 @@ int process_m0_transition(struct mhi_device_ctxt *mhi_dev_ctxt) void process_m1_transition(struct work_struct *work) { struct mhi_device_ctxt *mhi_dev_ctxt; + enum MHI_PM_STATE cur_state; mhi_dev_ctxt = container_of(work, struct mhi_device_ctxt, @@ -224,15 +413,18 @@ void process_m1_transition(struct work_struct *work) TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); /* We either Entered M3 or we did M3->M0 Exit */ - if (mhi_dev_ctxt->mhi_pm_state != MHI_PM_M1) { - write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); - mutex_unlock(&mhi_dev_ctxt->pm_lock); - return; - } + if (mhi_dev_ctxt->mhi_pm_state != MHI_PM_M1) + goto invalid_pm_state; mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Transitioning to M2 Transition\n"); - mhi_dev_ctxt->mhi_pm_state = MHI_PM_M1_M2_TRANSITION; + cur_state = mhi_tryset_pm_state(mhi_dev_ctxt, MHI_PM_M1_M2_TRANSITION); + if (unlikely(cur_state != MHI_PM_M1_M2_TRANSITION)) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Failed to transition to state 0x%x from 0x%x\n", + MHI_PM_M1_M2_TRANSITION, cur_state); + goto invalid_pm_state; + } mhi_dev_ctxt->counters.m1_m2++; mhi_dev_ctxt->mhi_state = MHI_STATE_M2; mhi_set_m_state(mhi_dev_ctxt, MHI_STATE_M2); @@ -245,7 +437,13 @@ void process_m1_transition(struct work_struct *work) if (mhi_dev_ctxt->mhi_pm_state == MHI_PM_M1_M2_TRANSITION) { mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Entered M2 State\n"); - mhi_dev_ctxt->mhi_pm_state = MHI_PM_M2; + cur_state = mhi_tryset_pm_state(mhi_dev_ctxt, MHI_PM_M2); + if (unlikely(cur_state != MHI_PM_M2)) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Failed to transition to state 0x%x from 0x%x\n", + MHI_PM_M2, cur_state); + goto invalid_pm_state; + } } write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); @@ -263,11 +461,17 @@ void process_m1_transition(struct work_struct *work) pm_request_autosuspend(&mhi_dev_ctxt->pcie_device->dev); } mutex_unlock(&mhi_dev_ctxt->pm_lock); + return; + +invalid_pm_state: + write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); + mutex_unlock(&mhi_dev_ctxt->pm_lock); } int process_m3_transition(struct mhi_device_ctxt *mhi_dev_ctxt) { unsigned long flags; + enum MHI_PM_STATE cur_state; mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Entered with State %s\n", TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state)); @@ -285,25 +489,18 @@ int process_m3_transition(struct mhi_device_ctxt *mhi_dev_ctxt) write_lock_irqsave(&mhi_dev_ctxt->pm_xfer_lock, flags); mhi_dev_ctxt->mhi_state = MHI_STATE_M3; - mhi_dev_ctxt->mhi_pm_state = MHI_PM_M3; + cur_state = mhi_tryset_pm_state(mhi_dev_ctxt, MHI_PM_M3); write_unlock_irqrestore(&mhi_dev_ctxt->pm_xfer_lock, flags); + if (unlikely(cur_state != MHI_PM_M3)) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Failed to transition to state 0x%x from 0x%x\n", + MHI_PM_M3, cur_state); + return -EIO; + } wake_up(mhi_dev_ctxt->mhi_ev_wq.m3_event); return 0; } -static int process_bhi_transition( - struct mhi_device_ctxt *mhi_dev_ctxt, - enum STATE_TRANSITION cur_work_item) -{ - mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Entered\n"); - write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); - mhi_dev_ctxt->mhi_state = MHI_STATE_BHI; - write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); - wake_up_interruptible(mhi_dev_ctxt->mhi_ev_wq.bhi_event); - mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exited\n"); - return 0; -} - static int process_ready_transition( struct mhi_device_ctxt *mhi_dev_ctxt, enum STATE_TRANSITION cur_work_item) @@ -313,15 +510,12 @@ static int process_ready_transition( mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Processing READY state transition\n"); - r = mhi_reset_all_thread_queues(mhi_dev_ctxt); - if (r) { - mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, - "Failed to reset thread queues\n"); - return r; - } - write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); mhi_dev_ctxt->mhi_state = MHI_STATE_READY; + if (!MHI_REG_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state)) { + write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); + return -EIO; + } r = mhi_init_mmio(mhi_dev_ctxt); write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); /* Initialize MMIO */ @@ -341,6 +535,10 @@ static int process_ready_transition( } write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); + if (!MHI_REG_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state)) { + write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); + return -EIO; + } mhi_reg_write_field(mhi_dev_ctxt, mhi_dev_ctxt->mmio_info.mmio_addr, MHICTRL, MHICTRL_MHISTATE_MASK, @@ -350,30 +548,25 @@ static int process_ready_transition( return r; } -static void mhi_reset_chan_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt, - int chan) -{ - struct mhi_chan_ctxt *chan_ctxt = - &mhi_dev_ctxt->dev_space.ring_ctxt.cc_list[chan]; - struct mhi_ring *local_chan_ctxt = - &mhi_dev_ctxt->mhi_local_chan_ctxt[chan]; - chan_ctxt->mhi_trb_read_ptr = chan_ctxt->mhi_trb_ring_base_addr; - chan_ctxt->mhi_trb_write_ptr = chan_ctxt->mhi_trb_ring_base_addr; - local_chan_ctxt->rp = local_chan_ctxt->base; - local_chan_ctxt->wp = local_chan_ctxt->base; - local_chan_ctxt->ack_rp = local_chan_ctxt->base; -} - static int process_reset_transition( struct mhi_device_ctxt *mhi_dev_ctxt, enum STATE_TRANSITION cur_work_item) { - int r = 0, i = 0; + int r = 0; + enum MHI_PM_STATE cur_state; + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Processing RESET state transition\n"); write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); mhi_dev_ctxt->mhi_state = MHI_STATE_RESET; + cur_state = mhi_tryset_pm_state(mhi_dev_ctxt, MHI_PM_POR); write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); + if (unlikely(cur_state != MHI_PM_POR)) { + mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, + "Error transitining from state:0x%x to:0x%x\n", + cur_state, MHI_PM_POR); + return -EIO; + } mhi_dev_ctxt->counters.mhi_reset_cntr++; r = mhi_test_for_device_reset(mhi_dev_ctxt); @@ -387,25 +580,6 @@ static int process_reset_transition( return r; } - for (i = 0; i < NR_OF_CMD_RINGS; ++i) { - mhi_dev_ctxt->mhi_local_cmd_ctxt[i].rp = - mhi_dev_ctxt->mhi_local_cmd_ctxt[i].base; - mhi_dev_ctxt->mhi_local_cmd_ctxt[i].wp = - mhi_dev_ctxt->mhi_local_cmd_ctxt[i].base; - mhi_dev_ctxt->dev_space.ring_ctxt.cmd_ctxt[i]. - mhi_cmd_ring_read_ptr = - mhi_v2p_addr(mhi_dev_ctxt, - MHI_RING_TYPE_CMD_RING, - i, - (uintptr_t)mhi_dev_ctxt->mhi_local_cmd_ctxt[i].rp); - } - for (i = 0; i < mhi_dev_ctxt->mmio_info.nr_event_rings; ++i) - mhi_reset_ev_ctxt(mhi_dev_ctxt, i); - - for (i = 0; i < MHI_MAX_CHANNELS; ++i) { - if (VALID_CHAN_NR(i)) - mhi_reset_chan_ctxt(mhi_dev_ctxt, i); - } r = mhi_init_state_transition(mhi_dev_ctxt, STATE_TRANSITION_READY); if (0 != r) @@ -441,19 +615,6 @@ static void enable_clients(struct mhi_device_ctxt *mhi_dev_ctxt, mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Done.\n"); } -static int process_sbl_transition( - struct mhi_device_ctxt *mhi_dev_ctxt, - enum STATE_TRANSITION cur_work_item) -{ - - mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Enabled\n"); - write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); - mhi_dev_ctxt->dev_exec_env = MHI_EXEC_ENV_SBL; - write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); - enable_clients(mhi_dev_ctxt, mhi_dev_ctxt->dev_exec_env); - return 0; -} - static int process_amss_transition( struct mhi_device_ctxt *mhi_dev_ctxt, enum STATE_TRANSITION cur_work_item) @@ -465,26 +626,19 @@ static int process_amss_transition( write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); mhi_dev_ctxt->dev_exec_env = MHI_EXEC_ENV_AMSS; write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); + mhi_dev_ctxt->flags.mhi_initialized = true; + complete(&mhi_dev_ctxt->cmd_complete); - if (!mhi_dev_ctxt->flags.mhi_initialized) { - r = mhi_add_elements_to_event_rings(mhi_dev_ctxt, + r = mhi_add_elements_to_event_rings(mhi_dev_ctxt, cur_work_item); - mhi_dev_ctxt->flags.mhi_initialized = 1; - if (r) { - mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, - "Failed to set local chan state ret %d\n", r); - mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt); - return r; - } - mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, - "Notifying clients that MHI is enabled\n"); - enable_clients(mhi_dev_ctxt, mhi_dev_ctxt->dev_exec_env); - } else { - mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, - "MHI is initialized\n"); + if (r) { + mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, + "Failed to set local chan state ret %d\n", r); + mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt); + return r; } + enable_clients(mhi_dev_ctxt, mhi_dev_ctxt->dev_exec_env); - complete(&mhi_dev_ctxt->cmd_complete); /* * runtime_allow will decrement usage_count, counts were @@ -508,7 +662,7 @@ static int process_amss_transition( return 0; } -static int process_stt_work_item( +void process_stt_work_item( struct mhi_device_ctxt *mhi_dev_ctxt, enum STATE_TRANSITION cur_work_item) { @@ -520,7 +674,10 @@ static int process_stt_work_item( trace_mhi_state(cur_work_item); switch (cur_work_item) { case STATE_TRANSITION_BHI: - r = process_bhi_transition(mhi_dev_ctxt, cur_work_item); + write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); + mhi_dev_ctxt->mhi_state = MHI_STATE_BHI; + write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); + wake_up_interruptible(mhi_dev_ctxt->mhi_ev_wq.bhi_event); break; case STATE_TRANSITION_RESET: r = process_reset_transition(mhi_dev_ctxt, cur_work_item); @@ -529,13 +686,34 @@ static int process_stt_work_item( r = process_ready_transition(mhi_dev_ctxt, cur_work_item); break; case STATE_TRANSITION_SBL: - r = process_sbl_transition(mhi_dev_ctxt, cur_work_item); + write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); + mhi_dev_ctxt->dev_exec_env = MHI_EXEC_ENV_SBL; + write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); + enable_clients(mhi_dev_ctxt, mhi_dev_ctxt->dev_exec_env); break; case STATE_TRANSITION_AMSS: r = process_amss_transition(mhi_dev_ctxt, cur_work_item); break; case STATE_TRANSITION_BHIE: - r = process_bhie_transition(mhi_dev_ctxt, cur_work_item); + write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); + mhi_dev_ctxt->dev_exec_env = MHI_EXEC_ENV_BHIE; + write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); + wake_up(mhi_dev_ctxt->mhi_ev_wq.bhi_event); + break; + case STATE_TRANSITION_RDDM: + write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock); + mhi_dev_ctxt->dev_exec_env = MHI_EXEC_ENV_RDDM; + mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt); + write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock); + complete(&mhi_dev_ctxt->cmd_complete); + + /* Notify bus master device entered rddm mode */ + if (!mhi_dev_ctxt->core.pci_master) { + mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, + "Notifying bus master RDDM Status\n"); + mhi_dev_ctxt->status_cb(MHI_CB_RDDM, + mhi_dev_ctxt->priv_data); + } break; default: mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL, @@ -543,12 +721,11 @@ static int process_stt_work_item( state_transition_str(cur_work_item)); break; } - return r; } void mhi_state_change_worker(struct work_struct *work) { - int r = 0; + int r; struct mhi_device_ctxt *mhi_dev_ctxt = container_of(work, struct mhi_device_ctxt, st_thread_worker); @@ -564,7 +741,7 @@ void mhi_state_change_worker(struct work_struct *work) MHI_ASSERT(r == 0, "Failed to delete element from STT workqueue\n"); spin_unlock_irq(work_q->q_lock); - r = process_stt_work_item(mhi_dev_ctxt, cur_work_item); + process_stt_work_item(mhi_dev_ctxt, cur_work_item); } } diff --git a/drivers/platform/msm/mhi/mhi_sys.c b/drivers/platform/msm/mhi/mhi_sys.c index 3389de2f95b3..1d9282627d4e 100644 --- a/drivers/platform/msm/mhi/mhi_sys.c +++ b/drivers/platform/msm/mhi/mhi_sys.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -35,15 +35,15 @@ module_param(mhi_ipc_log_lvl, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(mhi_ipc_log_lvl, "dbg lvl"); const char * const mhi_states_str[MHI_STATE_LIMIT] = { - "RESET", - "READY", - "M0", - "M1", - "M2", - "M3", + [MHI_STATE_RESET] = "RESET", + [MHI_STATE_READY] = "READY", + [MHI_STATE_M0] = "M0", + [MHI_STATE_M1] = "M1", + [MHI_STATE_M2] = "M2", + [MHI_STATE_M3] = "M3", "Reserved: 0x06", - "BHI", - "SYS_ERR", + [MHI_STATE_BHI] = "BHI", + [MHI_STATE_SYS_ERR] = "SYS_ERR", }; static ssize_t mhi_dbgfs_chan_read(struct file *fp, char __user *buf, diff --git a/drivers/platform/msm/mhi_uci/mhi_uci.c b/drivers/platform/msm/mhi_uci/mhi_uci.c index 0e28ebdd8fea..3191ec065a95 100644 --- a/drivers/platform/msm/mhi_uci/mhi_uci.c +++ b/drivers/platform/msm/mhi_uci/mhi_uci.c @@ -33,7 +33,6 @@ #define MHI_SOFTWARE_CLIENT_LIMIT 23 #define MHI_UCI_IPC_LOG_PAGES (25) -#define MAX_NR_TRBS_PER_CHAN 10 #define DEVICE_NAME "mhi" #define MHI_UCI_DRIVER_NAME "mhi_uci" #define CTRL_MAGIC 0x4C525443 @@ -95,33 +94,35 @@ struct chan_attr { u32 nr_trbs; enum MHI_CHAN_DIR dir; u32 uci_ownership; + bool enabled; + struct mhi_client_handle *mhi_handle; + wait_queue_head_t wq; + struct list_head buf_head; + struct mutex chan_lock; + atomic_t avail_pkts; /* no. avail tre to read or space avail for tx */ + u64 pkt_count; +}; + +struct uci_buf { + void *data; + u64 pkt_id; + struct list_head node; }; struct uci_client { - u32 out_chan; - u32 in_chan; - u32 out_chan_state; - u32 in_chan_state; struct chan_attr in_attr; struct chan_attr out_attr; - struct mhi_client_handle *out_handle; - struct mhi_client_handle *in_handle; - size_t pending_data; - wait_queue_head_t read_wq; - wait_queue_head_t write_wq; - atomic_t avail_pkts; struct device *dev; u8 local_tiocm; - atomic_t ref_count; - int mhi_status; - void *pkt_loc; + struct mutex client_lock; /* sync open and close */ + int ref_count; + struct uci_buf *cur_buf; /* current buffer read processing */ size_t pkt_size; - void **in_buf_list; + struct work_struct outbound_worker; /* clean up outbound pkts */ atomic_t out_pkt_pend_ack; - atomic_t mhi_disabled; + atomic_t completion_ack; struct mhi_uci_ctxt_t *uci_ctxt; - struct mutex in_chan_lock; - struct mutex out_chan_lock; + bool enabled; void *uci_ipc_log; }; @@ -133,8 +134,6 @@ struct mhi_uci_ctxt_t { struct mutex ctrl_mutex; struct cdev cdev[MHI_SOFTWARE_CLIENT_LIMIT]; struct uci_client *ctrl_client; - atomic_t mhi_disabled; - atomic_t mhi_enable_notif_wq_active; }; struct mhi_uci_drv_ctxt { @@ -250,6 +249,35 @@ static long mhi_uci_ctl_ioctl(struct file *file, unsigned int cmd, static struct mhi_uci_drv_ctxt mhi_uci_drv_ctxt; +static void mhi_uci_clean_acked_tre(struct work_struct *work) +{ + struct uci_client *uci_client; + int i = 0; + + uci_client = container_of(work, struct uci_client, outbound_worker); + while (atomic_read(&uci_client->completion_ack)) { + struct uci_buf *uci_buf; + + /* acquire lock per tre so we won't block other uci threads */ + mutex_lock(&uci_client->out_attr.chan_lock); + uci_buf = list_first_entry_or_null( + &uci_client->out_attr.buf_head, + struct uci_buf, node); + if (unlikely(!uci_buf)) { + mutex_unlock(&uci_client->out_attr.chan_lock); + break; + } + list_del(&uci_buf->node); + kfree(uci_buf->data); + atomic_dec(&uci_client->completion_ack); + mutex_unlock(&uci_client->out_attr.chan_lock); + i++; + } + uci_log(uci_client->uci_ipc_log, UCI_DBG_VERBOSE, + "freed %d tres for chan %d\n", + i, uci_client->out_attr.chan_id); +} + static int mhi_init_inbound(struct uci_client *client_handle) { int ret_val = 0; @@ -257,37 +285,32 @@ static int mhi_init_inbound(struct uci_client *client_handle) struct chan_attr *chan_attributes = &client_handle->in_attr; void *data_loc = NULL; size_t buf_size = chan_attributes->max_packet_size; + struct uci_buf *uci_buf; - if (client_handle == NULL) { - uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, - UCI_DBG_ERROR, - "Bad Input data, quitting\n"); - return -EINVAL; - } chan_attributes->nr_trbs = - mhi_get_free_desc(client_handle->in_handle); - client_handle->in_buf_list = - kmalloc(sizeof(void *) * chan_attributes->nr_trbs, - GFP_KERNEL); - if (!client_handle->in_buf_list) - return -ENOMEM; + mhi_get_free_desc(client_handle->in_attr.mhi_handle); uci_log(client_handle->uci_ipc_log, UCI_DBG_INFO, "Channel %d supports %d desc\n", chan_attributes->chan_id, chan_attributes->nr_trbs); for (i = 0; i < chan_attributes->nr_trbs; ++i) { - data_loc = kmalloc(buf_size, GFP_KERNEL); - uci_log(client_handle->uci_ipc_log, - UCI_DBG_INFO, - "Allocated buffer %p size %zd\n", - data_loc, - buf_size); + data_loc = kmalloc(buf_size + sizeof(*uci_buf), GFP_KERNEL); + + /* + * previously allocated memory will be freed after + * channel close + */ if (data_loc == NULL) return -ENOMEM; - client_handle->in_buf_list[i] = data_loc; - ret_val = mhi_queue_xfer(client_handle->in_handle, - data_loc, buf_size, MHI_EOT); + uci_buf = data_loc + buf_size; + uci_buf->data = data_loc; + uci_buf->pkt_id = chan_attributes->pkt_count++; + uci_log(client_handle->uci_ipc_log, UCI_DBG_INFO, + "Allocated buffer %llu size %ld for chan:%d\n", + uci_buf->pkt_id, buf_size, chan_attributes->chan_id); + ret_val = mhi_queue_xfer(client_handle->in_attr.mhi_handle, + data_loc, buf_size, MHI_EOT); if (0 != ret_val) { kfree(data_loc); uci_log(client_handle->uci_ipc_log, @@ -297,139 +320,138 @@ static int mhi_init_inbound(struct uci_client *client_handle) ret_val); break; } + list_add_tail(&uci_buf->node, &client_handle->in_attr.buf_head); } return ret_val; } static int mhi_uci_send_packet(struct mhi_client_handle **client_handle, - void *buf, u32 size, u32 is_uspace_buf) + void *buf, + u32 size) { u32 nr_avail_trbs = 0; u32 i = 0; void *data_loc = NULL; - uintptr_t memcpy_result = 0; + unsigned long memcpy_result = 0; int data_left_to_insert = 0; size_t data_to_insert_now = 0; u32 data_inserted_so_far = 0; int ret_val = 0; - enum MHI_FLAGS flags; struct uci_client *uci_handle; - uci_handle = container_of(client_handle, struct uci_client, - out_handle); + struct uci_buf *uci_buf; - if (client_handle == NULL || buf == NULL || - !size || uci_handle == NULL) - return -EINVAL; - - nr_avail_trbs = mhi_get_free_desc(*client_handle); + uci_handle = container_of(client_handle, struct uci_client, + out_attr.mhi_handle); + nr_avail_trbs = atomic_read(&uci_handle->out_attr.avail_pkts); data_left_to_insert = size; - if (0 == nr_avail_trbs) - return 0; - for (i = 0; i < nr_avail_trbs; ++i) { data_to_insert_now = min_t(size_t, data_left_to_insert, uci_handle->out_attr.max_packet_size); - if (is_uspace_buf) { - data_loc = kmalloc(data_to_insert_now, GFP_KERNEL); - if (NULL == data_loc) { - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_VERBOSE, - "Failed to allocate memory 0x%zx\n", - data_to_insert_now); + data_loc = kmalloc(data_to_insert_now + sizeof(*uci_buf), + GFP_KERNEL); + if (!data_loc) { + uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE, + "Failed to allocate memory 0x%zx\n", + data_to_insert_now); return -ENOMEM; - } - memcpy_result = copy_from_user(data_loc, - buf + data_inserted_so_far, - data_to_insert_now); - - if (0 != memcpy_result) - goto error_memcpy; - } else { - data_loc = buf; } - - flags = MHI_EOT; - if (data_left_to_insert - data_to_insert_now > 0) - flags |= MHI_CHAIN | MHI_EOB; - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_VERBOSE, - "At trb i = %d/%d, chain = %d, eob = %d, addr 0x%p chan %d\n", - i, - nr_avail_trbs, - flags & MHI_CHAIN, - flags & MHI_EOB, - data_loc, - uci_handle->out_chan); - ret_val = mhi_queue_xfer(*client_handle, data_loc, - data_to_insert_now, flags); - - if (0 != ret_val) { - goto error_queue; + uci_buf = data_loc + data_to_insert_now; + uci_buf->data = data_loc; + uci_buf->pkt_id = uci_handle->out_attr.pkt_count++; + memcpy_result = copy_from_user(uci_buf->data, + buf + data_inserted_so_far, + data_to_insert_now); + if (memcpy_result) + goto error_xfer; + + uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE, + "At trb i = %d/%d, size = %lu, id %llu chan %d\n", + i, nr_avail_trbs, data_to_insert_now, uci_buf->pkt_id, + uci_handle->out_attr.chan_id); + ret_val = mhi_queue_xfer(*client_handle, uci_buf->data, + data_to_insert_now, MHI_EOT); + if (ret_val) { + goto error_xfer; } else { data_left_to_insert -= data_to_insert_now; data_inserted_so_far += data_to_insert_now; atomic_inc(&uci_handle->out_pkt_pend_ack); + atomic_dec(&uci_handle->out_attr.avail_pkts); + list_add_tail(&uci_buf->node, + &uci_handle->out_attr.buf_head); } - if (0 == data_left_to_insert) + if (!data_left_to_insert) break; } return data_inserted_so_far; -error_queue: -error_memcpy: - kfree(data_loc); +error_xfer: + kfree(uci_buf->data); return data_inserted_so_far; } static int mhi_uci_send_status_cmd(struct uci_client *client) { + void *buf = NULL; struct rs232_ctrl_msg *rs232_pkt = NULL; + struct uci_buf *uci_buf = NULL; struct uci_client *uci_ctrl_handle; struct mhi_uci_ctxt_t *uci_ctxt = client->uci_ctxt; int ret_val = 0; - size_t pkt_size = sizeof(struct rs232_ctrl_msg); - u32 amount_sent; if (!uci_ctxt->ctrl_client) { - uci_log(client->uci_ipc_log, - UCI_DBG_INFO, + uci_log(client->uci_ipc_log, UCI_DBG_INFO, "Control channel is not defined\n"); return -EIO; } uci_ctrl_handle = uci_ctxt->ctrl_client; - mutex_lock(&uci_ctrl_handle->out_chan_lock); + mutex_lock(&uci_ctrl_handle->out_attr.chan_lock); - if (!atomic_read(&uci_ctrl_handle->mhi_disabled) && - !uci_ctrl_handle->out_chan_state) { - uci_log(uci_ctrl_handle->uci_ipc_log, - UCI_DBG_INFO, + if (!uci_ctrl_handle->enabled) { + uci_log(uci_ctrl_handle->uci_ipc_log, UCI_DBG_INFO, "Opening outbound control channel %d for chan:%d\n", - uci_ctrl_handle->out_chan, - client->out_chan); - ret_val = mhi_open_channel(uci_ctrl_handle->out_handle); - if (0 != ret_val) { - uci_log(uci_ctrl_handle->uci_ipc_log, - UCI_DBG_CRITICAL, + uci_ctrl_handle->out_attr.chan_id, + client->out_attr.chan_id); + if (!uci_ctrl_handle->out_attr.enabled) { + uci_log(uci_ctrl_handle->uci_ipc_log, UCI_DBG_CRITICAL, + "Channel %d is not enable\n", + uci_ctrl_handle->out_attr.chan_id); + ret_val = -EIO; + goto error_open; + } + ret_val = mhi_open_channel(uci_ctrl_handle-> + out_attr.mhi_handle); + if (ret_val) { + uci_log(uci_ctrl_handle->uci_ipc_log, UCI_DBG_CRITICAL, "Could not open chan %d, for sideband ctrl\n", - uci_ctrl_handle->out_chan); + uci_ctrl_handle->out_attr.chan_id); ret_val = -EIO; goto error_open; } - uci_ctrl_handle->out_chan_state = 1; + uci_ctrl_handle->enabled = true; + } + + if (mhi_get_free_desc(uci_ctrl_handle->out_attr.mhi_handle) <= 0) { + ret_val = -EIO; + goto error_open; } - rs232_pkt = kzalloc(sizeof(struct rs232_ctrl_msg), GFP_KERNEL); - if (rs232_pkt == NULL) { + buf = kzalloc(sizeof(*rs232_pkt) + sizeof(*uci_buf), GFP_KERNEL); + if (!buf) { ret_val = -ENOMEM; goto error_open; } - uci_log(uci_ctrl_handle->uci_ipc_log, - UCI_DBG_VERBOSE, + + + uci_log(uci_ctrl_handle->uci_ipc_log, UCI_DBG_VERBOSE, "Received request to send msg for chan %d\n", - client->out_chan); + client->out_attr.chan_id); + uci_buf = buf + sizeof(*rs232_pkt); + uci_buf->data = buf; + rs232_pkt = (struct rs232_ctrl_msg *)uci_buf->data; rs232_pkt->preamble = CTRL_MAGIC; if (client->local_tiocm & TIOCM_DTR) MHI_SET_CTRL_MSG(CTRL_MSG_DTR, rs232_pkt, 1); @@ -438,26 +460,27 @@ static int mhi_uci_send_status_cmd(struct uci_client *client) MHI_SET_CTRL_MSG_ID(CTRL_MSG_ID, rs232_pkt, MHI_CTRL_LINE_STATE_ID); MHI_SET_CTRL_MSG_SIZE(CTRL_MSG_SIZE, rs232_pkt, sizeof(u32)); - MHI_SET_CTRL_DEST_ID(CTRL_DEST_ID, rs232_pkt, client->out_chan); - - amount_sent = mhi_uci_send_packet(&uci_ctrl_handle->out_handle, - rs232_pkt, - pkt_size, 0); + MHI_SET_CTRL_DEST_ID(CTRL_DEST_ID, rs232_pkt, client->out_attr.chan_id); - if (pkt_size != amount_sent) { - uci_log(uci_ctrl_handle->uci_ipc_log, - UCI_DBG_INFO, + ret_val = mhi_queue_xfer(uci_ctrl_handle->out_attr.mhi_handle, + uci_buf->data, sizeof(*rs232_pkt), MHI_EOT); + if (ret_val) { + uci_log(uci_ctrl_handle->uci_ipc_log, UCI_DBG_INFO, "Failed to send signal for chan %d, ret : %d\n", - client->out_chan, - ret_val); - goto error; + client->out_attr.chan_id, ret_val); + goto error_queue; } -error_open: - mutex_unlock(&uci_ctrl_handle->out_chan_lock); + list_add_tail(&uci_buf->node, &uci_ctrl_handle->out_attr.buf_head); + + mutex_unlock(&uci_ctrl_handle->out_attr.chan_lock); + return 0; + + mutex_unlock(&uci_ctrl_handle->out_attr.chan_lock); return ret_val; -error: - kfree(rs232_pkt); - mutex_unlock(&uci_ctrl_handle->out_chan_lock); +error_queue: + kfree(buf); +error_open: + mutex_unlock(&uci_ctrl_handle->out_attr.chan_lock); return ret_val; } @@ -466,6 +489,7 @@ static int mhi_uci_tiocm_set(struct uci_client *client_ctxt, u32 set, u32 clear) u8 status_set = 0; u8 status_clear = 0; u8 old_status = 0; + int ret = 0; mutex_lock(&client_ctxt->uci_ctxt->ctrl_mutex); @@ -475,23 +499,21 @@ static int mhi_uci_tiocm_set(struct uci_client *client_ctxt, u32 set, u32 clear) client_ctxt->local_tiocm |= status_set; client_ctxt->local_tiocm &= ~status_clear; - uci_log(client_ctxt->uci_ipc_log, - UCI_DBG_VERBOSE, + uci_log(client_ctxt->uci_ipc_log, UCI_DBG_VERBOSE, "Old TIOCM0x%x for chan %d, Current TIOCM 0x%x\n", - old_status, - client_ctxt->out_chan, + old_status, client_ctxt->out_attr.chan_id, client_ctxt->local_tiocm); - mutex_unlock(&client_ctxt->uci_ctxt->ctrl_mutex); if (client_ctxt->local_tiocm != old_status) { - uci_log(client_ctxt->uci_ipc_log, - UCI_DBG_VERBOSE, + uci_log(client_ctxt->uci_ipc_log, UCI_DBG_VERBOSE, "Setting TIOCM to 0x%x for chan %d\n", client_ctxt->local_tiocm, - client_ctxt->out_chan); - return mhi_uci_send_status_cmd(client_ctxt); + client_ctxt->out_attr.chan_id); + ret = mhi_uci_send_status_cmd(client_ctxt); } - return 0; + + mutex_unlock(&client_ctxt->uci_ctxt->ctrl_mutex); + return ret; } static long mhi_uci_ctl_ioctl(struct file *file, unsigned int cmd, @@ -503,35 +525,26 @@ static long mhi_uci_ctl_ioctl(struct file *file, unsigned int cmd, uci_handle = file->private_data; if (uci_handle == NULL) { - uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, - UCI_DBG_VERBOSE, + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_VERBOSE, "Invalid handle for client\n"); return -ENODEV; } - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_VERBOSE, + uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE, "Attempting to dtr cmd 0x%x arg 0x%lx for chan %d\n", - cmd, - arg, - uci_handle->out_chan); + cmd, arg, uci_handle->out_attr.chan_id); switch (cmd) { case TIOCMGET: - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_VERBOSE, - "Returning 0x%x mask\n", - uci_handle->local_tiocm); + uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE, + "Returning 0x%x mask\n", uci_handle->local_tiocm); ret_val = uci_handle->local_tiocm; break; case TIOCMSET: if (0 != copy_from_user(&set_val, (void *)arg, sizeof(set_val))) return -ENOMEM; - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_VERBOSE, + uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE, "Attempting to set cmd 0x%x arg 0x%x for chan %d\n", - cmd, - set_val, - uci_handle->out_chan); + cmd, set_val, uci_handle->out_attr.chan_id); ret_val = mhi_uci_tiocm_set(uci_handle, set_val, ~set_val); break; default: @@ -551,29 +564,32 @@ static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait) return -ENODEV; uci_ctxt = uci_handle->uci_ctxt; - poll_wait(file, &uci_handle->read_wq, wait); - poll_wait(file, &uci_handle->write_wq, wait); - if (atomic_read(&uci_handle->avail_pkts) > 0) { - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_VERBOSE, + poll_wait(file, &uci_handle->in_attr.wq, wait); + poll_wait(file, &uci_handle->out_attr.wq, wait); + mutex_lock(&uci_handle->in_attr.chan_lock); + if (!uci_handle->in_attr.enabled || !uci_handle->enabled) + mask = POLLERR; + else if (atomic_read(&uci_handle->in_attr.avail_pkts) || + uci_handle->cur_buf) { + uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE, "Client can read chan %d\n", - uci_handle->in_chan); + uci_handle->in_attr.chan_id); mask |= POLLIN | POLLRDNORM; } - if (!atomic_read(&uci_ctxt->mhi_disabled) && - (mhi_get_free_desc(uci_handle->out_handle) > 0)) { - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_VERBOSE, + mutex_unlock(&uci_handle->in_attr.chan_lock); + mutex_lock(&uci_handle->out_attr.chan_lock); + if (!uci_handle->out_attr.enabled || !uci_handle->enabled) + mask |= POLLERR; + else if (atomic_read(&uci_handle->out_attr.avail_pkts) > 0) { + uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE, "Client can write chan %d\n", - uci_handle->out_chan); + uci_handle->out_attr.chan_id); mask |= POLLOUT | POLLWRNORM; } - - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_VERBOSE, + mutex_unlock(&uci_handle->out_attr.chan_lock); + uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE, "Client attempted to poll chan %d, returning mask 0x%x\n", - uci_handle->in_chan, - mask); + uci_handle->in_attr.chan_id, mask); return mask; } @@ -581,66 +597,67 @@ static int open_client_mhi_channels(struct uci_client *uci_client) { int ret_val = 0; int r = 0; + struct uci_buf *itr, *tmp; - uci_log(uci_client->uci_ipc_log, - UCI_DBG_INFO, + uci_log(uci_client->uci_ipc_log, UCI_DBG_INFO, "Starting channels %d %d\n", - uci_client->out_chan, - uci_client->in_chan); - mutex_lock(&uci_client->out_chan_lock); - mutex_lock(&uci_client->in_chan_lock); - ret_val = mhi_open_channel(uci_client->out_handle); + uci_client->out_attr.chan_id, + uci_client->in_attr.chan_id); + + ret_val = mhi_open_channel(uci_client->out_attr.mhi_handle); if (ret_val != 0) { if (ret_val == -ENOTCONN) - r = -EAGAIN; + return -EAGAIN; else - r = -EIO; - goto handle_not_rdy_err; + return -EIO; } - uci_client->out_chan_state = 1; + ret_val = mhi_get_free_desc(uci_client->out_attr.mhi_handle); + if (ret_val >= 0) + atomic_set(&uci_client->out_attr.avail_pkts, ret_val); - ret_val = mhi_open_channel(uci_client->in_handle); + ret_val = mhi_open_channel(uci_client->in_attr.mhi_handle); if (ret_val != 0) { - uci_log(uci_client->uci_ipc_log, - UCI_DBG_ERROR, + uci_log(uci_client->uci_ipc_log, UCI_DBG_ERROR, "Failed to open chan %d, ret 0x%x\n", - uci_client->out_chan, - ret_val); - goto handle_in_err; + uci_client->out_attr.chan_id, ret_val); + goto error_inbound_open; } - uci_log(uci_client->uci_ipc_log, - UCI_DBG_INFO, + uci_log(uci_client->uci_ipc_log, UCI_DBG_INFO, "Initializing inbound chan %d\n", - uci_client->in_chan); - uci_client->in_chan_state = 1; + uci_client->in_attr.chan_id); ret_val = mhi_init_inbound(uci_client); if (0 != ret_val) { - uci_log(uci_client->uci_ipc_log, - UCI_DBG_ERROR, + uci_log(uci_client->uci_ipc_log, UCI_DBG_ERROR, "Failed to init inbound 0x%x, ret 0x%x\n", - uci_client->in_chan, - ret_val); - } + uci_client->in_attr.chan_id, ret_val); + goto error_init_inbound; - mutex_unlock(&uci_client->in_chan_lock); - mutex_unlock(&uci_client->out_chan_lock); + } + atomic_set(&uci_client->completion_ack, 0); + uci_client->enabled = true; return 0; -handle_in_err: - mhi_close_channel(uci_client->out_handle); - uci_client->out_chan_state = 0; -handle_not_rdy_err: - mutex_unlock(&uci_client->in_chan_lock); - mutex_unlock(&uci_client->out_chan_lock); +error_init_inbound: + mhi_close_channel(uci_client->in_attr.mhi_handle); + list_for_each_entry_safe(itr, tmp, &uci_client->in_attr.buf_head, + node) { + list_del(&itr->node); + kfree(itr->data); + } + INIT_LIST_HEAD(&uci_client->in_attr.buf_head); + +error_inbound_open: + mhi_close_channel(uci_client->out_attr.mhi_handle); return r; } static int mhi_uci_client_open(struct inode *inode, - struct file *file_handle) + struct file *file_handle) { struct uci_client *uci_handle = NULL; struct mhi_uci_ctxt_t *uci_ctxt = NULL, *itr; + const long timeout = msecs_to_jiffies(1000); int r = 0; int client_id = iminor(inode); int major = imajor(inode); @@ -654,100 +671,136 @@ static int mhi_uci_client_open(struct inode *inode, } } mutex_unlock(&mhi_uci_drv_ctxt.list_lock); + if (!uci_ctxt || client_id >= MHI_SOFTWARE_CLIENT_LIMIT) return -EINVAL; uci_handle = &uci_ctxt->client_handles[client_id]; - if (atomic_read(&uci_handle->mhi_disabled)) { - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_INFO, + r = wait_event_interruptible_timeout(uci_handle->out_attr.wq, + uci_handle->out_attr.enabled, + timeout); + if (r < 0) + return -EAGAIN; + r = wait_event_interruptible_timeout(uci_handle->in_attr.wq, + uci_handle->in_attr.enabled, + timeout); + if (r < 0) + return -EAGAIN; + r = 0; + mutex_lock(&uci_handle->client_lock); + mutex_lock(&uci_handle->out_attr.chan_lock); + mutex_lock(&uci_handle->in_attr.chan_lock); + if (!uci_handle->out_attr.enabled || !uci_handle->in_attr.enabled) { + uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO, "MHI channel still disable for, client %d\n", client_id); - msleep(500); + mutex_unlock(&uci_handle->in_attr.chan_lock); + mutex_unlock(&uci_handle->out_attr.chan_lock); + mutex_unlock(&uci_handle->client_lock); return -EAGAIN; } - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_INFO, + uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO, "Client opened device node 0x%x, ref count 0x%x\n", - client_id, - atomic_read(&uci_handle->ref_count)); + client_id, uci_handle->ref_count); - if (1 == atomic_add_return(1, &uci_handle->ref_count)) { - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_INFO, - "Opening channels client %d\n", + if (++uci_handle->ref_count == 1) { + uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO, + "Opening channels client %d for first time\n", client_id); r = open_client_mhi_channels(uci_handle); - if (r) - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_INFO, - "Failed to open channels ret %d\n", - r); + if (r) { + uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO, + "Failed to open channels ret %d\n", r); + uci_handle->ref_count--; + } } + mutex_unlock(&uci_handle->in_attr.chan_lock); + mutex_unlock(&uci_handle->out_attr.chan_lock); + mutex_unlock(&uci_handle->client_lock); file_handle->private_data = uci_handle; return r; } static int mhi_uci_client_release(struct inode *mhi_inode, - struct file *file_handle) + struct file *file_handle) { struct uci_client *uci_handle = file_handle->private_data; u32 nr_in_bufs = 0; int in_chan = 0; - int i = 0; u32 buf_size = 0; - if (uci_handle == NULL) - return -EINVAL; - + mutex_lock(&uci_handle->client_lock); in_chan = uci_handle->in_attr.chan_id; nr_in_bufs = uci_handle->in_attr.nr_trbs; buf_size = uci_handle->in_attr.max_packet_size; + uci_handle->ref_count--; + if (!uci_handle->ref_count) { + struct uci_buf *itr, *tmp; - if (atomic_sub_return(1, &uci_handle->ref_count) == 0) { - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_ERROR, + uci_log(uci_handle->uci_ipc_log, UCI_DBG_ERROR, "Last client left, closing channel 0x%x\n", in_chan); + mutex_lock(&uci_handle->in_attr.chan_lock); + mutex_lock(&uci_handle->out_attr.chan_lock); + if (atomic_read(&uci_handle->out_pkt_pend_ack)) - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_CRITICAL, + uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO, "Still waiting on %d acks!, chan %d\n", atomic_read(&uci_handle->out_pkt_pend_ack), uci_handle->out_attr.chan_id); - mhi_close_channel(uci_handle->out_handle); - mhi_close_channel(uci_handle->in_handle); - uci_handle->out_chan_state = 0; - uci_handle->in_chan_state = 0; + atomic_set(&uci_handle->in_attr.avail_pkts, 0); + if (uci_handle->in_attr.enabled) + mhi_close_channel(uci_handle->in_attr.mhi_handle); + list_for_each_entry_safe(itr, tmp, + &uci_handle->in_attr.buf_head, node) { + list_del(&itr->node); + kfree(itr->data); + } + if (uci_handle->cur_buf) + kfree(uci_handle->cur_buf->data); + uci_handle->cur_buf = NULL; + INIT_LIST_HEAD(&uci_handle->in_attr.buf_head); + atomic_set(&uci_handle->out_attr.avail_pkts, 0); atomic_set(&uci_handle->out_pkt_pend_ack, 0); - for (i = 0; i < nr_in_bufs; ++i) { - kfree((void *)uci_handle->in_buf_list[i]); + if (uci_handle->out_attr.enabled) + mhi_close_channel(uci_handle->out_attr.mhi_handle); + list_for_each_entry_safe(itr, tmp, + &uci_handle->out_attr.buf_head, node) { + list_del(&itr->node); + kfree(itr->data); } - kfree(uci_handle->in_buf_list); - atomic_set(&uci_handle->avail_pkts, 0); + INIT_LIST_HEAD(&uci_handle->out_attr.buf_head); + uci_handle->enabled = false; + mutex_unlock(&uci_handle->out_attr.chan_lock); + flush_work(&uci_handle->outbound_worker); + atomic_set(&uci_handle->completion_ack, 0); + mutex_unlock(&uci_handle->in_attr.chan_lock); } else { - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_ERROR, + uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO, "Client close chan %d, ref count 0x%x\n", iminor(mhi_inode), - atomic_read(&uci_handle->ref_count)); + uci_handle->ref_count); } + mutex_unlock(&uci_handle->client_lock); + return 0; } -static ssize_t mhi_uci_client_read(struct file *file, char __user *buf, - size_t uspace_buf_size, loff_t *bytes_pending) +static ssize_t mhi_uci_client_read(struct file *file, + char __user *buf, + size_t uspace_buf_size, + loff_t *bytes_pending) { struct uci_client *uci_handle = NULL; struct mhi_client_handle *client_handle = NULL; int ret_val = 0; size_t buf_size = 0; - struct mutex *mutex; + struct mutex *chan_lock; u32 chan = 0; - ssize_t bytes_copied = 0; + size_t bytes_copied = 0; u32 addr_offset = 0; struct mhi_result result; @@ -756,213 +809,194 @@ static ssize_t mhi_uci_client_read(struct file *file, char __user *buf, return -EINVAL; uci_handle = file->private_data; - client_handle = uci_handle->in_handle; - mutex = &uci_handle->in_chan_lock; - chan = uci_handle->in_chan; - mutex_lock(mutex); + client_handle = uci_handle->in_attr.mhi_handle; + chan_lock = &uci_handle->in_attr.chan_lock; + chan = uci_handle->in_attr.chan_id; buf_size = uci_handle->in_attr.max_packet_size; result.buf_addr = NULL; - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_VERBOSE, - "Client attempted read on chan %d\n", - chan); - do { - if (!uci_handle->pkt_loc && - !atomic_read(&uci_handle->uci_ctxt->mhi_disabled)) { - ret_val = mhi_poll_inbound(client_handle, &result); - if (ret_val) { - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_ERROR, - "Failed to poll inbound ret %d avail pkt %d\n", - ret_val, - atomic_read(&uci_handle->avail_pkts)); - } - if (result.buf_addr) - uci_handle->pkt_loc = result.buf_addr; - else - uci_handle->pkt_loc = 0; - uci_handle->pkt_size = result.bytes_xferd; - *bytes_pending = uci_handle->pkt_size; - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_VERBOSE, - "Got pkt size 0x%zx at addr 0x%lx, chan %d\n", - uci_handle->pkt_size, - (uintptr_t)result.buf_addr, - chan); + uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE, + "Client attempted read on chan %d\n", chan); + + mutex_lock(chan_lock); + + /* confirm channel is active */ + if (!uci_handle->in_attr.enabled || !uci_handle->enabled) { + uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO, + "chan:%d is disabled\n", chan); + ret_val = -ERESTARTSYS; + goto read_error; + } + + /* No data available to read, wait */ + if (!uci_handle->cur_buf && + !atomic_read(&uci_handle->in_attr.avail_pkts)) { + uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO, + "No data available to read for chan:%d waiting\n", + chan); + mutex_unlock(chan_lock); + ret_val = wait_event_interruptible(uci_handle->in_attr.wq, + (atomic_read(&uci_handle->in_attr.avail_pkts) || + !uci_handle->in_attr.enabled)); + mutex_lock(chan_lock); + if (ret_val == -ERESTARTSYS) { + uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO, + "Exit signal caught for chan:%d\n", chan); + goto read_error; + } - if ((*bytes_pending == 0 || uci_handle->pkt_loc == 0) && - (atomic_read(&uci_handle->avail_pkts) <= 0)) { - /* If nothing was copied yet, wait for data */ - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_VERBOSE, - "No data avail_pkts %d, chan %d\n", - atomic_read(&uci_handle->avail_pkts), - chan); - ret_val = wait_event_interruptible( - uci_handle->read_wq, - (atomic_read(&uci_handle->avail_pkts) > 0)); - if (ret_val == -ERESTARTSYS) { - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_ERROR, - "Exit signal caught\n"); - goto error; - } - /* A pending reset exists */ - } else if ((atomic_read(&uci_handle->avail_pkts) > 0) && - 0 == uci_handle->pkt_size && - 0 == uci_handle->pkt_loc && - uci_handle->mhi_status == -ENETRESET) { - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_ERROR, - "Detected pending reset, reporting chan %d\n", - chan); - atomic_dec(&uci_handle->avail_pkts); - uci_handle->mhi_status = 0; - mutex_unlock(mutex); - return -ENETRESET; - /* A valid packet was returned from MHI */ - } else if (atomic_read(&uci_handle->avail_pkts) && - uci_handle->pkt_size != 0 && - uci_handle->pkt_loc != 0) { - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_VERBOSE, - "Got packet: avail pkts %d phy_adr 0x%p, chan %d\n", - atomic_read(&uci_handle->avail_pkts), - result.buf_addr, - chan); - break; - /* - * MHI did not return a valid packet, but we have one - * which we did not finish returning to user - */ - } else { - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_CRITICAL, - "chan %d err: avail pkts %d mhi_stat%d\n", - chan, - atomic_read(&uci_handle->avail_pkts), - uci_handle->mhi_status); - return -EIO; + if (!uci_handle->in_attr.enabled || !uci_handle->enabled) { + uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO, + "chan:%d is disabled\n", chan); + ret_val = -ERESTARTSYS; + goto read_error; } - } while (!uci_handle->pkt_loc); + } - if (uspace_buf_size >= *bytes_pending) { - addr_offset = uci_handle->pkt_size - *bytes_pending; - if (0 != copy_to_user(buf, - uci_handle->pkt_loc + addr_offset, - *bytes_pending)) { + /* new read, get the data from MHI */ + if (!uci_handle->cur_buf) { + struct uci_buf *cur_buf; + + ret_val = mhi_poll_inbound(client_handle, &result); + if (unlikely(ret_val || !result.buf_addr)) { + uci_log(uci_handle->uci_ipc_log, UCI_DBG_ERROR, + "Failed to poll inbound ret %d avail_pkt %d\n", + ret_val, + atomic_read(&uci_handle->in_attr.avail_pkts)); + goto read_error; + } + cur_buf = list_first_entry_or_null( + &uci_handle->in_attr.buf_head, + struct uci_buf, node); + if (unlikely(!cur_buf)) { + uci_log(uci_handle->uci_ipc_log, UCI_DBG_ERROR, + "Received completion cb but no packets queued, avail_pkt:%d\n", + atomic_read(&uci_handle->in_attr.avail_pkts)); ret_val = -EIO; - goto error; + goto read_error; } - bytes_copied = *bytes_pending; - *bytes_pending = 0; - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_VERBOSE, - "Copied 0x%zx of 0x%x, chan %d\n", - bytes_copied, - (u32)*bytes_pending, - chan); - } else { - addr_offset = uci_handle->pkt_size - *bytes_pending; - if (copy_to_user(buf, - (void *)(uintptr_t)uci_handle->pkt_loc + - addr_offset, - uspace_buf_size) != 0) { + if (unlikely(cur_buf->data != result.buf_addr)) { + uci_log(uci_handle->uci_ipc_log, UCI_DBG_ERROR, + "Receive out of order packet id:%llu\n", + cur_buf->pkt_id); ret_val = -EIO; - goto error; + goto read_error; } - bytes_copied = uspace_buf_size; - *bytes_pending -= uspace_buf_size; - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_VERBOSE, - "Copied 0x%zx of 0x%x,chan %d\n", - bytes_copied, - (u32)*bytes_pending, - chan); + + list_del(&cur_buf->node); + uci_handle->cur_buf = cur_buf; + *bytes_pending = result.bytes_xferd; + uci_handle->pkt_size = result.bytes_xferd; + atomic_dec(&uci_handle->in_attr.avail_pkts); + uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE, + "Got pkt @ %llu size:%llu for chan:%d\n", + uci_handle->cur_buf->pkt_id, *bytes_pending, chan); } + + /* Copy the buffer to user space */ + bytes_copied = min_t(size_t, uspace_buf_size, *bytes_pending); + addr_offset = uci_handle->pkt_size - *bytes_pending; + ret_val = copy_to_user(buf, uci_handle->cur_buf->data + addr_offset, + bytes_copied); + if (ret_val != 0) + goto read_error; + uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE, + "Copied %lu of %llu bytes for chan:%d\n", + bytes_copied, *bytes_pending, chan); + *bytes_pending -= bytes_copied; + /* We finished with this buffer, map it back */ if (*bytes_pending == 0) { - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_VERBOSE, - "Pkt loc %p ,chan %d\n", - uci_handle->pkt_loc, - chan); - memset(uci_handle->pkt_loc, 0, buf_size); - atomic_dec(&uci_handle->avail_pkts); - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_VERBOSE, - "Decremented avail pkts avail 0x%x\n", - atomic_read(&uci_handle->avail_pkts)); - ret_val = mhi_queue_xfer(client_handle, uci_handle->pkt_loc, + struct uci_buf *uci_buf = uci_handle->cur_buf; + + uci_handle->cur_buf = NULL; + uci_buf->pkt_id = uci_handle->in_attr.pkt_count++; + memset(uci_buf->data, 0xdeadbeef, buf_size); + ret_val = mhi_queue_xfer(client_handle, uci_buf->data, buf_size, MHI_EOT); if (0 != ret_val) { - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_ERROR, + uci_log(uci_handle->uci_ipc_log, UCI_DBG_ERROR, "Failed to recycle element\n"); - ret_val = -EIO; - goto error; + kfree(uci_buf->data); + goto read_error; } - uci_handle->pkt_loc = 0; + list_add_tail(&uci_buf->node, &uci_handle->in_attr.buf_head); } - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_VERBOSE, - "Returning 0x%zx bytes, 0x%x bytes left\n", - bytes_copied, - (u32)*bytes_pending); - mutex_unlock(mutex); + uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE, + "Returning %lu bytes, %llu bytes left\n", + bytes_copied, *bytes_pending); + mutex_unlock(chan_lock); return bytes_copied; -error: - mutex_unlock(mutex); - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_ERROR, - "Returning %d\n", - ret_val); + +read_error: + mutex_unlock(chan_lock); return ret_val; } static ssize_t mhi_uci_client_write(struct file *file, - const char __user *buf, - size_t count, loff_t *offp) + const char __user *buf, + size_t count, + loff_t *offp) { struct uci_client *uci_handle = NULL; + struct chan_attr *chan_attr; + size_t bytes_transferrd = 0; int ret_val = 0; u32 chan = 0xFFFFFFFF; - if (file == NULL || buf == NULL || - !count || file->private_data == NULL) + if (file == NULL || buf == NULL || !count || + file->private_data == NULL) return -EINVAL; else uci_handle = file->private_data; - chan = uci_handle->out_chan; - mutex_lock(&uci_handle->out_chan_lock); - - while (ret_val == 0) { - ret_val = mhi_uci_send_packet(&uci_handle->out_handle, - (void *)buf, count, 1); - if (!ret_val) { - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_VERBOSE, - "No descriptors available, did we poll, chan %d?\n", - chan); - mutex_unlock(&uci_handle->out_chan_lock); - ret_val = - wait_event_interruptible( - uci_handle->write_wq, - mhi_get_free_desc(uci_handle->out_handle) > 0); - mutex_lock(&uci_handle->out_chan_lock); - if (-ERESTARTSYS == ret_val) { - goto sys_interrupt; - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_WARNING, - "Waitqueue cancelled by system\n"); - } + chan_attr = &uci_handle->out_attr; + chan = chan_attr->chan_id; + mutex_lock(&chan_attr->chan_lock); + + if (!chan_attr->enabled || !uci_handle->enabled) { + uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO, + "Link is disabled\n"); + ret_val = -ERESTARTSYS; + goto sys_interrupt; + } + + while (bytes_transferrd != count) { + ret_val = mhi_uci_send_packet(&chan_attr->mhi_handle, + (void *)buf, count); + if (ret_val < 0) + goto sys_interrupt; + + bytes_transferrd += ret_val; + if (bytes_transferrd == count) + break; + uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE, + "No descriptors available, did we poll, chan %d?\n", + chan); + mutex_unlock(&chan_attr->chan_lock); + ret_val = wait_event_interruptible(chan_attr->wq, + (atomic_read(&chan_attr->avail_pkts) || + !chan_attr->enabled)); + mutex_lock(&chan_attr->chan_lock); + if (-ERESTARTSYS == ret_val) { + uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO, + "Waitqueue cancelled by system\n"); + goto sys_interrupt; + } + if (!chan_attr->enabled || !uci_handle->enabled) { + uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO, + "Link is disabled\n"); + ret_val = -ERESTARTSYS; + goto sys_interrupt; } } + + mutex_unlock(&chan_attr->chan_lock); + return bytes_transferrd; + sys_interrupt: - mutex_unlock(&uci_handle->out_chan_lock); + mutex_unlock(&chan_attr->chan_lock); return ret_val; } @@ -1022,7 +1056,12 @@ static int uci_init_client_attributes(struct mhi_uci_ctxt_t *uci_ctxt, if (chan_attrib->chan_id == ctrl_chan) uci_ctxt->ctrl_client = client; + + INIT_LIST_HEAD(&chan_attrib->buf_head); + mutex_init(&chan_attrib->chan_lock); + atomic_set(&chan_attrib->avail_pkts, 0); } + INIT_WORK(&client->outbound_worker, mhi_uci_clean_acked_tre); } error_dts: @@ -1030,35 +1069,6 @@ error_dts: return ret_val; } -static int process_mhi_disabled_notif_sync(struct uci_client *uci_handle) -{ - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_INFO, - "Entered.\n"); - if (uci_handle->mhi_status != -ENETRESET) { - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_CRITICAL, - "Setting reset for chan %d\n", - uci_handle->out_chan); - uci_handle->pkt_size = 0; - uci_handle->pkt_loc = NULL; - uci_handle->mhi_status = -ENETRESET; - atomic_set(&uci_handle->avail_pkts, 1); - mhi_close_channel(uci_handle->out_handle); - mhi_close_channel(uci_handle->in_handle); - uci_handle->out_chan_state = 0; - uci_handle->in_chan_state = 0; - wake_up(&uci_handle->read_wq); - } else { - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_CRITICAL, - "Chan %d state already reset\n", - uci_handle->out_chan); - } - uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO, "Exited\n"); - return 0; -} - static void process_rs232_state(struct uci_client *ctrl_client, struct mhi_result *result) { @@ -1071,15 +1081,13 @@ static void process_rs232_state(struct uci_client *ctrl_client, mutex_lock(&uci_ctxt->ctrl_mutex); if (result->transaction_status != 0) { - uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, - UCI_DBG_ERROR, + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_ERROR, "Non successful transfer code 0x%x\n", result->transaction_status); goto error_bad_xfer; } if (result->bytes_xferd != sizeof(struct rs232_ctrl_msg)) { - uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, - UCI_DBG_ERROR, + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_ERROR, "Buffer is of wrong size is: 0x%zx: expected 0x%zx\n", result->bytes_xferd, sizeof(struct rs232_ctrl_msg)); @@ -1088,8 +1096,8 @@ static void process_rs232_state(struct uci_client *ctrl_client, rs232_pkt = result->buf_addr; MHI_GET_CTRL_DEST_ID(CTRL_DEST_ID, rs232_pkt, chan); for (i = 0; i < MHI_SOFTWARE_CLIENT_LIMIT; i++) - if (chan == uci_ctxt->client_handles[i].out_chan || - chan == uci_ctxt->client_handles[i].in_chan) { + if (chan == uci_ctxt->client_handles[i].out_attr.chan_id || + chan == uci_ctxt->client_handles[i].in_attr.chan_id) { client = &uci_ctxt->client_handles[i]; break; } @@ -1114,13 +1122,12 @@ static void process_rs232_state(struct uci_client *ctrl_client, error_bad_xfer: error_size: memset(rs232_pkt, 0, sizeof(struct rs232_ctrl_msg)); - ret_val = mhi_queue_xfer(ctrl_client->in_handle, + ret_val = mhi_queue_xfer(ctrl_client->in_attr.mhi_handle, result->buf_addr, result->bytes_xferd, result->flags); if (0 != ret_val) { - uci_log(ctrl_client->uci_ipc_log, - UCI_DBG_ERROR, + uci_log(ctrl_client->uci_ipc_log, UCI_DBG_ERROR, "Failed to recycle ctrl msg buffer\n"); } mutex_unlock(&uci_ctxt->ctrl_mutex); @@ -1129,13 +1136,12 @@ error_size: static void parse_inbound_ack(struct uci_client *uci_handle, struct mhi_result *result) { - atomic_inc(&uci_handle->avail_pkts); - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_VERBOSE, + atomic_inc(&uci_handle->in_attr.avail_pkts); + uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE, "Received cb on chan %d, avail pkts: 0x%x\n", - uci_handle->in_chan, - atomic_read(&uci_handle->avail_pkts)); - wake_up(&uci_handle->read_wq); + uci_handle->in_attr.chan_id, + atomic_read(&uci_handle->in_attr.avail_pkts)); + wake_up(&uci_handle->in_attr.wq); if (uci_handle == uci_handle->uci_ctxt->ctrl_client) process_rs232_state(uci_handle, result); } @@ -1143,25 +1149,25 @@ static void parse_inbound_ack(struct uci_client *uci_handle, static void parse_outbound_ack(struct uci_client *uci_handle, struct mhi_result *result) { - kfree(result->buf_addr); - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_VERBOSE, + uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE, "Received ack on chan %d, pending acks: 0x%x\n", - uci_handle->out_chan, + uci_handle->out_attr.chan_id, atomic_read(&uci_handle->out_pkt_pend_ack)); atomic_dec(&uci_handle->out_pkt_pend_ack); - if (mhi_get_free_desc(uci_handle->out_handle)) - wake_up(&uci_handle->write_wq); + atomic_inc(&uci_handle->out_attr.avail_pkts); + atomic_inc(&uci_handle->completion_ack); + wake_up(&uci_handle->out_attr.wq); + schedule_work(&uci_handle->outbound_worker); } static void uci_xfer_cb(struct mhi_cb_info *cb_info) { struct uci_client *uci_handle = NULL; struct mhi_result *result; + struct chan_attr *chan_attr; if (!cb_info || !cb_info->result) { - uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, - UCI_DBG_CRITICAL, + uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_CRITICAL, "Bad CB info from MHI\n"); return; } @@ -1169,22 +1175,57 @@ static void uci_xfer_cb(struct mhi_cb_info *cb_info) uci_handle = cb_info->result->user_data; switch (cb_info->cb_reason) { case MHI_CB_MHI_ENABLED: - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_INFO, - "MHI enabled CB received.\n"); - atomic_set(&uci_handle->mhi_disabled, 0); + uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO, + "MHI enabled CB received for chan %d\n", + cb_info->chan); + chan_attr = (cb_info->chan % 2) ? &uci_handle->in_attr : + &uci_handle->out_attr; + mutex_lock(&chan_attr->chan_lock); + chan_attr->enabled = true; + mutex_unlock(&chan_attr->chan_lock); + wake_up(&chan_attr->wq); break; + case MHI_CB_SYS_ERROR: + case MHI_CB_MHI_SHUTDOWN: case MHI_CB_MHI_DISABLED: - atomic_set(&uci_handle->mhi_disabled, 1); - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_INFO, - "MHI disabled CB received\n"); - process_mhi_disabled_notif_sync(uci_handle); + uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO, + "MHI disabled CB received 0x%x for chan:%d\n", + cb_info->cb_reason, cb_info->chan); + + chan_attr = (cb_info->chan % 2) ? &uci_handle->in_attr : + &uci_handle->out_attr; + mutex_lock(&chan_attr->chan_lock); + chan_attr->enabled = false; + /* we disable entire handler by grabbing only one lock */ + uci_handle->enabled = false; + mutex_unlock(&chan_attr->chan_lock); + wake_up(&chan_attr->wq); + + /* + * if it's ctrl channel clear the resource now + * otherwise during file close we will release the + * resources + */ + if (uci_handle == uci_handle->uci_ctxt->ctrl_client && + chan_attr == &uci_handle->out_attr) { + struct uci_buf *itr, *tmp; + + mutex_lock(&chan_attr->chan_lock); + atomic_set(&uci_handle->out_attr.avail_pkts, 0); + atomic_set(&uci_handle->out_pkt_pend_ack, 0); + list_for_each_entry_safe(itr, tmp, &chan_attr->buf_head, + node) { + list_del(&itr->node); + kfree(itr->data); + } + atomic_set(&uci_handle->completion_ack, 0); + INIT_LIST_HEAD(&uci_handle->out_attr.buf_head); + mutex_unlock(&chan_attr->chan_lock); + } break; case MHI_CB_XFER: if (!cb_info->result) { - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_CRITICAL, + uci_log(uci_handle->uci_ipc_log, UCI_DBG_CRITICAL, "Failed to obtain mhi result from CB\n"); return; } @@ -1195,8 +1236,7 @@ static void uci_xfer_cb(struct mhi_cb_info *cb_info) parse_outbound_ack(uci_handle, result); break; default: - uci_log(uci_handle->uci_ipc_log, - UCI_DBG_VERBOSE, + uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE, "Cannot handle cb reason 0x%x\n", cb_info->cb_reason); } @@ -1208,48 +1248,40 @@ static int mhi_register_client(struct uci_client *mhi_client, int ret_val = 0; struct mhi_client_info_t client_info; - uci_log(mhi_client->uci_ipc_log, - UCI_DBG_INFO, + uci_log(mhi_client->uci_ipc_log, UCI_DBG_INFO, "Setting up workqueues\n"); - init_waitqueue_head(&mhi_client->read_wq); - init_waitqueue_head(&mhi_client->write_wq); - mhi_client->out_chan = mhi_client->out_attr.chan_id; - mhi_client->in_chan = mhi_client->in_attr.chan_id; - - mutex_init(&mhi_client->in_chan_lock); - mutex_init(&mhi_client->out_chan_lock); - atomic_set(&mhi_client->mhi_disabled, 1); + init_waitqueue_head(&mhi_client->in_attr.wq); + init_waitqueue_head(&mhi_client->out_attr.wq); - uci_log(mhi_client->uci_ipc_log, - UCI_DBG_INFO, + uci_log(mhi_client->uci_ipc_log, UCI_DBG_INFO, "Registering chan %d\n", - mhi_client->out_chan); + mhi_client->out_attr.chan_id); client_info.dev = dev; client_info.node_name = "qcom,mhi"; client_info.user_data = mhi_client; client_info.mhi_client_cb = uci_xfer_cb; - client_info.chan = mhi_client->out_chan; + client_info.chan = mhi_client->out_attr.chan_id; client_info.max_payload = mhi_client->out_attr.max_packet_size; - ret_val = mhi_register_channel(&mhi_client->out_handle, &client_info); + ret_val = mhi_register_channel(&mhi_client->out_attr.mhi_handle, + &client_info); if (0 != ret_val) uci_log(mhi_client->uci_ipc_log, UCI_DBG_ERROR, "Failed to init outbound chan 0x%x, ret 0x%x\n", - mhi_client->out_chan, + mhi_client->out_attr.chan_id, ret_val); - uci_log(mhi_client->uci_ipc_log, - UCI_DBG_INFO, + uci_log(mhi_client->uci_ipc_log, UCI_DBG_INFO, "Registering chan %d\n", - mhi_client->in_chan); + mhi_client->in_attr.chan_id); client_info.max_payload = mhi_client->in_attr.max_packet_size; - client_info.chan = mhi_client->in_chan; - ret_val = mhi_register_channel(&mhi_client->in_handle, &client_info); + client_info.chan = mhi_client->in_attr.chan_id; + ret_val = mhi_register_channel(&mhi_client->in_attr.mhi_handle, + &client_info); if (0 != ret_val) - uci_log(mhi_client->uci_ipc_log, - UCI_DBG_ERROR, + uci_log(mhi_client->uci_ipc_log, UCI_DBG_ERROR, "Failed to init inbound chan 0x%x, ret 0x%x\n", - mhi_client->in_chan, + mhi_client->in_attr.chan_id, ret_val); return 0; } @@ -1313,6 +1345,7 @@ static int mhi_uci_probe(struct platform_device *pdev) struct uci_client *uci_client = &uci_ctxt->client_handles[i]; uci_client->uci_ctxt = uci_ctxt; + mutex_init(&uci_client->client_lock); if (uci_client->in_attr.uci_ownership) { ret_val = mhi_register_client(uci_client, &pdev->dev); @@ -1328,10 +1361,10 @@ static int mhi_uci_probe(struct platform_device *pdev) snprintf(node_name, sizeof(node_name), "mhi_uci_%04x_%02u.%02u.%02u_%d", - uci_client->out_handle->dev_id, - uci_client->out_handle->domain, - uci_client->out_handle->bus, - uci_client->out_handle->slot, + uci_client->out_attr.mhi_handle->dev_id, + uci_client->out_attr.mhi_handle->domain, + uci_client->out_attr.mhi_handle->bus, + uci_client->out_attr.mhi_handle->slot, uci_client->out_attr.chan_id); uci_client->uci_ipc_log = ipc_log_context_create (MHI_UCI_IPC_LOG_PAGES, @@ -1380,12 +1413,12 @@ static int mhi_uci_probe(struct platform_device *pdev) uci_ctxt->dev_t + i, NULL, DEVICE_NAME "_%04x_%02u.%02u.%02u%s%d", - uci_client->out_handle->dev_id, - uci_client->out_handle->domain, - uci_client->out_handle->bus, - uci_client->out_handle->slot, + uci_client->out_attr.mhi_handle->dev_id, + uci_client->out_attr.mhi_handle->domain, + uci_client->out_attr.mhi_handle->bus, + uci_client->out_attr.mhi_handle->slot, "_pipe_", - uci_client->out_chan); + uci_client->out_attr.chan_id); if (IS_ERR(uci_client->dev)) { uci_log(uci_client->uci_ipc_log, UCI_DBG_ERROR, @@ -1427,8 +1460,8 @@ static int mhi_uci_remove(struct platform_device *pdev) uci_client->uci_ctxt = uci_ctxt; if (uci_client->in_attr.uci_ownership) { - mhi_deregister_channel(uci_client->out_handle); - mhi_deregister_channel(uci_client->in_handle); + mhi_deregister_channel(uci_client->out_attr.mhi_handle); + mhi_deregister_channel(uci_client->in_attr.mhi_handle); cdev_del(&uci_ctxt->cdev[i]); device_destroy(mhi_uci_drv_ctxt.mhi_uci_class, MKDEV(MAJOR(uci_ctxt->dev_t), i)); diff --git a/drivers/platform/msm/msm_11ad/msm_11ad.c b/drivers/platform/msm/msm_11ad/msm_11ad.c index 61a870c9928b..c6009d767db5 100644 --- a/drivers/platform/msm/msm_11ad/msm_11ad.c +++ b/drivers/platform/msm/msm_11ad/msm_11ad.c @@ -750,6 +750,25 @@ static int msm_11ad_ssr_powerup(const struct subsys_desc *subsys) return rc; } +static int msm_11ad_ssr_copy_ramdump(struct msm11ad_ctx *ctx) +{ + if (ctx->rops.ramdump && ctx->wil_handle) { + int rc = ctx->rops.ramdump(ctx->wil_handle, ctx->ramdump_addr, + WIGIG_RAMDUMP_SIZE); + if (rc) { + dev_err(ctx->dev, "ramdump failed : %d\n", rc); + return -EINVAL; + } + } + + ctx->dump_data.version = WIGIG_DUMP_FORMAT_VER; + strlcpy(ctx->dump_data.name, WIGIG_SUBSYS_NAME, + sizeof(ctx->dump_data.name)); + + ctx->dump_data.magic = WIGIG_DUMP_MAGIC_VER_V1; + return 0; +} + static int msm_11ad_ssr_ramdump(int enable, const struct subsys_desc *subsys) { int rc; @@ -766,13 +785,10 @@ static int msm_11ad_ssr_ramdump(int enable, const struct subsys_desc *subsys) if (!enable) return 0; - if (ctx->rops.ramdump && ctx->wil_handle) { - rc = ctx->rops.ramdump(ctx->wil_handle, ctx->ramdump_addr, - WIGIG_RAMDUMP_SIZE); - if (rc) { - dev_err(ctx->dev, "ramdump failed : %d\n", rc); - return -EINVAL; - } + if (!ctx->recovery_in_progress) { + rc = msm_11ad_ssr_copy_ramdump(ctx); + if (rc) + return rc; } memset(&segment, 0, sizeof(segment)); @@ -784,7 +800,6 @@ static int msm_11ad_ssr_ramdump(int enable, const struct subsys_desc *subsys) static void msm_11ad_ssr_crash_shutdown(const struct subsys_desc *subsys) { - int rc; struct platform_device *pdev; struct msm11ad_ctx *ctx; @@ -796,19 +811,8 @@ static void msm_11ad_ssr_crash_shutdown(const struct subsys_desc *subsys) return; } - if (ctx->rops.ramdump && ctx->wil_handle) { - rc = ctx->rops.ramdump(ctx->wil_handle, ctx->ramdump_addr, - WIGIG_RAMDUMP_SIZE); - if (rc) - dev_err(ctx->dev, "ramdump failed : %d\n", rc); - /* continue */ - } - - ctx->dump_data.version = WIGIG_DUMP_FORMAT_VER; - strlcpy(ctx->dump_data.name, WIGIG_SUBSYS_NAME, - sizeof(ctx->dump_data.name)); - - ctx->dump_data.magic = WIGIG_DUMP_MAGIC_VER_V1; + if (!ctx->recovery_in_progress) + (void)msm_11ad_ssr_copy_ramdump(ctx); } static void msm_11ad_ssr_deinit(struct msm11ad_ctx *ctx) @@ -1305,6 +1309,7 @@ static int msm_11ad_notify_crash(struct msm11ad_ctx *ctx) if (ctx->subsys) { dev_info(ctx->dev, "SSR requested\n"); + (void)msm_11ad_ssr_copy_ramdump(ctx); ctx->recovery_in_progress = true; rc = subsystem_restart_dev(ctx->subsys); if (rc) { diff --git a/drivers/platform/msm/seemp_core/seemp_logk.c b/drivers/platform/msm/seemp_core/seemp_logk.c index 9b6096485c39..d0f21943cb0f 100644 --- a/drivers/platform/msm/seemp_core/seemp_logk.c +++ b/drivers/platform/msm/seemp_core/seemp_logk.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -184,6 +184,8 @@ static int seemp_logk_usr_record(const char __user *buf, size_t count) if (copy_from_user(&usr_blk.payload, &local_blk->payload, sizeof(struct blk_payload)) != 0) return -EFAULT; + } else { + return -EFAULT; } idx = ret = 0; now = current_kernel_time(); @@ -283,7 +285,12 @@ static bool seemp_logk_get_bit_from_vector(__u8 *pVec, __u32 index) { unsigned int byte_num = index/8; unsigned int bit_num = index%8; - unsigned char byte = pVec[byte_num]; + unsigned char byte; + + if (DIV_ROUND_UP(index, 8) > MASK_BUFFER_SIZE) + return false; + + byte = pVec[byte_num]; return !(byte & (1 << bit_num)); } diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index 438da2c51dd6..723b9eaf658a 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -293,6 +293,7 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(die_health), POWER_SUPPLY_ATTR(connector_health), POWER_SUPPLY_ATTR(ctm_current_max), + POWER_SUPPLY_ATTR(hw_current_max), /* Local extensions of type int64_t */ POWER_SUPPLY_ATTR(charge_counter_ext), /* Properties of type `const char *' */ diff --git a/drivers/power/qcom/msm-core.c b/drivers/power/qcom/msm-core.c index 3ac4611da9bd..43ad33ea234b 100644 --- a/drivers/power/qcom/msm-core.c +++ b/drivers/power/qcom/msm-core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1069,6 +1069,7 @@ static int msm_core_dev_probe(struct platform_device *pdev) if (ret) goto failed; + INIT_DEFERRABLE_WORK(&sampling_work, samplequeue_handle); ret = msm_core_task_init(&pdev->dev); if (ret) goto failed; @@ -1076,7 +1077,6 @@ static int msm_core_dev_probe(struct platform_device *pdev) for_each_possible_cpu(cpu) set_threshold(&activity[cpu]); - INIT_DEFERRABLE_WORK(&sampling_work, samplequeue_handle); schedule_delayed_work(&sampling_work, msecs_to_jiffies(0)); cpufreq_register_notifier(&cpu_policy, CPUFREQ_POLICY_NOTIFIER); pm_notifier(system_suspend_handler, 0); diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index 0c80c8be7909..914a6e4eae64 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -13,6 +13,7 @@ #define pr_fmt(fmt) "QCOM-BATT: %s: " fmt, __func__ #include <linux/device.h> +#include <linux/delay.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/regmap.h> @@ -36,6 +37,7 @@ #define PL_HW_ABSENT_VOTER "PL_HW_ABSENT_VOTER" #define PL_VOTER "PL_VOTER" #define RESTRICT_CHG_VOTER "RESTRICT_CHG_VOTER" +#define ICL_CHANGE_VOTER "ICL_CHANGE_VOTER" struct pl_data { int pl_mode; @@ -49,14 +51,16 @@ struct pl_data { struct votable *pl_disable_votable; struct votable *pl_awake_votable; struct votable *hvdcp_hw_inov_dis_votable; + struct votable *usb_icl_votable; struct work_struct status_change_work; struct work_struct pl_disable_forever_work; struct delayed_work pl_taper_work; struct power_supply *main_psy; struct power_supply *pl_psy; struct power_supply *batt_psy; + struct power_supply *usb_psy; int charge_type; - int main_settled_ua; + int total_settled_ua; int pl_settled_ua; struct class qcom_batt_class; struct wakeup_source *pl_ws; @@ -92,15 +96,10 @@ enum { ********/ static void split_settled(struct pl_data *chip) { - int slave_icl_pct; + int slave_icl_pct, total_current_ua; int slave_ua = 0, main_settled_ua = 0; union power_supply_propval pval = {0, }; - int rc; - - /* TODO some parallel chargers do not have a fine ICL resolution. For - * them implement a psy interface which returns the closest lower ICL - * for desired split - */ + int rc, total_settled_ua = 0; if ((chip->pl_mode != POWER_SUPPLY_PL_USBIN_USBIN) && (chip->pl_mode != POWER_SUPPLY_PL_USBIN_USBIN_EXT)) @@ -122,12 +121,31 @@ static void split_settled(struct pl_data *chip) slave_icl_pct = max(0, chip->slave_pct - 10); slave_ua = ((main_settled_ua + chip->pl_settled_ua) * slave_icl_pct) / 100; + total_settled_ua = main_settled_ua + chip->pl_settled_ua; } - /* ICL_REDUCTION on main could be 0mA when pl is disabled */ - pval.intval = slave_ua; + total_current_ua = get_effective_result_locked(chip->usb_icl_votable); + if (total_current_ua < 0) { + if (!chip->usb_psy) + chip->usb_psy = power_supply_get_by_name("usb"); + if (!chip->usb_psy) { + pr_err("Couldn't get usbpsy while splitting settled\n"); + return; + } + /* no client is voting, so get the total current from charger */ + rc = power_supply_get_property(chip->usb_psy, + POWER_SUPPLY_PROP_HW_CURRENT_MAX, &pval); + if (rc < 0) { + pr_err("Couldn't get max current rc=%d\n", rc); + return; + } + total_current_ua = pval.intval; + } + + pval.intval = total_current_ua - slave_ua; + /* Set ICL on main charger */ rc = power_supply_set_property(chip->main_psy, - POWER_SUPPLY_PROP_ICL_REDUCTION, &pval); + POWER_SUPPLY_PROP_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't change slave suspend state rc=%d\n", rc); return; @@ -142,10 +160,12 @@ static void split_settled(struct pl_data *chip) return; } - /* main_settled_ua represents the total capability of adapter */ - if (!chip->main_settled_ua) - chip->main_settled_ua = main_settled_ua; + chip->total_settled_ua = total_settled_ua; chip->pl_settled_ua = slave_ua; + + pl_dbg(chip, PR_PARALLEL, + "Split total_current_ua=%d main_settled_ua=%d slave_ua=%d\n", + total_current_ua, main_settled_ua, slave_ua); } static ssize_t version_show(struct class *c, struct class_attribute *attr, @@ -213,6 +233,10 @@ static ssize_t restrict_chg_store(struct class *c, struct class_attribute *attr, chip->restricted_charging_enabled = !!val; + /* disable parallel charger in case of restricted charging */ + vote(chip->pl_disable_votable, RESTRICT_CHG_VOTER, + chip->restricted_charging_enabled, 0); + vote(chip->fcc_votable, RESTRICT_CHG_VOTER, chip->restricted_charging_enabled, chip->restricted_current); @@ -487,6 +511,59 @@ static int pl_fv_vote_callback(struct votable *votable, void *data, return 0; } +#define ICL_STEP_UV 25000 +static int usb_icl_vote_callback(struct votable *votable, void *data, + int icl_ua, const char *client) +{ + int rc; + struct pl_data *chip = data; + union power_supply_propval pval = {0, }; + + if (!chip->main_psy) + return 0; + + if (client == NULL) + icl_ua = INT_MAX; + + /* + * Disable parallel for new ICL vote - the call to split_settled will + * ensure that all the input current limit gets assigned to the main + * charger. + */ + vote(chip->pl_disable_votable, ICL_CHANGE_VOTER, true, 0); + + /* rerun AICL */ + /* get the settled current */ + rc = power_supply_get_property(chip->main_psy, + POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, + &pval); + if (rc < 0) { + pr_err("Couldn't get aicl settled value rc=%d\n", rc); + return rc; + } + + /* rerun AICL if new ICL is above settled ICL */ + if (icl_ua > pval.intval) { + /* set a lower ICL */ + pval.intval = max(pval.intval - ICL_STEP_UV, ICL_STEP_UV); + power_supply_set_property(chip->main_psy, + POWER_SUPPLY_PROP_CURRENT_MAX, + &pval); + /* wait for ICL change */ + msleep(100); + + pval.intval = icl_ua; + power_supply_set_property(chip->main_psy, + POWER_SUPPLY_PROP_CURRENT_MAX, + &pval); + /* wait for ICL change */ + msleep(100); + } + vote(chip->pl_disable_votable, ICL_CHANGE_VOTER, false, 0); + + return 0; +} + static void pl_disable_forever_work(struct work_struct *work) { struct pl_data *chip = container_of(work, @@ -508,7 +585,7 @@ static int pl_disable_vote_callback(struct votable *votable, int rc; chip->taper_pct = 100; - chip->main_settled_ua = 0; + chip->total_settled_ua = 0; chip->pl_settled_ua = 0; if (!pl_disable) { /* enable */ @@ -596,13 +673,15 @@ static int pl_awake_vote_callback(struct votable *votable, static bool is_main_available(struct pl_data *chip) { - if (!chip->main_psy) - chip->main_psy = power_supply_get_by_name("main"); + if (chip->main_psy) + return true; - if (!chip->main_psy) - return false; + chip->main_psy = power_supply_get_by_name("main"); - return true; + if (chip->main_psy) + rerun_election(chip->usb_icl_votable); + + return !!chip->main_psy; } static bool is_batt_available(struct pl_data *chip) @@ -711,6 +790,7 @@ static void handle_main_charge_type(struct pl_data *chip) static void handle_settled_icl_change(struct pl_data *chip) { union power_supply_propval pval = {0, }; + int new_total_settled_ua; int rc; if (get_effective_result(chip->pl_disable_votable)) @@ -730,9 +810,15 @@ static void handle_settled_icl_change(struct pl_data *chip) return; } + new_total_settled_ua = pval.intval + chip->pl_settled_ua; + pl_dbg(chip, PR_PARALLEL, + "total_settled_ua=%d settled_ua=%d new_total_settled_ua=%d\n", + chip->total_settled_ua, pval.intval, + new_total_settled_ua); + /* If ICL change is small skip splitting */ - if (abs((chip->main_settled_ua - chip->pl_settled_ua) - - pval.intval) > MIN_ICL_CHANGE_DELTA_UA) + if (abs(new_total_settled_ua - chip->total_settled_ua) + > MIN_ICL_CHANGE_DELTA_UA) split_settled(chip); } else { rerun_election(chip->fcc_votable); @@ -855,6 +941,14 @@ static int pl_init(void) goto destroy_votable; } + chip->usb_icl_votable = create_votable("USB_ICL", VOTE_MIN, + usb_icl_vote_callback, + chip); + if (IS_ERR(chip->usb_icl_votable)) { + rc = PTR_ERR(chip->usb_icl_votable); + goto destroy_votable; + } + chip->pl_disable_votable = create_votable("PL_DISABLE", VOTE_SET_ANY, pl_disable_vote_callback, chip); @@ -909,6 +1003,7 @@ destroy_votable: destroy_votable(chip->pl_disable_votable); destroy_votable(chip->fv_votable); destroy_votable(chip->fcc_votable); + destroy_votable(chip->usb_icl_votable); release_wakeup_source: wakeup_source_unregister(chip->pl_ws); cleanup: diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index e8249163e948..4dfa43012b54 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -414,6 +414,7 @@ static enum power_supply_property smb2_usb_props[] = { POWER_SUPPLY_PROP_BOOST_CURRENT, POWER_SUPPLY_PROP_PE_START, POWER_SUPPLY_PROP_CTM_CURRENT_MAX, + POWER_SUPPLY_PROP_HW_CURRENT_MAX, }; static int smb2_usb_get_prop(struct power_supply *psy, @@ -502,6 +503,9 @@ static int smb2_usb_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CTM_CURRENT_MAX: val->intval = get_client_vote(chg->usb_icl_votable, CTM_VOTER); break; + case POWER_SUPPLY_PROP_HW_CURRENT_MAX: + rc = smblib_get_charge_current(chg, &val->intval); + break; default: pr_err("get prop %d is not supported in usb\n", psp); rc = -EINVAL; @@ -610,12 +614,12 @@ static int smb2_init_usb_psy(struct smb2 *chip) static enum power_supply_property smb2_usb_main_props[] = { POWER_SUPPLY_PROP_VOLTAGE_MAX, - POWER_SUPPLY_PROP_ICL_REDUCTION, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, POWER_SUPPLY_PROP_TYPE, POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, POWER_SUPPLY_PROP_INPUT_VOLTAGE_SETTLED, POWER_SUPPLY_PROP_FCC_DELTA, + POWER_SUPPLY_PROP_CURRENT_MAX, /* * TODO move the TEMP and TEMP_MAX properties here, * and update the thermal balancer to look here @@ -634,9 +638,6 @@ static int smb2_usb_main_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_VOLTAGE_MAX: rc = smblib_get_charge_param(chg, &chg->param.fv, &val->intval); break; - case POWER_SUPPLY_PROP_ICL_REDUCTION: - val->intval = chg->icl_reduction_ua; - break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: rc = smblib_get_charge_param(chg, &chg->param.fcc, &val->intval); @@ -653,6 +654,9 @@ static int smb2_usb_main_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_FCC_DELTA: rc = smblib_get_prop_fcc_delta(chg, val); break; + case POWER_SUPPLY_PROP_CURRENT_MAX: + val->intval = get_effective_result(chg->usb_icl_votable); + break; default: pr_debug("get prop %d is not supported in usb-main\n", psp); rc = -EINVAL; @@ -677,12 +681,12 @@ static int smb2_usb_main_set_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_VOLTAGE_MAX: rc = smblib_set_charge_param(chg, &chg->param.fv, val->intval); break; - case POWER_SUPPLY_PROP_ICL_REDUCTION: - rc = smblib_set_icl_reduction(chg, val->intval); - break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: rc = smblib_set_charge_param(chg, &chg->param.fcc, val->intval); break; + case POWER_SUPPLY_PROP_CURRENT_MAX: + rc = smblib_set_icl_current(chg, val->intval); + break; default: pr_err("set prop %d is not supported\n", psp); rc = -EINVAL; @@ -1133,6 +1137,9 @@ static int smb2_init_vconn_regulator(struct smb2 *chip) struct regulator_config cfg = {}; int rc = 0; + if (chg->micro_usb_mode) + return 0; + chg->vconn_vreg = devm_kzalloc(chg->dev, sizeof(*chg->vconn_vreg), GFP_KERNEL); if (!chg->vconn_vreg) @@ -1344,9 +1351,10 @@ static int smb2_disable_typec(struct smb_charger *chg) int rc; /* Move to typeC mode */ - /* configure FSM in idle state */ + /* configure FSM in idle state and disable UFP_ENABLE bit */ rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, - TYPEC_DISABLE_CMD_BIT, TYPEC_DISABLE_CMD_BIT); + TYPEC_DISABLE_CMD_BIT | UFP_EN_CMD_BIT, + TYPEC_DISABLE_CMD_BIT); if (rc < 0) { dev_err(chg->dev, "Couldn't put FSM in idle rc=%d\n", rc); return rc; @@ -1568,6 +1576,16 @@ static int smb2_init_hw(struct smb2 *chip) return rc; } + /* disable h/w autonomous parallel charging control */ + rc = smblib_masked_write(chg, MISC_CFG_REG, + STAT_PARALLEL_1400MA_EN_CFG_BIT, 0); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't disable h/w autonomous parallel control rc=%d\n", + rc); + return rc; + } + /* configure float charger options */ switch (chip->dt.float_option) { case 1: @@ -2131,7 +2149,7 @@ static int smb2_probe(struct platform_device *pdev) rc = smb2_init_vconn_regulator(chip); if (rc < 0) { pr_err("Couldn't initialize vconn regulator rc=%d\n", - rc); + rc); goto cleanup; } @@ -2226,6 +2244,8 @@ static int smb2_probe(struct platform_device *pdev) } batt_charge_type = val.intval; + device_init_wakeup(chg->dev, true); + pr_info("QPNP SMB2 probed successfully usb:present=%d type=%d batt:present = %d health = %d charge = %d\n", usb_present, chg->usb_psy_desc.type, batt_present, batt_health, batt_charge_type); diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index 51c87f963307..bd96703579f6 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -654,10 +654,13 @@ static void smblib_uusb_removal(struct smb_charger *chg) { int rc; + cancel_delayed_work_sync(&chg->pl_enable_work); + vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0); + vote(chg->awake_votable, PL_DELAY_VOTER, false, 0); + /* reset both usbin current and voltage votes */ vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0); vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0); - vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER, true, 0); cancel_delayed_work_sync(&chg->hvdcp_detect_work); @@ -693,13 +696,6 @@ static void smblib_uusb_removal(struct smb_charger *chg) if (rc < 0) smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n", rc); - - /* clear USB ICL vote for PL_USBIN_USBIN_VOTER */ - rc = vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0); - if (rc < 0) - smblib_err(chg, - "Couldn't un-vote PL_USBIN_USBIN from USB ICL rc=%d\n", - rc); } void smblib_suspend_on_debug_battery(struct smb_charger *chg) @@ -795,29 +791,12 @@ static int smblib_get_pulse_cnt(struct smb_charger *chg, int *count) return 0; } -/********************* - * VOTABLE CALLBACKS * - *********************/ - -static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data, - int suspend, const char *client) -{ - struct smb_charger *chg = data; - - /* resume input if suspend is invalid */ - if (suspend < 0) - suspend = 0; - - return smblib_set_dc_suspend(chg, (bool)suspend); -} - #define USBIN_25MA 25000 #define USBIN_100MA 100000 #define USBIN_150MA 150000 #define USBIN_500MA 500000 #define USBIN_900MA 900000 - static int set_sdp_current(struct smb_charger *chg, int icl_ua) { int rc; @@ -856,20 +835,18 @@ static int set_sdp_current(struct smb_charger *chg, int icl_ua) return rc; } -static int smblib_usb_icl_vote_callback(struct votable *votable, void *data, - int icl_ua, const char *client) +int smblib_set_icl_current(struct smb_charger *chg, int icl_ua) { - struct smb_charger *chg = data; int rc = 0; bool override; union power_supply_propval pval; /* suspend and return if 25mA or less is requested */ - if (client && (icl_ua < USBIN_25MA)) + if (icl_ua < USBIN_25MA) return smblib_set_usb_suspend(chg, true); disable_irq_nosync(chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq); - if (!client) + if (icl_ua == INT_MAX) goto override_suspend_config; rc = smblib_get_prop_typec_mode(chg, &pval); @@ -887,8 +864,7 @@ static int smblib_usb_icl_vote_callback(struct votable *votable, void *data, goto enable_icl_changed_interrupt; } } else { - rc = smblib_set_charge_param(chg, &chg->param.usb_icl, - icl_ua - chg->icl_reduction_ua); + rc = smblib_set_charge_param(chg, &chg->param.usb_icl, icl_ua); if (rc < 0) { smblib_err(chg, "Couldn't set HC ICL rc=%d\n", rc); goto enable_icl_changed_interrupt; @@ -898,7 +874,7 @@ static int smblib_usb_icl_vote_callback(struct votable *votable, void *data, override_suspend_config: /* determine if override needs to be enforced */ override = true; - if (client == NULL) { + if (icl_ua == INT_MAX) { /* remove override if no voters - hw defaults is desired */ override = false; } else if (pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) { @@ -906,7 +882,7 @@ override_suspend_config: /* For std cable with type = SDP never override */ override = false; else if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB_CDP - && icl_ua - chg->icl_reduction_ua == 1500000) + && icl_ua == 1500000) /* * For std cable with type = CDP override only if * current is not 1500mA @@ -936,6 +912,22 @@ enable_icl_changed_interrupt: return rc; } +/********************* + * VOTABLE CALLBACKS * + *********************/ + +static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data, + int suspend, const char *client) +{ + struct smb_charger *chg = data; + + /* resume input if suspend is invalid */ + if (suspend < 0) + suspend = 0; + + return smblib_set_dc_suspend(chg, (bool)suspend); +} + static int smblib_dc_icl_vote_callback(struct votable *votable, void *data, int icl_ua, const char *client) { @@ -1793,6 +1785,10 @@ int smblib_set_prop_system_temp_level(struct smb_charger *chg, return -EINVAL; chg->system_temp_level = val->intval; + /* disable parallel charge in case of system temp level */ + vote(chg->pl_disable_votable, THERMAL_DAEMON_VOTER, + chg->system_temp_level ? true : false, 0); + if (chg->system_temp_level == chg->thermal_levels) return vote(chg->chg_disable_votable, THERMAL_DAEMON_VOTER, true, 0); @@ -2027,7 +2023,7 @@ int smblib_get_prop_usb_online(struct smb_charger *chg, int rc = 0; u8 stat; - if (get_client_vote(chg->usb_icl_votable, USER_VOTER) == 0) { + if (get_client_vote_locked(chg->usb_icl_votable, USER_VOTER) == 0) { val->intval = false; return rc; } @@ -2521,10 +2517,6 @@ int smblib_set_prop_usb_voltage_min(struct smb_charger *chg, return rc; } - if (chg->mode == PARALLEL_MASTER) - vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, - min_uv > MICRO_5V, 0); - chg->voltage_min_uv = min_uv; return rc; } @@ -2609,29 +2601,12 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, "Couldn't un-vote DCP from USB ICL rc=%d\n", rc); - /* clear USB ICL vote for PL_USBIN_USBIN_VOTER */ - rc = vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0); - if (rc < 0) - smblib_err(chg, - "Couldn't un-vote PL_USBIN_USBIN from USB ICL rc=%d\n", - rc); - /* remove USB_PSY_VOTER */ rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0); if (rc < 0) { smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc); return rc; } - - /* pd active set, parallel charger can be enabled now */ - rc = vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER, - false, 0); - if (rc < 0) { - smblib_err(chg, - "Couldn't unvote PL_DELAY_HVDCP_VOTER rc=%d\n", - rc); - return rc; - } } /* CC pin selection s/w override in PD session; h/w otherwise. */ @@ -2880,15 +2855,21 @@ int smblib_get_prop_fcc_delta(struct smb_charger *chg, #define TYPEC_DEFAULT_CURRENT_MA 900000 #define TYPEC_MEDIUM_CURRENT_MA 1500000 #define TYPEC_HIGH_CURRENT_MA 3000000 -static int smblib_get_charge_current(struct smb_charger *chg, +int smblib_get_charge_current(struct smb_charger *chg, int *total_current_ua) { const struct apsd_result *apsd_result = smblib_update_usb_type(chg); union power_supply_propval val = {0, }; - int rc, typec_source_rd, current_ua; + int rc = 0, typec_source_rd, current_ua; bool non_compliant; u8 stat5; + if (chg->pd_active) { + *total_current_ua = + get_client_vote_locked(chg->usb_icl_votable, PD_VOTER); + return rc; + } + rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc); @@ -2963,39 +2944,12 @@ static int smblib_get_charge_current(struct smb_charger *chg, return 0; } -int smblib_set_icl_reduction(struct smb_charger *chg, int reduction_ua) -{ - int current_ua, rc; - - if (reduction_ua == 0) { - vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0); - } else { - /* - * No usb_icl voter means we are defaulting to hw chosen - * max limit. We need a vote from s/w to enforce the reduction. - */ - if (get_effective_result(chg->usb_icl_votable) == -EINVAL) { - rc = smblib_get_charge_current(chg, ¤t_ua); - if (rc < 0) { - pr_err("Failed to get ICL rc=%d\n", rc); - return rc; - } - vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, true, - current_ua); - } - } - - chg->icl_reduction_ua = reduction_ua; - - return rerun_election(chg->usb_icl_votable); -} - /************************ * PARALLEL PSY GETTERS * ************************/ int smblib_get_prop_slave_current_now(struct smb_charger *chg, - union power_supply_propval *pval) + union power_supply_propval *pval) { if (IS_ERR_OR_NULL(chg->iio.batt_i_chan)) chg->iio.batt_i_chan = iio_channel_get(chg->dev, "batt_i"); @@ -3058,7 +3012,7 @@ irqreturn_t smblib_handle_chg_state_change(int irq, void *data) rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n", - rc); + rc); return IRQ_HANDLED; } @@ -3163,6 +3117,7 @@ irqreturn_t smblib_handle_usbin_uv(int irq, void *data) return IRQ_HANDLED; } +#define PL_DELAY_MS 30000 irqreturn_t smblib_handle_usb_plugin(int irq, void *data) { struct smb_irq_data *irq_data = data; @@ -3201,6 +3156,11 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data) smblib_err(chg, "Couldn't enable dpdm regulator rc=%d\n", rc); } + + /* Schedule work to enable parallel charger */ + vote(chg->awake_votable, PL_DELAY_VOTER, true, 0); + schedule_delayed_work(&chg->pl_enable_work, + msecs_to_jiffies(PL_DELAY_MS)); } else { if (chg->wa_flags & BOOST_BACK_WA) vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0); @@ -3378,9 +3338,6 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg, } } - /* QC authentication done, parallel charger can be enabled now */ - vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER, false, 0); - smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n", apsd_result->name); } @@ -3410,15 +3367,6 @@ static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg, /* enforce DCP ICL if specified */ vote(chg->usb_icl_votable, DCP_VOTER, chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua); - /* - * If adapter is not QC2.0/QC3.0 remove vote for parallel - * disable. - * Otherwise if adapter is QC2.0/QC3.0 wait for authentication - * to complete. - */ - if (!qc_charger) - vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER, - false, 0); } smblib_dbg(chg, PR_INTERRUPT, "IRQ: smblib_handle_hvdcp_check_timeout %s\n", @@ -3490,13 +3438,9 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) true); case OCP_CHARGER_BIT: case FLOAT_CHARGER_BIT: - /* - * if not DCP then no hvdcp timeout happens. Enable - * pd/parallel here. - */ + /* if not DCP then no hvdcp timeout happens, Enable pd here. */ vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER, false, 0); - vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER, false, 0); break; case DCP_CHARGER_BIT: if (chg->wa_flags & QC_CHARGER_DETECTION_WA_BIT) @@ -3608,12 +3552,6 @@ static void typec_source_removal(struct smb_charger *chg) smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n", rc); - /* clear USB ICL vote for PL_USBIN_USBIN_VOTER */ - rc = vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0); - if (rc < 0) - smblib_err(chg, - "Couldn't un-vote PL_USBIN_USBIN from USB ICL rc=%d\n", - rc); } static void typec_source_insertion(struct smb_charger *chg) @@ -3649,9 +3587,12 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) { int rc; + cancel_delayed_work_sync(&chg->pl_enable_work); + vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0); + vote(chg->awake_votable, PL_DELAY_VOTER, false, 0); + vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0); vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER, true, 0); - vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER, true, 0); vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0); vote(chg->usb_irq_enable_votable, QC_VOTER, false, 0); @@ -3707,8 +3648,6 @@ static void smblib_handle_typec_insertion(struct smb_charger *chg, if (rp == POWER_SUPPLY_TYPEC_SOURCE_HIGH || rp == POWER_SUPPLY_TYPEC_NON_COMPLIANT) { smblib_dbg(chg, PR_MISC, "VBUS & CC could be shorted; keeping HVDCP disabled\n"); - /* HVDCP is not going to be enabled; enable parallel */ - vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER, false, 0); vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0); } else { @@ -4117,6 +4056,9 @@ static void smblib_vconn_oc_work(struct work_struct *work) int rc, i; u8 stat; + if (chg->micro_usb_mode) + return; + smblib_err(chg, "over-current detected on VCONN\n"); if (!chg->vconn_vreg || !chg->vconn_vreg->rdev) return; @@ -4211,6 +4153,16 @@ static void smblib_icl_change_work(struct work_struct *work) smblib_dbg(chg, PR_INTERRUPT, "icl_settled=%d\n", settled_ua); } +static void smblib_pl_enable_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, struct smb_charger, + pl_enable_work.work); + + smblib_dbg(chg, PR_PARALLEL, "timer expired, enabling parallel\n"); + vote(chg->pl_disable_votable, PL_DELAY_VOTER, false, 0); + vote(chg->awake_votable, PL_DELAY_VOTER, false, 0); +} + static int smblib_create_votables(struct smb_charger *chg) { int rc = 0; @@ -4227,13 +4179,19 @@ static int smblib_create_votables(struct smb_charger *chg) return rc; } + chg->usb_icl_votable = find_votable("USB_ICL"); + if (!chg->usb_icl_votable) { + rc = -EPROBE_DEFER; + return rc; + } + chg->pl_disable_votable = find_votable("PL_DISABLE"); if (!chg->pl_disable_votable) { rc = -EPROBE_DEFER; return rc; } vote(chg->pl_disable_votable, PL_INDIRECT_VOTER, true, 0); - vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER, true, 0); + vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0); chg->dc_suspend_votable = create_votable("DC_SUSPEND", VOTE_SET_ANY, smblib_dc_suspend_vote_callback, @@ -4243,14 +4201,6 @@ static int smblib_create_votables(struct smb_charger *chg) return rc; } - chg->usb_icl_votable = create_votable("USB_ICL", VOTE_MIN, - smblib_usb_icl_vote_callback, - chg); - if (IS_ERR(chg->usb_icl_votable)) { - rc = PTR_ERR(chg->usb_icl_votable); - return rc; - } - chg->dc_icl_votable = create_votable("DC_ICL", VOTE_MIN, smblib_dc_icl_vote_callback, chg); @@ -4401,6 +4351,7 @@ int smblib_init(struct smb_charger *chg) INIT_WORK(&chg->vconn_oc_work, smblib_vconn_oc_work); INIT_DELAYED_WORK(&chg->otg_ss_done_work, smblib_otg_ss_done_work); INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work); + INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work); chg->fake_capacity = -EINVAL; switch (chg->mode) { diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index 048e7c2b4091..49b9d3da783c 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -56,7 +56,7 @@ enum print_reason { #define MICRO_USB_VOTER "MICRO_USB_VOTER" #define DEBUG_BOARD_VOTER "DEBUG_BOARD_VOTER" #define PD_SUSPEND_SUPPORTED_VOTER "PD_SUSPEND_SUPPORTED_VOTER" -#define PL_DELAY_HVDCP_VOTER "PL_DELAY_HVDCP_VOTER" +#define PL_DELAY_VOTER "PL_DELAY_VOTER" #define CTM_VOTER "CTM_VOTER" #define SW_QC3_VOTER "SW_QC3_VOTER" #define AICL_RERUN_VOTER "AICL_RERUN_VOTER" @@ -288,6 +288,7 @@ struct smb_charger { struct work_struct vconn_oc_work; struct delayed_work otg_ss_done_work; struct delayed_work icl_change_work; + struct delayed_work pl_enable_work; /* cached status */ int voltage_min_uv; @@ -321,8 +322,6 @@ struct smb_charger { /* extcon for VBUS / ID notification to USB for uUSB */ struct extcon_dev *extcon; - int icl_reduction_ua; - /* qnovo */ int qnovo_fcc_ua; int qnovo_fv_uv; @@ -488,9 +487,10 @@ int smblib_rerun_apsd_if_required(struct smb_charger *chg); int smblib_get_prop_fcc_delta(struct smb_charger *chg, union power_supply_propval *val); int smblib_icl_override(struct smb_charger *chg, bool override); -int smblib_set_icl_reduction(struct smb_charger *chg, int reduction_ua); int smblib_dp_dm(struct smb_charger *chg, int val); int smblib_rerun_aicl(struct smb_charger *chg); +int smblib_set_icl_current(struct smb_charger *chg, int icl_ua); +int smblib_get_charge_current(struct smb_charger *chg, int *total_current_ua); int smblib_init(struct smb_charger *chg); int smblib_deinit(struct smb_charger *chg); diff --git a/drivers/power/supply/qcom/smb-reg.h b/drivers/power/supply/qcom/smb-reg.h index b79060094cf6..167666a8c548 100644 --- a/drivers/power/supply/qcom/smb-reg.h +++ b/drivers/power/supply/qcom/smb-reg.h @@ -919,6 +919,7 @@ enum { #define MISC_CFG_REG (MISC_BASE + 0x52) #define GSM_PA_ON_ADJ_SEL_BIT BIT(0) +#define STAT_PARALLEL_1400MA_EN_CFG_BIT BIT(3) #define TCC_DEBOUNCE_20MS_BIT BIT(5) #define SNARL_BARK_BITE_WD_CFG_REG (MISC_BASE + 0x53) diff --git a/drivers/power/supply/qcom/smb1351-charger.c b/drivers/power/supply/qcom/smb1351-charger.c index 8467d167512f..7014fd706d9e 100644 --- a/drivers/power/supply/qcom/smb1351-charger.c +++ b/drivers/power/supply/qcom/smb1351-charger.c @@ -1655,7 +1655,7 @@ static int smb1351_parallel_get_property(struct power_supply *psy, switch (prop) { case POWER_SUPPLY_PROP_CHARGING_ENABLED: - val->intval = !chip->usb_suspended_status; + val->intval = !chip->parallel_charger_suspended; break; case POWER_SUPPLY_PROP_CURRENT_MAX: if (!chip->parallel_charger_suspended) diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c index 4916c87aced8..694591c3ec56 100644 --- a/drivers/power/supply/qcom/smb138x-charger.c +++ b/drivers/power/supply/qcom/smb138x-charger.c @@ -577,13 +577,15 @@ static int smb138x_parallel_get_prop(struct power_supply *psy, rc = smblib_get_usb_suspend(chg, &val->intval); break; case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED: - if (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) + if ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) + || (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) rc = smblib_get_prop_input_current_limited(chg, val); else val->intval = 0; break; case POWER_SUPPLY_PROP_CURRENT_MAX: - if (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) + if ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) + || (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) rc = smblib_get_charge_param(chg, &chg->param.usb_icl, &val->intval); else @@ -669,7 +671,8 @@ static int smb138x_parallel_set_prop(struct power_supply *psy, rc = smb138x_set_parallel_suspend(chip, (bool)val->intval); break; case POWER_SUPPLY_PROP_CURRENT_MAX: - if (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) + if ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) + || (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) rc = smblib_set_charge_param(chg, &chg->param.usb_icl, val->intval); break; @@ -1484,7 +1487,8 @@ static int smb138x_slave_probe(struct smb138x *chip) goto cleanup; } - if (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) { + if ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) + || (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) { rc = smb138x_init_vbus_regulator(chip); if (rc < 0) { pr_err("Couldn't initialize vbus regulator rc=%d\n", diff --git a/drivers/pps/clients/pps-gpio.c b/drivers/pps/clients/pps-gpio.c index 333ad7d5b45b..da72b0b59c3a 100644 --- a/drivers/pps/clients/pps-gpio.c +++ b/drivers/pps/clients/pps-gpio.c @@ -57,7 +57,7 @@ static irqreturn_t pps_gpio_irq_handler(int irq, void *data) int rising_edge; /* Get the time stamp first */ - pps_get_ts(&ts); + get_monotonic_boottime(&ts.ts_real); info = data; diff --git a/drivers/regulator/qpnp-lcdb-regulator.c b/drivers/regulator/qpnp-lcdb-regulator.c index aef28dbeb931..724e8a4c00da 100644 --- a/drivers/regulator/qpnp-lcdb-regulator.c +++ b/drivers/regulator/qpnp-lcdb-regulator.c @@ -24,6 +24,7 @@ #include <linux/regulator/driver.h> #include <linux/regulator/of_regulator.h> #include <linux/regulator/machine.h> +#include <linux/qpnp/qpnp-revid.h> #define QPNP_LCDB_REGULATOR_DRIVER_NAME "qcom,qpnp-lcdb-regulator" @@ -192,6 +193,7 @@ struct qpnp_lcdb { struct device *dev; struct platform_device *pdev; struct regmap *regmap; + struct pmic_revid_data *pmic_rev_id; u32 base; int sc_irq; @@ -199,9 +201,6 @@ struct qpnp_lcdb { bool ttw_enable; bool ttw_mode_sw; - /* top level DT params */ - bool force_module_reenable; - /* status parameters */ bool lcdb_enabled; bool settings_saved; @@ -579,6 +578,65 @@ static int qpnp_lcdb_ttw_exit(struct qpnp_lcdb *lcdb) return 0; } +static int qpnp_lcdb_enable_wa(struct qpnp_lcdb *lcdb) +{ + int rc; + u8 val = 0; + + /* required only for PM660L */ + if (lcdb->pmic_rev_id->pmic_subtype != PM660L_SUBTYPE) + return 0; + + val = MODULE_EN_BIT; + rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG, + &val, 1); + if (rc < 0) { + pr_err("Failed to enable lcdb rc= %d\n", rc); + return rc; + } + + val = 0; + rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG, + &val, 1); + if (rc < 0) { + pr_err("Failed to disable lcdb rc= %d\n", rc); + return rc; + } + + /* execute the below for rev1.1 */ + if (lcdb->pmic_rev_id->rev3 == PM660L_V1P1_REV3 && + lcdb->pmic_rev_id->rev4 == PM660L_V1P1_REV4) { + /* + * delay to make sure that the MID pin – ie the + * output of the LCDB boost – returns to 0V + * after the module is disabled + */ + usleep_range(10000, 10100); + + rc = qpnp_lcdb_masked_write(lcdb, + lcdb->base + LCDB_MISC_CTL_REG, + DIS_SCP_BIT, DIS_SCP_BIT); + if (rc < 0) { + pr_err("Failed to disable SC rc=%d\n", rc); + return rc; + } + /* delay for SC-disable to take effect */ + usleep_range(1000, 1100); + + rc = qpnp_lcdb_masked_write(lcdb, + lcdb->base + LCDB_MISC_CTL_REG, + DIS_SCP_BIT, 0); + if (rc < 0) { + pr_err("Failed to enable SC rc=%d\n", rc); + return rc; + } + /* delay for SC-enable to take effect */ + usleep_range(1000, 1100); + } + + return 0; +} + static int qpnp_lcdb_enable(struct qpnp_lcdb *lcdb) { int rc = 0, timeout, delay; @@ -598,31 +656,20 @@ static int qpnp_lcdb_enable(struct qpnp_lcdb *lcdb) } } + rc = qpnp_lcdb_enable_wa(lcdb); + if (rc < 0) { + pr_err("Failed to execute enable_wa rc=%d\n", rc); + return rc; + } + val = MODULE_EN_BIT; rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG, &val, 1); if (rc < 0) { - pr_err("Failed to enable lcdb rc= %d\n", rc); + pr_err("Failed to disable lcdb rc= %d\n", rc); goto fail_enable; } - if (lcdb->force_module_reenable) { - val = 0; - rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG, - &val, 1); - if (rc < 0) { - pr_err("Failed to enable lcdb rc= %d\n", rc); - goto fail_enable; - } - val = MODULE_EN_BIT; - rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG, - &val, 1); - if (rc < 0) { - pr_err("Failed to disable lcdb rc= %d\n", rc); - goto fail_enable; - } - } - /* poll for vreg_ok */ timeout = 10; delay = lcdb->bst.soft_start_us + lcdb->ldo.soft_start_us + @@ -1674,7 +1721,8 @@ static int qpnp_lcdb_hw_init(struct qpnp_lcdb *lcdb) return rc; } - if (lcdb->sc_irq >= 0) { + if (lcdb->sc_irq >= 0 && + lcdb->pmic_rev_id->pmic_subtype != PM660L_SUBTYPE) { lcdb->sc_count = 0; rc = devm_request_threaded_irq(lcdb->dev, lcdb->sc_irq, NULL, qpnp_lcdb_sc_irq_handler, IRQF_ONESHOT, @@ -1714,7 +1762,23 @@ static int qpnp_lcdb_parse_dt(struct qpnp_lcdb *lcdb) { int rc = 0; const char *label; - struct device_node *temp, *node = lcdb->dev->of_node; + struct device_node *revid_dev_node, *temp, *node = lcdb->dev->of_node; + + revid_dev_node = of_parse_phandle(node, "qcom,pmic-revid", 0); + if (!revid_dev_node) { + pr_err("Missing qcom,pmic-revid property - fail driver\n"); + return -EINVAL; + } + + lcdb->pmic_rev_id = get_revid_data(revid_dev_node); + if (IS_ERR(lcdb->pmic_rev_id)) { + pr_debug("Unable to get revid data\n"); + /* + * revid should to be defined, return -EPROBE_DEFER + * until the revid module registers. + */ + return -EPROBE_DEFER; + } for_each_available_child_of_node(node, temp) { rc = of_property_read_string(temp, "label", &label); @@ -1742,9 +1806,6 @@ static int qpnp_lcdb_parse_dt(struct qpnp_lcdb *lcdb) } } - lcdb->force_module_reenable = of_property_read_bool(node, - "qcom,force-module-reenable"); - if (of_property_read_bool(node, "qcom,ttw-enable")) { rc = qpnp_lcdb_parse_ttw(lcdb); if (rc < 0) { diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index d5c00951cf93..5d81bcc1dc75 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2806,10 +2806,10 @@ static int sd_revalidate_disk(struct gendisk *disk) if (sdkp->opt_xfer_blocks && sdkp->opt_xfer_blocks <= dev_max && sdkp->opt_xfer_blocks <= SD_DEF_XFER_BLOCKS && - logical_to_bytes(sdp, sdkp->opt_xfer_blocks) >= PAGE_CACHE_SIZE) { - q->limits.io_opt = logical_to_bytes(sdp, sdkp->opt_xfer_blocks); - rw_max = logical_to_sectors(sdp, sdkp->opt_xfer_blocks); - } else + sdkp->opt_xfer_blocks * sdp->sector_size >= PAGE_CACHE_SIZE) + rw_max = q->limits.io_opt = + sdkp->opt_xfer_blocks * sdp->sector_size; + else rw_max = BLK_DEF_MAX_SECTORS; /* Combine with controller limits */ diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 765a6f1ac1b7..654630bb7d0e 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -151,11 +151,6 @@ static inline sector_t logical_to_sectors(struct scsi_device *sdev, sector_t blo return blocks << (ilog2(sdev->sector_size) - 9); } -static inline unsigned int logical_to_bytes(struct scsi_device *sdev, sector_t blocks) -{ - return blocks * sdev->sector_size; -} - /* * A DIF-capable target device can be formatted with different * protection schemes. Currently 0 through 3 are defined: diff --git a/drivers/scsi/ufs/ufs_quirks.c b/drivers/scsi/ufs/ufs_quirks.c index 176c3888aa34..7a501d6d7c84 100644 --- a/drivers/scsi/ufs/ufs_quirks.c +++ b/drivers/scsi/ufs/ufs_quirks.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -30,6 +30,20 @@ static struct ufs_card_fix ufs_fixups[] = { UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE), UFS_FIX(UFS_VENDOR_HYNIX, UFS_ANY_MODEL, UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME), + UFS_FIX(UFS_VENDOR_HYNIX, "hB8aL1", + UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH), + UFS_FIX(UFS_VENDOR_HYNIX, "hC8aL1", + UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH), + UFS_FIX(UFS_VENDOR_HYNIX, "hD8aL1", + UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH), + UFS_FIX(UFS_VENDOR_HYNIX, "hC8aM1", + UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH), + UFS_FIX(UFS_VENDOR_HYNIX, "h08aM1", + UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH), + UFS_FIX(UFS_VENDOR_HYNIX, "hC8GL1", + UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH), + UFS_FIX(UFS_VENDOR_HYNIX, "hC8HL1", + UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH), END_FIX }; diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h index b8ab5948f12d..3102517e841c 100644 --- a/drivers/scsi/ufs/ufs_quirks.h +++ b/drivers/scsi/ufs/ufs_quirks.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -139,6 +139,14 @@ struct ufs_card_fix { */ #define UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME (1 << 7) +/* + * Some UFS devices may stop responding after switching from HS-G1 to HS-G3. + * Also, it is found that these devices work fine if we do 2 steps switch: + * HS-G1 to HS-G2 followed by HS-G2 to HS-G3. Enabling this quirk for such + * device would apply this 2 steps gear switch workaround. + */ +#define UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH (1 << 8) + struct ufs_hba; void ufs_advertise_fixup_device(struct ufs_hba *hba); #endif /* UFS_QUIRKS_H_ */ diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index c891fc8d34a3..79bb3337ba36 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -509,7 +509,7 @@ out: /* replace non-printable or non-ASCII characters with spaces */ static inline void ufshcd_remove_non_printable(char *val) { - if (!val) + if (!val || !*val) return; if (*val < 0x20 || *val > 0x7e) @@ -1388,7 +1388,7 @@ static void ufshcd_gate_work(struct work_struct *work) * state to CLKS_ON. */ if (hba->clk_gating.is_suspended || - (hba->clk_gating.state == REQ_CLKS_ON)) { + (hba->clk_gating.state != REQ_CLKS_OFF)) { hba->clk_gating.state = CLKS_ON; trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state); @@ -3651,7 +3651,7 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, u8 *buf, goto out; } - buff_ascii = kmalloc(ascii_len, GFP_KERNEL); + buff_ascii = kzalloc(ascii_len, GFP_KERNEL); if (!buff_ascii) { dev_err(hba->dev, "%s: Failed allocating %d bytes\n", __func__, ascii_len); @@ -4289,15 +4289,25 @@ static int __ufshcd_uic_hibern8_enter(struct ufs_hba *hba) * mode hence full reinit is required to move link to HS speeds. */ if (ret || hba->full_init_linereset) { + int err; + hba->full_init_linereset = false; ufshcd_update_error_stats(hba, UFS_ERR_HIBERN8_ENTER); dev_err(hba->dev, "%s: hibern8 enter failed. ret = %d", __func__, ret); /* - * If link recovery fails then return error so that caller - * don't retry the hibern8 enter again. + * If link recovery fails then return error code (-ENOLINK) + * returned ufshcd_link_recovery(). + * If link recovery succeeds then return -EAGAIN to attempt + * hibern8 enter retry again. */ - ret = ufshcd_link_recovery(hba); + err = ufshcd_link_recovery(hba); + if (err) { + dev_err(hba->dev, "%s: link recovery failed", __func__); + ret = err; + } else { + ret = -EAGAIN; + } } else { dev_dbg(hba->dev, "%s: Hibern8 Enter at %lld us", __func__, ktime_to_us(ktime_get())); @@ -4314,8 +4324,8 @@ int ufshcd_uic_hibern8_enter(struct ufs_hba *hba) ret = __ufshcd_uic_hibern8_enter(hba); if (!ret) goto out; - /* Unable to recover the link, so no point proceeding */ - if (ret == -ENOLINK) + else if (ret != -EAGAIN) + /* Unable to recover the link, so no point proceeding */ BUG(); } out: @@ -9207,6 +9217,31 @@ static int ufshcd_scale_gear(struct ufs_hba *hba, bool scale_up) if (scale_up) { memcpy(&new_pwr_info, &hba->clk_scaling.saved_pwr_info.info, sizeof(struct ufs_pa_layer_attr)); + /* + * Some UFS devices may stop responding after switching from + * HS-G1 to HS-G3. Also, it is found that these devices work + * fine if we do 2 steps switch: HS-G1 to HS-G2 followed by + * HS-G2 to HS-G3. If UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH + * quirk is enabled for such devices, this 2 steps gear switch + * workaround will be applied. + */ + if ((hba->dev_quirks & UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH) + && (hba->pwr_info.gear_tx == UFS_HS_G1) + && (new_pwr_info.gear_tx == UFS_HS_G3)) { + /* scale up to G2 first */ + new_pwr_info.gear_tx = UFS_HS_G2; + new_pwr_info.gear_rx = UFS_HS_G2; + ret = ufshcd_change_power_mode(hba, &new_pwr_info); + if (ret) + goto out; + + /* scale up to G3 now */ + new_pwr_info.gear_tx = UFS_HS_G3; + new_pwr_info.gear_rx = UFS_HS_G3; + ret = ufshcd_change_power_mode(hba, &new_pwr_info); + if (ret) + goto out; + } } else { memcpy(&new_pwr_info, &hba->pwr_info, sizeof(struct ufs_pa_layer_attr)); @@ -9226,10 +9261,10 @@ static int ufshcd_scale_gear(struct ufs_hba *hba, bool scale_up) new_pwr_info.pwr_rx = FASTAUTO_MODE; } } + ret = ufshcd_change_power_mode(hba, &new_pwr_info); } - ret = ufshcd_change_power_mode(hba, &new_pwr_info); - +out: if (ret) dev_err(hba->dev, "%s: failed err %d, old gear: (tx %d rx %d), new gear: (tx %d rx %d), scale_up = %d", __func__, ret, @@ -9292,10 +9327,29 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up) goto clk_scaling_unprepare; } + /* + * If auto hibern8 is supported then put the link in + * hibern8 manually, this is to avoid auto hibern8 + * racing during clock frequency scaling sequence. + */ + if (ufshcd_is_auto_hibern8_supported(hba)) { + ret = ufshcd_uic_hibern8_enter(hba); + if (ret) + /* link will be bad state so no need to scale_up_gear */ + return ret; + } + ret = ufshcd_scale_clks(hba, scale_up); if (ret) goto scale_up_gear; + if (ufshcd_is_auto_hibern8_supported(hba)) { + ret = ufshcd_uic_hibern8_exit(hba); + if (ret) + /* link will be bad state so no need to scale_up_gear */ + return ret; + } + /* scale up the gear after scaling up clocks */ if (scale_up) { ret = ufshcd_scale_gear(hba, true); diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 70874da9d176..ab46eb70651c 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -48,6 +48,11 @@ #include <soc/qcom/socinfo.h> #include <soc/qcom/ramdump.h> +#ifdef CONFIG_WCNSS_MEM_PRE_ALLOC +#include <net/cnss_prealloc.h> +#endif + + #include "wlan_firmware_service_v01.h" #ifdef CONFIG_ICNSS_DEBUG @@ -1775,11 +1780,29 @@ static void icnss_qmi_wlfw_clnt_notify(struct qmi_handle *handle, } } +static int icnss_call_driver_uevent(struct icnss_priv *priv, + enum icnss_uevent uevent, void *data) +{ + struct icnss_uevent_data uevent_data; + + if (!priv->ops || !priv->ops->uevent) + return 0; + + icnss_pr_dbg("Calling driver uevent state: 0x%lx, uevent: %d\n", + priv->state, uevent); + + uevent_data.uevent = uevent; + uevent_data.data = data; + + return priv->ops->uevent(&priv->pdev->dev, &uevent_data); +} + static void icnss_qmi_wlfw_clnt_ind(struct qmi_handle *handle, unsigned int msg_id, void *msg, unsigned int msg_len, void *ind_cb_priv) { struct icnss_event_pd_service_down_data *event_data; + struct icnss_uevent_fw_down_data fw_down_data; if (!penv) return; @@ -1811,6 +1834,9 @@ static void icnss_qmi_wlfw_clnt_ind(struct qmi_handle *handle, return; event_data->crashed = true; event_data->fw_rejuvenate = true; + fw_down_data.crashed = true; + icnss_call_driver_uevent(penv, ICNSS_UEVENT_FW_DOWN, + &fw_down_data); icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN, 0, event_data); break; @@ -1924,23 +1950,6 @@ static int icnss_driver_event_server_exit(void *data) return 0; } -static int icnss_call_driver_uevent(struct icnss_priv *priv, - enum icnss_uevent uevent, void *data) -{ - struct icnss_uevent_data uevent_data; - - if (!priv->ops || !priv->ops->uevent) - return 0; - - icnss_pr_dbg("Calling driver uevent state: 0x%lx, uevent: %d\n", - priv->state, uevent); - - uevent_data.uevent = uevent; - uevent_data.data = data; - - return priv->ops->uevent(&priv->pdev->dev, &uevent_data); -} - static int icnss_call_driver_probe(struct icnss_priv *priv) { int ret; @@ -1959,6 +1968,8 @@ static int icnss_call_driver_probe(struct icnss_priv *priv) if (ret < 0) { icnss_pr_err("Driver probe failed: %d, state: 0x%lx\n", ret, priv->state); + wcnss_prealloc_check_memory_leak(); + wcnss_pre_alloc_reset(); goto out; } @@ -2088,6 +2099,8 @@ static int icnss_driver_event_register_driver(void *data) if (ret) { icnss_pr_err("Driver probe failed: %d, state: 0x%lx\n", ret, penv->state); + wcnss_prealloc_check_memory_leak(); + wcnss_pre_alloc_reset(); goto power_off; } @@ -2097,7 +2110,6 @@ static int icnss_driver_event_register_driver(void *data) power_off: icnss_hw_power_off(penv); - penv->ops = NULL; out: return ret; } @@ -2113,6 +2125,8 @@ static int icnss_driver_event_unregister_driver(void *data) penv->ops->remove(&penv->pdev->dev); clear_bit(ICNSS_DRIVER_PROBED, &penv->state); + wcnss_prealloc_check_memory_leak(); + wcnss_pre_alloc_reset(); penv->ops = NULL; @@ -2137,6 +2151,8 @@ static int icnss_call_driver_remove(struct icnss_priv *priv) penv->ops->remove(&priv->pdev->dev); clear_bit(ICNSS_DRIVER_PROBED, &priv->state); + wcnss_prealloc_check_memory_leak(); + wcnss_pre_alloc_reset(); icnss_hw_power_off(penv); @@ -2154,7 +2170,8 @@ static int icnss_fw_crashed(struct icnss_priv *priv, icnss_pm_stay_awake(priv); - icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_CRASHED, NULL); + if (test_bit(ICNSS_DRIVER_PROBED, &priv->state)) + icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_CRASHED, NULL); if (event_data->wdog_bite) { set_bit(ICNSS_WDOG_BITE, &priv->state); @@ -2320,6 +2337,7 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, struct notif_data *notif = data; struct icnss_priv *priv = container_of(nb, struct icnss_priv, modem_ssr_nb); + struct icnss_uevent_fw_down_data fw_down_data; icnss_pr_vdbg("Modem-Notify: event %lu\n", code); @@ -2352,6 +2370,9 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, if (notif->crashed == CRASH_STATUS_WDOG_BITE) event_data->wdog_bite = true; + fw_down_data.crashed = !!notif->crashed; + icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data); + icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN, ICNSS_EVENT_SYNC, event_data); @@ -2415,6 +2436,7 @@ static int icnss_service_notifier_notify(struct notifier_block *nb, service_notifier_nb); enum pd_subsys_state *state = data; struct icnss_event_pd_service_down_data *event_data; + struct icnss_uevent_fw_down_data fw_down_data; icnss_pr_dbg("PD service notification: 0x%lx state: 0x%lx\n", notification, priv->state); @@ -2450,6 +2472,8 @@ static int icnss_service_notifier_notify(struct notifier_block *nb, event_post: icnss_ignore_qmi_timeout(true); + fw_down_data.crashed = event_data->crashed; + icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data); icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN, ICNSS_EVENT_SYNC, event_data); done: @@ -2621,7 +2645,7 @@ int icnss_register_driver(struct icnss_driver_ops *ops) } ret = icnss_driver_event_post(ICNSS_DRIVER_EVENT_REGISTER_DRIVER, - ICNSS_EVENT_SYNC, ops); + 0, ops); if (ret == -EINTR) ret = 0; diff --git a/drivers/soc/qcom/msm_glink_pkt.c b/drivers/soc/qcom/msm_glink_pkt.c index 78f6a2aa8f66..a92e5c416678 100644 --- a/drivers/soc/qcom/msm_glink_pkt.c +++ b/drivers/soc/qcom/msm_glink_pkt.c @@ -625,14 +625,17 @@ ssize_t glink_pkt_read(struct file *file, return -ENETRESET; } + mutex_lock(&devp->ch_lock); if (!glink_rx_intent_exists(devp->handle, count)) { ret = glink_queue_rx_intent(devp->handle, devp, count); if (ret) { GLINK_PKT_ERR("%s: failed to queue_rx_intent ret[%d]\n", __func__, ret); + mutex_unlock(&devp->ch_lock); return ret; } } + mutex_unlock(&devp->ch_lock); GLINK_PKT_INFO("Begin %s on glink_pkt_dev id:%d buffer_size %zu\n", __func__, devp->i, count); diff --git a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c index d11ffdde23be..3a6d84140bc9 100644 --- a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c +++ b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c @@ -98,8 +98,7 @@ static int __apr_tal_write(struct apr_svc_ch_dev *apr_ch, void *data, unsigned long flags; spin_lock_irqsave(&apr_ch->w_lock, flags); - rc = glink_tx(apr_ch->handle, pkt_priv, data, len, - GLINK_TX_REQ_INTENT | GLINK_TX_ATOMIC); + rc = glink_tx(apr_ch->handle, pkt_priv, data, len, GLINK_TX_ATOMIC); spin_unlock_irqrestore(&apr_ch->w_lock, flags); if (rc) diff --git a/drivers/soc/qcom/service-locator.c b/drivers/soc/qcom/service-locator.c index 5ac2a58899f4..0625f75de373 100644 --- a/drivers/soc/qcom/service-locator.c +++ b/drivers/soc/qcom/service-locator.c @@ -266,8 +266,10 @@ static int service_locator_send_msg(struct pd_qmi_client_data *pd) if (!domains_read) { db_rev_count = pd->db_rev_count = resp->db_rev_count; pd->total_domains = resp->total_domains; - if (!resp->total_domains) - pr_info("No matching domains found\n"); + if (!resp->total_domains) { + pr_err("No matching domains found\n"); + goto out; + } pd->domain_list = kmalloc( sizeof(struct servreg_loc_entry_v01) * diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c index 6f75eee8f921..8efe18dcc98f 100644 --- a/drivers/spi/spi_qsd.c +++ b/drivers/spi/spi_qsd.c @@ -45,6 +45,8 @@ #include <linux/msm-bus-board.h> #include "spi_qsd.h" +#define SPI_MAX_BYTES_PER_WORD (4) + static int msm_spi_pm_resume_runtime(struct device *device); static int msm_spi_pm_suspend_runtime(struct device *device); static inline void msm_spi_dma_unmap_buffers(struct msm_spi *dd); @@ -438,10 +440,12 @@ static void msm_spi_read_word_from_fifo(struct msm_spi *dd) u32 data_in; int i; int shift; + int read_bytes = (dd->pack_words ? + SPI_MAX_BYTES_PER_WORD : dd->bytes_per_word); data_in = readl_relaxed(dd->base + SPI_INPUT_FIFO); if (dd->read_buf) { - for (i = 0; (i < dd->bytes_per_word) && + for (i = 0; (i < read_bytes) && dd->rx_bytes_remaining; i++) { /* The data format depends on bytes_per_word: 4 bytes: 0x12345678 @@ -454,8 +458,8 @@ static void msm_spi_read_word_from_fifo(struct msm_spi *dd) dd->rx_bytes_remaining--; } } else { - if (dd->rx_bytes_remaining >= dd->bytes_per_word) - dd->rx_bytes_remaining -= dd->bytes_per_word; + if (dd->rx_bytes_remaining >= read_bytes) + dd->rx_bytes_remaining -= read_bytes; else dd->rx_bytes_remaining = 0; } @@ -552,7 +556,7 @@ msm_spi_set_bpw_and_no_io_flags(struct msm_spi *dd, u32 *config, int n) if (n != (*config & SPI_CFG_N)) *config = (*config & ~SPI_CFG_N) | n; - if (dd->mode == SPI_BAM_MODE) { + if (dd->tx_mode == SPI_BAM_MODE) { if (dd->read_buf == NULL) *config |= SPI_NO_INPUT; if (dd->write_buf == NULL) @@ -617,25 +621,34 @@ static void msm_spi_set_spi_config(struct msm_spi *dd, int bpw) static void msm_spi_set_mx_counts(struct msm_spi *dd, u32 n_words) { /* - * n_words cannot exceed fifo_size, and only one READ COUNT - * interrupt is generated per transaction, so for transactions - * larger than fifo size READ COUNT must be disabled. - * For those transactions we usually move to Data Mover mode. + * For FIFO mode: + * - Set the MX_OUTPUT_COUNT/MX_INPUT_COUNT registers to 0 + * - Set the READ/WRITE_COUNT registers to 0 (infinite mode) + * or num bytes (finite mode) if less than fifo worth of data. + * For Block mode: + * - Set the MX_OUTPUT/MX_INPUT_COUNT registers to num xfer bytes. + * - Set the READ/WRITE_COUNT registers to 0. */ - if (dd->mode == SPI_FIFO_MODE) { - if (n_words <= dd->input_fifo_size) { - writel_relaxed(n_words, - dd->base + SPI_MX_READ_COUNT); - msm_spi_set_write_count(dd, n_words); - } else { - writel_relaxed(0, dd->base + SPI_MX_READ_COUNT); - msm_spi_set_write_count(dd, 0); - } - if (dd->qup_ver == SPI_QUP_VERSION_BFAM) { - /* must be zero for FIFO */ - writel_relaxed(0, dd->base + SPI_MX_INPUT_COUNT); + if (dd->tx_mode != SPI_BAM_MODE) { + if (dd->tx_mode == SPI_FIFO_MODE) { + if (n_words <= dd->input_fifo_size) + msm_spi_set_write_count(dd, n_words); + else + msm_spi_set_write_count(dd, 0); writel_relaxed(0, dd->base + SPI_MX_OUTPUT_COUNT); - } + } else + writel_relaxed(n_words, dd->base + SPI_MX_OUTPUT_COUNT); + + if (dd->rx_mode == SPI_FIFO_MODE) { + if (n_words <= dd->input_fifo_size) + writel_relaxed(n_words, + dd->base + SPI_MX_READ_COUNT); + else + writel_relaxed(0, + dd->base + SPI_MX_READ_COUNT); + writel_relaxed(0, dd->base + SPI_MX_INPUT_COUNT); + } else + writel_relaxed(n_words, dd->base + SPI_MX_INPUT_COUNT); } else { /* must be zero for BAM and DMOV */ writel_relaxed(0, dd->base + SPI_MX_READ_COUNT); @@ -882,7 +895,7 @@ xfr_err: static int msm_spi_bam_next_transfer(struct msm_spi *dd) { - if (dd->mode != SPI_BAM_MODE) + if (dd->tx_mode != SPI_BAM_MODE) return 0; if (dd->tx_bytes_remaining > 0) { @@ -901,7 +914,7 @@ msm_spi_bam_next_transfer(struct msm_spi *dd) static int msm_spi_dma_send_next(struct msm_spi *dd) { int ret = 0; - if (dd->mode == SPI_BAM_MODE) + if (dd->tx_mode == SPI_BAM_MODE) ret = msm_spi_bam_next_transfer(dd); return ret; } @@ -932,32 +945,38 @@ static inline irqreturn_t msm_spi_qup_irq(int irq, void *dev_id) } op = readl_relaxed(dd->base + SPI_OPERATIONAL); + writel_relaxed(op, dd->base + SPI_OPERATIONAL); + /* + * Ensure service flag was cleared before further + * processing of interrupt. + */ + mb(); if (op & SPI_OP_INPUT_SERVICE_FLAG) { - writel_relaxed(SPI_OP_INPUT_SERVICE_FLAG, - dd->base + SPI_OPERATIONAL); - /* - * Ensure service flag was cleared before further - * processing of interrupt. - */ - mb(); ret |= msm_spi_input_irq(irq, dev_id); } if (op & SPI_OP_OUTPUT_SERVICE_FLAG) { - writel_relaxed(SPI_OP_OUTPUT_SERVICE_FLAG, - dd->base + SPI_OPERATIONAL); - /* - * Ensure service flag was cleared before further - * processing of interrupt. - */ - mb(); ret |= msm_spi_output_irq(irq, dev_id); } - if (dd->done) { + if (dd->tx_mode != SPI_BAM_MODE) { + if (!dd->rx_done) { + if (dd->rx_bytes_remaining == 0) + dd->rx_done = true; + } + if (!dd->tx_done) { + if (!dd->tx_bytes_remaining && + (op & SPI_OP_IP_FIFO_NOT_EMPTY)) { + dd->tx_done = true; + } + } + } + if (dd->tx_done && dd->rx_done) { + msm_spi_set_state(dd, SPI_OP_STATE_RESET); + dd->tx_done = false; + dd->rx_done = false; complete(&dd->rx_transfer_complete); complete(&dd->tx_transfer_complete); - dd->done = 0; } return ret; } @@ -968,17 +987,23 @@ static irqreturn_t msm_spi_input_irq(int irq, void *dev_id) dd->stat_rx++; - if (dd->mode == SPI_MODE_NONE) + if (dd->rx_mode == SPI_MODE_NONE) return IRQ_HANDLED; - if (dd->mode == SPI_FIFO_MODE) { + if (dd->rx_mode == SPI_FIFO_MODE) { while ((readl_relaxed(dd->base + SPI_OPERATIONAL) & SPI_OP_IP_FIFO_NOT_EMPTY) && (dd->rx_bytes_remaining > 0)) { msm_spi_read_word_from_fifo(dd); } - if (dd->rx_bytes_remaining == 0) - msm_spi_complete(dd); + } else if (dd->rx_mode == SPI_BLOCK_MODE) { + int count = 0; + + while (dd->rx_bytes_remaining && + (count < dd->input_block_size)) { + msm_spi_read_word_from_fifo(dd); + count += SPI_MAX_BYTES_PER_WORD; + } } return IRQ_HANDLED; @@ -989,18 +1014,20 @@ static void msm_spi_write_word_to_fifo(struct msm_spi *dd) u32 word; u8 byte; int i; + int write_bytes = + (dd->pack_words ? SPI_MAX_BYTES_PER_WORD : dd->bytes_per_word); word = 0; if (dd->write_buf) { - for (i = 0; (i < dd->bytes_per_word) && + for (i = 0; (i < write_bytes) && dd->tx_bytes_remaining; i++) { dd->tx_bytes_remaining--; byte = *dd->write_buf++; word |= (byte << (BITS_PER_BYTE * i)); } } else - if (dd->tx_bytes_remaining > dd->bytes_per_word) - dd->tx_bytes_remaining -= dd->bytes_per_word; + if (dd->tx_bytes_remaining > write_bytes) + dd->tx_bytes_remaining -= write_bytes; else dd->tx_bytes_remaining = 0; dd->write_xfr_cnt++; @@ -1012,11 +1039,22 @@ static inline void msm_spi_write_rmn_to_fifo(struct msm_spi *dd) { int count = 0; - while ((dd->tx_bytes_remaining > 0) && (count < dd->input_fifo_size) && - !(readl_relaxed(dd->base + SPI_OPERATIONAL) & - SPI_OP_OUTPUT_FIFO_FULL)) { - msm_spi_write_word_to_fifo(dd); - count++; + if (dd->tx_mode == SPI_FIFO_MODE) { + while ((dd->tx_bytes_remaining > 0) && + (count < dd->input_fifo_size) && + !(readl_relaxed(dd->base + SPI_OPERATIONAL) + & SPI_OP_OUTPUT_FIFO_FULL)) { + msm_spi_write_word_to_fifo(dd); + count++; + } + } + + if (dd->tx_mode == SPI_BLOCK_MODE) { + while (dd->tx_bytes_remaining && + (count < dd->output_block_size)) { + msm_spi_write_word_to_fifo(dd); + count += SPI_MAX_BYTES_PER_WORD; + } } } @@ -1026,11 +1064,11 @@ static irqreturn_t msm_spi_output_irq(int irq, void *dev_id) dd->stat_tx++; - if (dd->mode == SPI_MODE_NONE) + if (dd->tx_mode == SPI_MODE_NONE) return IRQ_HANDLED; /* Output FIFO is empty. Transmit any outstanding write data. */ - if (dd->mode == SPI_FIFO_MODE) + if ((dd->tx_mode == SPI_FIFO_MODE) || (dd->tx_mode == SPI_BLOCK_MODE)) msm_spi_write_rmn_to_fifo(dd); return IRQ_HANDLED; @@ -1106,7 +1144,7 @@ error: static int msm_spi_dma_map_buffers(struct msm_spi *dd) { int ret = 0; - if (dd->mode == SPI_BAM_MODE) + if (dd->tx_mode == SPI_BAM_MODE) ret = msm_spi_bam_map_buffers(dd); return ret; } @@ -1135,7 +1173,7 @@ static void msm_spi_bam_unmap_buffers(struct msm_spi *dd) static inline void msm_spi_dma_unmap_buffers(struct msm_spi *dd) { - if (dd->mode == SPI_BAM_MODE) + if (dd->tx_mode == SPI_BAM_MODE) msm_spi_bam_unmap_buffers(dd); } @@ -1197,9 +1235,11 @@ static void msm_spi_set_transfer_mode(struct msm_spi *dd, u8 bpw, u32 read_count) { if (msm_spi_use_dma(dd, dd->cur_transfer, bpw)) { - dd->mode = SPI_BAM_MODE; + dd->tx_mode = SPI_BAM_MODE; + dd->rx_mode = SPI_BAM_MODE; } else { - dd->mode = SPI_FIFO_MODE; + dd->rx_mode = SPI_FIFO_MODE; + dd->tx_mode = SPI_FIFO_MODE; dd->read_len = dd->cur_transfer->len; dd->write_len = dd->cur_transfer->len; } @@ -1215,14 +1255,23 @@ static void msm_spi_set_qup_io_modes(struct msm_spi *dd) spi_iom = readl_relaxed(dd->base + SPI_IO_MODES); /* Set input and output transfer mode: FIFO, DMOV, or BAM */ spi_iom &= ~(SPI_IO_M_INPUT_MODE | SPI_IO_M_OUTPUT_MODE); - spi_iom = (spi_iom | (dd->mode << OUTPUT_MODE_SHIFT)); - spi_iom = (spi_iom | (dd->mode << INPUT_MODE_SHIFT)); - /* Turn on packing for data mover */ - if (dd->mode == SPI_BAM_MODE) + spi_iom = (spi_iom | (dd->tx_mode << OUTPUT_MODE_SHIFT)); + spi_iom = (spi_iom | (dd->rx_mode << INPUT_MODE_SHIFT)); + + /* Always enable packing for the BAM mode and for non BAM mode only + * if bpw is % 8 and transfer length is % 4 Bytes. + */ + if (dd->tx_mode == SPI_BAM_MODE || + ((dd->cur_msg_len % SPI_MAX_BYTES_PER_WORD == 0) && + (dd->cur_transfer->bits_per_word) && + (dd->cur_transfer->bits_per_word <= 32) && + (dd->cur_transfer->bits_per_word % 8 == 0))) { spi_iom |= SPI_IO_M_PACK_EN | SPI_IO_M_UNPACK_EN; - else { + dd->pack_words = true; + } else { spi_iom &= ~(SPI_IO_M_PACK_EN | SPI_IO_M_UNPACK_EN); spi_iom |= SPI_IO_M_OUTPUT_BIT_SHIFT_EN; + dd->pack_words = false; } /*if (dd->mode == SPI_BAM_MODE) { @@ -1280,7 +1329,7 @@ static void msm_spi_set_qup_op_mask(struct msm_spi *dd) { /* mask INPUT and OUTPUT service flags in to prevent IRQs on FIFO status * change in BAM mode */ - u32 mask = (dd->mode == SPI_BAM_MODE) ? + u32 mask = (dd->tx_mode == SPI_BAM_MODE) ? QUP_OP_MASK_OUTPUT_SERVICE_FLAG | QUP_OP_MASK_INPUT_SERVICE_FLAG : 0; writel_relaxed(mask, dd->base + QUP_OPERATIONAL_MASK); @@ -1321,6 +1370,8 @@ static int msm_spi_process_transfer(struct msm_spi *dd) dd->rx_bytes_remaining = dd->cur_msg_len; dd->read_buf = dd->cur_transfer->rx_buf; dd->write_buf = dd->cur_transfer->tx_buf; + dd->tx_done = false; + dd->rx_done = false; init_completion(&dd->tx_transfer_complete); init_completion(&dd->rx_transfer_complete); if (dd->cur_transfer->bits_per_word) @@ -1351,10 +1402,12 @@ static int msm_spi_process_transfer(struct msm_spi *dd) msm_spi_set_transfer_mode(dd, bpw, read_count); msm_spi_set_mx_counts(dd, read_count); - if (dd->mode == SPI_BAM_MODE) { + if (dd->tx_mode == SPI_BAM_MODE) { ret = msm_spi_dma_map_buffers(dd); if (ret < 0) { pr_err("Mapping DMA buffers\n"); + dd->tx_mode = SPI_MODE_NONE; + dd->rx_mode = SPI_MODE_NONE; return ret; } } @@ -1368,11 +1421,11 @@ static int msm_spi_process_transfer(struct msm_spi *dd) the first. Restricting this to one write avoids contention issues and race conditions between this thread and the int handler */ - if (dd->mode == SPI_FIFO_MODE) { + if (dd->tx_mode != SPI_BAM_MODE) { if (msm_spi_prepare_for_write(dd)) goto transfer_end; msm_spi_start_write(dd, read_count); - } else if (dd->mode == SPI_BAM_MODE) { + } else { if ((msm_spi_bam_begin_transfer(dd)) < 0) { dev_err(dd->dev, "%s: BAM transfer setup failed\n", __func__); @@ -1388,11 +1441,11 @@ static int msm_spi_process_transfer(struct msm_spi *dd) * might fire before the first word is written resulting in a * possible race condition. */ - if (dd->mode != SPI_BAM_MODE) + if (dd->tx_mode != SPI_BAM_MODE) if (msm_spi_set_state(dd, SPI_OP_STATE_RUN)) { dev_warn(dd->dev, "%s: Failed to set QUP to run-state. Mode:%d", - __func__, dd->mode); + __func__, dd->tx_mode); goto transfer_end; } @@ -1422,10 +1475,11 @@ static int msm_spi_process_transfer(struct msm_spi *dd) msm_spi_udelay(dd->xfrs_delay_usec); transfer_end: - if ((dd->mode == SPI_BAM_MODE) && status) + if ((dd->tx_mode == SPI_BAM_MODE) && status) msm_spi_bam_flush(dd); msm_spi_dma_unmap_buffers(dd); - dd->mode = SPI_MODE_NONE; + dd->tx_mode = SPI_MODE_NONE; + dd->rx_mode = SPI_MODE_NONE; msm_spi_set_state(dd, SPI_OP_STATE_RESET); if (!dd->cur_transfer->cs_change) @@ -2349,7 +2403,8 @@ static int init_resources(struct platform_device *pdev) pclk_enabled = 0; dd->transfer_pending = 0; - dd->mode = SPI_MODE_NONE; + dd->tx_mode = SPI_MODE_NONE; + dd->rx_mode = SPI_MODE_NONE; rc = msm_spi_request_irq(dd, pdev, master); if (rc) diff --git a/drivers/spi/spi_qsd.h b/drivers/spi/spi_qsd.h index 7a5cfadaa5a0..47d69965f18a 100644 --- a/drivers/spi/spi_qsd.h +++ b/drivers/spi/spi_qsd.h @@ -113,6 +113,8 @@ #define INPUT_MODE_SHIFT QSD_REG(10) QUP_REG(12) /* SPI_OPERATIONAL fields */ +#define SPI_OP_IN_BLK_RD_REQ_FLAG 0x00002000 +#define SPI_OP_OUT_BLK_WR_REQ_FLAG 0x00001000 #define SPI_OP_MAX_INPUT_DONE_FLAG 0x00000800 #define SPI_OP_MAX_OUTPUT_DONE_FLAG 0x00000400 #define SPI_OP_INPUT_SERVICE_FLAG 0x00000200 @@ -321,7 +323,8 @@ struct msm_spi { bool transfer_pending; wait_queue_head_t continue_suspend; /* DMA data */ - enum msm_spi_mode mode; + enum msm_spi_mode tx_mode; + enum msm_spi_mode rx_mode; bool use_dma; int tx_dma_chan; int tx_dma_crci; @@ -353,7 +356,8 @@ struct msm_spi { #endif struct msm_spi_platform_data *pdata; /* Platform data */ /* When set indicates multiple transfers in a single message */ - bool done; + bool rx_done; + bool tx_done; u32 cur_msg_len; /* Used in FIFO mode to keep track of the transfer being processed */ struct spi_transfer *cur_tx_transfer; @@ -371,6 +375,7 @@ struct msm_spi { struct pinctrl_state *pins_active; struct pinctrl_state *pins_sleep; bool is_init_complete; + bool pack_words; }; /* Forward declaration */ @@ -524,7 +529,8 @@ static inline void msm_spi_set_write_count(struct msm_spi *dd, int val) static inline void msm_spi_complete(struct msm_spi *dd) { - dd->done = 1; + dd->tx_done = true; + dd->rx_done = true; } static inline void msm_spi_enable_error_flags(struct msm_spi *dd) diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c index b5905fc81147..dfb6d2f77af1 100644 --- a/drivers/staging/android/ion/ion_cma_heap.c +++ b/drivers/staging/android/ion/ion_cma_heap.c @@ -238,7 +238,7 @@ void ion_cma_heap_destroy(struct ion_heap *heap) static void ion_secure_cma_free(struct ion_buffer *buffer) { int ret = 0; - u32 source_vm; + int source_vm; int dest_vmid; int dest_perms; struct ion_cma_buffer_info *info = buffer->priv_virt; diff --git a/drivers/staging/android/ion/ion_system_secure_heap.c b/drivers/staging/android/ion/ion_system_secure_heap.c index ec09f9f12b47..803811597f37 100644 --- a/drivers/staging/android/ion/ion_system_secure_heap.c +++ b/drivers/staging/android/ion/ion_system_secure_heap.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -78,7 +78,7 @@ int ion_system_secure_heap_unassign_sg(struct sg_table *sgt, int source_vmid) int ion_system_secure_heap_assign_sg(struct sg_table *sgt, int dest_vmid) { - u32 source_vmid = VMID_HLOS; + int source_vmid = VMID_HLOS; u32 dest_perms = PERM_READ | PERM_WRITE; struct scatterlist *sg; int ret, i; diff --git a/drivers/thermal/msm_thermal-dev.c b/drivers/thermal/msm_thermal-dev.c index e6af6b884e99..ead9765666c8 100644 --- a/drivers/thermal/msm_thermal-dev.c +++ b/drivers/thermal/msm_thermal-dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -35,6 +35,7 @@ static unsigned int freq_table_len[NR_CPUS], freq_table_set[NR_CPUS]; static unsigned int voltage_table_set[NR_CPUS]; static unsigned int *freq_table_ptr[NR_CPUS]; static uint32_t *voltage_table_ptr[NR_CPUS]; +static DEFINE_MUTEX(ioctl_access_mutex); static int msm_thermal_ioctl_open(struct inode *node, struct file *filep) { @@ -291,8 +292,9 @@ static long msm_thermal_ioctl_process(struct file *filep, unsigned int cmd, ret = validate_and_copy(&cmd, &arg, &query); if (ret) - goto process_exit; + return ret; + mutex_lock(&ioctl_access_mutex); switch (cmd) { case MSM_THERMAL_SET_CPU_MAX_FREQUENCY: ret = msm_thermal_set_frequency(query.cpu_freq.cpu_num, @@ -321,6 +323,7 @@ static long msm_thermal_ioctl_process(struct file *filep, unsigned int cmd, goto process_exit; } process_exit: + mutex_unlock(&ioctl_access_mutex); return ret; } diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 5b648460e621..c2eba06f2ace 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -670,6 +670,16 @@ int dwc3_core_init(struct dwc3 *dwc) } } + /* + * Workaround for STAR 9000961433 which affects only version + * 3.00a of the DWC_usb3 core. This prevents the controller + * interrupt from being masked while handling events. IMOD + * allows us to work around this issue. Enable it for the + * affected version. + */ + if (!dwc->imod_interval && (dwc->revision == DWC3_REVISION_300A)) + dwc->imod_interval = 1; + ret = dwc3_core_reset(dwc); if (ret) goto err0; @@ -1000,6 +1010,15 @@ err0: #define DWC3_ALIGN_MASK (16 - 1) +/* check whether the core supports IMOD */ +bool dwc3_has_imod(struct dwc3 *dwc) +{ + return ((dwc3_is_usb3(dwc) && + dwc->revision >= DWC3_REVISION_300A) || + (dwc3_is_usb31(dwc) && + dwc->revision >= DWC3_USB31_REVISION_120A)); +} + static int dwc3_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1040,8 +1059,8 @@ static int dwc3_probe(struct platform_device *pdev) /* will be enabled in dwc3_msm_resume() */ irq_set_status_flags(irq, IRQ_NOAUTOEN); - ret = devm_request_threaded_irq(dev, irq, NULL, dwc3_interrupt, - IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc); + ret = devm_request_irq(dev, irq, dwc3_interrupt, IRQF_SHARED, "dwc3", + dwc); if (ret) { dev_err(dwc->dev, "failed to request irq #%d --> %d\n", irq, ret); @@ -1219,6 +1238,14 @@ static int dwc3_probe(struct platform_device *pdev) dev->dma_parms = dev->parent->dma_parms; dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask); + dwc->dwc_wq = alloc_ordered_workqueue("dwc_wq", WQ_HIGHPRI); + if (!dwc->dwc_wq) { + pr_err("%s: Unable to create workqueue dwc_wq\n", __func__); + return -ENOMEM; + } + + INIT_WORK(&dwc->bh_work, dwc3_bh_work); + pm_runtime_no_callbacks(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); @@ -1284,6 +1311,7 @@ err0: * memory region the next time probe is called. */ res->start -= DWC3_GLOBALS_REGS_START; + destroy_workqueue(dwc->dwc_wq); return ret; } @@ -1313,6 +1341,8 @@ static int dwc3_remove(struct platform_device *pdev) dwc3_core_exit(dwc); dwc3_ulpi_exit(dwc); + destroy_workqueue(dwc->dwc_wq); + pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index f6e2bea7b9aa..453eee734b23 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -66,6 +66,7 @@ #define DWC3_DEVICE_EVENT_OVERFLOW 11 #define DWC3_GEVNTCOUNT_MASK 0xfffc +#define DWC3_GEVNTCOUNT_EHB (1 << 31) #define DWC3_GSNPSID_MASK 0xffff0000 #define DWC3_GSNPSREV_MASK 0xffff @@ -149,6 +150,8 @@ #define DWC3_DEPCMDPAR0(n) (0xc808 + (n * 0x10)) #define DWC3_DEPCMD(n) (0xc80c + (n * 0x10)) +#define DWC3_DEV_IMOD(n) (0xca00 + (n * 0x4)) + /* OTG Registers */ #define DWC3_OCFG 0xcc00 #define DWC3_OCTL 0xcc04 @@ -433,6 +436,11 @@ #define DWC3_DEPCMD_TYPE_BULK 2 #define DWC3_DEPCMD_TYPE_INTR 3 +#define DWC3_DEV_IMOD_COUNT_SHIFT 16 +#define DWC3_DEV_IMOD_COUNT_MASK (0xffff << 16) +#define DWC3_DEV_IMOD_INTERVAL_SHIFT 0 +#define DWC3_DEV_IMOD_INTERVAL_MASK (0xffff << 0) + /* Structures */ struct dwc3_trb; @@ -837,6 +845,8 @@ struct dwc3_scratchpad_array { * @bh_dbg_index: index for capturing bh_completion_time and bh_handled_evt_cnt * @wait_linkstate: waitqueue for waiting LINK to move into required state * @vbus_draw: current to be drawn from USB + * @imod_interval: set the interrupt moderation interval in 250ns + * increments or 0 to disable. */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; @@ -920,6 +930,7 @@ struct dwc3 { #define DWC3_REVISION_260A 0x5533260a #define DWC3_REVISION_270A 0x5533270a #define DWC3_REVISION_280A 0x5533280a +#define DWC3_REVISION_300A 0x5533300a #define DWC3_REVISION_310A 0x5533310a /* @@ -928,6 +939,7 @@ struct dwc3 { */ #define DWC3_REVISION_IS_DWC31 0x80000000 #define DWC3_USB31_REVISION_110A (0x3131302a | DWC3_REVISION_IS_USB31) +#define DWC3_USB31_REVISION_120A (0x3132302a | DWC3_REVISION_IS_DWC31) enum dwc3_ep0_next ep0_next_event; enum dwc3_ep0_state ep0state; @@ -1008,6 +1020,11 @@ struct dwc3 { bool b_suspend; unsigned vbus_draw; + u16 imod_interval; + + struct workqueue_struct *dwc_wq; + struct work_struct bh_work; + /* IRQ timing statistics */ int irq; unsigned long irq_cnt; @@ -1175,6 +1192,20 @@ struct dwc3_gadget_ep_cmd_params { void dwc3_set_mode(struct dwc3 *dwc, u32 mode); int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc); +/* check whether we are on the DWC_usb3 core */ +static inline bool dwc3_is_usb3(struct dwc3 *dwc) +{ + return !(dwc->revision & DWC3_REVISION_IS_DWC31); +} + +/* check whether we are on the DWC_usb31 core */ +static inline bool dwc3_is_usb31(struct dwc3 *dwc) +{ + return !!(dwc->revision & DWC3_REVISION_IS_DWC31); +} + +bool dwc3_has_imod(struct dwc3 *dwc); + #if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) int dwc3_host_init(struct dwc3 *dwc); void dwc3_host_exit(struct dwc3 *dwc); diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 623f3ce211aa..a80fb34cdce8 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -2053,6 +2053,9 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) if (dwc->irq) disable_irq(dwc->irq); + if (work_busy(&dwc->bh_work)) + dbg_event(0xFF, "pend evt", 0); + /* disable power event irq, hs and ss phy irq is used as wake up src */ disable_irq(mdwc->pwr_event_irq); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index e1284b6cc2ef..9608a79cbe40 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2011,6 +2011,17 @@ static int __dwc3_gadget_start(struct dwc3 *dwc) int ret = 0; u32 reg; + /* + * Use IMOD if enabled via dwc->imod_interval. Otherwise, if + * the core supports IMOD, disable it. + */ + if (dwc->imod_interval) { + dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval); + dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB); + } else if (dwc3_has_imod(dwc)) { + dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), 0); + } + reg = dwc3_readl(dwc->regs, DWC3_DCFG); reg &= ~(DWC3_DCFG_SPEED_MASK); @@ -3362,8 +3373,6 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) */ evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE; left -= 4; - - dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4); } dwc->bh_handled_evt_cnt[dwc->bh_dbg_index] += (evt->count / 4); @@ -3377,9 +3386,22 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) reg &= ~DWC3_GEVNTSIZ_INTMASK; dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg); + if (dwc->imod_interval) + dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), + DWC3_GEVNTCOUNT_EHB); + return ret; } +void dwc3_bh_work(struct work_struct *w) +{ + struct dwc3 *dwc = container_of(w, struct dwc3, bh_work); + + pm_runtime_get_sync(dwc->dev); + dwc3_thread_interrupt(dwc->irq, dwc); + pm_runtime_put(dwc->dev); +} + static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc) { struct dwc3 *dwc = _dwc; @@ -3434,6 +3456,8 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc, u32 buf) reg |= DWC3_GEVNTSIZ_INTMASK; dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg); + dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), count); + return IRQ_WAKE_THREAD; } @@ -3469,7 +3493,7 @@ irqreturn_t dwc3_interrupt(int irq, void *_dwc) dwc->irq_dbg_index = (dwc->irq_dbg_index + 1) % MAX_INTR_STATS; if (ret == IRQ_WAKE_THREAD) - dwc3_thread_interrupt(dwc->irq, dwc); + queue_work(dwc->dwc_wq, &dwc->bh_work); return IRQ_HANDLED; } diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index 99ff6df063a7..baa83cf9638b 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -105,6 +105,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol); void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force); irqreturn_t dwc3_interrupt(int irq, void *_dwc); +void dwc3_bh_work(struct work_struct *w); static inline dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep, struct dwc3_trb *trb) diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index ed0ff7b1fc15..c31aaf7a9880 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -141,21 +141,28 @@ struct gadget_config_name { struct list_head list; }; +#define MAX_USB_STRING_LEN 126 +#define MAX_USB_STRING_WITH_NULL_LEN (MAX_USB_STRING_LEN+1) + static int usb_string_copy(const char *s, char **s_copy) { int ret; char *str; char *copy = *s_copy; ret = strlen(s); - if (ret > 126) + if (ret > MAX_USB_STRING_LEN) return -EOVERFLOW; - str = kstrdup(s, GFP_KERNEL); - if (!str) - return -ENOMEM; + if (copy) { + str = copy; + } else { + str = kmalloc(MAX_USB_STRING_WITH_NULL_LEN, GFP_KERNEL); + if (!str) + return -ENOMEM; + } + strncpy(str, s, MAX_USB_STRING_WITH_NULL_LEN); if (str[ret - 1] == '\n') str[ret - 1] = '\0'; - kfree(copy); *s_copy = str; return 0; } diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index be532503954f..7216fdd4245d 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -1550,13 +1550,6 @@ static void gsi_ctrl_notify_resp_complete(struct usb_ep *ep, event->bNotificationType, req->status); /* FALLTHROUGH */ case 0: - /* - * handle multiple pending resp available - * notifications by queuing same until we're done, - * rest of the notification require queuing new - * request. - */ - gsi_ctrl_send_notification(gsi); break; } } @@ -1651,6 +1644,14 @@ static void gsi_ctrl_reset_cmd_complete(struct usb_ep *ep, gsi_ctrl_send_cpkt_tomodem(gsi, req->buf, 0); } +static void gsi_ctrl_send_response_complete(struct usb_ep *ep, + struct usb_request *req) +{ + struct f_gsi *gsi = req->context; + + gsi_ctrl_send_notification(gsi); +} + static int gsi_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) { @@ -1737,6 +1738,8 @@ gsi_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) memcpy(req->buf, cpkt->buf, value); gsi_ctrl_pkt_free(cpkt); + req->complete = gsi_ctrl_send_response_complete; + req->context = gsi; log_event_dbg("copied encap_resp %d bytes", value); break; diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 7423645c204c..1ddf882fb607 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -245,7 +245,7 @@ static int xhci_plat_probe(struct platform_device *pdev) goto put_usb3_hcd; } - ret = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_ONESHOT); + ret = usb_add_hcd(hcd, irq, IRQF_SHARED); if (ret) goto disable_usb_phy; @@ -254,7 +254,7 @@ static int xhci_plat_probe(struct platform_device *pdev) if (HCC_MAX_PSA(xhci->hcc_params) >= 4) xhci->shared_hcd->can_do_streams = 1; - ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED | IRQF_ONESHOT); + ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED); if (ret) goto dealloc_usb2_hcd; diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c index 2d499ef903d3..226198efbeec 100644 --- a/drivers/video/fbdev/msm/mdss_dp.c +++ b/drivers/video/fbdev/msm/mdss_dp.c @@ -1512,8 +1512,14 @@ exit_loop: pr_debug("end\n"); - /* Send a connect notification */ - if (!mdss_dp_is_phy_test_pattern_requested(dp_drv)) + /* + * Send a connect notification to clients except when processing link + * training and electrical compliance tests. There is no need to send + * a notification in these testing use cases as there is no + * expectation of receiving a video signal as part of the test. + */ + if (!mdss_dp_is_phy_test_pattern_requested(dp_drv) && + !mdss_dp_is_link_training_requested(dp_drv)) mdss_dp_notify_clients(dp_drv, NOTIFY_CONNECT_IRQ_HPD); return ret; @@ -1609,6 +1615,14 @@ int mdss_dp_on(struct mdss_panel_data *pdata) panel_data); if (dp_drv->power_on) { + /* + * Acknowledge the connection event if link training has already + * been done. This will unblock the external display thread and + * allow the driver to progress. For example, in the case of + * video test pattern requests, to send the test response and + * start transmitting the test pattern. + */ + mdss_dp_ack_state(dp_drv, true); pr_debug("Link already setup, return\n"); return 0; } diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c index bf701e2a4ac5..6f20c0ed0455 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_panel.c +++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c @@ -365,13 +365,17 @@ int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable) if (gpio_is_valid(ctrl_pdata->bklt_en_gpio)) { - if (ctrl_pdata->bklt_en_gpio_invert) + if (ctrl_pdata->bklt_en_gpio_invert) { rc = gpio_direction_output( ctrl_pdata->bklt_en_gpio, 0); - else + gpio_set_value( + (ctrl_pdata->bklt_en_gpio), 0); + } else { rc = gpio_direction_output( ctrl_pdata->bklt_en_gpio, 1); - + gpio_set_value( + (ctrl_pdata->bklt_en_gpio), 1); + } if (rc) { pr_err("%s: unable to set dir for bklt gpio\n", __func__); diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index fe79b6fd52b4..fc47de7692e7 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -301,6 +301,7 @@ static void mdss_fb_set_bl_brightness(struct led_classdev *led_cdev, mdss_fb_set_backlight(mfd, bl_lvl); mutex_unlock(&mfd->bl_lock); } + mfd->bl_level_usr = bl_lvl; } static enum led_brightness mdss_fb_get_bl_brightness( @@ -309,7 +310,7 @@ static enum led_brightness mdss_fb_get_bl_brightness( struct msm_fb_data_type *mfd = dev_get_drvdata(led_cdev->dev->parent); enum led_brightness value; - MDSS_BL_TO_BRIGHT(value, mfd->bl_level, mfd->panel_info->bl_max, + MDSS_BL_TO_BRIGHT(value, mfd->bl_level_usr, mfd->panel_info->bl_max, mfd->panel_info->brightness_max); return value; @@ -1276,6 +1277,7 @@ static int mdss_fb_probe(struct platform_device *pdev) mfd->calib_mode_bl = 0; mfd->unset_bl_level = U32_MAX; mfd->bl_extn_level = -1; + mfd->bl_level_usr = backlight_led.brightness; mfd->pdev = pdev; diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h index 321531c72a08..f046ff08cbf7 100644 --- a/drivers/video/fbdev/msm/mdss_fb.h +++ b/drivers/video/fbdev/msm/mdss_fb.h @@ -314,6 +314,7 @@ struct msm_fb_data_type { u32 unset_bl_level; bool allow_bl_update; u32 bl_level_scaled; + u32 bl_level_usr; struct mutex bl_lock; struct mutex mdss_sysfs_lock; bool ipc_resume; diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index bd70535e79f9..49348e5e16a9 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -6061,6 +6061,7 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg, mutex_lock(&ctl->mfd->bl_lock); mdss_fb_set_backlight(ctl->mfd, ctl->mfd->bl_extn_level); + ctl->mfd->bl_level_usr = ctl->mfd->bl_extn_level; mutex_unlock(&ctl->mfd->bl_lock); } } diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index 5daa8a7a2752..8eb12d764be3 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -48,6 +48,12 @@ #define BUF_POOL_SIZE 32 +#define DFPS_DATA_MAX_HFP 8192 +#define DFPS_DATA_MAX_HBP 8192 +#define DFPS_DATA_MAX_HPW 8192 +#define DFPS_DATA_MAX_FPS 0x7fffffff +#define DFPS_DATA_MAX_CLK_RATE 250000 + static int mdss_mdp_overlay_free_fb_pipe(struct msm_fb_data_type *mfd); static int mdss_mdp_overlay_fb_parse_dt(struct msm_fb_data_type *mfd); static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd); @@ -519,16 +525,16 @@ static int __mdss_mdp_validate_pxl_extn(struct mdss_mdp_pipe *pipe) return 0; } + static int __mdss_mdp_validate_qseed3_cfg(struct mdss_mdp_pipe *pipe) { int plane; for (plane = 0; plane < MAX_PLANES; plane++) { u32 hor_req_pixels, hor_fetch_pixels; - u32 hor_ov_fetch, vert_ov_fetch; u32 vert_req_pixels, vert_fetch_pixels; - u32 src_w = DECIMATED_DIMENSION(pipe->src.w, pipe->horz_deci); - u32 src_h = DECIMATED_DIMENSION(pipe->src.h, pipe->vert_deci); + u32 src_w = pipe->src.w; + u32 src_h = pipe->src.h; /* * plane 1 and 2 are for chroma and are same. While configuring @@ -545,9 +551,8 @@ static int __mdss_mdp_validate_qseed3_cfg(struct mdss_mdp_pipe *pipe) */ if (plane == 1 && !pipe->horz_deci && ((pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_420) || - (pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_H2V1))) { + (pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_H2V1))) src_w >>= 1; - } if (plane == 1 && !pipe->vert_deci && ((pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_420) || @@ -556,39 +561,37 @@ static int __mdss_mdp_validate_qseed3_cfg(struct mdss_mdp_pipe *pipe) hor_req_pixels = pipe->scaler.num_ext_pxls_left[plane]; - hor_fetch_pixels = src_w + - (pipe->scaler.left_ftch[plane] >> pipe->horz_deci) + - pipe->scaler.left_rpt[plane] + - (pipe->scaler.right_ftch[plane] >> pipe->horz_deci) + - pipe->scaler.right_rpt[plane]; - - hor_ov_fetch = src_w + - (pipe->scaler.left_ftch[plane] >> pipe->horz_deci) + - (pipe->scaler.right_ftch[plane] >> pipe->horz_deci); + /** + * libscaler provides the fetch values before decimation + * and the rpt values are always 0, since qseed3 block + * internally does the repeat. + */ + hor_fetch_pixels = DECIMATED_DIMENSION(src_w + + (int8_t)(pipe->scaler.left_ftch[plane] + & 0xFF) + + (int8_t)(pipe->scaler.right_ftch[plane] + & 0xFF), + pipe->horz_deci); vert_req_pixels = pipe->scaler.num_ext_pxls_top[plane]; - vert_fetch_pixels = src_h + - (pipe->scaler.top_ftch[plane] >> pipe->vert_deci) + - pipe->scaler.top_rpt[plane] + - (pipe->scaler.btm_ftch[plane] >> pipe->vert_deci) + - pipe->scaler.btm_rpt[plane]; - - vert_ov_fetch = src_h + - (pipe->scaler.top_ftch[plane] >> pipe->vert_deci) + - (pipe->scaler.btm_ftch[plane] >> pipe->vert_deci); + vert_fetch_pixels = DECIMATED_DIMENSION(src_h + + (int8_t)(pipe->scaler.top_ftch[plane] + & 0xFF)+ + (int8_t)(pipe->scaler.btm_ftch[plane] + & 0xFF), + pipe->vert_deci); if ((hor_req_pixels != hor_fetch_pixels) || - (hor_ov_fetch > pipe->img_width) || + (hor_fetch_pixels > pipe->img_width) || (vert_req_pixels != vert_fetch_pixels) || - (vert_ov_fetch > pipe->img_height)) { - pr_err("err: plane=%d h_req:%d h_fetch:%d v_req:%d v_fetch:%d src_img[%d %d] ov_fetch[%d %d]\n", + (vert_fetch_pixels > pipe->img_height)) { + pr_err("err: plane=%d h_req:%d h_fetch:%d v_req:%d v_fetch:%d src_img[%d %d]\n", plane, hor_req_pixels, hor_fetch_pixels, vert_req_pixels, vert_fetch_pixels, - pipe->img_width, pipe->img_height, - hor_ov_fetch, vert_ov_fetch); + pipe->img_width, pipe->img_height); pipe->scaler.enable = 0; return -EINVAL; } @@ -3519,6 +3522,13 @@ static ssize_t dynamic_fps_sysfs_wta_dfps(struct device *dev, return count; } + if (data.hfp > DFPS_DATA_MAX_HFP || data.hbp > DFPS_DATA_MAX_HBP || + data.hpw > DFPS_DATA_MAX_HPW || data.fps > DFPS_DATA_MAX_FPS || + data.clk_rate > DFPS_DATA_MAX_CLK_RATE){ + pr_err("Data values out of bound.\n"); + return -EINVAL; + } + rc = mdss_mdp_dfps_update_params(mfd, pdata, &data); if (rc) { pr_err("failed to set dfps params\n"); diff --git a/include/linux/input/synaptics_dsx_v2_6.h b/include/linux/input/synaptics_dsx_v2_6.h deleted file mode 100644 index 5d4bbedb5f1a..000000000000 --- a/include/linux/input/synaptics_dsx_v2_6.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Synaptics DSX touchscreen driver - * - * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved. - * - * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com> - * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com> - * 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 as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - * - * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS - * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, - * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS. - * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION - * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED - * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES - * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' - * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. - * DOLLARS. - */ - -#ifndef _SYNAPTICS_DSX_H_ -#define _SYNAPTICS_DSX_H_ - -#define PLATFORM_DRIVER_NAME "synaptics_dsxv26" -#define STYLUS_DRIVER_NAME "synaptics_dsxv26_stylus" -#define ACTIVE_PEN_DRIVER_NAME "synaptics_dsxv26_active_pen" -#define PROXIMITY_DRIVER_NAME "synaptics_dsxv26_proximity" -#define GESTURE_DRIVER_NAME "synaptics_dsxv26_gesture" -#define I2C_DRIVER_NAME "synaptics_dsxv26" -#define SPI_DRIVER_NAME "synaptics_dsxv26" - -/* - * struct synaptics_dsx_button_map - button map - * @nbuttons: number of buttons - * @map: pointer to array of button codes - */ -struct synaptics_dsx_button_map { - unsigned char nbuttons; - unsigned int *map; -}; - -/* - * struct synaptics_dsx_board_data - DSX board data - * @x_flip: x flip flag - * @y_flip: y flip flag - * @swap_axes: swap axes flag - * @resume_in_workqueue: defer resume function to workqueue - * @irq_gpio: attention interrupt GPIO - * @irq_on_state: attention interrupt active state - * @power_gpio: power switch GPIO - * @power_on_state: power switch active state - * @reset_gpio: reset GPIO - * @reset_on_state: reset active state - * @max_y_for_2d: maximum y value for 2D area when virtual buttons are present - * @irq_flags: IRQ flags - * @i2c_addr: I2C slave address - * @ub_i2c_addr: microbootloader mode I2C slave address - * @device_descriptor_addr: HID device descriptor address - * @panel_x: x-axis resolution of display panel - * @panel_y: y-axis resolution of display panel - * @power_delay_ms: delay time to wait after powering up device - * @reset_delay_ms: delay time to wait after resetting device - * @reset_active_ms: reset active time - * @byte_delay_us: delay time between two bytes of SPI data - * @block_delay_us: delay time between two SPI transfers - * @pwr_reg_name: pointer to name of regulator for power control - * @bus_reg_name: pointer to name of regulator for bus pullup control - * @cap_button_map: pointer to 0D button map - * @vir_button_map: pointer to virtual button map - * @resume_in_workqueue: defer resume function to workqueue - */ -struct synaptics_dsx_board_data { - bool x_flip; - bool y_flip; - bool swap_axes; - bool resume_in_workqueue; - int irq_gpio; - int irq_on_state; - int power_gpio; - int power_on_state; - int reset_gpio; - int reset_on_state; - int max_y_for_2d; - unsigned long irq_flags; - unsigned short i2c_addr; - unsigned short ub_i2c_addr; - unsigned short device_descriptor_addr; - unsigned int panel_x; - unsigned int panel_y; - unsigned int power_delay_ms; - unsigned int reset_delay_ms; - unsigned int reset_active_ms; - unsigned int byte_delay_us; - unsigned int block_delay_us; - const char *pwr_reg_name; - const char *bus_reg_name; - struct synaptics_dsx_button_map *cap_button_map; - struct synaptics_dsx_button_map *vir_button_map; -}; - -#endif diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 1c87478b5fc0..31cc6f40baa5 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -432,9 +432,10 @@ struct mmc_card { struct mmc_wr_pack_stats wr_pack_stats; /* packed commands stats*/ struct notifier_block reboot_notify; enum mmc_pon_type pon_type; - u8 *cached_ext_csd; bool cmdq_init; struct mmc_bkops_info bkops; + bool err_in_sdr104; + bool sdr104_blocked; }; /* diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 1068953943d8..2a1a6fec179f 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -169,6 +169,7 @@ extern int __mmc_switch_cmdq_mode(struct mmc_command *cmd, u8 set, u8 index, extern int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error); extern int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd); extern int mmc_set_auto_bkops(struct mmc_card *card, bool enable); +extern int mmc_suspend_clk_scaling(struct mmc_host *host); #define MMC_ERASE_ARG 0x00000000 #define MMC_SECURE_ERASE_ARG 0x80000000 diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 055b879dfa6b..d9e12c1b1748 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -595,6 +595,7 @@ struct mmc_host { struct io_latency_state io_lat_s; #endif + bool sdr104_wa; unsigned long private[0] ____cacheline_aligned; }; @@ -728,6 +729,16 @@ static inline int mmc_host_uhs(struct mmc_host *host) MMC_CAP_UHS_DDR50); } +static inline void mmc_host_clear_sdr104(struct mmc_host *host) +{ + host->caps &= ~MMC_CAP_UHS_SDR104; +} + +static inline void mmc_host_set_sdr104(struct mmc_host *host) +{ + host->caps |= MMC_CAP_UHS_SDR104; +} + static inline int mmc_host_packed_wr(struct mmc_host *host) { return host->caps2 & MMC_CAP2_PACKED_WR; diff --git a/include/linux/msm_mhi.h b/include/linux/msm_mhi.h index b9fd610f92da..2b50ce59406e 100644 --- a/include/linux/msm_mhi.h +++ b/include/linux/msm_mhi.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -13,6 +13,7 @@ #define MSM_MHI_H #include <linux/types.h> #include <linux/device.h> +#include <linux/scatterlist.h> #define MHI_DMA_MASK 0xFFFFFFFFFFULL #define MHI_MAX_MTU 0xFFFF @@ -77,6 +78,7 @@ enum MHI_CB_REASON { MHI_CB_MHI_ENABLED, MHI_CB_MHI_SHUTDOWN, MHI_CB_SYS_ERROR, + MHI_CB_RDDM, }; enum MHI_FLAGS { @@ -128,16 +130,22 @@ struct __packed bhi_vec_entry { * @dev: device node points to of_node * @pdev: pci device node * @resource: bar memory space and IRQ resources + * @support_rddm: this device support ramdump collection + * @rddm_size: size of ramdump buffer in bytes to allocate * @pm_runtime_get: fp for bus masters rpm pm_runtime_get * @pm_runtime_noidle: fp for bus masters rpm pm_runtime_noidle + * @status_cb: fp for MHI status change notifications * @mhi_dev_ctxt: private data for host */ struct mhi_device { struct device *dev; struct pci_dev *pci_dev; struct resource resources[2]; + bool support_rddm; + size_t rddm_size; int (*pm_runtime_get)(struct pci_dev *pci_dev); - void (*pm_runtime_noidle)(struct pci_dev *pci_dev); + void (*pm_runtime_put_noidle)(struct pci_dev *pci_dev); + void (*status_cb)(enum MHI_CB_REASON, void *priv); struct mhi_device_ctxt *mhi_dev_ctxt; }; @@ -148,10 +156,16 @@ enum mhi_dev_ctrl { MHI_DEV_CTRL_RESUME, MHI_DEV_CTRL_POWER_OFF, MHI_DEV_CTRL_POWER_ON, - MHI_DEV_CTRL_RAM_DUMP, + MHI_DEV_CTRL_RDDM, + MHI_DEV_CTRL_RDDM_KERNEL_PANIC, MHI_DEV_CTRL_NOTIFY_LINK_ERROR, }; +enum mhi_rddm_segment { + MHI_RDDM_FW_SEGMENT, + MHI_RDDM_RD_SEGMENT, +}; + /** * mhi_is_device_ready - Check if MHI is ready to register clients * @@ -173,7 +187,7 @@ bool mhi_is_device_ready(const struct device * const dev, */ int mhi_register_device(struct mhi_device *mhi_device, const char *node_name, - unsigned long user_data); + void *user_data); /** * mhi_pm_control_device - power management control api @@ -185,6 +199,15 @@ int mhi_pm_control_device(struct mhi_device *mhi_device, enum mhi_dev_ctrl ctrl); /** + * mhi_xfer_rddm - transfer rddm segment to bus master + * @mhi_device: registered device structure + * @seg: scatterlist pointing to segments + * @Return: # of segments, 0 if no segment available + */ +int mhi_xfer_rddm(struct mhi_device *mhi_device, enum mhi_rddm_segment seg, + struct scatterlist **sg_list); + +/** * mhi_deregister_channel - de-register callbacks from MHI * * @client_handle: Handle populated by MHI, opaque to client diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 864f7f6a0d01..7488bb993d7a 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -246,6 +246,7 @@ enum power_supply_property { POWER_SUPPLY_PROP_DIE_HEALTH, POWER_SUPPLY_PROP_CONNECTOR_HEALTH, POWER_SUPPLY_PROP_CTM_CURRENT_MAX, + POWER_SUPPLY_PROP_HW_CURRENT_MAX, /* Local extensions of type int64_t */ POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT, /* Properties of type `const char *' */ diff --git a/include/linux/qpnp/qpnp-revid.h b/include/linux/qpnp/qpnp-revid.h index a0e2283ef4c9..7254f4d16176 100644 --- a/include/linux/qpnp/qpnp-revid.h +++ b/include/linux/qpnp/qpnp-revid.h @@ -208,6 +208,12 @@ #define PM660_V1P1_REV3 0x01 #define PM660_V1P1_REV4 0x01 +/* PM660L REV_ID */ +#define PM660L_V1P1_REV1 0x00 +#define PM660L_V1P1_REV2 0x00 +#define PM660L_V1P1_REV3 0x01 +#define PM660L_V1P1_REV4 0x01 + /* PMI8998 FAB_ID */ #define PMI8998_FAB_ID_SMIC 0x11 #define PMI8998_FAB_ID_GF 0x30 diff --git a/include/linux/sched.h b/include/linux/sched.h index 95d758d63784..4b56a62a0a58 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -3247,6 +3247,15 @@ static inline void cond_resched_rcu(void) #endif } +static inline unsigned long get_preempt_disable_ip(struct task_struct *p) +{ +#ifdef CONFIG_DEBUG_PREEMPT + return p->preempt_disable_ip; +#else + return 0; +#endif +} + /* * Does a critical section need to be broken due to another * task waiting?: (technically does not depend on CONFIG_PREEMPT, diff --git a/include/soc/qcom/icnss.h b/include/soc/qcom/icnss.h index 731fa6970b95..7ef984afc442 100644 --- a/include/soc/qcom/icnss.h +++ b/include/soc/qcom/icnss.h @@ -20,6 +20,11 @@ enum icnss_uevent { ICNSS_UEVENT_FW_READY, ICNSS_UEVENT_FW_CRASHED, + ICNSS_UEVENT_FW_DOWN, +}; + +struct icnss_uevent_fw_down_data { + bool crashed; }; struct icnss_uevent_data { diff --git a/kernel/cpu.c b/kernel/cpu.c index 8b6940755e4a..0ca3599cee1f 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -530,9 +530,41 @@ out: return ret; } +static int switch_to_rt_policy(void) +{ + struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 }; + unsigned int policy = current->policy; + int err; + + /* Nobody should be attempting hotplug from these policy contexts. */ + if (policy == SCHED_BATCH || policy == SCHED_IDLE || + policy == SCHED_DEADLINE) + return -EPERM; + + if (policy == SCHED_FIFO || policy == SCHED_RR) + return 1; + + /* Only SCHED_NORMAL left. */ + err = sched_setscheduler_nocheck(current, SCHED_FIFO, ¶m); + return err; + +} + +static int switch_to_fair_policy(void) +{ + struct sched_param param = { .sched_priority = 0 }; + + return sched_setscheduler_nocheck(current, SCHED_NORMAL, ¶m); +} + int cpu_up(unsigned int cpu) { int err = 0; + int switch_err = 0; + + switch_err = switch_to_rt_policy(); + if (switch_err < 0) + return switch_err; if (!cpu_possible(cpu)) { pr_err("can't online cpu %d because it is not configured as may-hotadd at boot time\n", @@ -558,6 +590,13 @@ int cpu_up(unsigned int cpu) out: cpu_maps_update_done(); + + if (!switch_err) { + switch_err = switch_to_fair_policy(); + pr_err("Hotplug policy switch err. Task %s pid=%d\n", + current->comm, current->pid); + } + return err; } EXPORT_SYMBOL_GPL(cpu_up); diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 1017a3f77391..e107c4d6b385 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -3364,6 +3364,9 @@ NOKPROBE_SYMBOL(preempt_count_sub); */ static noinline void __schedule_bug(struct task_struct *prev) { + /* Save this before calling printk(), since that will clobber it */ + unsigned long preempt_disable_ip = get_preempt_disable_ip(current); + if (oops_in_progress) return; @@ -3374,13 +3377,12 @@ static noinline void __schedule_bug(struct task_struct *prev) print_modules(); if (irqs_disabled()) print_irqtrace_events(prev); -#ifdef CONFIG_DEBUG_PREEMPT - if (in_atomic_preempt_off()) { + if (IS_ENABLED(CONFIG_DEBUG_PREEMPT) + && in_atomic_preempt_off()) { pr_err("Preemption disabled at:"); - print_ip_sym(current->preempt_disable_ip); + print_ip_sym(preempt_disable_ip); pr_cont("\n"); } -#endif #ifdef CONFIG_PANIC_ON_SCHED_BUG BUG(); #endif @@ -8513,6 +8515,7 @@ EXPORT_SYMBOL(__might_sleep); void ___might_sleep(const char *file, int line, int preempt_offset) { static unsigned long prev_jiffy; /* ratelimiting */ + unsigned long preempt_disable_ip; rcu_sleep_check(); /* WARN_ON_ONCE() by default, no rate limit reqd. */ if ((preempt_count_equals(preempt_offset) && !irqs_disabled() && @@ -8525,6 +8528,9 @@ void ___might_sleep(const char *file, int line, int preempt_offset) return; prev_jiffy = jiffies; + /* Save this before calling printk(), since that will clobber it */ + preempt_disable_ip = get_preempt_disable_ip(current); + printk(KERN_ERR "BUG: sleeping function called from invalid context at %s:%d\n", file, line); @@ -8539,13 +8545,12 @@ void ___might_sleep(const char *file, int line, int preempt_offset) debug_show_held_locks(current); if (irqs_disabled()) print_irqtrace_events(current); -#ifdef CONFIG_DEBUG_PREEMPT - if (!preempt_count_equals(preempt_offset)) { + if (IS_ENABLED(CONFIG_DEBUG_PREEMPT) + && !preempt_count_equals(preempt_offset)) { pr_err("Preemption disabled at:"); - print_ip_sym(current->preempt_disable_ip); + print_ip_sym(preempt_disable_ip); pr_cont("\n"); } -#endif #ifdef CONFIG_PANIC_ON_SCHED_BUG BUG(); #endif diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c index 4b98d1ee0ecd..7f9ad8ebcd3d 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.c +++ b/sound/soc/codecs/wcd-mbhc-v2.c @@ -53,7 +53,7 @@ #define WCD_MBHC_BTN_PRESS_COMPL_TIMEOUT_MS 50 #define ANC_DETECT_RETRY_CNT 7 -#define WCD_MBHC_SPL_HS_CNT 2 +#define WCD_MBHC_SPL_HS_CNT 1 static int det_extn_cable_en; module_param(det_extn_cable_en, int, @@ -1162,7 +1162,7 @@ static void wcd_correct_swch_plug(struct work_struct *work) bool wrk_complete = false; int pt_gnd_mic_swap_cnt = 0; int no_gnd_mic_swap_cnt = 0; - bool is_pa_on = false, spl_hs = false; + bool is_pa_on = false, spl_hs = false, spl_hs_reported = false; bool micbias2 = false; bool micbias1 = false; int ret = 0; @@ -1368,6 +1368,16 @@ correct_plug_type: plug_type); if (!(plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP)) { plug_type = MBHC_PLUG_TYPE_HEADSET; + if (!spl_hs_reported && + spl_hs_count == WCD_MBHC_SPL_HS_CNT) { + spl_hs_reported = true; + WCD_MBHC_RSC_LOCK(mbhc); + wcd_mbhc_find_plug_and_report(mbhc, + plug_type); + WCD_MBHC_RSC_UNLOCK(mbhc); + continue; + } else if (spl_hs_reported) + continue; /* * Report headset only if not already reported * and if there is not button press without @@ -1442,6 +1452,29 @@ exit: !mbhc->micbias_enable) mbhc->mbhc_cb->mbhc_micbias_control(codec, MIC_BIAS_2, MICB_DISABLE); + + /* + * If plug type is corrected from special headset to headphone, + * clear the micbias enable flag, set micbias back to 1.8V and + * disable micbias. + */ + if (plug_type == MBHC_PLUG_TYPE_HEADPHONE && + mbhc->micbias_enable) { + if (mbhc->mbhc_cb->mbhc_micbias_control) + mbhc->mbhc_cb->mbhc_micbias_control( + codec, MIC_BIAS_2, + MICB_DISABLE); + if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) + mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic( + codec, + MIC_BIAS_2, false); + if (mbhc->mbhc_cb->set_micbias_value) { + mbhc->mbhc_cb->set_micbias_value(codec); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 0); + } + mbhc->micbias_enable = false; + } + if (mbhc->mbhc_cb->micbias_enable_status) { micbias1 = mbhc->mbhc_cb->micbias_enable_status(mbhc, MIC_BIAS_1); diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c index 192d9291a8f3..e125ed8c2a16 100644 --- a/sound/soc/codecs/wcd934x/wcd934x.c +++ b/sound/soc/codecs/wcd934x/wcd934x.c @@ -798,11 +798,13 @@ int wcd934x_bringup(struct wcd9xxx *wcd9xxx) regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x01); regmap_write(wcd_regmap, WCD934X_SIDO_NEW_VOUT_A_STARTUP, 0x19); regmap_write(wcd_regmap, WCD934X_SIDO_NEW_VOUT_D_STARTUP, 0x15); + /* Add 1msec delay for VOUT to settle */ + usleep_range(1000, 1100); regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x5); regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x7); - regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3); regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x3); regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x7); + regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3); return 0; } @@ -8277,6 +8279,9 @@ static int __tavil_cdc_mclk_enable(struct tavil_priv *tavil, WCD9XXX_V2_BG_CLK_LOCK(tavil->resmgr); ret = __tavil_cdc_mclk_enable_locked(tavil, enable); + if (enable) + wcd_resmgr_set_sido_input_src(tavil->resmgr, + SIDO_SOURCE_RCO_BG); WCD9XXX_V2_BG_CLK_UNLOCK(tavil->resmgr); return ret; @@ -8415,6 +8420,8 @@ static int __tavil_codec_internal_rco_ctrl(struct snd_soc_codec *codec, __func__, ret); goto done; } + wcd_resmgr_set_sido_input_src(tavil->resmgr, + SIDO_SOURCE_RCO_BG); ret = wcd_resmgr_enable_clk_block(tavil->resmgr, WCD_CLK_RCO); ret |= tavil_cdc_req_mclk_enable(tavil, false); @@ -9069,8 +9076,9 @@ static int tavil_device_down(struct wcd9xxx *wcd9xxx) 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); + if (priv->swr.ctrl_data) + 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++) @@ -9816,18 +9824,23 @@ static int __tavil_enable_efuse_sensing(struct tavil_priv *tavil) { int val, rc; - __tavil_cdc_mclk_enable(tavil, true); + WCD9XXX_V2_BG_CLK_LOCK(tavil->resmgr); + __tavil_cdc_mclk_enable_locked(tavil, true); regmap_update_bits(tavil->wcd9xxx->regmap, WCD934X_CHIP_TIER_CTRL_EFUSE_CTL, 0x1E, 0x10); regmap_update_bits(tavil->wcd9xxx->regmap, WCD934X_CHIP_TIER_CTRL_EFUSE_CTL, 0x01, 0x01); - /* * 5ms sleep required after enabling efuse control * before checking the status. */ usleep_range(5000, 5500); + wcd_resmgr_set_sido_input_src(tavil->resmgr, + SIDO_SOURCE_RCO_BG); + + WCD9XXX_V2_BG_CLK_UNLOCK(tavil->resmgr); + rc = regmap_read(tavil->wcd9xxx->regmap, WCD934X_CHIP_TIER_CTRL_EFUSE_STATUS, &val); if (rc || (!(val & 0x01))) diff --git a/sound/soc/codecs/wcd9xxx-resmgr-v2.c b/sound/soc/codecs/wcd9xxx-resmgr-v2.c index bd92ccc9e009..f16fc05a5eaa 100644 --- a/sound/soc/codecs/wcd9xxx-resmgr-v2.c +++ b/sound/soc/codecs/wcd9xxx-resmgr-v2.c @@ -25,8 +25,7 @@ #define WCD93XX_CDC_CLK_RST_CTRL_MCLK_CONTROL 0x0d41 #define WCD93XX_CDC_CLK_RST_CTRL_FS_CNT_CONTROL 0x0d42 -static void wcd_resmgr_set_sido_input_src(struct wcd9xxx_resmgr_v2 *resmgr, - int sido_src); + static const char *wcd_resmgr_clk_type_to_str(enum wcd_clock_type clk_type) { if (clk_type == WCD_CLK_OFF) @@ -267,8 +266,6 @@ static int wcd_resmgr_enable_clk_mclk(struct wcd9xxx_resmgr_v2 *resmgr) 0x01, 0x01); wcd_resmgr_codec_reg_update_bits(resmgr, WCD934X_CODEC_RPM_CLK_GATE, 0x03, 0x00); - wcd_resmgr_set_sido_input_src(resmgr, - SIDO_SOURCE_RCO_BG); } else { wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, @@ -515,7 +512,7 @@ int wcd_resmgr_enable_clk_block(struct wcd9xxx_resmgr_v2 *resmgr, return ret; } -static void wcd_resmgr_set_sido_input_src(struct wcd9xxx_resmgr_v2 *resmgr, +void wcd_resmgr_set_sido_input_src(struct wcd9xxx_resmgr_v2 *resmgr, int sido_src) { if (!resmgr) @@ -553,6 +550,7 @@ static void wcd_resmgr_set_sido_input_src(struct wcd9xxx_resmgr_v2 *resmgr, pr_debug("%s: sido input src to external\n", __func__); } } +EXPORT_SYMBOL(wcd_resmgr_set_sido_input_src); /* * wcd_resmgr_set_sido_input_src_locked: diff --git a/sound/soc/codecs/wcd9xxx-resmgr-v2.h b/sound/soc/codecs/wcd9xxx-resmgr-v2.h index f605a249a620..e831ba61e9c2 100644 --- a/sound/soc/codecs/wcd9xxx-resmgr-v2.h +++ b/sound/soc/codecs/wcd9xxx-resmgr-v2.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -87,4 +87,7 @@ int wcd_resmgr_get_clk_type(struct wcd9xxx_resmgr_v2 *resmgr); void wcd_resmgr_post_ssr_v2(struct wcd9xxx_resmgr_v2 *resmgr); void wcd_resmgr_set_sido_input_src_locked(struct wcd9xxx_resmgr_v2 *resmgr, int sido_src); +void wcd_resmgr_set_sido_input_src(struct wcd9xxx_resmgr_v2 *resmgr, + int sido_src); + #endif diff --git a/sound/soc/msm/apq8096-auto.c b/sound/soc/msm/apq8096-auto.c index 138f4a02452c..c01150f883ff 100644 --- a/sound/soc/msm/apq8096-auto.c +++ b/sound/soc/msm/apq8096-auto.c @@ -115,6 +115,9 @@ static int msm_ec_ref_ch = 4; static int msm_ec_ref_bit_format = SNDRV_PCM_FORMAT_S16_LE; static int msm_ec_ref_sampling_rate = SAMPLING_RATE_48KHZ; +static int msm_tdm_slot_width = 32; +static int msm_tdm_num_slots = 8; + static void *adsp_state_notifier; static bool dummy_device_registered; @@ -295,6 +298,62 @@ static unsigned int tdm_slot_offset_adp_mmxf[TDM_MAX][TDM_SLOT_OFFSET_MAX] = { {0xFFFF}, /* not used */ }; +static unsigned int tdm_slot_offset_custom[TDM_MAX][TDM_SLOT_OFFSET_MAX] = { + /* QUAT_TDM_RX */ + {0, 2, 0xFFFF}, + {4, 6, 8, 10, 12, 14, 16, 18}, + {20, 22, 24, 26, 28, 30, 0xFFFF}, + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + /* QUAT_TDM_TX */ + {0, 2, 4, 6, 8, 10, 12, 0xFFFF}, + {14, 16, 0xFFFF}, + {18, 20, 22, 24, 26, 28, 30, 0xFFFF}, + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + /* TERT_TDM_RX */ + {0, 2, 0xFFFF}, + {4, 0xFFFF}, + {6, 0xFFFF}, + {8, 0xFFFF}, + {10, 0xFFFF}, + {12, 14, 16, 18, 20, 22, 24, 26}, + {28, 30, 0xFFFF}, + {0xFFFF}, /* not used */ + /* TERT_TDM_TX */ + {0, 2, 0xFFFF}, + {4, 6, 8, 10, 12, 14, 16, 18}, + {20, 22, 24, 26, 28, 30, 0xFFFF}, + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + /* SEC_TDM_RX */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + /* SEC_TDM_TX */ + {0xFFFF}, + {0xFFFF}, + {0xFFFF}, + {0xFFFF}, + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ +}; static char const *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five", "Six", "Seven", "Eight"}; @@ -2256,44 +2315,38 @@ static int apq8096_tdm_snd_hw_params(struct snd_pcm_substream *substream, pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id); channels = params_channels(params); - switch (channels) { - case 1: - case 2: - case 3: - case 4: - case 6: - case 8: - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S32_LE: - case SNDRV_PCM_FORMAT_S24_LE: - case SNDRV_PCM_FORMAT_S16_LE: - /* - * up to 8 channel HW configuration should - * use 32 bit slot width for max support of - * stream bit width. (slot_width > bit_width) - */ - slot_width = 32; - break; - default: - pr_err("%s: invalid param format 0x%x\n", - __func__, params_format(params)); - return -EINVAL; - } - slots = 8; - slot_mask = tdm_param_set_slot_mask(cpu_dai->id, - slot_width, slots); - if (!slot_mask) { - pr_err("%s: invalid slot_mask 0x%x\n", - __func__, slot_mask); - return -EINVAL; - } - break; - default: + if (channels < 1 || channels > 8) { pr_err("%s: invalid param channels %d\n", __func__, channels); return -EINVAL; } + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S32_LE: + case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S16_LE: + /* + * up to 8 channel HW configuration should + * use 32 bit slot width for max support of + * stream bit width. (slot_width > bit_width) + */ + slot_width = msm_tdm_slot_width; + break; + default: + pr_err("%s: invalid param format 0x%x\n", + __func__, params_format(params)); + return -EINVAL; + } + + slots = msm_tdm_num_slots; + slot_mask = tdm_param_set_slot_mask(cpu_dai->id, + slot_width, slots); + if (!slot_mask) { + pr_err("%s: invalid slot_mask 0x%x\n", + __func__, slot_mask); + return -EINVAL; + } + switch (cpu_dai->id) { case AFE_PORT_ID_SECONDARY_TDM_RX: slot_offset = tdm_slot_offset[SECONDARY_TDM_RX_0]; @@ -2660,7 +2713,7 @@ static int apq8096_get_ll_qos_val(struct snd_pcm_runtime *runtime) return usecs; } -static int apq8096_mm5_prepare(struct snd_pcm_substream *substream) +static int apq8096_ll_prepare(struct snd_pcm_substream *substream) { if (pm_qos_request_active(&substream->latency_pm_qos_req)) pm_qos_remove_request(&substream->latency_pm_qos_req); @@ -2670,8 +2723,8 @@ static int apq8096_mm5_prepare(struct snd_pcm_substream *substream) return 0; } -static struct snd_soc_ops apq8096_mm5_ops = { - .prepare = apq8096_mm5_prepare, +static struct snd_soc_ops apq8096_ll_ops = { + .prepare = apq8096_ll_prepare, }; /* Digital audio interface glue - connects codec <---> CPU */ @@ -2938,7 +2991,7 @@ static struct snd_soc_dai_link apq8096_common_dai_links[] = { /* this dainlink has playback support */ .ignore_pmdown_time = 1, .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5, - .ops = &apq8096_mm5_ops, + .ops = &apq8096_ll_ops, }, { .name = "Listen 1 Audio Service", @@ -3647,6 +3700,192 @@ static struct snd_soc_dai_link apq8096_auto_fe_dai_links[] = { }, }; +static struct snd_soc_dai_link apq8096_custom_fe_dai_links[] = { + /* FrontEnd DAI Links */ + { + .name = "MSM8996 Media1", + .stream_name = "MultiMedia1", + .cpu_dai_name = "MultiMedia1", + .platform_name = "msm-pcm-dsp.1", + .dynamic = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, + .dpcm_playback = 1, + .dpcm_capture = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1, + .ops = &apq8096_ll_ops, + }, + { + .name = "MSM8996 Media2", + .stream_name = "MultiMedia2", + .cpu_dai_name = "MultiMedia2", + .platform_name = "msm-pcm-dsp.1", + .dynamic = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, + .dpcm_playback = 1, + .dpcm_capture = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2, + .ops = &apq8096_ll_ops, + }, + { + .name = "MSM8996 Media3", + .stream_name = "MultiMedia3", + .cpu_dai_name = "MultiMedia3", + .platform_name = "msm-pcm-dsp.1", + .dynamic = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, + .dpcm_playback = 1, + .dpcm_capture = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3, + .ops = &apq8096_ll_ops, + }, + { + .name = "MSM8996 Media5", + .stream_name = "MultiMedia5", + .cpu_dai_name = "MultiMedia5", + .platform_name = "msm-pcm-dsp.1", + .dynamic = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, + .dpcm_playback = 1, + .dpcm_capture = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5, + .ops = &apq8096_ll_ops, + }, + { + .name = "MSM8996 Media6", + .stream_name = "MultiMedia6", + .cpu_dai_name = "MultiMedia6", + .platform_name = "msm-pcm-dsp.1", + .dynamic = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, + .dpcm_playback = 1, + .dpcm_capture = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA6, + .ops = &apq8096_ll_ops, + }, + { + .name = "MSM8996 Media8", + .stream_name = "MultiMedia8", + .cpu_dai_name = "MultiMedia8", + .platform_name = "msm-pcm-dsp.1", + .dynamic = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, + .dpcm_playback = 1, + .dpcm_capture = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA8, + .ops = &apq8096_ll_ops, + }, + { + .name = "MSM8996 Media9", + .stream_name = "MultiMedia9", + .cpu_dai_name = "MultiMedia9", + .platform_name = "msm-pcm-dsp.1", + .dynamic = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, + .dpcm_playback = 1, + .dpcm_capture = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA9, + .ops = &apq8096_ll_ops, + }, + { + .name = "INT_HFP_BT Hostless", + .stream_name = "INT_HFP_BT Hostless", + .cpu_dai_name = "INT_HFP_BT_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "AUXPCM Hostless", + .stream_name = "AUXPCM Hostless", + .cpu_dai_name = "AUXPCM_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "Tertiary MI2S TX_Hostless", + .stream_name = "Tertiary MI2S_TX Hostless Capture", + .cpu_dai_name = "TERT_MI2S_TX_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, +}; + static struct snd_soc_dai_link apq8096_common_be_dai_links[] = { /* Backend AFE DAI Links */ { @@ -4115,6 +4354,13 @@ static struct snd_soc_dai_link apq8096_auto_dai_links[ ARRAY_SIZE(apq8096_auto_be_dai_links) + ARRAY_SIZE(apq8096_hdmi_dai_link)]; +static struct snd_soc_dai_link apq8096_auto_custom_dai_links[ + ARRAY_SIZE(apq8096_custom_fe_dai_links) + + ARRAY_SIZE(apq8096_auto_fe_dai_links) + + ARRAY_SIZE(apq8096_common_be_dai_links) + + ARRAY_SIZE(apq8096_auto_be_dai_links) + + ARRAY_SIZE(apq8096_hdmi_dai_link)]; + struct snd_soc_card snd_soc_card_auto_apq8096 = { .name = "apq8096-auto-snd-card", }; @@ -4127,6 +4373,10 @@ struct snd_soc_card snd_soc_card_adp_mmxf_apq8096 = { .name = "apq8096-adp-mmxf-snd-card", }; +struct snd_soc_card snd_soc_card_auto_custom_apq8096 = { + .name = "apq8096-auto-custom-snd-card", +}; + static int apq8096_populate_dai_link_component_of_node( struct snd_soc_card *card) { @@ -4220,6 +4470,8 @@ static const struct of_device_id apq8096_asoc_machine_of_match[] = { .data = "adp_agave_codec"}, { .compatible = "qcom,apq8096-asoc-snd-adp-mmxf", .data = "adp_mmxf_codec"}, + { .compatible = "qcom,apq8096-asoc-snd-auto-custom", + .data = "auto_custom_codec"}, {}, }; @@ -4243,31 +4495,55 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) card = &snd_soc_card_adp_agave_apq8096; else if (!strcmp(match->data, "adp_mmxf_codec")) card = &snd_soc_card_adp_mmxf_apq8096; - else { + else if (!strcmp(match->data, "auto_custom_codec")) { + card = &snd_soc_card_auto_custom_apq8096; + } else { dev_err(dev, "%s: Codec not supported\n", __func__); return NULL; } - /* same FE and BE used for all codec */ - len_1 = ARRAY_SIZE(apq8096_common_dai_links); - len_2 = len_1 + ARRAY_SIZE(apq8096_auto_fe_dai_links); - len_3 = len_2 + ARRAY_SIZE(apq8096_common_be_dai_links); - - memcpy(apq8096_auto_dai_links, - apq8096_common_dai_links, - sizeof(apq8096_common_dai_links)); - memcpy(apq8096_auto_dai_links + len_1, - apq8096_auto_fe_dai_links, - sizeof(apq8096_auto_fe_dai_links)); - memcpy(apq8096_auto_dai_links + len_2, - apq8096_common_be_dai_links, - sizeof(apq8096_common_be_dai_links)); - memcpy(apq8096_auto_dai_links + len_3, - apq8096_auto_be_dai_links, - sizeof(apq8096_auto_be_dai_links)); - - dailink = apq8096_auto_dai_links; + if (!strcmp(match->data, "auto_custom_codec")) { + len_1 = ARRAY_SIZE(apq8096_custom_fe_dai_links); + len_2 = len_1 + ARRAY_SIZE(apq8096_auto_fe_dai_links); + len_3 = len_2 + ARRAY_SIZE(apq8096_common_be_dai_links); + + memcpy(apq8096_auto_custom_dai_links, + apq8096_custom_fe_dai_links, + sizeof(apq8096_custom_fe_dai_links)); + memcpy(apq8096_auto_custom_dai_links + len_1, + apq8096_auto_fe_dai_links, + sizeof(apq8096_auto_fe_dai_links)); + memcpy(apq8096_auto_custom_dai_links + len_2, + apq8096_common_be_dai_links, + sizeof(apq8096_common_be_dai_links)); + memcpy(apq8096_auto_custom_dai_links + len_3, + apq8096_auto_be_dai_links, + sizeof(apq8096_auto_be_dai_links)); + + dailink = apq8096_auto_custom_dai_links; + } else { + /* same FE and BE used for all non-custom codec */ + len_1 = ARRAY_SIZE(apq8096_common_dai_links); + len_2 = len_1 + ARRAY_SIZE(apq8096_auto_fe_dai_links); + len_3 = len_2 + ARRAY_SIZE(apq8096_common_be_dai_links); + + memcpy(apq8096_auto_dai_links, + apq8096_common_dai_links, + sizeof(apq8096_common_dai_links)); + memcpy(apq8096_auto_dai_links + len_1, + apq8096_auto_fe_dai_links, + sizeof(apq8096_auto_fe_dai_links)); + memcpy(apq8096_auto_dai_links + len_2, + apq8096_common_be_dai_links, + sizeof(apq8096_common_be_dai_links)); + memcpy(apq8096_auto_dai_links + len_3, + apq8096_auto_be_dai_links, + sizeof(apq8096_auto_be_dai_links)); + + dailink = apq8096_auto_dai_links; + } + len_4 = len_3 + ARRAY_SIZE(apq8096_auto_be_dai_links); if (of_property_read_bool(dev->of_node, "qcom,hdmi-audio-rx")) { @@ -4308,10 +4584,20 @@ static int apq8096_init_tdm_dev(struct device *dev) memcpy(tdm_slot_offset, tdm_slot_offset_adp_mmxf, sizeof(tdm_slot_offset_adp_mmxf)); + } else if (!strcmp(match->data, "auto_custom_codec")) { + dev_dbg(dev, "%s: custom tdm slot offset\n", __func__); + msm_tdm_slot_width = 16; + msm_tdm_num_slots = 16; + memcpy(tdm_slot_offset, + tdm_slot_offset_custom, + sizeof(tdm_slot_offset_custom)); } else { dev_dbg(dev, "%s: DEFAULT tdm slot offset\n", __func__); } + dev_dbg(dev, "%s: tdm slot_width %d, num_slots %d\n", + __func__, msm_tdm_slot_width, msm_tdm_num_slots); + return 0; } diff --git a/sound/soc/msm/qdsp6v2/msm-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c index ec4380036047..109e1a202ff2 100644 --- a/sound/soc/msm/qdsp6v2/msm-lsm-client.c +++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c @@ -1165,28 +1165,27 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream, break; case SNDRV_LSM_SET_FWK_MODE_CONFIG: { - u32 *mode = NULL; + u32 mode; - if (!arg) { - dev_err(rtd->dev, - "%s: Invalid param arg for ioctl %s session %d\n", - __func__, "SNDRV_LSM_SET_FWK_MODE_CONFIG", - prtd->lsm_client->session); - rc = -EINVAL; - break; + if (copy_from_user(&mode, arg, sizeof(mode))) { + dev_err(rtd->dev, "%s: %s: copy_frm_user failed\n", + __func__, "LSM_SET_FWK_MODE_CONFIG"); + return -EFAULT; } - mode = (u32 *)arg; - if (prtd->lsm_client->event_mode == *mode) { + + dev_dbg(rtd->dev, "%s: ioctl %s, enable = %d\n", + __func__, "SNDRV_LSM_SET_FWK_MODE_CONFIG", mode); + if (prtd->lsm_client->event_mode == mode) { dev_dbg(rtd->dev, "%s: mode for %d already set to %d\n", - __func__, prtd->lsm_client->session, *mode); + __func__, prtd->lsm_client->session, mode); rc = 0; } else { dev_dbg(rtd->dev, "%s: Event mode = %d\n", - __func__, *mode); - rc = q6lsm_set_fwk_mode_cfg(prtd->lsm_client, *mode); + __func__, mode); + rc = q6lsm_set_fwk_mode_cfg(prtd->lsm_client, mode); if (!rc) - prtd->lsm_client->event_mode = *mode; + prtd->lsm_client->event_mode = mode; else dev_err(rtd->dev, "%s: set event mode failed %d\n", diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index 837a08488991..7ce73484a681 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -5362,6 +5362,57 @@ static const struct snd_kcontrol_new tert_tdm_rx_3_mixer_controls[] = { msm_routing_put_audio_mixer), }; +static const struct snd_kcontrol_new tert_tdm_rx_4_mixer_controls[] = { + SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERT_TDM_RX_4, + 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_RX_4, + 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_RX_4, + 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_RX_4, + 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_RX_4, + 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_RX_4, + 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_RX_4, + 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_RX_4, + 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_RX_4, + 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_RX_4, + 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_RX_4, + 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_RX_4, + 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_RX_4, + 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_RX_4, + 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_RX_4, + 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_RX_4, + 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_0_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUAT_TDM_RX_0 , MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, @@ -11158,6 +11209,9 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { SND_SOC_DAPM_MIXER("TERT_TDM_RX_3 Audio Mixer", SND_SOC_NOPM, 0, 0, tert_tdm_rx_3_mixer_controls, ARRAY_SIZE(tert_tdm_rx_3_mixer_controls)), + SND_SOC_DAPM_MIXER("TERT_TDM_RX_4 Audio Mixer", SND_SOC_NOPM, 0, 0, + tert_tdm_rx_4_mixer_controls, + ARRAY_SIZE(tert_tdm_rx_4_mixer_controls)), 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)), @@ -12182,6 +12236,24 @@ static const struct snd_soc_dapm_route intercon[] = { {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia16", "MM_DL16"}, {"TERT_TDM_RX_3", NULL, "TERT_TDM_RX_3 Audio Mixer"}, + {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia1", "MM_DL1"}, + {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia2", "MM_DL2"}, + {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia3", "MM_DL3"}, + {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia4", "MM_DL4"}, + {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia5", "MM_DL5"}, + {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia6", "MM_DL6"}, + {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia7", "MM_DL7"}, + {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia8", "MM_DL8"}, + {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia9", "MM_DL9"}, + {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia10", "MM_DL10"}, + {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia11", "MM_DL11"}, + {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia12", "MM_DL12"}, + {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia13", "MM_DL13"}, + {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia14", "MM_DL14"}, + {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia15", "MM_DL15"}, + {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"TERT_TDM_RX_4", NULL, "TERT_TDM_RX_4 Audio Mixer"}, + {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"}, {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia2", "MM_DL2"}, {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia3", "MM_DL3"}, @@ -12937,6 +13009,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"VOIP_UL", NULL, "VOC_EXT_EC MUX"}, {"VoLTE_UL", NULL, "VOC_EXT_EC MUX"}, {"VOICE2_UL", NULL, "VOC_EXT_EC MUX"}, + {"VoWLAN_UL", NULL, "VOC_EXT_EC MUX"}, {"VOICEMMODE1_UL", NULL, "VOC_EXT_EC MUX"}, {"VOICEMMODE2_UL", NULL, "VOC_EXT_EC MUX"}, @@ -13890,6 +13963,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"BE_OUT", NULL, "TERT_TDM_RX_1"}, {"BE_OUT", NULL, "TERT_TDM_RX_2"}, {"BE_OUT", NULL, "TERT_TDM_RX_3"}, + {"BE_OUT", NULL, "TERT_TDM_RX_4"}, {"BE_OUT", NULL, "QUAT_TDM_RX_0"}, {"BE_OUT", NULL, "QUAT_TDM_RX_1"}, {"BE_OUT", NULL, "QUAT_TDM_RX_2"}, diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index 1ca99c3f9115..731f439f5286 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -4300,6 +4300,20 @@ static int q6asm_map_channels(u8 *channel_mapping, uint32_t channels, PCM_CHANNEL_LB : PCM_CHANNEL_LS; lchannel_mapping[5] = use_back_flavor ? PCM_CHANNEL_RB : PCM_CHANNEL_RS; + } else if (channels == 7) { + /* + * Configured for 5.1 channel mapping + 1 channel for debug + * Can be customized based on DSP. + */ + lchannel_mapping[0] = PCM_CHANNEL_FL; + lchannel_mapping[1] = PCM_CHANNEL_FR; + lchannel_mapping[2] = PCM_CHANNEL_FC; + lchannel_mapping[3] = PCM_CHANNEL_LFE; + lchannel_mapping[4] = use_back_flavor ? + PCM_CHANNEL_LB : PCM_CHANNEL_LS; + lchannel_mapping[5] = use_back_flavor ? + PCM_CHANNEL_RB : PCM_CHANNEL_RS; + lchannel_mapping[6] = PCM_CHANNEL_CS; } else if (channels == 8) { lchannel_mapping[0] = PCM_CHANNEL_FL; lchannel_mapping[1] = PCM_CHANNEL_FR; |
