I2S support for ADV7481

I am working on a carrier board for my employer which uses an ADV7481 to convert HDMI to CSI2 for the Jetson Xavier NX. I have managed to adapt a driver by Renesas for the ADV7482 to capture the video but I am now trying to handle audio.

I have registered the snd_soc_dai_ops structure with the driver and can see from the kernel logs that it is binding, but I receive an I/O error when running arecord.

The device tree include and driver source are attached.

adv7482.c (90.1 KB)
amp_adv_7481.dtsi (6.5 KB)

Hello!

A couple questions …

  1. What is the exact error that you are seeing?
  2. The device-tree ‘nvidia,audio-routing’ defines a route between the I2S interface and codec. However, I don’t see any DAPM widget defined in the codec driver. Typically, codec drivers define DAPM widgets like these. There are probably some messages in the dmesg output about the widgets no being found. Please attach the dmesg output.
  3. Do you call snd_soc_dai_set_sysclk() anywhere to set the sysclk frequency?

Thanks
Jon

Thank you; I have actually been experimenting with widgets but have had no luck so far. I have attached copy of my current experimental source.
adv7482.c (90.9 KB)
This is the kernel log from dmesg:
dmesg-210908-1127.log (87.4 KB)
I do not currently call snd_soc_dai_set_sysclk.

Hello!

Please also share the error message you see.

To call snd_soc_dai_set_sysclk() you would typically add an ‘init’ function like this to the Tegra machine driver. Then check for the presence of the DAI link for your codec in codec_init to register your init function with the appropriate DAI link.

I always recommend tracing the DAPM widgets when running arecord/aplay to see that the I2S is being enabled.

$ 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_widget_power/enable
$ arecord <params>
$ sudo cat /sys/kernel/debug/tracing/trace

Regards,
Jon

trace-210908-1158.log (432 Bytes)
dmesg-210908-1157.log (87.7 KB)
I’ve tried those commands but the trace comes back empty.

I will look at building the kernel source so that I can add the init function to the machine driver.

Hello!

What is the exact arecord command you are using?

You need to make sure that the I2S5 is mapped to the appropriate DMA interface. By default I2S5 should be mapped to ADMAIF0 and so you should use something like the following command …

$ arecord -D hw:jetsonxaviernxa,0 -c 2 -r 48000 -f S16_LE -d 10 cap.wav

You can check the mapping of I2S5 to the DMA interface by …

$ amixer -c jetsonxaviernxa cget name="ADMAIF0 Mux"

For more details please see this doc.

Regards,
Jon

I had been using

arecord -D hw:jetsonxaviernxa,0 -r 48000 -f S16_LE in.wav

I hadn’t included the -c 2; I have tried that but I still see an I/O error.

I had been using

amixer -c jetsonxaviernxa sget ‘ADMAIF1 Mux’

to verify that it was routed to I2S5 but said command is currently returning:

amixer: Mixer hw:1 load error: Input/output error

Said command has worked in the past so I will attempt to see why that is not currently working.

Hello!

Please be-careful with copy-paste. We have seen problems with the quotes when copied from the forum post.

Cheers
Jon

Hello!

Does ‘dmesg’ show any other errors?

The ‘-c 2’ just indicates 2 channels which is common for standard I2S, but not sure how many channels you are need to capture and if it is standard I2S signalling or something like TDM.

Jon

I have tried enabling the dynamic debug in /sys/kernel/debug/dynamic_debug/control
for soc-core.c, tegra_machine_driver_mobile.c, soc-pcm.c, soc-dapm.c and pcm.c to see if it sheds any light on the matter. I have attached a log.
dmesg-210909-0922.log (171.2 KB)
The reason for amixer not working seems to be related to the entry in adv7482_snd_controls; commenting it out gives me this:

amixer -c jetsonxaviernxa sget ‘ADMAIF1 Mux’
Simple mixer control ‘ADMAIF1 Mux’,0
Capabilities: enum
Items: ‘None’ ‘ADMAIF1’ ‘ADMAIF2’ ‘ADMAIF3’ ‘ADMAIF4’ ‘ADMAIF5’ ‘ADMAIF6’ ‘ADM
AIF7’ ‘ADMAIF8’ ‘ADMAIF9’ ‘ADMAIF10’ ‘ADMAIF11’ ‘ADMAIF12’ ‘ADMAIF13’ ‘ADMAIF14’
‘ADMAIF15’ ‘ADMAIF16’ ‘I2S1’ ‘I2S2’ ‘I2S3’ ‘I2S4’ ‘I2S5’ ‘I2S6’ ‘SFC1’ ‘SFC2’ ’
SFC3’ ‘SFC4’ ‘MIXER1-1’ ‘MIXER1-2’ ‘MIXER1-3’ ‘MIXER1-4’ ‘MIXER1-5’ ‘AMX1’ 'AMX2
’ ‘AMX3’ ‘AMX4’ ‘ARAD1’ ‘AFC1’ ‘AFC2’ ‘AFC3’ ‘AFC4’ ‘AFC5’ ‘AFC6’ ‘OPE1’ ‘SPKPRO
T1’ ‘MVC1’ ‘MVC2’ ‘IQC1-1’ ‘IQC1-2’ ‘IQC2-1’ ‘IQC2-2’ ‘DMIC1’ ‘DMIC2’ ‘DMIC3’ ‘D
MIC4’ ‘ADX1-1’ ‘ADX1-2’ ‘ADX1-3’ ‘ADX1-4’ ‘ADX2-1’ ‘ADX2-2’ ‘ADX2-3’ ‘ADX2-4’ ‘A
DX3-1’ ‘ADX3-2’ ‘ADX3-3’ ‘ADX3-4’ ‘ADX4-1’ ‘ADX4-2’ ‘ADX4-3’ ‘ADX4-4’ ‘ADMAIF17’
‘ADMAIF18’ ‘ADMAIF19’ ‘ADMAIF20’ ‘ASRC1-1’ ‘ASRC1-2’ ‘ASRC1-3’ ‘ASRC1-4’ ‘ASRC1
-5’ ‘ASRC1-6’
Item0: ‘I2S5’

However, this has not affected the behaviour of arecord.

Hello!

Is the trace still empty?

Could you please share the exact error message you see? After arecord fails, are there any additional error messages seen in dmesg?

Thanks
Jon

The error that I see is:

arecord: pcm_read:2103: read error: Input/output error

The only output from dmesg when I run arecord is:

[ 147.290933] ASoC: ADMAIF1 ↔ ADMAIF1 info:
[ 147.291047] ASoC: rate mask 0x1ffe
[ 147.291112] ASoC: min ch 1 max ch 16
[ 147.291178] ASoC: min rate 8000 max rate 192000
[ 147.305593] pll_a_out0 = 49152000 Hz, aud_mclk = 12288000 Hz, sample rate = 48000 Hz
[ 147.305823] tegra-asoc: sound: ASoC: failed to find rtd rt565x-playback
[ 147.305957] tegra-asoc: sound: ASoC: failed to find rtd rt565x-codec-sysclk-bclk1
[ 147.306099] tegra-asoc: sound: ASoC: failed to find rtd dspk-playback-r
[ 147.306296] tegra-asoc: sound: ASoC: failed to find rtd dspk-playback-l

I am still not seeing anything in trace.

Something that I have noticed this morning is that I have been calling devm_snd_soc_register_component to register the driver; should I actually be calling snd_soc_register_codec?

I have reimplemented the driver as a snd_soc_codec_driver and added an initialisation function to the machine driver. However, I am finding that the mclk_hw pointer is coming back as NULL, which causes the set_sysclk function to crash. I have by-passed this for now and I still see the same Input/output error message.

I now see the following in dmesg when I reun arecord but still no errors:

[ 236.651868] pll_a_out0 = 49152000 Hz, aud_mclk = 12288000 Hz, sample rate = 48000 Hz
[ 236.652077] tegra-asoc: sound: adv7481 runtime adv7482

I have also attached the latest source.
adv7482.c (91.9 KB)

I have been using the patch from the following post on the mailing list as a reference:
https://lore.kernel.org/driverdev-devel/20200323084011.GC4298@pflmari/T/
I can’t see exactly what is going on with the mclk_hw pointer but I’m assuming that it’s identifying the MCLK output from the ADV748x as a clock source.

I have found the issue with the sysclk; it turns out that snd_soc_codec_get_drvdata was returning the v4l2_subdev, not the adv7482_state.

I’ve been loloking further at the trace and if I run this command:

for FILE in $(sudo find /sys/kernel/debug/tracing/events/asoc -name enable); do echo 1 | sudo tee $FILE;done

I get a trace:

entries-in-buffer/entries-written: 8/8 #P:6

                         _-----=> irqs-off
                        / _----=> need-resched
                       | / _---=> hardirq/softirq
                       || / _--=> preempt-depth
                       ||| /     delay
      TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
         | |       |   ||||       |         |
    arecord-9084  [001] ....  1032.042985: snd_soc_dapm_start: card=jetson-xaviernx-ape
    arecord-9084  [001] ....  1032.044039: snd_soc_dapm_walk_done: jetson-xaviernx-ape: checks 2 power, 2 path, 0 neighbour
    arecord-9084  [001] ....  1032.044082: snd_soc_dapm_done: card=jetson-xaviernx-ape
    arecord-9084  [001] ....  1042.271344: snd_soc_dapm_start: card=jetson-xaviernx-ape
    arecord-9084  [001] ....  1042.272203: snd_soc_dapm_path: *ADMAIF1 Transmit -> (direct) -> Capture 1
    arecord-9084  [001] ....  1042.272213: snd_soc_dapm_path: *ADMAIF1 Transmit -> (direct) -> ADMAIF1 Transmit-ADMAIF1 CIF Transmit
    arecord-9084  [001] ....  1042.272767: snd_soc_dapm_walk_done: jetson-xaviernx-ape: checks 2 power, 2 path, 2 neighbour
    arecord-9084  [001] ....  1042.272811: snd_soc_dapm_done: card=jetson-xaviernx-ape

