ALSA之Codec注册过程

一 提纲

二 概述

三 代码分析


一 提纲

在这里插入图片描述

在这里插入图片描述

codec 分步骤综述

1 定义并且注册 平台驱动 (设备树匹配)
       struct platform_driver mtk_codec_6331_driver {}

2 定义 struct snd_soc_codec_driver soc_mtk_codec{}

3 定义 struct snd_soc_dai_driver mtk_6331_dai_codecs{}

4 定义 struct snd_soc_dai_ops mt6323_aif1_dai_ops{}

5 平台驱动的 prob()中

5.1 设置平台设备设备名  platform_device -> device 名称 "mt-soc-codec"

5.2 将 snd_soc_codec_drive  和 snd_soc_dai_driver 注册到 soc-core。
 : snd_soc_register_codec(&pdev->dev, &soc_mtk_codec, mtk_6331_dai_codecs, ARRAY_SIZE(mtk_6331_dai_codecs));

	5.2 
	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)完成如下工作
	1 创建 snd_soc_codec
	2 初始化 snd_soc_codec -> snd_soc_componen
	2 初始化 snd_soc_codec -> snd_soc_dapm_context
	3 创建一个 头为  snd_soc_codec -> snd_soc_component -> dai_list 的双向链表
	4 绑定 snd_soc_codec -> device 与  platform_device->device
	5 绑定 snd_soc_codec -> snd_soc_codec_drive 与 snd_soc_codec_driver soc_mtk_codec{}

6 snd_soc_register_dais(&codec->component, dai_drv, num_dai, false)

	6.1 创建 snd_soc_dai
	6.2 snd_soc_codec -> snd_soc_component -> snd_soc_dai_driver = snd_soc_dai_driver mtk_6331_dai_codecs{}
	6.3 绑定 
		struct snd_soc_dai -> snd_soc_component   = snd_soc_codec -> snd_soc_component 
		struct snd_soc_dai -> device              = snd_soc_codec -> snd_soc_component -> device  = platform_device->device
		struct snd_soc_dai -> snd_soc_dai_driver  = snd_soc_codec -> snd_soc_component -> snd_soc_dai_driver = snd_soc_dai_driver mtk_6331_dai_codecs{}

	6.3 添加 struct snd_soc_dai -> list_head  到  snd_soc_codec -> snd_soc_component -> list_head dai_list 双向链表

7 遍历以 &snd_soc_codec->snd_soc_component.list_head  为头节点,以 snd_soc_dai 为节点的双向链表。
   初始化链表中节点的  snd_soc_dai -> snd_soc_codec = snd_soc_codec

8 将 snd_soc_codec -> list_head 添加到  codec_list 双向链表

二 概述

总的来讲,主要的工作是

首先定义
struct snd_soc_codec_driver soc_mtk_codec{} 和 struct snd_soc_dai_driver mtk_6331_dai_codecs{} 结构体。

并且将它俩注册到 soc-core。具体的表现形式就是 :

创建一个 snd_soc_codec 实例 并且将前面定义的 struct snd_soc_codec_driver soc_mtk_codec{} 结构体绑定到 snd_soc_codec 实例中对应项 snd_soc_codec -> snd_soc_codec_drive
创建一个 snd_soc_dai 实例 并且将将前面定义的 struct snd_soc_dai_driver mtk_6331_dai_codecs{} 结构体绑定到 snd_soc_dai 实例中对应项 snd_soc_dai -> snd_soc_dai_drive、

添加 snd_soc_dai 实例 到 以 snd_soc_dai 为节点的双向链表
添加 snd_soc_codec 实例 到 以  snd_soc_codec 为节点的双向链表

代码分析

mt3561.dtsi

	mt_soc_codec_name {
		compatible = "mediatek,mt_soc_codec_63xx";
	};

sound/soc/mediatek/mt_soc_audio_6755/mt_soc_codec_63xx.c

static const struct snd_soc_dai_ops mt6323_aif1_dai_ops = {
	.startup = mt63xx_codec_startup,
	.prepare = mt63xx_codec_prepare,
	.trigger = mt6323_codec_trigger,
};

