I am having issues getting I2S working on the Xavier NX under JetPack 35.3.1 (kernel 5.10.104) and am seeking some assistance. It seems that the design of the ALSA soc drivers have changed from that used by older JetPack versions, and the documentation or examples I’m finding (frequently involving a ‘tegra-alt’ driver) seem to no longer apply for this kernel version.
This is a custom board with a MAX98365 audio codec, which is just a DAC accepting 2-channel I2S. ALSA DAPM requires a codec to establish a channel, so I’ve chosen to use the MAX98357A driver (have also tried simple-audio-amplifier). However, the codec is not the focus of this question, and I would be happy just being able to observe raw I2S output on the pins. These are the I2S0 pins, which seem to be attached to the I2S5 peripheral on this SoC.
I have tried to follow the examples to link I2S5 to the APE PCM via ADMAIF1. If I define the device tree as I’ve provided below, I can see the below output in dmesg (dynamic debugging is on so some rates are displayed).
[ 12.491417] tegra210_i2s_probe:1228: tegra210-i2s 2901400.i2s: can't retrieve I2S sync input clock
[ 16.191844] tegra_machine_dai_init:175: pll_a_out0 = 45158400 Hz, aud_mclk = 11289600 Hz, sample rate = 44100 Hz
[ 16.205230] tegra_machine_dai_init:175: pll_a_out0 = 45158400 Hz, aud_mclk = 11289600 Hz, sample rate = 44100 Hz
[ 16.216690] tegra210-i2s 2901400.i2s: timeout: failed to reset I2S for playback
[ 16.216921] tegra210-i2s 2901400.i2s: ASoC: PRE_PMU: I2S5 RX event failed: -110
Despite being overridden in the device tree, alsamixer control values seem to always load as 0. For example, ‘I2S5 FSYNC Width’ and ‘I2S5 codec master mode’ are both 0, which is not a valid selection. Is this normal? I have also tried to explicitly set every one of these controls via amixer, and I see no change in behavior: I run ‘aplay’ but I see no output on any pin.
- I am running all these tests on a freshly flashed device with no changes from the release other than a new kernel.
- To help with debugging, I’ve gathered trace events for asoc during boot, where it appears that I2S5 Mux gets routed to and from ADMAIF1. I have culled this down to list only the selected routes so that it’s actually readable. dapm_trace_snippets.txt (13.6 KB)
- I have also collected all alsamixer values for every control. amixer_contents.txt (215.6 KB)
Is there an obvious mistake I’m making, or is there an example that applies to JetPack 35.3.1 to just drive raw I2S5 output and no input?
Here is the relevant portion of the device tree. I’ve tried to explicitly set the sample rate and format to match the default FSYNC and BCLK values, but I don’t actually care what they are.
pinmux@2430000 {
pinmux_state: pinmux {
// I2S5
dap5_sclk_pt5 {
nvidia,pins = "dap5_sclk_pt5";
nvidia,function = "i2s5";
nvidia,pin-label = "i2s5_sclk";
nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
nvidia,enable-input = <TEGRA_PIN_ENABLE>;
nvidia,lpdr = <TEGRA_PIN_DISABLE>;
};
dap5_dout_pt6 {
nvidia,pins = "dap5_dout_pt6";
nvidia,function = "i2s5";
nvidia,pin-label = "i2s5_dout";
nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
nvidia,enable-input = <TEGRA_PIN_DISABLE>;
nvidia,lpdr = <TEGRA_PIN_DISABLE>;
};
dap5_din_pt7 {
nvidia,pins = "dap5_din_pt7";
nvidia,function = "i2s5";
nvidia,pin-label = "i2s5_din";
nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
nvidia,tristate = <TEGRA_PIN_ENABLE>;
nvidia,enable-input = <TEGRA_PIN_ENABLE>;
nvidia,lpdr = <TEGRA_PIN_DISABLE>;
};
dap5_fs_pu0 {
nvidia,pins = "dap5_fs_pu0";
nvidia,function = "i2s5";
nvidia,pin-label = "i2s5_fs";
nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
nvidia,enable-input = <TEGRA_PIN_ENABLE>;
nvidia,lpdr = <TEGRA_PIN_DISABLE>;
};
};};
tegra_sound: sound {
status = "okay";
compatible = "nvidia,tegra186-ape";
nvidia-audio-card,name = "NVIDIA Jetson Xavier NX APE";
clocks = <&bpmp_clks TEGRA194_CLK_PLLA>,
<&bpmp_clks TEGRA194_CLK_PLLA_OUT0>,
<&bpmp_clks TEGRA194_CLK_AUD_MCLK>;
clock-names = "pll_a", "pll_a_out0", "extern1";
assigned-clocks = <&bpmp_clks TEGRA194_CLK_AUD_MCLK>;
assigned-clock-parents = <&bpmp_clks TEGRA194_CLK_PLLA_OUT0>;
nvidia-audio-card,mclk-fs = <256>;
nvidia-audio-card,widgets =
"Headphone", "MONOAMP IntSpkr";
nvidia-audio-card,routing =
"MONOAMP IntSpkr", "MONOAMP Speaker";
};
// I2S DAC + Amplifier
// Could also use simple-audio-amplifier
max98365: max98365 {
#sound-dai-cells = <0>;
sound-name-prefix = "MONOAMP";
compatible = "maxim,max98357a";
sdmode-gpios = <&iox 7 GPIO_ACTIVE_HIGH>;
sdmode-delay = <0>;
status = "okay";
port {
max98365_ep: endpoint {
remote-endpoint = <&i2s5_dap_ep>;
mclk-fs = <256>;
link-name = "max98365-spkamp";
};
};
};
// ...
&tegra_i2s5 {
status = "okay";
fsync-width = <31>;
bclk-ratio = <64>;
};
&i2s5_to_codec {
link-name = "max98365-spkamp";
link-type = <C2C_LINK>;
format = "i2s";
srate = <48000>;
num-channel = <2>;
bit-format = "s32_le";
status = "okay";
bitclock-master;
frame-master;
i2s5_cpu: cpu {
sound-dai = <&tegra_i2s5 I2S_DAP>;
};
codec {
sound-dai = <&max98365>;
prefix = "MONOAMP";
};
};
&i2s5_dap_ep {
bitclock-master;
frame-master;
remote-endpoint = <&max98365_ep>;
};
Thank you.