imx8mm sai3 and adau1761 driver

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

imx8mm sai3 and adau1761 driver

4,052 Views
tanyid
Contributor I

在调试adau1761时,驱动正常加载上去,但gplay a.wav时,总是报
[   43.439222] fsl-sai 30030000.sai: failed to derive required Rx rate: 2822400
[   43.446285] fsl-sai 30030000.sai: ASoC: can't set 30030000.sai hw params: -22
错误 提示,跟进源码中,发现在函数:

static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
{
    struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);
    unsigned char offset = sai->soc->reg_offset;
    unsigned long clk_rate;
    unsigned int reg = 0;
    u32 ratio, savesub = freq, saveratio = 0, savediv = 0;
    u32 id;
    int ret = 0;

    /* Don't apply to slave mode */
    if (sai->slave_mode[tx])
        return 0;

    fsl_sai_check_ver(dai);
    for (id = 0; id < FSL_SAI_MCLK_MAX; id++)
    {
        clk_rate = clk_get_rate(sai->mclk_clk[id]);

        if (!clk_rate)continue;

        ratio = clk_rate / freq;
        ret = clk_rate - ratio * freq;
printk("fsl_sai_set_bclk ret:%d \n",ret);//1996800

        /*
         * Drop the source that can not be
         * divided into the required rate.
         */
        if (ret != 0 && clk_rate / ret < 1000) //
            continue;

printk("fsl_sai_set_bclk line:%d \n",__LINE__);
        if ((ratio % 2 == 0 && ratio >= 2 && ratio <= 512) ||(ratio == 1 && sai->verid.id >= FSL_SAI_VERID_0301))
        {
printk("fsl_sai_set_bclk line:%d \n",__LINE__);
            if (ret < savesub) {
printk("fsl_sai_set_bclk line:%d \n",__LINE__);
                saveratio = ratio;
                sai->mclk_id[tx] = id;
                savesub = ret;
            }
printk("fsl_sai_set_bclk line:%d ret %d\n",__LINE__,ret);
            if (ret == 0)
                break;
        }
    }

    if (saveratio == 0) {
        printk("ratio %d sai->verid.id %d\n",ratio,sai->verid.id);//8 0
        dev_err(dai->dev, "failed to derive required %cx rate: %d\n",tx ? 'T' : 'R', freq);
        return -EINVAL;
    }

        if (ret != 0 && clk_rate / ret < 1000) //
            continue;


,这个判断条件值引用的sai3的配置

&sai3 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_sai3>;
    assigned-clocks = <&clk IMX8MM_CLK_SAI3_SRC>,
            <&clk IMX8MM_CLK_SAI3_DIV>;
    assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL1_OUT>;
    assigned-clock-rates = <0>, <49152000>;
    status = "okay";
};

按这些条件计算,根本不会大于1000,配成最大值 得到的结果也只有:41.967213。
所以,这个是sai3配置是否有错?这个问题要如何解决?

我的需求是sai配成master模式,收发时钟都要提供,adau1761工作在slave模式下。

0 Kudos
11 Replies

3,886 Views
weidong_sun
NXP TechSupport
NXP TechSupport

Hi Tan,

有这样几个建议,供你参考:

1. 关于硬件ADAU1761

我看了一下它的datasheet,它的用法与WM8960外部接口非常相似,首先要保证您的硬件连接是正确的。它有I2C接口,与I.MX8MM-EVK的WM8524不太一样。

2. 关于sai3节点配置

&sai3 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_sai3>;
    assigned-clocks = <&clk IMX8MM_CLK_SAI3>;
    assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL1_OUT>;
    assigned-clock-rates = <24576000>;
    status = "okay";
};

这里的24.576MHz是给audio codec的工作时钟,这个时钟对您来说,不需要修改。ADAU1761的PLL输入clock是8-27MHz,您用49.152MHz是很容易出错的: 内部的PLL是无法使用的

这是它datasheet中,给出对24.576MHz的配置方法:

pastedImage_2.png

3. 您可以参考的代码

对于Linux ALSA SoC driver,需要3个部分才能把声卡驱动起来:

1. platform driver:  fsl_sai.c

