Trouble setting custom clock rate for ADC connected to an Orin nx

Dear Nvidia Support,

In my previous post I got the ADC( TLV320ADC3100) to work on the Orin nx using a the TEGRA234_CLK_AUD_MCLK clock and not changing its rate. However, I figured out for my setup I need the clock rate to be 24.576MHz in order to sync with hdmi video. I read the following from the audio section in the developer guide.
Audio Setup and Development — NVIDIA Jetson Linux Developer Guide

Be sure that the parent clock’s rate is an integer multiple of the rate set by AUD_MCLK. Choose the parent clock rate based on the MCLK rate that the codec requires.

I also read that I can override the parent clock rates but that is advised for only debug purposes.
Clocks — NVIDIA Jetson Linux Developer Guide

Non of the PLL_OUT clocks seem to be a integer multiple of 24.576MHz.

I would like to know the following information.

  1. Is there a way to create a custom parent clock?
  2. Why is the PLLA clock preferred over the PLLP clock or other clocks for audio?

Device Tree for reference

		i2c@3160000 {
			clocks-frequency = <100000>;
			status = "okay";

			/delete-node/ eeprom@50;
			/delete-node/ eeprom@57;
			/* ADC */
			tlv320adc3100: tlv320adc3100@18 {
				#sound-dai-cells = <0>;
				compatible = "ti,tlv320adc3100";
				status ="okay";
				reg = <0x18>;

				reset-gpios = <&gpio TEGRA234_MAIN_GPIO(Q, 6) GPIO_ACTIVE_LOW>;

				clocks = <&bpmp TEGRA234_CLK_AUD_MCLK>;
				clock-names = "mclk";
				AVDD-supply = <&reg_3p3v>;
				IOVDD-supply = <&reg_1p8v>;
				DVDD-supply = <&reg_1p8v>;

			};
		};
.
.
.
	sound {
		nvidia,num-codec-link = <1>;
		nvidia-audio-card,widgets =
			"Microphone",            "CVB-TLV Mic Jack";

		nvidia-audio-card,routing =
				"CVB-TLV IN_2L",       "CVB-TLV Mic Jack",
				"CVB-TLV IN_2R",       "CVB-TLV Mic Jack",
				"CVB-TLV Left ADC",    "CVB-TLV IN_2L",
				"CVB-TLV Right ADC",   "CVB-TLV IN_2R",
				"CVB-TLV AIF_OUT",    "CVB-TLV Left ADC",
				"CVB-TLV AIF_OUT",   "CVB-TLV Right ADC",
				"CVB-TLV Capture",     "CVB-TLV AIF_OUT";

		nvidia-audio-card,mclk-fs = <256>;
		/* ADC */
		i2s4_to_codec: nvidia-audio-card,dai-link@79 {
			link-name = "tlv320adc3xxx-hifi";
			codec {
				sound-dai = <&tlv320adc3100 0>;
				prefix = "CVB-TLV";
			};
		};
	};

Thank You

When I set the TEGRA234_CLK_AUD_MCLK to 24.576MHz and then check the clock it shows to be very close to 24.576MHz and PLLA_OUT0 changed it’s rate.

I used cat /sys/kernel/debug/bpmp/debug/clk/clk_tree to check the clock rates.

Before setting the fixed rate to 24.576MHz

    pll_a                                              1  270950390    2    1

        plla_out0                                      1   45158398    2    1

            aud_mclk                                   1   11289599    1    1 vdd_core@637304

After setting the fixed rate to 24.576MHz

    pll_a                                              1  294911718    2    1

        plla_out0                                      1   49151953    2    1

            aud_mclk                                   1   24575976    1    1 vdd_core@637304
  1. Why does this happen?
  2. Does this affect the I2S rate?
  3. Do I need to change the I2S rate?

There is not any information listed as to why this happens.

Just to give an overview, Audio PLLA supports two sampling rates i.e Multiple of 11.025KHz and 8KHz. The PLLA changes as per the sampling rate of usecase or file played.

>Why does this happen?

On Boot, it could be set to 44.1KHz, the reason could be Ubuntu GUI opens audio sampling rate with 44.1KHZ during boot. Later, if we start 48KHz the PLLA rate could change which might be the reason you see change in pll_a rate.

>Does this affect the I2S rate?

Yes, this will effect the I2S rate.

>Do I need to change the I2S rate?

It should be automatically taken care based on the I2S sampling rate usecase you are running. So no need to worry about explicitly configuring rates. Driver should take care.

