Re: [alsa-devel] System with multiple arizona (wm5102) codecs
From: Caleb Crome
Date: Tue Sep 15 2015 - 11:27:03 EST
>
> 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@18 {
+ compatible = "ti,tlv320aic3x";
+ reg = <0x18>;
+ tdm-offset = <0>;
+ status = "okay";
+ };
+
+ tlv320aic3x_b: tlv320aic3x@19 {
+ compatible = "ti,tlv320aic3x";
+ reg = <0x19>;
+ tdm-offset = <32>;
+ status = "okay";
+ };
+
+ tlv320aic3x_c: tlv320aic3x@1a {
+ compatible = "ti,tlv320aic3x";
+ reg = <0x1a>;
+ tdm-offset = <64>;
+ status = "okay";
+ };
+
+ tlv320aic3x_d: tlv320aic3x@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 {
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/