内核Alsa之ASoC

9 篇文章 0 订阅

 

ASoCAlsa System on Chip的缩写,用于实现那些集成了声音控制器 的CPU,像移动设备中的arm/mips/atom等。它的设计目标如下:

  1. 解耦codec. codec的驱动不依赖具体的平台。
  2. 简单易用的I2S/PCM配置接口。让soc和codec的配置相匹配。
  3. 动态的电源管理DAPM。实现对用户空间透明的电源管理,各个widget按需供电,实现功耗最小化。
  4. 消除pop音。控制各个widget上下电的顺序消除pop音。
  5. 添加平台相关的控制。如earphone, speaker.

为实现这个目标,有了下面的ASoC架构。

ASOC架构

ASOC将soc_snd_card逻辑上分为codec/platform/machine三个组件。

  1. Codec. 用于实现平台无关的功能,如寄存器读写接口,音频接口,各widgets的控制接口和DAPM的实现等。
  2. Platform. 用于实现平台相关的DMA驱动和音频接口等。
  3. Machine. 用于描述设备组件信息和特定的控制如耳机/外放等。

ASOC的架构如下图。

asoc_arch

ASoC对于Alsa来说,就是分别注册PCM/CONTROL类型的snd_device设备,并实现相应的操 作方法集。图中DAI是数字音频接口,用于配置音频数据格式等。

  • Codec驱动向ASoC注册snd_soc_codecsnd_soc_dai设备。
  • Platform驱动向ASoC注册snd_soc_platformsnd_soc_dai设备。
  • Machine驱动通过snd_soc_dai_link绑定codec/dai/platform.

Widget是各个组件内部的小单元。处在活动通路上电,不在活动通路下电。ASoC的DAPM正是通过控制这些Widget的上下电达到动态电源管理的效果。

  • path描述与其它widget的连接关系。
  • event用于通知该widget的上下电状态。
  • power指示当前的上电状态。
  • control实现空间用户接口用于控制widget的音量/通路切换等。

对驱动开者来说,就可以很好的解耦了:

  • codec驱动的开发者,实现codec的IO读写方法,描述DAI支持的数据格式/操作方法和Widget的连接关系就可以了;
  • soc芯片的驱动开发者,Platform实现snd_pcm的操作方法集和DAI的配置如操作 DMA,I2S/AC97/PCM的设定等;
  • 板级的开发者,描述Machine上codec与platform之间的总线连接, earphone/Speaker的布线情况就可以了。

数据结构

晒一下snd_soc_card数据结构的主要成员以一窥究竟吧。

struct snd_soc_card {
	const char *name; /* 传递给snd_card字段 */
	const char *long_name;
	const char *driver_name;
	struct device *dev; /* */
	struct snd_card *snd_card; /* 指向alsa注册的snd_card结构 */

	int (*probe)(struct snd_soc_card *card); /* 用于添加板级的widget如earphone等 */
	int (*late_probe)(struct snd_soc_card *card);
	int (*remove)(struct snd_soc_card *card);

	/* callbacks */ 
	int (*set_bias_level)(struct snd_soc_card *, /* DAPM 全局功耗级别设定 */
			      struct snd_soc_dapm_context *dapm,
			      enum snd_soc_bias_level level);
	int (*set_bias_level_post)(struct snd_soc_card *,
				   struct snd_soc_dapm_context *dapm,
				   enum snd_soc_bias_level level);

	/* CPU <--> Codec DAI links  */
	struct snd_soc_dai_link *dai_link; /* Machine驱动描述的各组件绑定关系 */
	int num_links;
	struct snd_soc_pcm_runtime *rtd; /* card注册后,dai_link对应的各组件数据结构 */
	int num_rtd;

	const struct snd_kcontrol_new *controls; /* Machine描述的特定control */
	int num_controls;

	/*
	 * Card-specific routes and widgets.
	 */
	const struct snd_soc_dapm_widget *dapm_widgets; /* Machine描述的特定的widget  */
	int num_dapm_widgets;
	const struct snd_soc_dapm_route *dapm_routes; /* Machine描述的widgets之间的连通关系 */
	int num_dapm_routes;
	bool fully_routed; /* 不存在没法连通的widget */

	/* lists of probed devices belonging to this card */
	struct list_head codec_dev_list; /* card上的codec设备链接头 */
	struct list_head platform_dev_list; /* card上platform链接头 */
	struct list_head dai_dev_list; /* card上dai链接头 */

	struct list_head widgets; /* 所有组件上widgets的链接头 */
	struct list_head paths; /* 所有widgets之间path的链接头 */
	struct list_head dapm_list; /* 各个组件dapm的链接头 */
	struct list_head dapm_dirty; /* 需要更新power状态的widgets链接头 */

	/* Generic DAPM context for the card */
	struct snd_soc_dapm_context dapm;
	struct snd_soc_dapm_stats dapm_stats;
	struct snd_soc_dapm_update *update; /* 对widget除上电之外的操作,如通道切换等。 */

	u32 pop_time; /* 在widget上下电时防pop音 */
};

没有code直接上结构体似乎没有多少意义,以后用Entity Relationship画图表示各个 模块的关系是不是好点呢?

调试

ASoC添加了DEBUGFS和FTRACE的调试支持。

  • 在DEBUGFS下,可以查看一个各个组件及widgets的状态。
  • 在FTRACE下,echo asoc >> set_event打开调试,就可以查看widget的上下电顺序, 通路的切换等。

看起来很贴心呐,是不是有点小激动啊☺

~EOF~

 

http://www.alivepea.me/kernel/alsa-asoc/

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值