Incase, to make AUD_MCLK fixed rate Audio Setup and Development — NVIDIA Jetson Linux Developer Guide . Also I could see AUD_MCLK clock handle is provided to codec driver, to make it fixed the codec driver should not change the rate as per sampling rate.

Thank you for the quick reply mkumard,

I set the AUD_MCLK to be a fixed rate by doing the following to the Device tree

	sound {
+		fixed-pll;
+		assigned-clocks = <&bpmp TEGRA234_CLK_PLLA_OUT0>, <&bpmp TEGRA234_CLK_AUD_MCLK>;
+		assigned-clock-parents = <&bpmp TEGRA234_CLK_PLLA>, <&bpmp TEGRA234_CLK_PLLA_OUT0>;
+		assigned-clock-rates = <0>, <24576000>;
+		nvidia-audio-card,mclk-fs = <512>;
		nvidia,num-codec-link = <1>;
		nvidia-audio-card,widgets =
			"Microphone",            "CVB-TLV Mic Jack";

		nvidia-audio-card,routing =
				"CVB-TLV IN_2L",       "CVB-TLV Mic Jack",
				"CVB-TLV IN_2R",       "CVB-TLV Mic Jack",
				"CVB-TLV Left ADC",    "CVB-TLV IN_2L",
				"CVB-TLV Right ADC",   "CVB-TLV IN_2R",
				"CVB-TLV AIF_OUT",    "CVB-TLV Left ADC",
				"CVB-TLV AIF_OUT",   "CVB-TLV Right ADC",
				"CVB-TLV Capture",     "CVB-TLV AIF_OUT";

		/* ADC */
		i2s4_to_codec: nvidia-audio-card,dai-link@79 {
			link-name = "tlv320adc3xxx-hifi";
			codec {
				sound-dai = <&tlv320adc3100 0>;
				prefix = "CVB-TLV";
			};
		};
	};

After these changes the PLLA and PLLA_OUT0 clock changed automatically.

    pll_a                                              1  294911718    2    1

        plla_out0                                      1   49151953    2    1

            aud_mclk                                   1   24575976    1    1 vdd_core@637304
  1. If I set the AUD_MCLK to a fixed rate and use fixed-pll; will the PLLA always adjust to make sure I can achieve the AUD_MCLK rate?
  2. In the developer guide it says to set the clk rates to be assigned-clock-rates = <368640000>, <49152000>, <12288000>; for 8x sampling rates.
    Do the clock rates need to be this or can they be other values?

Thank You

For fixed rate config, nvidia-audio-card,mclk-fs = <512>; should be removed from sound node.

assigned-clock-rates = <> in DT are applicable only during boot, This rate shall be changed by driver based on usecase requirement.

One question, does your requirement always need AUD_MCLK to be 24576000? How about support of 44.1 and 48KHz?. This rate is multiple of 48KHz.

Based on my knowledge it needs to be 24.576MHz in order for the Hdmi video to sync with the external audio. I do not care about supporting 44.1KHz recording, so I am fine with a fixed rate.

Based on you response are you suggesting that setting AUD_MCLK to be 24576000 is not a problem?

Yes, AUD_MCLK rate 24576000 could be derived from 48KHz PLLA. This should not be a problem unless you always running Multiple of 8KHz usecase which will always have PLLA set to fixed rate.

Make sure codec driver is not changing the AUD_MCLK rate as it was provided as a mclk clock input in codec node.

Thank you for the information and helping me out.

Dear Nvidia support,

While the advice i got seemed to have fixed the problem. It turns out while the clock rate was set to a fixed rate the ADC chip was not receiving any clock and the aud_clk was reported as 0 when configuring the clock in the codec drivers hw_params function.

It seems like there is a logic bug in the kernel/nvidia-oot/sound/soc/tegra/tegra_asoc_utils.c code.

tegra_asoc_utils_init() never sets the set_mclk variable for tegra234 boards, so set_mclk = 0.

Later when an audio session is started the tegra_asoc_utils_set_tegra210_rate() is called from kernel/nvidia-oot/sound/soc/tegra/tegra_machine_driver.c : tegra_machine_dai_init().

In tegra_asoc_utils_set_tegra210_rate() the set_mclk is 0 and mclk-fs is 0 so set_mclk is never configured.

