ETDM (I2S/TDM)

ETDM (Enhanced Time Division Multiplexer) is an advanced version of the TDM technology, designed to improve data transmission efficiency and flexibility for audio applications. The ETDM interface is notable for its ability to support a larger number of audio channels and higher data rates compared to standard TDM interfaces. The ETDM interface can operate as an I2S interface for transmitting stereo or mono data, and also as a TDM interface capable of handling multiple independent audio channels simultaneously.

This section will provide some common use cases for the ETDM driver, and will introduce the ETDM configurations, such as DAI settings in the machine driver. It will also explain how to make customized modifications in the DTS. Finally, it will also cover the porting of I2S.

Driver Command Usage

The MT8370/MT8390/MT8395 features 6 ETDM interfaces, with two dedicated to capture and the remaining four allocated for playback.

  • etdm_in1: TDM capture

  • etdm_in2: I2S capture

  • etdm_out1: TDM playback

  • etdm_out2: I2S playback

  • etdm_out3: HDMI playback

  • DPTX: DP playback

  • Capture

    Example for I2SIN, use ETDM_XXX_Clock_Source control to set the clock source.

    The default clock source is in low power mode, it saves power but may be jitter at high sample rates. You can set the control to a1sys_a2sys to activates the low jitter mode, which means either the 48K clock generated by APLL1 or the 44.1K clock generated by APLL2 will be chosen.

    amixer -c 0 cset name='ETDM_IN2_Clock_Source' 'a1sys_a2sys'
    

    Here are two examples of ETDM capture, etdm_in1 interface is connected to UL8, and etdm_in2 interface is connected to UL3 in the direct path.

    etdm_in1:
    arecord -Dhw:0,13 -c 2 -r 48000 -f S32_LE -d 10 etdm_rec1.wav
    
    etdm_in2:
    arecord -Dhw:0,9 -c 2 -r 48000 -f S32_LE -d 10 etdm_rec2.wav
    
    ../../../../_images/sw_rity_porting-guide_audio_etdm-capture.svg

    ETDM capture

  • Playback

    Example for I2S OUT, set clock source from low power mode to low jitter mode.

    ETDM out1:
    amixer -c 0 cset name='ETDM_OUT1_Clock_Source' 'a1sys_a2sys'
    
    ETDM out2:
    amixer -c 0 cset name='ETDM_OUT2_Clock_Source' 'a1sys_a2sys'
    

    Here are two examples of ETDM playback.

    ETDM out1:
    amixer -c 0 cset name='O072 I022 Switch' 1
    amixer -c 0 cset name='O073 I023 Switch' 1
    aplay test.wav -Dhw:0,6
    
    ETDM out2:
    amixer -c 0 cset name='O048 I022 Switch' 1
    amixer -c 0 cset name='O049 I023 Switch' 1
    aplay test.wav -Dhw:0,6
    
  • HDMI/DP playback

    Set clock source from low power mode to low jitter mode.

    amixer -c 0 cset name='ETDM_OUT3_Clock_Source' 'a1sys_a2sys'
    
    • Switch to HDMI playback

      amixer -c 0 cset name='DPTX_OUT_MUX' 0
      amixer -c 0 cset name='HDMI_OUT_MUX' 1
      
    • Switch to DP playback

      amixer -c 0 cset name='HDMI_OUT_MUX' 0
      amixer -c 0 cset name='DPTX_OUT_MUX' 1
      
    • Using HDMI playback and DP playback simultaneously

      amixer -c 0 cset name='HDMI_OUT_MUX' 1
      amixer -c 0 cset name='DPTX_OUT_MUX' 1
      

      Note

      MT8370/MT8390/MT8395 only supports 2 channels of playback for this configuration!

Machine Driver Configuration