2. codec driver :  adau17x1.c (linux 系统提供了这个driver)

另外的DSP firmware,我看到ADI提供了方法如何加载带目标板上,供linux driver调用它:

SigmaDSP Firmware Utility for Linux [Analog Devices Wiki]

3. Machine driver :

这个需要您自己动手写,可以参考的代码是imx-wm8960.c,这个driver,就是基于 sai I2S的,所以您的驱动架构需要和它差不多。

4. 关于CPU端做Master的配置,是这样的:

fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
            SND_SOC_DAIFMT_CBM_CFM;

ret = snd_soc_dai_set_fmt(cpu_dai, fmt);

如果您这样配置:

fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
            SND_SOC_DAIFMT_CBS_CFS;

ret = snd_soc_dai_set_fmt(cpu_dai, fmt);

那么CPU端就是slave了。

5. 关于SAI3引脚复用

我们EVK给出了SAI这样的复用:

                MX8MM_IOMUXC_SAI3_TXFS_SAI3_TX_SYNC     0xd6
                MX8MM_IOMUXC_SAI3_TXC_SAI3_TX_BCLK      0xd6
                MX8MM_IOMUXC_SAI3_MCLK_SAI3_MCLK        0xd6
                MX8MM_IOMUXC_SAI3_TXD_SAI3_TX_DATA0     0xd6

数据线只有TXD,您还需要再加上RXD接收线:

                MX8MM_IOMUXC_SAI3_RXD_SAI3_RX_DATA0   0xd6

这样就完整了。

上面的建议,对于您移植 adau1761来说,够用了!

Have a nice day!

B.R,

Weidong

0 Kudos

2,270 Views
shao-gaoyan
Contributor II

你好我准备在imx8mp芯片上使用TLV320AIC3110音频解码芯片。当前环境是没有TLV320AIC3110芯片的

数据手册:

https://www.ti.com/lit/ds/symlink/tlv320aic3110.pdf?ts=1676947942331&ref_url=https%253A%252F%252Fwww...

设备树配置:

&sai3 {
 pinctrl-names = "default";
 pinctrl-0 = <&pinctrl_sai3>;
 assigned-clocks = <&clk IMX8MP_CLK_SAI3>;
 assigned-clock-parents = <&clk IMX8MP_AUDIO_PLL1_OUT>;
 assigned-clock-rates = <12288000>;
 clocks = <&audio_blk_ctrl IMX8MP_CLK_AUDIO_BLK_CTRL_SAI3_IPG>,   <&clk  IMX8MP_CLK_DUMMY>,
 <&audio_blk_ctrl IMX8MP_CLK_AUDIO_BLK_CTRL_SAI3_MCLK1>, <&clk IMX8MP_CLK_DUMMY>,
 <&clk IMX8MP_CLK_DUMMY>;
 clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
 fsl,sai-mclk-direction-output;
 status = "okay";
};
 
sound-tlv320aic31xx {
 compatible = "simple-audio-card";
 simple-audio-card,name = "TI-TLV320AIC31xx-Card";
 simple-audio-card,format = "i2s";
 simple-audio-card,bitclock-master = <&dailink_master>;
 simple-audio-card,frame-master = <&dailink_master>;
 simple-audio-card,widgets =
 "Microphone", "Microphone Jack",
 "Headphone", "Headphone Jack",
 "Speaker", "Speaker Line";
 simple-audio-card,routing =
 "Headphone Jack", "HPL",
 "Headphone Jack", "HPR",
 "Speaker Line", "SPL",
 "Speaker Line", "SPR",
 "MIC1RP", "Microphone Jack";
 dailink_master: simple-audio-card,cpu {
 sound-dai = <&sai3 0>;
 };
 
 simple-audio-card,codec {
  sound-dai = <&tlv320aic31xx>;
 
  clocks = <&clk IMX8MP_CLK_SAI3_ROOT>;
 };
};
 
确认点:
我尝试看了代码,好像能正确执行下去的只能改变sai->mclk_clk的值。因为刚接触alsa,不了解原理。所以希望得到你的帮助。
1. 下面函数中的sai->mclk_clk[]中的值只和sai3有关吗?与codec有没有关系?
 
