Microsemi zl38063 microphone

Hello,
we made a custom carrier board for the Nvidia Jetson TX2. The carrier board is equipped with a Microsemi zl38063 audio processor. The connections between the Jetson TX2 and the audio processor are reported below.

Jetson       Pin Net           ZLS38063

I2S0_CLK     G2  I2S0_CLK      ZL_HI2S_SCKA
I2S0_LRCLK   H1  I2S0_LRCLK    ZL_HI2S_WSA
I2S0_SDIN    G1  I2S0_SDIN     ZL_I2S_SDOA
I2S0_SDOUT   H2  I2S0_SDOUT    ZL_I2S_SDIA

I2S1_CLK     C15 I2S1_CLK      ZL_HI2S_SCKB
I2S1_LRCLK   D13 I2S1_LRCLK    ZL_HI2S_WSB
I2S1_SDIN    C14 I2S1_SDIN     ZL_I2S_SDOB
I2S1_SDOUT   D14 I2S1_SDOUT    ZL_I2S_SDIB

We would like to add a new audio codec and disable the current one (rt565x). Could you please indicate to us the needed changes to the device tree in order to perform this task? In addition, what are the steps to follow to instantiate the codec and the audio card?

Thanks in advance for your help.

Hello!

I see that the Microsemi audio processor has a I2C/SPI control interface, is this also connected to Tegra? Do you know if there is a Linux driver available for this audio processor? If not then how do you plan to handle the configuration of the audio processor?

Although the audio machine driver for TX2 references the rt565x codec, because there is no rt565x codec on the Jetson TX2 board by default, this codec is not actually linked to any of the I2S interfaces in device-tree. By default all the I2S interfaces use a dummy codec (spdif) which is needed so that we can drive the I2S pins without having a physical codec connected. Therefore, on the TX2, if you attempt to play any audio file to the I2S interfaces you should see the pins toggle …

For example, to play a 500Hz tone on I2S1 (I2S0 pins) …

$ amixer -c tegrasndt86ref cset name="I2S1 Mux" ADMAIF1
$ speaker-test -D hw:tegrasndt186ref,0 -c 2 -r 48000 -F S16_LE -t sine -f 500

For example, to play a 500Hz tone on I2S2 (I2S1 pins) …

$ amixer -c tegrasndt86ref cset name="I2S2 Mux" ADMAIF2
$ speaker-test -D hw:tegrasndt186ref,1 -c 2 -r 48000 -F S16_LE -t sine -f 500

The above assumes that the pinmux has been correctly setup for the board to enable the I2S0/1 pins.

Regards,
Jon

Hello Jon,
thanks for your prompt response.

Yes, the Microsemi microphone is connected via SPI interface to Tegra.

Microsemi provided us with a codec and a machine driver for its microsemi audio processor. However, the machine driver is not designed for the Tegra platform. Also, it does not support the Tegra Audio Hub.

Currently, we are proceeding through the following steps.

First, we disabled the rt565x driver.

tegra_sound: sound {
status = "disabled";
};

Then, we modified the device tree so that the Microsemi codec is used.

