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.

TDA4VM: How add new snd card in linux?

Part Number: TDA4VM

Tool/software:

Hi Ti expert

SDK: 0806
Board: customer Board(No matter)

This is my design:


I want to get the audio data from the sensor through mcasp0 and mcasp11.
The configuration of the A2B daisy chain is configured through the I2C of c6x_1.
How can I modify the device tree to create two sound cards (mcasp0 and mcasp11) in Linux to get the audio data from the two sound cards?

Best Regards
Eason


  • I want to use 

    arecord -D hw:1,0 -c 32 -f S32_LE -r 48000 -d 10 >> test.wav
    arecord -D hw:0,0 -c 32 -f S32_LE -r 48000 -d 10 >> test.wav
    

    to get audio data.

  • Hi Eason,

    You can look at the TDA4VM EVM device tree for inspiration. You will just need to create device tree nodes for the McASP0 and McASP11.

    I also go into more details in this thread: https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1501141/tda4vm-mcasp1-can-not-work 

    Also, can you move to a newer SDK version?

    Best,
    Jared

  • Hi, Jared

    I clicked the wrong button, this problem is not solved, so let's continue discussing it.

    The reference link you gave is very helpful, but actually my problem is not solved. Here are my debugging methods and questions:

    1), I use A2B chip also AD2428.In normal applications, I have integrated or write the AD2428 codec driver, but in fact, the configuration of AD2428 is   completed on C6X_1 (through I2C, but this I2C is also configured with other A2B chips, so it cannot be used on Linux), so it is impossible to add the AD2428 codec driver in Linux. So I still need codec???

    2), I have I modified the dts and a dummy-codec:

    	mcasp0_pins_default: mcasp0_pins_default {
    		pinctrl-single,pins = <
    			J721E_IOPAD(0xd4, PIN_OUTPUT_PULLDOWN, 12) /* (AB26) PRG0_PRU0_GPO9.MCASP0_ACLKX */
    			J721E_IOPAD(0xd8, PIN_OUTPUT_PULLDOWN, 12) /* (AB25) PRG0_PRU0_GPO10.MCASP0_AFSX */
    			J721E_IOPAD(0xb0, PIN_INPUT_PULLDOWN, 12) /* (AF28) PRG0_PRU0_GPO0.MCASP0_AXR0 */
    			/* J721E_IOPAD(0xb4, PIN_INPUT_PULLDOWN, 12)*/ /* (AE28) PRG0_PRU0_GPO1.MCASP0_AXR1 */
    			J721E_IOPAD(0xc0, PIN_OUTPUT_PULLDOWN, 12) /* (AD25) PRG0_PRU0_GPO4.MCASP0_AXR2 */
    			/* J721E_IOPAD(0xc8, PIN_OUTPUT_PULLDOWN, 12)*/ /* (AE26) PRG0_PRU0_GPO6.MCASP0_AXR4 */
    		>;
    	};
    
    	sound2: sound@2 {
    		status = "okay";
    		compatible = "simple-audio-card";
    		simple-audio-card,name = "front-sensor-a2b3-mcasp0";
    		simple-audio-card,format = "left_j";
    		simple-audio-card,mclk-fs = <1024>;
    		simple-audio-card,bitclock-master = <&dailink2_master>;
    		simple-audio-card,frame-master = <&dailink2_master>;
    
    		dailink2_master: simple-audio-card,cpu {
    			sound-dai = <&mcasp0>;
    			dai-tdm-slot-num = <32>;
    			dai-tdm-slot-width = <32>;
    			mclk-fs = <1024>;
    			clocks = <&k3_clks 174 1>;
    			clock-names = "fck";
    			system-clock-direction-out;
    		};
    		simple-audio-card,codec {
    			sound-dai = <&dummy_codec2>;
    		};
    	};
    
    	dummy_codec2: dummy-codec2 {
    		status = "okay";
    		compatible = "autox,a2b-codec";
    		#sound-dai-cells = <0>;
    		id = <1>;
    	};
    &mcasp0 {
    	status = "okay";
    	#sound-dai-cells = <0>;
    
    	pinctrl-names = "default";
    	pinctrl-0 = <&mcasp0_pins_default>;
    
    	op-mode = <0>;          /* MCASP_IIS_MODE */
    	tdm-slots = <32>;
    	auxclk-fs-ratio = <1024>;
    
    	serial-dir = <	/* 0: INACTIVE, 1: TX, 2: RX */
    		2 0 0 0 
    		0 0 0 0
    		1 0 0 0
    		0 0 0 0
    	>;
    	tx-num-evt = <1>;
    	rx-num-evt = <1>;
    };
    
    



    and this is my dummy-codec.c and davinci-mcasp.c

    3343.davinci-mcasp.c


    /*
     * dummy_codec.c  --  dummy audio codec
     *
     * This software is licensed under the terms of the GNU General Public
     * License version 2, as published by the Free Software Foundation, and
     * may be copied, distributed, and modified under those terms.
     *
     * 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/clk.h>
    #include <linux/module.h>
    #include <linux/moduleparam.h>
    #include <linux/slab.h>
    #include <linux/of.h>
    #include <linux/of_gpio.h>
    #include <sound/soc.h>
    #include <sound/pcm.h>
    #include <sound/initval.h>
    
    struct a2b_net_cfg {
    	int id;
    };
    
    struct dummy_codec_priv {
    	struct snd_soc_codec *codec;
    	struct a2b_net_cfg a2b_cfg;
    };
    
    static int dummy_codec_startup(struct snd_pcm_substream *substream,
    			       struct snd_soc_dai *dai)
    {
    	return 0;
    }
    
    static void dummy_codec_shutdown(struct snd_pcm_substream *substream,
    				 struct snd_soc_dai *dai)
    {
        return;
    }
    
    static struct snd_soc_dai_ops dummy_codec_dai_ops = {
    	.startup	= dummy_codec_startup,
    	.shutdown	= dummy_codec_shutdown,
    };
    
    static struct snd_soc_dai_driver a2b_dai[] = {
    	{
    		.name = "a2b-codec-0",
    		.playback = {
    			.stream_name = "a2b Playback",
    			.channels_min = 2,
    			.channels_max = 32,
    			.rates = SNDRV_PCM_RATE_8000_192000,
    			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
    					SNDRV_PCM_FMTBIT_S20_3LE |
    					SNDRV_PCM_FMTBIT_S24_LE |
    					SNDRV_PCM_FMTBIT_S32_LE),
    		},
    		.capture = {
    			.stream_name = "a2b Capture",
    			.channels_min = 2,
    			.channels_max = 32,
    			.rates = SNDRV_PCM_RATE_8000_192000,
    			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
    					SNDRV_PCM_FMTBIT_S20_3LE |
    					SNDRV_PCM_FMTBIT_S24_LE |
    					SNDRV_PCM_FMTBIT_S32_LE),
    		},
    		.ops = &dummy_codec_dai_ops,
    	},
    	{
    		.name = "a2b-codec-1",
    		.playback = {
    			.stream_name = "a2b Playback",
    			.channels_min = 2,
    			.channels_max = 32,
    			.rates = SNDRV_PCM_RATE_8000_192000,
    			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
    					SNDRV_PCM_FMTBIT_S20_3LE |
    					SNDRV_PCM_FMTBIT_S24_LE |
    					SNDRV_PCM_FMTBIT_S32_LE),
    		},
    		.capture = {
    			.stream_name = "a2b Capture",
    			.channels_min = 2,
    			.channels_max = 32,
    			.rates = SNDRV_PCM_RATE_8000_192000,
    			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
    					SNDRV_PCM_FMTBIT_S20_3LE |
    					SNDRV_PCM_FMTBIT_S24_LE |
    					SNDRV_PCM_FMTBIT_S32_LE),
    		},
    		.ops = &dummy_codec_dai_ops,
    	},
    	{
    		.name = "a2b-codec-2",
    		.playback = {
    			.stream_name = "a2b Playback",
    			.channels_min = 2,
    			.channels_max = 32,
    			.rates = SNDRV_PCM_RATE_8000_192000,
    			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
    					SNDRV_PCM_FMTBIT_S20_3LE |
    					SNDRV_PCM_FMTBIT_S24_LE |
    					SNDRV_PCM_FMTBIT_S32_LE),
    		},
    		.capture = {
    			.stream_name = "a2b Capture",
    			.channels_min = 2,
    			.channels_max = 32,
    			.rates = SNDRV_PCM_RATE_8000_192000,
    			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
    					SNDRV_PCM_FMTBIT_S20_3LE |
    					SNDRV_PCM_FMTBIT_S24_LE |
    					SNDRV_PCM_FMTBIT_S32_LE),
    		},
    		.ops = &dummy_codec_dai_ops,
    	},
        {
        	.name = "fpga-codec-0",
    		.playback = {
    			.stream_name = "fpga Playback",
    			.channels_min = 2,
    			.channels_max = 32,
    			.rates = SNDRV_PCM_RATE_8000_192000,
    			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
    					SNDRV_PCM_FMTBIT_S20_3LE |
    					SNDRV_PCM_FMTBIT_S24_LE |
    					SNDRV_PCM_FMTBIT_S32_LE),
    		},
    		.capture = {
    			.stream_name = "fpga Capture",
    			.channels_min = 2,
    			.channels_max = 32,
    			.rates = SNDRV_PCM_RATE_8000_192000,
    			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
    					SNDRV_PCM_FMTBIT_S20_3LE |
    					SNDRV_PCM_FMTBIT_S24_LE |
    					SNDRV_PCM_FMTBIT_S32_LE),
    		},
    		.ops = &dummy_codec_dai_ops,
        },
        {
        	.name = "fpga-codec-1",
    		.playback = {
    			.stream_name = "fpga Playback",
    			.channels_min = 2,
    			.channels_max = 32,
    			.rates = SNDRV_PCM_RATE_8000_192000,
    			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
    					SNDRV_PCM_FMTBIT_S20_3LE |
    					SNDRV_PCM_FMTBIT_S24_LE |
    					SNDRV_PCM_FMTBIT_S32_LE),
    		},
    		.capture = {
    			.stream_name = "fpga Capture",
    			.channels_min = 2,
    			.channels_max = 32,
    			.rates = SNDRV_PCM_RATE_8000_192000,
    			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
    					SNDRV_PCM_FMTBIT_S20_3LE |
    					SNDRV_PCM_FMTBIT_S24_LE |
    					SNDRV_PCM_FMTBIT_S32_LE),
    		},
    		.ops = &dummy_codec_dai_ops,
        }
    };
    
    static struct snd_soc_component_driver soc_a2b_codec = {
    	.name = "a2b-codec",
    };
    
    static int autox_dummy_codec_probe(struct platform_device *pdev)
    {
    	struct dummy_codec_priv *codec_priv = NULL;
    	struct device_node *np = pdev->dev.of_node;
    	int ret, val;
    
    	codec_priv = devm_kzalloc(&pdev->dev, sizeof(*codec_priv),
    				  GFP_KERNEL);
    	if (!codec_priv)
    		return -ENOMEM;
    	platform_set_drvdata(pdev, codec_priv);
    
    	if (np != NULL) {
    		ret = of_property_read_u32(np, "id", &val);
    		if (ret >= 0 && val>=0 && val < ARRAY_SIZE(a2b_dai))
    			codec_priv->a2b_cfg.id = val;
    		else {
    			dev_warn(&pdev->dev, "Unable to get id\n");
    		}
    	}
    
    	return devm_snd_soc_register_component(&pdev->dev, &soc_a2b_codec,
    				      &a2b_dai[codec_priv->a2b_cfg.id], 1);
    }
    
    static int autox_dummy_codec_remove(struct platform_device *pdev)
    {
    	return 0;
    }
    
    static const struct of_device_id autox_dummy_codec_of_match[] = {
    	{ .compatible = "autox,a2b-codec", },
    	{},
    };
    MODULE_DEVICE_TABLE(of, autox_dummy_codec_of_match);
    
    static struct platform_driver autox_dummy_codec_driver = {
    	.driver = {
    		.name = "A2B-codec",
    		.of_match_table = of_match_ptr(autox_dummy_codec_of_match),
    	},
    	.probe = autox_dummy_codec_probe,
    	.remove = autox_dummy_codec_remove,
    };
    
    module_platform_driver(autox_dummy_codec_driver);
    
    MODULE_AUTHOR("Eason <zhanxingzhou@autox.ai>");
    MODULE_DESCRIPTION("autox Dummy Codec Driver");
    MODULE_LICENSE("GPL v2");
    
    
    


    I can find tow snd in linux:

    When I use : arecord -D hw:1,0 -c 32 -f S32_LE -r 48000 -d 10 >> test.wav
    I can see the bclk waveform, but not the data (no data).




    Hope to get your support.

    Best Regards
    Eason

  • Hi Eason,

    Can you remove the pulldowns on the pins?

    Additionally, the serial-dir property doesn't appear to be correct.

    Below is the correct property, if you are using AXR0 as RX and AXR2 as TX.

    serial-dir = <
        2 0 1 0
        0 0 0 0
        0 0 0 0
        0 0 0 0
    >;

    Best,
    Jared

  • Hi Jared

    Below is the correct property, if you are using AXR0 as RX and AXR2 as TX.

    Fullscreen
    1
    2
    3
    4
    5
    6
    serial-dir = <
    2 0 1 0
    0 0 0 0
    0 0 0 0
    0 0 0 0
    >;
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    Best,

    Ok,

    How can I set Mcasp Slot size?

    Best Regards
    Eason

  • Hi Eason,

    The tdm-slots property.

    Best,
    Jared