Skip to main content
Visitor II
February 13, 2024
Question

Need help with SAI DeviceTree - STM32MP135F - TI TLV320AIC3254

  • February 13, 2024
  • 6 replies
  • 6168 views

Hi,

I need help to setup the DeviceTree for our custom board using STM32MP135FAE7 and TI TLV320AIC3254.

I have read the Wiki about SAI and read and tried to implement SAI using these posts as reference:

No Luck.

And also got confused about where to put the Codec. On the Wiki Page here shows codec under i2c node but on this post there is a comment from @Erwan SZYMANSKI saying that codec should be under root not I2C or I2S. How should I decide where to put it, is it depending on the IC ? What am I missing?

and following those comments, I have enabled the configs related to codec in the config file and updated the kernel and they show up.

CONFIG_SND_SOC_TLV320AIC32X4_I2C=m
CONFIG_SND_SOC_TLV320AIC32X4_SPI=m

root@stm32mp1:~# lsmod
Module Size Used by
cfg80211 663552 0
usb_f_ncm 24576 2
u_ether 20480 1 usb_f_ncm
libcomposite 49152 10 usb_f_ncm
stm32_adc 36864 0
stm32_timer_trigger 20480 1 stm32_adc
stm32_lptimer_trigger 16384 1 stm32_adc
snd_soc_stm32_sai_sub 28672 0
snd_soc_audio_graph_card 16384 0
snd_soc_simple_card_utils 20480 1 snd_soc_audio_graph_card
stm32_adc_core 20480 0
snd_soc_tlv320aic32x4_spi 16384 0
snd_soc_tlv320aic32x4_i2c 16384 0
snd_soc_tlv320aic32x4 36864 2 snd_soc_tlv320aic32x4_spi,snd_soc_tlv320aic32x4_i2c
snd_soc_core 184320 4 snd_soc_audio_graph_card,snd_soc_simple_card_utils,snd_soc_tlv320aic32x4,snd_soc_stm32_sai_sub
snd_soc_stm32_sai 16384 0
snd_pcm_dmaengine 16384 1 snd_soc_core
ac97_bus 16384 1 snd_soc_core
snd_pcm 98304 5 snd_pcm_dmaengine,snd_soc_simple_card_utils,snd_soc_tlv320aic32x4,snd_soc_core,snd_soc_stm32_sai_sub
snd_timer 28672 1 snd_pcm
snd 57344 5 snd_timer,snd_soc_tlv320aic32x4,snd_soc_core,snd_pcm,snd_soc_stm32_sai_sub
soundcore 16384 1 snd
sch_fq_codel 20480 4
ip_tables 24576 0
x_tables 24576 1 ip_tables
ipv6 503808 40

But I don't get any error messages or anything related with the soundcard except the messages below:

root@stm32mp1:~# dmesg |grep sound
root@stm32mp1:~# dmesg |grep audio
[ 0.056931] platform ti-codec: Fixed dependency cycle(s) with /soc/sai@4400a000/audio-controller@4400a024
[ 0.056977] platform ti-codec: Fixed dependency cycle(s) with /soc/sai@4400a000/audio-controller@4400a004
root@stm32mp1:~# dmesg |grep sai
[ 0.056931] platform ti-codec: Fixed dependency cycle(s) with /soc/sai@4400a000/audio-controller@4400a024
[ 0.056977] platform ti-codec: Fixed dependency cycle(s) with /soc/sai@4400a000/audio-controller@4400a004

Here is my devicetree related to SAI part:

