summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/sound/qcom-audio-dev.txt25
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-gpu.dtsi3
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-v2-qrd-skuk-hdk.dts92
-rw-r--r--arch/arm/boot/dts/qcom/sdm630.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-camera-sensor-qrd.dtsi100
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-gpu.dtsi80
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-qrd.dts37
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-qrd.dtsi87
-rw-r--r--arch/arm/boot/dts/qcom/sdm660.dtsi149
-rw-r--r--arch/arm/configs/msmcortex_defconfig6
-rw-r--r--drivers/clk/msm/clock-mmss-8998.c1
-rw-r--r--drivers/clk/qcom/gcc-sdm660.c2
-rw-r--r--drivers/clk/qcom/vdd-level-660.h10
-rw-r--r--drivers/crypto/msm/qcedev.c4
-rw-r--r--drivers/gpu/msm/kgsl_pwrctrl.c107
-rw-r--r--drivers/mfd/qcom-i2c-pmic.c21
-rw-r--r--drivers/mfd/wcd9xxx-core.c33
-rw-r--r--drivers/mfd/wcd9xxx-slimslave.c10
-rw-r--r--drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c16
-rw-r--r--drivers/mmc/core/Kconfig11
-rw-r--r--drivers/mmc/core/Makefile1
-rw-r--r--drivers/mmc/core/debugfs.c25
-rw-r--r--drivers/mmc/core/host.c3
-rw-r--r--drivers/mmc/core/mmc.c5
-rw-r--r--drivers/mmc/core/ring_buffer.c123
-rw-r--r--drivers/mmc/core/sd.c4
-rw-r--r--drivers/mmc/core/sdio.c5
-rw-r--r--drivers/mmc/host/cmdq_hci.c33
-rw-r--r--drivers/mmc/host/sdhci-msm-ice.c11
-rw-r--r--drivers/mmc/host/sdhci-msm.c7
-rw-r--r--drivers/mmc/host/sdhci.c35
-rw-r--r--drivers/platform/msm/gsi/gsi.c11
-rw-r--r--drivers/soc/qcom/msm_smem.c18
-rw-r--r--drivers/spi/spi_qsd.c195
-rw-r--r--drivers/spi/spi_qsd.h14
-rw-r--r--drivers/usb/gadget/function/f_mass_storage.c25
-rw-r--r--drivers/usb/gadget/function/f_qc_rndis.c1
-rw-r--r--drivers/usb/gadget/function/u_ctrl_qti.c2
-rw-r--r--drivers/usb/gadget/function/u_data_ipa.c8
-rw-r--r--fs/fuse/file.c37
-rw-r--r--include/linux/mmc/host.h2
-rw-r--r--include/linux/mmc/ring_buffer.h55
-rw-r--r--include/sound/apr_audio-v2.h154
-rw-r--r--include/sound/q6adm-v2.h3
-rw-r--r--kernel/sched/core.c2
-rw-r--r--kernel/sched/hmp.c18
-rw-r--r--kernel/sched/sched.h2
-rw-r--r--sound/soc/codecs/wcd-mbhc-v2.c324
-rw-r--r--sound/soc/codecs/wcd-mbhc-v2.h17
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x-mbhc.c8
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x.c50
-rw-r--r--sound/soc/codecs/wcd9xxx-common-v2.c162
-rw-r--r--sound/soc/codecs/wcd9xxx-resmgr-v2.c10
-rw-r--r--sound/soc/codecs/wcd_cpe_core.c12
-rw-r--r--sound/soc/msm/msm8998.c24
-rw-r--r--sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c5
-rw-r--r--sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c10
-rw-r--r--sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c7
-rw-r--r--sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c6
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c31
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c82
-rw-r--r--sound/soc/msm/qdsp6v2/msm-qti-pp-config.c46
-rw-r--r--sound/soc/msm/qdsp6v2/q6adm.c104
-rw-r--r--sound/soc/msm/qdsp6v2/q6asm.c81
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, &notify, true);
if (ctx->props.exclusive &&
atomic_read(&ctx->chan->poll_mode)) {
cntr = 0;
break;
}
+ gsi_process_evt_re(ctx, &notify, 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) {