Yuhang Zheng

基于i.MX6X的音频驱动分析(一)ALSA and ASOC基本概念

N 人看过

ALSA是Advanced Linux Sound Architecture 的缩写,目前已经成为了linux的主流音频体系结构,它提供了linux操作系统的音频与MIDI功能 。

在内核设备驱动层,ALSA提供了alsa-driver,同时在应用层,ALSA为我们提供了alsa-lib,应用程序只要调用alsa-lib提供的API,即可以完成对底层音频硬件的控制。

alsa的软件体系结构

图1.1 alsa的软件体系结构

由图1.1可以看出,用户空间的alsa-lib对应用程序提供统一的API接口,这样可以隐藏了驱动层的实现细节,简化了应用程序的实现难度。内核空间中,alsa-soc其实是对alsa-driver的进一步封装,他针对嵌入式设备提供了一些列增强的功能。

ALSA包括以下一些典型特点:

  • 有效的支持各种音频接口,包括消费级的立体声声卡,以及专业的多声道声卡
  • 全部模块化的音频接口
  • 支持SMP及线程安全设计 
  • 使用用户空间的库(also-lib)来简化应用程序调用和提供更多高级功能
  • 支持旧有的Open Sound System(OSS)API。提供对OSS应用程序二进制级别兼容

ASoC的由来

ASoC–ALSA System on Chip ,是建立在标准ALSA驱动层上,为了更好地支持嵌入式处理器和移动设备中的音频Codec的一套软件体系。在ASoc出现之前,内核对于SoC中的音频已经有部分的支持,不过会有一些局限性:

  • Codec驱动与SoC CPU的底层耦合过于紧密,这种不理想会导致代码的重复,例如,仅是wm8731的驱动,当时Linux中有分别针对4个平台的驱动代码。
  • 音频事件没有标准的方法来通知用户,例如耳机、麦克风的插拔和检测,这些事件在移动设备中是非常普通的,而且通常都需要特定于机器的代码进行重新对音频路劲进行配置。
  • 当进行播放或录音时,驱动会让整个codec处于上电状态,这对于PC没问题,但对于移动设备来说,这意味着浪费大量的电量。同时也不支持通过改变过取样频率和偏置电流来达到省电的目的。

ASoC正是为了解决上述种种问题而提出的,目前已经被整合至内核的代码树中:sound/soc。ASoC不能单独存在,他只是建立在标准ALSA驱动上的一个它必须和标准的ALSA驱动框架相结合才能工作。ASOC的特点有:

  • 与具体的音频codec芯片独立,不同平台(CPU SOC芯片)的不同机器(板)可以重用相同的codec芯片驱动
  • 方便建立CPU SOC芯片与音频Codec芯片之间的I2S/PCM音频接口
  • Dynamic Audio Power Management (DAPM),动态音频电源管理,用于手持设备或复杂音频设备的电源管理,以降低音频设备功耗。
  • 减少Pop音和click音,通过正确的操作Codec音频芯片来完成(包括使用数字静音功能)
  • 基于机器定制的控制,允许机器对声卡进行控制,比如说音量控制或喇叭增益控制。

硬件架构

整个ALSA的详图如下:

其中ASOC可以被划分为板载硬件(Machine)、Soc(Platform)、Codec三大部分,如下图所示:

音频系统结构

  • Machine  是指某一款机器,可以是某款设备,某款开发板,又或者是某款智能手机,由此可以看出Machine几乎是不可重用的,每个Machine上的硬件实现可能都不一样,CPU不一样,Codec不一样,音频的输入、输出设备也不一样,Machine为CPU、Codec、输入输出设备提供了一个载体。主要用于控制与机器相关的设备,比如说在放音前操作一个外部功放。
  • Platform  一般是指某一个SoC平台,比如imx,pxaxxx,s3cxxxx,omapxxx等等,与音频相关的通常包含该SoC中的时钟、DMA、I2S、PCM等等,只要指定了SoC,那么我们可以认为它会有一个对应的Platform,它只与SoC相关,与Machine无关,这样我们就可以把Platform抽象出来,使得同一款SoC不用做任何的改动,就可以用在不同的Machine中。实际上,把Platform认为是某个SoC更好理解。
  • Codec  字面上的意思就是编解码器,Codec里面包含了I2S接口、D/A、A/D、Mixer、PA(功放),通常包含多种输入(Mic、Line-in、I2S、PCM)和多个输出(耳机、喇叭、听筒,Line-out),Codec和Platform一样,是可重用的部件,同一个Codec可以被不同的Machine使用。嵌入式Codec通常通过I2C对内部的寄存器进行控制。

软件架构

