ALSA ASOC Codec Driver
- 一、Codec 简介
- 二、Codec 注册
- 2.1 Codec Driver 的 Platform Driver & Platform Device 驱动模型
- 2.2 在 Probe() 中注册 Codec Driver
一、Codec 简介
Codec 的作用可以归结为 4 种,分别是:
- 对 PCM 等信号进行 D/A 转换,把数字的音频信号转换为模拟信号
- 对 Mic、Line in 或者其他输入源的模拟信号进行 A/D 转换,把模拟的声音信号转变 CPU 能够处理的数字信号
- 对音频通路进行控制,比如播放音乐,收听调频收音机,又或者接听电话时,音频信号在 codec 内的流通路线是不一样的
- 对音频信号做出相应的处理,例如音量控制,功率放大,EQ 控制等等
ASoC 对 Codec 的这些功能都定义了一个基本要求是:驱动程序的代码必须要做到平台无关性,以方便同一个 Codec 的代码不经修改即可在不同的平台上。
二、Codec 注册
# Note下面均以 wm8960.c 为例进行讲解
2.1 Codec Driver 的 Platform Driver & Platform Device 驱动模型
该部分其实就是 /sound/soc/codecs/wm8960.c
中的 platform driver 与 /arch/arm/boot/dts/mt7623a-rfb-emmc.dts
中的 platform device 进行匹配,匹配成功后调用 wm8960_i2c_probe()
函数。
1)wm8960.c
static const struct of_device_id wm8960_of_match[] = {{ .compatible = "wlf,wm8960", },{ }
};
MODULE_DEVICE_TABLE(of, wm8960_of_match);static struct i2c_driver wm8960_i2c_driver = {.driver = {.name = "wm8960",.of_match_table = wm8960_of_match,},.probe = wm8960_i2c_probe,.remove = wm8960_i2c_remove,.id_table = wm8960_i2c_id,
};module_i2c_driver(wm8960_i2c_driver);
在 platform driver
中有注册名为 "wlf,wm8960"
;
2)mt7623a-rfb-emmc.dts
...
&i2c1 {pinctrl-names = "default";pinctrl-0 = <&i2c1_pins_b>;status = "okay";wm8960: wm8960@1a {compatible = "wlf,wm8960";reg = <0x1a>;};
};
...
在设备树文件中有注册名为 "wlf,wm8960"
的 platform device
,当 platform driver & platform device 匹配之后则会调用 platform_driver 下的 probe() 函数。
2.2 在 Probe() 中注册 Codec Driver
devm_snd_soc_register_component(&i2c->dev,&soc_component_dev_wm8960, &wm8960_dai, 1); // 创建 Codec Component
同 Platform Dai Driver 一样,Codec Driver 调用 snd_soc_register_component() 函数将 snd_soc_component_driver & snd_soc_dai_driver
注册为一个 snd_soc_component
实例,并且通过 snd_soc_register_dais() 循环将所有的 snd_soc_dai_driver register 为 snd_soc_dai,加入到 component->dai_list
中,最后将该 component 添加到全局链表 component_list
中以便能被 Machine 驱动识别,注册时序框图如下:
1)Codec Driver
static const struct snd_soc_component_driver soc_component_dev_wm8960 = {.probe = wm8960_probe,.set_bias_level = wm8960_set_bias_level,.suspend_bias_off = 1,.idle_bias_on = 1,.use_pmdown_time = 1,.endianness = 1,.non_legacy_dai_naming = 1,
};
Codec Driver 一般都是 dapm widgets,dapm_route 数组。有两种方式可以注册 dapm widgets 和 dapm route.
- 通过上面的 struct snd_soc_component_driver soc_component_dev_wm8960 结构体中初始化 dapm widgets 数组和 dapm route 数组;
- 在 struct snd_soc_component_driver 的 probe 函数中注册,需要调用 snd_soc_dapm_new_controls 和 snd_soc_dapm_add_routes 注册 dapm widgets 和 dapm route.
实际上第一种方式 struct snd_soc_component_driver 注册到 asoc core 里的时候也会通过这两个函数注册。
# Note涉及的 DAPM 详见后面 DAPM 章节
2)Codec Dai Driver
static const struct snd_soc_dai_ops wm8960_dai_ops = {.hw_params = wm8960_hw_params,.hw_free = wm8960_hw_free,.digital_mute = wm8960_mute,.set_fmt = wm8960_set_dai_fmt,.set_clkdiv = wm8960_set_dai_clkdiv,.set_pll = wm8960_set_dai_pll,.set_sysclk = wm8960_set_dai_sysclk,
};static struct snd_soc_dai_driver wm8960_dai = {.name = "wm8960-hifi",.playback = {.stream_name = "Playback",.channels_min = 1,.channels_max = 2,.rates = WM8960_RATES,.formats = WM8960_FORMATS,},.capture = {.stream_name = "Capture",.channels_min = 1,.channels_max = 2,.rates = WM8960_RATES,.formats = WM8960_FORMATS,},.ops = &wm8960_dai_ops,.symmetric_rates = 1,
};
参考链接:
linux-alsa详解6 ASOC-codec