数字音频接口,即The Digital Audio Interface,简称DAI。
相关代码分析:
DAI driver
在codec驱动中注册驱动函数
int snd_soc_register_codec(struct device *dev, const struct snd_soc_codec_driver *codec_drv, struct snd_soc_dai_driver *dai_drv, int num_dai)
注意,这里注册了两个驱动,一个是codec驱动,另一个dai驱动。在板子相关的注册声卡驱动时,成员dai_link中:
#define DEV_NAME_PCM "nxp-pcm" static struct snd_soc_dai_link es8396_dai_link = { .name = "ASOC-es8396", .stream_name = "es8396 HiFi", .cpu_dai_name = "nxp-i2s.0", /* nxp_snd_i2s_driver name */ .platform_name = DEV_NAME_PCM, /* nxp_snd_pcm_driver name */ .codec_dai_name = "es8396-sdp1", /* dai驱动的名称 */ .codec_name = "es8396-codec.0-0011", /* .0-001a es8396_i2c_driver name + '.' + bus + '-' + address(7bit) */ .ops = &es8396_ops, .symmetric_rates = 1, .init = es8396_dai_init, //.ops = &es8396_ops, }; //es8396.c static struct snd_soc_dai_driver es8396_dai[] = { { .name = "es8396-sdp1", .id = 0, .playback = { .stream_name = "SDP1 Playback", .channels_min = 1, .channels_max = 2, .rates = ES8396_RATES, .formats = ES8396_FORMATS, }, .capture = { .stream_name = "SDP1 Capture", .channels_min = 1, .channels_max = 2, .rates = ES8396_RATES, .formats = ES8396_FORMATS, }, .ops = &es8396_aif1_dai_ops, },音频驱动包含了三部分,关于machine的,关于platform的,关于codec的。
codec_dai_name的名称即是es8396.c中定义的 snd_soc_dai_driver实体的名称。 codec级别
.cpu_dai_name指向的是nxp-i2.c中的i2s驱动,名称为“nxp-i2s” machine级别
.platform_name指向的是nxp-pcm.c中的驱动,相关代码如下: platform级别
static int nxp_pcm_new(struct snd_soc_pcm_runtime *runtime) { struct snd_card *card = runtime->card->snd_card; struct snd_pcm *pcm = runtime->pcm; int ret = 0; /* dma mask */ if (!card->dev->dma_mask) card->dev->dma_mask = &nxp_pcm_dmamask; if (!card->dev->coherent_dma_mask) card->dev->coherent_dma_mask = DMA_BIT_MASK(32); if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { ret = nxp_pcm_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK); if (ret) goto err; } if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { ret = nxp_pcm_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE); if (ret) goto err_free; } return 0; err_free: nxp_pcm_release_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK); err: return ret; } static void nxp_pcm_free(struct snd_pcm *pcm) { nxp_pcm_release_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE); nxp_pcm_release_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK); } static struct snd_soc_platform_driver pcm_platform = { .ops = &nxp_pcm_ops, .pcm_new = nxp_pcm_new, .pcm_free = nxp_pcm_free, }; static int __devinit nxp_pcm_probe(struct platform_device *pdev) { int ret = snd_soc_register_platform(&pdev->dev, &pcm_platform); printk(KERN_INFO "snd pcm: %s sound platform '%s'\n", ret?"fail":"register", pdev->name); return ret; } static struct platform_device pcm_device = { .name = DEV_NAME_PCM, //”nxp-pcm” .id = -1, }; static int __init nxp_pcm_init(void) { platform_device_register(&pcm_device); return platform_driver_register(&pcm_driver); }
cpu_dia
codec_name指向的是es8396驱动(I2C驱动,名称是”es8396-codec”, I2C在总线0上,I2C地址是0x11)。
在调用snd_soc_register_card()的过程中,根据定义好的card->dai_link来生成card->rtd,参考snd_soc_register_card()的代码:
/* bind DAIs */ for (i = 0; i < card->num_links; i++) soc_bind_dai_link(card, i); //每次成功调用后card->num_rtd加1。初始化成功后,card->num_rtd==card->num_link。
在 soc_bind_dai_link函数中,它根据card→dai_link中的cpu_dai_name、codec_dai_name 、codec_name 、platform_name、,分别生成card→rtd[i].cpu_dai、rtd-rtd→codec、rtd->codec_dai、rtd->codec、rtd->platform。