[iMX8 QM] Using SAI2 interface as I2S slave

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

[iMX8 QM] Using SAI2 interface as I2S slave

2,382 Views
tlugaric
Contributor II

I am trying to use the SAI2 interface on the iMX8 QM to receive audio from a radio tuner module. The radio module only supports I2S master configuration, so I have configured SAI2 as I2S slave. When in such configuration, I am unable to record any audio from the SAI2 interface in Linux.

For purposes of testing, I have made a loopback interface between SAI0 and SAI2 by making the following connections:

SAI0_TXD -> SAI2_RXD
SAI0_TXFS -> SAI2_RXFS
SAI0_TXC -> SAI2_RXC
 
I have configured my pinmux as follows:
SAI0:
SC_P_SAI1_RXC_AUD_SAI0_TXD              0x00000021
SC_P_SPI0_CS1_AUD_SAI0_TXC              0x00000021
SC_P_SAI1_RXFS_AUD_SAI0_RXD             0x00000021
SC_P_SPI2_CS1_AUD_SAI0_TXFS            0x00000021
 
SAI2:
SC_P_ESAI1_TX0_AUD_SAI2_RXD             0x00000021
SC_P_ESAI1_TX1_AUD_SAI2_RXFS            0x00000021
SC_P_ESAI1_SCKT_AUD_SAI2_RXC            0x00000021

 

I have then tried to make two tests, one with SAI0 as I2S master, the other one with SAI2 as I2S master. In both tests, I used aplay to output audio from SAI0 (hw:3,0 in Linux) and arecord to record it from SAI2 (hw:4,0):

aplay -Dplughw:3,0 -vv test.wav
arecord -Dplughw:4,0 -vv test2.wav
 
When SAI0 is configured as master, aplay shows data is being output (i can see the VU meter moving), and there is BCLK, FS and data visible on the I2S lines with a logic analyzer. however arecord does not record any audio (there is no VU meter displayed, and the "test2.wav" file is empty)
 
When SAI2 is configured as master, both aplay and arecord show data is going (VU meter moving), data, BCLK and FSCLK are visible with the logic analyzer  and the test2.wav contains the same audio as test1.wav.
 
From this it seems to me like the SAI2 interface only works properly in I2S master mode. 
 
I tried this on kernel version 4.14 and 5.4.
 
Extract from my device tree with SAI0 as master:
&sai0 {
        #sound-dai-cells = <0>;
        status = "okay";
        fsl,txmasterflag = <4>; // SND_SOC_DAIFMT_CBS_CFS
        fsl,rxmasterflag = <4>; // SND_SOC_DAIFMT_CBS_CFS
};
 
&sai2 {
        #sound-dai-cells = <0>;
        status= "okay";
        fsl,txmasterflag = <1>; // SND_SOC_DAIFMT_CBM_CFM
        fsl,rxmasterflag = <1>; // SND_SOC_DAIFMT_CBM_CFM
};

       sound-btsco {
                compatible = "simple-audio-card";
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_btsco_gpios>;
                simple-audio-card,bitclock-master = <&btsco_master>;
                simple-audio-card,format = "i2s";
                simple-audio-card,frame-master = <&btsco_master>;
                simple-audio-card,name = "bt-sco";
 
                btsco_master: simple-audio-card,cpu {
                        sound-dai = <&sai0>;
                };
 
                simple-audio-card,codec {
                        sound-dai = <&btsco_codec>;
                };
 
        };
 
        btsco_codec: btsco_codec {
                compatible= "linux,bt-sco";
                status = "okay";
                #sound-dai-cells = <0>;
        };
 
        sound-radio {
                compatible = "simple-audio-card";
                pinctrl-names = "default";
                pinctrl-0 =  <&pinctrl_st_radio_control>,<&pinctrl_st_radio_audio>;
                simple-audio-card,bitclock-master = <&radio_master>;
                simple-audio-card,format = "i2s";
                simple-audio-card,frame-master = <&radio_master>;
                simple-audio-card,name = "radio";
 
                simple-audio-card,cpu {
                        sound-dai = <&sai2>;
                };
 
                radio_master: simple-audio-card,codec {
                        sound-dai = <&radio_codec>;
                };
        };
 
        radio_codec: radio_codec {
                compatible= "linux,bt-sco";
                status = "okay";
                #sound-dai-cells = <0>;
        };
 
