我正在基于IMX6 Solo processor和TX6S-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信号。有人对此问题有任何想法吗? 谢谢。 最好的问候!
答案 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:3ff86050da41e072dd9fffc373c4f5691573cf4e:clk: 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的时钟。codec
和sound
卡.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 */
>;
};
};