WM8978移植到imx6或imx8上

有人移植过WM8978的音频吗?求指教啊~~~~~~~~~~~~~~~~~~~~~~~~~~

 

 

设备树:
MX8MM_IOMUXC_SAI3_RXD_SAI3_RX_DATA0     0xd6
驱动:
sound/soc/soc-pcm.c
sound/soc/codecs/wm8978.c
sound/soc/fsl/imx-ak5558.c
kernel-source/include/sound/soc.h 包括snd_soc头文件定义
snd_soc_codec *codec
    snd_soc_codec_get_drvdata(codec)

    soc_dai_hw_params

        devm_snd_soc_register_card
imx-wm8962.c
        hpjack_status_check;// 相当于耳机插拔的中断回调函数。
        snd_soc_jack_add_gpios(&imx_hp_jack, 1, &imx_hp_jack_gpio);//耳机插拔的中断操作,实际上是在这个函数里进行的。
ASoC有把Platform驱动分为两个部分:snd_soc_platform_driver和snd_soc_dai_driver。其中,platform_driver负责管理音频数据,把音频数据通过dma或其他操作传送至cpu dai中,dai_driver则主要完成cpu一侧的dai的参数配置,同时也会通过一定的途径把必要的dma等参数与snd_soc_platform_driver进行交互。
(1)ALSA是Advanced Linux Sound Architecture  高级音频架构
(2)PCM是英文Pulse-code modulation        脉冲编码调制
(3)ASoC--ALSA System on Chip:   建立在标准ALSA驱动层上,为了更好地支持嵌入式处理器和移动设备 中的音频Codec的一套软件体系。
①Machine 是指某一款机器
②Platform 一般是指某一个SoC平台
③Codec 字面上的意思就是编解码器
更多https://www.cnblogs.com/blogs-of-lxl/p/6538769.html


platform driver(i2c)的name要和前面 snd_soc_dai_link 结构中定义的codec_name相同

