IMX6开发板出现音频问题(max98357a编解码器)

时间:2018-10-24 13:19:08

标签: audio linux-device-driver codec device-tree imx6

我正在基于IMX6 Solo processorTX6S-8035模块的定制板上工作,试图用MAX98357a codec播放音频。我只是开始研究如何在4.1.15 linux内核上实现简单音频卡的设备树的工作方式,并按照i.MX6和MA98357a的建议将以下DTS与简单音频卡一起使用:

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

    sound {
        compatible = "simple-audio-card";
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_ssi1>;
        simple-audio-card,name = "TI3 Audio";
        simple-audio-card,format = "i2s";
        simple-audio-card,widgets = "Speaker", "Speakers";
        simple-audio-card,routing = "Speakers", "Speaker";
        simple-audio-card,bitclock-master = <&cpu_dai>;
        simple-audio-card,frame-master = <&cpu_dai>;
        cpu_dai: simple-audio-card,cpu {
            sound-dai = <&ssi1>;
            system-clock-frequency = <883200>;
            dai-tdm-slot-num = <2>;
            dai-tdm-slot-width = <16>;
        };
        codec_dai: simple-audio-card,codec {
            sound-dai = <&codec>;
        };
    };



&audmux {
    status = "okay";
    // Note: 'ssi1' (node of first SSI) corresponds to '_SSI0' below.
    ssi1 {
         fsl,audmux-port = <MX31_AUDMUX_PORT1_SSI0>;
         fsl,port-config = <
               0x00000000
               IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT3_SSI_PINS_3)
               >;
           };


    aud3 {
      fsl,audmux-port = <MX31_AUDMUX_PORT3_SSI_PINS_3>;
      fsl,port-config = <
          (IMX_AUDMUX_V2_PTCR_TFSDIR |
          IMX_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT1_SSI0) |
          IMX_AUDMUX_V2_PTCR_TCLKDIR |
          IMX_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT1_SSI0))
          IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0)
          >;
     };
};


&ssi1 {
      fsl,mode = "i2s-master";
      assigned-clocks = <&clks IMX6QDL_CLK_SSI1_SEL>, <&clks IMX6QDL_CLK_SSI1>;
      assigned-clock-parents = <&clks IMX6QDL_CLK_PLL4_AUDIO_DIV>;
      assigned-clock-rates = <0>, <49152000>; // 48kHz on SSI1 clock
      status = "okay";    
};

MAX98357a编解码器连接到SSI1。声卡被ALSA检测到。但是,当我尝试播放音频文件时,扬声器上什么也没有,而且SSI1引脚上没有I2S信号。有人对此问题有任何想法吗? 谢谢。 最好的问候!

1 个答案:

答案 0 :(得分:0)

我在使声卡(带有简单声卡的MA98357a编解码器)与最新版本的imx6q(i.MX 6 Quad)一起使用时遇到了一些麻烦,所以我在这里分享我的解决方案:

  • CONFIG_SND_SOC_MAX98357A需要启用(与兼容的"maxim,max98357a"相关联)。但是“默认情况下”无法在make menuconfig下选择此选项。相关的Kconfig(sound/soc/codecs/Kconfig)需要打补丁。替换:
config SND_SOC_MAX98357A
    tristate

通过:

config SND_SOC_MAX98357A
    tristate "Maxim MAX98357A CODEC"
  • CONFIG_SND_SIMPLE_CARD需要启用(与兼容的"simple-audio-card"相关联)

  • 应用/合并/自动选择以下补丁(如果尚未应用):在主服务器中提交ID:3ff86050da41e072dd9fffc373c4f5691573cf4eclk: imx6q: disable non functional divider。由于我使用的是较早的内核版本4.19.134

    ,因此必须手动“合并”它。
  • 为此音频卡编写.dts:

    • 配置audmux,在我的情况下,引脚(TXD,CLK,FS)连接到AUD5引脚。使用第一个SSI(ssi1)。该SSI将生成位时钟(CLK),并将其提供给max98357a声卡。
    • 配置iomux:需要在正确的模式下配置AUD5引脚
    • 配置ssi1和相关的时钟。最好的时钟是PLL4,它是唯一可以精确产生48 kHz的时钟。
    • 添加codecsound