static struct snd_soc_dai_driver mtk_6331_dai_codecs[] = {
	{
	 .name = MT_SOC_CODEC_TXDAI_NAME,
	 .ops = &mt6323_aif1_dai_ops,
	 .playback = {
		      .stream_name = MT_SOC_DL1_STREAM_NAME,
		      .channels_min = 1,
		      .channels_max = 2,
		      .rates = SNDRV_PCM_RATE_8000_192000,
		      .formats = SND_SOC_ADV_MT_FMTS,
		      },
	 },
	{
	 .name = MT_SOC_CODEC_RXDAI_NAME,
	 .ops = &mt6323_aif1_dai_ops,
	 .capture = {
		     .stream_name = MT_SOC_UL1_STREAM_NAME,
		     .channels_min = 1,
		     .channels_max = 2,
		     .rates = SNDRV_PCM_RATE_8000_192000,
		     .formats = SND_SOC_ADV_MT_FMTS,
		     },
	 },

......

};

static const struct snd_soc_dapm_widget mt6331_dapm_widgets[] = {
	/* Outputs */
	SND_SOC_DAPM_OUTPUT("EARPIECE"),
	SND_SOC_DAPM_OUTPUT("HEADSET"),
	SND_SOC_DAPM_OUTPUT("SPEAKER"),
};

static const struct snd_soc_dapm_route mtk_audio_map[] = {
	{"VOICE_Mux_E", "Voice Mux", "SPEAKER PGA"},
};

/*
定义 struct snd_soc_codec_driver soc_mtk_codec
.prob
.remove
.read
.write
.dapm_widgets
.num_dapm_widgets
.dapm_routes
.num_dapm_routes

*/
static struct snd_soc_codec_driver soc_mtk_codec = {
	.probe = mt6331_codec_probe,
	.remove = mt6331_codec_remove,

	.read = mt6331_read,
	.write = mt6331_write,

	.dapm_widgets = mt6331_dapm_widgets,
	.num_dapm_widgets = ARRAY_SIZE(mt6331_dapm_widgets),
	.dapm_routes = mtk_audio_map,
	.num_dapm_routes = ARRAY_SIZE(mtk_audio_map),

};


static int mtk_mt6331_codec_dev_probe(struct platform_device *pdev)
{
	/*coherent_dma_mask 表示它能寻址的物理地址的范围*/
	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(64);

	if (pdev->dev.dma_mask == NULL)
		pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;

	/*设置设备名*/
	if (pdev->dev.of_node)
		dev_set_name(&pdev->dev, "%s", MT_SOC_CODEC_NAME);//#define MT_SOC_CODEC_NAME "mt-soc-codec"


	pr_warn("%s: dev name %s\n", __func__, dev_name(&pdev->dev));

	/* 将 codec_driver 和 codec_dai_driver 注册到 soc-core。
	&pdev->dev : platform_device->device
	&soc_mtk_codec : struct snd_soc_codec_driver soc_mtk_codec,codec设备驱动
	mtk_6331_dai_codecs : struct snd_soc_dai_driver mtk_6323_dai_codecs[],dai driver
	ARRAY_SIZE(mtk_6323_dai_codecs)
	*/
	return snd_soc_register_codec(&pdev->dev, &soc_mtk_codec, mtk_6331_dai_codecs, ARRAY_SIZE(mtk_6331_dai_codecs));
}





#ifdef CONFIG_OF
/*
设备树匹配
*/
static const struct of_device_id mt_soc_codec_63xx_of_ids[] = {
	{.compatible = "mediatek,mt_soc_codec_63xx",},
	{}
};
#endif

/*定义平台驱动

*/
static struct platform_driver mtk_codec_6331_driver = {
	.driver = {
		   .name = MT_SOC_CODEC_NAME,//#define MT_SOC_CODEC_NAME "mt-soc-codec"
		   .owner = THIS_MODULE,
#ifdef CONFIG_OF
		   .of_match_table = mt_soc_codec_63xx_of_ids,
#endif
		   },
	.probe = mtk_mt6331_codec_dev_probe,
	.remove = mtk_mt6331_codec_dev_remove,
};

#ifndef CONFIG_OF
static struct platform_device *soc_mtk_codec6331_dev;
#endif

