- 瞭解ASoC
1.概述
ASoC是Alsa System on Chip的縮寫,用於實現那些集成了聲音控制器 的CPU,像移動設備中的arm/mips/atom等。它的設計目標如下:
- 解耦codec. codec的驅動不依賴具體的平臺。
- 簡單易用的I2S/PCM配置接口。讓soc和codec的配置相匹配。
- 動態的電源管理DAPM。實現對用戶空間透明的電源管理,各個widget按需供電,實現功耗最小化。
- 消除pop音。控制各個widget上下電的順序消除pop音。
- 添加平臺相關的控制。如earphone, speaker。
2.ASOC架構
ASOC將soc_snd_card邏輯上分爲codec/platform/machine三個組件。
- Codec :用於實現平臺無關的功能,如寄存器讀寫接口,音頻接口,各widgets的控制接口和DAPM的實現等。
- Platform: 用於實現平臺相關的DMA驅動和音頻接口等。
- Machine. 用於描述設備組件信息和特定的控制如耳機/外放等。
ASOC的架構如下圖:
ASoC對於Alsa來說,就是分別註冊PCM/CONTROL類型的snd_device設備,並實現相應的操作方法集。圖中DAI是數字音頻接口,用於配置音頻數據格式等。
- Codec驅動向ASoC註冊snd_soc_codec和snd_soc_dai設備。
- Platform驅動向ASoC註冊snd_soc_platform和snd_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的佈線情況就可以了。
2.1.struct snd_soc_card
struct snd_soc_card {
const char *name;
const char *long_name;
const char *driver_name;
struct device *dev;
struct snd_card *snd_card;--------------------card結構體,最終是要註冊card
struct module *owner;
struct list_head list;
struct mutex mutex;
struct mutex dapm_mutex;
bool instantiated;
int (*probe)(struct snd_soc_card *card);
int (*late_probe)(struct snd_soc_card *card);
int (*remove)(struct snd_soc_card *card);
/* the pre and post PM functions are used to do any PM work before and
* after the codec and DAI's do any PM work. */
int (*suspend_pre)(struct snd_soc_card *card);
int (*suspend_post)(struct snd_soc_card *card);
int (*resume_pre)(struct snd_soc_card *card);
int (*resume_post)(struct snd_soc_card *card);
/* callbacks */
int (*set_bias_level)(struct snd_soc_card *,
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);
long pmdown_time;
/* CPU <--> Codec DAI links */----------------附屬部件鏈接表
struct snd_soc_dai_link *dai_link;
int num_links;
struct snd_soc_pcm_runtime *rtd;
int num_rtd;
/* optional codec specific configuration */
struct snd_soc_codec_conf *codec_conf;
int num_configs;
/*
* optional auxiliary devices such as amplifiers or codecs with DAI
* link unused
*/
struct snd_soc_aux_dev *aux_dev;
int num_aux_devs;
struct snd_soc_pcm_runtime *rtd_aux;
int num_aux_rtd;
const struct snd_kcontrol_new *controls;
int num_controls;
/*
* Card-specific routes and widgets.----------------------DAPM內容
*/
const struct snd_soc_dapm_widget *dapm_widgets;
int num_dapm_widgets;
const struct snd_soc_dapm_route *dapm_routes;
int num_dapm_routes;
bool fully_routed;
struct work_struct deferred_resume_work;
/* lists of probed devices belonging to this card */--------附屬部件鏈表
struct list_head codec_dev_list;
struct list_head platform_dev_list;
struct list_head dai_dev_list;
struct list_head widgets;
struct list_head paths;
struct list_head dapm_list;
struct list_head dapm_dirty;
/* Generic DAPM context for the card */---------------DAPM內容
struct snd_soc_dapm_context dapm;
struct snd_soc_dapm_stats dapm_stats;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_card_root;
struct dentry *debugfs_pop_time;
#endif
u32 pop_time;
void *drvdata;
};
2.2.card註冊
聲卡註冊函數:
int snd_soc_register_card(struct snd_soc_card *card);
註冊流程如下:
- A:綁定系統中相關的platform/cedec
- B:聲卡對象的創建
- C:聲卡註冊
- control:這是control相關的一些初始化函數