static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);
unsigned int ofs = sai->soc_data->reg_offset;
unsigned long clk_rate;
int adir = tx ? RX : TX;
int dir = tx ? TX : RX;
unsigned int reg = 0;
u32 ratio, savesub = freq, saveratio = 0, savediv = 0;
u32 id;
int ret = 0;
 
dev_dbg(dai->dev, "%s freq = %ld\n", __func__, freq);

/* Don't apply to slave mode */
if (sai->slave_mode[tx])
return 0;

/*
* There is no point in polling MCLK0 if it is identical to MCLK1.
* And given that MQS use case has to use MCLK1 though two clocks
* are the same, we simply skip MCLK0 and start to find from MCLK1.
*/
id = sai->soc_data->mclk0_is_mclk1 ? 1 : 0;
 
dev_dbg(dai->dev, "%s id = %ld\n", __func__, id);

for (; id < FSL_SAI_MCLK_MAX; id++) {
clk_rate = clk_get_rate(sai->mclk_clk[id]);
dev_dbg(dai->dev, "%s clk_rate = %ld\n", __func__, clk_rate);
if (!clk_rate)
continue;

ratio = clk_rate / freq;

ret = clk_rate - ratio * freq;
dev_dbg(dai->dev, "%s ret = %d\n", __func__, ret);
 
/*
* Drop the source that can not be
* divided into the required rate.
*/
if (ret != 0 && clk_rate / ret < 1000)
continue;
...
}
 
Mar 11 00:53:29.169290 fedge-v0-2-0 kernel: 30c30000.sai-tlv320aic31xx-hifi: ASoC: soc_pcm_hw_params() failed (-22)
Mar 11 00:53:29.187628 fedge-v0-2-0 kernel: tlv320aic31xx-codec 2-0018: ## aic31xx_hw_params: width 16 rate 44100
Mar 11 00:53:29.188244 fedge-v0-2-0 kernel: tlv320aic31xx-codec 2-0018: pll 7.3500/1 dosr 128 n 8 m 2 aosr 128 n 8 m 2 bclk_n 8
Mar 11 00:53:29.188714 fedge-v0-2-0 kernel: tlv320aic31xx-codec 2-0018: Update DAI routes for tlv320aic31xx-hifi capture
Mar 11 00:53:29.189156 fedge-v0-2-0 kernel: tlv320aic31xx-codec 2-0018: Connecting DAI route AIF OUT -> Capture
Mar 11 00:53:29.189599 fedge-v0-2-0 kernel: fsl-sai 30c30000.sai: bclk = 1411200, rate = 44100, sai->bclk_ratio = 0, slots * slot_width = 2 * 16
Mar 11 00:53:29.190097 fedge-v0-2-0 kernel: fsl-sai 30c30000.sai: fsl_sai_set_bclk freq = 1411200
Mar 11 00:53:29.199863 fedge-v0-2-0 kernel: fsl-sai 30c30000.sai: fsl_sai_set_bclk id = 0
Mar 11 00:53:29.200900 fedge-v0-2-0 kernel: fsl-sai 30c30000.sai: fsl_sai_set_bclk clk_rate = 400000000
Mar 11 00:53:29.206658 fedge-v0-2-0 kernel: fsl-sai 30c30000.sai: fsl_sai_set_bclk ret = 630400

Mar 11 00:53:29.212523 fedge-v0-2-0 kernel: fsl-sai 30c30000.sai: fsl_sai_set_bclk clk_rate = 12288000
Mar 11 00:53:29.224682 fedge-v0-2-0 kernel: fsl-sai 30c30000.sai: fsl_sai_set_bclk ret = 998400
Mar 11 00:53:29.236180 fedge-v0-2-0 kernel: fsl-sai 30c30000.sai: fsl_sai_set_bclk clk_rate = 0
Tags (1)
0 Kudos

2,247 Views
shao-gaoyan
Contributor II

看了设备树

https://www.kernel.org/doc/Documentation/devicetree/bindings/sound/simple-card.txt

 simple-audio-card,bitclock-master = <&dailink_master>;
 simple-audio-card,frame-master = <&dailink_master>;
