一 提纲

二 概述

三 代码分析


一 提纲

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_codec2 初始化 snd_soc_codec -> snd_soc_componen2 初始化 snd_soc_codec -> snd_soc_dapm_context3 创建一个 头为  snd_soc_codec -> snd_soc_component -> dai_list 的双向链表4 绑定 snd_soc_codec -> device 与  platform_device->device5 绑定 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_dai6.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->devicestruct 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_codec8 将 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 driverARRAY_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;
#endifstatic int __init mtk_mt6331_codec_init(void)
{pr_warn("%s:\n", __func__);
#ifndef CONFIG_OFint 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;}
#endifInitGlobalVarDefault();/*注册平台驱动*/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.cstatic 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_driversnd_soc_codec -> snd_soc_component -> snd_soc_dai_driver = snd_soc_dai_driversnd_soc_codec -> snd_soc_component -> num_dai  = ARRAY_SIZE(mtk_6323_dai_codecs)为每一个 snd_soc_dai 分配空间 设置  struct snd_soc_dai -> namestruct snd_soc_dai -> snd_soc_component = snd_soc_codec -> snd_soc_component struct snd_soc_dai -> device = snd_soc_codec -> snd_soc_component -> devicestruct snd_soc_dai -> snd_soc_dai_driver = snd_soc_codec -> snd_soc_component -> snd_soc_dai_driverstruct 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_driversnd_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 -> namestruct snd_soc_dai -> snd_soc_component = snd_soc_codec -> snd_soc_component struct snd_soc_dai -> device = snd_soc_codec -> snd_soc_component -> devicestruct snd_soc_dai -> snd_soc_dai_driver = snd_soc_codec -> snd_soc_component -> snd_soc_dai_driverstruct 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;elsedai->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 -> namesnd_soc_codec -> snd_soc_component -> device                    = platform_device->devicesnd_soc_codec -> snd_soc_component -> snd_soc_component_driver  = snd_soc_codec_driver -> snd_soc_component_driversnd_soc_codec -> snd_soc_component -> probe                     = snd_soc_codec-> snd_soc_component -> snd_soc_component_driver -> probsnd_soc_codec -> snd_soc_component -> remove                    = snd_soc_codec-> snd_soc_component -> snd_soc_component_driver -> removesnd_soc_codec -> snd_soc_component -> struct snd_soc_dapm_context *dapm_ptr      = snd_soc_codec-> snd_soc_component -> struct snd_soc_dapm_context dapmstruct 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->devicestruct 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_widgetssnd_soc_codec -> snd_soc_component -> num_dapm_widgets = snd_soc_codec_driver -> snd_soc_component_driver -> num_dapm_widgetssnd_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 -> namesnd_soc_codec -> snd_soc_component -> device                    = platform_device->devicesnd_soc_codec -> snd_soc_component -> snd_soc_component_driver  = snd_soc_codec_driver -> snd_soc_component_driversnd_soc_codec -> snd_soc_component -> probe                     = snd_soc_codec-> snd_soc_component -> snd_soc_component_driver -> probsnd_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->devicestruct 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_widgetssnd_soc_codec -> snd_soc_component -> num_dapm_widgets = snd_soc_codec_driver -> snd_soc_component_driver -> num_dapm_widgetssnd_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.cmtk_mt6331_codec_dev_probesnd_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_codec1 定义 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 -> namesnd_soc_codec -> snd_soc_component -> device                                     = platform_device->devicesnd_soc_codec -> snd_soc_component -> snd_soc_component_driver                   = snd_soc_codec_driver -> snd_soc_component_driversnd_soc_codec -> snd_soc_component -> probe                                      = snd_soc_codec-> snd_soc_component -> snd_soc_component_driver -> probsnd_soc_codec -> snd_soc_component -> remove                                     = snd_soc_codec-> snd_soc_component -> snd_soc_component_driver -> removesnd_soc_codec -> snd_soc_component -> struct snd_soc_dapm_context *dapm_ptr      = snd_soc_codec-> snd_soc_component -> struct snd_soc_dapm_context dapmsnd_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_widgetssnd_soc_codec -> snd_soc_component -> num_dapm_widgets                           = snd_soc_codec_driver -> snd_soc_component_driver -> num_dapm_widgetssnd_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_routes2.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->devicestruct 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_newsnd_soc_codec -> snd_soc_component -> num_controls         = snd_soc_codec_driver -> num_controlssnd_soc_codec -> snd_soc_component -> snd_soc_dapm_widget  = snd_soc_codec_driver -> snd_soc_dapm_widgetsnd_soc_codec -> snd_soc_component -> num_dapm_widgets     = snd_soc_codec_driver -> num_dapm_widgetssnd_soc_codec -> snd_soc_component -> snd_soc_dapm_route   = snd_soc_codec_driver -> snd_soc_dapm_routesnd_soc_codec -> snd_soc_component -> num_dapm_routes      = snd_soc_codec_driver -> num_dapm_routessnd_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_readsnd_soc_codec -> snd_soc_component -> ignore_pmdown_time   = snd_soc_codec_driver -> ignore_pmdown_time3.2 初始化 snd_soc_codec -> snd_soc_dapm_context 成员snd_soc_codec -> snd_soc_dapm_context -> idle_bias_off     = snd_soc_codec_driver -> idle_bias_offsnd_soc_codec -> snd_soc_dapm_context -> suspend_bias_off  = snd_soc_codec_driver -> suspend_bias_offsnd_soc_codec -> snd_soc_dapm_context -> seq_notifier      = snd_soc_codec_driver -> seq_notifiersnd_soc_codec -> snd_soc_dapm_context -> set_bias_level    = snd_soc_codec_set_bias_level()3.3 绑定 snd_soc_codec -> device 与  platform_device->devicesnd_soc_codec -> device = platform_device->device3.4 绑定 snd_soc_codec -> snd_soc_codec_drive 与 snd_soc_codec_driver soc_mtk_codecsnd_soc_codec -> snd_soc_codec_drive = snd_soc_codec_driver4 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_driversnd_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 -> namestruct snd_soc_dai -> snd_soc_component                     = snd_soc_codec -> snd_soc_component struct snd_soc_dai -> device                                = snd_soc_codec -> snd_soc_component -> devicestruct snd_soc_dai -> snd_soc_dai_driver                    = snd_soc_codec -> snd_soc_component -> snd_soc_dai_driverstruct 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_codec6 将 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_newsnd_soc_codec -> snd_soc_component -> num_controls         = snd_soc_codec_driver -> num_controlssnd_soc_codec -> snd_soc_component -> snd_soc_dapm_widget  = snd_soc_codec_driver -> snd_soc_dapm_widgetsnd_soc_codec -> snd_soc_component -> num_dapm_widgets     = snd_soc_codec_driver -> num_dapm_widgetssnd_soc_codec -> snd_soc_component -> snd_soc_dapm_route   = snd_soc_codec_driver -> snd_soc_dapm_routesnd_soc_codec -> snd_soc_component -> num_dapm_routes      = snd_soc_codec_driver -> num_dapm_routessnd_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_readsnd_soc_codec -> snd_soc_component -> ignore_pmdown_time   = snd_soc_codec_driver -> ignore_pmdown_timesnd_soc_codec -> snd_soc_dapm_context -> idle_bias_off     = snd_soc_codec_driver -> idle_bias_offsnd_soc_codec -> snd_soc_dapm_context -> suspend_bias_off  = snd_soc_codec_driver -> suspend_bias_offsnd_soc_codec -> snd_soc_dapm_context -> seq_notifier      = snd_soc_codec_driver -> seq_notifiersnd_soc_codec -> snd_soc_dapm_context -> set_bias_level    = snd_soc_codec_set_bias_level()snd_soc_codec -> device = platform_device->devicesnd_soc_codec -> snd_soc_codec_drive = snd_soc_codec_driversnd_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_FScodec->component.init_debugfs = soc_init_codec_debugfs;codec->component.debugfs_prefix = "codec";
#endifif (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);

ALSA之Codec注册过程相关推荐

  1. Linux ALSA 之九:ALSA ASOC Codec Driver

    ALSA ASOC Codec Driver 一.Codec 简介 二.Codec 注册 2.1 Codec Driver 的 Platform Driver & Platform Devic ...

  2. alsa 添加codec

    在嵌入式Linux的开发中,我们经常会更换codec芯片,这就需要我们添加codec驱动,下面就介绍下如何添加音频codec驱动. 1 codec驱动的数据结构 struct snd_soc_code ...

  3. Linux ALSA音频系统:platform,machine,codec

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/weixin_41965270/arti ...

  4. Linux ALSA 音频系统:物理链路篇

    原址 1. Overview 硬件平台及软件版本: Kernel - 3.4.5 SoC - Samsung exynos CODEC - WM8994 Machine - goni_wm8994 U ...

  5. PCM data flow - 3 - ASoC codec driver

    上一章提到codec_drv的几个组成部分,下面逐一介绍,基本是以内核文档Documentation/sound/alsa/soc/codec.txt中的内容为脉络来分析的.codec的作用,在概述中 ...

  6. linux alsa驱动讲解

    转载自:https://codertw.com/%E7%A8%8B%E5%BC%8F%E8%AA%9E%E8%A8%80/477412/ 程式前沿 幫助程式設計師解決問題,增加專業技能,提升個人能力與 ...

  7. (一)Linux ALSA 音频系统:物理链路篇

    物理链路篇 转自:https://me.csdn.net/zyuanyun Linux ALSA 音频系统:物理链路篇 Linux ALSA 音频系统:物理链路篇 原创 zyuanyun 最后发布于2 ...

  8. PCM data flow - 1 - Overview

    Kernel     - 3.4.5 SoC        - Samsung exynos CODEC      - WM8994 Machine    - goni_wm8994 Userspac ...

  9. Linux下 WiFi rtl 移植,IMX6Q Linux WIFI+BT(RTL8723au)模块移植问题

    软件环境:IMX6Q 4核,Linux 下    BSP: L3.0.35_4.1.0_130816_source 开机打印信息: U-Boot 2009.08 ( 5��月 26 2016 - 12 ...

  10. imx6 kernel boog log

    U-Boot 2009.08-dirty ( 9�19 2014 - 18:53:46) CPU: Freescale i.MX6 family TO1.2 at 792 MHz Thermal ...

最新文章

  1. 深度解析KGDB调试Linux模块和内核
  2. 谁把20岁上下的你给洗脑了
  3. 源哥每日一题第十三弹 百练4124:海贼王之伟大航路 状压dp
  4. gulp加速hexo的yelee主题
  5. HDLBits答案(8)_Verilog半加器、全加器和行波进位加法器原理与设计
  6. ssm(Spring+Spring mvc+mybatis)Service层实现类——DeptServiceImpl
  7. linux堆上的内存可执行吗,pwn的艺术浅谈(二):linux堆相关
  8. [html] 如何让<p>测试 空格</p>这两个词之间的空格变大?
  9. 查看你所使用计算机的网卡信息,查看网卡信息命令
  10. 《推荐系统实战(二)》音乐推荐系统(数据清洗、召回、排序)
  11. idea快捷键汇总mac_IntelliJ IDEA for MAC 快捷键设置汇总
  12. 苹果沦为语音识别领域失败者?
  13. 中铁总数据中心落户武清 项目总投资22.7亿元
  14. Ubuntu18.04卸载QQ
  15. 计算机网络对社会发展的影响
  16. 从零开始快速搭建LoRaWAN节点设备
  17. C++一本通题库1012
  18. C语言七巧板游戏制作,七巧板具体玩法与制作方法详解
  19. 原生JS制作抽奖小游戏
  20. C++ 与、或、异或、取反等运算

热门文章

  1. java计算机毕业设计BS用户小票系统MyBatis+系统+LW文档+源码+调试部署
  2. 未来10年,最值得投资的40个城市
  3. php怎么字符串转成json对象_php如何将字符串转成json_后端开发
  4. Mac访问Github加速
  5. 字体管理工具字由 v2.4.0.0 绿色便携版
  6. Python数据处理Tips机器学习中文数据8种常用处理方法
  7. wincc怎么c语言编程,WINCC几个常用C语言编程
  8. xmind8 安装方法(old)
  9. java 读音_java怎么读?
  10. 硬件电路设计之电平转换芯片SN74LVC4245A