最近使用tinymix 調試相應的音頻通道,但是一直不知道音頻通道的原理是什麼。所以百度了一下,百度結果是與DPAM有關。 一、DAPM簡介: DAPM是Dynamic Audio Power Management的縮寫,直譯過來就是動態音頻電源管理的意思,DAPM是為了使基於linux的移動設備上 ...
最近使用tinymix 調試相應的音頻通道,但是一直不知道音頻通道的原理是什麼。所以百度了一下,百度結果是與DPAM有關。
一、DAPM簡介:
DAPM是Dynamic Audio Power Management的縮寫,直譯過來就是動態音頻電源管理的意思,DAPM是為了使基於linux的移動設備上的音頻子系統,在任何時候都工作在最小功耗狀態下。DAPM對用戶空間的應用程式來說是透明的,所有與電源相關的開關都在ASoc core中完成。用戶空間的應用程式無需對代碼做出修改,也無需重新編譯,DAPM根據當前激活的音頻流(playback/capture)和音效卡中的mixer等的配置來決定那些音頻控制項的電源開關被打開或關閉。
DAPM是基於kcontrol改進過後的相應框架,增加了相應的電源管理機制,其電源管理機制其實就是按照相應的音頻路徑,完美的對各種部件的電源進行控制,而且按照某種順序進行。
kcontrol是什麼?
http://blog.csdn.net/droidphone/article/details/12793293
二、DAPM的基本單位widget:
widget把kcontrol和動態電源管理進行了有機的結合,同時還具備音頻路徑的連結功能,一個widget可以與它相鄰的widget有某種動態的連結關係。在DAPM框架中,widget用結構體snd_soc_dapm_widget來描述:
1 struct snd_soc_dapm_widget { 2 enum snd_soc_dapm_type id; //該widget的類型值,比如snd_soc_dapm_output,snd_soc_dapm_mixer等等。 3 const char *name; /* widget name */ 4 5 ...... 6 /* dapm control */ 7 int reg; /* negative reg = no direct dapm */ 8 unsigned char shift; /* bits to shift */ 9 unsigned int value; /* widget current value */ 10 unsigned int mask; /* non-shifted mask */ 11 ...... 12 13 int (*power_check)(struct snd_soc_dapm_widget *w); 14 15 int (*event)(struct snd_soc_dapm_widget*, struct snd_kcontrol *, int); 16 17 /* kcontrols that relate to this widget */ 18 int num_kcontrols; 19 const struct snd_kcontrol_new *kcontrol_news; 20 struct snd_kcontrol **kcontrols; 21 22 /* widget input and outputs */ 23 struct list_head sources; 24 struct list_head sinks; 25 ...... 26 };
2.1 widget的種類:
在DAPM框架中,把各種不同的widget劃分為不同的種類,snd_soc_dapm_widget結構中的id欄位用來表示該widget的種類,可選的種類都定義在一個枚舉中:
1 enum snd_soc_dapm_type {......}
下麵我們逐個解釋一下這些widget的種類:
1 snd_soc_dapm_input 該widget對應一個輸入引腳。 2 snd_soc_dapm_output 該widget對應一個輸出引腳。 3 snd_soc_dapm_mux 該widget對應一個mux控制項。 4 snd_soc_dapm_virt_mux 該widget對應一個虛擬的mux控制項。 5 snd_soc_dapm_value_mux 該widget對應一個value類型的mux控制項。 6 snd_soc_dapm_mixer 該widget對應一個mixer控制項。 7 snd_soc_dapm_mixer_named_ctl 該widget對應一個mixer控制項,但是對應的kcontrol的名字不會加入widget的名字作為首碼。 8 snd_soc_dapm_pga 該widget對應一個pga控制項(可編程增益控制項)。 9 snd_soc_dapm_out_drv 該widget對應一個輸出驅動控制項 10 snd_soc_dapm_adc 該widget對應一個ADC 11 snd_soc_dapm_dac 該widget對應一個DAC 12 snd_soc_dapm_micbias 該widget對應一個麥克風偏置電壓控制項 13 snd_soc_dapm_mic 該widget對應一個麥克風。 14 snd_soc_dapm_hp 該widget對應一個耳機。 15 snd_soc_dapm_spk 該widget對應一個揚聲器。 16 snd_soc_dapm_line 該widget對應一個線路輸入。 17 snd_soc_dapm_switch 該widget對應一個模擬開關。 18 snd_soc_dapm_vmid 該widget對應一個codec的vmid偏置電壓。 19 snd_soc_dapm_pre machine級別的專用widget,會先於其它widget執行檢查操作。 20 snd_soc_dapm_post machine級別的專用widget,會後於其它widget執行檢查操作。 21 snd_soc_dapm_supply 對應一個電源或是時鐘源。 22 snd_soc_dapm_regulator_supply 對應一個外部regulator穩壓器。 23 snd_soc_dapm_clock_supply 對應一個外部時鐘源。 24 snd_soc_dapm_aif_in 對應一個數字音頻輸入介面,比如I2S介面的輸入端。 25 snd_soc_dapm_aif_out 對應一個數字音頻輸出介面,比如I2S介面的輸出端。 26 snd_soc_dapm_siggen 對應一個信號發生器。 27 snd_soc_dapm_dai_in 對應一個platform或codec域的輸入DAI結構。 28 snd_soc_dapm_dai_out 對應一個platform或codec域的輸出DAI結構。 29 snd_soc_dapm_dai_link 用於鏈接一對輸入/輸出DAI結構。
2.2 widget之間的連接器path:
DAPM為我們提出了path這一概念,path相當於電路中的一根跳線,它把一個widget的輸出端和另一個widget的輸入端連接在一起,path用snd_soc_dapm_path結構來描述:
1 /* dapm audio path between two widgets */ 2 struct snd_soc_dapm_path { 3 const char *name; 4 const char *long_name; 5 6 /* source (input) and sink (output) widgets */ 7 struct snd_soc_dapm_widget *source; 8 struct snd_soc_dapm_widget *sink; 9 struct snd_kcontrol *kcontrol; 10 11 /* status */ 12 u32 connect:1; /* source and sink widgets are connected */ 13 u32 walked:1; /* path has been walked */ 14 u32 walking:1; /* path is in the process of being walked */ 15 u32 weak:1; /* path ignored for power management */ 16 17 int (*connected)(struct snd_soc_dapm_widget *source, 18 struct snd_soc_dapm_widget *sink); 19 20 struct list_head list_source; 21 struct list_head list_sink; 22 struct list_head list; 23 };
path與widget的關係如下圖:
2.3 widget的連接關係route:
1 struct snd_soc_dapm_route { 2 const char *sink; 3 const char *control; 4 const char *source; 5 int (*connected)(struct snd_soc_dapm_widget *source, 6 struct snd_soc_dapm_widget *sink); 7 };
sink指向到達端widget的名字字元串,source指向起始端widget的名字字元串,control指向負責控制該連接所對應的kcontrol名字字元串,connected回調則定義了上一節所提到的自定義連接檢查回調函數。該結構的意義很明顯就是:source通過一個kcontrol,和sink連接在一起,現在是否處於連接狀態,請調用connected回調函數檢查。
2.4 如何定義各種widget:
和普通的kcontrol一樣,DAPM框架為我們提供了大量的輔助巨集用來定義各種各樣的widget控制項,這些巨集定義根據widget的類型,按照它們的電源所在的域,被分為了幾個域,他們分別是:
- codec域 比如VREF和VMID等提供參考電壓的widget,這些widget通常在codec的probe/remove回調中進行控制,當然,在工作中如果沒有音頻流時,也可以適當地進行控制它們的開啟與關閉。
- platform域 位於該域上的widget通常是針對平臺或板子的一些需要物理連接的輸入/輸出介面,例如耳機、揚聲器、麥克風,因為這些介面在每塊板子上都可能不一樣,所以通常它們是在machine驅動中進行定義和控制,並且也可以由用戶空間的應用程式通過某種方式來控制它們的打開和關閉。
- 音頻路徑域 一般是指codec內部的mixer、mux等控制音頻路徑的widget,這些widget可以根據用戶空間的設定連接關係,自動設定他們的電源狀態。
- 音頻數據流域 是指那些需要處理音頻數據流的widget,例如ADC、DAC等等。
codec域widget的定義
目前,DAPM框架只提供了定義一個codec域widget的輔助巨集:
1 #define SND_SOC_DAPM_VMID(wname) \ 2 { .id = snd_soc_dapm_vmid, .name = wname, .kcontrol_news = NULL, \ 3 .num_kcontrols = 0}
platform域widget的定義
DAPM框架為我們提供了多種platform域widget的輔助定義巨集:
1 #define SND_SOC_DAPM_SIGGEN(wname) \ 2 { .id = snd_soc_dapm_siggen, .name = wname, .kcontrol_news = NULL, \ 3 .num_kcontrols = 0, .reg = SND_SOC_NOPM } 4 #define SND_SOC_DAPM_INPUT(wname) \ 5 { .id = snd_soc_dapm_input, .name = wname, .kcontrol_news = NULL, \ 6 .num_kcontrols = 0, .reg = SND_SOC_NOPM } 7 #define SND_SOC_DAPM_OUTPUT(wname) \ 8 { .id = snd_soc_dapm_output, .name = wname, .kcontrol_news = NULL, \ 9 .num_kcontrols = 0, .reg = SND_SOC_NOPM } 10 #define SND_SOC_DAPM_MIC(wname, wevent) \ 11 { .id = snd_soc_dapm_mic, .name = wname, .kcontrol_news = NULL, \ 12 .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ 13 .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD} 14 #define SND_SOC_DAPM_HP(wname, wevent) \ 15 { .id = snd_soc_dapm_hp, .name = wname, .kcontrol_news = NULL, \ 16 .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ 17 .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD} 18 #define SND_SOC_DAPM_SPK(wname, wevent) \ 19 { .id = snd_soc_dapm_spk, .name = wname, .kcontrol_news = NULL, \ 20 .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ 21 .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD} 22 #define SND_SOC_DAPM_LINE(wname, wevent) \ 23 { .id = snd_soc_dapm_line, .name = wname, .kcontrol_news = NULL, \ 24 .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ 25 .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
音頻路徑(path)域widget的定義
這種widget通常是對普通kcontrols控制項的再封裝,增加音頻路徑和電源管理功能,所以這種widget會包含一個或多個kcontrol。
1 #define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\ 2 wcontrols, wncontrols) \ 3 { .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \ 4 .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols} 5 #define SND_SOC_DAPM_OUT_DRV(wname, wreg, wshift, winvert,\ 6 wcontrols, wncontrols) \ 7 { .id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \ 8 .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols} 9 #define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \ 10 wcontrols, wncontrols)\ 11 { .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ 12 .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols} 13 #define SND_SOC_DAPM_MIXER_NAMED_CTL(wname, wreg, wshift, winvert, \ 14 wcontrols, wncontrols)\ 15 { .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \ 16 .shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \ 17 .num_kcontrols = wncontrols} 18 #define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \ 19 { .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \ 20 .invert = winvert, .kcontrol_news = NULL, .num_kcontrols = 0} 21 #define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \ 22 { .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \ 23 .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1} 24 #define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \ 25 { .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \ 26 .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1} 27 #define SND_SOC_DAPM_VIRT_MUX(wname, wreg, wshift, winvert, wcontrols) \ 28 { .id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \ 29 .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1} 30 #define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \ 31 { .id = snd_soc_dapm_value_mux, .name = wname, .reg = wreg, \ 32 .shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \ 33 .num_kcontrols = 1}
音頻數據流(stream)域widget的定義
這些widget主要包含音頻輸入/輸出介面,ADC/DAC等等:
1 #define SND_SOC_DAPM_AIF_IN(wname, stname, wslot, wreg, wshift, winvert) \ 2 { .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \ 3 .reg = wreg, .shift = wshift, .invert = winvert } 4 #define SND_SOC_DAPM_AIF_IN_E(wname, stname, wslot, wreg, wshift, winvert, \ 5 wevent, wflags) \ 6 { .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \ 7 .reg = wreg, .shift = wshift, .invert = winvert, \ 8 .event = wevent, .event_flags = wflags } 9 #define SND_SOC_DAPM_AIF_OUT(wname, stname, wslot, wreg, wshift, winvert) \ 10 { .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \ 11 .reg = wreg, .shift = wshift, .invert = winvert } 12 #define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wslot, wreg, wshift, winvert, \ 13 wevent, wflags) \ 14 { .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \ 15 .reg = wreg, .shift = wshift, .invert = winvert, \ 16 .event = wevent, .event_flags = wflags } 17 #define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \ 18 { .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \ 19 .shift = wshift, .invert = winvert} 20 #define SND_SOC_DAPM_DAC_E(wname, stname, wreg, wshift, winvert, \ 21 wevent, wflags) \ 22 { .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \ 23 .shift = wshift, .invert = winvert, \ 24 .event = wevent, .event_flags = wflags} 25 #define SND_SOC_DAPM_ADC(wname, stname, wreg, wshift, winvert) \ 26 { .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \ 27 .shift = wshift, .invert = winvert} 28 #define SND_SOC_DAPM_ADC_E(wname, stname, wreg, wshift, winvert, \ 29 wevent, wflags) \ 30 { .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \ 31 .shift = wshift, .invert = winvert, \ 32 .event = wevent, .event_flags = wflags} 33 #define SND_SOC_DAPM_CLOCK_SUPPLY(wname) \ 34 { .id = snd_soc_dapm_clock_supply, .name = wname, \ 35 .reg = SND_SOC_NOPM, .event = dapm_clock_event, \ 36 .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD }
2.5 dapm kcontrol:
dapm kcontrol是widget的開關,info函數是顯示widget的函數,put是設置,get是獲取;
三、建立widget和route:
以我們打開音頻tinymix ‘PRI_MI2S_RX Audio Mixer MultiMedia1’ 1 為例子來瞭解整個過程:
3.1 利用輔助巨集定義widget所需要的dapm kcontrol:
1 static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = { 2 SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_MI2S_RX , 3 MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, 4 msm_routing_put_audio_mixer), 5 SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_PRI_MI2S_RX, 6 MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, 7 msm_routing_put_audio_mixer), 8 SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_PRI_MI2S_RX, 9 MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, 10 msm_routing_put_audio_mixer), 11 SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_PRI_MI2S_RX, 12 MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, 13 msm_routing_put_audio_mixer), 14 SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_MI2S_RX, 15 MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, 16 msm_routing_put_audio_mixer), 17 SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_PRI_MI2S_RX, 18 MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, 19 msm_routing_put_audio_mixer), 20 SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_PRI_MI2S_RX, 21 MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, 22 msm_routing_put_audio_mixer), 23 SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_PRI_MI2S_RX, 24 MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, 25 msm_routing_put_audio_mixer), 26 SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_PRI_MI2S_RX, 27 MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, 28 msm_routing_put_audio_mixer), 29 };
1 static const struct snd_kcontrol_new primary_mi2s_rx_port_mixer_controls[] = { 2 SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_RX, 3 MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, 4 msm_routing_put_port_mixer), 5 SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_RX, 6 MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, 7 msm_routing_put_port_mixer), 8 SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_PRI_MI2S_RX, 9 MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, 10 msm_routing_put_port_mixer), 11 SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_RX, 12 MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, 13 msm_routing_put_port_mixer), 14 SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_PRI_MI2S_RX, 15 MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer, 16 msm_routing_put_port_mixer), 17 };
以上我們定義了prior通道的控制項和MultiMedia1數據流通道;
3.2 定義真正的widget,包含第一步定義好的dapm控制項:
1 static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { 2 /* Frontend AIF */ 3 /* Widget name equals to Front-End DAI name<Need confirmation>, 4 * Stream name must contains substring of front-end dai name 5 */ 6 SND_SOC_DAPM_AIF_IN("MM_DL1", "MultiMedia1 Playback", 0, 0, 0, 0), 7 SND_SOC_DAPM_AIF_IN("MM_DL2", "MultiMedia2 Playback", 0, 0, 0, 0), 8 SND_SOC_DAPM_AIF_IN("MM_DL3", "MultiMedia3 Playback", 0, 0, 0, 0), 9 SND_SOC_DAPM_AIF_IN("MM_DL4", "MultiMedia4 Playback", 0, 0, 0, 0), 10 SND_SOC_DAPM_AIF_IN("MM_DL5", "MultiMedia5 Playback", 0, 0, 0, 0), 11 SND_SOC_DAPM_AIF_IN("MM_DL6", "MultiMedia6 Playback", 0, 0, 0, 0), 12 SND_SOC_DAPM_AIF_IN("MM_DL7", "MultiMedia7 Playback", 0, 0, 0, 0), 13 SND_SOC_DAPM_AIF_IN("MM_DL8", "MultiMedia8 Playback", 0, 0, 0, 0), 14 SND_SOC_DAPM_AIF_IN("MM_DL9", "MultiMedia9 Playback", 0, 0, 0, 0), 15 SND_SOC_DAPM_AIF_IN("VOIP_DL", "VoIP Playback", 0, 0, 0, 0), 16 SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0), 17 SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0), 18 SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0), 19 SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0), 20 SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0), 21 SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, 0, 0, 0), 22 SND_SOC_DAPM_AIF_OUT("MM_UL9", "MultiMedia9 Capture", 0, 0, 0, 0), 23 SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0), 24 SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0), 25 SND_SOC_DAPM_AIF_IN("VOICE2_DL", "Voice2 Playback", 0, 0, 0, 0), 26 SND_SOC_DAPM_AIF_OUT("VOICE2_UL", "Voice2 Capture", 0, 0, 0, 0), 27 SND_SOC_DAPM_AIF_IN("VoLTE_DL", "VoLTE Playback", 0, 0, 0, 0), 28 SND_SOC_DAPM_AIF_OUT("VoLTE_UL", "VoLTE Capture", 0, 0, 0, 0), 29 SND_SOC_DAPM_AIF_IN("VoWLAN_DL", "VoWLAN Playback", 0, 0, 0, 0), 30 SND_SOC_DAPM_AIF_OUT("VoWLAN_UL", "VoWLAN Capture", 0, 0, 0, 0), 31 SND_SOC_DAPM_AIF_OUT("VOIP_UL", "VoIP Capture", 0, 0, 0, 0), 32 SND_SOC_DAPM_AIF_IN("SLIM0_DL_HL", "SLIMBUS0_HOSTLESS Playback", 33 0, 0, 0, 0), 34 SND_SOC_DAPM_AIF_OUT("SLIM0_UL_HL", "SLIMBUS0_HOSTLESS Capture", 35 0, 0, 0, 0), 36 SND_SOC_DAPM_AIF_IN("SLIM1_DL_HL", "SLIMBUS1_HOSTLESS Playback", 37 0, 0, 0, 0), 38 SND_SOC_DAPM_AIF_OUT("SLIM1_UL_HL", "SLIMBUS1_HOSTLESS Capture", 39 0, 0, 0, 0), 40 SND_SOC_DAPM_AIF_IN("SLIM3_DL_HL", "SLIMBUS3_HOSTLESS Playback", 41 0, 0, 0, 0), 42 SND_SOC_DAPM_AIF_OUT("SLIM3_UL_HL", "SLIMBUS3_HOSTLESS Capture", 43 0, 0, 0, 0), 44 SND_SOC_DAPM_AIF_IN("SLIM4_DL_HL", "SLIMBUS4_HOSTLESS Playback", 45 0, 0, 0, 0), 46 SND_SOC_DAPM_AIF_OUT("SLIM4_UL_HL", "SLIMBUS4_HOSTLESS Capture", 47 0, 0, 0, 0), 48 SND_SOC_DAPM_AIF_IN("INTFM_DL_HL", "INT_FM_HOSTLESS Playback", 49 0, 0, 0, 0), 50 SND_SOC_DAPM_AIF_OUT("INTFM_UL_HL", "INT_FM_HOSTLESS Capture", 51 0, 0, 0, 0), 52 SND_SOC_DAPM_AIF_IN("INTHFP_DL_HL", "INT_HFP_BT_HOSTLESS Playback", 53 0, 0, 0, 0), 54 SND_SOC_DAPM_AIF_OUT("INTHFP_UL_HL", "INT_HFP_BT_HOSTLESS Capture", 55 0, 0, 0, 0), 56 SND_SOC_DAPM_AIF_IN("HDMI_DL_HL", "