This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Compiler/DRA76P: DRA76: Multichannel DAI link on tlv320aic3106 sound cards

Part Number: DRA76P
Other Parts Discussed in Thread: TLV320AIC3106

Tool/software: TI C/C++ Compiler

Hi,

I am working on multi channel audio on customer board  based dra76p.

I'm able to back port kernel patches from 3.14 to 4.4 version and now each stereo CODEC instance receives two channels of the stereo stream.

                            +--o tlv320aic3106 (Instance A)
                     tdm |
McASP3  o-------- |--o tlv320aic3106 (Instance B)
                            |
                           +--o tlv320aic3106 (Instance C)

But I need that each stereo CODEC  two channels of the 6ch stream.

ch1-2 codecA

ch2-3 codecB

ch4-5 codecC

here my dts config :

sound0:multicodec_sound {
compatible = "ti,dra7xx-jamr3-multicodec-evm";
ti,model = "ACTIA SOUND CARD";
ti,always-on;
clocks = <&atl_clkin2_ck>;
clock-names = "ti,codec-clock";

ti,audio-routing =
"J3A LINE1L", "JAMR3 Stereo Aux In",
"J3A LINE1R", "JAMR3 Stereo Aux In",
"J3B LINE1L", "JAMR3 Mono Mic 1",
"J3B LINE1R", "JAMR3 Mono Mic 2",
"JAMR3 Line Out 1", "J3A LLOUT",
"JAMR3 Line Out 1", "J3A RLOUT",
"JAMR3 Line Out 2", "J3B LLOUT",
"JAMR3 Line Out 2", "J3B RLOUT",
"JAMR3 Line Out 3", "J3C LLOUT",
"JAMR3 Line Out 3", "J3C RLOUT";

/* Multichannel DAI link */
ti,multichannel-cpu = <&mcasp3>;
ti,multichannel-codec-a = <&tlv320aic3106a>;
ti,multichannel-codec-b = <&tlv320aic3106b>;
ti,multichannel-codec-c = <&tlv320aic3106c>;
ti,multichannel-slots = <8>;
ti,multichannel-mclk-freq = <11289600>;
};

&mcasp3 {

#sound-dai-cells = <0>;

assigned-clocks = <&mcasp3_ahclkx_mux>;
assigned-clock-parents = <&atl_clkin2_ck>;

status = "okay";

op-mode = <0>; /* MCASP_IIS_MODE */
tdm-slots = <8>;
num-serializer = <4>;
/* 4 serializer */
serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */
1 2 0 0
>;
tx-num-evt = <32>;
rx-num-evt = <32>;
};

act1000:/ $ cat /proc/asound/pcm
00-00: (null) multicodec-0 : : playback 1 : capture 1
02-00: HDMI 58040000.encoder snd-soc-dummy-dai-0 : : playback 1
act1000:/ $ cat /proc/asound/devices
2: [ 0] : control
3: [ 0- 0]: digital audio playback
4: [ 0- 0]: digital audio capture
5: [ 2] : control
6: [ 2- 0]: digital audio playback
33: : timer
act1000:/ $

Do you know please how to fix it ?

