alsa Machine、Platform和Codec 驱动实例源码解析(基于am335x)

1840阅读 0评论2020-01-08 fangdikui
分类:LINUX

学习alsa音频驱动过程,一定有了解ASoC被分为MachinePlatformCodec三大部分。其中的Machine驱动负责PlatformCodec之间的耦合和设备或板子特定的代码。框架的资料网上比较多,具体实例确不多,以致于我看了好多资料,还不知源码中哪一部分属于machine驱动。希望能帮助初学的人

那么这三大部分结合到具体的单板,到底是如何初始化的呢,本文就以am335x为例一步一步解说

machine驱动,用于为目标板绑定正确的platformcodec驱动,完成这个任务的就在soc_bind_dai_link(struct snd_soc_card *card, int num)中,实际上就是将card->rtd的三个重要成员card->rtd->cpu_daicard->rtd->codeccard->rtd->platform初始化

全文涉及的文有:

点击(此处)折叠或打开

  1. sound\soc\davinci\davinci-evm.c "soc-audio" 设备注册(alsa machine)
  2. sound\soc\soc-core.c "soc-audio" 驱动注册(alsa machine)
  3. sound\soc\davinci\davinci-pcm.c "davinci-pcm-audio" 驱动注册(alsa platform)
  4. arch\arm\mach-omap2\devices.c "davinci-pcm-audio"设备注册 (alsa platform)
  5. sound\soc\codecs\tlv320aic3x.c i2c驱动注册(alsa codec)
  6. arch\arm\mach-omap2\board-am335xevm.c i2c "tlv320aic3x-codec.1-001b"设备注册(alsa codec)
  7. sound\soc\davinci\davinci-mcasp.c "davinci-mcasp" 驱动注册(alsa dai)
  8. arch\arm\mach-omap2\devices.c "davinci-mcasp"设备注册(alsa dai)




 (1)  alsamachine驱动

sound\soc\davinci\davinci-evm.c     
 

点击(此处)折叠或打开

  1. static struct snd_soc_dai_link am335x_evm_dai = {

  2.          .name = "TLV320AIC3X",

  3.          .stream_name = "AIC3X",

  4.          .cpu_dai_name = "davinci-mcasp.0",//1->0

  5.          .codec_dai_name = "tlv320aic3x-hifi",

  6.          .codec_name = "tlv320aic3x-codec.1-001b",//2->1

  7.          .platform_name = "davinci-pcm-audio",

  8.          .init = evm_aic3x_init,

  9.          .ops = &evm_ops,

  10. };

  11. static struct snd_soc_card am335x_snd_soc_card = {

  12.          .name = "AM335X EVM",

  13.          .dai_link = &am335x_evm_dai,

  14.          .num_links = 1,

  15. };

  16. evm_init(){

  17.   evm_snd_dev_data = &am335x_snd_soc_card;

  18.   evm_snd_device = platform_device_alloc("soc-audio", index);

  19.   platform_set_drvdata(evm_snd_device, evm_snd_dev_data);

  20.   platform_device_add(evm_snd_device);

  21. }
   


这将触发"soc-audio"平台设备驱动的probe函数,这在soc-core.c

sound\soc\soc-core.c                                                                 


