The PCM3060 cannot play sound normally on the NX core board

Hi,
I am trying to drive pcm3060 to work on our circuit diagram based on NX core board, but I have some troubles with the device tree and the machine driver.

The phenomenon I encountered is:
On the Ubuntu Setting tool interface, I can hear the sound output when I click the left and right channels of stereo sound test and click the mono sound test. As follows:

But when I play the audio file through the command line, the pineline is established, but no sound is heard.
The shell command is:
GST_DEBUG=3 gst-launch-1.0 filesrc location=~/test.wav ! wavparse ! alsasink device=hw:2,0
The message printed by the terminal as follows:

Setting pipeline to PAUSED ...
0:00:02.150928031  9818   0x5583abe070 WARN                 basesrc gstbasesrc.c:3583:gst_base_src_start_complete:<filesrc0> pad not activated yet
Pipeline is PREROLLING ...
0:00:02.151942471  9818   0x5583ab9ad0 FIXME                default gstutils.c:3981:gst_pad_create_stream_id_internal:<wavparse0:src> Creating random stream-id, consider implementing a deterministic way of creating a stream-id
0:00:02.369465112  9818   0x5583ab9ad0 WARN                    alsa conf.c:4886:parse_args: alsalib error: Parameter DEV must be an integer
0:00:02.369530393  9818   0x5583ab9ad0 WARN                    alsa conf.c:4991:snd_config_expand: alsalib error: Parse arguments error: Invalid argument
0:00:02.369559513  9818   0x5583ab9ad0 WARN                    alsa pcm.c:2495:snd_pcm_open_noupdate: alsalib error: Unknown PCM hw:2,0:{AES0 0x02 AES1 0x82 AES2 0x00 AES3 0x02}
0:00:02.373202615  9818   0x5583ab9ad0 WARN                    alsa pcm_hw.c:1250:snd_pcm_hw_get_chmap: alsalib error: Cannot read Channel Map ctl
: No such file or directory
0:00:02.375902062  9818   0x7f7c02fed0 WARN               audiosink gstaudiosink.c:218:audioringbuffer_thread_func:<alsasink0> failed to set thread priority
Redistribute latency...
Pipeline is PREROLLED ...
Setting pipeline to PLAYING ...
New clock: GstAudioSinkClock
Got EOS from element "pipeline0".
Execution ended after 0:00:10.126101083
Setting pipeline to PAUSED ...
Setting pipeline to READY ...
Setting pipeline to NULL ...
Freeing pipeline ...

Another shell command is:
aplay -D plughw:2,0 test.wav
The message printed by the terminal as follows:
Playing WAVE 'test.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo
No sound output can be heard when running the above two commands.

I have added the Codec node at i2c@31e0000 and modified the codec dai link and audio-routing at sound node as follows:

hdr40_i2c1 = "/i2c@31e0000";
hdr40_i2c1: pcm3060: pcm3060@47 {
			compatible = "ti,pcm3060";
			reg = <0x47>;
			ti,out-single-ended = "true";
};
sound {
nvidia,audio-routing =
			"x Headphone",          "x OUTL",
			"x Headphone",          "x OUTR",
			"x INL",               "x Mic",
			"x INR",               "x Mic",
			"y Headphone",          "y OUT",
			"y IN",                 "y Mic",
			"z Headphone",          "z OUT",
			"z IN",                 "z Mic",
			"m Headphone",          "m OUT",
			"m IN",                 "m Mic",
			"n Headphone",          "n OUT",
			"n IN",                 "n Mic",
			"o Headphone",          "o OUT",
			"o IN",                 "o Mic",
			"a IN",                 "a Mic",
			"b IN",                 "b Mic",
			"c IN",                 "c Mic",
			"d IN",                 "d Mic",
			"d1 Headphone",         "d1 OUT",
			"d2 Headphone",         "d2 OUT";
nvidia,dai-link-5 {
			link-name = "pcm3060-codec";
			cpu-dai = <&tegra_i2s5>;
			codec-dai = <&pcm3060>;
			cpu-dai-name = "I2S5";
			codec-dai-name = "pcm3060-dac", "pcm3060-adc";
			format = "i2s";
			bit-format = "s16_le";
			srate = <0xbb80>;
			num-channel = <0x2>;
			ignore_suspend;
			name-prefix = "x";
			status = "okay";
		};
};

And the machine driver was updated as follows:

rtd = snd_soc_get_pcm_runtime(card, "pcm3060-codec");
	if (rtd) {
		dai_params =
		(struct snd_soc_pcm_stream *)rtd->dai_link->params;
		dai_params->rate_min = srate;
		dai_params->channels_min = channels;
		dai_params->formats = formats;
		err = snd_soc_dai_set_sysclk(rtd->codec_dai, 0, aud_mclk, SND_SOC_CLOCK_IN);
		if (err) {
			dev_err(card->dev, "failed to set pcm3060 sysclk!\n");
			return err;
		}
	}
