Audio codec TLV320AIC3120 and devicetree config

We have a board with the tlv320aic3120. I’m having trouble configuring the devicetree. Searching the forums it appears to be more in-depth than the driver documentation mentions and for my limited knowledge. I’m on Jetpack 4.3.

We aren’t using a regulator. I’ve enabled the driver and dummy regulator in the kernel and modified the driver as mentioned in this post. I can run the following commands and see the codec:

i2cdetect -r -y 1
cat /sys/kernel/debug/asoc/codecs

My devicetree right now has:

   i2c@3160000 {
	  tlv320aic31xx: tlv320aic31xx@18 {
		compatible = "ti,tlv320aic3120";
		reg = <0x18>;
		status = "okay";
		gpio-reset = <19>;		
	  };
   };

I’m guessing I need something in the devicetree in tegra_sound based on other forum posts, but I don’t understand enough about what to configure.

Hello!

The process of integrating a new audio codec is complex indeed and if you are not familiar with the Linux ASoC infrastructure then it can be challenging. We have put some high-level details in the audio documentation for L4T to describe the process and this can be found here:

https://docs.nvidia.com/jetson/l4t/index.html#page/Tegra%20Linux%20Driver%20Package%20Development%20Guide%2Fasoc_driver.18.2.html%23wwpID0E0S20HA

Please note that do to the complexities with integrating audio codecs with Linux, the latest L4T release does include support for the following audio card with the SGTL5000 audio codec …

https://fe-pi.com/products/fe-pi-audio-z-v2

Regards,
Jon

Jon,

Thanks. I found that documentation not long before your response. I’ve been going in circles chasing down some error messages, but I’ve hit a dead end. I’ve modified tegra186-quill-common.dtsi. Currently it has:

i2c@3160000 {

        .....

		tlv320aic31xx: tlv320aic31xx@18 {
		compatible = "ti,tlv320aic3120";
		reg = <0x18>;
		
		status = "okay";
		
		/* Deprecated in future versions (used reset-gpios instead) */
		gpio-reset = <&tegra_main_gpio TEGRA_MAIN_GPIO(J, 6) GPIO_ACTIVE_LOW>; //GPIO3_PJ.06
	};
};

.....

tegra_sound: sound {
	compatible = "nvidia,tegra-audio-t186ref-mobile-rt565x";
	nvidia,model = "tegra-snd-t186ref-mobile-rt565x";
	nvidia,num-codec-link = <12>;
	clocks = <&tegra_car TEGRA186_CLK_PLLA>,
		 <&tegra_car TEGRA186_CLK_PLL_A_OUT0>,
		 <&tegra_car TEGRA186_CLK_AHUB>,
		 <&tegra_car TEGRA186_CLK_AUD_MCLK>;
	clock-names = "pll_a", "pll_a_out0", "ahub", "extern1";
	assigned-clocks = <&tegra_car TEGRA186_CLK_PLL_A_OUT0>,
			  <&tegra_car TEGRA186_CLK_AHUB>,
			  <&tegra_car TEGRA186_CLK_AUD_MCLK>;
	assigned-clock-parents = <&tegra_car TEGRA186_CLK_PLLA>,
				 <&tegra_car TEGRA186_CLK_PLL_A_OUT0>,
				 <&tegra_car TEGRA186_CLK_PLL_A_OUT0>;
	resets = <&tegra_car TEGRA186_RESET_AUD_MCLK>;
	reset-names = "extern1_rst";

	status = "okay";
	nvidia,audio-routing =
		"x Headphone",		"x HPL",
		"x Headphone",		"x HPR",
		"x Speaker",		"x SPK",
		"x MIC1LP",			"x Mic",
		"x MIC1RP",			"x Mic",
		"x MIC1LM",			"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",
		"d3 Headphone",		"d3 OUT";

	nvidia,xbar = <&tegra_axbar>;
	mclk-fs = <256>;

	rt565x_dai_link: nvidia,dai-link-1 {
		link-name = "tlv320aic31xx-codec";
		cpu-dai = <&tegra_i2s1>;
		codec-dai = <&tlv320aic31xx>;
		cpu-dai-name = "I2S1";
		codec-dai-name = "tlv320aic31xx-hifi";
		format = "i2s";
		bit-format = "s16_le";
		srate = <48000>;
		num-channel = <2>;
		ignore_suspend;
	    bitclock-master;
	    frame-master;
        frame-noninversion;
		name-prefix = "x";
		status = "okay";
	};

    ....

};