/ { /* ROOT */
sound {
        compatible = "audio-graph-card";
        label = "Prove-Audio-Card";
        // routing =
        //  "Playback" , "MCLK",
        //  "Capture", "MCLK";
        dais = <&sai1a_port>;
        status = "okay";
    };
    codec: ti-codec {
        compatible = "ti,tlv320aic32x4";
        #sound-dai-cells = <0>;
        reset-gpios = <&gpioc 0 GPIO_ACTIVE_LOW>;
        ldoin-supply = <&scmi_vdd>;
        iov-supply = <&scmi_vdd>;
        dv-supply = <&scmi_vdd>;
        av-supply = <&scmi_v1v8_periph>;
        clocks = <&sai1a>;
        clock-names = "mclk";
       
tlv320aic32x4_port: port {
            #address-cells = <1>;
            #size-cells = <0>;
            tlv320aic32x4_tx_endpoint: endpoint@0 {
                reg = <0>;
                remote-endpoint = <&sai1a_endpoint>;
                frame-master;               /* codec is master */
                bitclock-master;
            };
            tlv320aic32x4_rx_endpoint: endpoint@1 {
                reg = <1>;
                remote-endpoint = <&sai1b_endpoint>;
                frame-master;               /* codec is master */
                bitclock-master;
            };
        };
    };
};
&i2c5{

    pinctrl-names = "default", "sleep";

    pinctrl-0 = <&i2c5_pins_mx>;

    pinctrl-1 = <&i2c5_sleep_pins_mx>;

    status = "okay";

    /* USER CODE BEGIN i2c5 */

    i2c-scl-rising-time-ns = <185>;

    i2c-scl-falling-time-ns = <20>;

    clock-frequency = <400000>;

   

    /* spare dmas for other usage */

    /delete-property/dmas;

    /delete-property/dma-names;

    /* USER CODE END i2c5 */

};
 
&sai1{

    pinctrl-names = "default", "sleep";

    pinctrl-0 = <&sai1a_pins_mx>, <&sai1b_pins_mx>;

    pinctrl-1 = <&sai1a_sleep_pins_mx>, <&sai1b_sleep_pins_mx>;

    status = "okay";

    /* USER CODE BEGIN sai1 */

    clocks = <&rcc SAI1>, <&scmi_clk CK_SCMI_PLL3_Q>, <&scmi_clk CK_SCMI_PLL3_R>;

    clock-names = "pclk", "x8k", "x11k";

    // #sound-dai-cells = <1>;

    /* USER CODE END sai1 */

    sai1a:audio-controller@4400a004{

        status = "okay";

        /* USER CODE BEGIN sai1a */

        #sound-dai-cells = <0>;

        compatible = "st,stm32-sai-sub-a";

        dma-names = "tx";

        #clock-cells = <0>;

        clocks = <&rcc SAI1_K>;

        clock-names = "sai_ck";

        sai1a_port: port {

            sai1a_endpoint: endpoint {

                remote-endpoint = <&tlv320aic32x4_tx_endpoint>;

                format = "i2s";

                mclk-fs = <256>;

                dai-tdm-slot-num = <2>;

                dai-tdm-slot-width = <32>;

            };

        };

        /* USER CODE END sai1a */

    };

    sai1b:audio-controller@4400a024{

        status = "okay";

        /* USER CODE BEGIN sai1b */

        #sound-dai-cells = <0>;

        dma-names = "rx";               /* SAI set as receiver */

        st,sync = <&sai1a 1>;           /* SAI1B is slave of SAI1A */

        clocks = <&rcc SAI1_K>, <&sai1a>;

        clock-names = "sai_ck", "mclk";

        sai1b_port: port {

            sai1b_endpoint: endpoint {

                remote-endpoint = <&tlv320aic32x4_rx_endpoint>;

                format = "i2s";

                mclk-fs = <256>;

                dai-tdm-slot-num = <2>;

                dai-tdm-slot-width = <32>;

            };

        };

    };

};
&pinctrl {
    i2c5_pins_mx: i2c5_mx-0 {
        pins {
            pinmux = <STM32_PINMUX('F', 3, AF4)>, /* I2C5_SDA */
                     <STM32_PINMUX('H', 13, AF4)>; /* I2C5_SCL */
            bias-disable;
            drive-open-drain;
            slew-rate = <0>;
        };
    };
    i2c5_sleep_pins_mx: i2c5_sleep_mx-0 {
        pins {
            pinmux = <STM32_PINMUX('F', 3, ANALOG)>, /* I2C5_SDA */
                     <STM32_PINMUX('H', 13, ANALOG)>; /* I2C5_SCL */
        };
    };
    sai1a_pins_mx: sai1a_mx-0 {
        pins {
            pinmux = <STM32_PINMUX('A', 4, AF12)>, /* SAI1_SCK_A */
                     <STM32_PINMUX('A', 5, AF6)>, /* SAI1_SD_A */
                     <STM32_PINMUX('C', 3, AF10)>, /* SAI1_MCLK_A */
                     <STM32_PINMUX('E', 4, AF6)>; /* SAI1_FS_A */
            bias-disable;
            drive-push-pull;
            slew-rate = <0>;
        };
    };
    sai1a_sleep_pins_mx: sai1a_sleep_mx-0 {
        pins {
            pinmux = <STM32_PINMUX('A', 4, ANALOG)>, /* SAI1_SCK_A */
                     <STM32_PINMUX('A', 5, ANALOG)>, /* SAI1_SD_A */
                     <STM32_PINMUX('C', 3, ANALOG)>, /* SAI1_MCLK_A */
                     <STM32_PINMUX('E', 4, ANALOG)>; /* SAI1_FS_A */
        };
    };
    sai1b_pins_mx: sai1b_mx-0 {
        pins {
            pinmux = <STM32_PINMUX('A', 0, AF6)>; /* SAI1_SD_B */
            bias-disable;
            drive-push-pull;
            slew-rate = <0>;
        };
    };
    sai1b_sleep_pins_mx: sai1b_sleep_mx-0 {
        pins {
            pinmux = <STM32_PINMUX('A', 0, ANALOG)>; /* SAI1_SD_B */
        };
    };
};

