android audio/linux alsa音频-数字音频接口DAI

数字音频接口,即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。



猜你喜欢

转载自blog.csdn.net/xgbing/article/details/79578165