主要理解核心思想是alsa将底层硬件的不同做了抽象分别是cpu digital audio interface的不同,声卡codec的不同,以及如何将这两者进行关联的中介machine driver :dai link,通常名字是chipName_codecName.c;
simple_card架构即是简单通用的machine driver即dai_link
项目 | 功能 | 路径 |
---|---|---|
Sound soc | 主要包含公共部分代码,包括dapm 控制, jack, dmaengine,core 等等 | sound/soc/ |
rockchip platform | Rockchip 平台的 cpu dai 的驱动,比如 I²S, spdif 等以及自定义声卡machine driver | sound/soc/rockchip |
generic platform | simple card framework | sound/soc/generic |
codec driver | 所有的 codec driver 存放位置 | sound/soc/codecs |
一个声卡包含 cpu_dai, codec_dai, 以及 dai_link 组成,分别对应 cpu dai 的 dirver,比如I²S driver, spdif driver; codec driver, 比如 rk817 codec driver; dai_link driver,也就是 machine driver, 比如 sound/soc/rockchip/rockchip_rt5640.c。 4.4 的内核中支持两种方式创建声卡,一种是通用的 simple-card framework,一种是传统的编写自定义的 machinedriver 来创建。 本文以 rk817 为例。
sound/soc/codec/Kconfig:
tristate "Rockchip RK817 CODEC"
depends on MFD_RK808
select REGMAP_I2C
sound/soc/codec/Makefile:
snd-soc-rk817-objs := rk817_codec.o
obj-$(CONFIG_SND_SOC_RK817) += snd-soc-rk817.o
make menuconfig
Device Drivers --->
[*] Sound card support --->
[*] Advanced Linux Sound Architecture --->
[*] ALSA for SoC audio support --->
[*] ASoC support for Rockchip
[*] Rockchip I2S Device Driver
CODEC drivers --->
[*] Rockchip RK817 CODEC
[*] ASoC Simple sound card support
rk809-sound {
compatible = "simple-audio-card";
simple-audio-card,format = "i2s";
simple-audio-card,name = "rockchip,rk809-codec";
simple-audio-card,mclk-fs = <256>;
simple-audio-card,widgets =
"Microphone", "Mic Jack",
"Headphone", "Headphone Jack";
simple-audio-card,routing =
"Mic Jack", "MICBIAS1",
"IN1P", "Mic Jack",
"Headphone Jack", "HPOL",
"Headphone Jack", "HPOR";
simple-audio-card,cpu {
sound-dai = <&i2s1>;
};
simple-audio-card,codec {
sound-dai = <&rk809_codec>;
};
};
&i2c0 {
rk809: pmic@20 {
rk809_codec: codec {
#sound-dai-cells = <0>;
compatible = "rockchip,rk809-codec", "rockchip,rk817-codec";
clocks = <&cru SCLK_I2S_8CH_OUT>;
clock-names = "mclk";
pinctrl-names = "default","spk_gpio";
pinctrl-0 = <&i2s_8ch_mclk>;
hp-volume = <20>;
spk-volume = <3>;
io-channels = <&saradc 4>;
hp-det-adc-value = <930>;
capture-volume = <0>;
spk-ctl = <&gpio0 RK_PB1 GPIO_ACTIVE_HIGH>;
pinctrl-1 = <&spk_ctl_gpio>;
status = "okay";
};
};
};
首先通过打印大致看看:
[ 2.527416] asoc-simple-card rk809-sound: New simple-card: rockchip,rk809-codec
[ 2.527458] asoc-simple-card rk809-sound: Revert to legacy daifmt parsing
[ 2.527681] asoc-simple-card rk809-sound: name : ff890000.i2s-rk817-hifi
[ 2.527702] asoc-simple-card rk809-sound: format : 4001
[ 2.527721] asoc-simple-card rk809-sound: cpu : ff890000.i2s / 0
[ 2.527739] asoc-simple-card rk809-sound: codec : rk817-hifi / 0
[ 2.527761] of_get_named_gpiod_flags: can't parse 'simple-audio-card,hp-det-gpio' property of node '/rk809-sound[0]'
[ 2.527782] of_get_named_gpiod_flags: can't parse 'simple-audio-card,mic-det-gpio' property of node '/rk809-sound[0]'
[ 2.536256] asoc-simple-card rk809-sound: rk817-hifi <-> ff890000.i2s mapping ok
[ 2.536953] asoc-simple-card rk809-sound: ASoC: no source widget found for MICBIAS1
[ 2.537668] asoc-simple-card rk809-sound: ASoC: Failed to add route MICBIAS1 -> direct -> Mic Jack
[ 2.538485] asoc-simple-card rk809-sound: ASoC: no sink widget found for IN1P
[ 2.539150] asoc-simple-card rk809-sound: ASoC: Failed to add route Mic Jack -> direct -> IN1P
[ 2.539924] asoc-simple-card rk809-sound: ASoC: no source widget found for HPOL
[ 2.540594] asoc-simple-card rk809-sound: ASoC: Failed to add route HPOL -> direct -> Headphone Jack
[ 2.541425] asoc-simple-card rk809-sound: ASoC: no source widget found for HPOR
[ 2.542098] asoc-simple-card rk809-sound: ASoC: Failed to add route HPOR -> direct -> Headphone Jack
[ 2.544603] input: rockchip,rk809-codec Headphone Jack as /devices/platform/rk809-sound/sound/card1/input4
kernel/sound/soc/generic/simple-card.c
函数调用顺序大致如下:
static const struct of_device_id asoc_simple_of_match[] = {
{ .compatible = "simple-audio-card", },
{},
};
通过driver platform框架我们可以知道下面会调用probe函数
asoc_simple_card_probe
asoc_simple_card_parse_of
snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name");//拿到卡的名字即dts中rockchip,rk809-codec
/* For single DAI link & old style of DT node */
asoc_simple_card_dai_link_of //连接cpu dai与codec dai
asoc_simple_card_sub_parse_of(cpu, &dai_props->cpu_dai,
&dai_link->cpu_of_node,
&dai_link->cpu_dai_name,
&cpu_args); //拿到cpu dai
asoc_simple_card_sub_parse_of(codec, &dai_props->codec_dai,
&dai_link->codec_of_node,
&dai_link->codec_dai_name,
NULL;//拿到codec dai
//soc/soc-core.c +3606
of_parse_phandle_with_args(of_node, "sound-dai",
"#sound-dai-cells", 0, &args);//#sound-dai-cells 在dts中是0,即rk817_codec.c中的struct snd_soc_dai_driver rk817_dai[0]节点 即rk817-hifi。
snd_soc_of_get_dai_name(np, name); //拿到dai name
//注册声卡
snd_soc_card_set_drvdata(&priv->snd_card, priv);
ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
这个达到的效果跟machine driver是一样的,只不过这个属于读取dts然后批量注册声卡,更加简单高效。