No soundcards on Colibri iMX6ULL 1GB

I’m following some guidelines (Audio) Linux to play music over the SAI interface (pcm, spdif, tdm).
When building the TorizonOS. it seems that the command

more /proc/asound/cards

outputs – no soundcards –
How to proceed?

Software summary
------------------------------------------------------------
Bootloader:               U-Boot
Kernel version:           6.1.80+git.a3eb3a74aa8c #1-TorizonCore Tue Jan 16 14:35:15 UTC 2024
Kernel command line:      user_debug=30 root=LABEL=otaroot rootfstype=ext4 quiet logo.nologo vt.global_cursor_default=0 plymouth.ignore-serial-consoles splash fbcon=map:3 ostree=/ostree/boot.1/torizon/acef2d15e42510588a1cf8e5dcaa419052475ca11b03c298cf41ffa123716146/0
Distro name:              NAME="TorizonCore Upstream"
Distro version:           VERSION_ID=6.6.0-devel-20240328135229-build.0
Distro variant:           VARIANT="Minimal"
Hostname:                 colibri-imx6ull-emmc-15264448
------------------------------------------------------------

Hardware info
------------------------------------------------------------
HW model:                 Toradex Colibri iMX6ULL 1GB (eMMC) on Colibri Evaluation Board V3
Toradex version:          0062 V1.1A
Serial number:            15264448
Processor arch:           armv7l

Dear @bkennis,

Thank you for contacting us. Unfortunately there is no codec on the Colibri iMX6ULL as can be seen in this documentation. For your audio to work you would thusly need a codec to be connected to the SAI/I2S interface and enabled via a device tree or device tree overlay.

Best regards
Collin

Hi collin.tx, thanks for the information. Is there some example of how to create a specific overlay for audio (I2S)?

Bram

Dear Bram,

Since you are using a Colibri iMX6ULL 1GB it has an eMMC and can thusly make use of overlays. At this link you will find a community thread about somebody using a sgtl5000 and SAI for audio as an example. You might get some inspiration from it. :slight_smile:

Best regards
Collin

Hi collin.tx,

I also noticed that the Torizon-core doesn’t have “aplay” or “amixer” installed. So i pulled the torizon/weston container and added alsa-utils and libasound2-dev to my Dockerfile. After building the docker image (pushing to my account and pulling it back on the imx6ull). It still doens’t find the aplay binary.

How to troubleshoot this?

Bram

Dear @bkennis,

Have you implemented an external codec on your hardware? If so, which one have you chosen?
If you implemented this hardware you will have to alter the device tree on the carrier board level accordingly.
Following this you will have to create your docker file similar to what is written in this article. You will however need to change the platform from linux/arm64 to your specification (linux/armv7) as well as specifying the correct audio codec you will have chosen.
This should work for what you are trying to implement.

Best regards
Collin

Hi @collin.tx ,

I have an MAX98357a audio codec connected to the SAI3 interface of the Colibri-imx6ULL-eval kit.
It uses pins:

  • SODIMM_54 => I2S (BLCK)
  • SODIMM_52 => I2S (LRC)
  • SODIMM_64 => I2S (DIN)

So i added a custom overlay, in my tcbuild.yaml file.

// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
/*
 * Copyright 2022 Toradex
 */

// Enable I2S on SAI interface

/dts-v1/;
/plugin/;

#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/clock/imx6ul-clock.h>
#include <dt-bindings/pinctrl/imx6ul-pinfunc.h>

/ {
	compatible = "toradex,colibri-imx6ull-emmc";

codec_ext: max98357a@0 {
    compatible = "maxim,max98357a";
    #sound-dai-cells = <0>;
};

    sound {
        compatible = "toradex,colibri-imx6ull-emmc",
                     "simple-audio-card";
        simple-audio-card,name = "max98357a";
        simple-audio-card,format = "i2s";
        simple-audio-card,bitclock-master = <&dailink_master_cpu>;
        simple-audio-card,frame-master = <&dailink_master_cpu>;

        simple-audio-card,codec {
                sound-dai = <&codec_ext>;
        };

        dailink_master_cpu: simple-audio-card,cpu {
                sound-dai = <&sai3>;
        };

    };

};

&sai3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_sai3>;
        assigned-clocks = <&clks IMX6UL_CLK_SAI3_SEL>,
                          <&clks IMX6UL_CLK_SAI3>, <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;
        assigned-clock-parents = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;
        assigned-clock-rates = <2>, <24576000>, <786432000>;
        fsl,sai-asynchronous;
        //fsl,sai-mclk-direction-output;
        status = "okay";
};

&iomuxc {
                pinctrl_sai3: sai3grp {
                        fsl,pins = <
                                MX6UL_PAD_LCD_DATA13__SAI3_TX_BCLK      0x1F089
                                MX6UL_PAD_LCD_DATA12__SAI3_TX_SYNC      0x17088
                                MX6UL_PAD_LCD_DATA15__SAI3_TX_DATA      0x11088
                                MX6UL_PAD_LCD_DATA14__SAI3_RX_DATA      0x11088
                                //MX6UL_PAD_LCD_DATA09__SAI3_MCLK         0x17088
                        >;
                };
                pinctrl_sai3_mclk: sai3grp_mclk {
                        fsl,pins = <
                                MX6UL_PAD_LCD_DATA09__SAI3_MCLK         0x17088
                        >;
                };
};

I think i’m missing the kernel option to enable the MAX98357a.