356 static struct platform_driver imx_ak5558_driver = {
357     .driver = {
358         .name = "imx-ak5558",
359         .pm = &snd_soc_pm_ops,
360         .of_match_table = imx_ak5558_dt_ids,
361     },
362     .probe = imx_ak5558_probe,

Codec:
两个重要的结构体snd_soc_dai_driver与snd_soc_codec_driver。
snd_soc_dai_driver主要用来描述codec的数据传输接口:
    static const struct snd_soc_dai_ops rt5651_aif_dai_ops = {
    .hw_params = rt5651_hw_params,
    .set_fmt = rt5651_set_dai_fmt,
    .set_sysclk = rt5651_set_dai_sysclk,
    .set_pll = rt5651_set_dai_pll,
};
static struct snd_soc_dai_driver rt5651_dai[] = {
    {
        .name = "rt5651-aif1",
        .id = RT5651_AIF1,
        .playback = {//代表输出通道1
            .stream_name = "AIF1 Playback",
            .channels_min = 1,
            .channels_max = 2,
            .rates = RT5651_STEREO_RATES,//代表波特率
            .formats = RT5651_FORMATS,//
        },
        .capture = {//代表输入通道1
            .stream_name = "AIF1 Capture",
            .channels_min = 1,
            .channels_max = 2,
            .rates = RT5651_STEREO_RATES,//代表波特率
            .formats = RT5651_FORMATS,//数据格式
        },
        .ops = &rt5651_aif_dai_ops,/*主要用于设置硬件的参数*/
    },

snd_soc_codec_driver 用来描述控制接口:
    static struct snd_soc_codec_driver soc_codec_dev_rt5651 = {
    .probe = rt5651_probe,
    .suspend = rt5651_suspend,
    .resume = rt5651_resume,
    .set_bias_level = rt5651_set_bias_level,
    .idle_bias_off = true,
    .controls = rt5651_snd_controls,
    .num_controls = ARRAY_SIZE(rt5651_snd_controls),
    .dapm_widgets = rt5651_dapm_widgets,
    .num_dapm_widgets = ARRAY_SIZE(rt5651_dapm_widgets),
    .dapm_routes = rt5651_dapm_routes,
    .num_dapm_routes = ARRAY_SIZE(rt5651_dapm_routes),
};
snd_soc_codec_driver 其主要提供了读写编解码寄存器的函数。在snd_soc_dai_driver 结构体中的.ops = &rt5651_aif_dai_ops中的操作,肯定需要使用snd_soc_codec_driver soc_codec_dev_rt5651中的一些读写函数。

platform:
目录;kernel/sound/soc/soc-core.c
ASoC又把Platform驱动分为两个部分:snd_soc_platform_driver和snd_soc_dai_driver。
snd_soc_dai_driver
static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = {
    /*设置参数*/
    .hw_params = rockchip_i2s_hw_params,
    .set_sysclk = rockchip_i2s_set_sysclk,
    .set_fmt = rockchip_i2s_set_fmt,
    /*启动数据传输*/
    .trigger = rockchip_i2s_trigger,
};
static struct snd_soc_dai_driver rockchip_i2s_dai = {
    .probe = rockchip_i2s_dai_probe,
    .playback = {
        .stream_name = "Playback",//名字
        .channels_min = 2,  //参数
        .channels_max = 8,
        .rates = SNDRV_PCM_RATE_8000_192000,
        .formats = (SNDRV_PCM_FMTBIT_S8 |
                SNDRV_PCM_FMTBIT_S16_LE |
                SNDRV_PCM_FMTBIT_S20_3LE |
                SNDRV_PCM_FMTBIT_S24_LE |
                SNDRV_PCM_FMTBIT_S32_LE),
    },
    .capture = {
        .stream_name = "Capture",
        .channels_min = 2,
        .channels_max = 2,
        .rates = SNDRV_PCM_RATE_8000_192000,
        .formats = (SNDRV_PCM_FMTBIT_S8 |
                SNDRV_PCM_FMTBIT_S16_LE |
                SNDRV_PCM_FMTBIT_S20_3LE |
                SNDRV_PCM_FMTBIT_S24_LE |
                SNDRV_PCM_FMTBIT_S32_LE),
    },
    .ops = &rockchip_i2s_dai_ops,
};
static int rockchip_i2s_probe(struct platform_device *pdev)
ret = devm_snd_soc_register_component(&pdev->dev,&rockchip_i2s_component,soc_dai, 1);

snd_soc_platform_driver
static const struct snd_pcm_ops dmaengine_mpcm_ops = {
    .open        = dmaengine_mpcm_open,
    .close        = dmaengine_mpcm_close,
    .ioctl        = snd_pcm_lib_ioctl,
    .hw_params    = dmaengine_mpcm_hw_params,
    .hw_free    = snd_pcm_lib_free_pages,
    .trigger    = snd_dmaengine_mpcm_trigger,
    .pointer    = dmaengine_mpcm_pointer,
};

static const struct snd_soc_platform_driver dmaengine_mpcm_platform = {
    .component_driver = {
        .probe_order = SND_SOC_COMP_ORDER_LATE,
    },
    .ops        = &dmaengine_mpcm_ops,
    .pcm_new    = dmaengine_mpcm_new,
};
int snd_dmaengine_mpcm_register(struct rk_mdais_dev *mdais)
        ret = snd_soc_add_platform(dev, &pcm->platform,&dmaengine_mpcm_platform);
Machine部分:
snd_soc_card rockchip_sound_card结构体,snd_soc_card结构体中又包含了dai_link成员。dai_link中的.codec_dai_name = "rt5651-aif1"必须与codec中的snd_soc_dai_driver rt5651_dai的.name = "rt5651-aif1"对应。

static struct snd_soc_ops rockchip_sound_rt5651_hifi_ops = {
    .hw_params = rockchip_rt5651_hw_params,
};
static struct  rockchip_dailinks[] = {
    [DAILINK_RT5651_HIFI] = {
        .name = "RT5651 HIFI",
        .stream_name = "RT5651 PCM",
        .codec_dai_name = "rt5651-aif1",
        .ops = &rockchip_sound_rt5651_hifi_ops,
        /* set rt5651 as slave */
        .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
            SND_SOC_DAIFMT_CBS_CFS,
    },
    [DAILINK_RT5651_VOICE] = {
        .name = "RT5651 HDMIIN",
        .stream_name = "RT5651 PCM",
        .codec_dai_name = "rt5651-aif2",
        .ops = &rockchip_sound_rt5651_voice_ops,
        /* set rt5651 as slave */
        .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
            SND_SOC_DAIFMT_CBS_CFS,
    },
    [DAILINK_TC358749_HDMIIN] = {
        .name = "TC358749 HDMIIN",
        .stream_name = "TC358749 PCM",
        .codec_dai_name = "tc358749x-audio",
    },
};

static struct snd_soc_card rockchip_sound_card = {
    .name = "realtekrt5651codec_hdmiin",
    .owner = THIS_MODULE,
    .dai_link = rockchip_dailinks,
    .num_links =  ARRAY_SIZE(rockchip_dailinks),
    .dapm_widgets = rockchip_dapm_widgets,
    .num_dapm_widgets = ARRAY_SIZE(rockchip_dapm_widgets),
    .dapm_routes = rockchip_dapm_routes,
    .num_dapm_routes = ARRAY_SIZE(rockchip_dapm_routes),
    .controls = rockchip_controls,
    .num_controls = ARRAY_SIZE(rockchip_controls),
};
static int rockchip_sound_probe(struct platform_device *pdev)
{
    struct snd_soc_card *card = &rockchip_sound_card;
    /*以"rockchip,cpu"为参数,使用of_parse_phandle获取I2S adapter的device node*/
    cpu_node = of_parse_phandle(pdev->dev.of_node, "rockchip,cpu", 0);
    
    /*machine驱动负责platform与code之间的耦合*/
    for (i = 0; i < DAILINK_ENTITIES; i++) {
        /*决定使用哪个平台*/
        rockchip_dailinks[i].platform_of_node = cpu_node;
        /**/
        rockchip_dailinks[i].cpu_of_node = cpu_node;

        /*以"rockchip,codec"为参数,使用of_parse_phandle获取sound codec的device node*/
        /*决定使用哪个编解码芯片*/
        rockchip_dailinks[i].codec_of_node =
            of_parse_phandle(pdev->dev.of_node,
                     "rockchip,codec", i);
        if (!rockchip_dailinks[i].codec_of_node) {
            dev_err(&pdev->dev,
                "Property[%d] 'rockchip,codec' failed\n", i);
            return -EINVAL;
        }
    }

    card->dev = &pdev->dev;
    platform_set_drvdata(pdev, card);
    ret = devm_snd_soc_register_card(&pdev->dev, card);
    if (ret)
        dev_err(&pdev->dev, "%s register card failed %d\n",
            __func__, ret);

    dev_info(&pdev->dev, "snd_soc_register_card successful\n");
    return ret;
}
最后我们可以看到其调用了devm_snd_soc_register_card,把进行注册:
int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card)
    ret = snd_soc_register_card(card);
        /*在该函数内,会做很多工作,如绑定dai等等*/
        ret = snd_soc_instantiate_card(card);
            /*绑定完成之后创建一个声卡,此时没有生成设备节点*/
            ret = snd_card_new(card->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,card->owner, 0, &card->snd_card);
            /*调用snd_card_register注册之后,生成设备节点*/
            ret = snd_card_register(card->snd_card);    
ASoC框架分三个部分:
a. platform(用来描述芯片的DAI[音频数字]接口、负责数据传输)
    DAI:snd_soc_dai_driver
            用来表示支持哪些格式数据
            提供设置格式的函数
            启动数据传输
    数据传输:snd_soc_platform_driver
b. codec (用来描述音频编解码芯片,2部分:DAI接口、控制接口)
    DAI:snd_soc_dai_driver
            用来表示支持哪些格式数据
            提供设置格式的函数
    控制接口:snd_soc_codec_driver
c. machine(snd_cod_card,snd_soc_dai_link)
        用来确定使用哪一个platform,哪一个codec芯片
        可能会注册一个名为“soc-audio”的平台设备
        导致soc-core.c中的soc_probe函数被调用
        进而分配/设置/注册 snd_card
设备树:
    rt5651-sound {
        status = "okay";
        compatible = "simple-audio-card";
        /*指定声卡传输数据格式,是通过"i2s"*/
        simple-audio-card,format = "i2s";
        /*声卡的名字为realtek,rt5651-codec,可以通过*/
        simple-audio-card,name = "realtek,rt5651-codec";
        /*猜测是混合声音的时钟信号*/
        simple-audio-card,mclk-fs = <256>;
        /*声音的部件,麦克风,耳机等等*/
        simple-audio-card,widgets =
            "Microphone", "Mic Jack",
            "Headphone", "Headphone Jack";
        /*/*声音的部件,第一个指定的是接收器,第二个指定的是接收员*/*/
        simple-audio-card,routing =
            "Mic Jack", "MICBIAS1",
            "IN1P", "Mic Jack",
            "Headphone Jack", "HPOL",
            "Headphone Jack", "HPOR";
        /*根据我们的原理图,可以知道,传输数据的i2s为i2s0*/
        simple-audio-card,cpu {
            sound-dai = <&i2s0>;
        };
        /*rt5651为我们编码器的节点*/
        simple-audio-card,codec {
            sound-dai = <&rt5651>;
        };
    };
&i2c1 {
    status = "okay";
    i2c-scl-rising-time-ns = <300>;
    i2c-scl-falling-time-ns = <15>;
    /*编码器节点*/
    rt5651: rt5651@1a {
        status = "okay";
        #sound-dai-cells = <0>;
        compatible = "rockchip,rt5651";
        reg = <0x1a>;
        clocks = <&cru SCLK_I2S_8CH_OUT>;
        clock-names = "mclk";
        pinctrl-names = "default";
        pinctrl-0 = <&i2s_8ch_mclk>;
        /*扬声器使能引脚*/
        spk-con-gpio = <&gpio0 11 GPIO_ACTIVE_HIGH>;
        /*监测是否有耳机插入*/
        hp-det-gpio = <&gpio4 28 GPIO_ACTIVE_LOW>;
    };
};

route包括3个部分:sink(获得数据),kontrol(控制寄存器),source(发出数据)


codec的输入输出引脚:

snd_soc_dapm_output
snd_soc_dapm_input
外接的音频设备:
snd_soc_dapm_hp
snd_soc_dapm_spk
snd_soc_dapm_line
音频流(stream domain):
snd_soc_dapm_adc
snd_soc_dapm_dac
snd_soc_dapm_aif_out
snd_soc_dapm_aif_in
snd_soc_dapm_dai_out
snd_soc_dapm_dai_in
电源、时钟和其它:
snd_soc_dapm_supply
snd_soc_dapm_regulator_supply
snd_soc_dapm_clock_supply
snd_soc_dapm_kcontrol
————————————————
版权声明:本文为CSDN博主「DroidPhone」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/DroidPhone/article/details/13756651
其他链接
https://blog.csdn.net/DroidPhone/article/details/14548631
https://blog.csdn.net/weixin_43013761/article/details/89385135

应用:

设置声音 amixer scontrols
amixer set Headphone 100%
root@imx8mmevk:~# gplay-1.0 1.mp4 

FSL_GPLAY2_01.00_LINUX build on Mar 22 2019 14:48:45


====== AIUR: 4.4.5 build on Mar 22 2019 14:48:23. ======
    Core: MPEG4PARSER_06.16.01  build on Dec 11 2018 03:04:17
 file: /usr/lib/imx-mm/parser/lib_mp4_parser_arm_elinux.so.3.2
------------------------
    Track 00 [video_0] Enabled
    Duration: 0:00:02.600000000
    Language: eng
    Mime:
    video/x-h264, parsed=(boolean)true, alignment=(string)au, stream-format=(string)avc, width=(int)1920, height=(int)1080, framerate=(fraction)25/1, codec_data=(buffer)01640028ffe1003567640028acdb01e0089f97ff000100014a020202800001f4000061a870400007270e0003dcc57bdc1820000393870001ee62bdee0501000468ea43cb 
------------------------
====== VPUDEC: 4.4.5 build on Mar 22 2019 14:48:36. ======
    wrapper: 3.0.0 (VPUWRAPPER_ARM64_LINUX Build on Feb 21 2019 21:16:17)
    vpulib: 1.1.1
    firmware: 1.1.1.65535
------------------------
    Track 01 [audio_0] Enabled
    Duration: 0:00:02.581333000
    Language: eng
    Mime:
    audio/mpeg, mpegversion=(int)4, channels=(int)2, rate=(int)48000, bitrate=(int)192000, stream-format=(string)raw, codec_data=(buffer)1190 
------------------------
8524
[  139.446610] alloc_contig_range: [780b0, 780c0) PFNs busy
[  139.633627] alloc_contig_range: [780b0, 780c0) PFNs busy
[  139.640759] cjf wm8978 hw params 1 
[  139.644365] cjf wm8978 hw params 2 
[  139.647955] cjf wm8978 hw params 3.1 
[  139.651654] cjf wm8978 hw params 3.2 
[  139.655454] wm8978 1-001a: ASoC: can't set wm8978-hifi hw params: -22
[  139.661950] cjf wm8978 mute 1
[  139.665219] cjf wm8978 mute ok

[  139.668444] cjf wm8978 hw params 1 
[  139.671961] cjf wm8978 hw params 2 
[  139.675473] cjf wm8978 hw params 3.1 
[  139.679184] cjf wm8978 hw params 3.2 
[  139.682876] wm8978 1-001a: ASoC: can't set wm8978-hifi hw params: -22
[  139.689411] cjf wm8978 mute 1
[  139.692428] cjf wm8978 mute ok

[  139.695598] cjf wm8978 hw params 1 
[  139.699115] cjf wm8978 hw params 2 
[  139.702624] cjf wm8978 hw params 3.1 
[  139.706302] cjf wm8978 hw params 3.2 
[  139.710019] wm8978 1-001a: ASoC: can't set wm8978-hifi hw params: -22

8962:
[  128.118107] alloc_contig_range: [780b0, 780c0) PFNs busy
[  128.303987] alloc_contig_range: [780b0, 780c0) PFNs busy
[  128.311256] cjf wm8978 set dai fmt 1 
[  128.315627] cjf wm8978 set dai fmt ok 1 
[  128.319607] imx-wm8962 sound: failed to start FLL: -22
[  128.324840] imx-wm8962 sound: cjf ASoC: machine hw_params failed: -22
[  128.331354] cjf wm8978 dai sysclk 1 0, 0 ,0
[  128.335575] cjf wm8978 dai ok0
[  128.338657] imx-wm8962 sound: failed to stop FLL: -22
[  128.343831] cjf wm8978 set dai fmt 1 
[  128.348101] cjf wm8978 set dai fmt ok 1 
[  128.352069] imx-wm8962 sound: failed to start FLL: -22
[  128.357233] imx-wm8962 sound: cjf ASoC: machine hw_params failed: -22

root@imx8mmevk:~# dmesg | grep wm
[    4.450267] cjf i2c wm8978 probe 1
[    4.454048] cjf i2c wm8978 probe ok
[    4.498024] cjf wm8962 probe 1
[    4.501290] cjf wm8978 probe 2 
[    4.507151] cjf wm8978 probe ok
[    4.510504] cjf wm8978 set dai fmt 1 
[    4.514713] cjf wm8978 set dai fmt ok 1 
[    4.518744] imx-wm8962 sound: wm8962 <-> 30030000.sai mapping ok
[    4.524781] imx-wm8962 sound: ASoC: no source widget found for HPOUTL
[    4.531258] imx-wm8962 sound: ASoC: Failed to add route HPOUTL -> direct -> Headphone Jack
[    4.539538] imx-wm8962 sound: ASoC: no source widget found for HPOUTR
[    4.545989] imx-wm8962 sound: ASoC: Failed to add route HPOUTR -> direct -> Headphone Jack
[    4.554268] imx-wm8962 sound: ASoC: no source widget found for SPKOUTL
[    4.560805] imx-wm8962 sound: ASoC: Failed to add route SPKOUTL -> direct -> Ext Spk
[    4.568564] imx-wm8962 sound: ASoC: no source widget found for SPKOUTR
[    4.575103] imx-wm8962 sound: ASoC: Failed to add route SPKOUTR -> direct -> Ext Spk
[    4.582858] imx-wm8962 sound: ASoC: no source widget found for MICBIAS
[    4.589396] imx-wm8962 sound: ASoC: Failed to add route MICBIAS -> direct -> AMIC
[    4.596889] imx-wm8962 sound: ASoC: no sink widget found for IN3R
[    4.602993] imx-wm8962 sound: ASoC: Failed to add route AMIC -> direct -> IN3R
[    4.610226] imx-wm8962 sound: ASoC: no source widget found for MICBIAS
[    4.616764] imx-wm8962 sound: ASoC: Failed to add route MICBIAS -> direct -> DMIC
[    4.624257] imx-wm8962 sound: ASoC: no sink widget found for DMICDAT
[    4.630622] imx-wm8962 sound: ASoC: Failed to add route DMIC -> direct -> DMICDAT
[    4.638117] imx-wm8962 sound: ASoC: no source widget found for ASRC-Playback
[    4.645175] imx-wm8962 sound: ASoC: Failed to add route ASRC-Playback -> direct -> CPU-Playback
[    4.653887] imx-wm8962 sound: ASoC: no sink widget found for ASRC-Capture
[    4.660685] imx-wm8962 sound: ASoC: Failed to add route CPU-Capture -> direct -> ASRC-Capture
[    4.669223] imx-wm8962 sound: ASoC: no DMI vendor name!
[    4.674460] cjf wm8978 dai sysclk 1 0, 24576000 ,24576000
[    4.679866] cjf wm8978 dai 0
[    4.682755] cjf wm8978 dai 110
[    4.685818] cjf wm8978 dai ok0
[    4.689136] cjf wm8978 set bias level 1 
[    4.794821] cjf wm8962 probe ok
[    5.150845]   #0: wm8962-audio
root@imx8mmevk:~# dmesg | grep cjf
[    4.396688] cjf i2c ak4458 probe 1
[    4.411668] cjf i2c ak4458 probe 1
[    4.450267] cjf i2c wm8978 probe 1
[    4.454048] cjf i2c wm8978 probe ok
[    4.498024] cjf wm8962 probe 1
[    4.501290] cjf wm8978 probe 2 
[    4.507151] cjf wm8978 probe ok
[    4.510504] cjf wm8978 set dai fmt 1 
[    4.514713] cjf wm8978 set dai fmt ok 1 
[    4.674460] cjf wm8978 dai sysclk 1 0, 24576000 ,24576000
[    4.679866] cjf wm8978 dai 0
[    4.682755] cjf wm8978 dai 110
[    4.685818] cjf wm8978 dai ok0
[    4.689136] cjf wm8978 set bias level 1 
[    4.794821] cjf wm8962 probe ok
[    4.831265] cjf imx ak4458 1
[    5.048266] cjf i2c ak4458 probe 1
[    5.063259] cjf i2c ak4458 probe 1
[    5.102013] cjf imx ak4458 1
[    5.932847] cjf i2c ak4458 probe 1
[    5.955957] cjf i2c ak4458 probe 1
[    5.998805] cjf imx ak4458 1


分析:
root@imx8mmevk:~# dmesg | grep cjf
wm8962.c:
    .compatible = "wlf,wm8978 -> 
    wm8978_i2c_probe
[    4.450267] cjf i2c wm8978 probe 1  
           ret = snd_soc_register_codec(&i2c->dev,&soc_codec_dev_wm8978, &wm8978_dai,1);
                                            snd_soc_codec_driver        snd_soc_dai_driver
                                                                            .name = "wm8962",
                                                                            .playback = {.stream_name = "Playback",
                                                                            .ops=(snd_soc_dai_ops)&wm8978_dai_ops,{
                            1021     .probe =    wm8978_probe,                .hw_params  = wm8978_hw_params,
                            1022     .suspend =  wm8978_suspend,            .digital_mute   = wm8978_mute,
                            1023     .resume =   wm8978_resume,                .set_fmt    = wm8978_set_dai_fmt,
                            1024     .set_bias_level = wm8978_set_bias_level,.set_clkdiv = wm8978_set_dai_clkdiv,
                            1025                                                 .set_sysclk = wm8978_set_dai_sysclk,}
                            1026     .component_driver = {                                
                            1027         .controls       = wm8978_snd_controls,
                            1028         .num_controls       = ARRAY_SIZE(wm8978_snd_controls),
                            1029         .dapm_widgets       = wm8978_dapm_widgets,
                            1030         .num_dapm_widgets   = ARRAY_SIZE(wm8978_dapm_widgets),
                            1031         .dapm_routes        = wm8978_dapm_routes,
                            1032         .num_dapm_routes    = ARRAY_SIZE(wm8978_dapm_routes),
                            1033     },
[    4.454048] cjf i2c wm8978 probe ok
imx-wm8962.c:
    imx_wm8962_probe
[    4.498024] cjf wm8962 probe 1
        data->dai[0].name = "HiFi";
        data->dai[0].stream_name = "HiFi";
        data->dai[0].codec_dai_name = "wm8962";
        data->dai[0].cpu_dai_name = dev_name(&cpu_pdev->dev);
        devm_snd_soc_register_card(&pdev->dev, &data->card);
wm8978.c里的soc_codec_dev_wm8978初始化,probe,suspend,resume,level
[    4.501290] cjf wm8978 probe 2 
[    4.507151] cjf wm8978 probe ok
wm8978.c里的wm8978_dai开始初始化hw,mute,fmt,clkdiv,sysclk
[    4.510504] cjf wm8978 set dai fmt 1 
[    4.514713] cjf wm8978 set dai fmt ok 1 
一大堆初始化,imx-wm8962 sound
        [    4.536543] imx-wm8962 sound: wm8962 <-> 30030000.sai mapping ok
        [    4.542576] imx-wm8962 sound: ASoC: no source widget found for HPOUTL
        [    4.549054] imx-wm8962 sound: ASoC: Failed to add route HPOUTL -> direct -> Headphone Jack
        [    4.557334] imx-wm8962 sound: ASoC: no source widget found for HPOUTR
        [    4.563786] imx-wm8962 sound: ASoC: Failed to add route HPOUTR -> direct -> Headphone Jack
        [    4.687029] imx-wm8962 sound: ASoC: no DMI vendor name!
[    4.674460] cjf wm8978 dai sysclk 1 0, 24576000 ,24576000
[    4.679866] cjf wm8978 dai 0
[    4.682755] cjf wm8978 dai 110
[    4.685818] cjf wm8978 dai ok0
[    4.689136] cjf wm8978 set bias level 1 
imx-wm8962.c:结束
[    4.794821] cjf wm8962 probe ok


------------------------
[ 5634.332342] alloc_contig_range: [780b0, 780c0) PFNs busy
[ 5634.516602] alloc_contig_range: [780b0, 780c0) PFNs busy
[ 5634.523735] cjf wm8978 set dai fmt 1 
[ 5634.528226] cjf wm8978 set dai fmt ok 1 
[ 5634.532190] imx-wm8962 sound: failed to start FLL: -22
[ 5634.537348] imx-wm8962 sound: cjf ASoC: machine hw_params failed: -22
[ 5634.543851] cjf wm8978 dai sysclk 1 0, 0 ,0
[ 5634.548086] cjf wm8978 dai ok0
[ 5634.551145] imx-wm8962 sound: failed to stop FLL: -22

-------------有时钟-----------
[   42.899742] alloc_contig_range: [780b0, 780c0) PFNs busy
[   43.084240] alloc_contig_range: [780b0, 780c0) PFNs busy
[   43.091296] cjf wm8978 set dai fmt 1 
[   43.095697] cjf wm8978 set dai fmt ok 1 
[   43.099677] imx-wm8962 sound: cjf 1failed to start FLL: -22
[   43.105280] imx-wm8962 sound: cjf ASoC: machine hw_params failed: -22
[   43.111781] cjf wm8978 dai sysclk 1 0, 0 ,0
[   43.116036] cjf wm8978 dai ok0
[   43.119094] imx-wm8962 sound: failed to stop FLL: -22

amixer set Headphone 35

430 static struct snd_soc_ops imx_hifi_ops = {
431     .startup = imx_hifi_startup,
432     .hw_params = imx_hifi_hw_params,
433     .hw_free = imx_hifi_hw_free,
434 };
imx_hifi_hw_params
    snd_soc_dai_set_pll
    
    snd_soc_dai_set_fmt()  实际上会调用snd_soc_dai_ops或者codec driver中的set_fmt回调;
snd_soc_dai_set_pll()   实际上会调用 snd_soc_dai_ops 或者codec driver 中的 set_pll 回调;

                        8962.c
                        static const struct snd_soc_dai_ops wm8962_dai_ops = {
                                .hw_params = wm8962_hw_params,
                                .set_sysclk = wm8962_set_dai_sysclk,
                                .set_fmt = wm8962_set_dai_fmt,
                                .digital_mute = wm8962_mute,
                            };

                            static struct snd_soc_dai_driver wm8962_dai = {
                                .name = "wm8962",
                                .playback = {
                                    .stream_name = "Playback",
                                },
                                .capture = {
                                    .stream_name = "Capture",
                                },
                                .ops = &wm8962_dai_ops,
                                
                        static const struct snd_soc_codec_driver soc_codec_dev_wm8962 = {
                            .probe =    wm8962_probe,
                            .remove =    wm8962_remove,
                            .set_bias_level = wm8962_set_bias_level,
                            .set_pll = wm8962_set_fll,
snd_soc_dai_set_sysclk()  实际上会调用snd_soc_dai_ops或者codec driver中的set_sysclk回调;
snd_soc_dai_set_clkdiv()  实际上会调用snd_soc_dai_ops或者codec driver中的set_clkdiv回调;

 o Headphone Jack                耳机插孔
 o Internal Speaker                内部扬声器
 o Internal Mic                        内部麦克风
 o Mic Jack                            麦克风插孔
 o Codec Pins                        Codec引脚
 https://blog.csdn.net/wangyijieonline/article/details/88179309 更多请看
 

你可能感兴趣的:(移植)