cancel
Showing results for 
Search instead for 
Did you mean: 

Need help with SAI DeviceTree - STM32MP135F - TI TLV320AIC3254

skarayigit
Associate III

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 ?

 

10 REPLIES 10
Erwan SZYMANSKI
ST Employee

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.

In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question.
skarayigit
Associate III

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

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.

In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question.
skarayigit
Associate III

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 */
    };
};

 

skarayigit
Associate III

Hello @Erwan SZYMANSKI,

Any update?

Erwan SZYMANSKI
ST Employee

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.

In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question.

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.

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)

In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question.

Hi @Erwan SZYMANSKI ,

By hanging, the process stops responding; neither ctrl+z or ctrl+c can suspend or terminate it. We tried attaching a GDB debugger which also stops responding. 
We believe this is less of an audio or ALSA issue and more of a clocking issue.

After loading the driver via "modprobe snd-soc-tlv320aic32x4-i2c" which also loads "snd-soc-tlv320aic32x4" as well, we noticed we could not do "cat /sys/kernel/debug/clk/clk_summary". 

It seems any operation which requires a clock operation after loading the driver results in a hang. 

To try and help the conversation, I added some printk statements to the driver tlv320aic32x4.c on the stm linux git and discovered that if you run "speaker-test", the driver never returns from the following function.
Our kernel version is 6.1.28

 

 

static int aic32x4_set_dai_sysclk(struct snd_soc_dai * codec_dai, int clk_id, unsigned int freq, int dir) {
   printk("Start of aic32x4_set_dai_sysclk");

   struct snd_soc_component *component = codec_dai->component;
   struct clk *mclk;
   struct clk *pll;

   pll = devm_clk_get(component->dev, "pll");
   if (IS_ERR(pll))
      return PTR_ERR(pll);

   // We set mclk as "sai1a" in the Device tree, this means this mclk is 'sai1a_mclk'
   // We can see this in "cat /sys/kernel/debug/clk/pll/clk_parent" which does not hang?
   mclk = clk_get_parent(pll);

   // Originally this code was just "return clk_set_rate(mclk, freq);"
   // But to find the return value, was modified

   int success = clk_set_rate(mclk, freq); // Never returns, could be waiting for a spinlock or mutex?

   printk("End of aic32x4_set_dai_sysclk, clk_set_rate returns %d", success);
   return success;
}

 

 

 
As for BCLK and WCLK, I have not yet had the chance to probe these. I will probe them when I next get the chance and upload the results here.
By data lane do you mean DIN for i2s or the data bus for I2c?
Cheers,