.dts的摘录以下:

/dts-v1/;
#include <dt-bindings/sound/fsl-imx-audmux.h>
#include "imx6q.dtsi"
#include "imx6qdl-phytec-phycore-som.dtsi"

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

    sound {
        compatible = "simple-audio-card";
        simple-audio-card,name = "max98357a";
        simple-audio-card,format = "i2s";
        simple-audio-card,widgets = "Speaker", "Speakers";
        simple-audio-card,routing = "Speakers", "Speaker";
        simple-audio-card,bitclock-master = <&cpu_dai>;
        simple-audio-card,frame-master = <&cpu_dai>;
        cpu_dai: simple-audio-card,cpu {
            sound-dai = <&ssi1>;
            dai-tdm-slot-num = <2>;
            dai-tdm-slot-width = <16>;
        };
        codec_dai: simple-audio-card,codec {
            sound-dai = <&codec>;
            clocks = <&clks IMX6QDL_CLK_SSI1>;
        };
    };
};

&audmux {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_audmux>;
    status = "okay";

    ssi1 {
        fsl,audmux-port = <MX31_AUDMUX_PORT1_SSI0>;
        fsl,port-config = <
            0x00000000
            IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT5_SSI_PINS_5)
            >;
    };

    aud5 {
        fsl,audmux-port = <MX31_AUDMUX_PORT5_SSI_PINS_5>;
        fsl,port-config = <
            (IMX_AUDMUX_V2_PTCR_TFSDIR |
             IMX_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT1_SSI0) |
             IMX_AUDMUX_V2_PTCR_TCLKDIR |
             IMX_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT1_SSI0))
             IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0)
             >;
    };
};

/* The clock tree used to generate the SSI1 bit clock (See IMX6DQRM reference manual):
 *  pll4                                    -- 24e6 * (DIV_SELECT + NUM/DENOM)
 *    pll4_bypass                           -- Bypass PLL4: CCM_ANALOG_PLL_AUDIO[BYPASS]
 *      pll4_audio                          -- Enable PLL4: CCM_ANALOG_PLL_AUDIO[ENABLE]
 *        pll4_post_div                     -- Divide PLL4: CCM_ANALOG_PLL_AUDIO[POST_DIV_SELECT]
 *          pll4_audio_div                  -- Reserved: Fixed factor of x1
 *            ssi1_sel                      -- Clock multiplexer
 *              ssi1_pred                   -- Divide SSI1: CS1CDR[SSI1_CLK_PRED]
 *                ssi1_podf                 -- Divide SSI1: CS1CDR[SSI1_CLK_PODF]
 *                  ssi1 (SSI1_CLK_ROOT)    -- Clock gate: CCM_CCGR5[CG9]
 *                    ssi1 (Int. bit clock) -- Divide SSI1: STCCR[DIV2, PSR, PM] (See formula below)
 *
 * With the following constraint:
 *  - (DIV_SELECT + NUM/DENOM): Must be between 27 and 54: PLL4 clock between 650 and 1300 MHz
 *  - DENOM = 24e6: As implemented in clk_pllv3_av_set_rate()
 *  - POST_DIV_SELECT: Can divide by [1; 2; 4]
 *  - SSI1_CLK_PRED: Can divide by [1, 8]
 *  - SSI1_CLK_PODF: Can divide by [1, 64]
 *  - DIV2 and PSR = 0: As implemented in fsl_ssi_set_bclk()
 *  - PM > 0: Since DIV2, PSR and PM should not be all set to zero at the same time.
 *  - SSI bit clock = SSI1_CLK_ROOT / ((DIV2 + 1) * (7 * PSR + 1) * (PM + 1) * 2)
 *
 * SSI bit clock needs to be equal to 3072000 Hz (for 2 channels/stereo, 48kHz) since:
 *  - For 2 channels, slot width is fixed to 32 bits since in I2S Master mode, and STCCR[WL] are
 *    used to control the amount of valid data in those 32 bits.
 *  - 2 slots are used, one for each channel. The slot number (STCCR[DC]) is fixed to 2.
 *  => SSI bit clock = 48000 * 32 * 2 = 3072000
 *
 * SSI bit clock needs to be equal to 1536000 Hz (for 1 channel/mono, 48kHz) since:
 *  - Slot width is set to 16 bits, in I2S Normal mode.
 *  - 2 slots are used (fixed to 2), and data are only provided in first slot
 *  => SSI bit clock = 48000 * 16 * 2 = 1536000
 *
 * So SSI1_CLK_ROOT frequency needs to be equal to: 3072000 * (PM + 1) * 2 = 6144000 * (PM + 1)
 *
 * The following configuration is applied:
 *  - SSI1_SEL parent clock is configured to be PLL4_AUDIO_DIV
 *  - SSI1_SEL clock is automatically configured
 *  - PLL4 clock is set to 663.552 MHz, which is a multiple of 6144000 Hz (x 108).
 *    The PLL4 must be configured in the DTS otherwise Linux keeps the default/reset values, which
 *    are invalid. /sys/kernel/debug/clk/clk_summary report 147456000 Hz but the generated clock
 *    is not at this frequency.
 *  - SSI1_CLK_ROOT is set to 18.432 MHz. (18.432 * 36 = 663.552 MHz)
 *  - STCCR[PM] will be automatically set to 2. (18.432 / (2 + 1) / 2 = 3.072 MHz)
 */