static int __init mtk_mt6331_codec_init(void)
{
	pr_warn("%s:\n", __func__);
#ifndef CONFIG_OF
	int ret = 0;

	/* 分配平台设备 
	#define MT_SOC_CODEC_NAME "mt-soc-codec"
	*/
	soc_mtk_codec6331_dev = platform_device_alloc(MT_SOC_CODEC_NAME, -1);

	if (!soc_mtk_codec6331_dev)
		return -ENOMEM;

	/*添加设备*/
	ret = platform_device_add(soc_mtk_codec6331_dev);
	if (ret != 0) {
		platform_device_put(soc_mtk_codec6331_dev);
		return ret;
	}
#endif
	InitGlobalVarDefault();

	/*注册平台驱动*/
	return platform_driver_register(&mtk_codec_6331_driver);
}

module_init(mtk_mt6331_codec_init);

static void __exit mtk_mt6331_codec_exit(void)
{
	pr_warn("%s:\n", __func__);

	platform_driver_unregister(&mtk_codec_6331_driver);
}

module_exit(mtk_mt6331_codec_exit);

/* Module information */
MODULE_DESCRIPTION("MTK  codec driver");
MODULE_LICENSE("GPL v2");



---------------------------------------------------------------------------------

soc-core.c

static DEFINE_MUTEX(client_mutex);
static LIST_HEAD(platform_list);
static LIST_HEAD(codec_list);
static LIST_HEAD(component_list);




static const struct snd_soc_dai_ops null_dai_ops = {
};


/* 注册  snd_soc_dai_driver

	snd_soc_codec -> snd_soc_component -> snd_soc_dai_driver = snd_soc_dai_driver
	snd_soc_codec -> snd_soc_component -> num_dai  = ARRAY_SIZE(mtk_6323_dai_codecs)
	
	为每一个 snd_soc_dai 分配空间 
	设置  struct snd_soc_dai -> name
	struct snd_soc_dai -> snd_soc_component = snd_soc_codec -> snd_soc_component 
	struct snd_soc_dai -> device = snd_soc_codec -> snd_soc_component -> device
	struct snd_soc_dai -> snd_soc_dai_driver = snd_soc_codec -> snd_soc_component -> snd_soc_dai_driver
	struct snd_soc_dai -> snd_soc_dai_driver -> snd_soc_dai_ops = 空
	添加 struct snd_soc_dai -> list_head  插入到  snd_soc_codec -> snd_soc_component -> list_head dai_list 双向链表
	
 */

static int snd_soc_register_dais(struct snd_soc_component *component, struct snd_soc_dai_driver *dai_drv, size_t count, bool legacy_dai_naming)
{
/*
创建 struct snd_soc_dai *dai
定义 struct device *dev,并用 snd_soc_codec -> snd_soc_component -> device 初始化
*/
	struct device *dev = component->dev;
	struct snd_soc_dai *dai;
	unsigned int i;
	int ret;

	dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count);

	/*
	snd_soc_codec -> snd_soc_component -> snd_soc_dai_driver = snd_soc_dai_driver
	snd_soc_codec -> snd_soc_component -> num_dai  = ARRAY_SIZE(mtk_6323_dai_codecs)
	*/
	component->dai_drv = dai_drv;
	component->num_dai = count;

	/* 为每一个 snd_soc_dai 分配空间 
	设置  struct snd_soc_dai -> name
	struct snd_soc_dai -> snd_soc_component = snd_soc_codec -> snd_soc_component 
	struct snd_soc_dai -> device = snd_soc_codec -> snd_soc_component -> device
	struct snd_soc_dai -> snd_soc_dai_driver = snd_soc_codec -> snd_soc_component -> snd_soc_dai_driver
	struct snd_soc_dai -> snd_soc_dai_driver -> snd_soc_dai_ops = 空
	添加 struct snd_soc_dai -> list_head  插入到  snd_soc_codec -> snd_soc_component -> list_head dai_list 双向链表
	*/
	for (i = 0; i < count; i++) {

		dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
		if (dai == NULL) {
			ret = -ENOMEM;
			goto err;
		}

		if (count == 1 && legacy_dai_naming) {
			dai->name = fmt_single_name(dev, &dai->id);
		} else {
			dai->name = fmt_multiple_name(dev, &dai_drv[i]);
			if (dai_drv[i].id)
				dai->id = dai_drv[i].id;
			else
				dai->id = i;
		}
		if (dai->name == NULL) {
			kfree(dai);
			ret = -ENOMEM;
			goto err;
		}

		dai->component = component;
		dai->dev = dev;
		dai->driver = &dai_drv[i];
		if (!dai->driver->ops)
			dai->driver->ops = &null_dai_ops;//空

		list_add(&dai->list, &component->dai_list);

		dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
	}

	return 0;

