有人移植过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 更多请看