Thank you !

  • /*
     * dra7-jamr3-card.c  --  SoC audio for TI DRA7-JAMR3-EVM
     *
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License
     * 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/platform_device.h>
    #include <linux/module.h>
    #include <linux/of.h>
    #include <linux/clk.h>
    #include <linux/pm_runtime.h>
    #include <sound/core.h>
    #include <sound/pcm.h>
    #include <sound/soc.h>
    #include <sound/pcm_params.h>
    #include <sound/soc-dapm.h>
    
    #include <linux/moduleparam.h>
    #include <linux/timer.h>
    #include <linux/interrupt.h>
    #include <linux/platform_device.h>
    #include <linux/i2c.h>
    #include <linux/of_platform.h>
    
    #include <asm/dma.h>
    #include <asm/mach-types.h>
    
    #define NUM_CODECS	3
    
    struct jamr3_snd_data {
    	struct clk *mclk;
    	unsigned int multichannel_mclk_freq;
    	unsigned int multichannel_slots;
    	int always_on;
    	const int *rates;
    	int num_rates;
    };
    
    static const int jamr3_snd_rates[] = {
    	 5512,  8000, 11025, 16000, 22050,
    	32000, 44100, 48000, 88200, 96000,
    };
    
    /* DRA7 JAMR3 board widgets */
    static const struct snd_soc_dapm_widget jamr3_dapm_widgets[] = {
    
    	/* JAMR3 board inputs */
    	SND_SOC_DAPM_LINE("JAMR3 Stereo Aux In", NULL),
    	SND_SOC_DAPM_LINE("JAMR3 Mono Mic 1", NULL),
    	SND_SOC_DAPM_LINE("JAMR3 Mono Mic 2", NULL),
    
    	/* JAMR3 board outputs */
    	SND_SOC_DAPM_LINE("JAMR3 Line Out 1", NULL),
    	SND_SOC_DAPM_LINE("JAMR3 Line Out 2", NULL),
    	SND_SOC_DAPM_LINE("JAMR3 Line Out 3", NULL),
    };
    
    
    static unsigned int jamr3_get_bclk(struct snd_pcm_hw_params *params, int slots)
    {
    	int sample_size = snd_pcm_format_width(params_format(params));
    	int rate = params_rate(params);
    
    	return sample_size * slots * rate;
    }
    
    static int jamr3_snd_multichannel_hwrule_rates(struct snd_pcm_hw_params *params,
    					      struct snd_pcm_hw_rule *rule)
    {
    	struct jamr3_snd_data *card_data = rule->private;
    	unsigned int slots = card_data->multichannel_slots;
    	unsigned int mclk_freq = card_data->multichannel_mclk_freq;
    	unsigned int bclk_freq;
    	int width = snd_pcm_format_physical_width(params_format(params));
    	int rates[10], count = 0;
    	int i;
    
    	for (i = 0; i < card_data->num_rates; i++) {
    		bclk_freq = slots * card_data->rates[i] * width;
    		if ((mclk_freq % bclk_freq) == 0)
    			rates[count++] = card_data->rates[i];
    	}
    
    	return snd_interval_list(hw_param_interval(params, rule->var),
    				 count, rates, 0);
    }
    
    static int jamr3_snd_multichannel_startup(struct snd_pcm_substream *substream)
    {
    	struct snd_soc_pcm_runtime *rtd = substream->private_data;
    	struct snd_soc_card *card = rtd->card;
    	struct jamr3_snd_data *card_data = snd_soc_card_get_drvdata(card);
    
    	/* CODEC's TDM slot mask is always 2, aligned on 2-ch boundaries */
    	snd_pcm_hw_constraint_step(substream->runtime, 0,
    				   SNDRV_PCM_HW_PARAM_CHANNELS, 2);
    
    	snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
    			    jamr3_snd_multichannel_hwrule_rates, card_data,
    			    SNDRV_PCM_HW_PARAM_RATE, -1);
    
    	return 0;
    }
    
    static int jamr3_snd_multichannel_hw_params(struct snd_pcm_substream *substream,
    					   struct snd_pcm_hw_params *params)
    {
    	struct snd_soc_pcm_runtime *rtd = substream->private_data;
    	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
    	struct snd_soc_dai *codec_dai;
    	struct snd_soc_card *card = rtd->card;
    	struct jamr3_snd_data *card_data = snd_soc_card_get_drvdata(card);
    	unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_DSP_B |
    			   SND_SOC_DAIFMT_IB_NF;
    	unsigned int bclk_freq;
    	unsigned int slot_mask = 3;
    	int sample_size = snd_pcm_format_width(params_format(params));
    	int i, ret;
    
    	bclk_freq = jamr3_get_bclk(params, card_data->multichannel_slots);
    
    	ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
    	if (ret < 0) {
    		dev_err(card->dev, "can't set CPU DAI format %d\n", ret);
    		return ret;
    	}
    
    	/* Set McASP BCLK divider (clkid = 1) */
    	ret = snd_soc_dai_set_clkdiv(cpu_dai, 1,
    				card_data->multichannel_mclk_freq / bclk_freq);
    	if (ret < 0) {
    		dev_err(card->dev, "can't set CPU DAI clock divider %d\n", ret);
    		return ret;
    	}
    
    	/* Set McASP sysclk from AHCLKX sourced from ATL */
    	ret = snd_soc_dai_set_sysclk(cpu_dai, 0,
    				     card_data->multichannel_mclk_freq,
    				     SND_SOC_CLOCK_IN);
    	if (ret < 0) {
    		dev_err(card->dev, "can't set CPU DAI sysclk %d\n", ret);
    		return ret;
    	}
    
    	for (i = 0; i < rtd->num_codecs; i++) {
    		codec_dai = rtd->codec_dais[i];
    
    		ret = snd_soc_dai_set_fmt(codec_dai, fmt);
    		if (ret < 0) {
    			dev_err(card->dev, "can't set CODEC DAI format %d\n",
    				ret);
    			return ret;
    		}
    
    		ret = snd_soc_dai_set_tdm_slot(codec_dai, slot_mask, slot_mask,
    					       card_data->multichannel_slots,
    					       sample_size);
    		if (ret < 0) {
    			dev_err(card->dev, "can't set CODEC DAI tdm slots %d\n",
    				ret);
    			return ret;
    		}
    		slot_mask <<= 2;
    
    		/* Set MCLK as clock source for tlv320aic3106 */
    		ret = snd_soc_dai_set_sysclk(codec_dai, 0,
    					     card_data->multichannel_mclk_freq,
    					     SND_SOC_CLOCK_IN);
    		if (ret < 0) {
    			dev_err(card->dev, "can't set CODEC sysclk %d\n", ret);
    			return ret;
    		}
    	}
    
    	return 0;
    }
    
    static struct snd_soc_ops jamr3_snd_multichannel_ops = {
    	.startup = jamr3_snd_multichannel_startup,
    	.hw_params = jamr3_snd_multichannel_hw_params,
    };
    
    static int jamr3_multichannel_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
    					     struct snd_pcm_hw_params *params)
    {
    	struct snd_interval *channels = hw_param_interval(params,
    						SNDRV_PCM_HW_PARAM_CHANNELS);
    
    	/* Each tlv320aic3x receives two channels from McASP in TDM mode */
    	channels->min = 2;
    	channels->max = 2;
    
    	return 0;
    }
    
    static int jamr3_snd_multichannel_init(struct snd_soc_pcm_runtime *rtd)
    {
    	struct snd_soc_card *card = rtd->card;
    	struct jamr3_snd_data *card_data = snd_soc_card_get_drvdata(card);
    	struct device_node *np = card->dev->of_node;
    	int ret;
    	/* Minimize artifacts as much as possible if can be afforded */
    	if (card_data->always_on)
    		rtd->pmdown_time = INT_MAX;
    	else
    		rtd->pmdown_time = 0;
    
    	/* Add jamr3 specific widgets */
    	snd_soc_dapm_new_controls(&card->dapm, jamr3_dapm_widgets,
    				  ARRAY_SIZE(jamr3_dapm_widgets));
    
    	if (np) {
    		ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing");
    		if (ret)
    			return ret;
    	} 
    	
    	return 0;
    }
    
    
    static struct snd_soc_dai_link_component jamr3_snd_multichannel_codecs[] = {
    	{
    		.dai_name = "tlv320aic3x-hifi",
    	},
    	{
    		.dai_name = "tlv320aic3x-hifi",
    	},
    	{
    		.dai_name = "tlv320aic3x-hifi",
    	},
    };
    
    static struct snd_soc_dai_link jamr3_snd_dai = {
    
    	/* Multichannel: McASP6 + 3 * tlv320aic3106 */
    	.name = "Multichannel",
    	.ops = &jamr3_snd_multichannel_ops,
    	.codecs = jamr3_snd_multichannel_codecs,
    	.num_codecs = ARRAY_SIZE(jamr3_snd_multichannel_codecs),
    	.init = jamr3_snd_multichannel_init,
    	.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
    		   SND_SOC_DAIFMT_IB_NF,
    	.be_hw_params_fixup = jamr3_multichannel_hw_params_fixup,
    };
    
    static int jamr3_snd_add_multichannel_dai_link(struct snd_soc_card *card)
    {
    	struct jamr3_snd_data *card_data = snd_soc_card_get_drvdata(card);
    	struct device_node *node = card->dev->of_node;
    	struct snd_soc_dai_link *dai_link = card->dai_link;
    	struct device_node *dai_node;
    	char prop[32];
    	const char *prefix = "ti,multichannel";
    	int index = 0, ret;
    
    	if (!node) {
    		dev_err(card->dev, "card node is invalid\n");
    		return -EINVAL;
    	}
    
    	if (card_data->mclk == NULL) {
    		snprintf(prop, sizeof(prop), "%s-mclk-freq", prefix);
    		ret = of_property_read_u32(node, prop,
    				&card_data->multichannel_mclk_freq);
    		if (ret < 0) {
    			dev_err(card->dev,
    				"Must Specify codec clock.\n");
    			return -EINVAL;
    		}
    	}
    
    	snprintf(prop, sizeof(prop), "%s-cpu", prefix);
    	dai_node = of_parse_phandle(node, prop, 0);
    	if (!dai_node) {
    		dev_err(card->dev, "cpu dai node is invalid\n");
    		return -EINVAL;
    	}
    
    	dai_link->cpu_of_node = dai_node;
    
    	dai_link->platform_of_node = dai_node;
    
    	snprintf(prop, sizeof(prop), "%s-codec-a", prefix);
    	dai_node = of_parse_phandle(node, prop, 0);
    	if (!dai_node) {
    		dev_err(card->dev, "codec dai node is invalid\n");
    		return -EINVAL;
    	}
    
    	dai_link->codecs[index].of_node = dai_node;
    	index++;
    
    	snprintf(prop, sizeof(prop), "%s-codec-b", prefix);
    	dai_node = of_parse_phandle(node, prop, 0);
    	if (!dai_node) {
    		dev_err(card->dev, "codec dai node is invalid\n");
    		return -EINVAL;
    	}
    
    	dai_link->codecs[index].of_node = dai_node;
    	index++;
    
    	snprintf(prop, sizeof(prop), "%s-codec-c", prefix);
    	dai_node = of_parse_phandle(node, prop, 0);
    	if (!dai_node) {
    		dev_err(card->dev, "codec dai node is invalid\n");
    		return -EINVAL;
    	}
    
    	dai_link->codecs[index].of_node = dai_node;
    
    	snprintf(prop, sizeof(prop), "%s-slots", prefix);
    	of_property_read_u32(node, prop, &card_data->multichannel_slots);
    	if ((card_data->multichannel_slots < 1) ||
    	    (card_data->multichannel_slots > 32)) {
    		dev_err(card->dev, "invalid slot count %d\n",
    			card_data->multichannel_slots);
    		return -EINVAL;
    	}
    
    	return 0;
    }
    
    static const struct of_device_id jamr3_snd_of_match[] = {
    	{.compatible = "ti,dra7xx-jamr3-multicodec-evm", 
    	 .data = (void *) &jamr3_snd_dai,
    	},
    	{ },
    };
    MODULE_DEVICE_TABLE(of, jamr3_snd_of_match);
    
    
    /* Audio machine driver */
    static struct snd_soc_card jamr3_snd_card = {
    	.owner = THIS_MODULE,
    	.dapm_widgets = jamr3_dapm_widgets,
    	.num_dapm_widgets = ARRAY_SIZE(jamr3_dapm_widgets),
    	.dai_link = &jamr3_snd_dai,
    	.num_links = 1,
    };
    
    static int jamr3_snd_probe(struct platform_device *pdev)
    {
    	struct device_node *node = pdev->dev.of_node;
    	struct snd_soc_card *card = &jamr3_snd_card;
    	struct jamr3_snd_data *card_data;
    	int ret;
    
    	card->dev = &pdev->dev;
    
    	card_data = devm_kzalloc(&pdev->dev, sizeof(*card_data), GFP_KERNEL);
    	if (card_data == NULL)
    		return -ENOMEM;
    
    	if (!node) {
    		dev_err(card->dev, "missing of_node\n");
    		return -ENODEV;
    	}
    
    	card_data->rates = jamr3_snd_rates;
    	card_data->num_rates = ARRAY_SIZE(jamr3_snd_rates);
    
    	ret = snd_soc_of_parse_card_name(card, "ti,model");
    	if (ret) {
    		dev_err(card->dev, "card name is not provided\n");
    		return -ENODEV;
    	}
    
    	card_data->mclk = devm_clk_get(&pdev->dev, "ti,codec-clock");
    	if (PTR_ERR(card_data->mclk) == -EPROBE_DEFER) {
    		return -EPROBE_DEFER;
    	} else if (IS_ERR(card_data->mclk)) {
    		dev_dbg(&pdev->dev, "ti,codec-clock not found.\n");
    		card_data->mclk = NULL;
    	}
    
    	ret = snd_soc_of_parse_audio_routing(card,
    					     "ti,audio-routing");
    	if (ret) {
    		dev_err(card->dev, "failed to parse DAPM routing\n");
    		return ret;
    	}
    
    	snd_soc_card_set_drvdata(card, card_data);
    
    	card_data->multichannel_mclk_freq = clk_get_rate(card_data->mclk);
    
    	if (of_find_property(node, "ti,always-on", NULL))
    		card_data->always_on = 1;
    
    	ret = jamr3_snd_add_multichannel_dai_link(card);
    	if (ret) {
    		dev_err(card->dev, "failed to add multichannel dai link %d\n",
    			ret);
    		return ret;
    	}
    
    	ret = devm_snd_soc_register_card(&pdev->dev, card);
    	if (ret)
    		dev_err(card->dev, "failed to register sound card %d\n", ret);
    
    
    	return ret;
    }
    
    
    static struct platform_driver jamr3_snd_driver = {
    	.driver = {
    		.name = "dra7xx-jamr3-multicodec-evm",
    		.owner = THIS_MODULE,
    		.pm = &snd_soc_pm_ops,
    		.of_match_table = jamr3_snd_of_match,
    	},
    	.probe = jamr3_snd_probe,
    };
    
    module_platform_driver(jamr3_snd_driver);
    
    MODULE_AUTHOR("Texas Instrument Inc.");
    MODULE_DESCRIPTION("ALSA SoC for DRA7 JAMR3 EVM");
    MODULE_LICENSE("GPL");
    MODULE_ALIAS("platform:dra7xx-jamr3-multicodec-evm");
    

    Here the used driver

    Regards,

    Chokri

  • additional information: with same driver and sound card dts node the multi-channel is working fine :

    the only diff the EVM use mcasp6 and our customer board mcasp3.

    any diff between mcasp6 and mcasp3 ?

    I tried also to change mcasp3 config like mcasp6 on JAMR3 dts 

    &mcasp3 {

    #sound-dai-cells = <0>;

    assigned-clocks = <&mcasp3_ahclkx_mux>;
    assigned-clock-parents = <&atl_clkin1_ck>;
    status = "okay";
    op-mode = <0>; /* MCASP_IIS_MODE */
    tdm-slots = <8>;
    /* 4 serializer */
    serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */
    1 2 1 2 1 2
    >;
    tx-num-evt = <8>;
    rx-num-evt = <8>;
    shared-dai;
    };

    but still not working and each stereo CODEC instance receives always two channels of the stereo stream.

  • Re "each stereo CODEC instance receives always two channels of the stereo stream."

    In stereo playback, only codec A should render audio. If all codecs are rendering same audio, then check what TDM slots codecs B and C are active on.

    Re "But I need that each stereo CODEC  two channels of the 6ch stream: ch1-2 codecA, ch2-3 codecB, ch4-5 codecC"

    What do you observe if a 6-channel audio sample is played?

    Also, consider using omapconf tool. It has support for McASP which comes in handy in cases like this. You could run "omapconf show mcasp3" and it will print the McASP configuration. In this case, you could use it to verify the active TDM slots are as per expectation for a given number of channels being played.

  • Hi Misael,

    What do you observe if a 6-channel audio sample is played?

    each stereo CODEC instance receives the first two channels of the 6ch audio sample.

    Here the dump of mcasp3 during play 6ch wav audio file :

    |--------------------------------------------|
    | Reg. Name | Reg. Addr | Reg. Val. |
    |--------------------------------------------|
    | MCASP_PID | 0x48468000 | 0x44307B03 |
    | PWRIDLESYSCONFIG | 0x48468004 | 0x00000002 |
    | MCASP_PFUNC | 0x48468010 | 0x00000000 |
    | MCASP_PDIR | 0x48468014 | 0xB4000001 |
    | MCASP_PDOUT | 0x48468018 | 0x00000000 |
    | MCASP_PDIN | 0x4846801C | 0x2C000000 |
    | MCASP_PDCLR | 0x48468020 | 0x00000000 |
    | MCASP_GBLCTL | 0x48468044 | 0x00001F00 |
    | MCASP_AMUTE | 0x48468048 | 0x00000000 |
    | MCASP_LBCTL | 0x4846804C | 0x00000000 |
    | MCASP_TXDITCTL | 0x48468050 | 0x00000000 |
    | MCASP_GBLCTLR | 0x48468060 | 0x00001F00 |
    | MCASP_RXMASK | 0x48468064 | 0x0000FFFF |
    | MCASP_RXFMT | 0x48468068 | 0x00000070 |
    | MCASP_RXFMCTL | 0x4846806C | 0x00000002 |
    | MCASP_ACLKRCTL | 0x48468070 | 0x00180021 |
    | MCASP_AHCLKRCTL | 0x48468074 | 0x00180000 |
    | MCASP_RXTDM | 0x48468078 | 0x00000000 |
    | MCASP_EVTCTLR | 0x4846807C | 0x00000000 |
    | MCASP_RXSTAT | 0x48468080 | 0x00000104 |
    | MCASP_RXTDMSLOT | 0x48468084 | 0x00000000 |
    | MCASP_RXCLKCHK | 0x48468088 | 0x00000000 |
    | MCASP_REVTCTL | 0x4846808C | 0x00000000 |
    | MCASP_GBLCTLX | 0x484680A0 | 0x00001F00 |
    | MCASP_TXMASK | 0x484680A4 | 0x0000FFFF |
    | MCASP_TXFMT | 0x484680A8 | 0x00008074 |
    | MCASP_TXFMCTL | 0x484680AC | 0x00000402 |
    | MCASP_ACLKXCTL | 0x484680B0 | 0x00000021 |
    | MCASP_AHCLKXCTL | 0x484680B4 | 0x00000000 |
    | MCASP_TXTDM | 0x484680B8 | 0x0000003F |
    | MCASP_EVTCTLX | 0x484680BC | 0x00000000 |
    | MCASP_TXSTAT | 0x484680C0 | 0x0000015C |
    | MCASP_TXTDMSLOT | 0x484680C4 | 0x00000007 |
    | MCASP_TXCLKCHK | 0x484680C8 | 0xF1000000 |
    | MCASP_XEVTCTL | 0x484680CC | 0x00000000 |
    | MCASP_CLKADJEN | 0x484680D0 | 0x00000000 |
    | MCASP_XRSRCTL0 | 0x48468180 | 0x00000009 |
    | MCASP_XRSRCTL1 | 0x48468184 | 0x00000002 |
    | MCASP_XRSRCTL2 | 0x48468188 | 0x00000000 |
    | MCASP_XRSRCTL3 | 0x4846818C | 0x00000000 |
    | MCASP_WFIFOCTL | 0x48469000 | 0x00010801 |
    | MCASP_WFIFOSTS | 0x48469004 | 0x0000003A |
    | MCASP_RFIFOCTL | 0x48469008 | 0x00001004 |
    | MCASP_RFIFOSTS | 0x4846900C | 0x00000000 |
    |--------------------------------------------|

    Regards,

    Chokri

  • omapconf show mcasp3

    |--------------------------------------------|
    | Data Ports and Buffers |
    |--------------------------------------------|
    | Port | DATA bus |
    | Transmit DMA | |
    | DMA request | Enabled |
    | Status | No error |
    | Receive DMA | |
    | DMA request | Enabled |
    | Status | No error |
    | Transmit Buffer (XBUF) | |
    | Status | No error |
    | Receive Buffer (RBUF) | |
    | Status | No error |
    | Write FIFO (WFIFO) | |
    | State | Disabled |
    | Threshold | 8 samples |
    | Level | 0 samples in FIFO |
    | Read FIFO (RFIFO) | |
    | State | Disabled |
    | Threshold | 16 samples |
    | Level | 0 samples in FIFO |
    |--------------------------------------------|

    |----------------------------------------|
    | Control |
    |----------------------------------------|
    | Transmit State-Machine | |
    | State | Held in reset |
    | Transmit Sequencer | |
    | Enabled Slots | 8 |
    | Active Slots | 2 |
    | Active Slots Mask | 0x00000003 |
    | Current Slot | Inactive |
    | Receive State-Machine | |
    | State | Held in reset |
    | Receive Sequencer | |
    | Enabled Slots | INVALID |
    | Active Slots | 0 |
    | Active Slots Mask | 0x00000000 |
    | Current Slot | Inactive |
    |----------------------------------------|

    |-----------------------------------------------------|
    | Clocks |
    |-----------------------------------------------------|
    | Transmit Bit Clock | |
    | State | Held in reset |
    | Divider | Divide-by 2 |
    | Source | Internal |
    | Polarity | Driven on rising edge |
    | Transmit High-Speed Clock | |
    | State | Held in reset |
    | Divider | Divide-by 1 |
    | Source | External (AHCLKX pin) |
    | Polarity | Non-inverted |
    | Receive Bit Clock | |
    | State | Held in reset |
    | Divider | Divide-by 2 |
    | Source | Internal |
    | Polarity | Samples on falling edge |
    | Sync Mode | Synchronous to TX |
    | Idle Mode | Smart-idle |
    |-----------------------------------------------------|

    |---------------------------------------------------|
    | Frame Sync Generator |
    |---------------------------------------------------|
    | Transmit Frame Sync | |
    | Generator State | Held in reset |
    | Source | Internal |
    | Polarity | Frame starts on rising edge |
    | Pulse Width | Single bit |
    | Slot Count | 8 (TDM) |
    | Data Delay | 0-bit |
    | Status | No error |
    | Receive Frame Sync | |
    | Generator State | Held in reset |
    | Source | Internal |
    | Polarity | Frame starts on rising edge |
    | Pulse Width | Single bit |
    | Slot Count | INVALID |
    | Data Delay | 0-bit |
    | Status | No error |
    | Sync Mode | Synchronous to TX |
    |---------------------------------------------------|

    |-----------------------------------------|
    | Format Units |
    |-----------------------------------------|
    | Transmit Format Unit | |
    | Slot Size | 16 bits |
    | Bit Mask | 0x0000FFFF |
    | Padding | Pad with 0 |
    | Right-Rotation | 16 bit positions |
    | Bitstream Order | MSB first |
    | Receive Format Unit | |
    | Slot Size | 16 bits |
    | Bit Mask | 0x0000FFFF |
    | Padding | Pad with 0 |
    | Right-Rotation | 0 bit positions |
    | Bitstream Order | LSB first |
    |-----------------------------------------|

    |----------------------------------|
    | Serializers |
    |----------------------------------|
    | Transmit Serializers | Cleared |
    | Receive Serializers | Cleared |
    | Serializer 0 | |
    | Mode | Transmit |
    | Inactive State | Logic Low |
    | Serializer 1 | |
    | Mode | Receive |
    | Inactive State | Hi-Z |
    | Serializer 2 | |
    | Mode | Inactive |
    | Inactive State | Hi-Z |
    | Serializer 3 | |
    | Mode | Inactive |
    | Inactive State | Hi-Z |
    |----------------------------------|

    |--------------------------------------------|
    | Pin Control |
    |--------------------------------------------|
    | AFSR | |
    | Functionality | Receive Frame Sync |
    | Direction | Output |
    | ACLKR | |
    | Functionality | Receive Bit Clock |
    | Direction | Output |
    | AFSX | |
    | Functionality | Transmit Frame Sync |
    | Direction | Output |
    | ACLKX | |
    | Functionality | Transmit Bit Clock |
    | Direction | Output |
    | AHCLKX | |
    | Functionality | Transmit High-Freq Clock |
    | Direction | Input |
    | AXR0 | |
    | Functionality | TX/RX Data Channel 0 |
    | Direction | Output |
    | AXR1 | |
    | Functionality | TX/RX Data Channel 1 |
    | Direction | Input |
    | AXR2 | |
    | Functionality | TX/RX Data Channel 2 |
    | Direction | Input |
    | AXR3 | |
    | Functionality | TX/RX Data Channel 3 |
    | Direction | Input |
    |--------------------------------------------|

  • Chokri,

    Was omapconf command run while playback while going on? It must be done while playback is going on in the background. McASP register values are different during playback vs after playback is done.

    Is McASP configured as master?

    While 6-ch audio sample playback is happening, it'd expect that "Enabled slots" be 8, but also that "Active Slots" is 6 ("Active Slots Mask" should match the slots your audio codecs are active on). I don't see that happening in your omapconf logs.

    |----------------------------------------|
    | Control                                |
    |----------------------------------------|
    | Transmit State-Machine |               |
    | State                  | Held in reset |
    | Transmit Sequencer     |               |
    | Enabled Slots          |             8 |
    | Active Slots           |             2 |
    | Active Slots Mask      |    0x00000003 |

  • Hi Misael,

    Here the dump during playback of 6-ch audio sample :

    |----------------------------------------|
    | Control |
    |----------------------------------------|
    | Transmit State-Machine | |
    | State | Active |
    | Transmit Sequencer | |
    | Enabled Slots | 8 |
    | Active Slots | 6 |
    | Active Slots Mask | 0x0000003F |
    | Current Slot | 2 |
    | Receive State-Machine | |
    | State | Held in reset |
    --

    |----------------------------------------|
    | Control |
    |----------------------------------------|
    | Transmit State-Machine | |
    | State | Active |
    | Transmit Sequencer | |
    | Enabled Slots | 8 |
    | Active Slots | 6 |
    | Active Slots Mask | 0x0000003F |
    | Current Slot | 5 |
    | Receive State-Machine | |
    | State | Held in reset |
    --

    |----------------------------------------|
    | Control |
    |----------------------------------------|
    | Transmit State-Machine | |
    | State | Active |
    | Transmit Sequencer | |
    | Enabled Slots | 8 |
    | Active Slots | 6 |
    | Active Slots Mask | 0x0000003F |
    | Current Slot | 1 |
    | Receive State-Machine | |
    | State | Held in reset |
    --
    |----------------------------------------|
    | Control |
    |----------------------------------------|
    | Transmit State-Machine | |
    | State | Active |
    | Transmit Sequencer | |
    | Enabled Slots | 8 |
    | Active Slots | 6 |
    | Active Slots Mask | 0x0000003F |
    | Current Slot | 6 |
    | Receive State-Machine | |
    | State | Held in reset |
    --
    |----------------------------------------|
    | Control |
    |----------------------------------------|
    | Transmit State-Machine | |
    | State | Active |
    | Transmit Sequencer | |
    | Enabled Slots | 8 |
    | Active Slots | 6 |
    | Active Slots Mask | 0x0000003F |
    | Current Slot | 0 |
    | Receive State-Machine | |
    | State | Held in reset |
    --

    But each stereo CODEC instance still receives the first two channels of the 6ch audio sample.

    &mcasp3 {
    #sound-dai-cells = <0>;

    assigned-clocks = <&mcasp3_ahclkx_mux>;
    assigned-clock-parents = <&atl_clkin1_ck>;

    status = "okay";

    op-mode = <0>; /* MCASP_IIS_MODE */
    tdm-slots = <8>;
    num-serializer = <4>;
    /* 4 serializer */
    serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */
    1 2 0 0
    >;
    tx-num-evt = <32>;
    rx-num-evt = <32>;
    };

    //Chokri

  • Chokri,

    Re "But each stereo CODEC instance still receives the first two channels of the 6ch audio sample" - please check the TDM slots that the codec is active on. You can check that in codec's set_dai_tdm_slot() function.

    In DRA7xx EVM drivers, we configured that in tlv320aic3106's register 10 "Audio Serial Data Interface Control Register C."

  • It seems that TDM slots are configured correctly :

    [ 1.725315] dra7xx-jamr3-multicodec-evm multicodec_sound: multicodec <-> 48468000.mcasp mapping ok
    [ 3.895862] dra7xx-jamr3-multicodec-evm multicodec_sound: Codec 0 snd_soc_dai_set_tdm_slot slot_mask 0X3 sample_size 16 and card_data->multichannel_slots 8
    [ 3.910064] tlv320aic3x-codec 0-0018: aic3x_set_dai_tdm_slot aic3x->tdm_delay 0X0 slot width 16
    [ 3.918974] dra7xx-jamr3-multicodec-evm multicodec_sound: Codec 1 snd_soc_dai_set_tdm_slot slot_mask 0Xc sample_size 16 and card_data->multichannel_slots 8
    [ 3.933095] tlv320aic3x-codec 0-0019: aic3x_set_dai_tdm_slot aic3x->tdm_delay 0X2 slot width 16
    [ 3.948462] dra7xx-jamr3-multicodec-evm multicodec_sound: Codec 2 snd_soc_dai_set_tdm_slot slot_mask 0X30 sample_size 16 and card_data->multichannel_slots 8
    [ 3.948467] tlv320aic3x-codec 0-001a: aic3x_set_dai_tdm_slot aic3x->tdm_delay 0X4 slot width 16
    [ 3.972448] tlv320aic3x-codec 0-001a: Unable to sync registers 0x7-0xa. -121

    maybe it's related to this error ?

    Thanks,

    Chokri

  • Yes, it could be related to that error for codec-c. But codec-b seems to have TDM delay incorrectly configured also but no error message.

    Could you read register 10 from all codecs while playback is happening in the background? omapconf has support for i2c read/write - I believe it's something like "omapconf read i2c <bus> <device addr> <reg addr>", but you can double check syntax with "omapconf --help".

  • During playback the  register 10 contains 0x20.

    $omapconf i2c read 0 0x18 0x10

    0x20

    $omapconf i2c read 0 0x19 0x10

    0x20

    if 10dec => 0x0A

    $omapconf i2c read 0 0x18 0x0A

    0x00

    $omapconf i2c read 0 0x19 0x0A

    0x20

     

     

    Regards,

  • The TDM delay/offset setting is correct for codecs A and B. Please also check for codec C.

    There is no channel data duplication happening at any point during audio playback on the kernel side. I can't think of any other reason to explain why channels 0 and 1 are being rendered on all 3 codecs.

    Is it possible to share the WAV file you're using for testing? If possible, please try with 2-channel and 4-channel sample files, and let me know what the behavior is. Hoping that may give additional clues. Please also share the exact command you're using for playback (aplay, tinyplay, own app).

  • Thanks Misael,

    I can't dump codec C due to [ 3.972448] tlv320aic3x-codec 0-001a: Unable to sync registers 0x7-0xa. -121 error,

    for the alsa comd ; alsa_aplay /sdcard/Music/6-ch.wav

    We will check our schematic before.

    Regards,

    Chokri 

  • Chokri,

    Could you try running aplay with -v option? Make sure that no sample conversion is happening under the hood. You could also try aplay -Dhw:0,0.

  • #alsa_aplay /sdcard/Music/6ch.wav -Dhw:0,0 -vv 
    Playing WAVE '/sdcard/Music/6ch.wav' :
    Signed 16 bit Little Endian, Rate 44100 Hz, Channels 6
    Hardware PCM card 0 'SND_CARD' device 0 subdevice 0
    Its setup is:
    stream : PLAYBACK
    access : RW_INTERLEAVED
    format : S16_LE
    subformat : STD
    channels : 6
    rate : 44100
    exact rate : 44100 (44100/1)
    msbits : 16
    buffer_size : 8193
    period_size : 2731
    period_time : 61927
    tstamp_mode : NONE
    period_step : 1
    avail_min : 2731
    period_event : 0
    start_threshold : 8193
    stop_threshold : 8193
    silence_threshold: 0
    silence_size : 0
    boundary : 1073872896
    appl_ptr : 0
    hw_ptr : 0
    # + | 09%

    //Chokri

  • Chokri,

    Your initial dts configuration corresponds to a connection where all three codecs are sitting on the same AXR serializer line. But later you posted other dts configuration which corresponded to a case where each codec has its own AXR serializer.

    Could you provide more details on how McASP serializers are connected to the audio codecs?

  • Hi Misael,

    I confirm that all three codecs are sitting on the same AXR serializer line.

    all 4 codecs use the same AXT to receive data MCASP3 AXR.

    Regards,

    Chokri

  • 4 codecs? Initial post says codecs a, b and c. You'd need to update dts and driver to support a "codec d".

    Could you please try aplay -Dhw:0,0 with 2-channel and 4-channel sample files? I can't think of any other reason for all codecs playing only first two slots. I'm hoping that observations with 2-ch and 4-ch playback could give some other leads.

  • the forth codec is not detected well (i2c issue)

    Yes with 4-ch sample, ch1-2 to codec A and ch3-4 to Codec B

    Thanks a lot