master cpu改为了codec,将跳过static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)函数
请问这是一个正确的解决方案吗?
0 Kudos

2,262 Views
shao-gaoyan
Contributor II

我又尝试了在wm8960上的播放。

我先前的理解可能有错误:

1. 下面函数中的sai->mclk_clk[]中的值应该与codec无关。

2.是与下面的函数中的rate有关? struct snd_pcm_hw_params *params 请问这个参数是与谁有关呢?

(因为刚接触还不了解alsa,所以问题可能问的不是很清楚。我自己正在追寻params的源头,但是如果能直接告诉我的,那就更好了)

static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
unsigned int ofs = sai->soc_data->reg_offset;
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
unsigned int channels = params_channels(params);
u32 word_width = params_width(params);
u32 rate = params_rate(params);
...
}
0 Kudos

3,886 Views
xiewei_linux
Contributor I

您好!

  请问imx8mm sai3上接wm8960 dts怎么配置?我的软件版本是imx-p9.0.0_2.3.0 linux是4.14.98 

我目前的配置如下:

wm8960: wm8960@1a {
   compatible = "wlf,wm8960";
   reg = <0x1a>;
   clocks = <&clk IMX8MM_CLK_SAI3_ROOT>;
   clock-names = "mclk";
   wlf,shared-lrclk;
   status = "okay";
};

sound-wm8960 {
compatible = "fsl,imx7d-evk-wm8960",
"fsl,imx-audio-wm8960";
model = "wm8960-audio";
cpu-dai = <&sai3>;
audio-codec = <&wm8960>;
//codec-rpmsg;
codec-master;
/*
* hp-det = <hp-det-pin hp-det-polarity>;
* hp-det-pin: JD1 JD2 or JD3
* hp-det-polarity = 0: hp detect high for headphone
* hp-det-polarity = 1: hp detect high for speaker
*/
//hp-det = <2 0>;
//hp-det-gpios = <&gpio1 13 0>;
//mic-det-gpios = <&gpio1 13 0>;
audio-routing =
"Headphone Jack", "HP_L",
"Headphone Jack", "HP_R",
"Ext Spk", "SPK_LP",
"Ext Spk", "SPK_LN",
"Ext Spk", "SPK_RP",
"Ext Spk", "SPK_RN",
"LINPUT2", "Mic Jack",
"LINPUT3", "Mic Jack",
"RINPUT1", "Main MIC",
"RINPUT2", "Main MIC",
"Mic Jack", "MICB",
"Main MIC", "MICB";
status = "okay";
};

pinctrl_sai3: sai3grp {
fsl,pins = <
MX8MM_IOMUXC_SAI3_TXFS_SAI3_TX_SYNC 0xd6
MX8MM_IOMUXC_SAI3_TXC_SAI3_TX_BCLK 0xd6
MX8MM_IOMUXC_SAI3_MCLK_SAI3_MCLK 0xd6
MX8MM_IOMUXC_SAI3_TXD_SAI3_TX_DATA0 0xd6
MX8MM_IOMUXC_SAI3_RXD_SAI3_RX_DATA0 0xd6
>;
};

&sai3 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_sai3>;
assigned-clocks = <&clk IMX8MM_CLK_SAI3>;
assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL1_OUT>;
assigned-clock-rates = <24576000>; //12288000 24576000 12289600
fsl,sai-asynchronous;
status = "okay";
};

以上配置,

tinyplay 播放wav文件 始终没有输出,并且有提示播放采样率错误

[ 891.073461]  wm8960_set_dai_sysclk 1277
[ 891.077774]  wm8960_hw_params 802
[ 891.081543] wm8960_hw_params 830 wm8960->lrclk=16000
[ 891.087233] wm8960_configure_clocking 738 wm8960->freq_in=24576000
[ 891.093883] wm8960_configure_sysclk 640 bclk=512000 lrclk=16000
Playing sample: 2 ch, 16000 hz, 16 bit

[ 891.102622] wm8960_set_bias_level_out3 888