Extract from my device tree with SAI2 as master:
&sai0 {
        #sound-dai-cells = <0>;
        status = "okay";
        fsl,txmasterflag = <1>; // SND_SOC_DAIFMT_CBM_CFM
        fsl,rxmasterflag = <1>; // SND_SOC_DAIFMT_CBM_CFM
};
 
&sai2 {
        #sound-dai-cells = <0>;
        status= "okay";
        fsl,txmasterflag = <4>; // SND_SOC_DAIFMT_CBS_CFS
        fsl,rxmasterflag = <4>; // SND_SOC_DAIFMT_CBS_CFS
};
       sound-btsco {
                compatible = "simple-audio-card";
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_btsco_gpios>;
                simple-audio-card,bitclock-master = <&btsco_master>;
                simple-audio-card,format = "i2s";
                simple-audio-card,frame-master = <&btsco_master>;
                simple-audio-card,name = "bt-sco";
 
                simple-audio-card,cpu {
                        sound-dai = <&sai0>;
                };
 
                btsco_master: simple-audio-card,codec {
                        sound-dai = <&btsco_codec>;
                };
 
        };
 
        btsco_codec: btsco_codec {
                compatible= "linux,bt-sco";
                status = "okay";
                #sound-dai-cells = <0>;
        };
 
        sound-radio {
                compatible = "simple-audio-card";
                pinctrl-names = "default";
                pinctrl-0 =  <&pinctrl_st_radio_control>,<&pinctrl_st_radio_audio>;
                simple-audio-card,bitclock-master = <&radio_master>;
                simple-audio-card,format = "i2s";
                simple-audio-card,frame-master = <&radio_master>;
                simple-audio-card,name = "radio";
 
                radio_master: simple-audio-card,cpu {
                        sound-dai = <&sai2>;
                };
 
                simple-audio-card,codec {
                        sound-dai = <&radio_codec>;
                };
        };
 
        radio_codec: radio_codec {
                compatible= "linux,bt-sco";
                status = "okay";
                #sound-dai-cells = <0>;
        };
 
Does anyone know how to make SAI2 work in I2S slave mode, or maybe what I could check? As far as I can see, SAI0 and SAI2 have identical configurations, but SAI2 only works as master, while SAI0 works as both.
0 Kudos
4 Replies

1,496 Views
mwilliams
Contributor III

How were you setting the devices into master of slave mode? Any reference?

Thanks

0 Kudos

2,356 Views
tlugaric
Contributor II

Hi Igor

 

Unfortunately, I don't know how to do what you proposed. I only have Yocto set up on the iMX8 CPU, and I am unable to get the SAI2 to work as slave. I have tried to do the same with sai0 connected to sai3, ran into the same problem. Enabling SAI2 with the M4 cores does little help, as I need the audio on the A cores.

The drivers present in the SDK you mentioned are significantly different from the drivers present in yocto, and are of little help for my use case.

0 Kudos

2,353 Views
igorpadykov
NXP Employee
NXP Employee

Hi tlugaric

 

one can debug it using AN12631

Normal and Secure Debug for i.MX8/8X Family of Applications Processors

since slave configuration is supported in SDK, one can check sai registers, then

compare them with linux driver.

May be useful to look at suggestions provided on:

https://community.nxp.com/t5/i-MX-Processors/i-MX7D-SAI1-Slave-connection-to-codec-Master/td-p/69091...

 

Best regards
igor

0 Kudos

2,372 Views
igorpadykov
NXP Employee
NXP Employee

Hi tlugaric

 

one can try to test sai slave with M4 SDK_MEK-MIMX8QM available on

https://mcuxpresso.nxp.com/en/welcome

there are several sai examples, in particular in fsl_sai.c:
/* Set master or slave */
if (config->masterSlave == kSAI_Master)

..drivers/fsl_sai.h

/*! @brief Master or slave mode */
typedef enum _sai_master_slave
{
kSAI_Master = 0x0U, /*!< Master mode include bclk and frame sync */
kSAI_Slave = 0x1U, /*!< Slave mode include bclk and frame sync */
kSAI_Bclk_Master_FrameSync_Slave = 0x2U, /*!< bclk in master mode, frame sync in slave mode */
kSAI_Bclk_Slave_FrameSync_Master = 0x3U, /*!< bclk in slave mode, frame sync in master mode */
} sai_master_slave_t;

 

Best regards
igor

0 Kudos