I2S/TDM ADX Demux

I am currently trying to integrate a pcm1865 codec with tegra asoc. I have managed to get I2S mode working by modifying pcm186x codec driver (albeit quite crude and hacky at the minute), the tegra_t186ref_mobile_rt565x machine driver and the device tree.

Codec/Machine settings:
capture format: 4 channel S16_LE
codec bitclock/frame master.
sysclock source is TX2 @ 12288000
codec sck → bck ratio: 1/4
codec bck → lrclk ratio: 1/64

I have scoped the clocks, they are good. I have scoped i2s_in and all the 4 channels are there.

In 4 channel TDM mode i have mapped ADMAIX1 Mux → ADX1-1, ADMAIX2 Mux → ADX1-2, ADMAIX3 Mux → ADX1-3, ADMAIX4 Mux → ADX1-4. I have also mapped ADX1 Mux → I2S1.

The above ADX demuxing doesnt appear to work. The DAPM routes are correct (i think) and the codec params are called correctly. No audio heard.

If i dont route the ADXs(and MAP ADMAIF1 MUX with I2S1). I can hear ADC1_R channel.

Any thoughts or guidance on using the ADX?

Regards
Chris

I realise that i haven’t set up the adx slot map. There is nothing mentioned on this in the driver development guide or the device tree bindings?

If i am wrong, please point me to the relevant documentation.

Regards,
Chris

Hi Chris,

Do you just want to capture 4 channels of audio? If so you don’t need to use the ADX. You can simply route the I2S data directly to the ADMAIF1 Mux (ie. I2S1 → ADMAIF1 Mux). For TDM testing this is what I do.

Regards,
Jon

Thanks for the response, Jonathan.

This will work with SND_SOC_DAIFMT_DSP_B?

I will at some point want to split the 4 channels into 4 seperate mono inputs, i assumed the ADX was the right way to go.

Regards,

Chris

Yes it will work with dsp-a/b modes. In fact these are the modes that I am using to test TDM.

OK, if you want to split the audio maybe the ADX is the right way to go. I will need to look at that.

Regards,
Jon

This almost worked. I have recorded to wav and can see 3 out of 4 channels have audio (first channel is empty). I will have to do some digging into the codec and tdm offsets etc to see why this might be happening.

Hi Chris,

BTW what L4T release are you using? There were alot of audio related fixes that went into rel28.2 for TX1/2 and I recommend using that if you are not. There was a bug with regard to the frame-sync polarity for dsp-a/b modes that was fixed in rel28.2.

Regards,
Jon

28.2, Jon.

Would be nice if we can get the ADX working. I will do some digging around the platform/codec drivers.

There are (unfortunately) huge gaps in the docs on this. Once i have this working completely i will share the drivers and adaptations to the community.

Chris

Hi Chris,

I will check on this. Yes the documentation is not complete (and has been out of date which I am trying to fix).

Regards
Jon

Ok, Jon. Thanks for your support.

Regards,
Chris

I can confirm that the pcm1865 codec is losing ADC1L in TDM (with my setup). I introduced a 2xBCK offset and all 4 channels are now there but the recording is now out of sync and noisey. Will do some digging.

Chris

Hi Chris,

Here is an example for using the ADX with I2S3 …

amixer -c 0 cset name=”ADX1 Mux” “I2S3”
// Route I2S output to ADX1 input

amixer -c 0 cset name=”ADMAIF1 Mux” “ADX1-1”
// Route ADX Output 1 to ADMAIF1 (hw:0,0)

amixer -c 0 cset name=”ADMAIF2 Mux” “ADX1-2”
// Route ADX Output 2 to ADMAIF2 (hw:0,1)

amixer -c 0 cset name=”ADMAIF3 Mux” “ADX1-3”
// Route ADX Output 3 to ADMAIF3 (hw:0,2)

amixer -c 0 cset name=”ADMAIF4 Mux” “ADX1-4”
// Route ADX Output 3 to ADMAIF4 (hw:0,3)

// Testing commands
arecord -D hw:0,0 -f DAT sample_rec.wav

Let me know if this helps.

Regards
Jon

Hi Chris,

Hang on, I don’t believe that the above is complete. There is some additional configuration that we need. I will update.

Regards,
Jon

Hi Jon, another update on the missing channel.

By changing LRCLK_DIV to 1/256 and BLCK_DIV to 1, all is well.

Now for ADX…

Regards,
Chris

Hi Chris,

Apologies here, but our documentation is a little incomplete on using the ADX. However, here is what I have found …

  1. If you look at the documentation from rel28.1 (not rel28.2 as it has been updated and legacy examples removed), under ‘System Configuration’ you will find the ‘Tegra ASoC Driver’ and under the ‘Machine Driver’ if you look at the ‘Tegra X2’ it is using the ADX and AMX blocks.

  2. To use the ADX we need to …
    a). Setup the ADX input/output params. This describes sample rate, sample size and number of channels, for the ADX input and ADX output. See tegra_t186ref_adx_input_params and tegra_t186ref_adx_output_params in [0]
    b). Setup the ADX slot map which tells the ADX which bytes of which channels to route to which ADX output. In the above documentation this is configured via DT but you can also configure via the driver as seen in tegra_t186ref_adx1_dai_init() [0]. The above documentation has some description of how the slot map is configured and so let me know if this is sufficient to get you started.
    c). Once configured then per comment #12 you should be able to setup the mapping of the ADX outputs to the ADMAIF.