static int tegra_machine_pcm3060_init(struct snd_soc_pcm_runtime *rtd)
{
return 0;
}
static int codec_init(struct tegra_machine *machine)
{
	struct snd_soc_dai_link *dai_links = machine->asoc->dai_links;
	unsigned int num_links = machine->asoc->num_links, i;

	if (!dai_links || !num_links)
		return -EINVAL;

	for (i = 0; i < num_links; i++) {
		if (!dai_links[i].name)
			continue;

		if (strstr(dai_links[i].name, "rt565x-playback") ||
		    strstr(dai_links[i].name, "rt565x-codec-sysclk-bclk1"))
			dai_links[i].init = tegra_machine_rt565x_init;
		else if (strstr(dai_links[i].name, "fe-pi-audio-z-v2"))
			dai_links[i].init = tegra_machine_fepi_init;
		else if (strstr(dai_links[i].name, "respeaker-4-mic-array"))
			dai_links[i].init = tegra_machine_respeaker_init;
		else if (strstr(dai_links[i].name, "pcm3060-codec")){
			dai_links[i].init = tegra_machine_pcm3060_init;
		}
	}
	return 0;
}

The codec driver pcm3060_drv.c and kern.log as follows:
pcm3060_drv and kern_log.rar (80.6 KB)

Before I run the pipeline, the following configuration has been modified:

    amixer -c jetsonxaviernxa cset name="I2S5 codec master mode" "cbm-cfm"
    amixer -c jetsonxaviernxa cset name="I2S5 Mux" ADMAIF1
    amixer -c jetsonxaviernxa cset name="ADMAIF1 Mux" I2S5
    amixer -c jetsonxaviernxa cset name="x Master Capture Switch" on
    amixer -c jetsonxaviernxa cset name="x Master Playback Switch" on

The driver pcm3060_drv.c is based on kernel 5.1, while our project is based on kernel 4.9. In order to adapt the driver to our project, a line is commented out in the driver as follows:

static const struct snd_soc_component_driver pcm3060_soc_comp_driver = {
.controls = pcm3060_dapm_controls,
.num_controls = ARRAY_SIZE(pcm3060_dapm_controls),
.dapm_widgets = pcm3060_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(pcm3060_dapm_widgets),
.dapm_routes = pcm3060_dapm_map,
.num_dapm_routes = ARRAY_SIZE(pcm3060_dapm_map),
//.endianness = 1,
};

I doubt whether this line is the cause of the problem, or whether there are other errors in my driver and dts.
Thanks.

I deleted the kern.log in the system, and the kern.log regenerated after power on is as follows:
kern.log (925.0 KB)

Hi 418281621,

While playing via Ubuntu settings tool interface you didn’t have to make these settings explicitly and you are getting sound on speakers connected to the codec PCM3060. Is that right? If so, then don’t modify the settings when you try command line.

Just want to confirm if you are opening the right sound card.
Can you please dump following info on your board?
$ cat /proc/asound/cards

Hello, thank you for your reply. I have solved the above problems, but now I have a new problem:
After I set the codec dai name in the dts file to the following, the playback function can be achieved, but the capture function cannot be achieved:

nvidia,dai-link-5 {
			link-name = "pcm3060-codec";
			cpu-dai = <0x37>;
			codec-dai = <&pcm3060>;
			cpu-dai-name = "I2S5";
			codec-dai-name = "pcm3060-dac", "pcm3060-adc";
			format = "i2s";
			bit-format = "s16_le";
			srate = <0xbb80>;
			num-channel = <0x2>;
			ignore_suspend;
			name-prefix = "x";
			status = "okay";
		};

After I revise the codec dai name in the dts file to the following, the capture function can be achieved, but the playback function cannot be achieved:
codec-dai-name = "pcm3060-adc", "pcm3060-dac";

The relevant codes in the driver are as follows:

static struct snd_soc_dai_driver pcm3060_dai[] = {
	{
		.name = "pcm3060-dac",
		.id = PCM3060_DAI_ID_DAC,
		.playback = {
			.stream_name = "Playback",
			.channels_min = 2,
			.channels_max = 2,
			.rates = PCM3060_DAI_RATES_DAC,
			.formats = SNDRV_PCM_FMTBIT_S24_LE,
		},
		.ops = &pcm3060_dai_ops,
	},
	{
		.name = "pcm3060-adc",
		.id = PCM3060_DAI_ID_ADC,
		.capture = {
			.stream_name = "Capture",
			.channels_min = 2,
			.channels_max = 2,
			.rates = PCM3060_DAI_RATES_ADC,
			.formats = SNDRV_PCM_FMTBIT_S24_LE,
		},
		.ops = &pcm3060_dai_ops,
	},
};

