本文以max98088为参照设备进行。
我自己也在学习audio, 本着多多交流,相互进步的原则写下流程,
欢迎大家来拍砖, 学习中有不正确的地方还请指出来。

大体结构: 
cpu_dai-------指的是I2C通路.
codec_dai-----codec的功能,如录音放音参数。
codec_dev-----解码设备,重点
platform------据我看只是做了pcm的操作函数和分配dma用的

1. 在文件中注册soc-audio设备,以唤醒soc-core中的probe
我们的注册
 

our_audio_device = snd_soc_dai_link("soc-audio", -1);
platform_set_drvdata(our_audio_device, &our_audio_device_data)


our_audio_device_data 中包括card和codec_dev, card中包括snd_soc_dai_link, 
snd_soc_dai_link中包括cpu_dai,和codec_dai, 这些比较简单,不需要赘述了.
 
2. 进入soc-core的probe, 由于我们注册了soc-audio 设备,故会调用soc-core中的probe,
soc_probe->snd_soc_register_card->snd_soc_instantiate_cards->snd_soc_instantiate_card
 
一大堆跳转,我想大家都懂的,不再赘述,切入主题.

3. 在snd_soc_instantiate_card中匹配platform
if (card->platform == platform)
 
接下来匹配cpu_dai
if (card->dai_link[i].cpu_dai == dai)
 
再是codec_dai
if (card->dai_link[i].codec_dai == dai)
 
如果都找到了,就进行card->probe, 一般都没有。
if (card->probe)
 
再进行cpu_dai的初始化,就是i2s接口的初始化。
ret = cpu_dai->probe(pdev, cpu_dai);
 
再进行codec_dev的probe, 就是soc_codec_dev_max98088,此为重点,放后讨论
ret = codec_dev->probe(pdev);
 
这个probe一般也都没有。 
ret = platform->probe(pdev);
 
初始化等待队列
INIT_DELAYED_WORK(&card->delayed_work, close_delayed_work);
 
重头戏来了, codec_dev的probe
1. snd_soc_new_pcms中调用snd_card_create创建1个基于PCM的声卡设备。 
 
snd_card_create创建声卡,进入snd_card_create中,
snd_ctl_create定义声卡device的操作方法,snd_device_new创建出声卡设备并注册到链表中。
 
2. 回到snd_soc_new_pcms中,看soc_new_pcm。
 
将codec与dai建立链接,snd_pcm_new中先创建SNDRV_PCM_STREAM_PLAYBACK和SNDRV_PCM_STREAM_CAPTURE流
然后snd_device_new创建pcm的device.
 
3. 回到soc_new_pcm中为soc_pcm_ops赋值,其实就是将platform中的ops全部指过来。
 
4. 然后调用platform中的new, 创建dma. 
ret = platform->pcm_new(codec->card, codec_dai, pcm);
至此PCM的数据路就注册好了,下面就要注册控制信息了,就是snd_kcontrol_new结构体。
 
max98088藏的比较深啊, 找出来.
进入max98088_add_widgets(codec);
 
这个注册比较简单不再赘述了。
snd_soc_add_controls(codec, max98088_snd_controls,
    ARRAY_SIZE(max98088_snd_controls));
 
最后是snd_soc_init_card, 这个不用讲了,就是一堆,最后就OK了。
Logo

更多推荐