I’m currently lookin at widgets and routes. I’ve added the following code:

static const struct snd_kcontrol_new adv7482_snd_controls = {
};

static const struct snd_soc_dapm_widget adv7482_dapm_widgets = {
SND_SOC_DAPM_INPUT(“IN”),
};

static const struct snd_soc_dapm_route adv7482_dapm_routes = {
{ “Capture”, NULL, “IN” },
};

I currently see the following message when I insert the module:

[ 40.533556] adv7482 8-0071: ASoC: Failed to create x IN debugfs file

Is there something more that I need to add?

Hello!

It is most likely failing because it already exists. Looking at your device-tree snippet you have …

		nvidia,dai-link-1 {
			link-name = "spdif-dit-0";
			cpu-dai = <&tegra_i2s1>;
			codec-dai = <&spdif_dit0>;
			cpu-dai-name = "I2S1";
			codec-dai-name = "dit-hifi";
			format = "i2s";
			bit-format = "s16_le";
			srate = <48000>;
			num-channel = <2>;
			ignore_suspend;
			name-prefix = "x";
			status = "okay";
		};
		
		hdr40_snd_link_i2s: i2s_dai_link5: nvidia,dai-link-5 {
			link-name = "adv7481";
			cpu-dai = <&tegra_i2s5>;
			codec-dai = <&adv7481>;
			cpu-dai-name = "I2S5";
			codec-dai-name = "adv7482.8-0071";
			format = "i2s";
			bitclock-master;
			frame-master;
			bitclock-noninversion;
			frame-noninversion;
			bit-format = "s16_le";
			srate = <48000>;
			num-channel = <2>;
			ignore_suspend;
			name-prefix = "x";
			status = "okay";
		};

The name-prefix for each dai-link must be unique. You may wish the change the I2S1 name-prefix to ‘y’ to remove the dai-link completely.

Regards,
Jon

Thank you. I have tried this but I am still getting:

arecord: pcm_read:2103: read error: Input/output error

I noticed this on some of the runs:

WARNING: pll_d2 has no dyn ramp

I still do not see any errors in the kernel log but I get the following trace:

tracer: nop

entries-in-buffer/entries-written: 8/8 #P:6

_-----=> irqs-off

/ _----=> need-resched

| / _—=> hardirq/softirq

|| / _–=> preempt-depth

||| / delay

TASK-PID CPU# |||| TIMESTAMP FUNCTION

| | | |||| | |

     arecord-9009  [000] ....   414.147784: snd_soc_dapm_start: card=jetson-xaviernx-ape
     arecord-9009  [000] ....   414.148108: snd_soc_dapm_walk_done: jetson-xaviernx-ape: checks 2 power, 2 path, 0 neighbour
     arecord-9009  [000] ....   414.148122: snd_soc_dapm_done: card=jetson-xaviernx-ape
     arecord-9009  [000] ....   424.300905: snd_soc_dapm_start: card=jetson-xaviernx-ape
     arecord-9009  [000] ....   424.301451: snd_soc_dapm_path: *ADMAIF1 Transmit -> (direct) -> Capture 1
     arecord-9009  [000] ....   424.301458: snd_soc_dapm_path: *ADMAIF1 Transmit -> (direct) -> ADMAIF1 Transmit-ADMAIF1 CIF Transmit
     arecord-9009  [000] ....   424.301742: snd_soc_dapm_walk_done: jetson-xaviernx-ape: checks 2 power, 2 path, 2 neighbour
     arecord-9009  [000] ....   424.301785: snd_soc_dapm_done: card=jetson-xaviernx-ape

Hello!

It is interesting that the trace still does not show the I2S interface or the codec widgets. Can you run the following script and send the output …

outfile="${HOME}/tegra-audio-debug.txt"

if [ -f "${outfile}" ]; then
    rm "${outfile}"
fi

alsactl store -f "${outfile}"

dapm_dirs=$(sudo find /sys/kernel/debug/asoc -type d -name dapm)

for dir in ${dapm_dirs}; do
    sudo find ${dir} -type f -exec echo {} \; -exec cat {} \; >> "${outfile}"
done

echo "Tegra audio debug info written to ${outfile}"

Thanks
Jon

tegra-audio-debug.txt (534.9 KB)
Attached.