Therefore, how do I modify the dts file so that the chip can play and record?
The driver of pcm3060 as follows:
pcm3060_drv.c (12.7 KB)

Do you mind sharing what you had to change?

Can you update the DAI structure like below?

static struct snd_soc_dai_driver pcm3060_dai[] = {
                .name = "pcm3060",
		.playback = {
			.stream_name = "Playback",
			.channels_min = 2,
			.channels_max = 2,
			.rates = PCM3060_DAI_RATES_DAC,
			.formats = SNDRV_PCM_FMTBIT_S24_LE,
		},
                .capture = {
			.stream_name = "Capture",
			.channels_min = 2,
			.channels_max = 2,
			.rates = PCM3060_DAI_RATES_ADC,
			.formats = SNDRV_PCM_FMTBIT_S24_LE,
		},
		.ops = &pcm3060_dai_ops,
};

And DT like below:

        nvidia,dai-link-5 {
			link-name = "pcm3060-codec";
			cpu-dai = <0x37>;
			codec-dai = <&pcm3060>;
			cpu-dai-name = "I2S5";
			codec-dai-name = "pcm3060";
			format = "i2s";
			bit-format = "s16_le";
			srate = <0xbb80>;
			num-channel = <0x2>;
			ignore_suspend;
			name-prefix = "x";
			status = "okay";
		};

Basically you don’t have to separate out DAC and ADC dais. The DAI driver is bi-directional and you can just use one DAI with both playback & capture capabilities.

Thanks. It was a hardware circuit problem before, but it was later modified.

And I have upgraded the DAI structure as you listed. The dts file has also been modified accordingly. The phenomenon is that the sound card cannot be found after reboot.
The following information can be seen in kern.log:

Dec 13 16:15:08 localhost kernel: [    6.748695] tegra-asoc: sound: ASoC: CODEC DAI pcm3060-hifi not registered
Dec 13 16:15:08 localhost kernel: [    6.748925] tegra-asoc: sound: snd_soc_register_card failed (-517)

I tried several times, but it still couldn’t find the sound card. Can you help me to find out what the problem is?

Error is related to “pcm3060-hifi”. Seems like your codec driver has not registered this DAI. You need to use exact same name in the DT. Please cross check this.

Thank you for your reply. Yes, I confirmed that it is the same.
Some programs modified in the driver are as follows:

static struct snd_soc_dai_driver pcm3060_dai = {
	//{
		.name = "pcm3060-hifi",
		//.id = PCM3060_DAI_ID_DAC,
		.playback = {
			.stream_name = "Playback",
			.channels_min = 2,
			.channels_max = 2,
			.rates = PCM3060_DAI_RATES_DAC,
			.formats = SNDRV_PCM_FMTBIT_S24_LE,
		},
		//.ops = &pcm3060_dai_ops,
	//},
	//{
		//.name = "pcm3060-adc",
		//.id = PCM3060_DAI_ID_ADC,
		.capture = {
			.stream_name = "Capture",
			.channels_min = 2,
			.channels_max = 2,
			.rates = PCM3060_DAI_RATES_ADC,
			.formats = SNDRV_PCM_FMTBIT_S24_LE,
		},
		.ops = &pcm3060_dai_ops,
	//},
};

Some programs modified in the dts are as follows:

nvidia,dai-link-5 {
			link-name = "pcm3060-codec";
			cpu-dai = <0x37>;
			codec-dai = <&pcm3060>;
			cpu-dai-name = "I2S5";
			codec-dai-name = "pcm3060-hifi";
			format = "i2s";
			bit-format = "s16_le";
			srate = <0xbb80>;
			num-channel = <0x2>;
			ignore_suspend;
			name-prefix = "x";
			status = "okay";
		};

Do you have any ideas?

One reason could be your codec probe might have failed. Please make sure it is registered fine. Can you attach complete codec driver?

Hello. This is the complete codec driver that I have revised. Thanks.
pcm3060_drv.c (13.1 KB)

Hi, hardware route as follows:


Both DIN and DOUT pins are connected to the same I2S5.

I don’t see anything wrong with the driver.
Like I mentioned before, can you confirm your codec probe is happening successfully?
You were able to get it working with DAC DAI, you just need to do the same with common DAI.

This is fine and not an issue. Failure you are seeing is not related to this.

I added some print information in probe, as follows:

int pcm3060_probe(struct device *dev)
{
	#define	regmap_update_bits(map, reg, mask, val) \
			regmap_update_bits_base(map, reg, mask, val, NULL, false, false)
	int rc;
	struct pcm3060_priv *priv = dev_get_drvdata(dev);
	printk("pcm3060: --------------------------- 3");
	/* soft reset */
	rc = regmap_update_bits(priv->regmap, PCM3060_REG64,
				PCM3060_REG_MRST, 0);
	if (rc) {
		dev_err(dev, "Failed to reset component, rc=%d\n", rc);
		//return rc;
	}
	if (dev->of_node)
		pcm3060_parse_dt(dev->of_node, priv);
	else
		printk("pcm3060: dev->of_node = NULL!");
	printk("pcm3060: --------------------------- 4");
	if (priv->out_se)
		regmap_update_bits(priv->regmap, PCM3060_REG64,
				   PCM3060_REG_SE, PCM3060_REG_SE);
	else
		printk("pcm3060: priv->out_se = 0!");

	printk("pcm3060: --------------------------- 5");
	/*rc = devm_snd_soc_register_component(dev, &pcm3060_soc_comp_driver,
										 pcm3060_dai,
										 ARRAY_SIZE(pcm3060_dai));*/
	rc = devm_snd_soc_register_component(dev, &pcm3060_soc_comp_driver,&pcm3060_dai,1);
	if (rc) {
		printk("pcm3060: --------------------------- failed to register component");
		dev_err(dev, "failed to register component, rc=%d\n", rc);
		return rc;
	}
	else {
		printk("pcm3060: --------------------------- success to register component");
	}

	printk("pcm3060: --------------------------- 6");

	return 0;
}

From the print message, the probe executes normally and the component is successfully registered. But the sound card is still not registered.

The printed message is as follows:

Seems like you are loading the codec driver too late. See the error message of DAI comes before the codec probe success.

Thanks, spujar. We tried again.

  1. When code dai does not integrate adc and dac into one, the printed kernlog is as follows:
    pcm3060-dac-kernlog.log (104.2 KB)

  2. When code dai integrates adc and dac into a hifi, the printed kernlog is as follows:
    pcm3060-hifi-kernlog.log (102.5 KB)

There is also error messages before codec probe in 1, but the sound card is registered normally and the playback function is normal.

However, from the kern log of 2, the sound card has not been registered.
I’m not sure where the problem is. Looking forward to your replay, thanks.

This is bit strange.

Can you make sure to load the codec driver before you load Tegra machine driver and see if it helps?

or just for testing purpose keep two DAIs in the driver structure and use only the first one. For reference:

static struct snd_soc_dai_driver pcm3060_dai[] = {
	{
		.name = "pcm3060-hifi",
		.playback = {
			.stream_name = "Playback",
			.channels_min = 2,
			.channels_max = 2,
			.rates = PCM3060_DAI_RATES_DAC,
			.formats = SNDRV_PCM_FMTBIT_S24_LE,
		},
               .capture = {
			.stream_name = "Capture",
			.channels_min = 2,
			.channels_max = 2,
			.rates = PCM3060_DAI_RATES_ADC,
			.formats = SNDRV_PCM_FMTBIT_S24_LE,
		},
		.ops = &pcm3060_dai_ops,
	},
	{
		.name = "pcm3060-dummy",
		.capture = {
			.stream_name = "Capture",
			.channels_min = 2,
			.channels_max = 2,
			.rates = PCM3060_DAI_RATES_ADC,
			.formats = SNDRV_PCM_FMTBIT_S24_LE,
		},
	},
};

Also use below:

rc = devm_snd_soc_register_component(dev, &pcm3060_soc_comp_driver,
										 pcm3060_dai,
										 ARRAY_SIZE(pcm3060_dai));

Hello, spujar, thanks for your advice. I tried it once as you suggested.

Now the sound card can be registered normally, but it has encountered a new problem: the audio file cannot be played normally. When I play a WAV audio file by aplay, I can only hear a brief noise.

The kern log printed after power-on is as follows:
kern.log (105.8 KB)

You seem to have commented some part of the code which falls under macro check of “PCM3060_DAI_ID_DAC”. If the codec registers are not programmed as expected you are likely to see problems. For now add “PCM3060_DAI_ID_DAC” this to your DAI driver structure and uncomment the code. Make sure just playback works.

Eventually you need to replace such checks with playback or capture stream checks wherever applicable.

Hi, spujar, I uncommented on the PCM3060_DAI_ID_DAC and the audio file plays normally. But the recording does not work properly.

As I understand it, the role of the id is to distinguish different codec dai. But now we need to distinguish the stream name of the same codec dai. I’m not sure how to do this, can you give me some advice?

	if (dai->id == PCM3060_DAI_ID_DAC)
		reg = PCM3060_REG67;
	else
		reg = PCM3060_REG72;