在软件层面,ASoC也把嵌入式设备的音频系统同样分为3大部分,Machine,Platform和Codec。

  • Codec**驱动**  ASoC中的一个重要设计原则就是要求Codec驱动是平台无关的,它包含了一些音频的控件(Controls),音频接口,DAMP(动态音频电源管理)的定义和某些Codec IO功能。为了保证硬件无关性,任何特定于平台和机器的代码都要移到Platform和Machine驱动中。所有的Codec驱动都要提供以下特性:

    • Codec DAI 和 PCM的配置信息;

    • Codec的IO控制方式(I2C,SPI等);

    • Mixer和其他的音频控件;

    • Codec的ALSA音频操作接口;

必要时,也可以提供以下功能:

  • DAPM描述信息;

    • DAPM事件处理程序;

    • DAC数字静音控制

  • Platform**驱动**  它包含了该SoC平台的音频DMA和音频接口的配置和控制(I2S,PCM,AC97等等);它也不能包含任何与板子或机器相关的代码。

  • Machine**驱动**  Machine驱动负责处理机器特有的一些控件和音频事件(例如,当播放音频时,需要先行打开一个放大器);单独的Platform和Codec驱动是不能工作的,它必须由Machine驱动把它们结合在一起才能完成整个设备的音频处理工作。

比如说i.MX6X SDP使用的WM8962立体声codec的驱动文件如下:

imx-pcm-dma-mx2.c文件是i.MX6X的平台文件,所有的音频codec都可以使用这个平台文件,它主要负责分配DMA缓冲与管理DMA缓冲。imx-ssi.c文件是i.MX6X的平台DAI连接文件,它主要用于注册音频设备的CPU DAI驱动,以及配置i.MX6X的SSI接口。

wm8962.c文件是音频codec层文件,它主要注册音频codec驱动和HiFi DAI驱动,它还包括了直接设置音频codec芯片硬件寄存器的代码,一般是通过I2C来操作。

imx-wm8962.c是机器层文件,主要用于创建驱动设备和声卡。

通过以上分析,我们可以了解到,imx-pcm-dma-mx2.c与imx-ssi.c文件是与平台相关的,所有在i.MX6X上通过SSI口连接的音频codec芯片都共用这些文件,所以再移植一下新codec时,一般不需要修改这些文件。这些文件也是由i.MX6X原厂提供的。

wm8962.c这种文件是音频codec的实际操作文件,是由音频codec芯片提供商提供的。如果查看文件夹\mx6x3.0.35_4.0.0\linux-3.0.35\sound\soc\codecs,就可以发现linux3.0.35已经预先提供了很多音频codec的文件,所以如果要移植一个新的音频codec,可以首先检查这个文件夹有没有相应的codec层文件,目前它包括了wolfson,TI,NXP SGTL500, Maxisam, AKM,ADI等多家厂商的驱动。

imx-wm8962.c是NXP的saber SDP板的机器层文件,如果移植一个新的音频codec,这个文件是主要要依靠自己实现的,因为这个是与机器相关的文件。如果查看文件夹\mx6x3.0.35_4.0.0\linux-3.0.35\sound\soc\imx,可能看到NXP提供了:

imx-cs42888.c: SaberAI 板所使用的多声道DSP Audio codec机器层.

imx-sgtl5000.c:Saber Lite板所使用的NXP的sgtl500的音频机器层。

imx-wm8958.c, imx-wm8962.c: SaberSDP板所使用过的wolfson codec的音频机器层

另外还有hdmi, spdif得i.MX6X内置的音频,NXP的OTT Box引入了imx-wm8524.c的音频机器层,这个codec是一个做从的,无i2c控制功能的单纯DAC,可以被参考使用于所有类似DAC音频codec芯片上。

所以理论上如果选择上述的音频codec芯片,则基本不需要开发新代码,主要是提供驱动资源数据和内核配置修改就可以了。如果使用了其它codec的芯片,可以参考这些机器层代码来实现。

数据结构

整个ASoC是由一些列数据结构组成,要搞清楚ASoC的工作机理,必须要理解这一系列数据结构之间的关系和作用,下面的关系图展示了ASoC中重要的数据结构之间的关联方式:

由上图我们可以看出,3.0中的数据结构更为合理和清晰,取消了snd_soc_device结构,直接用snd_soc_card取代了它,并且强化了snd_soc_pcm_runtime的作用,同时还增加了另外两个数据结构snd_soc_codec_driver和snd_soc_platform_driver,用于明确代表Codec驱动和Platform驱动。后续的章节中将会逐一介绍Machine和Platform以及Codec驱动的工作细节和关联。