err:
	snd_soc_unregister_dais(component);

	return ret;
}


/*

	获取 snd_soc_codec -> snd_soc_component -> name
	snd_soc_codec -> snd_soc_component -> device                    = platform_device->device
	snd_soc_codec -> snd_soc_component -> snd_soc_component_driver  = snd_soc_codec_driver -> snd_soc_component_driver
	snd_soc_codec -> snd_soc_component -> probe                     = snd_soc_codec-> snd_soc_component -> snd_soc_component_driver -> prob
	snd_soc_codec -> snd_soc_component -> remove                    = snd_soc_codec-> snd_soc_component -> snd_soc_component_driver -> remove
	snd_soc_codec -> snd_soc_component -> struct snd_soc_dapm_context *dapm_ptr      = snd_soc_codec-> snd_soc_component -> struct snd_soc_dapm_context dapm
	
	struct snd_soc_dapm_context  =  snd_soc_codec -> snd_soc_component -> struct snd_soc_dapm_context *dapm_ptr 
	struct snd_soc_dapm_context -> device = platform_device->device
	struct snd_soc_dapm_context -> snd_soc_component = snd_soc_codec -> snd_soc_component 
	struct snd_soc_dapm_context -> bias_level = SND_SOC_BIAS_OFF;//关闭电源状态
	struct snd_soc_dapm_context -> idle_bias_off = true;//低功耗待机状态
	
	snd_soc_codec -> snd_soc_component -> snd_kcontrol_new = snd_soc_codec_driver -> snd_soc_component_driver -> snd_kcontrol_new 
	snd_soc_codec -> snd_soc_component -> num_controls = snd_soc_codec_driver -> snd_soc_component_driver -> num_controls 
	snd_soc_codec -> snd_soc_component -> dapm_widgets = snd_soc_codec_driver -> snd_soc_component_driver -> dapm_widgets
	snd_soc_codec -> snd_soc_component -> num_dapm_widgets = snd_soc_codec_driver -> snd_soc_component_driver -> num_dapm_widgets
	snd_soc_codec -> snd_soc_component -> dapm_routes  = snd_soc_codec_driver -> snd_soc_component_driver -> dapm_routes 
	snd_soc_codec -> snd_soc_component -> num_dapm_routes  = snd_soc_codec_driver -> snd_soc_component_driver -> num_dapm_routes
	创建一个 头为  snd_soc_codec -> snd_soc_component -> dai_list 的双向链表
	
*/

