Audio codec TLV320AIC3120 and devicetree config

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

Alright, so I don’t really understand the MCLK stuff (I want 12 MHz but I get 256 x fs). I forgot to actually test the microphone input earlier. In slave mode the microphone does work. I can record and playback on another machine. The headphones and speaker still don’t work, which I guess means the routing is incomplete. I’ll try and figure that out now.

Hello!

Typically, if the codec is the BCLK slave, then the MCLK is scaled by a factor of 128, 256 or 512. By defaul the audio PLL is driven by a 38.4MHz clock (you can see this from the /sys/debug/kernel/clk/clk_summary output which is a clock tree) and so when requesting 250 x FS the PLL is unable to generate an exact 12MHz clock. What you need to do is change the parent clock for the AUD_MCLK. You can view the possible parent clocks for the AUD_MCLK by …

$ sudo cat /sys/kernel/debug/clk/aud_mclk/clk_possible_parents
pllp_grtbb pll_p_out0 pll_a_out0 clk_32k clk_m

If you look at the rate of pll_p_out0 you will see it is …

$ sudo grep pll_p_out0 /sys/kernel/debug/clk/clk_summary
       pll_p_out0                                          14           14   408000000   408000000          0 0 

Now 408MHz is evenly divisble by 12MHz and so this would be a good parent for the AUD_MCLK.

Under the sound node we should be able to use the ‘assigned-clock’ DT properties [0] to configure the AUD_MCLK parent and rate …

                 assigned-clocks = <&tegra_car TEGRA186_CLK_PLL_A_OUT0>,
                                   <&tegra_car TEGRA186_CLK_AUD_MCLK>;
                 assigned-clock-parents = <&tegra_car TEGRA186_CLK_PLLA>,
                                    <&tegra_car TEGRA186_CLK_PLLP_OUT0>;
                 assigned-clock-rates = <0>, <12000000>;

Note that you should also remove the ‘mclk-fs’ property completely to prevent the machine driver from attempting to scale the MCLK relative to the FS.

Regards
Jon

Great! Thanks. I’ll try that when I am back at the office (probably next week sometime).

I did get the routing on the headphones fixed (driver change, will post exact fix later) and was able to get audio out.

The routing on the speakers is broken. It appears to be a circular route inside the codec driver. There might be some naming conflict between the codec driver and the machine driver both using ‘x Speaker’.

This worked for getting a 12MHz mclk. How is this different than the following?

sound {
        nvidia,mclk-rate = <mclk_fixed_rate>;
        mclk_parent = <mclk parent> //optional
};

I believe I have the Speakers routed correctly but I’m not getting any sound. I modified the devicetree routing for the speakers to be:

"x Int Spk",  "x SPK",

Any thoughts?

tegra-audio-debug.txt (556.0 KB)

Hello!

Yes routing the ‘x SPK’ to the ‘x Int Spk’ should be fine. You can check to see if the route looks good by tracing the DAPM path …

$ 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

Regards,
Jon

Here the output. The headphones play, but not the speakers.

trace.txt (23.1 KB)

We checked our board again and ended up removing the codec and putting it back on. The speakers now work. I will post my final configuration soon to sum up everything.

I still have the question of what is the difference is between

assigned-clocks = <&tegra_car TEGRA186_CLK_PLL_A_OUT0>,
                               <&tegra_car TEGRA186_CLK_AUD_MCLK>;
assigned-clock-parents = <&tegra_car TEGRA186_CLK_PLLA>,
                                <&tegra_car TEGRA186_CLK_PLLP_OUT0>;
assigned-clock-rates = <0>, <12000000>;

and

nvidia,mclk-rate = <12000000>;
mclk_parent = <&tegra_car TEGRA186_CLK_PLLP_OUT0>;

These obviously do something different but the documentation only mentions the latter [0].

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

Here’s a complete breakdown of the changes I made to get things working with the TX2-4GB. We ended up switching from the TLV320AIC3120 to the TLV320AIC3100. What I have here should work for both codecs. Hopefully this helps some other newbie to audio codecs figure things out.

In the end, one thing that became particularly helpful for me was

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

