[alsa-devel] System with multiple arizona (wm5102) codecs

Caleb Crome caleb at crome.org
Tue Sep 15 17:26:36 CEST 2015


>
> Like Charles said earlier the Bells machine in mainline has multiple
> CODECs hooked up.  Speyside too.  To hook up multiple CODECs to a single
> DAI link see 88bd870f02dff5c94 (ASoC: core: Add initial support for DAI
> multicodec), sadly I don't think Benoit ever got round to submitting a
> machine.

Thanks Mark.

I've been staring at that diff for a a day or two, and I still can't
quite figure out how to use it.

I think I'm getting close:  all codecs are registered, the DAPM stuff
seems to be connected (all with prefixed names), but the card won't
open more than a 2 channel interface.

For example, when I do aplay -l, I get this:
**** List of PLAYBACK Hardware Devices ****
card 0: PUPPYAUDIO [PUPPY-AUDIO], device 0: AIC3X tlv320aic3x-hifi-0 []
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: PUPPYAUDIO [PUPPY-AUDIO], device 1: AIC3X tlv320aic3x-hifi-1 []
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: PUPPYAUDIO [PUPPY-AUDIO], device 2: AIC3X tlv320aic3x-hifi-2 []
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: PUPPYAUDIO [PUPPY-AUDIO], device 3: AIC3X tlv320aic3x-hifi-3 []
  Subdevices: 1/1
  Subdevice #0: subdevice #0

Each device is a 2 channel codec, so I thought I should get 8
channels. but when I try to run jackd with 8 channels, I get the
following:
# jackd  -d alsa -D -i 8 -o 8 -S -r16000
...
ALSA: cannot set channel count to 8 for capture
ALSA: cannot configure capture channel
...


So, here are the relevent bits of my patch.  Any chance you could
point out the error in my ways?

Basically, what I did was add a snd_soc_dai_link and a
snd_soc_codec_conf for each codec, and set num_links and num_configs
to the number of codecs.

Thanks

-Caleb

diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index 731fb0d..d2e7049 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -23,10 +23,11 @@

 #include <asm/dma.h>
 #include <asm/mach-types.h>
-
 struct snd_soc_card_drvdata_davinci {
     struct clk *mclk;
     unsigned sysclk;
+        int controls_added_already;
 };

