Linux 音频驱动

1 I.MX6ULL 开发板通过此接口外接了一个 WM8960 音频 DAC 芯片。

2 在信号处理领域,外界的声音是模拟信号处理器能理解的是数字信号,因此这里就涉及到一个模拟信号转换为数字信号的过程,而完成这个功能的就是 ADC 芯片。

如果处理器要向外界传达自己的“心声”,也就是放音,那么就涉及到将处理器能理解的 0 和 1 转化为外界能理解的连续变化的声音, 这个过程就是将数字信号转化为模拟信号,而完成这个功能的是 DAC 芯片。

3 WM8960 是一颗由 wolfson(欧胜)公司出品的音频编解码芯片,是一颗低功耗、高质量的立体声(左右声道)音频 CODEC。集成 D 类喇叭功放,每个通道可以驱动一个 1W 喇叭(8Ω )。内部集成 3 个立体声输入源,可以灵活配置,拥有一路完整的麦克风接口。

WM8960 内部 ADC (录音)和 DAC(放音) 都为24 位, WM8960 主要特性如下所示:
①、 DAC 的 SNR(信噪比)为 98dB, 3.3V、 48KHz 下 THD(谐波失真)为-84dB。
②、 ADC 的 SNR(信噪比)为 94dB, 3.3V、 48KHz 下 THD(谐波失真)为-82dB。
③、 3D 增强。
④、立体声 D 类功放, 可以直接外接喇叭, 8Ω负载下每通道 1W。
⑤、集成耳机接口。
⑥、集成麦克风接口。
⑦、采样率支持 8K、 11.025K、 12K、 16K、 22.05K、 24K、 32K、 44.1K 和 48K。

4 I2S 总线接口

I2S(Inter-IC Sound)总线有时候也写作 IIS, I2S 是飞利浦公司提出的一种用于数字音频设备之间进行音频数据传输的总线。和 I2C、 SPI 这些常见的通信协议一样, I2S 总线用于主控制器和音频 CODEC 芯片之间传输音频数据。

音频DAC,一般是i2c为控制接口;i2s为音频接口。

5 硬件连接图

6.音频驱动使能

1)需要一个WM8960驱动文件,IIC框架的,用来配置WM8960的功能;

2)需要一个SOC端SAI外设的驱动文件;

3)需要一个驱动文件,将WM8960与I.MX6ULL联系起来。

因此,有三个驱动文件。

7.ASoc是在ALSA基础上,针对SOC另外改进的ALSA音频驱动框架。目前ARM处理的音频驱动框架都是ASoC。

分为三部分:SOC(platform)、Codec部分、板载硬件(Machine)。

SOC:具体的SOC音频接口驱动,比如6ULL的SAI接口,都是半导体厂商编写好的

Codec:具体的音频芯片,比如WM8960,IIC驱动。也不需要我们编写,Codec芯片厂商会写好。

板载硬件:Machine部分,将具体的SOC与具体的Codec结合。与具体的硬件设备相关,也就是我们要处理的部分。使用ASOC驱动框架将SOC于Codec结合。

eg:本开发板:

1·、Codec部分驱动文件就是wm8960.c,IIC接口的

2、SOC(platform)部分就是I.MX6ULL的SAI驱动,驱动文件就是fsl_sai.c。

3、板载硬件(Machine)部分,sound节点。驱动文件就是imx-wm8960.c。

8.设备树

/{
	soc {
			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 = "disabled";
				};
         }; 

    /* 板载驱动 */
    sound {
			/* 用于匹配相应的驱动文件 */
            compatible = "fsl,imx6ul-evk-wm8960",
                         "fsl,imx-audio-wm8960";
            model = "wm8960-audio";     /* 声卡名字 */
			
			/* SOC音频接口驱动 */
            cpu-dai = <&sai2>;         
			
			/* 具体的音频芯片 */
            audio-codec = <&codec>;   
			
            asrc-controller = <&asrc>;  /* asrc 控制器, asrc:异步采样频率转化器。 */
            codec-master;
            gpr = <&gpr 4 0x100000 0x100000>;
			
			/* 耳机插入检测引脚设置 */
            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";
                status = "okay";
        };  
 };


&i2c2 {
    clock_frequency = <100000>; /* i2c2通信频率 */
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_i2c2>;
	
    status = "okay"; /* i2c2状态为开启 */

        codec: wm8960@1a {    
				compatible = "wlf,wm8960";				
				reg = <0x1a>;              /* 设置 WM8960 的 I2C 地址0X1A */
				
				/* 描述时钟相关信息 */
				clocks = <&clks IMX6UL_CLK_SAI2>; /* 指定时钟源为 SAI2 */
				clock-names = "mclk";             /* 指定时钟的名字为“mclk” */
				
				/* 这也是一个 bool 类型的属性, 如果添加了此属性, OUT3 引脚将会使能,并且为了响应耳机插入响应事件, HP_L 和 HP_R 这两个引脚都会关闭。 */
				wlf,shared-lrclk;
        };
};

&sai2 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_sai2>;

    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";
};

&iomuxc {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_hog_1>;
    imx6ul-evk {
        /* i2c */
        pinctrl_i2c2: i2c2grp {
            fsl,pins = <
                MX6UL_PAD_UART5_TX_DATA__I2C2_SCL 0x4001b8b0
                MX6UL_PAD_UART5_RX_DATA__I2C2_SDA 0x4001b8b0
            >;
        };
        /* sai2 */
        pinctrl_sai2: sai2grp {
            fsl,pins = <
                MX6UL_PAD_JTAG_TDI__SAI2_TX_BCLK    0x17088
                MX6UL_PAD_JTAG_TDO__SAI2_TX_SYNC    0x17088
                MX6UL_PAD_JTAG_TRST_B__SAI2_TX_DATA 0x11088
                MX6UL_PAD_JTAG_TCK__SAI2_RX_DATA    0x11088
                MX6UL_PAD_JTAG_TMS__SAI2_MCLK       0x17088
            >;
        };
     };
};

9.使能内核的 WM8960 驱动

 设备树配置完成以后就可以使能内核自带的 WM8960 驱动了,直接通过图形化界面配置即可。

10 查看在开发板中的 alsa 驱动框架设备文件

 controlC0:用于声卡控制, C0 表示声卡 0。
pcmC0D0c 和 pcmC0D1c: 用于录音的 pcm 设备,其中的“COD0”和“C0D1”分别表示
声卡 0 中的设备 0 和设备 1,最后面的“c”是 capture 的缩写,表示录音。
pcmC0D0p 和 pcmC0D1p:用于播放的 pcm 设备,其中的“COD0”和“C0D1”分别表示
声卡 0 中的设备 0 和设备 1,最后面的“p”是 playback 的缩写,表示放音。
timer: 定时器。
音频驱动使能以后还不能直接播放音乐或录音,我们还需要移植 alsa-lib 和 alsa-utils 这两个东西。


 

猜你喜欢

转载自blog.csdn.net/weixin_44981087/article/details/128511974