I also modified tegra_machine_driver_mobile.c to include the following (I’m not sure if I really need this though):

rtd = snd_soc_get_pcm_runtime(card, "tlv320aic31xx-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;
		dev_err(card->dev, "matched snd_soc_get_pcm_runtime");
 }

With this configuration when I get the following errors at boot time:

$ dmesg | grep tlv
[    1.620563] tlv320aic31xx-codec 0-0018: Unable to sync registers 0x1b-0x1d. -121
[    1.620568] tlv320aic31xx-codec 0-0018: Failed to restore cache: -121
[    1.630663] tlv320aic31xx-codec 0-0018: aic31xx_wait_bits: Failed! 0x25 was 0xffffffc0 expected 0x10 (-16, 0x10, 0 us)
[    1.630671] tlv320aic31xx-codec 0-0018: ASoC: POST_PMU: x SPK ClassD event failed: -1

After investigation I think I had the codec added to the wrong i2c in the devicetree because I see the following with i2cdetect. (Also, we are connected to I2C_GP0_CLK/DAT on the board)

$ i2cdetect -y -r 0
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: UU UU -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --  


$ i2cdetect -y -r 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- 18 -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --  

$ i2cdetect -l
i2c-3	i2c       	3190000.i2c                     	I2C adapter
i2c-1	i2c       	c240000.i2c                     	I2C adapter
i2c-8	i2c       	31e0000.i2c                     	I2C adapter
i2c-6	i2c       	31c0000.i2c                     	I2C adapter
i2c-4	i2c       	Tegra BPMP I2C adapter          	I2C adapter
i2c-2	i2c       	3180000.i2c                     	I2C adapter
i2c-0	i2c       	3160000.i2c                     	I2C adapter
i2c-7	i2c       	c250000.i2c                     	I2C adapter
i2c-5	i2c       	31b0000.i2c                     	I2C adapter

If I move the codec from i2c@3160000 to i2c@c240000 in the devicetree then there are no error messages in dmesg, but

$ i2cdetect -y -r 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --  

and I still don’t get any audio.

Any ideas where I’m going wrong?

Hello!

One of the biggest problem with integrated an I2S based codec on Linux is knowing how to configure the audio route for the codec and how to configure the codec itself. I2S codecs are not plug and play in the sense that once it is detected by I2C and the initial changes to device-tree have been made it will work. I see a lot of people send a lot of time getting various I2S codecs to work. In the L4T documentation [0] it is mentioned …

When you choose an audio codec to use with a Jetson device, be sure that:

•It is hardware-compatible in terms of functional pins (I2S, DMIC, etc.), GPIO, power, and clocks required to support the codec.

•It is compatible with the Jetson I2S interface (sample rates, sample sizes, frame formats, etc.).

•A Linux kernel driver is available for the codec

•ALSA examples are available for it to show how to configure its audio routing and general setup. Configuring the audio routing can be the most complex part of integrating an I2S codec.

Now you are using I2S1 and so the first thing to check is what the ‘x Playback’ DAPM widget is connected to …

$ sudo find /sys/kernel/debug/asoc/ -name 'x Playback'
$ sudo find /sys/kernel/debug/asoc/ -name 'x Playback' -exec cat {} \;

Hopefully it has a connection to both the I2S interface and codec. If the codec connection is missing we need to update the nvidia,audio-routing property to add a route.

Next it is then necessary to go through all the codec settings and make sure that they are configured appropriately …

$ amixer -c tegrasndt186ref controls | grep "name='x "