To specify ETDM DAI configurations in the MT8390/MT8395 machine driver.

  • Master/Slave mode

    In master mode, the ETDM device generates the clock signals needed for the communication. The devices operating in master mode controls the timing of the data transmission, dictating when the slave device should send or receive data.

    In slave mode, the ETDM device does not generate its own clock signals. Instead, it relies on an external source, the slave device receives the clock signals and synchronizes its data transmission or reception according to these external clocks.

    DAI master/slave mode configurations

    Parameters

    Mode

    SND_SOC_DAIFMT_CBC_CFC

    Master mode

    SND_SOC_DAIFMT_CBS_CFS

    Master mode (Deprecated since Linux v5.11)

    SND_SOC_DAIFMT_CBP_CFP

    Slave mode

    SND_SOC_DAIFMT_CBM_CFM

    Slave mode (Deprecated since Linux v5.11)

    Currently, the new definition has been adopted for MT8365, MT8370 and MT8390, but the old definition is still being used for MT8395.

  • Format

    There are various formats for DAI, and the user can specify the format in the machine driver.

    DAI format configurations

    Parameters

    DAI format

    SND_SOC_DAIFMT_I2S

    FORMAT_I2S

    SND_SOC_DAIFMT_LEFT_J

    FORMAT_LJ

    SND_SOC_DAIFMT_RIGHT_J

    FORMAT_RJ

    SND_SOC_DAIFMT_DSP_A

    FORMAT_DSPA

    SND_SOC_DAIFMT_DSP_B

    FORMAT_DSPB

  • Clock Inverse

    Clock inverse refers to the inversion of the clock signal polarity within a DAI, it means that the rising and falling edges of the clock signal are reversed. The clock signal is crucial for synchronizing the digital audio data stream during transmission. For instance, if one device’s DAI expects to receive data on the falling edge of the clock, while another device by default sends data on the rising edge, the clock inversion feature can ensure that the two devices can synchronize their data transfer correctly.

    DAI clock inverse configurations

    Parameters

    BCK inverse

    LRCK inverse

    SND_SOC_DAIFMT_NB_NF

    False

    False

    SND_SOC_DAIFMT_NB_IF

    False

    True

    SND_SOC_DAIFMT_IB_NF

    True

    False

    SND_SOC_DAIFMT_IB_IF

    True

    True

E.g.

Parameter settings

Parameters

Value

MCLK rate

128 * sampling rate

Master/Slave mode

master

Format

I2S

Clock inverse

False

Step1: Set the MCLK rate in the mclk_fs_ratio property within the machine driver:

static int mt8195_etdm_hw_params(struct snd_pcm_substream *substream,
            struct snd_pcm_hw_params *params)
{
    struct snd_soc_pcm_runtime *rtd = substream->private_data;
    struct snd_soc_card *card = rtd->card;
    struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
    unsigned int rate = params_rate(params);
    unsigned int mclk_fs_ratio = 128;
    unsigned int mclk_fs = rate * mclk_fs_ratio;
    int ret;

    ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_fs, SND_SOC_CLOCK_OUT);
    if (ret) {
        dev_err(card->dev, "failed to set sysclk\n");
        return ret;
    }

    return 0;
}

Step2: Add ops for ETDM MCLK rate:

static const struct snd_soc_ops mt8195_etdm_ops = {
    .hw_params = mt8195_etdm_hw_params,
};

Step3: Update the properties for .dai_format and .ops in the respective dai-link:

[DAI_LINK_ETDM1_IN_BE] = {
    .name = "ETDM1_IN_BE",
    .no_pcm = 1,
    .dai_fmt = SND_SOC_DAIFMT_I2S |
        SND_SOC_DAIFMT_NB_NF |
        SND_SOC_DAIFMT_CBS_CFS,
    .dpcm_capture = 1,
    .ops = &mt8195_etdm_ops,
    .be_hw_params_fixup = mt8195_etdm_hw_params_fixup,
    SND_SOC_DAILINK_REG(ETDM1_IN_BE),
},

DTS Setting

There are four customizable DTS properties for ETDM.

  • mediatek,X-multi-pin-mode

  • mediatek,X-mclk-always-on-rate

  • mediatek,X-cowork-source

  • mediatek,X-chn-disabled

Here, we use X to represent the specific item names corresponding to different digital audio interfaces in the DTS file.

ETDM Interface

DTS item name

Interface

etdm-in1

TDMIN

etdm-in2

I2SIN

etdm-out1

I2SO1

etdm-out2