@@ -118,11 +122,18 @@ static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd)
 {
     struct snd_soc_card *card = rtd->card;
     struct device_node *np = card->dev->of_node;
+
+    struct snd_soc_card_drvdata_davinci *drvdata =
+        snd_soc_card_get_drvdata(card);
     int ret;

     /* Add davinci-evm specific widgets */
-    snd_soc_dapm_new_controls(&card->dapm, aic3x_dapm_widgets,
-                  ARRAY_SIZE(aic3x_dapm_widgets));
+    if (!drvdata->controls_added_already) {
+        snd_soc_dapm_new_controls(&card->dapm, aic3x_dapm_widgets,
+                      ARRAY_SIZE(aic3x_dapm_widgets));
+        drvdata->controls_added_already = 1;
+    }

     if (np) {
         ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing");
@@ -330,14 +342,71 @@ static struct snd_soc_card da850_snd_soc_card = {
  * The struct is used as place holder. It will be completely
  * filled with data from dt node.
  */
-static struct snd_soc_dai_link evm_dai_tlv320aic3x = {
-    .name        = "TLV320AIC3X",
+static struct snd_soc_dai_link evm_dai_tlv320aic3x[] = {
+    {
+    .name        = "TLV320AIC3X a",
     .stream_name    = "AIC3X",
     .codec_dai_name    = "tlv320aic3x-hifi",
     .ops            = &evm_ops,
     .init           = evm_aic3x_init,
-    .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
-           SND_SOC_DAIFMT_IB_NF,
+    .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
SND_SOC_DAIFMT_IB_NF,
+    },
+    {
+    .name        = "TLV320AIC3X b",
+    .stream_name    = "AIC3X",
+    .codec_dai_name    = "tlv320aic3x-hifi",
+    .ops            = &evm_ops,
+    .init           = evm_aic3x_init,
+    .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
SND_SOC_DAIFMT_IB_NF,
+    },
+    {
+    .name        = "TLV320AIC3X c",
+    .stream_name    = "AIC3X",
+    .codec_dai_name    = "tlv320aic3x-hifi",
+    .ops            = &evm_ops,
+    .init           = evm_aic3x_init,
+    .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
SND_SOC_DAIFMT_IB_NF,
+    },
+    {
+    .name        = "TLV320AIC3X d",
+    .stream_name    = "AIC3X",
+    .codec_dai_name    = "tlv320aic3x-hifi",
+    .ops            = &evm_ops,
+    .init           = evm_aic3x_init,
+    .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
SND_SOC_DAIFMT_IB_NF,
+    },
+    {
+    .name        = "TLV320AIC3X e",
+    .stream_name    = "AIC3X",
+    .codec_dai_name    = "tlv320aic3x-hifi",
+    .ops            = &evm_ops,
+    .init           = evm_aic3x_init,
+    .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
SND_SOC_DAIFMT_IB_NF,
+    },
+    {
+    .name        = "TLV320AIC3X f",
+    .stream_name    = "AIC3X",
+    .codec_dai_name    = "tlv320aic3x-hifi",
+    .ops            = &evm_ops,
+    .init           = evm_aic3x_init,
+    .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
SND_SOC_DAIFMT_IB_NF,
+    },
+    {
+    .name        = "TLV320AIC3X g",
+    .stream_name    = "AIC3X",
+    .codec_dai_name    = "tlv320aic3x-hifi",
+    .ops            = &evm_ops,
+    .init           = evm_aic3x_init,
+    .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
SND_SOC_DAIFMT_IB_NF,
+    },
+    {
+    .name        = "TLV320AIC3X h",
+    .stream_name    = "AIC3X",
+    .codec_dai_name    = "tlv320aic3x-hifi",
+    .ops            = &evm_ops,
+    .init           = evm_aic3x_init,
+    .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
SND_SOC_DAIFMT_IB_NF,
+    },
 };

 static const struct of_device_id davinci_evm_dt_ids[] = {
@@ -355,6 +424,8 @@ static struct snd_soc_card evm_soc_card = {
     .num_links = 1,
 };

+static struct snd_soc_codec_conf evm_codec_confs[16];
+
 static int davinci_evm_probe(struct platform_device *pdev)
 {
     struct device_node *np = pdev->dev.of_node;
@@ -364,18 +435,36 @@ static int davinci_evm_probe(struct platform_device *pdev)
     struct snd_soc_card_drvdata_davinci *drvdata = NULL;
     struct clk *mclk;
     int ret = 0;
+    int i;

     evm_soc_card.dai_link = dai;
-
-    dai->codec_of_node = of_parse_phandle(np, "ti,audio-codec", 0);
-    if (!dai->codec_of_node)
+
+    evm_soc_card.codec_conf = evm_codec_confs;
+
+    for (i = 0;
+         (of_parse_phandle(np, "ti,audio-codec", i) != NULL) &&
+         (i < ARRAY_SIZE(evm_dai_tlv320aic3x)-1);
+         i++) {
+        char *name_prefix = kzalloc(4, GFP_KERNEL);
+
+        dai[i].codec_of_node = of_parse_phandle(np, "ti,audio-codec", i);
+
+        if (!dai[i].codec_of_node)
         return -EINVAL;

-    dai->cpu_of_node = of_parse_phandle(np, "ti,mcasp-controller", 0);
-    if (!dai->cpu_of_node)
+        evm_codec_confs[i].of_node = dai[i].codec_of_node;
+        snprintf(name_prefix, 4, "%c", 'a'+i);
+        evm_codec_confs[i].name_prefix = name_prefix;
+
+        dai[i].cpu_of_node = of_parse_phandle(np, "ti,mcasp-controller", 0);
+        if (!dai[i].cpu_of_node)
         return -EINVAL;

-    dai->platform_of_node = dai->cpu_of_node;
+        dai[i].platform_of_node = dai[i].cpu_of_node;
+    }
+    evm_soc_card.num_configs=i;
+    evm_soc_card.num_links  =i;
+

     evm_soc_card.dev = &pdev->dev;
     ret = snd_soc_of_parse_card_name(&evm_soc_card, "ti,model");
diff --git a/arch/arm/boot/dts/am335x-boneblack.dts
b/arch/arm/boot/dts/am335x-boneblack.dts
index 6335072..19af41f 100644
--- a/arch/arm/boot/dts/am335x-boneblack.dts
+++ b/arch/arm/boot/dts/am335x-boneblack.dts
+&i2c1 {
+    clock-frequency = <100000>;
+    status = "okay";
+    pinctrl-names = "default";
+    pinctrl-0 = <&i2c1_pins_default>;
+    status="okay";
+
+    tlv320aic3x_a: tlv320aic3x at 18 {
+        compatible = "ti,tlv320aic3x";
+        reg = <0x18>;
+        tdm-offset = <0>;
+        status = "okay";
+    };
+
+    tlv320aic3x_b: tlv320aic3x at 19 {
+        compatible = "ti,tlv320aic3x";
+        reg = <0x19>;
+        tdm-offset = <32>;
+        status = "okay";
+    };
+
+    tlv320aic3x_c: tlv320aic3x at 1a {
+        compatible = "ti,tlv320aic3x";
+        reg = <0x1a>;
+        tdm-offset = <64>;
+        status = "okay";
+    };
+
+    tlv320aic3x_d: tlv320aic3x at 1b {
+        compatible = "ti,tlv320aic3x";
+        reg = <0x1b>;
+        tdm-offset = <96>;
+        status = "okay";
+    };
+
+};
+
+&mcasp0 {
+    pinctrl-names = "default";
+    pinctrl-0 = <&mcasp_0_pins_default>;
+    status = "okay";
+
+    op-mode = <0>;          /* MCASP_IIS_MODE */
+    tdm-slots = <16>;
+    num-serializer = <16>;
+    serial-dir = <  /* 0: INACTIVE, 1: TX, 2: RX */
+        0 0 1 2
+        0 0 0 0
+        0 0 0 0
+        0 0 0 0
+    >;
+    tx-num-evt = <1>;
+    rx-num-evt = <1>;
 };

+
 / {
+    sound {
+        compatible = "ti,da830-evm-audio";
+        ti,model = "PUPPY-AUDIO";
+        ti,audio-codec = <
+                   &tlv320aic3x_a
+                   &tlv320aic3x_b
+                   &tlv320aic3x_c
+                   &tlv320aic3x_d
+                   >;
+        ti,mcasp-controller = <&mcasp0>;
+        ti,codec-clock-rate = <12288000>;
+        ti,audio-routing =
+            "Headphone Jack",       "a HPLOUT",
+            "Headphone Jack",       "a HPROUT",
+            "a LINE1L",               "Line In",
+            "a LINE1R",               "Line In";
+        status="okay";
+    };
 };

 &rtc {


More information about the Alsa-devel mailing list