You may need to refer to both the codec driver and datasheet about how to configure these. In the codec driver look for all the SND_SOC_DAPM_MUX widgets to ensure that these are configured correctly to connect the HPL/R and/or SPK outputs to the I2S inputs.

Finally, you can verify that the audio route and codec path is good by running a trace …

$ echo 0 | sudo tee /sys/kernel/debug/tracing/trace
$ echo 0 | sudo tee /sys/kernel/debug/tracing/events/enable
$ echo 1 | sudo tee /sys/kernel/debug/tracing/tracing_on
$ echo 1 | sudo tee /sys/kernel/debug/tracing/events/asoc/snd_soc_dapm_path/enable
$ echo 1 | sudo tee /sys/kernel/debug/tracing/events/asoc/snd_soc_dapm_widget_power/enable
$ speaker-test -D hw:tegrasndt210ref,0 -c 2 -r 48000 -F S16_LE -t sine -f 500
$ sudo cat /sys/kernel/debug/tracing/trace

The trace should show a lot of output and you should see the path from ADMAIF all the way to the codec outputs HPL/R and/or SPK. An example trace can be seen here, but this is for capture and so slightly different [1].

Regards,
Jon

[0] https://docs.nvidia.com/jetson/l4t/index.html#page/Tegra%20Linux%20Driver%20Package%20Development%20Guide%2Fasoc_driver.18.2.html%23wwpID0E0S20HA
[1] https://docs.nvidia.com/jetson/l4t/index.html#page/Tegra%20Linux%20Driver%20Package%20Development%20Guide%2Fasoc_driver.18.2.html%23wwpID0E02C0HA

The tlv320aic3120 codec uses the tlv320aic31xx driver included in the Linux kernel.

Output of previous post commands:

$sudo find /sys/kernel/debug/asoc/ -name 'x Playback'
/sys/kernel/debug/asoc/tegra-snd-t186ref-mobile-rt565x/codec:tlv320aic31xx-codec.1-0018/dapm/x Playback

$ sudo find /sys/kernel/debug/asoc/ -name 'x Playback' -exec cat {} \;
x Playback: Off  in 0 out 0
 stream Playback inactive
 in  "static" "I2S1 DAP Transmit-x Playback"

$ amixer -c tegrasndt186ref controls | grep "name='x "
numid=864,iface=MIXER,name='x ADC Capture Switch'
numid=865,iface=MIXER,name='x ADC Capture Volume'
numid=863,iface=MIXER,name='x ADC Fine Capture Volume'
numid=1105,iface=MIXER,name='x DAC Left Input'
numid=870,iface=MIXER,name='x DAC Playback Volume'
numid=1106,iface=MIXER,name='x DAC Right Input'
numid=873,iface=MIXER,name='x HP Analog Playback Volume'
numid=871,iface=MIXER,name='x HP Driver Playback Switch'
numid=872,iface=MIXER,name='x HP Driver Playback Volume'
numid=1107,iface=MIXER,name='x HP Left Switch'
numid=1108,iface=MIXER,name='x HP Right Switch'
numid=1112,iface=MIXER,name='x MIC1LM M-Terminal'
numid=1111,iface=MIXER,name='x MIC1LM P-Terminal'
numid=1109,iface=MIXER,name='x MIC1LP P-Terminal'
numid=1110,iface=MIXER,name='x MIC1RP P-Terminal'
numid=866,iface=MIXER,name='x Mic PGA Capture Volume'
numid=1113,iface=MIXER,name='x Output Left From Left DAC'
numid=1114,iface=MIXER,name='x Output Left From MIC1LP'
numid=1115,iface=MIXER,name='x Output Left From MIC1RP'
numid=1117,iface=MIXER,name='x Output Right From MIC1RP'
numid=1116,iface=MIXER,name='x Output Right From Right DAC'
numid=869,iface=MIXER,name='x Speaker Analog Playback Volume'
numid=867,iface=MIXER,name='x Speaker Driver Playback Switch'
numid=868,iface=MIXER,name='x Speaker Driver Playback Volume'
numid=1118,iface=MIXER,name='x Speaker Switch'