I2SO2

  • mediatek,X-multi-pin-mode

    By default, systems are configured to operate in one-pin mode, where one data pin handles the input from multiple devices. However, if your hardware setup requires multi-pin mode, where each device has a dedicated data pin, then this needs to be specified in the DTS file.

    Here’s an example of how you would specify a property in the DTS file to set up in multi-pin mode of I2SIN:

    &afe {
        mediatek,etdm-in2-multi-pin-mode;
    };
    
    • One-pin: Only one pin is responsible for transmitting/receiving data

      ../../../../_images/sw_rity_porting-guide_audio_etdm-one-pin.svg

      One-pin mode

    • Multi-pin: Each pin transmits/receives 2-channel data

      ../../../../_images/sw_rity_porting-guide_audio_etdm-multi-pin.svg

      Multi-pin mode

  • mediatek,X-mclk-always-on-rate

    Specify the MCLK output rate and MCLK will keep active all the time. MCLK rate is divided from APLL rate 196608000 or 180633600.

    Note

    mclk-always-on-rate is only supported in MT8395.

    Here’s an example of how you would specify mclk-always-on-rate property in the DTS file of I2SO1:

    &afe {
        mediatek,etdm-out1-mclk-always-on-rate = <24576000>;
    };
    

    In this way, I2SO1_MCLK always outputs 24.576MHz.

  • mediatek,X-cowork-source

    When configuring an ETDM interface, specifying the co-clock source is crucial when you have multiple audio devices sharing the same clock signal. A co-clock source is a common clock shared by different devices to ensure they are synchronized.

    co-clock source list

    Index

    Interface

    0

    etdm-in1 (TDMIN)

    1

    etdm-in2 (I2SIN)

    2

    etdm-out1 (I2SO1)

    3

    etdm-out2 (I2SO2)

    Here’s an example of how you would specify the co-clock source property in the DTS file.

    For instance, etdm-in1 and etdm-out1 share the same clock. In this case, clock input or output only requires I2SO1 clock pins.

    &afe {
        mediatek,etdm-in1-cowork-source = <2>; //out1
    };
    
  • mediatek,X-chn-disabled

    This property is used to disable ETDM in the channel for the direct path. The direct path refers to the data route connecting to memory interface UL without going through afe_interconn.

    Only etdm_in1 and etdm_in2 in the direct path supports the feature. When using this DTS property, the user also needs to add be_hw_params_fixup in the machine driver.

    static int mt8390_etdm_in_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params)
    {
        struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
        channels->min = channels->max = 4;
        return 0;
    }
    [DAI_LINK_ETDM2_IN_BE] = {
            .name = "ETDM2_IN_BE",
    ...
            .be_hw_params_fixup = mt8390_etdm_in_hw_params_fixup,
    },
    

    Here’s an example of how you would specify the channel disabled property in the DTS file.

    For example, if you are recording data from four channels (0~3) sourced from I2SIN, you may only be interested in retrieving the data from channel 1.

    &afe {
        mediatek,etdm-in2-chn-disabled = /bits/ 8 <0x0 0x2 0x3>;
    };
    

    By following this method, you can obtain stereo data where both channels are sourced from the channel 1 source.

I2S Porting

This section focuses on porting the I2S feature, starting from the hardware aspect, to the configuration in the DTS, and finally explaining how to connect the data path and set up the clock source. The following is an explanation using the Genio 1200-EVK as an example.

../../../../_images/sw_rity_porting-guide_audio_i2s_capture_playback_g1200.svg

I2S audio data complete route

  • Please ensure that pins have been allocated for I2S use on your hardware

    On the Genio 1200-EVK, for instance, there are no I2S pins allocated, so even if the software part is configured correctly, external devices cannot be connected for use. Therefore it can only be used for internal loopback testing.

  • Configure the I2S pins that will be used in the DTS file

    In the DTS file, add all the I2S pins that will be used, and please make sure that these pins are not being used by other functions. Sometimes, to save on hardware, a single pin may have multiple functions, which can be switched depending on user requirements. For example, on Genio 1200-EVK, GPIO47 and GPIO48 are by default used for the DSI panel.

    Here is an example of how to add I2S pins configuration in the DTS file:

    aud_pins_default: audiodefault {
        pins-cmd-dat {
            pinmux = ...
                <PINMUX_GPIO46__FUNC_I2SIN_MCK>,
                <PINMUX_GPIO47__FUNC_I2SIN_BCK>,
                <PINMUX_GPIO48__FUNC_I2SIN_WS>,
                <PINMUX_GPIO49__FUNC_I2SIN_D0>,
                <PINMUX_GPIO57__FUNC_I2SO2_MCK>,
                <PINMUX_GPIO58__FUNC_I2SO2_BCK>,
                <PINMUX_GPIO59__FUNC_I2SO2_WS>,
                <PINMUX_GPIO60__FUNC_I2SO2_D0>,
                ...
        };
    };
    
  • Confirm that the I2S audio data path is connected

    By default, the platform has configured the audio data transmission paths within the AFE for each audio device. It is important to ensure that the switches on the path are turned on before use.

    amixer -c mt8390evk cset name='O036 I012 Switch' on
    amixer -c mt8390evk cset name='O037 I013 Switch' on
    amixer -c mt8390evk cset name='O048 I022 Switch' on
    amixer -c mt8390evk cset name='O049 I023 Switch' on
    

    Configure the clock source for the eTDM interface, where a1sys and a2sys respectively represent the clock sources generated from APLL1 and APLL2 for 48K and 44.1K.

    amixer -c mt8390evk cset name='ETDM_IN2_Clock_Source' a1sys_a2sys
    amixer -c mt8390evk cset name='ETDM_OUT2_Clock_Source' a1sys_a2sys
    

The above is just an example, and the actual situation still needs to refer to the hardware schematic, application processor functional specification, GPIO list, and other relevant documentation.

If you want to integrate an external audio codec into the platform, please refer to here.