Hope this gets you started.

Regards,
Jon

[0] nv-tegra.nvidia Code Review - linux-t18x.git/blob - sound/soc/tegra-alt/tegra_t186ref_alt.c

Hi Jon,

I have managed to get stereo on ADX1-1 working but nothing on ADX1-2. ADMAIF1 Mux → ADX1-1, ADMAIF2 Mux → ADX1-2. I have setup the slot maps as follows…

TDM_SLOT_MAP(0, 1, 0)
TDM_SLOT_MAP(0, 1, 1)
TDM_SLOT_MAP(0, 2, 0)
TDM_SLOT_MAP(0, 2, 1)
TDM_SLOT_MAP(1, 3, 0)
TDM_SLOT_MAP(1, 3, 1)
TDM_SLOT_MAP(1, 4, 0)
TDM_SLOT_MAP(1, 4, 1)

I believe this to be correct for a 2 x stereo (4 x mono) TDM input?

Regards,
Chris

Not sure how/why this works, but it works…

	nvidia,adx-slot-size = <32>;
	nvidia,adx-slot-map = <
		TDM_SLOT_MAP(0, 1, 0)
		TDM_SLOT_MAP(0, 1, 1)
		TDM_SLOT_MAP(1, 1, 0)
		TDM_SLOT_MAP(1, 1, 1)
		TDM_SLOT_MAP(2, 1, 0)
		TDM_SLOT_MAP(2, 1, 1)
		TDM_SLOT_MAP(3, 1, 0)
		TDM_SLOT_MAP(3, 1, 1)

		 /* jack 1 */
		 TDM_SLOT_MAP(0, 0, 0)
		 TDM_SLOT_MAP(0, 0, 0)
		 TDM_SLOT_MAP(0, 0, 0)
		 TDM_SLOT_MAP(0, 0, 0)
		 TDM_SLOT_MAP(0, 0, 0)
		 TDM_SLOT_MAP(0, 0, 0)
		 TDM_SLOT_MAP(0, 0, 0)
		 TDM_SLOT_MAP(0, 0, 0)
		 /* jack 2 */
		 TDM_SLOT_MAP(0, 0, 0)
		 TDM_SLOT_MAP(0, 0, 0)
		 TDM_SLOT_MAP(0, 0, 0)
		 TDM_SLOT_MAP(0, 0, 0)
		 TDM_SLOT_MAP(0, 0, 0)
		 TDM_SLOT_MAP(0, 0, 0)
		 TDM_SLOT_MAP(0, 0, 0)
		 TDM_SLOT_MAP(0, 0, 0)
		 /* jack 3 */
		 TDM_SLOT_MAP(0, 0, 0)
		 TDM_SLOT_MAP(0, 0, 0)
		 TDM_SLOT_MAP(0, 0, 0)
		 TDM_SLOT_MAP(0, 0, 0)
		 TDM_SLOT_MAP(0, 0, 0)
		 TDM_SLOT_MAP(0, 0, 0)
		 TDM_SLOT_MAP(0, 0, 0)
		 TDM_SLOT_MAP(0, 0, 0)>;

Chris

Hi Chris,

I have been looking at this a bit more, and what you have looks correct to me, but could be simplified as …

nvidia,adx-slot-size = <8>;
nvidia,adx-slot-map = <
TDM_SLOT_MAP(0, 1, 0)
TDM_SLOT_MAP(0, 1, 1)
TDM_SLOT_MAP(1, 1, 0)
TDM_SLOT_MAP(1, 1, 1)
TDM_SLOT_MAP(2, 1, 0)
TDM_SLOT_MAP(2, 1, 1)
TDM_SLOT_MAP(3, 1, 0)
TDM_SLOT_MAP(3, 1, 1)>;

So each TDM_SLOT_MAP entry maps an input byte in the frame to an output byte on one of the ADX outputs. In your case each ADX output only has 1 channel and is made up of two bytes. So looking at the above, where there are 4 channels each with 16 bits and so a total of 8 bytes, we have …

Input frame byte 0 → slot map entry 0 → ADX1-1 output channel 1 byte 0
Input frame byte 1 → slot map entry 1 → ADX1-1 output channel 1 byte 1
Input frame byte 2 → slot map entry 2 → ADX1-2 output channel 1 byte 0
Input frame byte 3 → slot map entry 3 → ADX1-2 output channel 1 byte 1
Input frame byte 4 → slot map entry 4 → ADX1-3 output channel 1 byte 0
Input frame byte 5 → slot map entry 5 → ADX1-3 output channel 1 byte 1
Input frame byte 6 → slot map entry 6 → ADX1-4 output channel 1 byte 0
Input frame byte 7 → slot map entry 7 → ADX1-4 output channel 1 byte 1

Let me know if this helps.

Regards,
Jon

Thanks, Jon.

I did try this to no avail. I will retry incase I made a mistake. I will let you know next Monday (on holiday).

Regards,
Chris

One more thing… Does the ADX support other formats, i.e. S32LE? Obviously I’ll have to make a few changes to the driver, just need to know if the hw supports it.

Chris