$ sudo cat /sys/kernel/debug/tracing/trace
# tracer: nop
#
# entries-in-buffer/entries-written: 6/6   #P:4
#
#                              _-----=> irqs-off
#                             / _----=> need-resched
#                            | / _---=> hardirq/softirq
#                            || / _--=> preempt-depth
#                            ||| /     delay
#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
#              | |       |   ||||       |         |
alsa-sink-ADMAI-7167  [000] ....   256.660970: snd_soc_dapm_path: *ADMAIF1 Receive <- (direct) <- Playback 1
alsa-sink-ADMAI-7167  [000] ....   256.660976: snd_soc_dapm_path: *ADMAIF1 Receive <- (direct) <- ADMAIF1 CIF Receive-ADMAIF1 Receive
   speaker-test-7877  [003] ....   304.740858: snd_soc_dapm_path: *ADMAIF1 Receive <- (direct) <- Playback 1
   speaker-test-7877  [003] ....   304.740890: snd_soc_dapm_path: *ADMAIF1 Receive <- (direct) <- ADMAIF1 CIF Receive-ADMAIF1 Receive
alsa-sink-ADMAI-7167  [003] ....   313.141524: snd_soc_dapm_path: *ADMAIF1 Receive <- (direct) <- Playback 1
alsa-sink-ADMAI-7167  [003] ....   313.141532: snd_soc_dapm_path: *ADMAIF1 Receive <- (direct) <- ADMAIF1 CIF Receive-ADMAIF1 Receive

Any help from anyone? If I’m missing some routing I don’t understand what it is.

Hello!

Sorry for the delay. The routing looks to be OK. So the next thing to check the codec configuration. Looking at the codec route in the codec driver [0], we should check how the following are configured …

$ amixer -c tegrasndt186ref cget name='x HP Left Switch'
$ amixer -c tegrasndt186ref cget name='x HP Right Switch'
$ amixer -c tegrasndt186ref cget name='x HP Driver Playback Switch'
$ amixer -c tegrasndt186ref cget name='x DAC Left Input'
$ amixer -c tegrasndt186ref cget name='x DAC Right Input'

You want to ensure that the Left and Right inputs are configured as how you plan to use them and then you may just need to ensure that the other switches are turned on.

Regards,
Jon

[0] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/sound/soc/codecs/tlv320aic31xx.c#n642

Thanks. I realized I have no BCLK. It looks like the driver needs to call aic31xx_setup_pll, but it is not right now. At one point I know it was, but I’m not sure why it isn’t now.

I’m guessing my devicetree routing is incomplete or I need to set some other amixer settings due to the fact that aic31xx_setup_pll is not called and I have no BCLK. If I change my devicetree from

"x MIC1LP",		"x Mic",

to

"x MIC1LP P-Terminal",		"x Mic",

then I see aic31xx_setup_pll get called and I have BCLK when I open the Sound settings. I also get the following errors:

tegra210-i2s tegra210-i2s.0: Failed at I2S0_RX sw reset
tegra210-i2s tegra210-i2s.0: ASoC: PRE_PMU: I2S1 DAP RX event failed: -22

Also reported earlier I see the following, which looks like the codec isn’t seen:

$ sudo find /sys/kernel/debug/asoc/ -name 'x Playback' -exec cat {} \;
x Playback: Off  in 0 out 0
 stream Playback inactive
 in  "static" "I2S1 DAP Transmit-x Playback"

I checked the settings mentioned previously and they were all off. I turn them on, checked the other “name='x” settings, and still get nothing.

Hello!

What does the trace show now? I appears that it is trying to turn on the I2S interface which is a good sign …