点击(此处)折叠或打开

  1. static struct platform_driver soc_driver = {

  2.          .driver = {

  3.                    .name = "soc-audio",

  4.                    .owner = THIS_MODULE,

  5.                    .pm = &snd_soc_pm_ops,

  6.          },

  7.          .probe = soc_probe,

  8.          .remove = soc_remove,

  9. };

  10. soc_probe(){

  11.   snd_soc_register_card(am335x_snd_soc_card){

  12.     card->rtd = kzalloc()

  13.     snd_soc_instantiate_cards()

  14.     snd_soc_instantiate_card()

  15.       soc_bind_dai_link(){

  16.       rtd->cpu_dai [find cpu_dai_name == davinci-mcasp.0]

  17.       rtd->codec [find codec_name == tlv320aic3x-codec.1-001b]

  18.       rtd->platform [find platform_name == davinci-pcm-audio]

  19.   }

  20. }



soc_bind_dai_link找到合适的cpu_dai, codec, platform,具体查找过程看源码比较好理解,就是分别从dai_list ,codec_listplatform_list链表中找到名字相同的项,接下来就是理清这三个list是如何被add的就可以了

 (2) alsaplatform驱动 (platform_list)

soc_bind_dai_link()中可以看出,一定有一个名为davinci-pcm-audioalsa platform驱动,经过搜索snd_soc_register_platform()完成platform_listadd操作

 

sound\soc\davinci\davinci-pcm.c  davinci-pcm-audio驱动注册

点击(此处)折叠或打开

  1. static struct platform_driver davinci_pcm_driver = {

  2.          .driver = {

  3.                             .name = "davinci-pcm-audio",

  4.                             .owner = THIS_MODULE,

  5.          },

  6.          .probe = davinci_soc_platform_probe,

  7.          .remove = __devexit_p(davinci_soc_platform_remove),

  8. };

  9. static int __init snd_davinci_pcm_init(void)

  10. {

  11.          return platform_driver_register(&davinci_pcm_driver);

  12. }

  13. module_init(snd_davinci_pcm_init);

  14. davinci_soc_platform_probe (){

  15.    snd_soc_register_platform(){

  16.            platform->name = fmt_single_name(dev, &platform->id);// 取出"davinci-pcm-audio",

  17.       list_add(&platform->list, &platform_list);

  18.       snd_soc_instantiate_cards();

  19.    }

  20. }



 

arch\arm\mach-omap2\devices.c    davinci-pcm-audio设备注册

 

点击(此处)折叠或打开

  1. struct platform_device am33xx_pcm_device = {

  2.          .name = "davinci-pcm-audio",

  3.          .id = -1,

  4. };

  5. arch_initcall(omap2_init_devices);

  6. omap2_init_devices(){

  7.   am33xx_init_pcm(){

  8.     platform_device_register(&am33xx_pcm_device);

  9.   }

  10. }

 


(3) alsacodec驱动 (codec_list)

sound\soc\codecs\tlv320aic3x.c  i2c驱动注册

点击(此处)折叠或打开

  1. aic3x_modinit(){

  2.          i2c_add_driver(&aic3x_i2c_driver);

  3.        aic3x_i2c_probe(){

  4.          ret = snd_soc_register_codec(&i2c->dev,&soc_codec_dev_aic3x, &aic3x_dai, 1){

  5.          codec->name = fmt_single_name(dev, &codec->id);

  6.          list_add(&codec->list, &codec_list);

  7.          }

  8.        }

  9. }

  10. arch\arm\mach-omap2\board-am335xevm.c i2c tlv320aic3x-codec.1-001b设备注册



  11. static struct evm_dev_cfg evm_sk_dev_cfg[] = {

  12.                   {i2c0_init, DEV_ON_BASEBOARD, PROFILE_ALL},

  13. };

  14. am335x_evm_init(){

  15.   am335x_evm_setup(){

  16.     setup_starterkit(){

  17.       _configure_device(EVM_SK, evm_sk_dev_cfg, PROFILE_NONE);

  18.     }

  19.   }

  20. }

  21. static struct i2c_board_info __initdata am335x_i2c0_boardinfo[] = {

  22.          {

  23.                    I2C_BOARD_INFO("tlv320aic3x", 0x1b),

  24.          },

  25. };

  26. static void i2c0_init(int evm_id, int profile)

  27. {

  28.   omap_register_i2c_bus(1, 100, am335x_i2c0_boardinfo,ARRAY_SIZE(am335x_i2c0_boardinfo));

  29. }



(4) alsa的dai驱动 dai_list

sound\soc\davinci\davinci-mcasp.c  "davinci-mcasp" 驱动

点击(此处)折叠或打开

  1. static struct snd_soc_dai_driver davinci_mcasp_dai[] = {

  2.          {

  3.                    .name = "davinci-mcasp.0",

  4.                    .playback = {

  5.                             .channels_min = 2,

  6.                             .channels_max = 2,

  7.                             .rates = DAVINCI_MCASP_RATES,

  8.                             .formats = DAVINCI_MCASP_PCM_FMTS,

  9.                    },

  10.                    .capture = {

  11.                             .channels_min = 2,

  12.                             .channels_max = 2,

  13.                             .rates = DAVINCI_MCASP_RATES,

  14.                             .formats = DAVINCI_MCASP_PCM_FMTS,

  15.                    },

  16.                    .ops = &davinci_mcasp_dai_ops,

  17.  

  18.          },

  19.  

  20. };

  21.  

  22. static struct platform_driver davinci_mcasp_driver = {

  23.          .probe = davinci_mcasp_probe,

  24.          .remove = davinci_mcasp_remove,

  25. #ifdef CONFIG_PM

  26.          .suspend = davinci_mcasp_suspend,

  27.          .resume = davinci_mcasp_resume,

  28. #endif

  29.          .driver = {

  30.                    .name = "davinci-mcasp",

  31.                    .owner = THIS_MODULE,

  32.          },

  33. };

  34. davinci_mcasp_probe(){

  35.   snd_soc_register_dai(&pdev->dev, &davinci_mcasp_dai[pdata->op_mode]){

  36.     dai->name = fmt_single_name(dev, &dai->id);

  37.       list_add(&dai->list, &dai_list);

  38.            snd_soc_instantiate_cards();

  39.   }

  40. }



arch\arm\mach-omap2\devices.c  "davinci-mcasp"设备

点击(此处)折叠或打开

  1. mcasp0_init(){

  2.   am335x_register_mcasp(&am335x_evm_snd_data0, 0){

  3.   char *dev_name = "davinci-mcasp";

  4.   pdev = omap_device_build(dev_name, ctrl_nr, oh, pdata,

  5.                             sizeof(struct snd_platform_data), NULL, 0, 0);

  6.   }

  7. }



上一篇: 中断
下一篇:linux 3.2.0 vmem_disk驱动源码