static int snd_soc_component_initialize(struct snd_soc_component *component, const struct snd_soc_component_driver *driver, struct device *dev)
{
	/*定义 struct snd_soc_dapm_context 动态音频电源管理 */
	struct snd_soc_dapm_context *dapm;

	/*
	获取 snd_soc_codec -> snd_soc_component -> name
	snd_soc_codec -> snd_soc_component -> device                    = platform_device->device
	snd_soc_codec -> snd_soc_component -> snd_soc_component_driver  = snd_soc_codec_driver -> snd_soc_component_driver
	snd_soc_codec -> snd_soc_component -> probe                     = snd_soc_codec-> snd_soc_component -> snd_soc_component_driver -> prob
	snd_soc_codec -> snd_soc_component -> remove                    = snd_soc_codec-> snd_soc_component -> snd_soc_component_driver -> remove
	*/
	component->name = fmt_single_name(dev, &component->id);


	component->dev = dev;
	component->driver = driver;
	component->probe = component->driver->probe;
	component->remove = component->driver->remove;

	/*
	snd_soc_codec -> snd_soc_component -> struct snd_soc_dapm_context *dapm_ptr      = snd_soc_codec-> snd_soc_component -> struct snd_soc_dapm_context dapm
	*/
	if (!component->dapm_ptr)
		component->dapm_ptr = &component->dapm;


	/*
	struct snd_soc_dapm_context  =  snd_soc_codec -> snd_soc_component -> struct snd_soc_dapm_context *dapm_ptr 
	struct snd_soc_dapm_context -> device = platform_device->device
	struct snd_soc_dapm_context -> snd_soc_component = snd_soc_codec -> snd_soc_component 
	struct snd_soc_dapm_context -> bias_level = SND_SOC_BIAS_OFF;//关闭电源状态
	struct snd_soc_dapm_context -> idle_bias_off = true;//低功耗待机状态
	*/
	dapm = component->dapm_ptr;
	dapm->dev = dev;
	dapm->component = component;
	dapm->bias_level = SND_SOC_BIAS_OFF;//关闭电源状态
	dapm->idle_bias_off = true;//低功耗待机状态


	/*
	如果 snd_soc_codec_driver-> seq_notifier() 存在
		struct snd_soc_dapm_context -> seq_notifier() = snd_soc_component_seq_notifier()

	如果 snd_soc_codec_driver -> seq_notifier() 存在
		struct snd_soc_dapm_context -> seq_notifier() = snd_soc_component_stream_event()
	*/
	if (driver->seq_notifier)
		dapm->seq_notifier = snd_soc_component_seq_notifier;
	if (driver->stream_event)
		dapm->stream_event = snd_soc_component_stream_event;

	/*
	snd_soc_codec -> snd_soc_component -> snd_kcontrol_new = snd_soc_codec_driver -> snd_soc_component_driver -> snd_kcontrol_new 
	snd_soc_codec -> snd_soc_component -> num_controls = snd_soc_codec_driver -> snd_soc_component_driver -> num_controls 
	snd_soc_codec -> snd_soc_component -> dapm_widgets = snd_soc_codec_driver -> snd_soc_component_driver -> dapm_widgets
	snd_soc_codec -> snd_soc_component -> num_dapm_widgets = snd_soc_codec_driver -> snd_soc_component_driver -> num_dapm_widgets
	snd_soc_codec -> snd_soc_component -> dapm_routes  = snd_soc_codec_driver -> snd_soc_component_driver -> dapm_routes 
	snd_soc_codec -> snd_soc_component -> num_dapm_routes  = snd_soc_codec_driver -> snd_soc_component_driver -> num_dapm_routes

	*/
	component->controls = driver->controls;
	component->num_controls = driver->num_controls;
	component->dapm_widgets = driver->dapm_widgets;
	component->num_dapm_widgets = driver->num_dapm_widgets;
	component->dapm_routes = driver->dapm_routes;
	component->num_dapm_routes = driver->num_dapm_routes;

	/*创建一个 头为  snd_soc_codec -> snd_soc_component -> dai_list 的双向链表*/
	INIT_LIST_HEAD(&component->dai_list);
	mutex_init(&component->io_mutex);

	return 0;
}