$ echo 0 | sudo tee /sys/kernel/debug/tracing/trace
$ echo 0 | sudo tee /sys/kernel/debug/tracing/events/enable
$ echo 1 | sudo tee /sys/kernel/debug/tracing/tracing_on
$ echo 1 | sudo tee /sys/kernel/debug/tracing/events/asoc/snd_soc_dapm_path/enable
$ echo 1 | sudo tee /sys/kernel/debug/tracing/events/asoc/snd_soc_dapm_widget_power/enable
$ speaker-test -D hw:tegrasndt210ref,0 -c 2 -r 48000 -F S16_LE -t sine -f 500
$ sudo cat /sys/kernel/debug/tracing/trace

The error you are seeing is a common error if the BCLK is not enabled before the I2S interface is enabled. This causes the I2S soft reset to fail and the above error message is seen. So you need to ensure that the PLL is being turned on and the BCLK is active before the I2S soft reset function is called. It could be a problem with I2S pinmux not being configured correctly and so the I2S cannot detect the BCLK. If you dump the following we can check the pinmux …

$ sudo grep dap1 /sys/kernel/debug/tegra_pinctrl_reg

The pinmux values should be something like what is seen here:

Jon

The trace is the same as before. No change there.

$ sudo grep dap1 /sys/kernel/debug/tegra_pinctrl_reg
Bank: 0 Reg: 0x02431028 Val: 0x00000544 -> dap1_fs_pj3
Bank: 0 Reg: 0x02431030 Val: 0x00000554 -> dap1_din_pj2
Bank: 0 Reg: 0x02431038 Val: 0x00000504 -> dap1_dout_pj1
Bank: 0 Reg: 0x02431040 Val: 0x00000544 -> dap1_sclk_pj0

With regards to the pinmux, documentation seems to have gotten worse with later versions of L4T. I did modify the pinmux excel sheet and update the BCT. I’m guessing I ought to use the generated dtsi files in the devicetree that I flash but it was not very clear, nor am I finding which dtsi files I should overwrite/edit.

I have added a call to snd_soc_dai_set_sysclk to set it to 12MHz. With some debug code I do see that value being used. Probing MCLK I only see about 12.288MHz.

Correction on the trace. I had reverted my devicetree change. With the following set:

"x MIC1LP P-Terminal",		"x Mic",

the trace is:

Playback device is hw:tegrasndt186ref,0
Stream parameters are 48000Hz, S16_LE, 2 channels
Sine wave rate is 500.0000Hz
Playback open error: -16,Device or resource busy
# tracer: nop
#
# entries-in-buffer/entries-written: 0/0   #P:4
#
#                              _-----=> irqs-off
#                             / _----=> need-resched
#                            | / _---=> hardirq/softirq
#                            || / _--=> preempt-depth
#                            ||| /     delay
#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
#              | |       |   ||||       |         |

I have reverted back to

"x MIC1LP",		"x Mic",

I believe this is the proper setting anyways, which then begs the question: How do I get aic31xx_setup_pll to run so BCLK is setup?

I also ran the script mentioned in the linked post.
tegra-audio-debug.txt (555.4 KB)

Hello!

Looking at the pinmux I can see that you have a pull-down enabled on all pins, which is probably OK and the LPDR bit set. According the to TRM this …

“Enable Base Drivers when set High. Typically set when interfacing chips require minimal rise/fall time such as I2C.”

We don’t need to set this for I2S. However, the pins are correctly muxed for I2S. Yes the documentation for configuring the pinmux is not very good or clear and we are currently working to fix this. Essentially, the dtsi files that are outputted by the spreadsheet need to be converted to *.cfg files for Tegra186/Tegra194 devices. Assuming that you just have the standard TX2 and not the TX2i, as a shortcut you can directly modify the following file …

Linux_for_Tegra/bootloader/t186ref/BCT/tegra186-mb1-bct-pinmux-quill-p3310-1000-c03.cfg

You want to look for the following lines and update as follows …

