ASoC: soc-core: Enable to use extra format on each DAI
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Mon, 6 Jan 2025 05:49:45 +0000 (05:49 +0000)
committerMark Brown <broonie@kernel.org>
Mon, 13 Jan 2025 14:16:55 +0000 (14:16 +0000)
Current ASoC is using dai_link->dai_fmt to set DAI format for both
CPU/Codec. But because it is using same settings, and
SND_SOC_DAIFMT_CLOCK_PROVIDER is flipped for CPU, we can't set both
CPU/Codec as clock consumer, for example.

To solve this issue, this patch enable to use extra format for each
DAI which can keep compatibility with legacy system,

1. SND_SOC_DAIFMT_FORMAT_MASK
2. SND_SOC_DAIFMT_CLOCK
3. SND_SOC_DAIFMT_INV
4. SND_SOC_DAIFMT_CLOCK_PROVIDER

Legacy
dai_fmt  includes 1, 2, 3, 4

New idea
dai_fmt  includes 1, 2, 3
ext_fmt  includes 4

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Tested-by: Stephen Gordon <gordoste@iinet.net.au>
Link: https://patch.msgid.link/87r05go5ja.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
include/sound/soc.h
sound/soc/soc-core.c

index 1e09ff0842478dfa1f90332307c86de2c3cd9b66..fcdb5adfcd5eccd4d74ee6e52357543cfbc23e36 100644 (file)
@@ -681,6 +681,17 @@ struct snd_soc_dai_link_component {
        struct device_node *of_node;
        const char *dai_name;
        const struct of_phandle_args *dai_args;
+
+       /*
+        * Extra format = SND_SOC_DAIFMT_Bx_Fx
+        *
+        * [Note] it is Bx_Fx base, not CBx_CFx
+        *
+        * It will be used with dai_link->dai_fmt
+        * see
+        *      snd_soc_runtime_set_dai_fmt()
+        */
+       unsigned int ext_fmt;
 };
 
 /*
index 9d2c8b3939446d79dd4fa52ea33570c15a994022..3c6d8aef4130901c75a25c31337e641f6bb22f04 100644 (file)
@@ -1449,23 +1449,46 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
 {
        struct snd_soc_dai *cpu_dai;
        struct snd_soc_dai *codec_dai;
+       unsigned int ext_fmt;
        unsigned int i;
        int ret;
 
        if (!dai_fmt)
                return 0;
 
+       /*
+        * dai_fmt has 4 types
+        *      1. SND_SOC_DAIFMT_FORMAT_MASK
+        *      2. SND_SOC_DAIFMT_CLOCK
+        *      3. SND_SOC_DAIFMT_INV
+        *      4. SND_SOC_DAIFMT_CLOCK_PROVIDER
+        *
+        * 4. CLOCK_PROVIDER is set from Codec perspective in dai_fmt. So it will be flipped
+        * when this function calls set_fmt() for CPU (CBx_CFx -> Bx_Cx). see below.
+        * This mean, we can't set CPU/Codec both are clock consumer for example.
+        * New idea handles 4. in each dai->ext_fmt. It can keep compatibility.
+        *
+        * Legacy
+        *      dai_fmt  includes 1, 2, 3, 4
+        *
+        * New idea
+        *      dai_fmt  includes 1, 2, 3
+        *      ext_fmt  includes 4
+        */
        for_each_rtd_codec_dais(rtd, i, codec_dai) {
-               ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
+               ext_fmt = rtd->dai_link->codecs[i].ext_fmt;
+               ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt | ext_fmt);
                if (ret != 0 && ret != -ENOTSUPP)
                        return ret;
        }
 
        /* Flip the polarity for the "CPU" end of link */
+       /* Will effect only for 4. SND_SOC_DAIFMT_CLOCK_PROVIDER */
        dai_fmt = snd_soc_daifmt_clock_provider_flipped(dai_fmt);
 
        for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
-               ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
+               ext_fmt = rtd->dai_link->cpus[i].ext_fmt;
+               ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt | ext_fmt);
                if (ret != 0 && ret != -ENOTSUPP)
                        return ret;
        }