How to use wm8960 sound card on OrinNX(R36.3)

Hi,
I want to use the wm8960 sound card on the OrinNX of jetpack6, but there is not working.

This is my dts and modifications:
tegra234-p3768-0000.dtsi.txt (2.5 KB)
tegra_codecs.c.txt (7.9 KB)
Kconfig.txt (10.4 KB)

This is my amixer setting:

amixer -c APE cset name="I2S2 Mux" ADMAIF1
amixer -c APE cset name="I2S2 codec frame mode" i2s
amixer -c APE cset name="ADMAIF1 Mux" I2S2
amixer -c APE cset name="I2S2 codec master mode" cbs-cfs
amixer sset "x Headphone" 127,127
amixer sset "x Speaker" 127,127
amixer sset "x Right Output Mixer PCM" on
amixer sset "x Left Output Mixer PCM" on

aplay -D hw:APE,0 ./test.wav

This is dmesg info:

[  106.256075] wm8960 0-001a: No MCLK configured
[  106.256087] wm8960 0-001a: ASoC: error at snd_soc_component_set_bias_level on wm8960.0-001a: -22
[  106.256340] wm8960 0-001a: ASoC: Failed to prepare bias: -22
[  106.259183] wm8960 0-001a: No MCLK configured
[  106.259188] wm8960 0-001a: ASoC: error at snd_soc_dai_hw_params on wm8960-hifi: -22
[  106.259197] tegra-asoc: sound: ASoC: PRE_PMU: seeed-voicecard-2mic-playback event failed: -22

Hi,

You seem to be missing the codec related clock configuration in the machine driver

Please refer Audio Setup and Development — NVIDIA Jetson Linux Developer Guide 1 documentation as to how to update machine driver for supporting a codec

In your case, as can be inferred from below error,

[  106.256075] wm8960 0-001a: No MCLK configured

you may have to make changes on below lines

int tegra_codecs_init(struct snd_soc_card *card)
{
    struct snd_soc_dai_link *dai_links = card->dai_link;
    int i;
    ...
    for (i = 0; i < card->num_links; i++) {
        if (strstr(dai_links[i].name, "rt565x-playback") ||
            strstr(dai_links[i].name, "rt565x-codec-sysclk-bclk1"))
            dai_links[i].init = tegra_machine_rt565x_init;
        else if (strstr(dai_links[i].name, "fe-pi-audio-z-v2"))
            dai_links[i].init = tegra_machine_fepi_init;
        else if (strstr(dai_links[i].name, "wm8960-hifi"))
            dai_links[i].init = tegra_machine_wm8960_init;
    }
    ...
}

static int tegra_machine_wm8960_init(struct snd_soc_pcm_runtime *rtd)
{
    struct device *dev = rtd->card->dev;
    int err;
    unsigned int pll_f2, freq_in = 24000000;

    
    /*          
    * Per the wm8960 data-sheet the PLL performs best in the range of
    * 90-100MHz, therefore set the PLL to operate as close to 100MHz
    * as we can.
    */          
    pll_f2 = (100000000/freq_in) * freq_in;

    if (pll_f2 < 90000000 || pll_f2 > 100000000)
        dev_warn(card->dev, "PLL frequency is not optimal: %dHz\n", pll_f2);
               
    err = snd_soc_dai_set_sysclk(rtd->codec_dai,
                                WM8960_SYSCLK_PLL, (pll_f2/4), 
                                SND_SOC_CLOCK_IN);
    if (err < 0) { 
            dev_err(card->dev, "codec_dai sysclk not set\n");
            return err; 
    }           
                
    err = snd_soc_dai_set_pll(rtd->codec_dai,
                             WM8960_SYSCLK_PLL, WM8960_SYSCLK_MCLK,
                             freq_in, pll_f2/4);
    if (err) {  
        dev_err(card->dev, "failed to configure codec PLL: %d\n", err);
        return err; 
    }           
    return 0;
}

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, "wm8960-hifi");
    struct device *dev = rtd->card->dev;
    int err;
    unsigned int pll_f2, freq_in = 24000000;
    
    /*          
    * Per the wm8960 data-sheet the PLL performs best in the range of
    * 90-100MHz, therefore set the PLL to operate as close to 100MHz
    * as we can.
    */          
    pll_f2 = (100000000/freq_in) * freq_in;

    if (pll_f2 < 90000000 || pll_f2 > 100000000)
        dev_warn(card->dev, "PLL frequency is not optimal: %dHz\n", pll_f2);
               
    err = snd_soc_dai_set_sysclk(rtd->codec_dai,
                                WM8960_SYSCLK_PLL, (pll_f2/4), 
                                SND_SOC_CLOCK_IN);
    if (err < 0) { 
            dev_err(card->dev, "codec_dai sysclk not set\n");
            return err; 
    }           
                
    err = snd_soc_dai_set_pll(rtd->codec_dai,
                             WM8960_SYSCLK_PLL, WM8960_SYSCLK_MCLK,
                             freq_in, pll_f2/4);
    if (err) {  
        dev_err(card->dev, "failed to configure codec PLL: %d\n", err);
        return err; 
    }           
}

I formed above code from Audio Codec WM8960 on TX2 where similar codec was used and similar issues were faced. Please refer it for any further issues from codec’s end. Be aware that this post was using an older BSP release, so paths may not be directly usable. Refer Audio Setup and Development — NVIDIA Jetson Linux Developer Guide 1 documentation for latest machine driver path.

For your further reference, refer below links

Custom codec integration guide is available at Audio Setup and Development — NVIDIA Jetson Linux Developer Guide 1 documentation
For troubleshooting, refer Audio Setup and Development — NVIDIA Jetson Linux Developer Guide 1 documentation

Feel free to get in touch if any further issues

Thanks

Hi,

Thank you for your modification suggestions, the wm8960 can play audio and recording now

You’re welcome! I’m glad to hear that the modifications worked and the WM8960 is now able to play audio and record. Great job on getting it up and running!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.