This pointed me to the folder

/sys/kernel/debug/asoc/tegra-snd-t186ref-mobile-rt565x/codec:tlv320aic31xx-codec.1-0018/dapm/

Inspecting the files in this folder will show how the audio is routed. If things don’t work, then start mapping the audio route from the codec input/output back to I2S (x Playback).

My complete devicetree changes are:

File: kernel_src/hardware/nvidia/platform/t18x/common/kernel-dts/t18x-common-platforms/tegra186-qill-common.dtsi


i2c@c240000 {

    ...

+    tlv320aic31xx: tlv320aic31xx@18 {
+            compatible = "ti,tlv320aic3100";
+            reg = <0x18>;
+
+            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>;
+                                        <&tegra_car TEGRA186_CLK_PLLP_OUT0>;
+               assigned-clock-rates = <0>, <0>, <12000000>;
                resets = <&tegra_car TEGRA186_RESET_AUD_MCLK>;
		reset-names = "extern1_rst";

		status = "okay";
		nvidia,audio-routing =
-                       "x Headphone",  "x OUT",
-                       "x IN",         "x Mic",
+                       "x Headphone",  "x HPL",
+                       "x Headphone",  "x HPR",
+                       "x Int Spk",    "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 = "spdif-dit-0";
+                       link-name = "tlv320aic31xx-codec";
                        cpu-dai = <&tegra_i2s1>;
-                       codec-dai = <&spdif_dit0>;
+                       codec-dai = <&tlv320aic31xx>;
                        cpu-dai-name = "I2S1";
-                       codec-dai-name = "dit-hifi";
+                       codec-dai-name = "tlv320aic31xx-hifi";
                        format = "i2s";
                        bit-format = "s16_le";
                        srate = <48000>;
                        num-channel = <2>;
                        ignore_suspend;
                        name-prefix = "x";
                        status = "okay";
		};

...

};

Codec driver changes for slave mode [0]:

File: kernel_src/kernel/kernel-4.9/sound/soc/codecs/tlv320aic31xx.c

static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
                               unsigned int fmt)
{
        struct snd_soc_codec *codec = codec_dai->codec;
        u8 iface_reg1 = 0;
        u8 iface_reg2 = 0;
        u8 dsp_a_val = 0;

        dev_dbg(codec->dev, "## %s: fmt = 0x%x\n", __func__, fmt);

        /* set master/slave audio interface */
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBM_CFM:
                iface_reg1 |= AIC31XX_BCLK_MASTER | AIC31XX_WCLK_MASTER;
                break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+               iface_reg1 |= AIC31XX_WCLK_MASTER;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               iface_reg1 |= AIC31XX_BCLK_MASTER;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
        default:
                dev_alert(codec->dev, "Invalid DAI master/slave interface\n");
                return -EINVAL;
        }

Codec driver changes to correct audio routing so I2S was connected to the codec [1] (‘x Playback’ DAPM widget):

File: kernel_src/kernel/kernel-4.9/sound/soc/codecs/tlv320aic31xx.c

static const struct snd_soc_dapm_widget common31xx_dapm_widgets[] = {
        SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0),

        SND_SOC_DAPM_MUX("DAC Left Input",
                         SND_SOC_NOPM, 0, 0, &ldac_in_control),
        SND_SOC_DAPM_MUX("DAC Right Input",
                         SND_SOC_NOPM, 0, 0, &rdac_in_control),
        /* DACs */