[ 891.110270]  wm8960_configure_clocking 738 wm8960->freq_in=24576000
[ 891.116979] [wm8960_configure_sysclk 640 bclk=512000 lrclk=16000
[ 891.124857] wm8960_mute 868 mute = 0
Error playing sample

[ 901.221110]  wm8960_mute 868 mute = 1

evk_8mm:/storage/emulated/0/Download # [ 905.696469] healthd: battery l=85 v=3 t=35.0 h=2 st=2 c=400 fc=4000000 cc=32 chg=a
[ 905.832237] healthd: battery l=85 v=3 t=35.0 h=2 st=2 c=400 fc=4000000 cc=32 chg=a
[ 906.341049]  wm8960_set_bias_level_out3 888
[ 906.345724]  wm8960_set_bias_level_out3 914
[ 906.352038]  wm8960_set_bias_level_out3 929

0 Kudos

3,886 Views
weidong_sun
NXP TechSupport
NXP TechSupport

Hi wei xie,

WM8960在我们的I.MX6UL的开发板上有使用,linux BSP也支持它。

---platform: fsl_sai.c

---codec: wm8960.c

--Machine : imx-wm8960.c

这里的 imx-wm8960.c是for i.MX6UL的Machine driver,对您使用i.MX8MM SOC来说,你需要根据imx-wm8960.c再写一个Machine driver,而不能直接使用。例如,您可以起一个新的名字imx8mm-wm8960.c,做为您的Machine driver.

而device tree的配置方法,您可以参考imx6ul-14x14-evk.dts中的配置,两个节点:

sound和I2C 节点。同时注意node中member的含义,比如:gpr = <&gpr 4 0x100000 0x100000>;这个您就不需要,这是配置I.MX6UL中MCLK为24MHz输出,做为WM8960时钟的。

对您的I.MX8MM来说,codec的工作时钟配置的是24.576MHz,而且,i.mx8mm是master,所以,你节点中的codec_master应该去掉。

另外,你在调试audio的时候,play的时候,要注意的是,sample rate是在machine driver中硬件初始化时,从音频流中获取的,也就是说它来时您要播放的文件,所以,你要跟踪一下。 这一点参考imx-wm8960.c就可以,只是要注意的是master和slave的配置方法是不一样的。

 Hope above information is helpful for you.

Have  a nice day!

B.R,

Weidong

0 Kudos

3,886 Views
xiewei_linux
Contributor I

Hi Weidong :

   代码中的imx-wm8960.c 不能在imx8mm 上直接用,具体是有啥区别,我看代码里面没有特定soc的配置,

上面用户在imx8mm linux 上本来是要调 adau1761 但是他后面换成wm8960 直接使用起来了

《非常感谢!adau1761 与wm8960差异太大。现在使用WM8960模块,驱动起来,功能正常。非常感谢!

再请教:imx8mm linux怎么设置成横屏?》

谢谢!

0 Kudos

3,886 Views
weidong_sun
NXP TechSupport
NXP TechSupport

横屏的问题,你再重新开一个ticket。这里讨论的音频,就算是结贴了。

weidong

0 Kudos

3,886 Views
tanyid
Contributor I

非常感谢!adau1761 与wm8960差异太大。现在使用WM8960模块,驱动起来,功能正常。非常感谢!

再请教:imx8mm linux怎么设置成横屏?

0 Kudos

3,886 Views
weidong_sun
NXP TechSupport
NXP TechSupport

你可以参考这里修改一下试试,如果不行,你单独提交一个帖子上来。我们一般希望一个帖子讨论一个问题。

LCD横竖屏显示_alifrank的博客-CSDN博客 

伟东

0 Kudos

3,886 Views
tanyid
Contributor I


1.这个参考我试过,不能解决。

2.请移步这个问题,里面igorpadykov有提示patch的问题,目前还没有得到回复。请从内部帮我问一问。

https://community.nxp.com/thread/521316


How To Rotate 90 Degree Video For Display In I.MX8X

Hi Bright
   rotation patch was sent via mail.

Best regards
igor

3.我单独的开了一 个贴子,但没有解答。请支持。
https://community.nxp.com/thread/534933

谢谢你的协助。

0 Kudos