/*

sound/soc/mediatek/mt_soc_audio_6755/mt_soc_codec_63xx.c

mtk_mt6331_codec_dev_probe
  snd_soc_register_codec(&pdev->dev, &soc_mtk_codec, mtk_6331_dai_codecs, ARRAY_SIZE(mtk_6331_dai_codecs));//将 codec_driver 和 codec_dai_driver 注册到 soc-core。

参数:
struct device *dev                            ---- platform_device->device
const struct snd_soc_codec_driver *codec_drv  ---- struct snd_soc_codec_driver soc_mtk_codec,codec设备驱动
struct snd_soc_dai_driver *dai_drv            ---- struct snd_soc_dai_driver mtk_6323_dai_codecs[]
int num_dai                                   ---- ARRAY_SIZE(mtk_6331_dai_codecs)

说明
该函数内部的 所有 

struct snd_soc_dai_driver *dai_drv 就是  snd_soc_dai_driver mtk_6323_dai_codecs
struct snd_soc_codec_driver *codec_drv 就是 struct snd_soc_codec_driver soc_mtk_codec

1 
  定义 struct snd_soc_codec
  定义 snd_soc_dai
  分配struct snd_soc_codec 空间

2 ret = snd_soc_component_initialize(&codec->component, &codec_drv->component_driver, dev);

  2.1 初始化 snd_soc_codec -> snd_soc_component的成员
	
 	struct snd_soc_codec -> snd_soc_component -> snd_soc_codec  =  struct snd_soc_codec 	
 	struct snd_soc_codec -> snd_soc_component -> snd_soc_dapm_context  =  struct snd_soc_codec -> snd_soc_dapm_context	
 	获取 snd_soc_codec -> snd_soc_component -> name
	snd_soc_codec -> snd_soc_component -> device                                     = platform_device->device
	snd_soc_codec -> snd_soc_component -> snd_soc_component_driver                   = snd_soc_codec_driver -> snd_soc_component_driver
	snd_soc_codec -> snd_soc_component -> probe                                      = snd_soc_codec-> snd_soc_component -> snd_soc_component_driver -> prob
	snd_soc_codec -> snd_soc_component -> remove                                     = snd_soc_codec-> snd_soc_component -> snd_soc_component_driver -> remove
	snd_soc_codec -> snd_soc_component -> struct snd_soc_dapm_context *dapm_ptr      = snd_soc_codec-> snd_soc_component -> struct snd_soc_dapm_context dapm
	snd_soc_codec -> snd_soc_component -> snd_kcontrol_new                           = snd_soc_codec_driver -> snd_soc_component_driver -> snd_kcontrol_new 
	snd_soc_codec -> snd_soc_component -> num_controls                               = snd_soc_codec_driver -> snd_soc_component_driver -> num_controls 
	snd_soc_codec -> snd_soc_component -> dapm_widgets                               = snd_soc_codec_driver -> snd_soc_component_driver -> dapm_widgets
	snd_soc_codec -> snd_soc_component -> num_dapm_widgets                           = snd_soc_codec_driver -> snd_soc_component_driver -> num_dapm_widgets
	snd_soc_codec -> snd_soc_component -> dapm_routes                                = snd_soc_codec_driver -> snd_soc_component_driver -> dapm_routes 
	snd_soc_codec -> snd_soc_component -> num_dapm_routes                            = snd_soc_codec_driver -> snd_soc_component_driver -> num_dapm_routes
  
  2.2 定义struct snd_soc_dapm_context 并初始化部分成员
	struct snd_soc_dapm_context  =  snd_soc_codec -> snd_soc_component -> struct snd_soc_dapm_context *dapm_ptr 
	struct snd_soc_dapm_context -> device = platform_device->device
	struct snd_soc_dapm_context -> snd_soc_component = snd_soc_codec -> snd_soc_component 
	struct snd_soc_dapm_context -> bias_level = SND_SOC_BIAS_OFF;//关闭电源状态
	struct snd_soc_dapm_context -> idle_bias_off = true;//低功耗待机状态

  2.3
	创建一个 头为  snd_soc_codec -> snd_soc_component -> dai_list 的双向链表

3 
  3.1 继续初始化 snd_soc_codec -> snd_soc_component 成员
	snd_soc_codec -> snd_soc_component -> snd_kcontrol_new     = snd_soc_codec_driver -> snd_kcontrol_new
	snd_soc_codec -> snd_soc_component -> num_controls         = snd_soc_codec_driver -> num_controls
	snd_soc_codec -> snd_soc_component -> snd_soc_dapm_widget  = snd_soc_codec_driver -> snd_soc_dapm_widget
	snd_soc_codec -> snd_soc_component -> num_dapm_widgets     = snd_soc_codec_driver -> num_dapm_widgets
	snd_soc_codec -> snd_soc_component -> snd_soc_dapm_route   = snd_soc_codec_driver -> snd_soc_dapm_route
	snd_soc_codec -> snd_soc_component -> num_dapm_routes      = snd_soc_codec_driver -> num_dapm_routes
	snd_soc_codec -> snd_soc_component -> probe()              = snd_soc_codec_drv_probe()
	snd_soc_codec -> snd_soc_component -> remove()             = snd_soc_codec_drv_remove()
	snd_soc_codec -> snd_soc_component -> write()              = snd_soc_codec_drv_write()
	snd_soc_codec -> snd_soc_component -> read()               = snd_soc_codec_drv_read
	snd_soc_codec -> snd_soc_component -> ignore_pmdown_time   = snd_soc_codec_driver -> ignore_pmdown_time


  3.2 初始化 snd_soc_codec -> snd_soc_dapm_context 成员
	snd_soc_codec -> snd_soc_dapm_context -> idle_bias_off     = snd_soc_codec_driver -> idle_bias_off
	snd_soc_codec -> snd_soc_dapm_context -> suspend_bias_off  = snd_soc_codec_driver -> suspend_bias_off
	snd_soc_codec -> snd_soc_dapm_context -> seq_notifier      = snd_soc_codec_driver -> seq_notifier
	snd_soc_codec -> snd_soc_dapm_context -> set_bias_level    = snd_soc_codec_set_bias_level()

  3.3 绑定 snd_soc_codec -> device 与  platform_device->device
	snd_soc_codec -> device = platform_device->device

  3.4 绑定 snd_soc_codec -> snd_soc_codec_drive 与 snd_soc_codec_driver soc_mtk_codec
	snd_soc_codec -> snd_soc_codec_drive = snd_soc_codec_driver

4 register any DAIs : 注册
	ret = snd_soc_register_dais(&codec->component, dai_drv, num_dai, false);

  4.1 
	创建 struct snd_soc_dai *dai
	定义 struct device *dev,并用 snd_soc_codec -> snd_soc_component -> device 初始化。
		注意:前面已经将 platform_device->device 与 snd_soc_codec -> snd_soc_component -> device 绑定。此处就是用 platform_device->device 初始化
  4.2 
	snd_soc_codec -> snd_soc_component -> snd_soc_dai_driver = snd_soc_dai_driver
	snd_soc_codec -> snd_soc_component -> num_dai  = ARRAY_SIZE(mtk_6323_dai_codecs)
  
  4.3  初始化前面创建的  snd_soc_dai 中的成员

	为每一个 snd_soc_dai 分配空间 
	设置  struct snd_soc_dai -> name
	struct snd_soc_dai -> snd_soc_component                     = snd_soc_codec -> snd_soc_component 
	struct snd_soc_dai -> device                                = snd_soc_codec -> snd_soc_component -> device
	struct snd_soc_dai -> snd_soc_dai_driver                    = snd_soc_codec -> snd_soc_component -> snd_soc_dai_driver
	struct snd_soc_dai -> snd_soc_dai_driver -> snd_soc_dai_ops = 空
  4.4
	添加 struct snd_soc_dai -> list_head  插入到  snd_soc_codec -> snd_soc_component -> list_head dai_list 双向链表


5
  遍历以 &snd_soc_codec->snd_soc_component.list_head  为头节点,以 snd_soc_dai 为节点的双向链表。
	   初始化链表中每一个节点的  snd_soc_dai -> snd_soc_codec = snd_soc_codec

6 将 snd_soc_codec -> list_head 添加到  codec_list 双向链表
	list_add(&codec->list, &codec_list);

*/
 
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)
{
	/* 定义struct snd_soc_codec 结构体 */
	struct snd_soc_codec *codec;

	/* 定义 snd_soc_dai 结构体  */
	struct snd_soc_dai *dai;
	int ret, i;

	dev_dbg(dev, "codec register %s\n", dev_name(dev));

	/* 分配struct snd_soc_codec codec设备空间 */
	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
	if (codec == NULL)
		return -ENOMEM;

	/*
	struct snd_soc_codec -> snd_soc_component -> snd_soc_codec  =  struct snd_soc_codec 	
	struct snd_soc_codec -> snd_soc_component -> snd_soc_dapm_context  =  struct snd_soc_codec -> snd_soc_dapm_context	
	*/
	codec->component.dapm_ptr = &codec->dapm;
	codec->component.codec = codec;


	ret = snd_soc_component_initialize(&codec->component, &codec_drv->component_driver, dev);
	if (ret)
		goto err_free;


	/*

	snd_soc_codec -> snd_soc_component -> snd_kcontrol_new     = snd_soc_codec_driver -> snd_kcontrol_new
	snd_soc_codec -> snd_soc_component -> num_controls         = snd_soc_codec_driver -> num_controls
	snd_soc_codec -> snd_soc_component -> snd_soc_dapm_widget  = snd_soc_codec_driver -> snd_soc_dapm_widget
	snd_soc_codec -> snd_soc_component -> num_dapm_widgets     = snd_soc_codec_driver -> num_dapm_widgets
	snd_soc_codec -> snd_soc_component -> snd_soc_dapm_route   = snd_soc_codec_driver -> snd_soc_dapm_route
	snd_soc_codec -> snd_soc_component -> num_dapm_routes      = snd_soc_codec_driver -> num_dapm_routes

	snd_soc_codec -> snd_soc_component -> probe()              = snd_soc_codec_drv_probe()
	snd_soc_codec -> snd_soc_component -> remove()             = snd_soc_codec_drv_remove()
	snd_soc_codec -> snd_soc_component -> write()              = snd_soc_codec_drv_write()
	snd_soc_codec -> snd_soc_component -> read()               = snd_soc_codec_drv_read

	snd_soc_codec -> snd_soc_component -> ignore_pmdown_time   = snd_soc_codec_driver -> ignore_pmdown_time


	snd_soc_codec -> snd_soc_dapm_context -> idle_bias_off     = snd_soc_codec_driver -> idle_bias_off
	snd_soc_codec -> snd_soc_dapm_context -> suspend_bias_off  = snd_soc_codec_driver -> suspend_bias_off
	snd_soc_codec -> snd_soc_dapm_context -> seq_notifier      = snd_soc_codec_driver -> seq_notifier
	snd_soc_codec -> snd_soc_dapm_context -> set_bias_level    = snd_soc_codec_set_bias_level()

	snd_soc_codec -> device = platform_device->device
	snd_soc_codec -> snd_soc_codec_drive = snd_soc_codec_driver


	snd_soc_codec -> snd_soc_component -> val_bytes = snd_soc_codec_driver -> reg_word_size
	*/
	if (codec_drv->controls) {
		codec->component.controls = codec_drv->controls;
		codec->component.num_controls = codec_drv->num_controls;
	}
	if (codec_drv->dapm_widgets) {
		codec->component.dapm_widgets = codec_drv->dapm_widgets;
		codec->component.num_dapm_widgets = codec_drv->num_dapm_widgets;
	}
	if (codec_drv->dapm_routes) {
		codec->component.dapm_routes = codec_drv->dapm_routes;
		codec->component.num_dapm_routes = codec_drv->num_dapm_routes;
	}

	if (codec_drv->probe)
		codec->component.probe = snd_soc_codec_drv_probe;
	if (codec_drv->remove)
		codec->component.remove = snd_soc_codec_drv_remove;
	if (codec_drv->write)
		codec->component.write = snd_soc_codec_drv_write;
	if (codec_drv->read)
		codec->component.read = snd_soc_codec_drv_read;
	codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time;
	codec->dapm.idle_bias_off = codec_drv->idle_bias_off;
	codec->dapm.suspend_bias_off = codec_drv->suspend_bias_off;
	if (codec_drv->seq_notifier)
		codec->dapm.seq_notifier = codec_drv->seq_notifier;
	if (codec_drv->set_bias_level)
		codec->dapm.set_bias_level = snd_soc_codec_set_bias_level;
	codec->dev = dev;
	codec->driver = codec_drv;
	codec->component.val_bytes = codec_drv->reg_word_size;
	mutex_init(&codec->mutex);

#ifdef CONFIG_DEBUG_FS
	codec->component.init_debugfs = soc_init_codec_debugfs;
	codec->component.debugfs_prefix = "codec";
#endif

	if (codec_drv->get_regmap)
		codec->component.regmap = codec_drv->get_regmap(dev);

	for (i = 0; i < num_dai; i++) {
		fixup_codec_formats(&dai_drv[i].playback);
		fixup_codec_formats(&dai_drv[i].capture);
	}

	 /* register any DAIs */
	ret = snd_soc_register_dais(&codec->component, dai_drv, num_dai, false);

	/* 遍历以 &snd_soc_codec->snd_soc_component.list_head  为头节点,以 snd_soc_dai 为节点的双向链表。
	   初始化链表中节点的  snd_soc_dai -> snd_soc_codec = snd_soc_codec
	*/
	list_for_each_entry(dai, &codec->component.dai_list, list)
		dai->codec = codec;

	mutex_lock(&client_mutex);
	snd_soc_component_add_unlocked(&codec->component);

	/* 将 snd_soc_codec -> list_head 添加到  codec_list 双向链表*/
	list_add(&codec->list, &codec_list);
	mutex_unlock(&client_mutex);

	dev_dbg(codec->dev, "ASoC: Registered codec '%s'\n",
		codec->component.name);
	return 0;

err_cleanup:
	snd_soc_component_cleanup(&codec->component);
err_free:
	kfree(codec);
	return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_register_codec);
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Linux老A

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值