-       SND_SOC_DAPM_DAC_E("DAC Left", "Left Playback",
+       SND_SOC_DAPM_DAC_E("DAC Left", "Playback"
                           AIC31XX_DACSETUP, 7, 0, aic31xx_dapm_power_event,
                           SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),

-       SND_SOC_DAPM_DAC_E("DAC Right", "Right Playback",
+       SND_SOC_DAPM_DAC_E("DAC Right", "Playback",
                           AIC31XX_DACSETUP, 6, 0, aic31xx_dapm_power_event,
                           SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),

....

Codec driver changes fro dummy regulator:

File: kernel_src/kernel/kernel-4.9/sound/soc/codecs/tlv320aic31xx.c

-#define AIC31XX_NUM_SUPPLIES	6
+#define AIC31XX_NUM_SUPPLIES	1
static const char * const aic31xx_supply_names[AIC31XX_NUM_SUPPLIES] = {
-	"HPVDD",
-	"SPRVDD",
-	"SPLVDD",
-	"AVDD",
-	"IOVDD",
-	"DVDD",
+	"dummy",
};

Machine driver changes:

File: kernel_src/kernel/nvidia/sound/soc/tegra-alt/machine_drivers/tegra_machine_driver_mobile.c

+#include "tlv320aic31xx.h"

....


static int tegra_machine_dai_init(struct snd_soc_pcm_runtime *runtime,
				  unsigned int rate, unsigned int channels,
				  u64 formats)
{

....

+        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;
+        }
+
        rtd = snd_soc_get_pcm_runtime(card, "rt565x-playback");

....

}

....



+static int tegra_machine_tlv320aic31xx_init(struct snd_soc_pcm_runtime *rtd)
+{
+    struct device *dev = rtd->card->dev;
+    int err;

+    err = snd_soc_dai_set_sysclk(rtd->codec_dai, AIC31XX_PLL_CLKIN_MCLK, 12000000,
+                                 SND_SOC_CLOCK_IN);
+    if (err) {
+            dev_err(dev, "failed to set tlv320aic31xx sysclk!\n");
+            return err;
+    }
+
+    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, "tlv320aic31xx-codec"))
+                        dai_links[i].init = tegra_machine_tlv320aic31xx_init;
	}

	return 0;
}

Kernel config changes:

CONFIG_SND_SOC_TLV320AIC31XX=y
CONFIG_REGULATOR_DUMMY=y

Pinmux settings:

Amixer settings (Note: I configured the headphones in Mono output):

amixer -c tegrasndt186ref cset name='x ADC Capture Switch' on
amixer -c tegrasndt186ref cset name='x ADC Capture Volume' 64
amixer -c tegrasndt186ref cset name='x ADC Fine Capture Volume' 4
amixer -c tegrasndt186ref cset name='x DAC Left Input' 3
amixer -c tegrasndt186ref cset name='x DAC Playback Volume' 127
amixer -c tegrasndt186ref cset name='x DAC Right Input' 3
amixer -c tegrasndt186ref cset name='x HP Analog Playback Volume' 127,127
amixer -c tegrasndt186ref cset name='x HP Driver Playback Switch' on,on
amixer -c tegrasndt186ref cset name='x HP Driver Playback Volume' 7,7
amixer -c tegrasndt186ref cset name='x HP Left Switch' on
amixer -c tegrasndt186ref cset name='x HP Right Switch' on
amixer -c tegrasndt186ref cset name='x MIC1LM M-Terminal' 1
amixer -c tegrasndt186ref cset name='x MIC1LM P-Terminal' 1 
amixer -c tegrasndt186ref cset name='x MIC1LP P-Terminal' 1
amixer -c tegrasndt186ref cset name='x MIC1RP P-Terminal' 1
amixer -c tegrasndt186ref cset name='x Mic PGA Capture Volume' 80
amixer -c tegrasndt186ref cset name='x Output Left From Left DAC' on
amixer -c tegrasndt186ref cset name='x Output Left From MIC1LP' on
amixer -c tegrasndt186ref cset name='x Output Left From MIC1RP' on
amixer -c tegrasndt186ref cset name='x Output Right From MIC1RP' on
amixer -c tegrasndt186ref cset name='x Output Right From Right DAC' on
amixer -c tegrasndt186ref cset name='x Speaker Analog Playback Volume' 127
amixer -c tegrasndt186ref cset name='x Speaker Driver Playback Switch' on
amixer -c tegrasndt186ref cset name='x Speaker Driver Playback Volume' 3
amixer -c tegrasndt186ref cset name='x Speaker Switch' on

[0] https://github.com/torvalds/linux/commit/77f8b3cfc33cd4231cc2748bcac9f43b9eea546c
[1] Sound card transplantation

Hello!

Thanks for the update and sharing this!

Regards,
Jon