概述
ALSA(Advanced Linux Sound Architecture)是Linux内核中关于音频驱动的框架,它定义了音频驱动的框架,使得音频驱动可以方便地被用户空间调用。
ALSA驱动起始页https://kernel.org/doc/html/latest/sound/index.html
asla驱动代码结构https://kernel.org/doc/html/latest/sound/kernel-api/writing-an-alsa-driver.html
本文主要介绍一下ALSA驱动开发的相关设备树及源文件。
背景
基于正点原子的i.MX6ULL开发板,Linux内核版本 4.1.15
设备树 imx6ull-alientek-emmc.dts
sound {
compatible = "fsl,imx6ul-evk-wm8960",
"fsl,imx-audio-wm8960";
model = "wm8960-audio";
cpu-dai = <&sai2>;
audio-codec = <&codec>;
asrc-controller = <&asrc>;
codec-master;
gpr = <&gpr 4 0x100000 0x100000>;
/*
* hp-det = <hp-det-pin hp-det-polarity>;
* hp-det-pin: JD1 JD2 or JD3
* hp-det-polarity = 0: hp detect high for headphone
* hp-det-polarity = 1: hp detect high for speaker
*/
hp-det = <3 0>;
hp-det-gpios = <&gpio5 4 0>;
mic-det-gpios = <&gpio5 4 0>;
audio-routing =
"Headphone Jack", "HP_L",
"Headphone Jack", "HP_R",
"Ext Spk", "SPK_LP",
"Ext Spk", "SPK_LN",
"Ext Spk", "SPK_RP",
"Ext Spk", "SPK_RN",
"LINPUT2", "Mic Jack",
"LINPUT3", "Mic Jack",
"RINPUT1", "Main MIC",
"RINPUT2", "Main MIC",
"Mic Jack", "MICB",
"Main MIC", "MICB",
"CPU-Playback", "ASRC-Playback",
"Playback", "CPU-Playback",
"ASRC-Capture", "CPU-Capture",
"CPU-Capture", "Capture";
};
&i2c1 {
clock-frequency = <100000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1>;
status = "okay";
codec: wm8960@1a {
compatible = "wlf,wm8960";
reg = <0x1a>;
clocks = <&clks IMX6UL_CLK_SAI2>;
clock-names = "mclk";
wlf,shared-lrclk;
};
};
&sai2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_sai2
&pinctrl_sai2_hp_det_b>;
assigned-clocks = <&clks IMX6UL_CLK_SAI2_SEL>,
<&clks IMX6UL_CLK_SAI2>;
assigned-clock-parents = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;
assigned-clock-rates = <0>, <12288000>;
status = "okay";
};
次级设备树 imx6ull.dtsi
sai2: sai@0202c000 {
compatible = "fsl,imx6ul-sai",
"fsl,imx6sx-sai";
reg = <0x0202c000 0x4000>;
interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_SAI2_IPG>,
<&clks IMX6UL_CLK_DUMMY>,
<&clks IMX6UL_CLK_SAI2>,
<&clks 0>, <&clks 0>;
clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
dma-names = "rx", "tx";
dmas = <&sdma 37 24 0>, <&sdma 38 24 0>;
status = "okay";
};
asrc: asrc@02034000 {
compatible = "fsl,imx53-asrc";
reg = <0x02034000 0x4000>;
interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_ASRC_IPG>,
<&clks IMX6UL_CLK_ASRC_MEM>, <&clks 0>,
<&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>,
<&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>,
<&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>,
<&clks IMX6UL_CLK_SPDIF>, <&clks 0>, <&clks 0>,
<&clks IMX6UL_CLK_SPBA>;
clock-names = "mem", "ipg", "asrck_0",
"asrck_1", "asrck_2", "asrck_3", "asrck_4",
"asrck_5", "asrck_6", "asrck_7", "asrck_8",
"asrck_9", "asrck_a", "asrck_b", "asrck_c",
"asrck_d", "asrck_e", "asrck_f", "dma";
dmas = <&sdma 17 23 1>, <&sdma 18 23 1>, <&sdma 19 23 1>,
<&sdma 20 23 1>, <&sdma 21 23 1>, <&sdma 22 23 1>;
dma-names = "rxa", "rxb", "rxc",
"txa", "txb", "txc";
fsl,asrc-rate = <48000>;
fsl,asrc-width = <16>;
status = "okay";
};
sdma: sdma@020ec000 {
compatible = "fsl,imx6ul-sdma", "fsl,imx35-sdma";
reg = <0x020ec000 0x4000>;
interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_SDMA>,
<&clks IMX6UL_CLK_SDMA>;
clock-names = "ipg", "ahb";
#dma-cells = <3>;
iram = <&ocram>;
fsl,sdma-ram-script-name = "imx/sdma/sdma-imx6q.bin";
};
源文件
//sound/soc/fsl/imx-wm8960.c
static const struct of_device_id imx_wm8960_dt_ids[] = {
{ .compatible = "fsl,imx-audio-wm8960", },
{ /* sentinel */ }
};
static struct platform_driver imx_wm8960_driver = {
.driver = {
.name = "imx-wm8960",
.pm = &snd_soc_pm_ops,
.of_match_table = imx_wm8960_dt_ids,
},
.probe = imx_wm8960_probe,
.remove = imx_wm8960_remove,
};
module_platform_driver(imx_wm8960_driver);
//sound/soc/fsl/fsl_sai.c
static const struct of_device_id fsl_sai_ids[] = {
{ .compatible = "fsl,vf610-sai", },
{ .compatible = "fsl,imx6sx-sai", },
{ /* sentinel */ }
};
static struct platform_driver fsl_sai_driver = {
.probe = fsl_sai_probe,
.driver = {
.name = "fsl-sai",
.pm = &fsl_sai_pm_ops,
.of_match_table = fsl_sai_ids,
},
};
module_platform_driver(fsl_sai_driver);
//sound/soc/fsl/fsl_asrc.c
static const struct of_device_id fsl_asrc_ids[] = {
{ .compatible = "fsl,imx35-asrc", },
{ .compatible = "fsl,imx53-asrc", },
{}
};
static struct platform_driver fsl_asrc_driver = {
.probe = fsl_asrc_probe,
.remove = fsl_asrc_m2m_remove,
.driver = {
.name = "fsl-asrc",
.of_match_table = fsl_asrc_ids,
.pm = &fsl_asrc_pm,
},
};
module_platform_driver(fsl_asrc_driver);
//sound/soc/codecs/wm8960.c
static const struct of_device_id wm8960_of_match[] = {
{ .compatible = "wlf,wm8960", },
{ }
};
static struct i2c_driver wm8960_i2c_driver = {
.driver = {
.name = "wm8960",
.owner = THIS_MODULE,
.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);