&ssi1 {
    fsl,mode = "i2s-master";
    assigned-clocks = <&clks IMX6QDL_CLK_SSI1_SEL>, <&clks IMX6QDL_CLK_PLL4>, <&clks IMX6QDL_CLK_SSI1>;
    assigned-clock-parents = <&clks IMX6QDL_CLK_PLL4_AUDIO_DIV>;
    assigned-clock-rates = <0>, <663552000>, <18432000>;
    status = "okay";
};

/* For iomuxc, pin configuration (pad setting value):
 *  - Bit 0: Slew rate: 1 = fast, 0 = slow
 *  - Bit 3-5: Drive Strength: 0 = HI-Z, 1 = 260 Ohm, 2 = 130 Ohm, 3 = 90 Ohm, 4 = 60 Ohm, 5 = 50 Ohm, 6 = 40 Ohm, 7 = 33 Ohm
 *  - Bit 6-7: Speed: 0 = Low, 1 and 2 = Medium, 3 = Maximum
 *  - Bit 11: Open drain: 0 = Disabled, 1 = Enabled
 *  - Bit 12: Pull / Keep Enable: 0 = Disabled, 1 = Enabled
 *  - Bit 13: Pull / Keep Select: 0 = Keep, 1 = Pull
 *  - Bit 14-15: Pull Up / Down config: 0 = 100K Down, 1 = 47K Up, 2 = 100K Up, 3 = 22K Up
 *  - Bit 16: Hysteresis Enable: 0 = Disabled, 1 = Enabled
 *  - Bit 30: SION: Software Input On Field.
 *  - Bit 31: NO_PAD_CTL: indicate this pin does not need config.
 *
 * See fsl,imx-pinctrl.txt, fsl,imx6q-pinctrl.txt, and pinctrl-bindings.txt
 * See also https://www.nxp.com/docs/en/application-note/AN5078.pdf
 */
&iomuxc {
    pinctrl_audmux: audmuxgrp {
        fsl,pins = <
            MX6QDL_PAD_KEY_ROW0__AUD5_TXD      0x110b0  /* AUDIO: DIN, D56, X_AUD5_TXD, SSI1_TXD */
            MX6QDL_PAD_KEY_COL0__AUD5_TXC      0x130b0  /* AUDIO: BCLK, D53, X_AUD5_TXC, SSI1_CLK */
            MX6QDL_PAD_KEY_COL1__AUD5_TXFS     0x130b0  /* AUDIO: LRCLK, D54, X_AUD5_TXFS, SSI1_FS */
        >;
    };
};