zl380xx_sound {
compatible = "nvidia,tegra-audio-t186ref-mobile-rt565x";
nvidia,model = "audio-zl38xx0";

nvidia,num-codec-link = <1>;
nvidia,num-clk = <8>;
nvidia,clk-rates = < 270950400 / PLLA_x11025_RATE /
11289600 / AUD_MCLK_x11025_RATE /
45158400 / PLLA_OUT0_x11025_RATE /
45158400 / AHUB_x11025_RATE /
245760000 / PLLA_x8000_RATE /
12288000 / AUD_MCLK_x8000_RATE /
49152000 / PLLA_OUT0_x8000_RATE /
49152000 >; / AHUB_x8000_RATE /
clocks = <&tegra_car TEGRA186_CLK_PLLP_OUT0>,
<&tegra_car TEGRA186_CLK_PLLA>,
<&tegra_car TEGRA186_CLK_PLL_A_OUT0>,
<&tegra_car TEGRA186_CLK_AHUB>,
<&tegra_car TEGRA186_CLK_CLK_M>,
<&tegra_car TEGRA186_CLK_AUD_MCLK>;
clock-names = "pll_p_out1", "pll_a", "pll_a_out0", "ahub",
"clk_m", "extern1";
resets = <&tegra_car TEGRA186_RESET_AUD_MCLK>;
reset-names = "extern1_rst";

status = "okay";
nvidia,audio-routing =
"x Headphone", "x OUT",
"x IN" , "x Mic";

nvidia,xbar = <&tegra_axbar>;

zl380_dai_link: nvidia,dai-link-1 {
link-name = "rt565x-playback";
cpu-dai = <&tegra_i2s1>;
codec-dai = <&zl380_codec>;
cpu-dai-name = "I2S1";
codec-dai-name = "zl380xx-dai";
format = "i2s";
bitclock-slave;
frame-slave;
bitclock-noninversion;
frame-noninversion;
bit-format = "s16_le";
bclk_ratio = <0>;
srate = <48000>;
num-channel = <2>;
ignore_suspend;
name-prefix = "x";
status = "okay";
};

In order to proceed further, we would like to ask you if you can provide us with a skeleton of an audio codec driver that uses the tegra audio machine driver.

Thanks in advance for your help.

Hello!

The approach you have taken above is correct, and customising the Tegra audio machine driver is what we would advise. However, we cannot provide a skeleton for the audio codec driver for the zl38063, this should come from Microsemi. If Microsemi have provided a codec driver for the zl38063, there is no reason why you cannot use this inconjunction with the Tegra audio machine driver. We can assist with the customisation of the Tegra audio machine driver, but we would need to see the zl38063 codec and machine drivers to do so.

Regards,
Jon

Hello Jon,
you can find the zl38063 codec here https://gist.github.com/lrodorigo/2ae9c97ff9c07b42c44ef5d15216f882

Please note that we removed all the proprietary code from the codec.

We modified the device tree as follows:

zl380_dai_link: nvidia,dai-link-1 {
link-name = "rt565x-playback";
cpu-dai = <&tegra_i2s1>;
codec-dai = <&zl380_codec>;
cpu-dai-name = "I2S1";
codec-dai-name = "zl380xx-dai";
format = "i2s";
bitclock-master;
frame-master;
bitclock-noninversion;
frame-noninversion;
bit-format = "s16_le";
bclk_ratio = <0>;
srate = <48000>;
num-channel = <2>;
ignore_suspend;
name-prefix = "x";
status = "okay";
};

We tried the amixer commands you provided to us. However, no clock is generated on the i2s interface.

Hello!

From the device-tree snippet provide, I see that the zl38063 is both the I2S bit-clock and frame master, which is fine, but wanted to confirm that that is your intention. The DAI link is always from the perspective of the codec and sometimes people can overlook that.

Given that the zl38063 is the bitclock and frame master, I assume that the zl38063 device has its own oscillator and internal PLL that is used to generate the clocks and there is no master clock being provide by Tegra. Generally I would expect the codec to be the master when its internal PLL is used.

With regard to the no clock being generated, this can occur when the audio route through the codec is not complete. By this I mean that the codec is not configured correctly to route the audio from the I2S interface to the analog inputs/outputs. Typically, codecs have various audio paths with muxes that need to be configured to route the audio.

For example, the SGTL5000 codec defines sgtl5000_dapm_routes [0], where in the I2S side you have AIFIN and AIFOUT for the I2S input and output and then you have HP_OUT, LINE_OUT, MIC_IN and LINE_IN for the analog outputs and inputs. The paths from the I2S inputs/outputs are connected by routes to the analog inputs/outputs and need to be configured via various mixer settings using ‘amixer’. The SGTL50000 codec is quite simple but other codecs have much more complex routing.

The driver provided for the zl38063 shows no routing information, but I would have expected this to exist in the complete driver. Hopefully microsemi can provide support for how to configure the codec using amixer to configure the codec route.

In the initial device-tree snippet you provided you have …

nvidia,audio-routing =
            "x Headphone", "x OUT",
            "x IN" , "x Mic";

The above routing is used to link/route the codec analog inputs/outputs to the headphone output (‘x Headphone’) and microphone input (‘x Mic’) defined by the Tegra audio machine driver. This is needed in addition to configuring the codec internal route. And I assume that the codec driver for the zl38063 defines a ‘OUT’ and ‘IN’ DAPM widget.

Regards,
Jon

[0] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/sound/soc/codecs/sgtl5000.c#n312