torizon@colibri-imx6ull-emmc-15264448:~$ zcat /proc/config.gz | grep MAX98357
# CONFIG_SND_SOC_MAX98357A is not set
torizon@colibri-imx6ull-emmc-15264448:~$ 

I use the following source file for the “torizoncore-builder build” command.

torizon-core-docker-colibri-imx6ull-emmc-Tezi_6.7.0+build.18.tar

dmesg doesn’t show anything about the max98357.

What is the easiest way to enable: CONFIG_SND_SOC_MAX98357A=y

Thanks!

Bram

Dear @bkennis,

Sorry for the massive delay in replying. I am currently checking this out internally.

Best regards
Collin

Hi @collin.tx ,

I’m able to see the max98357a on my system.

torizon@colibri-imx6ull-emmc-15264448:~$ zcat /proc/config.gz | grep MAX98357
CONFIG_SND_SOC_MAX98357A=m
torizon@colibri-imx6ull-emmc-15264448:~$ lsmod
Module                  Size  Used by
cfg80211              819200  0
mcp251x                24576  0
can_dev                40960  1 mcp251x
joydev                 20480  0
vf610_adc              16384  0
industrialio_triggered_buffer    16384  1 vf610_adc
kfifo_buf              16384  1 industrialio_triggered_buffer
industrialio           90112  3 vf610_adc,industrialio_triggered_buffer,kfifo_buf
imx_sdma               24576  4
snd_soc_max98357a      16384  1
uio_pdrv_genirq        16384  0
uio                    24576  1 uio_pdrv_genirq
libcomposite           65536  0
fuse                  122880  1
torizon@colibri-imx6ull-emmc-15264448:~$ 

i’m now trying the play some wav file with aplay but i get the following error.

torizon@colibri-imx6ull-emmc-15264448:~$ aplay -D hw:0,0 pedro.wav 
Playing WAVE 'pedro.wav' : [ 1761.498699] fsl-sai 2030000.sai: failed to derive required Tx rate: 1411200
Signed 16 bit Little Endian, Rate[ 1761.507319] fsl-sai 2030000.sai: ASoC: error at snd_soc_dai_hw_params on 2030000.sai: -22
 44100 Hz, Stereo
[ 1761.518349]  2030000.sai-HiFi: ASoC: error at __soc_pcm_hw_params on 2030000.sai-HiFi: -22
aplay: set_params:1416: Unable to install hw params:
ACCESS:  RW_INTERLEAVED
FORMAT:  S16_LE
SUBFORMAT:  STD
SAMPLE_BITS: 16
FRAME_BITS: 32
CHANNELS: 2
RATE: 44100
PERIOD_TIME: (125011 125012)
PERIOD_SIZE: 5513
PERIOD_BYTES: 22052
PERIODS: 4
BUFFER_TIME: (500045 500046)
BUFFER_SIZE: 22052
BUFFER_BYTES: 88208
TICK_TIME: 0
torizon@colibri-imx6ull-emmc-15264448:~$ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: max98357a [max98357a], device 0: 2030000.sai-HiFi HiFi-0 [2030000.sai-HiFi HiFi-0]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
torizon@colibri-imx6ull-emmc-15264448:~$ 

Hi @collin.tx ,

i’m able to play music with the MAX98357A connected to the SAI3 interface.
Using the following changed devicetree:

// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
/*
 * Copyright 2022 Toradex
 */

/dts-v1/;

// Adding extra protocols

#include "imx6ull-colibri-emmc-eval-v3.dts"

/ {
	compatible = "toradex,colibri-imx6ull-emmc";

codec_ext: max98357a@0 {
    compatible = "maxim,max98357a";
    #sound-dai-cells = <0>;
};

    sound {
        compatible = "simple-audio-card"; 
        status = "okay";
        simple-audio-card,name = "max98357a";
        simple-audio-card,format = "i2s";
        simple-audio-card,bitclock-master = <&dailink_master_cpu>;
        simple-audio-card,frame-master = <&dailink_master_cpu>;

        simple-audio-card,codec {
                sound-dai = <&codec_ext>;
        };

        dailink_master_cpu: simple-audio-card,cpu {
                sound-dai = <&sai3>;
        };

    };
};

&sai3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_sai3>;
        assigned-clocks = <&clks IMX6UL_CLK_SAI3_SEL>,
                          <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;
        assigned-clock-parents = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;
        assigned-clock-rates = <2>, <196608000>;
        fsl,sai-asynchronous;
        status = "okay";
};

&iomuxc {
                pinctrl_sai3: sai3grp {
                        fsl,pins = <
                                MX6UL_PAD_LCD_DATA13__SAI3_TX_BCLK      0x1F089  // SODIMM_54
                                MX6UL_PAD_LCD_DATA12__SAI3_TX_SYNC      0x17088  // SODIMM_52
                                MX6UL_PAD_LCD_DATA15__SAI3_TX_DATA      0x11088  // SODIMM_64
                                //MX6UL_PAD_SD1_DATA2__CCM_CLKO1          0x17088  // SODIMM_51
                                MX6UL_PAD_LCD_DATA09__SAI3_MCLK         0x17088  // SODIMM_48
                        >;
                };
    };

Below: the I2S output in logic analyzer:

Dear @bkennis,

Thank you very much for sharing your results! I am glad you were able to make it work. Would you mind, if we make this thread public, in case another user is experiencing the same issues?

Best regards
Collin

Hi @collin.tx ,

Yes you can make this thread public.

Best regards
Bram