diff options
65 files changed, 2045 insertions, 533 deletions
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index f79f49608743..86e1bdb417ab 100644 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -177,6 +177,11 @@ Required properties: - compatible : "qcom,msm-pcm-loopback" +Optional properties: + + - qcom,msm-pcm-loopback-low-latency : Flag indicating whether + the device node is of type low latency. + * msm-dai-q6 [First Level Nodes] @@ -415,6 +420,11 @@ Example: qcom,msm-pcm-low-latency; }; + qcom,msm-pcm-loopback-low-latency { + compatible = "qcom,msm-pcm-loopback"; + qcom,msm-pcm-loopback-low-latency; + }; + qcom,msm-pcm-routing { compatible = "qcom,msm-pcm-routing"; }; @@ -2121,13 +2131,15 @@ Example: asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, <&loopback>, <&compress>, <&hostless>, - <&afe>, <&lsm>, <&routing>, <&compr>; + <&afe>, <&lsm>, <&routing>, <&compr>, + <&loopback1>; asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", "msm-pcm-dsp.2", "msm-voip-dsp", "msm-pcm-voice", "msm-pcm-loopback", "msm-compress-dsp", "msm-pcm-hostless", "msm-pcm-afe", "msm-lsm-client", - "msm-pcm-routing", "msm-compr-dsp"; + "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>, <&afe_pcm_rx>, <&afe_pcm_tx>, @@ -2334,6 +2346,11 @@ Optional properties: - qcom,wsa-devs : List of phandles for all possible WSA881x devices supported for the target - qcom,wsa-aux-dev-prefix : Name prefix with Left/Right configuration for WSA881x device - qcom,wcn-btfm : Property to specify if WCN BT/FM chip is used for the target +- qcom,msm-mbhc-usbc-audio-supported : Property to specify if analog audio feature is + enabled or not. +- qcom,usbc-analog-en1_gpio : EN1 GPIO to enable USB type-C analog audio +- qcom,usbc-analog-en2_n_gpio : EN2 GPIO to enable USB type-C analog audio +- qcom,usbc-analog-force_detect_gpio : Force detect GPIO to enable USB type-C analog audio Example: @@ -2407,6 +2424,10 @@ Example: <&wsa881x_213>, <&wsa881x_214>; qcom,wsa-aux-dev-prefix = "SpkrRight", "SpkrLeft", "SpkrRight", "SpkrLeft"; + qcom,msm-mbhc-usbc-audio-supported = <1>; + qcom,usbc-analog-en1_gpio = <&wcd_usbc_analog_en1_gpio>; + qcom,usbc-analog-en2_n_gpio = <&wcd_usbc_analog_en2n_gpio>; + qcom,usbc-analog-force_detect_gpio = <&wcd_usbc_analog_f_gpio>; }; * MSMSTUB ASoC Machine driver diff --git a/arch/arm/boot/dts/qcom/msm8998-gpu.dtsi b/arch/arm/boot/dts/qcom/msm8998-gpu.dtsi index 9a497a473a56..45ab53ccc2c2 100644 --- a/arch/arm/boot/dts/qcom/msm8998-gpu.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-gpu.dtsi @@ -1,4 +1,4 @@ -/* 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 @@ -98,6 +98,7 @@ qcom,gpubw-dev = <&gpubw>; qcom,bus-control; qcom,msm-bus,name = "grp3d"; + qcom,bus-width = <32>; qcom,msm-bus,num-cases = <13>; qcom,msm-bus,num-paths = <1>; qcom,msm-bus,vectors-KBps = diff --git a/arch/arm/boot/dts/qcom/msm8998-v2-qrd-skuk-hdk.dts b/arch/arm/boot/dts/qcom/msm8998-v2-qrd-skuk-hdk.dts index ca0609f34642..ace7fc169703 100644 --- a/arch/arm/boot/dts/qcom/msm8998-v2-qrd-skuk-hdk.dts +++ b/arch/arm/boot/dts/qcom/msm8998-v2-qrd-skuk-hdk.dts @@ -22,3 +22,95 @@ compatible = "qcom,msm8998-qrd", "qcom,msm8998", "qcom,qrd"; qcom,board-id = <0x06000b 0x10>; }; + +&pmx_mdss { + mdss_dsi_active: mdss_dsi_active { + mux { + pins = "gpio52", "gpio94"; + function = "gpio"; + }; + + config { + pins = "gpio52", "gpio94"; + drive-strength = <8>; /* 8 mA */ + bias-disable = <0>; /* no pull */ + }; + }; + + mdss_dsi_suspend: mdss_dsi_suspend { + mux { + pins = "gpio52", "gpio94"; + function = "gpio"; + }; + + config { + pins = "gpio52", "gpio94"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + }; + }; +}; + +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_dsi { + hw-config = "split_dsi"; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_dual_s6e3ha3_amoled_cmd>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-enable-gpio = <&tlmm 52 0>; + qcom,platform-reset-gpio = <&tlmm 94 0>; + qcom,platform-bklight-en-gpio = <&pmi8998_gpios 1 0>; + qcom,platform-bklight-en-gpio-invert; +}; + +&mdss_dsi1 { + qcom,dsi-pref-prim-pan = <&dsi_dual_s6e3ha3_amoled_cmd>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-enable-gpio = <&tlmm 52 0>; + qcom,platform-reset-gpio = <&tlmm 94 0>; + qcom,platform-bklight-en-gpio = <&pmi8998_gpios 1 0>; + qcom,platform-bklight-en-gpio-invert; +}; + +&pmi8998_wled { + qcom,disp-type-amoled; +}; + +&labibb { + status = "ok"; + qcom,qpnp-labibb-mode = "amoled"; + qcom,swire-control; +}; + +&pmi8998_gpios { + /* GPIO 1 for WLED power enable */ + gpio@c000 { + qcom,mode = <1>; + qcom,output-type = <0>; + qcom,pull = <5>; + qcom,vin-sel = <0>; + qcom,out-strength = <1>; + qcom,src-sel = <0>; + qcom,invert = <0>; + qcom,master-en = <1>; + status = "okay"; + }; +}; + +&dsi_dual_s6e3ha3_amoled_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; diff --git a/arch/arm/boot/dts/qcom/sdm630.dtsi b/arch/arm/boot/dts/qcom/sdm630.dtsi index fa826cbc6b18..5002a11652ae 100644 --- a/arch/arm/boot/dts/qcom/sdm630.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630.dtsi @@ -680,7 +680,7 @@ cell-index = <1>; compatible = "qcom,slim-ngd"; reg = <0x151c0000 0x2c000>, - <0x15180000 0x2e000>; + <0x15184000 0x2a000>; reg-names = "slimbus_physical", "slimbus_bam_physical"; interrupts = <0 163 0>, <0 164 0>; interrupt-names = "slimbus_irq", "slimbus_bam_irq"; @@ -693,7 +693,7 @@ cell-index = <3>; compatible = "qcom,slim-ngd"; reg = <0x15240000 0x2c000>, - <0x15200000 0x24000>; + <0x15204000 0x20000>; reg-names = "slimbus_physical", "slimbus_bam_physical"; interrupts = <0 291 0>, <0 292 0>; interrupt-names = "slimbus_irq", "slimbus_bam_irq"; diff --git a/arch/arm/boot/dts/qcom/sdm660-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm660-camera-sensor-qrd.dtsi index ae8da056d12b..f44d59e021d2 100644 --- a/arch/arm/boot/dts/qcom/sdm660-camera-sensor-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-camera-sensor-qrd.dtsi @@ -21,7 +21,7 @@ status = "ok"; }; - cam_avdd_gpio_regulator:fixed_regulator@1 { + cam_avdd_gpio_regulator:cam_avdd_fixed_regulator { compatible = "regulator-fixed"; regulator-name = "cam_vadd_gpio_regulator"; regulator-min-microvolt = <2800000>; @@ -31,17 +31,7 @@ vin-supply = <&pm660l_bob>; }; - cam_dvdd_gpio_regulator:fixed_regulator@1 { - compatible = "regulator-fixed"; - regulator-name = "cam_vadd_gpio_regulator"; - regulator-min-microvolt = <1050000>; - regulator-max-microvolt = <1050000>; - enable-active-high; - gpio = <&pm660l_gpios 4>; - vin-supply = <&pm660_s5>; - }; - - cam_vaf_gpio_regulator:fixed_regulator@2 { + cam_vaf_gpio_regulator:cam_vaf_fixed_regulator { compatible = "regulator-fixed"; regulator-name = "cam_vaf_gpio_regulator"; regulator-min-microvolt = <2800000>; @@ -182,11 +172,11 @@ compatible = "qcom,eeprom"; cam_vio-supply = <&pm660_l11>; cam_vana-supply = <&cam_avdd_gpio_regulator>; - cam_vdig-supply = <&cam_dvdd_gpio_regulator>; + cam_vdig-supply = <&pm660_s5>; qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <1750000 0 0>; - qcom,cam-vreg-max-voltage = <1980000 0 0>; - qcom,cam-vreg-op-mode = <105000 0 0>; + qcom,cam-vreg-min-voltage = <1780000 0 1350000>; + qcom,cam-vreg-max-voltage = <1950000 0 1350000>; + qcom,cam-vreg-op-mode = <105000 0 105000>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk0_active @@ -194,12 +184,15 @@ pinctrl-1 = <&cam_sensor_mclk0_suspend &cam_sensor_rear_suspend>; gpios = <&tlmm 32 0>, - <&tlmm 46 0>; + <&tlmm 46 0>, + <&pm660l_gpios 4 0>; qcom,gpio-reset = <1>; - qcom,gpio-req-tbl-num = <0 1>; - qcom,gpio-req-tbl-flags = <1 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK0", - "CAM_RESET0"; + qcom,gpio-vdig = <2>; + qcom,gpio-req-tbl-num = <0 1 1>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET0", + "CAM_VDIG"; qcom,sensor-position = <0>; qcom,sensor-mode = <0>; qcom,cci-master = <0>; @@ -216,11 +209,11 @@ compatible = "qcom,eeprom"; cam_vio-supply = <&pm660_l11>; cam_vana-supply = <&cam_avdd_gpio_regulator>; - cam_vdig-supply = <&cam_dvdd_gpio_regulator>; + cam_vdig-supply = <&pm660_s5>; qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <1750000 0 0>; - qcom,cam-vreg-max-voltage = <1980000 0 0>; - qcom,cam-vreg-op-mode = <105000 0 0>; + qcom,cam-vreg-min-voltage = <1780000 0 1350000>; + qcom,cam-vreg-max-voltage = <1950000 0 1350000>; + qcom,cam-vreg-op-mode = <105000 0 105000>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk2_active @@ -228,15 +221,18 @@ pinctrl-1 = <&cam_sensor_mclk2_suspend &cam_sensor_rear2_suspend>; gpios = <&tlmm 34 0>, - <&tlmm 48 0>; + <&tlmm 48 0>, + <&pm660l_gpios 4 0>; qcom,gpio-reset = <1>; - qcom,gpio-req-tbl-num = <0 1>; - qcom,gpio-req-tbl-flags = <1 0>; + qcom,gpio-vdig = <2>; + qcom,gpio-req-tbl-num = <0 1 1>; + qcom,gpio-req-tbl-flags = <1 0 0>; qcom,gpio-req-tbl-label = "CAMIF_MCLK1", - "CAM_RESET1"; + "CAM_RESET1", + "CAM_VDIG"; qcom,sensor-position = <0>; qcom,sensor-mode = <0>; - qcom,cci-master = <0>; + qcom,cci-master = <1>; status = "ok"; clocks = <&clock_mmss MCLK2_CLK_SRC>, <&clock_mmss MMSS_CAMSS_MCLK2_CLK>; @@ -287,18 +283,18 @@ reg = <0x0>; qcom,csiphy-sd-index = <0>; qcom,csid-sd-index = <0>; - qcom,mount-angle = <90>; + qcom,mount-angle = <270>; qcom,led-flash-src = <&led_flash0>; qcom,actuator-src = <&actuator0>; qcom,ois-src = <&ois0>; qcom,eeprom-src = <&eeprom0>; cam_vio-supply = <&pm660_l11>; cam_vana-supply = <&cam_avdd_gpio_regulator>; - cam_vdig-supply = <&cam_dvdd_gpio_regulator>; + cam_vdig-supply = <&pm660_s5>; qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <1780000 0 0>; - qcom,cam-vreg-max-voltage = <1950000 0 0>; - qcom,cam-vreg-op-mode = <105000 0 0>; + qcom,cam-vreg-min-voltage = <1780000 0 1350000>; + qcom,cam-vreg-max-voltage = <1950000 0 1350000>; + qcom,cam-vreg-op-mode = <105000 0 105000>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk0_active @@ -306,12 +302,15 @@ pinctrl-1 = <&cam_sensor_mclk0_suspend &cam_sensor_rear_suspend>; gpios = <&tlmm 32 0>, - <&tlmm 46 0>; + <&tlmm 46 0>, + <&pm660l_gpios 4 0>; qcom,gpio-reset = <1>; - qcom,gpio-req-tbl-num = <0 1>; - qcom,gpio-req-tbl-flags = <1 0>; + qcom,gpio-vdig = <2>; + qcom,gpio-req-tbl-num = <0 1 1>; + qcom,gpio-req-tbl-flags = <1 0 0>; qcom,gpio-req-tbl-label = "CAMIF_MCLK2", - "CAM_RESET0"; + "CAM_RESET0", + "CAM_VDIG"; qcom,sensor-position = <0>; qcom,sensor-mode = <0>; qcom,cci-master = <0>; @@ -328,16 +327,16 @@ reg = <0x1>; qcom,csiphy-sd-index = <1>; qcom,csid-sd-index = <1>; - qcom,mount-angle = <90>; + qcom,mount-angle = <270>; qcom,actuator-src = <&actuator1>; qcom,eeprom-src = <&eeprom1>; cam_vio-supply = <&pm660_l11>; cam_vana-supply = <&cam_avdd_gpio_regulator>; - cam_vdig-supply = <&cam_dvdd_gpio_regulator>; + cam_vdig-supply = <&pm660_s5>; qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <1780000 0 0>; - qcom,cam-vreg-max-voltage = <1950000 0 0>; - qcom,cam-vreg-op-mode = <105000 0 0>; + qcom,cam-vreg-min-voltage = <1780000 0 1350000>; + qcom,cam-vreg-max-voltage = <1950000 0 1350000>; + qcom,cam-vreg-op-mode = <105000 0 105000>; qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk2_active @@ -345,15 +344,18 @@ pinctrl-1 = <&cam_sensor_mclk2_suspend &cam_sensor_rear2_suspend>; gpios = <&tlmm 34 0>, - <&tlmm 48 0>; + <&tlmm 48 0>, + <&pm660l_gpios 4 0>; qcom,gpio-reset = <1>; - qcom,gpio-req-tbl-num = <0 1>; - qcom,gpio-req-tbl-flags = <1 0>; + qcom,gpio-vdig = <2>; + qcom,gpio-req-tbl-num = <0 1 1>; + qcom,gpio-req-tbl-flags = <1 0 0>; qcom,gpio-req-tbl-label = "CAMIF_MCLK1", - "CAM_RESET1"; + "CAM_RESET1", + "CAM_VDIG"; qcom,sensor-position = <0>; qcom,sensor-mode = <0>; - qcom,cci-master = <0>; + qcom,cci-master = <1>; status = "ok"; clocks = <&clock_mmss MCLK2_CLK_SRC>, <&clock_mmss MMSS_CAMSS_MCLK2_CLK>; diff --git a/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi b/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi index d347f033b12d..1e62a2423e38 100644 --- a/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi @@ -32,21 +32,26 @@ * subsystem is inactive */ qcom,active-only; + /* + * IB votes in MBPS, derived using below formula + * IB = (DDR frequency * DDR bus width in Bytes * Dual rate) + * Note: IB vote is per DDR channel vote + */ qcom,bw-tbl = < 0 /* off */ >, - < 762 /* 100 MHz */ >, - < 1144 /* 150 MHz */ >, - < 1525 /* 200 MHz */ >, - < 2288 /* 300 MHz */ >, - < 3143 /* 412 MHz */ >, - < 4173 /* 547 MHz */ >, - < 5195 /* 681 MHz */ >, - < 5859 /* 768 MHz */ >, - < 7759 /* 1017 MHz */ >, - < 9887 /* 1296 MHz */ >, - < 10327 /* 1353 MHz */ >, - < 11863 /* 1555 MHz */ >, - < 13763 /* 1804 MHz */ >; + < 381 /* 100 MHz */ >, + < 572 /* 150 MHz */ >, + < 762 /* 200 MHz */ >, + < 1144 /* 300 MHz */ >, + < 1571 /* 412 MHz */ >, + < 2086 /* 547 MHz */ >, + < 2597 /* 681 MHz */ >, + < 2929 /* 768 MHz */ >, + < 3879 /* 1017 MHz */ >, + < 4943 /* 1296 MHz */ >, + < 5161 /* 1353 MHz */ >, + < 5931 /* 1555 MHz */ >, + < 6881 /* 1804 MHz */ >; }; msm_gpu: qcom,kgsl-3d0@5000000 { @@ -85,26 +90,27 @@ /* Bus Scale Settings */ qcom,gpubw-dev = <&gpubw>; qcom,bus-control; - qcom,bus-width = <16>; + /* GPU to BIMC bus width, VBIF data transfer in 1 cycle */ + qcom,bus-width = <32>; qcom,msm-bus,name = "grp3d"; qcom,msm-bus,num-cases = <14>; qcom,msm-bus,num-paths = <1>; qcom,msm-bus,vectors-KBps = <26 512 0 0>, - <26 512 0 800000>, /* 1 bus=100 */ - <26 512 0 1200000>, /* 2 bus=150 */ - <26 512 0 1600000>, /* 3 bus=200 */ - <26 512 0 2400000>, /* 4 bus=300 */ - <26 512 0 3296000>, /* 5 bus=412 */ - <26 512 0 4376000>, /* 6 bus=547 */ - <26 512 0 5448000>, /* 7 bus=681 */ - <26 512 0 6144000>, /* 8 bus=768 */ - <26 512 0 8136000>, /* 9 bus=1017 */ - <26 512 0 10368000>, /* 10 bus=1296 */ - <26 512 0 10824000>, /* 11 bus=1353 */ - <26 512 0 12440000>, /* 12 bus=1555 */ - <26 512 0 14432000>; /* 13 bus=1804 */ + <26 512 0 400000>, /* 1 bus=100 */ + <26 512 0 600000>, /* 2 bus=150 */ + <26 512 0 800000>, /* 3 bus=200 */ + <26 512 0 1200000>, /* 4 bus=300 */ + <26 512 0 1648000>, /* 5 bus=412 */ + <26 512 0 2188000>, /* 6 bus=547 */ + <26 512 0 2724000>, /* 7 bus=681 */ + <26 512 0 3072000>, /* 8 bus=768 */ + <26 512 0 4068000>, /* 9 bus=1017 */ + <26 512 0 5184000>, /* 10 bus=1296 */ + <26 512 0 5412000>, /* 11 bus=1353 */ + <26 512 0 6220000>, /* 12 bus=1555 */ + <26 512 0 7216000>; /* 13 bus=1804 */ /* GDSC regulator names */ regulator-names = "vddcx", "vdd"; @@ -161,8 +167,8 @@ qcom,gpu-pwrlevel@0 { reg = <0>; qcom,gpu-freq = <750000000>; - qcom,bus-freq = <12>; - qcom,bus-min = <11>; + qcom,bus-freq = <13>; + qcom,bus-min = <12>; qcom,bus-max = <13>; }; @@ -171,7 +177,7 @@ reg = <1>; qcom,gpu-freq = <700000000>; qcom,bus-freq = <11>; - qcom,bus-min = <10>; + qcom,bus-min = <11>; qcom,bus-max = <13>; }; @@ -179,7 +185,7 @@ qcom,gpu-pwrlevel@2 { reg = <2>; qcom,gpu-freq = <647000000>; - qcom,bus-freq = <10>; + qcom,bus-freq = <11>; qcom,bus-min = <10>; qcom,bus-max = <12>; }; @@ -188,9 +194,9 @@ qcom,gpu-pwrlevel@3 { reg = <3>; qcom,gpu-freq = <588000000>; - qcom,bus-freq = <9>; + qcom,bus-freq = <10>; qcom,bus-min = <9>; - qcom,bus-max = <11>; + qcom,bus-max = <12>; }; /* SVS_L1 */ @@ -198,7 +204,7 @@ reg = <4>; qcom,gpu-freq = <465000000>; qcom,bus-freq = <9>; - qcom,bus-min = <7>; + qcom,bus-min = <8>; qcom,bus-max = <11>; }; @@ -206,8 +212,8 @@ qcom,gpu-pwrlevel@5 { reg = <5>; qcom,gpu-freq = <370000000>; - qcom,bus-freq = <7>; - qcom,bus-min = <5>; + qcom,bus-freq = <8>; + qcom,bus-min = <6>; qcom,bus-max = <9>; }; @@ -225,7 +231,7 @@ reg = <7>; qcom,gpu-freq = <160000000>; qcom,bus-freq = <3>; - qcom,bus-min = <2>; + qcom,bus-min = <3>; qcom,bus-max = <5>; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi index 6407b32082f4..f4290d1aef0b 100644 --- a/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi @@ -92,6 +92,8 @@ 24 1f 08 09 05 03 04 a0 24 1f 08 09 05 03 04 a0 24 1c 08 09 05 03 04 a0]; + qcom,mdss-dsi-t-clk-post = <0x0e>; + qcom,mdss-dsi-t-clk-pre = <0x31>; }; &dsi_dual_sharp_video { diff --git a/arch/arm/boot/dts/qcom/sdm660-qrd.dts b/arch/arm/boot/dts/qcom/sdm660-qrd.dts index c78d3cbad731..5d888c9d039f 100644 --- a/arch/arm/boot/dts/qcom/sdm660-qrd.dts +++ b/arch/arm/boot/dts/qcom/sdm660-qrd.dts @@ -24,6 +24,43 @@ <0x0001001b 0x0201011a 0x0 0x0>; }; +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_fb0 { + qcom,mdss-mixer-swap; +}; + +&mdss_dsi { + hw-config = "split_dsi"; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_dual_nt36850_truly_cmd>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + qcom,platform-reset-gpio = <&tlmm 53 0>; + qcom,platform-te-gpio = <&tlmm 59 0>; +}; + +&mdss_dsi1 { + qcom,dsi-pref-prim-pan = <&dsi_dual_nt36850_truly_cmd>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + qcom,platform-reset-gpio = <&tlmm 53 0>; + qcom,platform-te-gpio = <&tlmm 59 0>; +}; + +&dsi_dual_nt36850_truly_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + &pm660l_wled { qcom,led-strings-list = [00 01]; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi index 6037bfd97fef..c09ab4c50692 100644 --- a/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi @@ -120,6 +120,38 @@ }; }; +&tlmm { + pmx_ts_rst_active { + ts_rst_active: ts_rst_active { + mux { + pins = "gpio66"; + function = "gpio"; + }; + + config { + pins = "gpio66"; + drive-strength = <16>; + bias-pull-up; + }; + }; + }; + + pmx_ts_rst_suspend { + ts_rst_suspend: ts_rst_suspend { + mux { + pins = "gpio66"; + function = "gpio"; + }; + + config { + pins = "gpio66"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; +}; + &soc { gpio_keys { compatible = "gpio-keys"; @@ -135,6 +167,24 @@ debounce-interval = <15>; }; }; + + hbtp { + compatible = "qcom,hbtp-input"; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend"; + pinctrl-0 = <&ts_rst_active>; + pinctrl-1 = <&ts_rst_suspend>; + vcc_ana-supply = <&pm660l_l3>; + vcc_dig-supply = <&pm660_l13>; + qcom,afe-load = <20000>; + qcom,afe-vtg-min = <3008000>; + qcom,afe-vtg-max = <3008000>; + qcom,dig-load = <40000>; + qcom,dig-vtg-min = <1808000>; + qcom,dig-vtg-max = <1808000>; + qcom,fb-resume-delay-us = <10000>; + qcom,afe-power-on-delay-us = <1000>; + qcom,afe-power-off-delay-us = <6>; + }; }; / { @@ -150,40 +200,3 @@ qcom,fg-jeita-thresholds = <0 5 55 55>; qcom,fg-cutoff-voltage = <3700>; }; - -&mdss_mdp { - qcom,mdss-pref-prim-intf = "dsi"; -}; - -&mdss_fb0 { - qcom,mdss-mixer-swap; -}; - -&mdss_dsi { - hw-config = "split_dsi"; -}; - -&mdss_dsi0 { - qcom,dsi-pref-prim-pan = <&dsi_dual_nt36850_truly_cmd>; - pinctrl-names = "mdss_default", "mdss_sleep"; - pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; - pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; - qcom,platform-reset-gpio = <&tlmm 53 0>; - qcom,platform-te-gpio = <&tlmm 59 0>; -}; - -&mdss_dsi1 { - qcom,dsi-pref-prim-pan = <&dsi_dual_nt36850_truly_cmd>; - pinctrl-names = "mdss_default", "mdss_sleep"; - pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; - pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; - qcom,platform-reset-gpio = <&tlmm 53 0>; - qcom,platform-te-gpio = <&tlmm 59 0>; -}; - -&dsi_dual_nt36850_truly_cmd { - qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; - qcom,mdss-dsi-bl-min-level = <1>; - qcom,mdss-dsi-bl-max-level = <4095>; - qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; -}; diff --git a/arch/arm/boot/dts/qcom/sdm660.dtsi b/arch/arm/boot/dts/qcom/sdm660.dtsi index 7335aab92478..612ced1087dc 100644 --- a/arch/arm/boot/dts/qcom/sdm660.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660.dtsi @@ -841,7 +841,14 @@ interrupts = <0 291 0>, <0 292 0>; interrupt-names = "slimbus_irq", "slimbus_bam_irq"; qcom,apps-ch-pipes = <0x1800>; - status = "disabled"; + + /* Slimbus Slave DT for WCN3990 */ + btfmslim_codec: wcn3990 { + compatible = "qcom,btfmslim_slave"; + elemental-addr = [00 01 20 02 17 02]; + qcom,btfm-slim-ifd = "btfmslim_slave_ifd"; + qcom,btfm-slim-ifd-elemental-addr = [00 00 20 02 17 02]; + }; }; timer@17920000 { @@ -1004,19 +1011,19 @@ qcom,src-dst-ports = <1 512>; qcom,active-only; qcom,bw-tbl = - < 762 /* 100 MHz */ >, - < 1144 /* 150 MHz */ >, - < 1525 /* 200 MHz */ >, - < 2288 /* 300 MHz */ >, - < 3143 /* 412 MHz */ >, - < 4173 /* 547 MHz */ >, - < 5195 /* 681 MHz */ >, - < 5859 /* 768 MHz */ >, - < 7759 /* 1017 MHz */ >, - < 9887 /* 1296 MHz */ >, - < 10327 /* 1353 MHz */ >, - < 11863 /* 1555 MHz */ >, - < 13763 /* 1804 MHz */ >; + < 381 /* 100 MHz */ >, + < 572 /* 150 MHz */ >, + < 762 /* 200 MHz */ >, + < 1144 /* 300 MHz */ >, + < 1571 /* 412 MHz */ >, + < 2086 /* 547 MHz */ >, + < 2597 /* 681 MHz */ >, + < 2929 /* 768 MHz */ >, + < 3879 /* 1017 MHz */ >, + < 4943 /* 1296 MHz */ >, + < 5163 /* 1353 MHz */ >, + < 5931 /* 1555 MHz */ >, + < 6881 /* 1804 MHz */ >; }; bwmon: qcom,cpu-bwmon { @@ -1035,19 +1042,19 @@ qcom,src-dst-ports = <1 512>; qcom,active-only; qcom,bw-tbl = - < 762 /* 100 MHz */ >, - < 1144 /* 150 MHz */ >, - < 1525 /* 200 MHz */ >, - < 2288 /* 300 MHz */ >, - < 3143 /* 412 MHz */ >, - < 4173 /* 547 MHz */ >, - < 5195 /* 681 MHz */ >, - < 5859 /* 768 MHz */ >, - < 7759 /* 1017 MHz */ >, - < 9887 /* 1296 MHz */ >, - < 10327 /* 1353 MHz */ >, - < 11863 /* 1555 MHz */ >, - < 13763 /* 1804 MHz */ >; + < 381 /* 100 MHz */ >, + < 572 /* 150 MHz */ >, + < 762 /* 200 MHz */ >, + < 1144 /* 300 MHz */ >, + < 1571 /* 412 MHz */ >, + < 2086 /* 547 MHz */ >, + < 2597 /* 681 MHz */ >, + < 2929 /* 768 MHz */ >, + < 3879 /* 1017 MHz */ >, + < 4943 /* 1296 MHz */ >, + < 5163 /* 1353 MHz */ >, + < 5931 /* 1555 MHz */ >, + < 6881 /* 1804 MHz */ >; }; memlat_cpu0: qcom,memlat-cpu0 { @@ -1056,19 +1063,19 @@ qcom,src-dst-ports = <1 512>; qcom,active-only; qcom,bw-tbl = - < 762 /* 100 MHz */ >, - < 1144 /* 150 MHz */ >, - < 1525 /* 200 MHz */ >, - < 2288 /* 300 MHz */ >, - < 3143 /* 412 MHz */ >, - < 4173 /* 547 MHz */ >, - < 5195 /* 681 MHz */ >, - < 5859 /* 768 MHz */ >, - < 7759 /* 1017 MHz */ >, - < 9887 /* 1296 MHz */ >, - < 10327 /* 1353 MHz */ >, - < 11863 /* 1555 MHz */ >, - < 13763 /* 1804 MHz */ >; + < 381 /* 100 MHz */ >, + < 572 /* 150 MHz */ >, + < 762 /* 200 MHz */ >, + < 1144 /* 300 MHz */ >, + < 1571 /* 412 MHz */ >, + < 2086 /* 547 MHz */ >, + < 2597 /* 681 MHz */ >, + < 2929 /* 768 MHz */ >, + < 3879 /* 1017 MHz */ >, + < 4943 /* 1296 MHz */ >, + < 5163 /* 1353 MHz */ >, + < 5931 /* 1555 MHz */ >, + < 6881 /* 1804 MHz */ >; }; memlat_cpu4: qcom,memlat-cpu4 { @@ -1077,19 +1084,19 @@ qcom,src-dst-ports = <1 512>; qcom,active-only; qcom,bw-tbl = - < 762 /* 100 MHz */ >, - < 1144 /* 150 MHz */ >, - < 1525 /* 200 MHz */ >, - < 2288 /* 300 MHz */ >, - < 3143 /* 412 MHz */ >, - < 4173 /* 547 MHz */ >, - < 5195 /* 681 MHz */ >, - < 5859 /* 768 MHz */ >, - < 7759 /* 1017 MHz */ >, - < 9887 /* 1296 MHz */ >, - < 10327 /* 1353 MHz */ >, - < 11863 /* 1555 MHz */ >, - < 13763 /* 1804 MHz */ >; + < 381 /* 100 MHz */ >, + < 572 /* 150 MHz */ >, + < 762 /* 200 MHz */ >, + < 1144 /* 300 MHz */ >, + < 1571 /* 412 MHz */ >, + < 2086 /* 547 MHz */ >, + < 2597 /* 681 MHz */ >, + < 2929 /* 768 MHz */ >, + < 3879 /* 1017 MHz */ >, + < 4943 /* 1296 MHz */ >, + < 5163 /* 1353 MHz */ >, + < 5931 /* 1555 MHz */ >, + < 6881 /* 1804 MHz */ >; }; devfreq_memlat_0: qcom,arm-memlat-mon-0 { @@ -1097,9 +1104,9 @@ qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>; qcom,target-dev = <&memlat_cpu0>; qcom,core-dev-table = - < 633600 1525 >, - < 1401600 4173 >, - < 1881600 7759 >; + < 633600 762 >, + < 1401600 2086 >, + < 1881600 3879 >; }; devfreq_memlat_4: qcom,arm-memlat-mon-4 { @@ -1107,25 +1114,25 @@ qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>; qcom,target-dev = <&memlat_cpu4>; qcom,core-dev-table = - < 1113600 1525 >, - < 1401600 7759 >, - < 2150400 11863 >, - < 2457600 13763 >; + < 1113600 762 >, + < 1401600 3879 >, + < 2150400 5931 >, + < 2457600 6881 >; }; devfreq_cpufreq: devfreq-cpufreq { mincpubw-cpufreq { target-dev = <&mincpubw>; cpu-to-dev-map-0 = - < 633600 1525 >, - < 1401600 3143 >, - < 1881600 5859 >; + < 633600 762 >, + < 1401600 1571 >, + < 1881600 2929 >; cpu-to-dev-map-4 = - < 1113600 1525 >, - < 1401600 4173 >, - < 1747200 5859 >, - < 2150400 7759 >, - < 2457600 13763 >; + < 1113600 762 >, + < 1401600 2086 >, + < 1747200 2929 >, + < 2150400 3879 >, + < 2457600 6881 >; }; }; @@ -1269,8 +1276,10 @@ 100000000 200000000 400000000 4294967295>; clocks = <&clock_gcc GCC_SDCC1_AHB_CLK>, - <&clock_gcc GCC_SDCC1_APPS_CLK>; - clock-names = "iface_clk", "core_clk"; + <&clock_gcc GCC_SDCC1_APPS_CLK>, + <&clock_gcc GCC_SDCC1_ICE_CORE_CLK>; + clock-names = "iface_clk", "core_clk", "ice_core_clk"; + qcom,ice-clk-rates = <300000000 150000000>; status = "disabled"; }; diff --git a/arch/arm/configs/msmcortex_defconfig b/arch/arm/configs/msmcortex_defconfig index fec429d7bd0c..2cfe647855c3 100644 --- a/arch/arm/configs/msmcortex_defconfig +++ b/arch/arm/configs/msmcortex_defconfig @@ -293,12 +293,13 @@ CONFIG_PINCTRL_SDM660=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_QPNP_PIN=y CONFIG_POWER_SUPPLY=y -CONFIG_QPNP_FG_GEN3=y +CONFIG_QPNP_SMBCHARGER=y +CONFIG_SMB135X_CHARGER=y +CONFIG_SMB1351_USB_CHARGER=y CONFIG_MSM_BCL_CTL=y CONFIG_MSM_BCL_PERIPHERAL_CTL=y CONFIG_QPNP_SMB2=y CONFIG_SMB138X_CHARGER=y -CONFIG_QPNP_QNOVO=y CONFIG_APSS_CORE_EA=y CONFIG_MSM_APM=y CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y @@ -477,7 +478,6 @@ CONFIG_QCOM_DEVFREQ_DEVBW=y CONFIG_EXTCON=y CONFIG_IIO=y CONFIG_QCOM_RRADC=y -CONFIG_QCOM_TADC=y CONFIG_PWM=y CONFIG_PWM_QPNP=y CONFIG_ARM_GIC_V3_ACL=y diff --git a/drivers/clk/msm/clock-mmss-8998.c b/drivers/clk/msm/clock-mmss-8998.c index 2a112aad1fa3..eb543010c17b 100644 --- a/drivers/clk/msm/clock-mmss-8998.c +++ b/drivers/clk/msm/clock-mmss-8998.c @@ -527,6 +527,7 @@ static struct clk_freq_tbl ftbl_csiphy_clk_src[] = { static struct clk_freq_tbl ftbl_csiphy_clk_src_vq[] = { F_MM( 164570000, mmpll10_pll_out, 3.5, 0, 0), F_MM( 256000000, mmpll4_pll_out, 3, 0, 0), + F_MM( 274290000, mmpll7_pll_out, 3.5, 0, 0), F_MM( 300000000, mmsscc_gpll0, 2, 0, 0), F_MM( 384000000, mmpll4_pll_out, 2, 0, 0), F_END diff --git a/drivers/clk/qcom/gcc-sdm660.c b/drivers/clk/qcom/gcc-sdm660.c index 076ff3565ef4..d8ae85b65a47 100644 --- a/drivers/clk/qcom/gcc-sdm660.c +++ b/drivers/clk/qcom/gcc-sdm660.c @@ -818,7 +818,7 @@ static struct clk_rcg2 hmss_rbcpr_clk_src = { .parent_names = gcc_parent_names_ao_1, .num_parents = 3, .ops = &clk_rcg2_ops, - VDD_DIG_FMAX_MAP2( + VDD_DIG_FMAX_MAP2_AO( LOWER, 19200000, NOMINAL, 50000000), }, diff --git a/drivers/clk/qcom/vdd-level-660.h b/drivers/clk/qcom/vdd-level-660.h index f98a96033ea9..53317fe6d294 100644 --- a/drivers/clk/qcom/vdd-level-660.h +++ b/drivers/clk/qcom/vdd-level-660.h @@ -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 @@ -95,6 +95,14 @@ }, \ .num_rate_max = VDD_DIG_NUM +#define VDD_DIG_FMAX_MAP2_AO(l1, f1, l2, f2) \ + .vdd_class = &vdd_dig_ao, \ + .rate_max = (unsigned long[VDD_DIG_NUM]) { \ + [VDD_DIG_##l1] = (f1), \ + [VDD_DIG_##l2] = (f2), \ + }, \ + .num_rate_max = VDD_DIG_NUM + #define VDD_DIG_FMAX_MAP3_AO(l1, f1, l2, f2, l3, f3) \ .vdd_class = &vdd_dig_ao, \ .rate_max = (unsigned long[VDD_DIG_NUM]) { \ diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c index 433e4783d1d1..9ab03209b680 100644 --- a/drivers/crypto/msm/qcedev.c +++ b/drivers/crypto/msm/qcedev.c @@ -1,6 +1,6 @@ /* Qualcomm CE device driver. * - * Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2010-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 @@ -1381,7 +1381,7 @@ static int qcedev_check_cipher_key(struct qcedev_cipher_op_req *req, /* if not using HW key make sure key * length is valid */ - if ((req->mode == QCEDEV_AES_MODE_XTS)) { + if (req->mode == QCEDEV_AES_MODE_XTS) { if ((req->encklen != QCEDEV_AES_KEY_128*2) && (req->encklen != QCEDEV_AES_KEY_256*2)) { pr_err("%s: unsupported key size: %d\n", diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index cd9a82a9bf4a..fe6aa45901d0 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-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 @@ -1994,6 +1994,42 @@ static int _isense_clk_set_rate(struct kgsl_pwrctrl *pwr, int level) return clk_set_rate(pwr->grp_clks[pwr->isense_clk_indx], rate); } +static inline void _close_pcl(struct kgsl_pwrctrl *pwr) +{ + if (pwr->pcl) + msm_bus_scale_unregister_client(pwr->pcl); + + pwr->pcl = 0; +} + +static inline void _close_ocmem_pcl(struct kgsl_pwrctrl *pwr) +{ + if (pwr->ocmem_pcl) + msm_bus_scale_unregister_client(pwr->ocmem_pcl); + + pwr->ocmem_pcl = 0; +} + +static inline void _close_regulators(struct kgsl_pwrctrl *pwr) +{ + int i; + + for (i = 0; i < KGSL_MAX_REGULATORS; i++) + pwr->regulators[i].reg = NULL; +} + +static inline void _close_clks(struct kgsl_device *device) +{ + struct kgsl_pwrctrl *pwr = &device->pwrctrl; + int i; + + for (i = 0; i < KGSL_MAX_CLKS; i++) + pwr->grp_clks[i] = NULL; + + if (pwr->gpu_bimc_int_clk) + devm_clk_put(&device->pdev->dev, pwr->gpu_bimc_int_clk); +} + int kgsl_pwrctrl_init(struct kgsl_device *device) { int i, k, m, n = 0, result; @@ -2011,7 +2047,7 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) result = _get_clocks(device); if (result) - return result; + goto error_cleanup_clks; /* Make sure we have a source clk for freq setting */ if (pwr->grp_clks[0] == NULL) @@ -2029,7 +2065,8 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) if (pwr->num_pwrlevels == 0) { KGSL_PWR_ERR(device, "No power levels are defined\n"); - return -EINVAL; + result = -EINVAL; + goto error_cleanup_clks; } /* Initialize the user and thermal clock constraints */ @@ -2059,7 +2096,7 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) result = get_regulators(device); if (result) - return result; + goto error_cleanup_regulators; pwr->power_flags = 0; @@ -2079,8 +2116,10 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) pwr->ocmem_pcl = msm_bus_scale_register_client (ocmem_scale_table); - if (!pwr->ocmem_pcl) - return -EINVAL; + if (!pwr->ocmem_pcl) { + result = -EINVAL; + goto error_disable_pm; + } } /* Bus width in bytes, set it to zero if not found */ @@ -2110,14 +2149,18 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) * from the driver. */ pwr->pcl = msm_bus_scale_register_client(bus_scale_table); - if (pwr->pcl == 0) - return -EINVAL; + if (pwr->pcl == 0) { + result = -EINVAL; + goto error_cleanup_ocmem_pcl; + } } pwr->bus_ib = kzalloc(bus_scale_table->num_usecases * sizeof(*pwr->bus_ib), GFP_KERNEL); - if (pwr->bus_ib == NULL) - return -ENOMEM; + if (pwr->bus_ib == NULL) { + result = -ENOMEM; + goto error_cleanup_pcl; + } /* * Pull the BW vote out of the bus table. They will be used to @@ -2175,36 +2218,26 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) &pwr->tsens_name); return result; + +error_cleanup_pcl: + _close_pcl(pwr); +error_cleanup_ocmem_pcl: + _close_ocmem_pcl(pwr); +error_disable_pm: + pm_runtime_disable(&pdev->dev); +error_cleanup_regulators: + _close_regulators(pwr); +error_cleanup_clks: + _close_clks(device); + return result; } void kgsl_pwrctrl_close(struct kgsl_device *device) { struct kgsl_pwrctrl *pwr = &device->pwrctrl; - int i; KGSL_PWR_INFO(device, "close device %d\n", device->id); - pm_runtime_disable(&device->pdev->dev); - - if (pwr->pcl) - msm_bus_scale_unregister_client(pwr->pcl); - - pwr->pcl = 0; - - if (pwr->ocmem_pcl) - msm_bus_scale_unregister_client(pwr->ocmem_pcl); - - pwr->ocmem_pcl = 0; - - for (i = 0; i < KGSL_MAX_REGULATORS; i++) - pwr->regulators[i].reg = NULL; - - for (i = 0; i < KGSL_MAX_REGULATORS; i++) - pwr->grp_clks[i] = NULL; - - if (pwr->gpu_bimc_int_clk) - devm_clk_put(&device->pdev->dev, pwr->gpu_bimc_int_clk); - pwr->power_flags = 0; if (!IS_ERR_OR_NULL(pwr->sysfs_pwr_limit)) { @@ -2213,6 +2246,16 @@ void kgsl_pwrctrl_close(struct kgsl_device *device) pwr->sysfs_pwr_limit = NULL; } kfree(pwr->bus_ib); + + _close_pcl(pwr); + + _close_ocmem_pcl(pwr); + + pm_runtime_disable(&device->pdev->dev); + + _close_regulators(pwr); + + _close_clks(device); } /** diff --git a/drivers/mfd/qcom-i2c-pmic.c b/drivers/mfd/qcom-i2c-pmic.c index ea5ac972b096..590e4c1a3f52 100644 --- a/drivers/mfd/qcom-i2c-pmic.c +++ b/drivers/mfd/qcom-i2c-pmic.c @@ -1,4 +1,4 @@ -/* 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 @@ -467,12 +467,29 @@ static int i2c_pmic_parse_dt(struct i2c_pmic *chip) return rc; } +#define MAX_I2C_RETRIES 3 +static int i2c_pmic_read(struct regmap *map, unsigned int reg, void *val, + size_t val_count) +{ + int rc, retries = 0; + + do { + rc = regmap_bulk_read(map, reg, val, val_count); + } while (rc == -ENOTCONN && retries++ < MAX_I2C_RETRIES); + + if (retries > 1) + pr_err("i2c_pmic_read failed for %d retries, rc = %d\n", + retries - 1, rc); + + return rc; +} + static int i2c_pmic_determine_initial_status(struct i2c_pmic *chip) { int rc, i; for (i = 0; i < chip->num_periphs; i++) { - rc = regmap_bulk_read(chip->regmap, + rc = i2c_pmic_read(chip->regmap, chip->periph[i].addr | INT_SET_TYPE_OFFSET, chip->periph[i].cached, IRQ_MAX_REGS); if (rc < 0) { diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c index 5bcd0db929b3..ceef607f67c0 100644 --- a/drivers/mfd/wcd9xxx-core.c +++ b/drivers/mfd/wcd9xxx-core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-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 @@ -1214,11 +1214,19 @@ static int wcd9xxx_slim_probe(struct slim_device *slim) { struct wcd9xxx *wcd9xxx; struct wcd9xxx_pdata *pdata; + const struct slim_device_id *device_id; int ret = 0; int intf_type; intf_type = wcd9xxx_get_intf_type(); + wcd9xxx = devm_kzalloc(&slim->dev, sizeof(struct wcd9xxx), + GFP_KERNEL); + if (!wcd9xxx) { + ret = -ENOMEM; + goto err; + } + if (!slim) { ret = -EINVAL; goto err; @@ -1227,7 +1235,8 @@ static int wcd9xxx_slim_probe(struct slim_device *slim) if (intf_type == WCD9XXX_INTERFACE_TYPE_I2C) { dev_dbg(&slim->dev, "%s:Codec is detected in I2C mode\n", __func__); - return -ENODEV; + ret = -ENODEV; + goto err; } if (slim->dev.of_node) { dev_info(&slim->dev, "Platform data from device tree\n"); @@ -1261,21 +1270,22 @@ static int wcd9xxx_slim_probe(struct slim_device *slim) goto err; } - wcd9xxx = devm_kzalloc(&slim->dev, sizeof(struct wcd9xxx), - GFP_KERNEL); - if (!wcd9xxx) { - ret = -ENOMEM; - goto err; - } if (!slim->ctrl) { dev_err(&slim->dev, "%s: Error, no SLIMBUS control data\n", __func__); ret = -EINVAL; goto err_codec; } - wcd9xxx->type = slim_get_device_id(slim)->driver_data; + device_id = slim_get_device_id(slim); + if (!device_id) { + dev_err(&slim->dev, "%s: Error, no device id\n", __func__); + ret = -EINVAL; + goto err; + } + + wcd9xxx->type = device_id->driver_data; dev_info(&slim->dev, "%s: probing for wcd type: %d, name: %s\n", - __func__, wcd9xxx->type, slim_get_device_id(slim)->name); + __func__, wcd9xxx->type, device_id->name); /* wcd9xxx members init */ wcd9xxx->multi_reg_write = wcd9xxx_slim_multi_reg_write; @@ -1416,6 +1426,7 @@ err_supplies: err_codec: slim_set_clientdata(slim, NULL); err: + devm_kfree(&slim->dev, wcd9xxx); return ret; } static int wcd9xxx_slim_remove(struct slim_device *pdev) @@ -1508,9 +1519,9 @@ static int wcd9xxx_slim_device_down(struct slim_device *sldev) return 0; wcd9xxx->dev_up = false; - wcd9xxx_irq_exit(&wcd9xxx->core_res); if (wcd9xxx->dev_down) wcd9xxx->dev_down(wcd9xxx); + wcd9xxx_irq_exit(&wcd9xxx->core_res); wcd9xxx_reset_low(wcd9xxx->dev); return 0; } diff --git a/drivers/mfd/wcd9xxx-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c index 4bce44008c45..1ac7b597fdd3 100644 --- a/drivers/mfd/wcd9xxx-slimslave.c +++ b/drivers/mfd/wcd9xxx-slimslave.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-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,10 @@ int wcd9xxx_init_slimslave(struct wcd9xxx *wcd9xxx, u8 wcd9xxx_pgd_la, goto err; } + if (!rx_num || rx_num > wcd9xxx->num_rx_port) { + pr_err("%s: invalid rx num %d\n", __func__, rx_num); + return -EINVAL; + } if (wcd9xxx->rx_chs) { wcd9xxx->num_rx_port = rx_num; for (i = 0; i < rx_num; i++) { @@ -84,6 +88,10 @@ int wcd9xxx_init_slimslave(struct wcd9xxx *wcd9xxx, u8 wcd9xxx_pgd_la, wcd9xxx->num_rx_port); } + if (!tx_num || tx_num > wcd9xxx->num_tx_port) { + pr_err("%s: invalid tx num %d\n", __func__, tx_num); + return -EINVAL; + } if (wcd9xxx->tx_chs) { wcd9xxx->num_tx_port = tx_num; for (i = 0; i < tx_num; i++) { diff --git a/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c b/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c index 940fd08654d2..9889d9c4723b 100644 --- a/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c +++ b/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -29,6 +29,8 @@ struct q6audio_effects { struct audio_client *ac; struct msm_hwacc_effects_config config; + struct mutex lock; + atomic_t in_count; atomic_t out_count; @@ -230,8 +232,11 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd, uint32_t idx = 0; uint32_t size = 0; + mutex_lock(&effects->lock); + if (!effects->started) { rc = -EFAULT; + mutex_unlock(&effects->lock); goto ioctl_fail; } @@ -241,11 +246,13 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd, if (!rc) { pr_err("%s: write wait_event_timeout\n", __func__); rc = -EFAULT; + mutex_unlock(&effects->lock); goto ioctl_fail; } if (!atomic_read(&effects->out_count)) { pr_err("%s: pcm stopped out_count 0\n", __func__); rc = -EFAULT; + mutex_unlock(&effects->lock); goto ioctl_fail; } @@ -255,6 +262,7 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd, copy_from_user(bufptr, (void *)arg, effects->config.buf_cfg.output_len)) { rc = -EFAULT; + mutex_unlock(&effects->lock); goto ioctl_fail; } rc = q6asm_write(effects->ac, @@ -262,6 +270,7 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd, 0, 0, NO_TIMESTAMP); if (rc < 0) { rc = -EFAULT; + mutex_unlock(&effects->lock); goto ioctl_fail; } atomic_dec(&effects->out_count); @@ -269,6 +278,7 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd, pr_err("%s: AUDIO_EFFECTS_WRITE: Buffer dropped\n", __func__); } + mutex_unlock(&effects->lock); break; } case AUDIO_EFFECTS_READ: { @@ -466,6 +476,7 @@ static long audio_effects_ioctl(struct file *file, unsigned int cmd, break; } case AUDIO_EFFECTS_SET_BUF_LEN: { + mutex_lock(&effects->lock); if (copy_from_user(&effects->config.buf_cfg, (void *)arg, sizeof(effects->config.buf_cfg))) { pr_err("%s: copy from user for AUDIO_EFFECTS_SET_BUF_LEN failed\n", @@ -475,6 +486,7 @@ static long audio_effects_ioctl(struct file *file, unsigned int cmd, pr_debug("%s: write buf len: %d, read buf len: %d\n", __func__, effects->config.buf_cfg.output_len, effects->config.buf_cfg.input_len); + mutex_unlock(&effects->lock); break; } case AUDIO_EFFECTS_GET_BUF_AVAIL: { @@ -719,6 +731,7 @@ static int audio_effects_release(struct inode *inode, struct file *file) } q6asm_audio_client_free(effects->ac); + mutex_destroy(&effects->lock); kfree(effects); pr_debug("%s: close session success\n", __func__); @@ -749,6 +762,7 @@ static int audio_effects_open(struct inode *inode, struct file *file) init_waitqueue_head(&effects->read_wait); init_waitqueue_head(&effects->write_wait); + mutex_init(&effects->lock); effects->opened = 0; effects->started = 0; diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig index 57cc6b29b2d0..9e0ccdc44d6b 100644 --- a/drivers/mmc/core/Kconfig +++ b/drivers/mmc/core/Kconfig @@ -2,6 +2,17 @@ # MMC core configuration # +config MMC_RING_BUFFER + bool "MMC_RING_BUFFER" + depends on MMC + default n + help + This enables the ring buffer tracing of significant + events for mmc driver to provide command history for + debugging purpose. + + If unsure, say N. + config MMC_EMBEDDED_SDIO boolean "MMC embedded SDIO device support (EXPERIMENTAL)" help diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index 2c25138f28b7..60781dd192ab 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -10,3 +10,4 @@ mmc_core-y := core.o bus.o host.o \ quirks.o slot-gpio.o mmc_core-$(CONFIG_OF) += pwrseq.o pwrseq_simple.o pwrseq_emmc.o mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o +obj-$(CONFIG_MMC_RING_BUFFER) += ring_buffer.o diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index c894f64c2e38..a0d31ded04db 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -32,6 +32,26 @@ module_param(fail_request, charp, 0); #endif /* CONFIG_FAIL_MMC_REQUEST */ /* The debugfs functions are optimized away when CONFIG_DEBUG_FS isn't set. */ +static int mmc_ring_buffer_show(struct seq_file *s, void *data) +{ + struct mmc_host *mmc = s->private; + + mmc_dump_trace_buffer(mmc, s); + return 0; +} + +static int mmc_ring_buffer_open(struct inode *inode, struct file *file) +{ + return single_open(file, mmc_ring_buffer_show, inode->i_private); +} + +static const struct file_operations mmc_ring_buffer_fops = { + .open = mmc_ring_buffer_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int mmc_ios_show(struct seq_file *s, void *data) { static const char *vdd_str[] = { @@ -368,6 +388,11 @@ void mmc_add_host_debugfs(struct mmc_host *host) &host->cmdq_thist_enabled)) goto err_node; +#ifdef CONFIG_MMC_RING_BUFFER + if (!debugfs_create_file("ring_buffer", S_IRUSR, + root, host, &mmc_ring_buffer_fops)) + goto err_node; +#endif #ifdef CONFIG_MMC_CLKGATE if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR), root, &host->clk_delay)) diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index f6a54a8e1076..333f691a73c7 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -26,6 +26,8 @@ #include <linux/mmc/host.h> #include <linux/mmc/card.h> +#include <linux/mmc/ring_buffer.h> + #include <linux/mmc/slot-gpio.h> #include "core.h" @@ -869,6 +871,7 @@ int mmc_add_host(struct mmc_host *host) mmc_add_host_debugfs(host); #endif mmc_host_clk_sysfs_init(host); + mmc_trace_init(host); err = sysfs_create_group(&host->class_dev.kobj, &clk_scaling_attr_grp); if (err) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 449514bae4f3..414877874190 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -2635,6 +2635,7 @@ static int mmc_suspend(struct mmc_host *host) int err; ktime_t start = ktime_get(); + MMC_TRACE(host, "%s: Enter\n", __func__); err = _mmc_suspend(host, true); if (!err) { pm_runtime_disable(&host->card->dev); @@ -2643,6 +2644,7 @@ static int mmc_suspend(struct mmc_host *host) trace_mmc_suspend(mmc_hostname(host), err, ktime_to_us(ktime_sub(ktime_get(), start))); + MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err); return err; } @@ -2718,6 +2720,7 @@ static int mmc_resume(struct mmc_host *host) int err = 0; ktime_t start = ktime_get(); + MMC_TRACE(host, "%s: Enter\n", __func__); if (!(host->caps & MMC_CAP_RUNTIME_RESUME)) { err = _mmc_resume(host); pm_runtime_set_active(&host->card->dev); @@ -2727,7 +2730,7 @@ static int mmc_resume(struct mmc_host *host) trace_mmc_resume(mmc_hostname(host), err, ktime_to_us(ktime_sub(ktime_get(), start))); - + MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err); return err; } diff --git a/drivers/mmc/core/ring_buffer.c b/drivers/mmc/core/ring_buffer.c new file mode 100644 index 000000000000..83945e1cae40 --- /dev/null +++ b/drivers/mmc/core/ring_buffer.c @@ -0,0 +1,123 @@ +/* + * 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/mmc/ring_buffer.h> +#include <linux/mmc/host.h> + +void mmc_stop_tracing(struct mmc_host *mmc) +{ + mmc->trace_buf.stop_tracing = true; +} + +void mmc_trace_write(struct mmc_host *mmc, + const char *fmt, ...) +{ + unsigned int idx; + va_list args; + char *event; + unsigned long flags; + char str[MMC_TRACE_EVENT_SZ]; + + if (unlikely(!mmc->trace_buf.data) || + unlikely(mmc->trace_buf.stop_tracing)) + return; + + /* + * Here an increment and modulus is used to keep + * index within array bounds. The cast to unsigned is + * necessary so increment and rolover wraps to 0 correctly + */ + spin_lock_irqsave(&mmc->trace_buf.trace_lock, flags); + mmc->trace_buf.wr_idx += 1; + idx = ((unsigned int)mmc->trace_buf.wr_idx) & + (MMC_TRACE_RBUF_NUM_EVENTS - 1); + spin_unlock_irqrestore(&mmc->trace_buf.trace_lock, flags); + + /* Catch some unlikely machine specific wrap-around bug */ + if (unlikely(idx > (MMC_TRACE_RBUF_NUM_EVENTS - 1))) { + pr_err("%s: %s: Invalid idx:%d for mmc trace, tracing stopped !\n", + mmc_hostname(mmc), __func__, idx); + mmc_stop_tracing(mmc); + return; + } + + event = &mmc->trace_buf.data[idx * MMC_TRACE_EVENT_SZ]; + va_start(args, fmt); + snprintf(str, MMC_TRACE_EVENT_SZ, "<%d> %lld: %s: %s", + raw_smp_processor_id(), + ktime_to_ns(ktime_get()), + mmc_hostname(mmc), fmt); + memset(event, '\0', MMC_TRACE_EVENT_SZ); + vscnprintf(event, MMC_TRACE_EVENT_SZ, str, args); + va_end(args); +} + +void mmc_trace_init(struct mmc_host *mmc) +{ + BUILD_BUG_ON_NOT_POWER_OF_2(MMC_TRACE_RBUF_NUM_EVENTS); + + mmc->trace_buf.data = (char *) + __get_free_pages(GFP_KERNEL|__GFP_ZERO, + MMC_TRACE_RBUF_SZ_ORDER); + + if (!mmc->trace_buf.data) { + pr_err("%s: %s: Unable to allocate trace for mmc\n", + __func__, mmc_hostname(mmc)); + return; + } + + spin_lock_init(&mmc->trace_buf.trace_lock); + mmc->trace_buf.wr_idx = -1; +} + +void mmc_trace_free(struct mmc_host *mmc) +{ + if (mmc->trace_buf.data) + free_pages((unsigned long)mmc->trace_buf.data, + MMC_TRACE_RBUF_SZ_ORDER); +} + +void mmc_dump_trace_buffer(struct mmc_host *mmc, struct seq_file *s) +{ + unsigned int idx, cur_idx; + unsigned int N = MMC_TRACE_RBUF_NUM_EVENTS - 1; + char *event; + unsigned long flags; + + if (!mmc->trace_buf.data) + return; + + spin_lock_irqsave(&mmc->trace_buf.trace_lock, flags); + idx = ((unsigned int)mmc->trace_buf.wr_idx) & N; + cur_idx = (idx + 1) & N; + + do { + event = &mmc->trace_buf.data[cur_idx * MMC_TRACE_EVENT_SZ]; + if (s) + seq_printf(s, "%s", (char *)event); + else + pr_err("%s", (char *)event); + cur_idx = (cur_idx + 1) & N; + if (cur_idx == idx) { + event = + &mmc->trace_buf.data[cur_idx * MMC_TRACE_EVENT_SZ]; + if (s) + seq_printf(s, "latest_event: %s", + (char *)event); + else + pr_err("latest_event: %s", (char *)event); + break; + } + } while (1); + spin_unlock_irqrestore(&mmc->trace_buf.trace_lock, flags); +} diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 7b84030ffe92..7e7d7eb4da2a 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1222,11 +1222,13 @@ static int mmc_sd_suspend(struct mmc_host *host) { int err; + MMC_TRACE(host, "%s: Enter\n", __func__); err = _mmc_sd_suspend(host); if (!err) { pm_runtime_disable(&host->card->dev); pm_runtime_set_suspended(&host->card->dev); } + MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err); return err; } @@ -1292,12 +1294,14 @@ static int mmc_sd_resume(struct mmc_host *host) { int err = 0; + MMC_TRACE(host, "%s: Enter\n", __func__); if (!(host->caps & MMC_CAP_RUNTIME_RESUME)) { err = _mmc_sd_resume(host); pm_runtime_set_active(&host->card->dev); pm_runtime_mark_last_busy(&host->card->dev); } pm_runtime_enable(&host->card->dev); + MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err); return err; } diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 5fedab49cf34..13a2f2d14d12 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -998,6 +998,7 @@ static int mmc_sdio_pre_suspend(struct mmc_host *host) */ static int mmc_sdio_suspend(struct mmc_host *host) { + MMC_TRACE(host, "%s: Enter\n", __func__); mmc_claim_host(host); if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) @@ -1013,7 +1014,7 @@ static int mmc_sdio_suspend(struct mmc_host *host) } mmc_release_host(host); - + MMC_TRACE(host, "%s: Exit\n", __func__); return 0; } @@ -1024,6 +1025,7 @@ static int mmc_sdio_resume(struct mmc_host *host) BUG_ON(!host); BUG_ON(!host->card); + MMC_TRACE(host, "%s: Enter\n", __func__); /* Basic card reinitialization. */ mmc_claim_host(host); @@ -1079,6 +1081,7 @@ static int mmc_sdio_resume(struct mmc_host *host) host->pm_flags &= ~MMC_PM_KEEP_POWER; host->pm_flags &= ~MMC_PM_WAKE_SDIO_IRQ; + MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err); return err; } diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c index 52427815722b..d712f29da9f1 100644 --- a/drivers/mmc/host/cmdq_hci.c +++ b/drivers/mmc/host/cmdq_hci.c @@ -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 @@ -198,6 +198,14 @@ static void cmdq_dumpregs(struct cmdq_host *cq_host) { struct mmc_host *mmc = cq_host->mmc; + MMC_TRACE(mmc, + "%s: 0x0C=0x%08x 0x10=0x%08x 0x14=0x%08x 0x18=0x%08x 0x28=0x%08x 0x2C=0x%08x 0x30=0x%08x 0x34=0x%08x 0x54=0x%08x 0x58=0x%08x 0x5C=0x%08x 0x48=0x%08x\n", + __func__, cmdq_readl(cq_host, CQCTL), cmdq_readl(cq_host, CQIS), + cmdq_readl(cq_host, CQISTE), cmdq_readl(cq_host, CQISGE), + cmdq_readl(cq_host, CQTDBR), cmdq_readl(cq_host, CQTCN), + cmdq_readl(cq_host, CQDQS), cmdq_readl(cq_host, CQDPT), + cmdq_readl(cq_host, CQTERRI), cmdq_readl(cq_host, CQCRI), + cmdq_readl(cq_host, CQCRA), cmdq_readl(cq_host, CQCRDCT)); pr_err(DRV_NAME ": ========== REGISTER DUMP (%s)==========\n", mmc_hostname(mmc)); @@ -426,6 +434,7 @@ static int cmdq_enable(struct mmc_host *mmc) pm_ref_count: cmdq_runtime_pm_put(cq_host); out: + MMC_TRACE(mmc, "%s: CQ enabled err: %d\n", __func__, err); return err; } @@ -443,6 +452,7 @@ static void cmdq_disable_nosync(struct mmc_host *mmc, bool soft) cq_host->enabled = false; mmc_host_set_cq_disable(mmc); + MMC_TRACE(mmc, "%s: CQ disabled\n", __func__); } static void cmdq_disable(struct mmc_host *mmc, bool soft) @@ -525,6 +535,12 @@ static void cmdq_prep_task_desc(struct mmc_request *mrq, REL_WRITE(!!(req_flags & REL_WR)) | BLK_COUNT(mrq->cmdq_req->data.blocks) | BLK_ADDR((u64)mrq->cmdq_req->blk_addr); + + MMC_TRACE(mrq->host, + "%s: Task: 0x%08x | Args: 0x%08x | cnt: 0x%08x\n", __func__, + lower_32_bits(*data), + upper_32_bits(*data), + mrq->cmdq_req->data.blocks); } static int cmdq_dma_map(struct mmc_host *host, struct mmc_request *mrq) @@ -665,6 +681,11 @@ static void cmdq_prep_dcmd_desc(struct mmc_host *mmc, dataddr = (__le64 __force *)(desc + 4); dataddr[0] = cpu_to_le64((u64)mrq->cmd->arg); cmdq_log_task_desc_history(cq_host, *task_desc, true); + MMC_TRACE(mrq->host, + "%s: DCMD: Task: 0x%08x | Args: 0x%08x\n", + __func__, + lower_32_bits(*task_desc), + upper_32_bits(*task_desc)); } static void cmdq_pm_qos_vote(struct sdhci_host *host, struct mmc_request *mrq) @@ -743,6 +764,7 @@ ring_doorbell: cmdq_dumpregs(cq_host); BUG_ON(1); } + MMC_TRACE(mmc, "%s: tag: %d\n", __func__, tag); cmdq_writel(cq_host, 1 << tag, CQTDBR); /* Commit the doorbell write immediately */ wmb(); @@ -785,6 +807,8 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err) if (!status && !err) return IRQ_NONE; + MMC_TRACE(mmc, "%s: CQIS: 0x%x err: %d\n", + __func__, status, err); if (err || (status & CQIS_RED)) { err_info = cmdq_readl(cq_host, CQTERRI); @@ -920,7 +944,9 @@ skip_cqterri: /* complete the corresponding mrq */ pr_debug("%s: completing tag -> %lu\n", mmc_hostname(mmc), tag); - cmdq_finish_data(mmc, tag); + MMC_TRACE(mmc, "%s: completing tag -> %lu\n", + __func__, tag); + cmdq_finish_data(mmc, tag); } } @@ -997,6 +1023,8 @@ static int cmdq_halt(struct mmc_host *mmc, bool halt) retries--; continue; } else { + MMC_TRACE(mmc, "%s: halt done , retries: %d\n", + __func__, retries); /* halt done: re-enable legacy interrupts */ if (cq_host->ops->clear_set_irqs) cq_host->ops->clear_set_irqs(mmc, @@ -1014,6 +1042,7 @@ static int cmdq_halt(struct mmc_host *mmc, bool halt) cq_host->ops->set_data_timeout(mmc, 0xf); if (cq_host->ops->clear_set_irqs) cq_host->ops->clear_set_irqs(mmc, true); + MMC_TRACE(mmc, "%s: unhalt done\n", __func__); cmdq_writel(cq_host, cmdq_readl(cq_host, CQCTL) & ~HALT, CQCTL); } diff --git a/drivers/mmc/host/sdhci-msm-ice.c b/drivers/mmc/host/sdhci-msm-ice.c index abf2ae2020c9..2ef459582aae 100644 --- a/drivers/mmc/host/sdhci-msm-ice.c +++ b/drivers/mmc/host/sdhci-msm-ice.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 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 @@ -102,7 +102,7 @@ int sdhci_msm_ice_init(struct sdhci_host *host) struct sdhci_msm_host *msm_host = pltfm_host->priv; int err = 0; - if (msm_host->ice.vops->config) { + if (msm_host->ice.vops->init) { err = msm_host->ice.vops->init(msm_host->ice.pdev, msm_host, sdhci_msm_ice_error_cb); @@ -148,9 +148,10 @@ int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq, req = mrq->req; if (req) { lba = req->__sector; - if (msm_host->ice.vops->config) { - err = msm_host->ice.vops->config(msm_host->ice.pdev, - req, &ice_set); + if (msm_host->ice.vops->config_start) { + err = msm_host->ice.vops->config_start( + msm_host->ice.pdev, + req, &ice_set, false); if (err) { pr_err("%s: ice config failed %d\n", mmc_hostname(host->mmc), err); diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 203daf3bd5eb..466e0a2c8483 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -2,7 +2,7 @@ * drivers/mmc/host/sdhci-msm.c - Qualcomm Technologies, Inc. MSM SDHCI Platform * driver source file * - * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-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 @@ -3293,6 +3293,11 @@ void sdhci_msm_dump_vendor_regs(struct sdhci_host *host) if (host->cq_host) sdhci_msm_cmdq_dump_debug_ram(host); + MMC_TRACE(host->mmc, "Data cnt: 0x%08x | Fifo cnt: 0x%08x\n", + sdhci_msm_readl_relaxed(host, + msm_host_offset->CORE_MCI_DATA_CNT), + sdhci_msm_readl_relaxed(host, + msm_host_offset->CORE_MCI_FIFO_CNT)); pr_info("Data cnt: 0x%08x | Fifo cnt: 0x%08x | Int sts: 0x%08x\n", sdhci_msm_readl_relaxed(host, msm_host_offset->CORE_MCI_DATA_CNT), diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 08822464d82f..3fd564388720 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -111,6 +111,17 @@ static void sdhci_dump_state(struct sdhci_host *host) static void sdhci_dumpregs(struct sdhci_host *host) { + MMC_TRACE(host->mmc, + "%s: 0x04=0x%08x 0x06=0x%08x 0x0E=0x%08x 0x30=0x%08x 0x34=0x%08x 0x38=0x%08x\n", + __func__, + sdhci_readw(host, SDHCI_BLOCK_SIZE), + sdhci_readw(host, SDHCI_BLOCK_COUNT), + sdhci_readw(host, SDHCI_COMMAND), + sdhci_readl(host, SDHCI_INT_STATUS), + sdhci_readl(host, SDHCI_INT_ENABLE), + sdhci_readl(host, SDHCI_SIGNAL_ENABLE)); + mmc_stop_tracing(host->mmc); + pr_info(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n", mmc_hostname(host->mmc)); @@ -1013,6 +1024,11 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) /* Set the DMA boundary value and block size */ sdhci_set_blk_size_reg(host, data->blksz, SDHCI_DEFAULT_BOUNDARY_ARG); sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT); + MMC_TRACE(host->mmc, + "%s: 0x28=0x%08x 0x3E=0x%08x 0x06=0x%08x\n", __func__, + sdhci_readb(host, SDHCI_HOST_CONTROL), + sdhci_readw(host, SDHCI_HOST_CONTROL2), + sdhci_readw(host, SDHCI_BLOCK_COUNT)); } static void sdhci_set_transfer_mode(struct sdhci_host *host, @@ -1071,6 +1087,9 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host, mode |= SDHCI_TRNS_DMA; sdhci_writew(host, mode, SDHCI_TRANSFER_MODE); + MMC_TRACE(host->mmc, "%s: 0x00=0x%08x 0x0C=0x%08x\n", __func__, + sdhci_readw(host, SDHCI_ARGUMENT2), + sdhci_readw(host, SDHCI_TRANSFER_MODE)); } static void sdhci_finish_data(struct sdhci_host *host) @@ -1082,6 +1101,8 @@ static void sdhci_finish_data(struct sdhci_host *host) data = host->data; host->data = NULL; + MMC_TRACE(host->mmc, "%s: 0x24=0x%08x\n", __func__, + sdhci_readl(host, SDHCI_PRESENT_STATE)); if (host->flags & SDHCI_REQ_USE_DMA) { if (host->flags & SDHCI_USE_ADMA) sdhci_adma_table_post(host, data); @@ -1210,6 +1231,11 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) if (cmd->data) host->data_start_time = ktime_get(); trace_mmc_cmd_rw_start(cmd->opcode, cmd->arg, cmd->flags); + MMC_TRACE(host->mmc, + "%s: updated 0x8=0x%08x 0xC=0x%08x 0xE=0x%08x\n", __func__, + sdhci_readl(host, SDHCI_ARGUMENT), + sdhci_readw(host, SDHCI_TRANSFER_MODE), + sdhci_readw(host, SDHCI_COMMAND)); sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND); } EXPORT_SYMBOL_GPL(sdhci_send_command); @@ -1231,8 +1257,14 @@ static void sdhci_finish_command(struct sdhci_host *host) sdhci_readb(host, SDHCI_RESPONSE + (3-i)*4-1); } + MMC_TRACE(host->mmc, + "%s: resp 0: 0x%08x resp 1: 0x%08x resp 2: 0x%08x resp 3: 0x%08x\n", + __func__, host->cmd->resp[0], host->cmd->resp[1], + host->cmd->resp[2], host->cmd->resp[3]); } else { host->cmd->resp[0] = sdhci_readl(host, SDHCI_RESPONSE); + MMC_TRACE(host->mmc, "%s: resp 0: 0x%08x\n", + __func__, host->cmd->resp[0]); } } @@ -3169,6 +3201,9 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) goto out; } + MMC_TRACE(host->mmc, + "%s: intmask: 0x%x\n", __func__, intmask); + if (intmask & SDHCI_INT_AUTO_CMD_ERR) host->auto_cmd_err_sts = sdhci_readw(host, SDHCI_AUTO_CMD_ERR); diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index a617c9e8e11f..f32d3d9646c1 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -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 @@ -362,8 +362,13 @@ static void gsi_process_chan(struct gsi_xfer_compl_evt *evt, notify->chan_user_data = ch_ctx->props.chan_user_data; notify->evt_id = evt->code; notify->bytes_xfered = evt->len; - if (callback) + if (callback) { + if (atomic_read(&ch_ctx->poll_mode)) { + GSIERR("Calling client callback in polling mode\n"); + WARN_ON(1); + } ch_ctx->props.xfer_cb(notify); + } } static void gsi_process_evt_re(struct gsi_evt_ctx *ctx, @@ -459,12 +464,12 @@ check_again: ctx->ring.rp = rp; while (ctx->ring.rp_local != rp) { ++cntr; - gsi_process_evt_re(ctx, ¬ify, true); if (ctx->props.exclusive && atomic_read(&ctx->chan->poll_mode)) { cntr = 0; break; } + gsi_process_evt_re(ctx, ¬ify, true); } gsi_ring_evt_doorbell(ctx); if (cntr != 0) diff --git a/drivers/soc/qcom/msm_smem.c b/drivers/soc/qcom/msm_smem.c index 9c4d89ac704d..d3f44ab75f67 100644 --- a/drivers/soc/qcom/msm_smem.c +++ b/drivers/soc/qcom/msm_smem.c @@ -1222,12 +1222,18 @@ static void smem_init_security_partition(struct smem_toc_entry *entry, LOG_ERR("Smem partition %d cached heap exceeds size\n", num); BUG(); } - if (hdr->host0 == SMEM_COMM_HOST && hdr->host1 == SMEM_COMM_HOST) { - comm_partition.partition_num = num; - comm_partition.offset = entry->offset; - comm_partition.size_cacheline = entry->size_cacheline; - SMEM_INFO("Common Partition %d offset:%x\n", num, - entry->offset); + if (is_comm_partition) { + if (hdr->host0 == SMEM_COMM_HOST + && hdr->host1 == SMEM_COMM_HOST) { + comm_partition.partition_num = num; + comm_partition.offset = entry->offset; + comm_partition.size_cacheline = entry->size_cacheline; + SMEM_INFO("Common Partition %d offset:%x\n", num, + entry->offset); + } else { + LOG_ERR("Smem Comm partition hosts don't match TOC\n"); + WARN_ON(1); + } return; } if (hdr->host0 != SMEM_APPS && hdr->host1 != SMEM_APPS) { diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c index 7aa04a4fa156..b81348ceb469 100644 --- a/drivers/spi/spi_qsd.c +++ b/drivers/spi/spi_qsd.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-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 @@ -45,8 +45,6 @@ #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); @@ -440,12 +438,10 @@ 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 < read_bytes) && + for (i = 0; (i < dd->bytes_per_word) && dd->rx_bytes_remaining; i++) { /* The data format depends on bytes_per_word: 4 bytes: 0x12345678 @@ -458,8 +454,8 @@ static void msm_spi_read_word_from_fifo(struct msm_spi *dd) dd->rx_bytes_remaining--; } } else { - if (dd->rx_bytes_remaining >= read_bytes) - dd->rx_bytes_remaining -= read_bytes; + if (dd->rx_bytes_remaining >= dd->bytes_per_word) + dd->rx_bytes_remaining -= dd->bytes_per_word; else dd->rx_bytes_remaining = 0; } @@ -556,7 +552,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->tx_mode == SPI_BAM_MODE) { + if (dd->mode == SPI_BAM_MODE) { if (dd->read_buf == NULL) *config |= SPI_NO_INPUT; if (dd->write_buf == NULL) @@ -621,34 +617,25 @@ 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) { /* - * 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. + * 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. */ - 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); + 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); - } else - writel_relaxed(n_words, dd->base + SPI_MX_INPUT_COUNT); + writel_relaxed(0, dd->base + SPI_MX_OUTPUT_COUNT); + } } else { /* must be zero for BAM and DMOV */ writel_relaxed(0, dd->base + SPI_MX_READ_COUNT); @@ -895,7 +882,7 @@ xfr_err: static int msm_spi_bam_next_transfer(struct msm_spi *dd) { - if (dd->tx_mode != SPI_BAM_MODE) + if (dd->mode != SPI_BAM_MODE) return 0; if (dd->tx_bytes_remaining > 0) { @@ -914,7 +901,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->tx_mode == SPI_BAM_MODE) + if (dd->mode == SPI_BAM_MODE) ret = msm_spi_bam_next_transfer(dd); return ret; } @@ -945,38 +932,32 @@ 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->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; + if (dd->done) { complete(&dd->rx_transfer_complete); complete(&dd->tx_transfer_complete); + dd->done = 0; } return ret; } @@ -987,23 +968,17 @@ static irqreturn_t msm_spi_input_irq(int irq, void *dev_id) dd->stat_rx++; - if (dd->rx_mode == SPI_MODE_NONE) + if (dd->mode == SPI_MODE_NONE) return IRQ_HANDLED; - if (dd->rx_mode == SPI_FIFO_MODE) { + if (dd->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); } - } 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; - } + if (dd->rx_bytes_remaining == 0) + msm_spi_complete(dd); } return IRQ_HANDLED; @@ -1014,20 +989,18 @@ 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 < write_bytes) && + for (i = 0; (i < dd->bytes_per_word) && 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 > write_bytes) - dd->tx_bytes_remaining -= write_bytes; + if (dd->tx_bytes_remaining > dd->bytes_per_word) + dd->tx_bytes_remaining -= dd->bytes_per_word; else dd->tx_bytes_remaining = 0; dd->write_xfr_cnt++; @@ -1039,22 +1012,11 @@ static inline void msm_spi_write_rmn_to_fifo(struct msm_spi *dd) { int count = 0; - 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; - } + 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++; } } @@ -1064,11 +1026,11 @@ static irqreturn_t msm_spi_output_irq(int irq, void *dev_id) dd->stat_tx++; - if (dd->tx_mode == SPI_MODE_NONE) + if (dd->mode == SPI_MODE_NONE) return IRQ_HANDLED; /* Output FIFO is empty. Transmit any outstanding write data. */ - if ((dd->tx_mode == SPI_FIFO_MODE) || (dd->tx_mode == SPI_BLOCK_MODE)) + if (dd->mode == SPI_FIFO_MODE) msm_spi_write_rmn_to_fifo(dd); return IRQ_HANDLED; @@ -1144,7 +1106,7 @@ error: static int msm_spi_dma_map_buffers(struct msm_spi *dd) { int ret = 0; - if (dd->tx_mode == SPI_BAM_MODE) + if (dd->mode == SPI_BAM_MODE) ret = msm_spi_bam_map_buffers(dd); return ret; } @@ -1173,7 +1135,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->tx_mode == SPI_BAM_MODE) + if (dd->mode == SPI_BAM_MODE) msm_spi_bam_unmap_buffers(dd); } @@ -1235,11 +1197,9 @@ 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->tx_mode = SPI_BAM_MODE; - dd->rx_mode = SPI_BAM_MODE; + dd->mode = SPI_BAM_MODE; } else { - dd->rx_mode = SPI_FIFO_MODE; - dd->tx_mode = SPI_FIFO_MODE; + dd->mode = SPI_FIFO_MODE; dd->read_len = dd->cur_transfer->len; dd->write_len = dd->cur_transfer->len; } @@ -1255,19 +1215,14 @@ 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->tx_mode << OUTPUT_MODE_SHIFT)); - spi_iom = (spi_iom | (dd->rx_mode << INPUT_MODE_SHIFT)); - /* Always enable packing for all % 8 bits_per_word */ - if (dd->cur_transfer->bits_per_word && - ((dd->cur_transfer->bits_per_word == 8) || - (dd->cur_transfer->bits_per_word == 16) || - (dd->cur_transfer->bits_per_word == 32))) { + 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_IO_M_PACK_EN | SPI_IO_M_UNPACK_EN; - dd->pack_words = true; - } else { + 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) { @@ -1325,7 +1280,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->tx_mode == SPI_BAM_MODE) ? + u32 mask = (dd->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); @@ -1366,8 +1321,6 @@ 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) @@ -1398,12 +1351,10 @@ 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->tx_mode == SPI_BAM_MODE) { + if (dd->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; } } @@ -1417,11 +1368,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->tx_mode != SPI_BAM_MODE) { + if (dd->mode == SPI_FIFO_MODE) { if (msm_spi_prepare_for_write(dd)) goto transfer_end; msm_spi_start_write(dd, read_count); - } else { + } else if (dd->mode == SPI_BAM_MODE) { if ((msm_spi_bam_begin_transfer(dd)) < 0) { dev_err(dd->dev, "%s: BAM transfer setup failed\n", __func__); @@ -1437,11 +1388,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->tx_mode != SPI_BAM_MODE) + if (dd->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->tx_mode); + __func__, dd->mode); goto transfer_end; } @@ -1471,11 +1422,10 @@ static int msm_spi_process_transfer(struct msm_spi *dd) msm_spi_udelay(dd->xfrs_delay_usec); transfer_end: - if ((dd->tx_mode == SPI_BAM_MODE) && status) + if ((dd->mode == SPI_BAM_MODE) && status) msm_spi_bam_flush(dd); msm_spi_dma_unmap_buffers(dd); - dd->tx_mode = SPI_MODE_NONE; - dd->rx_mode = SPI_MODE_NONE; + dd->mode = SPI_MODE_NONE; msm_spi_set_state(dd, SPI_OP_STATE_RESET); if (!dd->cur_transfer->cs_change) @@ -2403,8 +2353,7 @@ static int init_resources(struct platform_device *pdev) pclk_enabled = 0; dd->transfer_pending = 0; - dd->tx_mode = SPI_MODE_NONE; - dd->rx_mode = SPI_MODE_NONE; + dd->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 e8e6cdce1a02..53ec1e600594 100644 --- a/drivers/spi/spi_qsd.h +++ b/drivers/spi/spi_qsd.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 @@ -113,8 +113,6 @@ #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 @@ -316,8 +314,7 @@ struct msm_spi { bool transfer_pending; wait_queue_head_t continue_suspend; /* DMA data */ - enum msm_spi_mode tx_mode; - enum msm_spi_mode rx_mode; + enum msm_spi_mode mode; bool use_dma; int tx_dma_chan; int tx_dma_crci; @@ -349,8 +346,7 @@ struct msm_spi { #endif struct msm_spi_platform_data *pdata; /* Platform data */ /* When set indicates multiple transfers in a single message */ - bool rx_done; - bool tx_done; + bool done; u32 cur_msg_len; /* Used in FIFO mode to keep track of the transfer being processed */ struct spi_transfer *cur_tx_transfer; @@ -368,7 +364,6 @@ struct msm_spi { struct pinctrl_state *pins_active; struct pinctrl_state *pins_sleep; bool is_init_complete; - bool pack_words; }; /* Forward declaration */ @@ -522,8 +517,7 @@ 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->tx_done = true; - dd->rx_done = true; + dd->done = 1; } static inline void msm_spi_enable_error_flags(struct msm_spi *dd) diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index f3715d85aedc..7cafd0dd59f5 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -454,13 +454,23 @@ static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req) struct fsg_buffhd *bh = req->context; if (req->status || req->actual != req->length) - DBG(common, "%s --> %d, %u/%u\n", __func__, + pr_debug("%s --> %d, %u/%u\n", __func__, req->status, req->actual, req->length); if (req->status == -ECONNRESET) /* Request was cancelled */ usb_ep_fifo_flush(ep); /* Hold the lock while we update the request and buffer states */ smp_wmb(); + /* + * Disconnect and completion might race each other and driver data + * is set to NULL during ep disable. So, add a check if that is case. + */ + if (!common) { + bh->inreq_busy = 0; + bh->state = BUF_STATE_EMPTY; + return; + } + spin_lock(&common->lock); bh->inreq_busy = 0; bh->state = BUF_STATE_EMPTY; @@ -473,15 +483,24 @@ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) struct fsg_common *common = ep->driver_data; struct fsg_buffhd *bh = req->context; - dump_msg(common, "bulk-out", req->buf, req->actual); if (req->status || req->actual != bh->bulk_out_intended_length) - DBG(common, "%s --> %d, %u/%u\n", __func__, + pr_debug("%s --> %d, %u/%u\n", __func__, req->status, req->actual, bh->bulk_out_intended_length); if (req->status == -ECONNRESET) /* Request was cancelled */ usb_ep_fifo_flush(ep); /* Hold the lock while we update the request and buffer states */ smp_wmb(); + /* + * Disconnect and completion might race each other and driver data + * is set to NULL during ep disable. So, add a check if that is case. + */ + if (!common) { + bh->outreq_busy = 0; + return; + } + + dump_msg(common, "bulk-out", req->buf, req->actual); spin_lock(&common->lock); bh->outreq_busy = 0; bh->state = BUF_STATE_FULL; diff --git a/drivers/usb/gadget/function/f_qc_rndis.c b/drivers/usb/gadget/function/f_qc_rndis.c index 11c73f584594..061095b78c37 100644 --- a/drivers/usb/gadget/function/f_qc_rndis.c +++ b/drivers/usb/gadget/function/f_qc_rndis.c @@ -683,6 +683,7 @@ static int rndis_qc_set_alt(struct usb_function *f, unsigned intf, unsigned alt) /* we know alt == 0 */ + opts = container_of(f->fi, struct f_rndis_qc_opts, func_inst); if (intf == rndis->ctrl_id) { if (rndis->notify->driver_data) { VDBG(cdev, "reset rndis control %d\n", intf); diff --git a/drivers/usb/gadget/function/u_ctrl_qti.c b/drivers/usb/gadget/function/u_ctrl_qti.c index 8ef223370827..013c54da0d0a 100644 --- a/drivers/usb/gadget/function/u_ctrl_qti.c +++ b/drivers/usb/gadget/function/u_ctrl_qti.c @@ -485,7 +485,7 @@ qti_ctrl_write(struct file *fp, const char __user *buf, size_t count, port->copied_from_modem++; spin_lock_irqsave(&port->lock, flags); - if (port && port->port_usb) { + if (port->port_usb) { if (port->port_type == QTI_PORT_RMNET) { g_rmnet = (struct grmnet *)port->port_usb; } else { diff --git a/drivers/usb/gadget/function/u_data_ipa.c b/drivers/usb/gadget/function/u_data_ipa.c index bf9e0fa9950b..6c18a04f6c1c 100644 --- a/drivers/usb/gadget/function/u_data_ipa.c +++ b/drivers/usb/gadget/function/u_data_ipa.c @@ -1107,18 +1107,18 @@ static void bam2bam_data_resume_work(struct work_struct *w) unsigned long flags; int ret; - if (!port->port_usb->cdev) { - pr_err("!port->port_usb->cdev is NULL"); + spin_lock_irqsave(&port->port_lock, flags); + if (!port->port_usb || !port->port_usb->cdev) { + pr_err("port->port_usb or cdev is NULL"); goto exit; } if (!port->port_usb->cdev->gadget) { - pr_err("!port->port_usb->cdev->gadget is NULL"); + pr_err("port->port_usb->cdev->gadget is NULL"); goto exit; } pr_debug("%s: resume started\n", __func__); - spin_lock_irqsave(&port->port_lock, flags); gadget = port->port_usb->cdev->gadget; if (!gadget) { spin_unlock_irqrestore(&port->port_lock, flags); diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 338ae65a160f..025f11b9cffa 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -900,6 +900,43 @@ static int fuse_readpages_fill(void *_data, struct page *page) return -EIO; } +#ifdef CONFIG_CMA + if (is_cma_pageblock(page)) { + struct page *oldpage = page, *newpage; + int err; + + /* make sure that old page is not free in-between the calls */ + page_cache_get(oldpage); + + newpage = alloc_page(GFP_HIGHUSER); + if (!newpage) { + page_cache_release(oldpage); + return -ENOMEM; + } + + err = replace_page_cache_page(oldpage, newpage, GFP_KERNEL); + if (err) { + __free_page(newpage); + page_cache_release(oldpage); + return err; + } + + /* + * Decrement the count on new page to make page cache the only + * owner of it + */ + lock_page(newpage); + put_page(newpage); + + lru_cache_add_file(newpage); + + /* finally release the old page and swap pointers */ + unlock_page(oldpage); + page_cache_release(oldpage); + page = newpage; + } +#endif + page_cache_get(page); req->pages[req->num_pages] = page; req->page_descs[req->num_pages].length = PAGE_SIZE; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 276dbf19805b..804d89a825fc 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -22,6 +22,7 @@ #include <linux/mmc/core.h> #include <linux/mmc/card.h> #include <linux/mmc/pm.h> +#include <linux/mmc/ring_buffer.h> #define MMC_AUTOSUSPEND_DELAY_MS 3000 @@ -571,6 +572,7 @@ struct mmc_host { } perf; bool perf_enable; #endif + struct mmc_trace_buffer trace_buf; enum dev_state dev_status; bool wakeup_on_idle; struct mmc_cmdq_context_info cmdq_ctx; diff --git a/include/linux/mmc/ring_buffer.h b/include/linux/mmc/ring_buffer.h new file mode 100644 index 000000000000..e6bf163ffcfe --- /dev/null +++ b/include/linux/mmc/ring_buffer.h @@ -0,0 +1,55 @@ +/* + * 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 __MMC_RING_BUFFER__ +#define __MMC_RING_BUFFER__ + +#include <linux/mmc/card.h> +#include <linux/smp.h> + +#include "core.h" + +#define MMC_TRACE_RBUF_SZ_ORDER 2 /* 2^2 pages */ +#define MMC_TRACE_RBUF_SZ (PAGE_SIZE * (1 << MMC_TRACE_RBUF_SZ_ORDER)) +#define MMC_TRACE_EVENT_SZ 256 +#define MMC_TRACE_RBUF_NUM_EVENTS (MMC_TRACE_RBUF_SZ / MMC_TRACE_EVENT_SZ) + +struct mmc_host; +struct mmc_trace_buffer { + int wr_idx; + bool stop_tracing; + spinlock_t trace_lock; + char *data; +}; + +#ifdef CONFIG_MMC_RING_BUFFER +void mmc_stop_tracing(struct mmc_host *mmc); +void mmc_trace_write(struct mmc_host *mmc, const char *fmt, ...); +void mmc_trace_init(struct mmc_host *mmc); +void mmc_trace_free(struct mmc_host *mmc); +void mmc_dump_trace_buffer(struct mmc_host *mmc, struct seq_file *s); +#else +static inline void mmc_stop_tracing(struct mmc_host *mmc) {} +static inline void mmc_trace_write(struct mmc_host *mmc, + const char *fmt, ...) {} +static inline void mmc_trace_init(struct mmc_host *mmc) {} +static inline void mmc_trace_free(struct mmc_host *mmc) {} +static inline void mmc_dump_trace_buffer(struct mmc_host *mmc, + struct seq_file *s) {} +#endif + +#define MMC_TRACE(mmc, fmt, ...) \ + mmc_trace_write(mmc, fmt, ##__VA_ARGS__) + +#endif /* __MMC_RING_BUFFER__ */ diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h index ceba9f7d759a..38d49a2af8be 100644 --- a/include/sound/apr_audio-v2.h +++ b/include/sound/apr_audio-v2.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-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 @@ -4263,6 +4263,9 @@ struct asm_multi_channel_pcm_enc_cfg_v2 { /* Enumeration for the raw AAC format. */ #define ASM_MEDIA_FMT_AAC_FORMAT_FLAG_RAW 3 +/* Enumeration for the AAC LATM format. */ +#define ASM_MEDIA_FMT_AAC_FORMAT_FLAG_LATM 4 + #define ASM_MEDIA_FMT_AAC_AOT_LC 2 #define ASM_MEDIA_FMT_AAC_AOT_SBR 5 #define ASM_MEDIA_FMT_AAC_AOT_PS 29 @@ -5955,6 +5958,138 @@ struct asm_stream_cmd_open_loopback_v2 { /* Reserved for future use. This field must be set to zero. */ } __packed; + +#define ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK 0x00010DBA + +/* Bitmask for the stream's Performance mode. */ +#define ASM_BIT_MASK_STREAM_PERF_MODE_FLAG_IN_OPEN_TRANSCODE_LOOPBACK \ + (0x70000000UL) + +/* Bit shift for the stream's Performance mode. */ +#define ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_TRANSCODE_LOOPBACK 28 + +/* Bitmask for the decoder converter enable flag. */ +#define ASM_BIT_MASK_DECODER_CONVERTER_FLAG (0x00000078UL) + +/* Shift value for the decoder converter enable flag. */ +#define ASM_SHIFT_DECODER_CONVERTER_FLAG 3 + +/* Converter mode is None (Default). */ +#define ASM_CONVERTER_MODE_NONE 0 + +/* Converter mode is DDP-to-DD. */ +#define ASM_DDP_DD_CONVERTER_MODE 1 + +/* Identifies a special converter mode where source and sink formats + * are the same but postprocessing must applied. Therefore, Decode + * @rarrow Re-encode is necessary. + */ +#define ASM_POST_PROCESS_CONVERTER_MODE 2 + + +struct asm_stream_cmd_open_transcode_loopback_t { + struct apr_hdr hdr; + u32 mode_flags; +/* Mode Flags specifies the performance mode in which this stream + * is to be opened. + * Supported values{for bits 30 to 28}(stream_perf_mode flag) + * + * #ASM_LEGACY_STREAM_SESSION -- This mode ensures backward + * compatibility to the original behavior + * of ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK + * + * #ASM_LOW_LATENCY_STREAM_SESSION -- Opens a loopback session by using + * shortened buffers in low latency POPP + * - Recommendation: Do not enable high latency algorithms. They might + * negate the benefits of opening a low latency stream, and they + * might also suffer quality degradation from unexpected jitter. + * - This Low Latency mode is supported only for PCM In and PCM Out + * loopbacks. An error is returned if Low Latency mode is opened for + * other transcode loopback modes. + * - To configure this subfield, use + * ASM_BIT_MASK_STREAM_PERF_MODE_FLAG_IN_OPEN_TRANSCODE_LOOPBACK and + * ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_TRANSCODE_LOOPBACK. + * + * Supported values{for bits 6 to 3} (decoder-converter compatibility) + * #ASM_CONVERTER_MODE_NONE (0x0) -- Default + * #ASM_DDP_DD_CONVERTER_MODE (0x1) + * #ASM_POST_PROCESS_CONVERTER_MODE (0x2) + * 0x3-0xF -- Reserved for future use + * - Use #ASM_BIT_MASK_DECODER_CONVERTER_FLAG and + * ASM_SHIFT_DECODER_CONVERTER_FLAG to set this bit + * All other bits are reserved; clients must set them to 0. + */ + + u32 src_format_id; +/* Specifies the media format of the input audio stream. + * + * Supported values + * - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2 + * - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3 + * - #ASM_MEDIA_FMT_DTS + * - #ASM_MEDIA_FMT_EAC3_DEC + * - #ASM_MEDIA_FMT_EAC3 + * - #ASM_MEDIA_FMT_AC3_DEC + * - #ASM_MEDIA_FMT_AC3 + */ + u32 sink_format_id; +/* Specifies the media format of the output stream. + * + * Supported values + * - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2 + * - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3 + * - #ASM_MEDIA_FMT_DTS (not supported in Low Latency mode) + * - #ASM_MEDIA_FMT_EAC3_DEC (not supported in Low Latency mode) + * - #ASM_MEDIA_FMT_EAC3 (not supported in Low Latency mode) + * - #ASM_MEDIA_FMT_AC3_DEC (not supported in Low Latency mode) + * - #ASM_MEDIA_FMT_AC3 (not supported in Low Latency mode) + */ + + u32 audproc_topo_id; +/* Postprocessing topology ID, which specifies the topology (order of + * processing) of postprocessing algorithms. + * + * Supported values + * - #ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT + * - #ASM_STREAM_POSTPROC_TOPO_ID_PEAKMETER + * - #ASM_STREAM_POSTPROC_TOPO_ID_MCH_PEAK_VOL + * - #ASM_STREAM_POSTPROC_TOPO_ID_NONE + * Topologies can be added through #ASM_CMD_ADD_TOPOLOGIES. + * This field is ignored for the Converter mode, in which no + * postprocessing is performed. + */ + + u16 src_endpoint_type; +/* Specifies the source endpoint that provides the input samples. + * + * Supported values + * - 0 -- Tx device matrix or stream router (gateway to the hardware + * ports) + * - All other values are reserved + * Clients must set this field to 0. Otherwise, an error is returned. + */ + + u16 sink_endpoint_type; +/* Specifies the sink endpoint type. + * + * Supported values + * - 0 -- Rx device matrix or stream router (gateway to the hardware + * ports) + * - All other values are reserved + * Clients must set this field to 0. Otherwise, an error is returned. + */ + + u16 bits_per_sample; +/* Number of bits per sample processed by the ASM modules. + * Supported values 16, 24 + */ + + u16 reserved; +/* This field must be set to 0. + */ +} __packed; + + #define ASM_STREAM_CMD_CLOSE 0x00010BCD #define ASM_STREAM_CMD_FLUSH 0x00010BCE @@ -10032,4 +10167,21 @@ struct adm_param_fluence_sourcetracking_t { #define AUDPROC_PARAM_ID_AUDIOSPHERE_DESIGN_MULTICHANNEL_INPUT 0x0001091D #define AUDPROC_PARAM_ID_AUDIOSPHERE_OPERATING_INPUT_MEDIA_INFO 0x0001091E + +#define AUDPROC_MODULE_ID_VOICE_TX_SECNS 0x10027059 +#define AUDPROC_PARAM_IDX_SEC_PRIMARY_MIC_CH 0x10014444 + +struct admx_sec_primary_mic_ch { + uint16_t version; + uint16_t reserved; + uint16_t sec_primary_mic_ch; + uint16_t reserved1; +} __packed; + + +struct adm_set_sec_primary_ch_params { + struct adm_cmd_set_pp_params_v5 params; + struct adm_param_data_v5 data; + struct admx_sec_primary_mic_ch sec_primary_mic_ch_data; +} __packed; #endif /*_APR_AUDIO_V2_H_ */ diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h index 47e8e2a73920..8c7da3b9838d 100644 --- a/include/sound/q6adm-v2.h +++ b/include/sound/q6adm-v2.h @@ -138,6 +138,9 @@ int adm_set_softvolume(int port_id, int copp_idx, int adm_set_mic_gain(int port_id, int copp_idx, int volume); +int adm_send_set_multichannel_ec_primary_mic_ch(int port_id, int copp_idx, + int primary_mic_ch); + int adm_param_enable(int port_id, int copp_idx, int module_id, int enable); int adm_send_calibration(int port_id, int copp_idx, int path, int perf_mode, diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 76cbd55e99ac..519aee32e122 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -5905,7 +5905,6 @@ int sched_isolate_cpu(int cpu) smp_call_function_any(&avail_cpus, hrtimer_quiesce_cpu, &cpu, 1); smp_call_function_any(&avail_cpus, timer_quiesce_cpu, &cpu, 1); - migrate_sync_cpu(cpu, cpumask_first(&avail_cpus)); stop_cpus(cpumask_of(cpu), do_isolation_work_cpu_stop, 0); calc_load_migrate(rq); @@ -6286,7 +6285,6 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu) sched_ttwu_pending(); /* Update our root-domain */ raw_spin_lock_irqsave(&rq->lock, flags); - migrate_sync_cpu(cpu, smp_processor_id()); if (rq->rd) { BUG_ON(!cpumask_test_cpu(cpu, rq->rd->span)); diff --git a/kernel/sched/hmp.c b/kernel/sched/hmp.c index e28f2b424643..40df4f8f1de0 100644 --- a/kernel/sched/hmp.c +++ b/kernel/sched/hmp.c @@ -786,8 +786,6 @@ __read_mostly unsigned int sched_ravg_window = MIN_SCHED_RAVG_WINDOW; /* Temporarily disable window-stats activity on all cpus */ unsigned int __read_mostly sched_disable_window_stats; -static unsigned int sync_cpu; - struct related_thread_group *related_thread_groups[MAX_NUM_CGROUP_COLOC_ID]; static LIST_HEAD(active_related_thread_groups); static DEFINE_RWLOCK(related_thread_group_lock); @@ -3011,18 +3009,20 @@ void mark_task_starting(struct task_struct *p) void set_window_start(struct rq *rq) { - int cpu = cpu_of(rq); - struct rq *sync_rq = cpu_rq(sync_cpu); + static int sync_cpu_available; if (rq->window_start || !sched_enable_hmp) return; - if (cpu == sync_cpu) { + if (!sync_cpu_available) { rq->window_start = sched_ktime_clock(); + sync_cpu_available = 1; } else { + struct rq *sync_rq = cpu_rq(cpumask_any(cpu_online_mask)); + raw_spin_unlock(&rq->lock); double_rq_lock(rq, sync_rq); - rq->window_start = cpu_rq(sync_cpu)->window_start; + rq->window_start = sync_rq->window_start; rq->curr_runnable_sum = rq->prev_runnable_sum = 0; rq->nt_curr_runnable_sum = rq->nt_prev_runnable_sum = 0; raw_spin_unlock(&sync_rq->lock); @@ -3031,12 +3031,6 @@ void set_window_start(struct rq *rq) rq->curr->ravg.mark_start = rq->window_start; } -void migrate_sync_cpu(int cpu, int new_cpu) -{ - if (cpu == sync_cpu) - sync_cpu = new_cpu; -} - static void reset_all_task_stats(void) { struct task_struct *g, *p; diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index a9d98b7dd10e..d907eeb297a3 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1123,7 +1123,6 @@ extern void clear_boost_kick(int cpu); extern void clear_hmp_request(int cpu); extern void mark_task_starting(struct task_struct *p); extern void set_window_start(struct rq *rq); -extern void migrate_sync_cpu(int cpu, int new_cpu); extern void update_cluster_topology(void); extern void note_task_waking(struct task_struct *p, u64 wallclock); extern void set_task_last_switch_out(struct task_struct *p, u64 wallclock); @@ -1525,7 +1524,6 @@ static inline void clear_boost_kick(int cpu) { } static inline void clear_hmp_request(int cpu) { } static inline void mark_task_starting(struct task_struct *p) { } static inline void set_window_start(struct rq *rq) { } -static inline void migrate_sync_cpu(int cpu, int new_cpu) {} static inline void init_clusters(void) {} static inline void update_cluster_topology(void) { } static inline void note_task_waking(struct task_struct *p, u64 wallclock) { } diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c index 51bb3387de16..3228be362bab 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.c +++ b/sound/soc/codecs/wcd-mbhc-v2.c @@ -25,6 +25,7 @@ #include <linux/input.h> #include <linux/firmware.h> #include <linux/completion.h> +#include <linux/mfd/msm-cdc-pinctrl.h> #include <sound/soc.h> #include <sound/jack.h> #include "wcd-mbhc-v2.h" @@ -52,7 +53,7 @@ #define WCD_MBHC_BTN_PRESS_COMPL_TIMEOUT_MS 50 #define ANC_DETECT_RETRY_CNT 7 -#define WCD_MBHC_SPL_HS_CNT 1 +#define WCD_MBHC_SPL_HS_CNT 2 static int det_extn_cable_en; module_param(det_extn_cable_en, int, @@ -2132,6 +2133,22 @@ static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc) if (mbhc->mbhc_cfg->moisture_en && mbhc->mbhc_cb->mbhc_moisture_config) mbhc->mbhc_cb->mbhc_moisture_config(mbhc); + /* + * For USB analog we need to override the switch configuration. + * Also, disable hph_l pull-up current source as HS_DET_L is driven + * by an external source + */ + if (mbhc->mbhc_cfg->enable_usbc_analog) { + mbhc->hphl_swh = 1; + mbhc->gnd_swh = 1; + + if (mbhc->mbhc_cb->hph_pull_up_control) + mbhc->mbhc_cb->hph_pull_up_control(codec, I_OFF); + else + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HS_L_DET_PULL_UP_CTRL, + 0); + } + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_PLUG_TYPE, mbhc->hphl_swh); WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_GND_PLUG_TYPE, mbhc->gnd_swh); WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_SW_HPH_LP_100K_TO_GND, 1); @@ -2304,15 +2321,263 @@ int wcd_mbhc_set_keycode(struct wcd_mbhc *mbhc) return result; } -int wcd_mbhc_start(struct wcd_mbhc *mbhc, - struct wcd_mbhc_config *mbhc_cfg) +static int wcd_mbhc_usb_c_analog_setup_gpios(struct wcd_mbhc *mbhc, + bool active) { int rc = 0; + struct usbc_ana_audio_config *config = + &mbhc->mbhc_cfg->usbc_analog_cfg; + + dev_dbg(mbhc->codec->dev, "%s: setting GPIOs active = %d\n", + __func__, active); + if (active) { + if (config->usbc_en1_gpio_p) { + rc = msm_cdc_pinctrl_select_active_state( + config->usbc_en1_gpio_p); + /* delay required to allow the hw to stabilize */ + usleep_range(1000, 1200); + } + if (rc == 0 && config->usbc_en2n_gpio_p) { + rc = msm_cdc_pinctrl_select_active_state( + config->usbc_en2n_gpio_p); + /* delay required to allow the hw to stabilize */ + usleep_range(1000, 1200); + } + if (rc == 0 && config->usbc_force_gpio_p) + rc = msm_cdc_pinctrl_select_active_state( + config->usbc_force_gpio_p); + mbhc->usbc_mode = POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER; + } else { + /* no delay is required when disabling GPIOs */ + if (config->usbc_en2n_gpio_p) + msm_cdc_pinctrl_select_sleep_state( + config->usbc_en2n_gpio_p); + if (config->usbc_en1_gpio_p) + msm_cdc_pinctrl_select_sleep_state( + config->usbc_en1_gpio_p); + if (config->usbc_force_gpio_p) + msm_cdc_pinctrl_select_sleep_state( + config->usbc_force_gpio_p); + mbhc->usbc_mode = POWER_SUPPLY_TYPEC_NONE; + } + + return rc; +} + +/* workqueue */ +static void wcd_mbhc_usbc_analog_work_fn(struct work_struct *work) +{ + struct wcd_mbhc *mbhc = + container_of(work, struct wcd_mbhc, usbc_analog_work); + + wcd_mbhc_usb_c_analog_setup_gpios(mbhc, + mbhc->usbc_mode != POWER_SUPPLY_TYPEC_NONE); +} + +/* this callback function is used to process PMI notification */ +static int wcd_mbhc_usb_c_event_changed(struct notifier_block *nb, + unsigned long evt, void *ptr) +{ + int ret; + union power_supply_propval mode; + struct wcd_mbhc *mbhc = container_of(nb, struct wcd_mbhc, psy_nb); + struct snd_soc_codec *codec = mbhc->codec; + + if (ptr != mbhc->usb_psy || evt != PSY_EVENT_PROP_CHANGED) + return 0; + + ret = power_supply_get_property(mbhc->usb_psy, + POWER_SUPPLY_PROP_TYPEC_MODE, &mode); + if (ret) { + dev_err(codec->dev, "%s: Unable to read USB TYPEC_MODE: %d\n", + __func__, ret); + return ret; + } + + dev_dbg(codec->dev, "%s: USB change event received\n", + __func__); + dev_dbg(codec->dev, "%s: supply mode %d, expected %d\n", __func__, + mode.intval, POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER); + + switch (mode.intval) { + case POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER: + case POWER_SUPPLY_TYPEC_NONE: + dev_dbg(codec->dev, "%s: usbc_mode: %d; mode.intval: %d\n", + __func__, mbhc->usbc_mode, mode.intval); + + if (mbhc->usbc_mode == mode.intval) + break; /* filter notifications received before */ + mbhc->usbc_mode = mode.intval; + + dev_dbg(codec->dev, "%s: queueing usbc_analog_work\n", + __func__); + schedule_work(&mbhc->usbc_analog_work); + break; + default: + break; + } + return ret; +} + +/* PMI registration code */ +static int wcd_mbhc_usb_c_analog_init(struct wcd_mbhc *mbhc) +{ + int ret = 0; + struct snd_soc_codec *codec = mbhc->codec; + + dev_dbg(mbhc->codec->dev, "%s: usb-c analog setup start\n", __func__); + INIT_WORK(&mbhc->usbc_analog_work, wcd_mbhc_usbc_analog_work_fn); + + mbhc->usb_psy = power_supply_get_by_name("usb"); + if (IS_ERR_OR_NULL(mbhc->usb_psy)) { + dev_err(codec->dev, "%s: could not get USB psy info\n", + __func__); + ret = -EPROBE_DEFER; + if (IS_ERR(mbhc->usb_psy)) + ret = PTR_ERR(mbhc->usb_psy); + mbhc->usb_psy = NULL; + goto err; + } + + ret = wcd_mbhc_usb_c_analog_setup_gpios(mbhc, false); + if (ret) { + dev_err(codec->dev, "%s: error while setting USBC ana gpios\n", + __func__); + goto err; + } + + mbhc->psy_nb.notifier_call = wcd_mbhc_usb_c_event_changed; + mbhc->psy_nb.priority = 0; + ret = power_supply_reg_notifier(&mbhc->psy_nb); + if (ret) { + dev_err(codec->dev, "%s: power supply registration failed\n", + __func__); + goto err; + } + + /* + * as part of the init sequence check if there is a connected + * USB C analog adapter + */ + dev_dbg(mbhc->codec->dev, "%s: verify if USB adapter is already inserted\n", + __func__); + ret = wcd_mbhc_usb_c_event_changed(&mbhc->psy_nb, + PSY_EVENT_PROP_CHANGED, + mbhc->usb_psy); + +err: + return ret; +} + +static int wcd_mbhc_usb_c_analog_deinit(struct wcd_mbhc *mbhc) +{ + wcd_mbhc_usb_c_analog_setup_gpios(mbhc, false); + + /* deregister from PMI */ + power_supply_unreg_notifier(&mbhc->psy_nb); + + return 0; +} + +static int wcd_mbhc_init_gpio(struct wcd_mbhc *mbhc, + struct wcd_mbhc_config *mbhc_cfg, + const char *gpio_dt_str, + int *gpio, struct device_node **gpio_dn) +{ + int rc = 0; + struct snd_soc_codec *codec = mbhc->codec; + struct snd_soc_card *card = codec->component.card; + + dev_dbg(mbhc->codec->dev, "%s: gpio %s\n", __func__, gpio_dt_str); + + *gpio_dn = of_parse_phandle(card->dev->of_node, gpio_dt_str, 0); + + if (!(*gpio_dn)) { + *gpio = of_get_named_gpio(card->dev->of_node, gpio_dt_str, 0); + if (!gpio_is_valid(*gpio)) { + dev_err(card->dev, "%s, property %s not in node %s", + __func__, gpio_dt_str, + card->dev->of_node->full_name); + rc = -EINVAL; + } + } + + return rc; +} + +int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *mbhc_cfg) +{ + int rc = 0; + struct usbc_ana_audio_config *config; + struct snd_soc_codec *codec; + struct snd_soc_card *card; + const char *usb_c_dt = "qcom,msm-mbhc-usbc-audio-supported"; + + if (!mbhc || !mbhc_cfg) + return -EINVAL; + + config = &mbhc_cfg->usbc_analog_cfg; + codec = mbhc->codec; + card = codec->component.card; - pr_debug("%s: enter\n", __func__); /* update the mbhc config */ mbhc->mbhc_cfg = mbhc_cfg; + dev_dbg(mbhc->codec->dev, "%s: enter\n", __func__); + + /* check if USB C analog is defined on device tree */ + mbhc_cfg->enable_usbc_analog = 0; + if (of_find_property(card->dev->of_node, usb_c_dt, NULL)) { + rc = of_property_read_u32(card->dev->of_node, usb_c_dt, + &mbhc_cfg->enable_usbc_analog); + } + if (mbhc_cfg->enable_usbc_analog == 0 || rc != 0) { + dev_info(card->dev, + "%s: %s in dt node is missing or false\n", + __func__, usb_c_dt); + dev_info(card->dev, + "%s: skipping USB c analog configuration\n", __func__); + } + + /* initialize GPIOs */ + if (mbhc_cfg->enable_usbc_analog) { + dev_dbg(mbhc->codec->dev, "%s: usbc analog enabled\n", + __func__); + rc = wcd_mbhc_init_gpio(mbhc, mbhc_cfg, + "qcom,usbc-analog-en1_gpio", + &config->usbc_en1_gpio, + &config->usbc_en1_gpio_p); + if (rc) + goto err; + + rc = wcd_mbhc_init_gpio(mbhc, mbhc_cfg, + "qcom,usbc-analog-en2_n_gpio", + &config->usbc_en2n_gpio, + &config->usbc_en2n_gpio_p); + if (rc) + goto err; + + if (of_find_property(card->dev->of_node, + "qcom,usbc-analog-force_detect_gpio", + NULL)) { + rc = wcd_mbhc_init_gpio(mbhc, mbhc_cfg, + "qcom,usbc-analog-force_detect_gpio", + &config->usbc_force_gpio, + &config->usbc_force_gpio_p); + if (rc) + goto err; + } + + dev_dbg(mbhc->codec->dev, "%s: calling usb_c_analog_init\n", + __func__); + /* init PMI notifier */ + rc = wcd_mbhc_usb_c_analog_init(mbhc); + if (rc) { + rc = EPROBE_DEFER; + goto err; + } + } + /* Set btn key code */ if ((!mbhc->is_btn_already_regd) && wcd_mbhc_set_keycode(mbhc)) pr_err("Set btn key code error!!!\n"); @@ -2329,14 +2594,44 @@ int wcd_mbhc_start(struct wcd_mbhc *mbhc, pr_err("%s: Skipping to read mbhc fw, 0x%pK %pK\n", __func__, mbhc->mbhc_fw, mbhc->mbhc_cal); } - pr_debug("%s: leave %d\n", __func__, rc); + + return rc; +err: + if (config->usbc_en1_gpio > 0) { + dev_dbg(card->dev, "%s free usb en1 gpio %d\n", + __func__, config->usbc_en1_gpio); + gpio_free(config->usbc_en1_gpio); + config->usbc_en1_gpio = 0; + } + if (config->usbc_en2n_gpio > 0) { + dev_dbg(card->dev, "%s free usb_en2 gpio %d\n", + __func__, config->usbc_en2n_gpio); + gpio_free(config->usbc_en2n_gpio); + config->usbc_en2n_gpio = 0; + } + if (config->usbc_force_gpio > 0) { + dev_dbg(card->dev, "%s free usb_force gpio %d\n", + __func__, config->usbc_force_gpio); + gpio_free(config->usbc_force_gpio); + config->usbc_force_gpio = 0; + } + if (config->usbc_en1_gpio_p) + of_node_put(config->usbc_en1_gpio_p); + if (config->usbc_en2n_gpio_p) + of_node_put(config->usbc_en2n_gpio_p); + if (config->usbc_force_gpio_p) + of_node_put(config->usbc_force_gpio_p); + dev_dbg(mbhc->codec->dev, "%s: leave %d\n", __func__, rc); return rc; } EXPORT_SYMBOL(wcd_mbhc_start); void wcd_mbhc_stop(struct wcd_mbhc *mbhc) { + struct usbc_ana_audio_config *config = &mbhc->mbhc_cfg->usbc_analog_cfg; + pr_debug("%s: enter\n", __func__); + if (mbhc->current_plug != MBHC_PLUG_TYPE_NONE) { if (mbhc->mbhc_cb && mbhc->mbhc_cb->skip_imped_detect) mbhc->mbhc_cb->skip_imped_detect(mbhc->codec); @@ -2358,6 +2653,25 @@ void wcd_mbhc_stop(struct wcd_mbhc *mbhc) mbhc->mbhc_fw = NULL; mbhc->mbhc_cal = NULL; } + + if (mbhc->mbhc_cfg->enable_usbc_analog) { + wcd_mbhc_usb_c_analog_deinit(mbhc); + /* free GPIOs */ + if (config->usbc_en1_gpio > 0) + gpio_free(config->usbc_en1_gpio); + if (config->usbc_en2n_gpio > 0) + gpio_free(config->usbc_en2n_gpio); + if (config->usbc_force_gpio) + gpio_free(config->usbc_force_gpio); + + if (config->usbc_en1_gpio_p) + of_node_put(config->usbc_en1_gpio_p); + if (config->usbc_en2n_gpio_p) + of_node_put(config->usbc_en2n_gpio_p); + if (config->usbc_force_gpio_p) + of_node_put(config->usbc_force_gpio_p); + } + pr_debug("%s: leave\n", __func__); } EXPORT_SYMBOL(wcd_mbhc_stop); diff --git a/sound/soc/codecs/wcd-mbhc-v2.h b/sound/soc/codecs/wcd-mbhc-v2.h index 60473ce8dab0..6f23a2dcbff7 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.h +++ b/sound/soc/codecs/wcd-mbhc-v2.h @@ -14,6 +14,7 @@ #include <linux/wait.h> #include <linux/stringify.h> +#include <linux/power_supply.h> #include "wcdcal-hwdep.h" #define TOMBAK_MBHC_NC 0 @@ -249,6 +250,15 @@ enum mbhc_moisture_rref { R_184_KOHM, }; +struct usbc_ana_audio_config { + int usbc_en1_gpio; + int usbc_en2n_gpio; + int usbc_force_gpio; + struct device_node *usbc_en1_gpio_p; /* used by pinctrl API */ + struct device_node *usbc_en2n_gpio_p; /* used by pinctrl API */ + struct device_node *usbc_force_gpio_p; /* used by pinctrl API */ +}; + struct wcd_mbhc_config { bool read_fw_bin; void *calibration; @@ -263,6 +273,8 @@ struct wcd_mbhc_config { int mbhc_micbias; int anc_micbias; bool enable_anc_mic_detect; + u32 enable_usbc_analog; + struct usbc_ana_audio_config usbc_analog_cfg; }; struct wcd_mbhc_intr { @@ -443,6 +455,11 @@ struct wcd_mbhc { unsigned long intr_status; bool is_hph_ocp_pending; + + int usbc_mode; + struct notifier_block psy_nb; + struct power_supply *usb_psy; + struct work_struct usbc_analog_work; }; #define WCD_MBHC_CAL_SIZE(buttons, rload) ( \ sizeof(struct wcd_mbhc_general_cfg) + \ diff --git a/sound/soc/codecs/wcd934x/wcd934x-mbhc.c b/sound/soc/codecs/wcd934x/wcd934x-mbhc.c index f9b588e87e87..3d032f0a7115 100644 --- a/sound/soc/codecs/wcd934x/wcd934x-mbhc.c +++ b/sound/soc/codecs/wcd934x/wcd934x-mbhc.c @@ -772,13 +772,19 @@ static void tavil_mbhc_moisture_config(struct wcd_mbhc *mbhc) { struct snd_soc_codec *codec = mbhc->codec; - if (mbhc->moist_rref == R_OFF) + if ((mbhc->moist_rref == R_OFF) || + (mbhc->mbhc_cfg->enable_usbc_analog)) { + snd_soc_update_bits(codec, WCD934X_MBHC_NEW_CTL_2, + 0x0C, R_OFF << 2); return; + } /* Donot enable moisture detection if jack type is NC */ if (!mbhc->hphl_swh) { dev_dbg(codec->dev, "%s: disable moisture detection for NC\n", __func__); + snd_soc_update_bits(codec, WCD934X_MBHC_NEW_CTL_2, + 0x0C, R_OFF << 2); return; } diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c index f2850d5e5ed3..86ad8752b6ff 100644 --- a/sound/soc/codecs/wcd934x/wcd934x.c +++ b/sound/soc/codecs/wcd934x/wcd934x.c @@ -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 @@ -1882,12 +1882,8 @@ static void tavil_codec_override(struct snd_soc_codec *codec, int mode, switch (event) { case SND_SOC_DAPM_PRE_PMU: case SND_SOC_DAPM_POST_PMU: - if (!(snd_soc_read(codec, - WCD934X_CDC_RX2_RX_PATH_CTL) & 0x10) && - (!(snd_soc_read(codec, - WCD934X_CDC_RX1_RX_PATH_CTL) & 0x10))) - snd_soc_update_bits(codec, - WCD9XXX_A_ANA_RX_SUPPLIES, 0x02, 0x02); + snd_soc_update_bits(codec, + WCD9XXX_A_ANA_RX_SUPPLIES, 0x02, 0x02); break; case SND_SOC_DAPM_POST_PMD: snd_soc_update_bits(codec, @@ -1923,10 +1919,14 @@ static int tavil_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_POST_PMU: /* * 7ms sleep is required after PA is enabled as per - * HW requirement + * HW requirement. If compander is disabled, then + * 20ms delay is needed. */ if (test_bit(HPH_PA_DELAY, &tavil->status_mask)) { - usleep_range(7000, 7100); + if (!tavil->comp_enabled[COMPANDER_2]) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); clear_bit(HPH_PA_DELAY, &tavil->status_mask); } @@ -1965,10 +1965,18 @@ static int tavil_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, WCD934X_HPH_R_TEST, 0x01, 0x00); snd_soc_update_bits(codec, WCD934X_CDC_RX2_RX_PATH_CTL, 0x10, 0x10); + snd_soc_update_bits(codec, WCD934X_CDC_RX2_RX_PATH_MIX_CTL, + 0x10, 0x10); break; case SND_SOC_DAPM_POST_PMD: - /* 5ms sleep is required after PA disable */ - usleep_range(5000, 5100); + /* + * 5ms sleep is required after PA disable. If compander is + * disabled, then 20ms delay is needed after PA disable. + */ + if (!tavil->comp_enabled[COMPANDER_2]) + usleep_range(20000, 20100); + else + usleep_range(5000, 5100); tavil_codec_override(codec, tavil->hph_mode, event); blocking_notifier_call_chain(&tavil->mbhc->notifier, WCD_EVENT_POST_HPHR_PA_OFF, @@ -2008,10 +2016,14 @@ static int tavil_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_POST_PMU: /* * 7ms sleep is required after PA is enabled as per - * HW requirement + * HW requirement. If compander is disabled, then + * 20ms delay is needed. */ if (test_bit(HPH_PA_DELAY, &tavil->status_mask)) { - usleep_range(7000, 7100); + if (!tavil->comp_enabled[COMPANDER_1]) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); clear_bit(HPH_PA_DELAY, &tavil->status_mask); } snd_soc_update_bits(codec, WCD934X_HPH_L_TEST, 0x01, 0x01); @@ -2049,10 +2061,18 @@ static int tavil_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, WCD934X_HPH_L_TEST, 0x01, 0x00); snd_soc_update_bits(codec, WCD934X_CDC_RX1_RX_PATH_CTL, 0x10, 0x10); + snd_soc_update_bits(codec, WCD934X_CDC_RX1_RX_PATH_MIX_CTL, + 0x10, 0x10); break; case SND_SOC_DAPM_POST_PMD: - /* 5ms sleep is required after PA disable */ - usleep_range(5000, 5100); + /* + * 5ms sleep is required after PA disable. If compander is + * disabled, then 20ms delay is needed after PA disable. + */ + if (!tavil->comp_enabled[COMPANDER_1]) + usleep_range(20000, 20100); + else + usleep_range(5000, 5100); tavil_codec_override(codec, tavil->hph_mode, event); blocking_notifier_call_chain(&tavil->mbhc->notifier, WCD_EVENT_POST_HPHL_PA_OFF, diff --git a/sound/soc/codecs/wcd9xxx-common-v2.c b/sound/soc/codecs/wcd9xxx-common-v2.c index 47518ec92661..c2f7b1e99cd5 100644 --- a/sound/soc/codecs/wcd9xxx-common-v2.c +++ b/sound/soc/codecs/wcd9xxx-common-v2.c @@ -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 @@ -130,6 +130,81 @@ static const struct wcd_reg_mask_val imped_table[][MAX_IMPED_PARAMS] = { }, }; +static const struct wcd_reg_mask_val imped_table_tavil[][MAX_IMPED_PARAMS] = { + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf2}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf2}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf2}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf2}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf4}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf4}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf4}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf4}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf7}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf7}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf7}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf7}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf9}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf9}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf9}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf9}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfa}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfa}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfa}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfa}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfb}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfb}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfb}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfb}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfc}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfc}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfc}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfc}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfd}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfd}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfd}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfd}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfd}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfd}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfd}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfd}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01}, + }, +}; + static const struct wcd_imped_val imped_index[] = { {4, 0}, {5, 1}, @@ -185,12 +260,26 @@ void wcd_clsh_imped_config(struct snd_soc_codec *codec, int imped, bool reset) { int i; int index = 0; + int table_size; + + static const struct wcd_reg_mask_val + (*imped_table_ptr)[MAX_IMPED_PARAMS]; + struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent); + + if (IS_CODEC_TYPE(wcd9xxx, WCD934X)) { + table_size = ARRAY_SIZE(imped_table_tavil); + imped_table_ptr = imped_table_tavil; + } else { + table_size = ARRAY_SIZE(imped_table); + imped_table_ptr = imped_table; + } /* reset = 1, which means request is to reset the register values */ if (reset) { for (i = 0; i < MAX_IMPED_PARAMS; i++) - snd_soc_update_bits(codec, imped_table[index][i].reg, - imped_table[index][i].mask, 0); + snd_soc_update_bits(codec, + imped_table_ptr[index][i].reg, + imped_table_ptr[index][i].mask, 0); return; } index = get_impedance_index(imped); @@ -198,15 +287,16 @@ void wcd_clsh_imped_config(struct snd_soc_codec *codec, int imped, bool reset) pr_debug("%s, impedance not in range = %d\n", __func__, imped); return; } - if (index >= ARRAY_SIZE(imped_table)) { + if (index >= table_size) { pr_debug("%s, impedance index not in range = %d\n", __func__, index); return; } for (i = 0; i < MAX_IMPED_PARAMS; i++) - snd_soc_update_bits(codec, imped_table[index][i].reg, - imped_table[index][i].mask, - imped_table[index][i].val); + snd_soc_update_bits(codec, + imped_table_ptr[index][i].reg, + imped_table_ptr[index][i].mask, + imped_table_ptr[index][i].val); } EXPORT_SYMBOL(wcd_clsh_imped_config); @@ -579,6 +669,11 @@ static void wcd_clsh_set_hph_mode(struct snd_soc_codec *codec, static void wcd_clsh_set_flyback_vneg_ctl(struct snd_soc_codec *codec, bool enable) { + struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent); + + if (!TASHA_IS_2_0(wcd9xxx)) + return; + if (enable) { snd_soc_update_bits(codec, WCD9XXX_FLYBACK_VNEG_CTRL_1, 0xE0, 0x00); @@ -758,35 +853,35 @@ static void wcd_clsh_state_ear_lo(struct snd_soc_codec *codec, dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode), is_enable ? "enable" : "disable"); - if (is_enable && (req_state == WCD_CLSH_STATE_LO)) { - wcd_clsh_set_buck_regulator_mode(codec, CLS_AB); - } else { - if (req_state == WCD_CLSH_STATE_EAR) - goto end; - - /* LO powerdown. - * If EAR Class-H is already enabled, just - * turn on regulator other enable Class-H - * configuration + if (is_enable) { + /* LO powerup is taken care in PA sequence. + * No need to change to class AB here. */ - if (wcd_clsh_enable_status(codec)) { - wcd_clsh_set_buck_regulator_mode(codec, - CLS_H_NORMAL); - goto end; + if (req_state == WCD_CLSH_STATE_EAR) { + /* EAR powerup.*/ + if (!wcd_clsh_enable_status(codec)) { + wcd_enable_clsh_block(codec, clsh_d, true); + wcd_clsh_set_buck_mode(codec, mode); + wcd_clsh_set_flyback_mode(codec, mode); + } + snd_soc_update_bits(codec, + WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, + 0x40, 0x40); } - wcd_enable_clsh_block(codec, clsh_d, true); - snd_soc_update_bits(codec, - WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, - 0x40, 0x40); - wcd_clsh_set_buck_regulator_mode(codec, - CLS_H_NORMAL); - wcd_clsh_set_buck_mode(codec, mode); - wcd_clsh_set_flyback_mode(codec, mode); - wcd_clsh_flyback_ctrl(codec, clsh_d, mode, true); - wcd_clsh_buck_ctrl(codec, clsh_d, mode, true); + } else { + if (req_state == WCD_CLSH_STATE_EAR) { + /* EAR powerdown.*/ + wcd_enable_clsh_block(codec, clsh_d, false); + wcd_clsh_set_buck_mode(codec, CLS_H_NORMAL); + wcd_clsh_set_flyback_mode(codec, CLS_H_NORMAL); + snd_soc_update_bits(codec, + WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, + 0x40, 0x00); + } + /* LO powerdown is taken care in PA sequence. + * No need to change to class H here. + */ } -end: - return; } static void wcd_clsh_state_hph_lo(struct snd_soc_codec *codec, @@ -1135,6 +1230,7 @@ static bool wcd_clsh_is_state_valid(u8 state) case WCD_CLSH_STATE_HPHL_LO: case WCD_CLSH_STATE_HPHR_LO: case WCD_CLSH_STATE_HPH_ST_LO: + case WCD_CLSH_STATE_EAR_LO: return true; default: return false; diff --git a/sound/soc/codecs/wcd9xxx-resmgr-v2.c b/sound/soc/codecs/wcd9xxx-resmgr-v2.c index 84754b8d09b0..71edded182e0 100644 --- a/sound/soc/codecs/wcd9xxx-resmgr-v2.c +++ b/sound/soc/codecs/wcd9xxx-resmgr-v2.c @@ -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 @@ -247,9 +247,15 @@ static int wcd_resmgr_enable_clk_mclk(struct wcd9xxx_resmgr_v2 *resmgr) * to CLK_SYS_MCLK_PRG */ wcd_resmgr_codec_reg_update_bits(resmgr, + WCD934X_CLK_SYS_MCLK_PRG, 0x91, 0x91); + wcd_resmgr_codec_reg_update_bits(resmgr, WCD934X_CLK_SYS_MCLK_PRG, 0x02, 0x00); wcd_resmgr_codec_reg_update_bits(resmgr, - WCD934X_CLK_SYS_MCLK_PRG, 0x91, 0x91); + WCD934X_CLK_SYS_INT_CLK_TEST2, 0x04, + 0x04); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD934X_CLK_SYS_INT_CLK_TEST2, 0x04, + 0x00); wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, 0x01, 0x01); diff --git a/sound/soc/codecs/wcd_cpe_core.c b/sound/soc/codecs/wcd_cpe_core.c index 3aa9ac8d40b6..2088698392de 100644 --- a/sound/soc/codecs/wcd_cpe_core.c +++ b/sound/soc/codecs/wcd_cpe_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 @@ -891,14 +891,7 @@ static int wcd_cpe_enable(struct wcd_cpe_core *core, * instead SSR handler will control CPE. */ wcd_cpe_enable_cpe_clks(core, false); - /* - * During BUS_DOWN event, possibly the - * irq driver is under cleanup, do not request - * cleanup of irqs here, rather cleanup irqs - * once BUS_UP event is received. - */ - if (core->ssr_type != WCD_CPE_BUS_DOWN_EVENT) - wcd_cpe_cleanup_irqs(core); + wcd_cpe_cleanup_irqs(core); goto done; } @@ -1149,7 +1142,6 @@ int wcd_cpe_ssr_event(void *core_handle, break; case WCD_CPE_BUS_UP_EVENT: - wcd_cpe_cleanup_irqs(core); wcd_cpe_set_and_complete(core, WCD_CPE_BUS_READY); /* * In case of bus up event ssr_type will be changed diff --git a/sound/soc/msm/msm8998.c b/sound/soc/msm/msm8998.c index 6396cd6aaf39..4af737680118 100644 --- a/sound/soc/msm/msm8998.c +++ b/sound/soc/msm/msm8998.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 @@ -3323,6 +3323,17 @@ static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd) 134, 135, 136, 137, 138, 139, 140, 141, 142, 143}; + /* Tavil Codec SLIMBUS configuration + * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8 + * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13 + * TX14, TX15, TX16 + */ + unsigned int rx_ch_tavil[WCD934X_RX_MAX] = {144, 145, 146, 147, 148, + 149, 150, 151}; + unsigned int tx_ch_tavil[WCD934X_TX_MAX] = {128, 129, 130, 131, 132, + 134, 135, 136, 137, 138, 139, + 133, 140, 141, 142, 143}; + pr_info("%s: dev_name%s\n", __func__, dev_name(cpu_dai->dev)); rtd->pmdown_time = 0; @@ -3383,8 +3394,15 @@ static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_sync(dapm); - snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch), - tx_ch, ARRAY_SIZE(rx_ch), rx_ch); + if (!strcmp(dev_name(codec_dai->dev), "tavil_codec")) { + snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch_tavil), + tx_ch_tavil, ARRAY_SIZE(rx_ch_tavil), + rx_ch_tavil); + } else { + snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch), + tx_ch, ARRAY_SIZE(rx_ch), + rx_ch); + } if (!strcmp(dev_name(codec_dai->dev), "tavil_codec")) { msm_codec_fn.get_afe_config_fn = tavil_get_afe_config; diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index d3c0850d8de2..9421d03f6a8d 100644 --- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-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 @@ -863,6 +863,9 @@ static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream, if (prtd->codec_param.codec.format == SND_AUDIOSTREAMFORMAT_MP4ADTS) aac_cfg.format = 0x0; + else if (prtd->codec_param.codec.format == + SND_AUDIOSTREAMFORMAT_MP4LATM) + aac_cfg.format = 0x04; else aac_cfg.format = 0x03; aac_cfg.ch_cfg = prtd->num_channels; diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c index 954db7943e48..7b292eef02f8 100644 --- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c @@ -1901,6 +1901,11 @@ static int msm_dai_q6_set_channel_map(struct snd_soc_dai *dai, pr_err("%s: rx slot not found\n", __func__); return -EINVAL; } + if (rx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) { + pr_err("%s: invalid rx num %d\n", __func__, rx_num); + return -EINVAL; + } + for (i = 0; i < rx_num; i++) { dai_data->port_config.slim_sch.shared_ch_mapping[i] = rx_slot[i]; @@ -1934,6 +1939,11 @@ static int msm_dai_q6_set_channel_map(struct snd_soc_dai *dai, pr_err("%s: tx slot not found\n", __func__); return -EINVAL; } + if (tx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) { + pr_err("%s: invalid tx num %d\n", __func__, tx_num); + return -EINVAL; + } + for (i = 0; i < tx_num; i++) { dai_data->port_config.slim_sch.shared_ch_mapping[i] = tx_slot[i]; diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c index 5866e46cc6a2..df32ede49ed0 100644 --- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c +++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2014, 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-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 * only version 2 as published by the Free Software Foundation. @@ -803,7 +803,7 @@ int msm_dolby_dap_param_to_get_control_get(struct snd_kcontrol *kcontrol, __func__, copp_idx); return -EINVAL; } - params_value = kzalloc(params_length, GFP_KERNEL); + params_value = kzalloc(params_length + param_payload_len, GFP_KERNEL); if (!params_value) { pr_err("%s, params memory alloc failed\n", __func__); return -ENOMEM; @@ -822,8 +822,7 @@ int msm_dolby_dap_param_to_get_control_get(struct snd_kcontrol *kcontrol, pr_err("%s: invalid param id to set", __func__); rc = -EINVAL; } else { - params_length = (dolby_dap_params_length[i] + - DOLBY_PARAM_PAYLOAD_SIZE) * + params_length = dolby_dap_params_length[i] * sizeof(uint32_t); rc = adm_get_params(port_id, copp_idx, DOLBY_BUNDLE_MODULE_ID, diff --git a/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c b/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c index 39e7e087b3e3..4de712a10f96 100644 --- a/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c +++ b/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.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 * only version 2 as published by the Free Software Foundation. @@ -198,7 +198,8 @@ static void msm_ds2_dap_check_and_update_ramp_wait(int port_id, int copp_idx, uint32_t param_payload_len = PARAM_PAYLOAD_SIZE * sizeof(uint32_t); int rc = 0; - update_params_value = kzalloc(params_length, GFP_KERNEL); + update_params_value = kzalloc(params_length + param_payload_len, + GFP_KERNEL); if (!update_params_value) { pr_err("%s: params memory alloc failed\n", __func__); goto end; @@ -1656,6 +1657,7 @@ static int msm_ds2_dap_param_visualizer_control_get(u32 cmd, void *arg) ret = 0; dolby_data->length = 0; pr_err("%s Incorrect VCNB length", __func__); + return -EINVAL; } params_length = (2*length + DOLBY_VIS_PARAM_HEADER_SIZE) * diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c index 82458275b892..bd1468beedf6 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c @@ -25,6 +25,7 @@ #include <sound/control.h> #include <sound/tlv.h> #include <asm/dma.h> +#include <sound/q6audio-v2.h> #include "msm-pcm-routing-v2.h" @@ -67,6 +68,10 @@ static struct fe_dai_session_map session_map[LOOPBACK_SESSION_MAX] = { static u32 hfp_tx_mute; +struct msm_pcm_pdata { + int perf_mode; +}; + static void stop_pcm(struct msm_pcm_loopback *pcm); static int msm_pcm_loopback_get_session(struct snd_soc_pcm_runtime *rtd, struct msm_pcm_loopback **pcm); @@ -244,6 +249,7 @@ static int msm_pcm_open(struct snd_pcm_substream *substream) struct msm_pcm_routing_evt event; struct asm_session_mtmx_strtr_param_window_v2_t asm_mtmx_strtr_window; uint32_t param_id; + struct msm_pcm_pdata *pdata; ret = msm_pcm_loopback_get_session(rtd, &pcm); if (ret) @@ -269,6 +275,15 @@ static int msm_pcm_open(struct snd_pcm_substream *substream) if (pcm->audio_client != NULL) stop_pcm(pcm); + pdata = (struct msm_pcm_pdata *) + dev_get_drvdata(rtd->platform->dev); + if (!pdata) { + dev_err(rtd->platform->dev, + "%s: platform data not populated\n", __func__); + mutex_unlock(&pcm->lock); + return -EINVAL; + } + pcm->audio_client = q6asm_audio_client_alloc( (app_cb)msm_pcm_loopback_event_handler, pcm); if (!pcm->audio_client) { @@ -278,7 +293,7 @@ static int msm_pcm_open(struct snd_pcm_substream *substream) return -ENOMEM; } pcm->session_id = pcm->audio_client->session; - pcm->audio_client->perf_mode = false; + pcm->audio_client->perf_mode = pdata->perf_mode; ret = q6asm_open_loopback_v2(pcm->audio_client, bits_per_sample); if (ret < 0) { @@ -745,9 +760,23 @@ static struct snd_soc_platform_driver msm_soc_platform = { static int msm_pcm_probe(struct platform_device *pdev) { + struct msm_pcm_pdata *pdata; + dev_dbg(&pdev->dev, "%s: dev name %s\n", __func__, dev_name(&pdev->dev)); + pdata = kzalloc(sizeof(struct msm_pcm_pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + if (of_property_read_bool(pdev->dev.of_node, + "qcom,msm-pcm-loopback-low-latency")) + pdata->perf_mode = LOW_LATENCY_PCM_MODE; + else + pdata->perf_mode = LEGACY_PCM_MODE; + + dev_set_drvdata(&pdev->dev, pdata); + return snd_soc_register_platform(&pdev->dev, &msm_soc_platform); } diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index 41f68e05e075..485ffa06f5bd 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -5257,6 +5257,57 @@ static const struct snd_kcontrol_new mmul8_mixer_controls[] = { msm_routing_put_audio_mixer), }; +static const struct snd_kcontrol_new mmul9_mixer_controls[] = { + SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX, + MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX, + MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX, + MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX, + MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX, + MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("SLIM_6_TX", MSM_BACKEND_DAI_SLIMBUS_6_TX, + MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0, + MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1, + MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2, + MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3, + MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1, + MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2, + MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3, + MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +}; + static const struct snd_kcontrol_new mmul17_mixer_controls[] = { SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, @@ -6084,6 +6135,12 @@ static const struct snd_kcontrol_new slimbus_8_rx_voice_mixer_controls[] = { msm_routing_put_voice_mixer), }; +static const struct snd_kcontrol_new quat_tdm_rx_2_voice_mixer_controls[] = { + SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, + msm_routing_put_voice_mixer), +}; + static const struct snd_kcontrol_new stub_rx_mixer_controls[] = { SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_EXTPROC_RX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, @@ -6349,6 +6406,9 @@ static const struct snd_kcontrol_new tx_voicemmode1_mixer_controls[] = { SOC_SINGLE_EXT("USB_AUDIO_TX_MMode1", MSM_BACKEND_DAI_USB_TX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), + SOC_SINGLE_EXT("QUAT_TDM_TX_0_MMode1", + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_VOICEMMODE1, + 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new tx_voicemmode2_mixer_controls[] = { @@ -7885,7 +7945,7 @@ int msm_routing_get_rms_value_control(struct snd_kcontrol *kcontrol, int *update_param_value; uint32_t param_length = sizeof(uint32_t); uint32_t param_payload_len = RMS_PAYLOAD_LEN * sizeof(uint32_t); - param_value = kzalloc(param_length, GFP_KERNEL); + param_value = kzalloc(param_length + param_payload_len, GFP_KERNEL); if (!param_value) { pr_err("%s, param memory alloc failed\n", __func__); return -ENOMEM; @@ -9225,6 +9285,8 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { mmul6_mixer_controls, ARRAY_SIZE(mmul6_mixer_controls)), SND_SOC_DAPM_MIXER("MultiMedia8 Mixer", SND_SOC_NOPM, 0, 0, mmul8_mixer_controls, ARRAY_SIZE(mmul8_mixer_controls)), + SND_SOC_DAPM_MIXER("MultiMedia9 Mixer", SND_SOC_NOPM, 0, 0, + mmul9_mixer_controls, ARRAY_SIZE(mmul9_mixer_controls)), SND_SOC_DAPM_MIXER("MultiMedia17 Mixer", SND_SOC_NOPM, 0, 0, mmul17_mixer_controls, ARRAY_SIZE(mmul17_mixer_controls)), SND_SOC_DAPM_MIXER("MultiMedia18 Mixer", SND_SOC_NOPM, 0, 0, @@ -9329,6 +9391,10 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { SND_SOC_NOPM, 0, 0, quin_mi2s_rx_voice_mixer_controls, ARRAY_SIZE(quin_mi2s_rx_voice_mixer_controls)), + SND_SOC_DAPM_MIXER("QUAT_TDM_RX_2_Voice Mixer", + SND_SOC_NOPM, 0, 0, + quat_tdm_rx_2_voice_mixer_controls, + ARRAY_SIZE(quat_tdm_rx_2_voice_mixer_controls)), SND_SOC_DAPM_MIXER("Voice_Tx Mixer", SND_SOC_NOPM, 0, 0, tx_voice_mixer_controls, ARRAY_SIZE(tx_voice_mixer_controls)), @@ -10260,6 +10326,15 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia8 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"}, {"MultiMedia8 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"}, + {"MultiMedia9 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"}, + {"MultiMedia9 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"}, + {"MultiMedia9 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"}, + {"MultiMedia9 Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"}, + {"MultiMedia9 Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"}, + {"MultiMedia9 Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"}, + {"MultiMedia9 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"}, + {"MultiMedia9 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"}, + {"MultiMedia1 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"}, {"MultiMedia2 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"}, {"MultiMedia4 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"}, @@ -10374,6 +10449,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"MM_UL5", NULL, "MultiMedia5 Mixer"}, {"MM_UL6", NULL, "MultiMedia6 Mixer"}, {"MM_UL8", NULL, "MultiMedia8 Mixer"}, + {"MM_UL9", NULL, "MultiMedia9 Mixer"}, {"MM_UL17", NULL, "MultiMedia17 Mixer"}, {"MM_UL18", NULL, "MultiMedia18 Mixer"}, {"MM_UL19", NULL, "MultiMedia19 Mixer"}, @@ -10698,6 +10774,9 @@ static const struct snd_soc_dapm_route intercon[] = { {"QUIN_MI2S_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"}, {"QUIN_MI2S_RX", NULL, "QUIN_MI2S_RX_Voice Mixer"}, + {"QUAT_TDM_RX_2_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"}, + {"QUAT_TDM_RX_2", NULL, "QUAT_TDM_RX_2_Voice Mixer"}, + {"VOC_EXT_EC MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"}, {"VOC_EXT_EC MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"}, {"VOC_EXT_EC MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"}, @@ -10863,6 +10942,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"VoiceMMode1_Tx Mixer", "SEC_AUX_PCM_TX_MMode1", "SEC_AUX_PCM_TX"}, {"VoiceMMode1_Tx Mixer", "TERT_AUX_PCM_TX_MMode1", "TERT_AUX_PCM_TX"}, {"VoiceMMode1_Tx Mixer", "QUAT_AUX_PCM_TX_MMode1", "QUAT_AUX_PCM_TX"}, + {"VoiceMMode1_Tx Mixer", "QUAT_TDM_TX_0_MMode1", "QUAT_TDM_TX_0"}, {"VOICEMMODE1_UL", NULL, "VoiceMMode1_Tx Mixer"}, {"VoiceMMode2_Tx Mixer", "PRI_TX_MMode2", "PRI_I2S_TX"}, diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c index ccd098d65160..24c47f764a7d 100644 --- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c +++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-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 @@ -93,6 +93,8 @@ static int msm_route_sec_auxpcm_lb_vol_ctrl; static const DECLARE_TLV_DB_LINEAR(sec_auxpcm_lb_vol_gain, 0, INT_RX_VOL_MAX_STEPS); +static int msm_multichannel_ec_primary_mic_ch; + static void msm_qti_pp_send_eq_values_(int eq_idx) { int result; @@ -343,7 +345,7 @@ static int msm_qti_pp_get_rms_value_control(struct snd_kcontrol *kcontrol, uint32_t param_length = sizeof(uint32_t); uint32_t param_payload_len = RMS_PAYLOAD_LEN * sizeof(uint32_t); struct msm_pcm_routing_bdai_data msm_bedai; - param_value = kzalloc(param_length, GFP_KERNEL); + param_value = kzalloc(param_length + param_payload_len, GFP_KERNEL); if (!param_value) { pr_err("%s, param memory alloc failed\n", __func__); return -ENOMEM; @@ -791,6 +793,43 @@ static int msm_qti_pp_asphere_set(struct snd_kcontrol *kcontrol, return 0; } +static int msm_multichannel_ec_primary_mic_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = 0; + int copp_idx = 0; + int port_id = AFE_PORT_ID_QUATERNARY_TDM_TX; + + msm_multichannel_ec_primary_mic_ch = ucontrol->value.integer.value[0]; + pr_debug("%s: msm_multichannel_ec_primary_mic_ch = %u\n", + __func__, msm_multichannel_ec_primary_mic_ch); + copp_idx = adm_get_default_copp_idx(port_id); + if ((copp_idx < 0) || (copp_idx > MAX_COPPS_PER_PORT)) { + pr_err("%s : no active copp to query multichannel ec copp_idx: %u\n", + __func__, copp_idx); + return -EINVAL; + } + adm_send_set_multichannel_ec_primary_mic_ch(port_id, copp_idx, + msm_multichannel_ec_primary_mic_ch); + + return ret; +} + +static int msm_multichannel_ec_primary_mic_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = msm_multichannel_ec_primary_mic_ch; + pr_debug("%s: msm_multichannel_ec_primary_mic_ch = %lu\n", + __func__, ucontrol->value.integer.value[0]); + return 0; +} + +static const struct snd_kcontrol_new msm_multichannel_ec_controls[] = { + SOC_SINGLE_EXT("Multichannel EC Primary Mic Ch", SND_SOC_NOPM, 0, + 0xFFFFFFFF, 0, msm_multichannel_ec_primary_mic_ch_get, + msm_multichannel_ec_primary_mic_ch_put), +}; + static const struct snd_kcontrol_new int_fm_vol_mixer_controls[] = { SOC_SINGLE_EXT_TLV("Internal FM RX Volume", SND_SOC_NOPM, 0, INT_RX_VOL_GAIN, 0, msm_qti_pp_get_fm_vol_mixer, @@ -1057,5 +1096,8 @@ void msm_qti_pp_add_controls(struct snd_soc_platform *platform) snd_soc_add_platform_controls(platform, asphere_mixer_controls, ARRAY_SIZE(asphere_mixer_controls)); + + snd_soc_add_platform_controls(platform, msm_multichannel_ec_controls, + ARRAY_SIZE(msm_multichannel_ec_controls)); } #endif /* CONFIG_QTI_PP */ diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c index 04eafdb240f2..32826d38f65a 100644 --- a/sound/soc/msm/qdsp6v2/q6adm.c +++ b/sound/soc/msm/qdsp6v2/q6adm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-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 @@ -978,9 +978,10 @@ int adm_get_params_v2(int port_id, int copp_idx, uint32_t module_id, char *params, uint32_t client_id) { struct adm_cmd_get_pp_params_v5 *adm_params = NULL; - int sz, rc = 0, i = 0; + int rc = 0, i = 0; int port_idx, idx; int *params_data = (int *)params; + uint64_t sz = 0; port_id = afe_convert_virtual_to_portid(port_id); port_idx = adm_validate_and_get_port_index(port_id); @@ -989,7 +990,16 @@ int adm_get_params_v2(int port_id, int copp_idx, uint32_t module_id, return -EINVAL; } - sz = sizeof(struct adm_cmd_get_pp_params_v5) + params_length; + sz = (uint64_t)sizeof(struct adm_cmd_get_pp_params_v5) + + (uint64_t)params_length; + /* + * Check if the value of "sz" (which is ultimately assigned to + * "hdr.pkt_size") crosses U16_MAX. + */ + if (sz > U16_MAX) { + pr_err("%s: Invalid params_length\n", __func__); + return -EINVAL; + } adm_params = kzalloc(sz, GFP_KERNEL); if (!adm_params) { pr_err("%s: adm params memory alloc failed", __func__); @@ -3668,6 +3678,94 @@ fail_cmd: return rc; } +int adm_send_set_multichannel_ec_primary_mic_ch(int port_id, int copp_idx, + int primary_mic_ch) +{ + struct adm_set_sec_primary_ch_params sec_primary_ch_params; + int rc = 0; + int sz, port_idx; + + pr_debug("%s port_id 0x%x, copp_idx 0x%x, primary_mic_ch %d\n", + __func__, port_id, copp_idx, primary_mic_ch); + port_id = afe_convert_virtual_to_portid(port_id); + port_idx = adm_validate_and_get_port_index(port_id); + if (port_idx < 0) { + pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id); + return -EINVAL; + } + + if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) { + pr_err("%s: Invalid copp_idx 0x%x\n", __func__, copp_idx); + return -EINVAL; + } + + sz = sizeof(struct adm_set_sec_primary_ch_params); + + sec_primary_ch_params.params.hdr.hdr_field = + APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); + sec_primary_ch_params.params.hdr.pkt_size = sz; + sec_primary_ch_params.params.hdr.src_svc = APR_SVC_ADM; + sec_primary_ch_params.params.hdr.src_domain = APR_DOMAIN_APPS; + sec_primary_ch_params.params.hdr.src_port = port_id; + sec_primary_ch_params.params.hdr.dest_svc = APR_SVC_ADM; + sec_primary_ch_params.params.hdr.dest_domain = APR_DOMAIN_ADSP; + sec_primary_ch_params.params.hdr.dest_port = + atomic_read(&this_adm.copp.id[port_idx][copp_idx]); + sec_primary_ch_params.params.hdr.token = port_idx << 16 | copp_idx; + sec_primary_ch_params.params.hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5; + sec_primary_ch_params.params.payload_addr_lsw = 0; + sec_primary_ch_params.params.payload_addr_msw = 0; + sec_primary_ch_params.params.mem_map_handle = 0; + sec_primary_ch_params.params.payload_size = + sizeof(struct adm_param_data_v5) + + sizeof(struct admx_sec_primary_mic_ch); + sec_primary_ch_params.data.module_id = + AUDPROC_MODULE_ID_VOICE_TX_SECNS; + sec_primary_ch_params.data.param_id = + AUDPROC_PARAM_IDX_SEC_PRIMARY_MIC_CH; + sec_primary_ch_params.data.param_size = + sizeof(struct admx_sec_primary_mic_ch); + sec_primary_ch_params.data.reserved = 0; + sec_primary_ch_params.sec_primary_mic_ch_data.version = 0; + sec_primary_ch_params.sec_primary_mic_ch_data.reserved = 0; + sec_primary_ch_params.sec_primary_mic_ch_data.sec_primary_mic_ch = + primary_mic_ch; + sec_primary_ch_params.sec_primary_mic_ch_data.reserved1 = 0; + + atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1); + rc = apr_send_pkt(this_adm.apr, (uint32_t *)&sec_primary_ch_params); + if (rc < 0) { + pr_err("%s: Set params failed port = %#x\n", + __func__, port_id); + rc = -EINVAL; + goto fail_cmd; + } + /* Wait for the callback */ + rc = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx], + atomic_read(&this_adm.copp.stat[port_idx][copp_idx]) >= 0, + msecs_to_jiffies(TIMEOUT_MS)); + if (!rc) { + pr_err("%s: Mic Set params timed out port = %#x\n", + __func__, port_id); + rc = -EINVAL; + goto fail_cmd; + } else if (atomic_read(&this_adm.copp.stat + [port_idx][copp_idx]) > 0) { + pr_err("%s: DSP returned error[%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&this_adm.copp.stat + [port_idx][copp_idx]))); + rc = adsp_err_get_lnx_err_code( + atomic_read(&this_adm.copp.stat + [port_idx][copp_idx])); + goto fail_cmd; + } + rc = 0; +fail_cmd: + return rc; +} + int adm_param_enable(int port_id, int copp_idx, int module_id, int enable) { struct audproc_enable_param_t adm_mod_enable; diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index 19105ffd9d4a..cfaa562fdaba 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * Author: Brian Swetland <swetland@google.com> * * This software is licensed under the terms of the GNU General Public @@ -1710,6 +1710,7 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) case ASM_STREAM_CMD_OPEN_PUSH_MODE_READ: case ASM_STREAM_CMD_OPEN_READWRITE_V2: case ASM_STREAM_CMD_OPEN_LOOPBACK_V2: + case ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK: case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2: case ASM_STREAM_CMD_SET_ENCDEC_PARAM: case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE: @@ -2877,6 +2878,7 @@ static int __q6asm_open_read_write(struct audio_client *ac, uint32_t rd_format, break; case FORMAT_DSD: open.dec_fmt_id = ASM_MEDIA_FMT_DSD; + break; case FORMAT_G711_ALAW_FS: open.dec_fmt_id = ASM_MEDIA_FMT_G711_ALAW_FS; break; @@ -2982,7 +2984,6 @@ int q6asm_open_read_write_v2(struct audio_client *ac, uint32_t rd_format, int q6asm_open_loopback_v2(struct audio_client *ac, uint16_t bits_per_sample) { int rc = 0x00; - struct asm_stream_cmd_open_loopback_v2 open; if (ac == NULL) { pr_err("%s: APR handle NULL\n", __func__); @@ -2994,29 +2995,67 @@ int q6asm_open_loopback_v2(struct audio_client *ac, uint16_t bits_per_sample) } pr_debug("%s: session[%d]\n", __func__, ac->session); - q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE); - atomic_set(&ac->cmd_state, -1); - open.hdr.opcode = ASM_STREAM_CMD_OPEN_LOOPBACK_V2; + if (ac->perf_mode == LOW_LATENCY_PCM_MODE) { + struct asm_stream_cmd_open_transcode_loopback_t open; - open.mode_flags = 0; - open.src_endpointype = 0; - open.sink_endpointype = 0; - /* source endpoint : matrix */ - open.postprocopo_id = q6asm_get_asm_topology_cal(); + q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE); + atomic_set(&ac->cmd_state, -1); + open.hdr.opcode = ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK; - ac->app_type = q6asm_get_asm_app_type_cal(); - ac->topology = open.postprocopo_id; - open.bits_per_sample = bits_per_sample; - open.reserved = 0; + open.mode_flags = 0; + open.src_endpoint_type = 0; + open.sink_endpoint_type = 0; + open.src_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2; + open.sink_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2; + /* source endpoint : matrix */ + open.audproc_topo_id = q6asm_get_asm_topology_cal(); - rc = apr_send_pkt(ac->apr, (uint32_t *) &open); - if (rc < 0) { - pr_err("%s: open failed op[0x%x]rc[%d]\n", __func__, - open.hdr.opcode, rc); - rc = -EINVAL; - goto fail_cmd; - } + ac->app_type = q6asm_get_asm_app_type_cal(); + if (ac->perf_mode == LOW_LATENCY_PCM_MODE) + open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION; + else + open.mode_flags |= ASM_LEGACY_STREAM_SESSION; + ac->topology = open.audproc_topo_id; + open.bits_per_sample = bits_per_sample; + open.reserved = 0; + pr_debug("%s: opening a transcode_loopback with mode_flags =[%d] session[%d]\n", + __func__, open.mode_flags, ac->session); + + rc = apr_send_pkt(ac->apr, (uint32_t *) &open); + if (rc < 0) { + pr_err("%s: open failed op[0x%x]rc[%d]\n", + __func__, open.hdr.opcode, rc); + rc = -EINVAL; + goto fail_cmd; + } + } else {/*if(ac->perf_mode == LEGACY_PCM_MODE)*/ + struct asm_stream_cmd_open_loopback_v2 open; + + q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE); + atomic_set(&ac->cmd_state, -1); + open.hdr.opcode = ASM_STREAM_CMD_OPEN_LOOPBACK_V2; + open.mode_flags = 0; + open.src_endpointype = 0; + open.sink_endpointype = 0; + /* source endpoint : matrix */ + open.postprocopo_id = q6asm_get_asm_topology_cal(); + + ac->app_type = q6asm_get_asm_app_type_cal(); + ac->topology = open.postprocopo_id; + open.bits_per_sample = bits_per_sample; + open.reserved = 0; + pr_debug("%s: opening a loopback_v2 with mode_flags =[%d] session[%d]\n", + __func__, open.mode_flags, ac->session); + + rc = apr_send_pkt(ac->apr, (uint32_t *) &open); + if (rc < 0) { + pr_err("%s: open failed op[0x%x]rc[%d]\n", + __func__, open.hdr.opcode, rc); + rc = -EINVAL; + goto fail_cmd; + } + } rc = wait_event_timeout(ac->cmd_wait, (atomic_read(&ac->cmd_state) >= 0), 5*HZ); if (!rc) { |