int tegra_asoc_utils_set_tegra210_rate(struct tegra_asoc_utils_data *data,
				       unsigned int sample_rate,
				       unsigned int channels,
				       unsigned int sample_size)
{
	unsigned int new_pll_base, pll_out, aud_mclk = 0, req_bclk;
	int err;
.
.
.
update_mclk_rate:
	if (data->mclk_fs){
		aud_mclk = sample_rate * data->mclk_fs;
	}

	if (data->set_mclk != aud_mclk) {
		err = clk_set_rate(data->clk_cdev1, aud_mclk);
		if (err) {
			dev_err(data->dev, "Can't set clk_cdev1 rate: %d\n",
				err);
			return err;
		}
		data->set_mclk = aud_mclk;
	}

	return 0;
}

I am using the following device tree settings.

	sound {
+		fixed-pll;
+		assigned-clocks = <&bpmp TEGRA234_CLK_PLLA_OUT0>, <&bpmp TEGRA234_CLK_AUD_MCLK>;
+		assigned-clock-parents = <&bpmp TEGRA234_CLK_PLLA>, <&bpmp TEGRA234_CLK_PLLA_OUT0>;
+		assigned-clock-rates = <0>, <24576000>;
		nvidia,num-codec-link = <1>;
		nvidia-audio-card,widgets =
			"Microphone",            "CVB-TLV Mic Jack";

		nvidia-audio-card,routing =
				"CVB-TLV IN_2L",       "CVB-TLV Mic Jack",
				"CVB-TLV IN_2R",       "CVB-TLV Mic Jack",
				"CVB-TLV Left ADC",    "CVB-TLV IN_2L",
				"CVB-TLV Right ADC",   "CVB-TLV IN_2R",
				"CVB-TLV AIF_OUT",    "CVB-TLV Left ADC",
				"CVB-TLV AIF_OUT",   "CVB-TLV Right ADC",
				"CVB-TLV Capture",     "CVB-TLV AIF_OUT";

		/* ADC */
		i2s4_to_codec: nvidia-audio-card,dai-link@79 {
			link-name = "tlv320adc3xxx-hifi";
			codec {
				sound-dai = <&tlv320adc3100 0>;
				prefix = "CVB-TLV";
			};
		};
	};

Is this a bug in the nvidia code or is set_mclk suppose to be defined by me somewhere else?

Thank you

Hi

I believe the ask from your side is to fix the MCLK rate always, which is the proposal provided earlier to do from DT during boot.

When we fix the MCLK clock to fixed rate, the driver should not change the rate after boot or during any usecase. This is expected.

My question is, What is the reason for expecting to change the MCLK later when your requirement is fixed rate?

I am not expecting the MCLK to change later. The clocks from the device tree are being set correctly as seen by the command cat /sys/kernel/debug/bpmp/debug/clk/clk_tree. However currently MCLK is not being set during the boot process, so MCLK is always 0.

The machine driver does not set the MCLK to the listed rate in the device tree during the driver initialization.

In the following flow because my model is tegra234 in tegra_asoc_utils_init() MCLK is not set, so the MCLK stays 0.
kernel/nvidia-oot/sound/soc/tegra/tegra_machine_driver.c : tegra_machine_driver_probe()kernel/nvidia-oot/sound/soc/tegra/tegra_asoc_utils.c: tegra_asoc_utils_init()

int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
			  struct device *dev)
{
.
.
.
	if (data->soc < TEGRA_ASOC_UTILS_SOC_TEGRA210) {
		ret = tegra_asoc_utils_set_rate(data, 44100, 256 * 44100);
		if (ret)
			return ret;
	}
.
.
.

In tegra_asoc_utils_set_rate the set_mclk is configured. However since my model is tegra234 set_mclk is never configured.

Please note, this entry would configure the AUD_MCLK to 24576000 during boot by clock framework via BPMP. So, it is not required to again configured by the audio driver to set mclk as it is configured as fixed rate. If we probe the signal during usecases, the aud_mclk rate should be as per above rate config in DT.

If configuration is Fixed rate the set_mclk would be always 0 .

If that is the case then why do i not get a MCLK signal on the ADC’s MCLK pin?

If i only set nvidia-audio-card,mclk-fs = <512>; in the device tree i get a MCLK signal on the ADC’s MCLK pin.

Could you provide the cat /sys/kernel/debug/bpmp/debug/clk/clk_tree dump during the playback and without the above property in DT.

Here is the dump during playback when nvidia-audio-card,mclk-fs = <512> is set in the device tree.

cat /sys/kernel/debug/bpmp/debug/clk/clk_tree
.
.
.
    pll_a                                              1  294911718    2    1
        plla_out0                                      1   49151953    3    1
            aud_mclk                                   1   24575976    1    1 vdd_core@637304
            dmic1                                      0    3071997    0    0
            dmic2                                      0    3071997    0    0
            dmic3                                      0    9830390    0    0
            dmic4                                      0    3071997    0    0
            dspk1                                      0    9830390    0    0
            dspk2                                      0    9830390    0    0
            i2s1                                       0   49151953    0    0
            i2s2                                       0    1404341    0    0
            i2s3                                       0    1535998    0    0
            i2s4                                       1    1535998    1    1 vdd_core@637304
            i2s5                                       0    1535998    0    0
            i2s6                                       0   49151953    0    0
            i2s7                                       0   24575977    0    0
            i2s8                                       0   24575977    0    0

Here is the dump during playback when the following is set in the device tree

