From c55676ec292e0ff83261eb61efaf99a91079a3b8 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Thu, 2 Dec 2021 15:55:01 +0100 Subject: [PATCH 1/5] ASoC: dt-bindings: qcom: sm8250: Drop redundant MultiMedia routes The MultiMedia audio routes can be deduced from other parts of the device tree (e.g. the definitions of the MultiMedia DAIs) and therefore specifying them again in "audio-routing" is redundant and prone to mistakes. This is no longer necessary since commit 6fd8d2d275f7 ("ASoC: qcom: qdsp6: Move frontend AIFs to q6asm-dai"). Let's drop them from the example in the DT schema as well to avoid confusion. Cc: Srinivas Kandagatla Signed-off-by: Stephan Gerhold Acked-by: Rob Herring Link: https://lore.kernel.org/r/20211202145505.58852-2-stephan@gerhold.net Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/qcom,sm8250.yaml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index 7d57eb91657a..a0f1d7340eb5 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -86,10 +86,7 @@ examples: audio-routing = "SpkrLeft IN", "WSA_SPK1 OUT", "SpkrRight IN", "WSA_SPK2 OUT", "VA DMIC0", "vdd-micb", - "VA DMIC1", "vdd-micb", - "MM_DL1", "MultiMedia1 Playback", - "MM_DL2", "MultiMedia2 Playback", - "MultiMedia3 Capture", "MM_UL3"; + "VA DMIC1", "vdd-micb"; mm1-dai-link { link-name = "MultiMedia0"; From 1875ae76f82c5c9acd7b7f44bd9226fbcbe858b7 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Thu, 2 Dec 2021 15:55:02 +0100 Subject: [PATCH 2/5] ASoC: dt-bindings: qcom: sm8250: Document "aux-devs" The sm8250 audio driver uses the common Qualcomm device tree parser and therefore already supports the "aux-devs" property that allows adding additional auxiliary devices to the sound card (e.g. analog speaker amplifiers that can be connected using "audio-routing"). Document the property in the DT schema for sm8250 as well. The description is taken from simple-card.yaml which has a very similar property. Cc: Srinivas Kandagatla Signed-off-by: Stephan Gerhold Acked-by: Rob Herring Link: https://lore.kernel.org/r/20211202145505.58852-3-stephan@gerhold.net Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/qcom,sm8250.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index a0f1d7340eb5..3123382297b8 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -27,6 +27,12 @@ properties: being the connection's source. Valid names could be power supplies, MicBias of codec and the jacks on the board. + aux-devs: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: | + List of phandles pointing to auxiliary devices, such + as amplifiers, to be added to the sound card. + model: $ref: /schemas/types.yaml#/definitions/string description: User visible long sound card name From b7875d88bf70100d2fe0dc08072018f994ccd6c4 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Thu, 2 Dec 2021 15:55:03 +0100 Subject: [PATCH 3/5] ASoC: dt-bindings: qcom: apq8016-sbc: Move to qcom,sm8250 DT schema All the Qualcomm sound card drivers use the same common device tree parsing code, so the allowed device tree nodes are almost the same for all of them. Convert the qcom,apq8016-sbc-sndcard documentation to a DT schema by adding it to the existing qcom,sm8250 schema. The only speciality of qcom,apq8016-sbc-sndcard is that it has memory resources for setting up an I/O mux. This can be handled using a conditional if statement that only requires it for the apq8016-sbc compatible. Cc: Srinivas Kandagatla Signed-off-by: Stephan Gerhold Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20211202145505.58852-4-stephan@gerhold.net Signed-off-by: Mark Brown --- .../bindings/sound/qcom,apq8016-sbc.txt | 96 ------------------- .../bindings/sound/qcom,sm8250.yaml | 83 +++++++++++++++- 2 files changed, 81 insertions(+), 98 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt diff --git a/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt b/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt deleted file mode 100644 index 23998262a0a7..000000000000 --- a/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt +++ /dev/null @@ -1,96 +0,0 @@ -* Qualcomm Technologies APQ8016 SBC ASoC machine driver - -This node models the Qualcomm Technologies APQ8016 SBC ASoC machine driver - -Required properties: - -- compatible : "qcom,apq8016-sbc-sndcard" - -- pinctrl-N : One property must exist for each entry in - pinctrl-names. See ../pinctrl/pinctrl-bindings.txt - for details of the property values. -- pinctrl-names : Must contain a "default" entry. -- reg : Must contain an address for each entry in reg-names. -- reg-names : A list which must include the following entries: - * "mic-iomux" - * "spkr-iomux" -- qcom,model : Name of the sound card. - -- qcom,audio-routing : A list of the connections between audio components. - Each entry is a pair of strings, the first being the - connection's sink, the second being the connection's - source. Valid names could be power supplies, MicBias - of msm8x16_wcd codec and the jacks on the board: - - Power supplies: - * MIC BIAS External1 - * MIC BIAS External2 - * MIC BIAS Internal1 - * MIC BIAS Internal2 - - Board connectors: - * Headset Mic - * Secondary Mic - * DMIC - * Ext Spk - -Optional properties: - -- aux-devs : A list of phandles for auxiliary devices (e.g. analog - amplifiers) that do not appear directly within the DAI - links. Should be connected to another audio component - using "qcom,audio-routing". - -Dai-link subnode properties and subnodes: - -Required dai-link subnodes: - -- cpu : CPU sub-node -- codec : CODEC sub-node - -Required CPU/CODEC subnodes properties: - --link-name : Name of the dai link. --sound-dai : phandle/s and port of CPU/CODEC - -Example: - -sound: sound { - compatible = "qcom,apq8016-sbc-sndcard"; - reg = <0x07702000 0x4>, <0x07702004 0x4>; - reg-names = "mic-iomux", "spkr-iomux"; - qcom,model = "DB410c"; - - qcom,audio-routing = - "MIC BIAS External1", "Handset Mic", - "MIC BIAS Internal2", "Headset Mic", - "MIC BIAS External1", "Secondary Mic", - "AMIC1", "MIC BIAS External1", - "AMIC2", "MIC BIAS Internal2", - "AMIC3", "MIC BIAS External1", - "DMIC1", "MIC BIAS Internal1", - "MIC BIAS Internal1", "Digital Mic1", - "DMIC2", "MIC BIAS Internal1", - "MIC BIAS Internal1", "Digital Mic2"; - - /* I2S - Internal codec */ - internal-dai-link@0 { - cpu { /* PRIMARY */ - sound-dai = <&lpass MI2S_PRIMARY>; - }; - codec { - sound-dai = <&lpass_codec 0>, <&wcd_codec 0>; - }; - }; - - /* External Primary or External Secondary -ADV7533 HDMI */ - external-dai-link@0 { - link-name = "ADV7533"; - cpu { /* QUAT */ - sound-dai = <&lpass MI2S_QUATERNARY>; - }; - codec { - sound-dai = <&adv_bridge 0>; - }; - }; -}; diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index 3123382297b8..97f13a0a71a9 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -4,18 +4,19 @@ $id: http://devicetree.org/schemas/sound/qcom,sm8250.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Qualcomm Technologies Inc. SM8250 ASoC sound card driver +title: Qualcomm Technologies Inc. ASoC sound card drivers maintainers: - Srinivas Kandagatla description: - This bindings describes SC8250 SoC based sound cards + This bindings describes Qualcomm SoC based sound cards which uses LPASS internal codec for audio. properties: compatible: enum: + - qcom,apq8016-sbc-sndcard - qcom,sm8250-sndcard - qcom,qrb5165-rb5-sndcard @@ -37,6 +38,10 @@ properties: $ref: /schemas/types.yaml#/definitions/string description: User visible long sound card name + # Only valid for some compatibles (see allOf if below) + reg: true + reg-names: true + patternProperties: ".*-dai-link$": description: @@ -79,6 +84,33 @@ required: - compatible - model +allOf: + - if: + properties: + compatible: + contains: + enum: + - qcom,apq8016-sbc-sndcard + then: + properties: + reg: + items: + - description: Microphone I/O mux register address + - description: Speaker I/O mux register address + reg-names: + items: + - const: mic-iomux + - const: spkr-iomux + required: + - compatible + - model + - reg + - reg-names + else: + properties: + reg: false + reg-names: false + additionalProperties: false examples: @@ -160,3 +192,50 @@ examples: }; }; }; + + - | + #include + sound@7702000 { + compatible = "qcom,apq8016-sbc-sndcard"; + reg = <0x07702000 0x4>, <0x07702004 0x4>; + reg-names = "mic-iomux", "spkr-iomux"; + + model = "DB410c"; + audio-routing = + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS External1"; + + pinctrl-0 = <&cdc_pdm_lines_act &ext_sec_tlmm_lines_act &ext_mclk_tlmm_lines_act>; + pinctrl-1 = <&cdc_pdm_lines_sus &ext_sec_tlmm_lines_sus &ext_mclk_tlmm_lines_sus>; + pinctrl-names = "default", "sleep"; + + quaternary-dai-link { + link-name = "ADV7533"; + cpu { + sound-dai = <&lpass MI2S_QUATERNARY>; + }; + codec { + sound-dai = <&adv_bridge 0>; + }; + }; + + primary-dai-link { + link-name = "WCD"; + cpu { + sound-dai = <&lpass MI2S_PRIMARY>; + }; + codec { + sound-dai = <&lpass_codec 0>, <&wcd_codec 0>; + }; + }; + + tertiary-dai-link { + link-name = "WCD-Capture"; + cpu { + sound-dai = <&lpass MI2S_TERTIARY>; + }; + codec { + sound-dai = <&lpass_codec 1>, <&wcd_codec 1>; + }; + }; + }; From 38192dc36f1fe1615b7a12cc78b9354d6b4ba8b7 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Thu, 2 Dec 2021 15:55:04 +0100 Subject: [PATCH 4/5] ASoC: dt-bindings: qcom: Document qcom,msm8916-qdsp6-sndcard compatible There are two possible audio setups on MSM8916/APQ8016: Normally the audio is routed through the audio/modem DSP (covered by the qdsp6 driver). During upstreaming for the DragonBoard 410c it was decided to bypass it and instead talk directly to the audio controller using the "lpass" driver. Bypassing the DSP gives more control about the audio configuration but limits the functionality: For example, routing audio through the audio/modem DSP is strictly required for voice call audio. Also, without the special changes in the DB410c firmware other MSM8916 devices can only use the bypass as long as the modem DSP is not started. Otherwise, the firmware will assume control of the LPASS hardware block and audio is no longer functional. Add support for using the DSP audio setup instead using a new "qcom,msm8916-qdsp6-sndcard" compatible. It is basically a mixture of the apq8016-sbc-sndcard and the newer sm8250-sndcard, which uses indirect QDSP6 DAI links instead of the direct LPASS DAI links. Cc: Srinivas Kandagatla Signed-off-by: Stephan Gerhold Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20211202145505.58852-5-stephan@gerhold.net Signed-off-by: Mark Brown --- .../bindings/sound/qcom,sm8250.yaml | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index 97f13a0a71a9..e50964c54bb9 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -17,6 +17,7 @@ properties: compatible: enum: - qcom,apq8016-sbc-sndcard + - qcom,msm8916-qdsp6-sndcard - qcom,sm8250-sndcard - qcom,qrb5165-rb5-sndcard @@ -91,6 +92,7 @@ allOf: contains: enum: - qcom,apq8016-sbc-sndcard + - qcom,msm8916-qdsp6-sndcard then: properties: reg: @@ -239,3 +241,43 @@ examples: }; }; }; + + - | + #include + #include + sound@7702000 { + compatible = "qcom,msm8916-qdsp6-sndcard"; + reg = <0x07702000 0x4>, <0x07702004 0x4>; + reg-names = "mic-iomux", "spkr-iomux"; + + model = "msm8916"; + audio-routing = + "AMIC1", "MIC BIAS Internal1", + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS Internal3"; + aux-devs = <&speaker_amp>; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&cdc_pdm_lines_act>; + pinctrl-1 = <&cdc_pdm_lines_sus>; + + mm1-dai-link { + link-name = "MultiMedia1"; + cpu { + sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA1>; + }; + }; + + primary-dai-link { + link-name = "Primary MI2S"; + cpu { + sound-dai = <&q6afedai PRIMARY_MI2S_RX>; + }; + platform { + sound-dai = <&q6routing>; + }; + codec { + sound-dai = <&lpass_codec 0>, <&wcd_codec 0>; + }; + }; + }; From a78a42fb48b8f261ab122c929f78c272ffc26d1b Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Thu, 2 Dec 2021 15:55:05 +0100 Subject: [PATCH 5/5] ASoC: qcom: apq8016_sbc: Allow routing audio through QDSP6 The apq8016-sbc-sndcard is designed to be used with the LPASS drivers (bypassing the combined audio/modem DSP in MSM8916/APQ8016). Make it possible to use QDSP6 audio instead for the msm8916-qdsp6-sndcard. This only requires adding some additional hooks that set up the DPCM backends correctly. Similar code is already used in drivers for newer SoCs such as apq8096.c, sdm845.c and sm8250.c. A slightly different initialization sequence is used for the apq8016-sbc and msm8916-qdsp6 sound card by defining the apq8016_sbc_add_ops() function as device match data. Cc: Srinivas Kandagatla Signed-off-by: Stephan Gerhold Reviewed-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20211202145505.58852-6-stephan@gerhold.net Signed-off-by: Mark Brown --- sound/soc/qcom/apq8016_sbc.c | 134 +++++++++++++++++++++++++++++++++-- 1 file changed, 129 insertions(+), 5 deletions(-) diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c index ba2a98268ee4..f9d69375320e 100644 --- a/sound/soc/qcom/apq8016_sbc.c +++ b/sound/soc/qcom/apq8016_sbc.c @@ -17,6 +17,9 @@ #include #include #include "common.h" +#include "qdsp6/q6afe.h" + +#define MI2S_COUNT (MI2S_QUATERNARY + 1) struct apq8016_sbc_data { struct snd_soc_card card; @@ -24,6 +27,7 @@ struct apq8016_sbc_data { void __iomem *spkr_iomux; struct snd_soc_jack jack; bool jack_setup; + int mi2s_clk_count[MI2S_COUNT]; }; #define MIC_CTRL_TER_WS_SLAVE_SEL BIT(21) @@ -38,10 +42,10 @@ struct apq8016_sbc_data { #define SPKR_CTL_TLMM_WS_EN_SEL_MASK GENMASK(19, 18) #define SPKR_CTL_TLMM_WS_EN_SEL_SEC BIT(18) #define DEFAULT_MCLK_RATE 9600000 +#define MI2S_BCLK_RATE 1536000 -static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd) +static int apq8016_dai_init(struct snd_soc_pcm_runtime *rtd, int mi2s) { - struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); struct snd_soc_dai *codec_dai; struct snd_soc_component *component; struct snd_soc_card *card = rtd->card; @@ -49,7 +53,7 @@ static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd) int i, rval; u32 value; - switch (cpu_dai->id) { + switch (mi2s) { case MI2S_PRIMARY: writel(readl(pdata->spkr_iomux) | SPKR_CTL_PRI_WS_SLAVE_SEL_11, pdata->spkr_iomux); @@ -128,6 +132,13 @@ static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd) return 0; } +static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + + return apq8016_dai_init(rtd, cpu_dai->id); +} + static void apq8016_sbc_add_ops(struct snd_soc_card *card) { struct snd_soc_dai_link *link; @@ -137,6 +148,113 @@ static void apq8016_sbc_add_ops(struct snd_soc_card *card) link->init = apq8016_sbc_dai_init; } +static int qdsp6_dai_get_lpass_id(struct snd_soc_dai *cpu_dai) +{ + switch (cpu_dai->id) { + case PRIMARY_MI2S_RX: + case PRIMARY_MI2S_TX: + return MI2S_PRIMARY; + case SECONDARY_MI2S_RX: + case SECONDARY_MI2S_TX: + return MI2S_SECONDARY; + case TERTIARY_MI2S_RX: + case TERTIARY_MI2S_TX: + return MI2S_TERTIARY; + case QUATERNARY_MI2S_RX: + case QUATERNARY_MI2S_TX: + return MI2S_QUATERNARY; + default: + return -EINVAL; + } +} + +static int msm8916_qdsp6_dai_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + + snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS); + return apq8016_dai_init(rtd, qdsp6_dai_get_lpass_id(cpu_dai)); +} + +static int msm8916_qdsp6_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct apq8016_sbc_data *data = snd_soc_card_get_drvdata(card); + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + int mi2s, ret; + + mi2s = qdsp6_dai_get_lpass_id(cpu_dai); + if (mi2s < 0) + return mi2s; + + if (++data->mi2s_clk_count[mi2s] > 1) + return 0; + + ret = snd_soc_dai_set_sysclk(cpu_dai, LPAIF_BIT_CLK, MI2S_BCLK_RATE, 0); + if (ret) + dev_err(card->dev, "Failed to enable LPAIF bit clk: %d\n", ret); + return ret; +} + +static void msm8916_qdsp6_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct apq8016_sbc_data *data = snd_soc_card_get_drvdata(card); + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + int mi2s, ret; + + mi2s = qdsp6_dai_get_lpass_id(cpu_dai); + if (mi2s < 0) + return; + + if (--data->mi2s_clk_count[mi2s] > 0) + return; + + ret = snd_soc_dai_set_sysclk(cpu_dai, LPAIF_BIT_CLK, 0, 0); + if (ret) + dev_err(card->dev, "Failed to disable LPAIF bit clk: %d\n", ret); +} + +static const struct snd_soc_ops msm8916_qdsp6_be_ops = { + .startup = msm8916_qdsp6_startup, + .shutdown = msm8916_qdsp6_shutdown, +}; + +static int msm8916_qdsp6_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); + + return 0; +} + +static void msm8916_qdsp6_add_ops(struct snd_soc_card *card) +{ + struct snd_soc_dai_link *link; + int i; + + /* Make it obvious to userspace that QDSP6 is used */ + card->components = "qdsp6"; + + for_each_card_prelinks(card, i, link) { + if (link->no_pcm) { + link->init = msm8916_qdsp6_dai_init; + link->ops = &msm8916_qdsp6_be_ops; + link->be_hw_params_fixup = msm8916_qdsp6_be_hw_params_fixup; + } + } +} + static const struct snd_soc_dapm_widget apq8016_sbc_dapm_widgets[] = { SND_SOC_DAPM_MIC("Handset Mic", NULL), @@ -148,11 +266,16 @@ static const struct snd_soc_dapm_widget apq8016_sbc_dapm_widgets[] = { static int apq8016_sbc_platform_probe(struct platform_device *pdev) { + void (*add_ops)(struct snd_soc_card *card); struct device *dev = &pdev->dev; struct snd_soc_card *card; struct apq8016_sbc_data *data; int ret; + add_ops = device_get_match_data(&pdev->dev); + if (!add_ops) + return -EINVAL; + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -177,12 +300,13 @@ static int apq8016_sbc_platform_probe(struct platform_device *pdev) snd_soc_card_set_drvdata(card, data); - apq8016_sbc_add_ops(card); + add_ops(card); return devm_snd_soc_register_card(&pdev->dev, card); } static const struct of_device_id apq8016_sbc_device_id[] __maybe_unused = { - { .compatible = "qcom,apq8016-sbc-sndcard" }, + { .compatible = "qcom,apq8016-sbc-sndcard", .data = apq8016_sbc_add_ops }, + { .compatible = "qcom,msm8916-qdsp6-sndcard", .data = msm8916_qdsp6_add_ops }, {}, }; MODULE_DEVICE_TABLE(of, apq8016_sbc_device_id);