- 論壇徽章:
- 0
|
內(nèi)核Alsa之ASoC
http://www.alivepea.me/kernel/alsa-asoc/
ASoC是Alsa System on Chip的縮寫,用于實現(xiàn)那些集成了聲音控制器 的CPU,像移動設(shè)備中的arm/mips/atom等。它的設(shè)計目標如下:
解耦codec. codec的驅(qū)動不依賴具體的平臺。
簡單易用的I2S/PCM配置接口。讓soc和codec的配置相匹配。
動態(tài)的電源管理DAPM。實現(xiàn)對用戶空間透明的電源管理,各個widget按需供電,實現(xiàn)功耗最小化。
消除pop音。控制各個widget上下電的順序消除pop音。
添加平臺相關(guān)的控制。如earphone, speaker.
為實現(xiàn)這個目標,有了下面的ASoC架構(gòu)。
ASOC架構(gòu)
ASOC將soc_snd_card邏輯上分為codec/platform/machine三個組件。
Codec. 用于實現(xiàn)平臺無關(guān)的功能,如寄存器讀寫接口,音頻接口,各widgets的控制接口和DAPM的實現(xiàn)等。
Platform. 用于實現(xiàn)平臺相關(guān)的DMA驅(qū)動和音頻接口等。
Machine. 用于描述設(shè)備組件信息和特定的控制如耳機/外放等。
ASOC的架構(gòu)如下圖。
ASoC對于Alsa來說,就是分別注冊PCM/CONTROL類型的snd_device設(shè)備,并實現(xiàn)相應(yīng)的操 作方法集。圖中DAI是數(shù)字音頻接口,用于配置音頻數(shù)據(jù)格式等。
Codec驅(qū)動向ASoC注冊snd_soc_codec和snd_soc_dai設(shè)備。
Platform驅(qū)動向ASoC注冊snd_soc_platform和snd_soc_dai設(shè)備。
Machine驅(qū)動通過snd_soc_dai_link綁定codec/dai/platform.
Widget是各個組件內(nèi)部的小單元。處在活動通路上電,不在活動通路下電。ASoC的DAPM 正是通過控制這些Widget的上下電達到動態(tài)電源管理的效果。
path描述與其它widget的連接關(guān)系。
event用于通知該widget的上下電狀態(tài),power指示當前的上電狀態(tài)。
control實現(xiàn)空間用戶接口用于控制widget的音量/通路切換等。
對驅(qū)動開者來說,就可以很好的解耦了:
codec驅(qū)動的開發(fā)者,實現(xiàn)codec的IO讀寫方法,描述DAI支持的數(shù)據(jù)格式/操作方法和Widget的連接關(guān)系就可以了;
soc芯片的驅(qū)動開發(fā)者,Platform實現(xiàn)snd_pcm的操作方法集和DAI的配置如操作 DMA,I2S/AC97/PCM的設(shè)定等;
板級的開發(fā)者,描述Machine上codec與platform之間的總線連接, earphone/Speaker的布線情況就可以了。
數(shù)據(jù)結(jié)構(gòu)
曬一下snd_soc_card數(shù)據(jù)結(jié)構(gòu)的主要成員以一窺究竟吧。
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結(jié)構(gòu) */
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 全局功耗級別設(shè)定 */
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驅(qū)動描述的各組件綁定關(guān)系 */
int num_links;
struct snd_soc_pcm_runtime *rtd; /* card注冊后,dai_link對應(yīng)的各組件數(shù)據(jù)結(jié)構(gòu) */
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之間的連通關(guān)系 */
int num_dapm_routes;
bool fully_routed; /* 不存在沒法連通的widget */
/* lists of probed devices belonging to this card */
struct list_head codec_dev_list; /* card上的codec設(shè)備鏈接頭 */
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狀態(tài)的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直接上結(jié)構(gòu)體似乎沒有多少意義,以后用Entity Relationship畫圖表示各個 模塊的關(guān)系是不是好點呢?
調(diào)試
ASoC添加了DEBUGFS和FTRACE的調(diào)試支持。
在DEBUGFS下,可以查看一個各個組件及widgets的狀態(tài)。
在FTRACE下,echo asoc >> set_event打開調(diào)試,就可以查看widget的上下電順序, 通路的切換等。
看起來很貼心吶,是不是有點小激動啊☺
~EOF~
|
評分
-
查看全部評分
|