And my clock settings:

root@stm32mp1:~# cat /sys/kernel/debug/clk/clk_summary |grep sai
sai2 0 0 0 104450000 0 0 50000 N
sai1 0 2 0 104450000 0 0 50000 N
sai2_k 0 0 0 24000000 0 0 50000 N
sai1_k 0 0 0 24000000 0 0 50000 N
sai1a_mclk 0 0 0 0 0 0 50000 ?

 

    This topic has been closed for replies.

    6 replies

    Technical Moderator
    February 14, 2024

    Hello @skarayigit ,
    Did you try to launch your audio playback ? For me this is normal to not see clock activation until you do not try to play your audio track or record.

    Kind regards,
    Erwan.

    Visitor II
    February 15, 2024

    Hi @Erwan SZYMANSKI ,

    Thank you for your quick reply. No soundcard appears in my system. 

    I've just configured for S/PDIF to try if I get any audio card, it is a success. If I configure it for S/PDIF and use it for rx and use sai1a for tx. I got a audio card and I was able to play some audio file and i can see the digital signal on the oscilloscope. 

    Does my devicetree seems OK? node placements?  I have also attached my full devicetree below. 

    I am expecting to see the soundcard on the system to confirm that the devicetree setted up correctly that part correctly, even if its not working properly and play audio. Am I wrong to expect to see soundcard on the system?

    Best Regards

    Technical Moderator
    February 15, 2024

    Hello @skarayigit ,
    In your situation, your codec is driven by I2C (or SPI I guess, but I suppose I2C is the default interface). If this codec is driven by I2C, indeed it has to be placed under your I2C interface node (that will drive it).

    Please check this configuration from another post with a quite similar codec: https://community.st.com/t5/stm32-mpus-embedded-software/stm32mp135-sai-missing-clock-error-at-boot-time/m-p/55114#M43

    Kind regards,
    Erwan.

    Visitor II
    February 20, 2024

    Hello @Erwan SZYMANSKI ,

    Thank you for the clarification about the I2C node. I have placed my codec under I2C node. I do not get any errors or messages while booting up. However, I still do not have any soundcard or devices in the linux. What should I do next? Do I have problems with my device tree?

    Here is some messages that might help:

    root@stm32mp1:~# dmesg |grep audio
    [ 3.739023] i2c 9-0018: Fixed dependency cycle(s) with /soc/sai@4400a000/audio-controller@4400a024
    [ 3.746728] i2c 9-0018: Fixed dependency cycle(s) with /soc/sai@4400a000/audio-controller@4400a004
    root@stm32mp1:~# cat /proc/asound/cards
    --- no soundcards ---
    root@stm32mp1:~# cat /proc/asound/devices
    33: : timer
    root@stm32mp1:~# cat /proc/asound/pcm
    root@stm32mp1:~# cat /proc/asound/modules
    root@stm32mp1:~# cat /sys/kernel/debug/asoc/
    components dais
    root@stm32mp1:~# cat /sys/kernel/debug/asoc/dais
    4400a024.audio-controller
    4400a004.audio-controller
    tlv320aic32x4-hifi
    snd-soc-dummy-dai
    root@stm32mp1:~# cat /sys/kernel/debug/asoc/components
    4400a024.audio-controller
    4400a024.audio-controller
    4400a004.audio-controller
    4400a004.audio-controller
    tlv320aic32x4.9-0018
    snd-soc-dummy
    snd-soc-dummy

    root@stm32mp1:~# lsmod
    Module Size Used by
    cfg80211 663552 0
    usb_f_ncm 24576 2
    u_ether 20480 1 usb_f_ncm
    stm32_adc 36864 0
    libcomposite 49152 10 usb_f_ncm
    stm32_timer_trigger 20480 1 stm32_adc
    stm32_lptimer_trigger 16384 1 stm32_adc
    snd_soc_stm32_sai_sub 28672 1
    snd_soc_tlv320aic32x4_spi 16384 0
    snd_soc_tlv320aic32x4_i2c 16384 0
    snd_soc_audio_graph_card 16384 0
    snd_soc_simple_card_utils 20480 1 snd_soc_audio_graph_card
    snd_soc_tlv320aic32x4 36864 2 snd_soc_tlv320aic32x4_spi,snd_soc_tlv320aic32x4_i2c
    snd_soc_core 184320 4 snd_soc_audio_graph_card,snd_soc_simple_card_utils,snd_soc_tlv320aic32x4,snd_soc_stm32_sai_sub
    snd_pcm_dmaengine 16384 1 snd_soc_core
    ac97_bus 16384 1 snd_soc_core
    snd_pcm 98304 5 snd_pcm_dmaengine,snd_soc_simple_card_utils,snd_soc_tlv320aic32x4,snd_soc_core,snd_soc_stm32_sai_sub
    snd_timer 28672 1 snd_pcm
    snd 57344 5 snd_timer,snd_soc_tlv320aic32x4,snd_soc_core,snd_pcm,snd_soc_stm32_sai_sub
    soundcore 16384 1 snd
    stm32_adc_core 20480 0
    snd_soc_stm32_sai 16384 0
    sch_fq_codel 20480 4
    ip_tables 24576 0
    x_tables 24576 1 ip_tables
    ipv6 503808 38

    Here is my related DT (updated):

     / * in the root */

    sound: sound {
            compatible = "audio-graph-card";
            label = "STM32MP135F-DK";
            routing =
                "Playback" , "MCLK",
                "Capture", "MCLK";
            dais = <&sai1a_port &sai1b_port>;
            status = "okay";
        };
    &i2c5{
        pinctrl-names = "default", "sleep";
        pinctrl-0 = <&i2c5_pins_mx>;
        pinctrl-1 = <&i2c5_sleep_pins_mx>;
        status = "okay";

        /* USER CODE BEGIN i2c5 */
        i2c-scl-rising-time-ns = <185>;
        i2c-scl-falling-time-ns = <20>;
        clock-frequency = <400000>;
        #address-cells = <1>;
        #size-cells = <0>;
       
        /* spare dmas for other usage */
        /delete-property/dmas;
        /delete-property/dma-names;

        tlv320aic32x4: tlv320aic32x4@18 {
            compatible = "ti,tlv320aic32x4";
            reg = <0x18>;
            // #sound-dai-cells = <0>;
            reset-gpios = <&gpioc 0 GPIO_ACTIVE_LOW>;
            ldoin-supply = <&scmi_vdd>;
            iov-supply = <&scmi_vdd>;
            clocks = <&sai1a>;
            clock-names = "mclk";
            status = "okay";

            port {
                #address-cells = <1>;
                #size-cells = <0>;
                tlv320aic32x4_tx_port: port@0 {
                    reg = <0>;
                    tlv320aic32x4_tx_endpoint: endpoint {
                        remote-endpoint = <&sai1a_endpoint>;
                        frame-master;               /* codec is master */
                        bitclock-master;
                    };
                };
                tlv320aic32x4_rx_port: port@1 {
                    reg = <1>;
                    tlv320aic32x4_rx_endpoint: endpoint {
                        remote-endpoint = <&sai1b_endpoint>;
                        frame-master;               /* codec is master */
                        bitclock-master;
                    };
                };
            };
        };
        /* USER CODE END i2c5 */
    };
     
    &sai1{
        pinctrl-names = "default", "sleep";
        pinctrl-0 = <&sai1a_pins_mx>, <&sai1b_pins_mx>;
        pinctrl-1 = <&sai1a_sleep_pins_mx>, <&sai1b_sleep_pins_mx>;
        status = "okay";

        /* USER CODE BEGIN sai1 */
        clocks = <&rcc SAI1>, <&scmi_clk CK_SCMI_PLL3_Q>, <&scmi_clk CK_SCMI_PLL3_R>;
        clock-names = "pclk", "x8k", "x11k";
        #sound-dai-cells = <1>;
        /* USER CODE END sai1 */

        sai1a:audio-controller@4400a004{
            status = "okay";

            /* USER CODE BEGIN sai1a */
            compatible = "st,stm32-sai-sub-a";
            #clock-cells = <0>;
            dma-names = "tx";
            clocks = <&rcc SAI1_K>;
            clock-names = "sai_ck";

            sai1a_port: port {
                sai1a_endpoint: endpoint {
                    remote-endpoint = <&tlv320aic32x4_tx_endpoint>;
                    format = "i2s";
                    mclk-fs = <512>;
                   
                    // mclk-fs = <256>;
                    // dai-tdm-slot-num = <2>;
                    // dai-tdm-slot-width = <16>;
                };
            };
            /* USER CODE END sai1a */
        };

        sai1b:audio-controller@4400a024{
            status = "okay";

            /* USER CODE BEGIN sai1b */
            compatible = "st,stm32-sai-sub-b";
            dma-names = "rx";
            st,sync = <&sai1a 1>;
            clocks = <&rcc SAI1_K>, <&sai1a>;
            clock-names = "sai_ck", "MCLK";

            sai1b_port: port {
                sai1b_endpoint: endpoint {
                    remote-endpoint = <&tlv320aic32x4_rx_endpoint>;
                    format = "i2s";
                    mclk-fs = <512>;

                    // mclk-fs = <256>;
                    // dai-tdm-slot-num = <2>;
                    // dai-tdm-slot-width = <16>;
                };
            };
            /* USER CODE END sai1b */
        };
    };

     

    Visitor II
    February 27, 2024

    Hello @Erwan SZYMANSKI,

    Any update?

    Technical Moderator
    February 27, 2024

    Hello @skarayigit ,
    Sorry for my late answer.
    The best way to understand what happens is to not work eyes closed on the issue. I suggest you either activate available debug traces or add your own logs in the soundcard driver to understand what is going wrong, and then give us more input to see where does it fail. You can as well activate debug in stm32_sai_sub.c driver to get it more verbose. 

    Can you also put your complete dmesg log here ? 

    Kind regards,
    Erwan.

    Visitor II
    April 29, 2024

    Hi @Erwan SZYMANSKI ,

    I am a colleague of @skarayigit and have continued to make progress since the last post.

    Our current device tree is setup such that we are able to get the kernel and ALSA to recognize that we have a audio card; listed via aplay -l and alsactl info 0. (see cardinfo.txt)

    I can see a 12Mhz signal being generated on the MCLK line for our tlv320xaic3254 codec once the driver is loaded. ref: https://www.ti.com/product/TLV320AIC3254 

    However, when we attempt to run a command such as "speaker-test -Dhw:0,0" it starts to run and then the process hangs. Any other process that attempts to touch clocks also hangs (this includes the sdcard driver) but other processes continue running.

    We copied our kernel image to a usb to stop the constant clock calls for the file system and we can see that the file system now is able to stay alive. We also noted that we were able to maintain and create new ssh sessions with the system whilst the speaker-test was hanging with this configuration.

    So long as we do not interact with the clocking subsystem we were able to operate as normal. 

    We're a bit lost as to where to look next. Could you suggest any fixes to our device tree or other tooling or specific trace logs we could enable to identify the issue?

    I will attach our kernel device tree and some other info which may help.

    Thanks again for your time, your help so far has been greatly appreciated.

    Technical Moderator
    April 30, 2024

    Hello @Bstyles ,
    As it is difficult to reproduce and as I am not an audio expert, it is difficult for me to well understand all that happens here.

    First, what do you mean by "it hangs" when you try to do an Alsa play ? 

    I see in your device tree that you well try to generate the MCLK by the SoC, and it seems good as in the datasheet of your Codec, it seems to only support MCLK input. 

    Did you also probe with an oscilloscope the BCLK and the WCLK ? Are they in the spec ? Did you choose to let the codec generate them (should be a good solution).

    If all of this is good, did you try to check the data lane at the osciloscope ? Do you see any activity on it ? 

    If also yes, you also have to check the codec configuration (amplification of sound and so on ...), if I remember well, you can do it through ALSA API as well. 

    Kind regards,
    Erwan.

    (PS: do not hesitate to share with me your different waveforms)

    Visitor II
    September 16, 2025

    Hi
    I have same issue in connecting tlv320aic3254 to sai2 in stm32mp157c,

    can you solve that or any other hint to solving this issue?