pinmux.0x02431040 = 0x00000400; # dap1_sclk_pj0: i2s1, tristate-disable, input-disable
pinmux.0x02431038 = 0x00000400; # dap1_dout_pj1: i2s1, tristate-disable, input-disable
pinmux.0x02431030 = 0x00000458; # dap1_din_pj2: i2s1, pull-up, tristate-enable, input-enable
pinmux.0x02431028 = 0x00000400; # dap1_fs_pj3: i2s1, tristate-disable, input-disable

With regard to configuring the codec PLL, this function is called by the codec hw_params() function. This should be called whenever playback/capture is started. However, given that this is not being called implies that there is still an issue with the codec configuration/routing. Please note that although we use certain codecs we are not familiar with all the different codecs that are out there and so although we can give general guidance, we cannot explain exactly how to configure. Now based upon what you have said it appears that the hw_params() is getting called if you add ‘x MIC1LP P-Terminal’ to the route. I agree that that does not appear to be correct, but have you tried configuring this control instead? Looking at the dump of all the settings I see that it is ‘off’ by default …

	control.1109 {
		iface MIXER
		name 'x MIC1LP P-Terminal'
		value Off
		comment {
			access 'read write'
			type ENUMERATED
			count 1
			item.0 Off
			item.1 'FFR 10 Ohm'
			item.2 'FFR 20 Ohm'
			item.3 'FFR 40 Ohm'
		}
	}

Regards,
Jon

We are using the TX2-4GB. Thanks for pointing to the TRM. I hadn’t found anything previously on LPDR and was taking a stab in the dark. As for the pull-downs, that’s what is set in the pinmux Excel sheet by default, which I didn’t change. I did try the pinmux settings mentioned, but they didn’t seem to have any effect. Since I am running with bit and frame master, shouldn’t dap1_sclk_pj0 and dap1_fs_pj3 have input-enabled?

Either way, I still have the I2S errors previously mentioned. When then driver runs I see the aic31xx_set_bias_level run and turn on the BCLK. Then aic31xx_setup_pll runs, and then I get the I2S errors.

I hadn’t enabled/set ‘x MIC1LP P-Terminal’ or any of the other mic settings with amixer yet because I was more focused on playback (IMO: what good is capture if you can’t playback anything?). But since you mentioned it, I did set set it to item.1 and I did see the aic31xx_setup_pll function run. I can see it run when switching between Mono and Stereo Input in the Sound settings for the mic. I don’t get any sound input as the “Input level” bars never show anything coming in.

Another question I do have is when everything is working should the Sound settings show something besides “Analog Output: Built-in Audio” and “Analog Input: Built-in Audio”? I’m thinking I should see Headphone and Speaker as Outputs and 2 Mics as inputs.

Hello!

Yes you are correct, you should have the input-enabled for the sclk and fs pins and so you actually want …

pinmux.0x02431040 = 0x00000440; # dap1_sclk_pj0: i2s1, tristate-disable, input-enable
pinmux.0x02431038 = 0x00000440; # dap1_dout_pj1: i2s1, tristate-disable, input-disable
pinmux.0x02431030 = 0x00000458; # dap1_din_pj2: i2s1, pull-up, tristate-enable, input-enable
pinmux.0x02431028 = 0x00000440; # dap1_fs_pj3: i2s1, tristate-disable, input-enable

Yes for playback we obviously don’t care about the Mic. You had mentioned that you had changed the Mic routing and so I was looking at the other Mic settings.

OK, does the aic31xx_setup_pll() run before the tegra210_i2s_sw_reset() [0]? If it does then either …

  1. Pinmux is not set correctly
  2. The BCLK is not connected to the right pin.
  3. There is an IO voltage mismatch. If you are using the 40-pin header on the TX2 devkit board, there is a jumper (J24) can can select between 1.8 and 3.3V.
  4. The BCLK is not starting up quick enough (you could try adding a delay to tegra210_i2s_sw_reset())

Regards,
Jon

[0] https://nv-tegra.nvidia.com/gitweb/?p=linux-nvidia.git;a=blob;f=sound/soc/tegra-alt/tegra210_i2s_alt.c;h=9d1bcf83e3b475659bac24394acb7179d10b4ef2;hb=db1076bd60b78c1ceb370be6901b19b3987110a2#l104