	sound {
+		fixed-pll;
+		assigned-clocks = <&bpmp TEGRA234_CLK_PLLA_OUT0>, <&bpmp TEGRA234_CLK_AUD_MCLK>;
+		assigned-clock-parents = <&bpmp TEGRA234_CLK_PLLA>, <&bpmp TEGRA234_CLK_PLLA_OUT0>;
+		assigned-clock-rates = <0>, <24576000>;
cat /sys/kernel/debug/bpmp/debug/clk/clk_tree
.
.
.
    pll_a                                              1  294911718    2    1
        plla_out0                                      1   49151953    3    1
            aud_mclk                                   1   24575976    1    1 vdd_core@637304
            dmic1                                      0    3071997    0    0
            dmic2                                      0    3071997    0    0
            dmic3                                      0   12287988    0    0
            dmic4                                      0    3071997    0    0
            dspk1                                      0   12287988    0    0
            dspk2                                      0   12287988    0    0
            i2s1                                       0   49151953    0    0
            i2s2                                       0    1404341    0    0
            i2s3                                       0    1535998    0    0
            i2s4                                       1    1535998    1    1 vdd_core@637304
            i2s5                                       0    1535998    0    0
            i2s6                                       0   49151953    0    0
            i2s7                                       0   49151953    0    0
            i2s8                                       0   49151953    0    0

Here is the error log that shows that the mclk is 0. The mclk pin has no signal on the oscilloscope as well.

[  929.018013] tlv320adc3xxx-codec 0-0018: Master clock rate 0 and sample rate 48000 is not supported
[  929.018022] tlv320adc3xxx-codec 0-0018: ASoC: error at snd_soc_dai_hw_params on tlv320adc3xxx-codec.0-0018: -22
[  929.018026] tegra-asoc: sound: ASoC: PRE_PMU: tlv320adc3xxx-hifi-capture event failed: -22

Above suggests AUD_MCLK clock is already enabled. The issue is usecase failed to start due to error in codec driver.

TLV codec trying to get information of AUD_MCLK clock rate which is failing, this could be due to missing snd_soc_dai_set_sysclk() call from machine driver to set the 245760000 rate to codec driver.

For e.g you can refer references in function tegra_machine_fepi_init() in tegra_codecs.c.

If you could point me the codec driver in upstream or attach the driver I could suggest a proper fix.

I am currently implementing this in the tegra_codecs.c file

int tegra_codecs_runtime_setup(struct snd_soc_card *card,
			       unsigned int srate,
			       unsigned int channels,
			       unsigned int aud_mclk)
{
.
.
.
	rtd = get_pcm_runtime(card, "tlv320adc3xxx-hifi");
	if (rtd) {
		err = snd_soc_dai_set_sysclk(rtd->dais[rtd->dai_link->num_cpus],
						 0,
					     aud_mclk, SND_SOC_CLOCK_IN);
		if (err < 0) {
			dev_err(card->dev, "dais[%d] clock not set\n",
				rtd->dai_link->num_cpus);
			return err;
		}
	}
.
.
.

Does the aud_mclk not get set when configuring a fixed rate clk in the device tree?
If so, I will change the rate argument in the function call to the 245760000 rate.

Yes, aud_mclk rate gets set to right frequency from DT.

The problem here is, the codec driver expects the input on aud_mclk rate which is missing, So codec driver is throwing error on aud_mclk rate as it doesn’t know what rate is actually set.

Yes, set the aud_mclk argument of set_sysclk to 245760000 as it is fixed rate in your case.

I understand, I will try this and reply how it goes.

Thank you

I have confirmed that the changes you suggested have fixed the problem.

Thank You