学习alsa音频驱动过程,一定有了解ASoC被分为Machine、Platform和Codec三大部分。其中的Machine驱动负责Platform和Codec之间的耦合和设备或板子特定的代码。框架的资料网上比较多,具体实例确不多,以致于我看了好多资料,还不知源码中哪一部分属于machine驱动。希望能帮助初学的人
那么这三大部分结合到具体的单板,到底是如何初始化的呢,本文就以am335x为例一步一步解说
machine驱动,用于为目标板绑定正确的platform和codec驱动,完成这个任务的就在soc_bind_dai_link(struct snd_soc_card *card, int num)中,实际上就是将card->rtd的三个重要成员card->rtd->cpu_dai,card->rtd->codec,card->rtd->platform初始化
全文涉及的文有:
点击(此处)折叠或打开
- sound\soc\davinci\davinci-evm.c "soc-audio" 设备注册(alsa machine)
- sound\soc\soc-core.c "soc-audio" 驱动注册(alsa machine)
- sound\soc\davinci\davinci-pcm.c "davinci-pcm-audio" 驱动注册(alsa platform)
- arch\arm\mach-omap2\devices.c "davinci-pcm-audio"设备注册 (alsa platform)
- sound\soc\codecs\tlv320aic3x.c i2c驱动注册(alsa codec)
- arch\arm\mach-omap2\board-am335xevm.c i2c "tlv320aic3x-codec.1-001b"设备注册(alsa codec)
- sound\soc\davinci\davinci-mcasp.c "davinci-mcasp" 驱动注册(alsa dai)
- arch\arm\mach-omap2\devices.c "davinci-mcasp"设备注册(alsa dai)
(1) alsa的machine驱动
sound\soc\davinci\davinci-evm.c
点击(此处)折叠或打开
-
static struct snd_soc_dai_link am335x_evm_dai = {
-
-
.name = "TLV320AIC3X",
-
-
.stream_name = "AIC3X",
-
-
.cpu_dai_name = "davinci-mcasp.0",//1->0
-
-
.codec_dai_name = "tlv320aic3x-hifi",
-
-
.codec_name = "tlv320aic3x-codec.1-001b",//2->1
-
-
.platform_name = "davinci-pcm-audio",
-
-
.init = evm_aic3x_init,
-
-
.ops = &evm_ops,
-
-
};
-
-
static struct snd_soc_card am335x_snd_soc_card = {
-
-
.name = "AM335X EVM",
-
-
.dai_link = &am335x_evm_dai,
-
-
.num_links = 1,
-
-
};
-
-
evm_init(){
-
-
evm_snd_dev_data = &am335x_snd_soc_card;
-
-
evm_snd_device = platform_device_alloc("soc-audio", index);
-
-
platform_set_drvdata(evm_snd_device, evm_snd_dev_data);
-
-
platform_device_add(evm_snd_device);
-
- }
这将触发"soc-audio"平台设备驱动的probe函数,这在soc-core.c中
sound\soc\soc-core.c
点击(此处)折叠或打开
-
static struct platform_driver soc_driver = {
-
-
.driver = {
-
-
.name = "soc-audio",
-
-
.owner = THIS_MODULE,
-
-
.pm = &snd_soc_pm_ops,
-
-
},
-
-
.probe = soc_probe,
-
-
.remove = soc_remove,
-
-
};
-
-
soc_probe(){
-
-
snd_soc_register_card(am335x_snd_soc_card){
-
-
card->rtd = kzalloc()
-
-
snd_soc_instantiate_cards()
-
-
snd_soc_instantiate_card()
-
-
soc_bind_dai_link(){
-
-
rtd->cpu_dai [find cpu_dai_name == davinci-mcasp.0]
-
-
rtd->codec [find codec_name == tlv320aic3x-codec.1-001b]
-
-
rtd->platform [find platform_name == davinci-pcm-audio]
-
-
}
-
- }
在soc_bind_dai_link找到合适的cpu_dai, codec, platform,具体查找过程看源码比较好理解,就是分别从dai_list ,codec_list,platform_list链表中找到名字相同的项,接下来就是理清这三个list是如何被add的就可以了
(2) alsa的platform驱动 (platform_list)
从soc_bind_dai_link()中可以看出,一定有一个名为davinci-pcm-audio的alsa platform驱动,经过搜索snd_soc_register_platform()完成platform_list的add操作
sound\soc\davinci\davinci-pcm.c
davinci-pcm-audio驱动注册
点击(此处)折叠或打开
-
static struct platform_driver davinci_pcm_driver = {
-
-
.driver = {
-
-
.name = "davinci-pcm-audio",
-
-
.owner = THIS_MODULE,
-
-
},
-
-
.probe = davinci_soc_platform_probe,
-
-
.remove = __devexit_p(davinci_soc_platform_remove),
-
-
};
-
-
static int __init snd_davinci_pcm_init(void)
-
-
{
-
-
return platform_driver_register(&davinci_pcm_driver);
-
-
}
-
-
module_init(snd_davinci_pcm_init);
-
-
davinci_soc_platform_probe (){
-
-
snd_soc_register_platform(){
-
-
platform->name = fmt_single_name(dev, &platform->id);// 取出"davinci-pcm-audio",
-
-
list_add(&platform->list, &platform_list);
-
-
snd_soc_instantiate_cards();
-
-
}
-
- }
arch\arm\mach-omap2\devices.c davinci-pcm-audio设备注册
点击(此处)折叠或打开
-
struct platform_device am33xx_pcm_device = {
-
-
.name = "davinci-pcm-audio",
-
-
.id = -1,
-
-
};
-
-
arch_initcall(omap2_init_devices);
-
-
omap2_init_devices(){
-
-
am33xx_init_pcm(){
-
-
platform_device_register(&am33xx_pcm_device);
-
-
}
-
- }
(3) alsa的codec驱动 (codec_list)
sound\soc\codecs\tlv320aic3x.c i2c驱动注册
点击(此处)折叠或打开
-
aic3x_modinit(){
-
-
i2c_add_driver(&aic3x_i2c_driver);
-
-
aic3x_i2c_probe(){
-
-
ret = snd_soc_register_codec(&i2c->dev,&soc_codec_dev_aic3x, &aic3x_dai, 1){
-
-
codec->name = fmt_single_name(dev, &codec->id);
-
-
list_add(&codec->list, &codec_list);
-
-
}
-
-
}
-
-
}
-
-
arch\arm\mach-omap2\board-am335xevm.c i2c tlv320aic3x-codec.1-001b设备注册
-
-
-
-
static struct evm_dev_cfg evm_sk_dev_cfg[] = {
-
-
{i2c0_init, DEV_ON_BASEBOARD, PROFILE_ALL},
-
-
};
-
-
am335x_evm_init(){
-
-
am335x_evm_setup(){
-
-
setup_starterkit(){
-
-
_configure_device(EVM_SK, evm_sk_dev_cfg, PROFILE_NONE);
-
-
}
-
-
}
-
-
}
-
-
static struct i2c_board_info __initdata am335x_i2c0_boardinfo[] = {
-
-
{
-
-
I2C_BOARD_INFO("tlv320aic3x", 0x1b),
-
-
},
-
-
};
-
-
static void i2c0_init(int evm_id, int profile)
-
-
{
-
-
omap_register_i2c_bus(1, 100, am335x_i2c0_boardinfo,ARRAY_SIZE(am335x_i2c0_boardinfo));
-
- }
(4) alsa的dai驱动 dai_list
sound\soc\davinci\davinci-mcasp.c
"davinci-mcasp" 驱动
点击(此处)折叠或打开
-
static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
-
-
{
-
-
.name = "davinci-mcasp.0",
-
-
.playback = {
-
-
.channels_min = 2,
-
-
.channels_max = 2,
-
-
.rates = DAVINCI_MCASP_RATES,
-
-
.formats = DAVINCI_MCASP_PCM_FMTS,
-
-
},
-
-
.capture = {
-
-
.channels_min = 2,
-
-
.channels_max = 2,
-
-
.rates = DAVINCI_MCASP_RATES,
-
-
.formats = DAVINCI_MCASP_PCM_FMTS,
-
-
},
-
-
.ops = &davinci_mcasp_dai_ops,
-
-
-
-
},
-
-
-
-
};
-
-
-
-
static struct platform_driver davinci_mcasp_driver = {
-
-
.probe = davinci_mcasp_probe,
-
-
.remove = davinci_mcasp_remove,
-
-
#ifdef CONFIG_PM
-
-
.suspend = davinci_mcasp_suspend,
-
-
.resume = davinci_mcasp_resume,
-
-
#endif
-
-
.driver = {
-
-
.name = "davinci-mcasp",
-
-
.owner = THIS_MODULE,
-
-
},
-
-
};
-
-
davinci_mcasp_probe(){
-
-
snd_soc_register_dai(&pdev->dev, &davinci_mcasp_dai[pdata->op_mode]){
-
-
dai->name = fmt_single_name(dev, &dai->id);
-
-
list_add(&dai->list, &dai_list);
-
-
snd_soc_instantiate_cards();
-
-
}
-
- }
arch\arm\mach-omap2\devices.c
"davinci-mcasp"设备
点击(此处)折叠或打开
-
mcasp0_init(){
-
-
am335x_register_mcasp(&am335x_evm_snd_data0, 0){
-
-
char *dev_name = "davinci-mcasp";
-
-
pdev = omap_device_build(dev_name, ctrl_nr, oh, pdata,
-
-
sizeof(struct snd_platform_data), NULL, 0, 0);
-
-
}
-
- }