Yes, aic31xx_setup_pll() is running before the tegra210_i2s_sw_reset(). I will check the options you mentioned.

  1. Here is my relevant pinmux settings.
  2. We verified BCLK is connected to right pin.
  3. We are using 1.8V on our board
  4. I tried several delays without any difference. If BCLK is not starting quick enough then I wonder if I have something configured incorrectly with MCLK. Our codec is receiving MCLK from the Jetson (I2S0_CLK). The codec driver expects an MCLK of either 12MHz or 12.5MHz [0]. I modified the machine driver to call snd_soc_dai_set_sysclk with a clock of 12MHz. In the devicetree I have srate = <48000>, mclk-fs = <250>. From a fresh boot, if I probe MCLK it is about 11.3 MHz. If I then open the sound settings and try a “Test Sound” then I see MCLK go to about 12.3MHz. I never actually see 12 MHz. When doing this, the debug statements I added to the machine driver I can see it go from a rate/clock of 44.1kHz/11.025MHz to 48kHz/12MHz. How can I get the Jetson to put out 12MHz on MCLK?

[0] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/sound/soc/codecs/tlv320aic31xx.c#n190

I did see the post Configuring frequency of AUDIO_MCLK. But it appears to use 256fs instead of 250fs as I set in my devicetree.

$ sudo grep aud_mclk /sys/kernel/debug/clk/clk_summary
   aud_mclk                                         1            1    12287998    12000000          0 0

Hello!

Per the above I believe you mean that the MCLK is being driven by the AUD_MCLK signal and not I2S0_CLK because this is the I2S bit clock.

By default the AUD_MCLK is configured to be 256 x fs. What changes did you make to make it 250 x fs? Note that if you want a constant 12MHz clock then unless you only plan to support a single sample rate, even setting to 250 will not work.

You should be able to use the nvidia,mclk-rate property in DT [0] to set the rate.

BTW, the codec driver appears to support slave mode [0] and so it can be easier to configure Tegra as the I2S BCLK and FSYNC master and the codec as slave. Then you can just have the MCLK configured as 256 x fs. You just need to ensure that you call snd_soc_dai_set_sysclk from the Tegra machine driver to set the codec MCLK rate on playback/capture start [1].

Regards,
Jon

[0] https://docs.nvidia.com/jetson/l4t/index.html#page/Tegra%20Linux%20Driver%20Package%20Development%20Guide%2Fasoc_driver.18.2.html%23wwpID0E0QS0HA
[1] https://nv-tegra.nvidia.com/gitweb/?p=linux-nvidia.git;a=blob;f=sound/soc/tegra-alt/machine_drivers/tegra_machine_driver_mobile.c;h=fbca4699d353de7e7eb2b8984c07efab954e5b15;hb=db1076bd60b78c1ceb370be6901b19b3987110a2#l314

Yes, I meant MCLK is driven by AUD_MCLK.

As mentioned ebfore, in the devicetree I set

mclk-fs = <250>;

Even with this set, AUD_MCLK is always 256 x fs. Only the requested rate is affected (250x). The actual rate is still a multiple of 256.

I’ve tried this. Again, only the requested rate is affected (250x). The actual rate is still a multiple of 256. If I remove “mclk-fs = <250>;” then I see an MCLK of almost 50MHz.

Actually the driver in the Nvidia sources only supports master mode. The main Linux kernel repo looks like the driver supports slave mode. It also looks like there are differences to account for the 4.9 vs 5.x kernel. I did poke around and the commit that enabled slave mode was pretty simple [0]. So I applied that to my build and used the pinmux mappings you first mentioned. As far as MCLK goes, nothing is different, but the I2S errors don’t occur.

[0] https://github.com/torvalds/linux/commit/77f8b3cfc33cd4231cc2748bcac9f43b9eea546c#diff-636e324870eaba7a16bfa5a1c7a306bd