@@ -844,6 +844,26 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
844844 return 0 ;
845845}
846846
847+ static const char * const dmic_text [] = {
848+ "DMIC1" , "DMIC2"
849+ };
850+
851+ static SOC_ENUM_SINGLE_DECL (dmic_enum , WM8904_DIGITAL_MICROPHONE_0 ,
852+ WM8904_DMIC_SRC_SHIFT , dmic_text ) ;
853+
854+ static const struct snd_kcontrol_new dmic_mux =
855+ SOC_DAPM_ENUM ("DMIC Mux" , dmic_enum );
856+
857+ static const char * const cin_text [] = {
858+ "ADC" , "DMIC"
859+ };
860+
861+ static SOC_ENUM_SINGLE_DECL (cin_enum , WM8904_DIGITAL_MICROPHONE_0 ,
862+ WM8904_DMIC_ENA_SHIFT , cin_text ) ;
863+
864+ static const struct snd_kcontrol_new cin_mux =
865+ SOC_DAPM_ENUM ("Capture Input" , cin_enum );
866+
847867static const char * input_mode_text [] = {
848868 "Single-Ended" , "Differential Line" , "Differential Mic"
849869};
@@ -963,6 +983,15 @@ SND_SOC_DAPM_AIF_OUT("AIFOUTL", "Capture", 0, SND_SOC_NOPM, 0, 0),
963983SND_SOC_DAPM_AIF_OUT ("AIFOUTR" , "Capture" , 1 , SND_SOC_NOPM , 0 , 0 ),
964984};
965985
986+ static const struct snd_soc_dapm_widget wm8904_dmic_dapm_widgets [] = {
987+ SND_SOC_DAPM_MUX ("DMIC Mux" , SND_SOC_NOPM , 0 , 0 , & dmic_mux ),
988+ };
989+
990+ static const struct snd_soc_dapm_widget wm8904_cin_dapm_widgets [] = {
991+ SND_SOC_DAPM_MUX ("Left Capture Input" , SND_SOC_NOPM , 0 , 0 , & cin_mux ),
992+ SND_SOC_DAPM_MUX ("Right Capture Input" , SND_SOC_NOPM , 0 , 0 , & cin_mux ),
993+ };
994+
966995static const struct snd_soc_dapm_widget wm8904_dac_dapm_widgets [] = {
967996SND_SOC_DAPM_AIF_IN ("AIFINL" , "Playback" , 0 , SND_SOC_NOPM , 0 , 0 ),
968997SND_SOC_DAPM_AIF_IN ("AIFINR" , "Playback" , 1 , SND_SOC_NOPM , 0 , 0 ),
@@ -1101,12 +1130,45 @@ static const struct snd_soc_dapm_route adc_intercon[] = {
11011130 { "AIFOUTR" , NULL , "AIFOUTR Mux" },
11021131
11031132 { "ADCL" , NULL , "CLK_DSP" },
1104- { "ADCL" , NULL , "Left Capture PGA" },
1105-
11061133 { "ADCR" , NULL , "CLK_DSP" },
1134+ };
1135+
1136+ /* No DMICs, always connect PGAs */
1137+ static const struct snd_soc_dapm_route cin_nodmic_con [] = {
1138+ { "ADCL" , NULL , "Left Capture PGA" },
11071139 { "ADCR" , NULL , "Right Capture PGA" },
11081140};
11091141
1142+ /* DMIC system in use: mux between ADC and DMICDAT1, 2 or both */
1143+ static const struct snd_soc_dapm_route cin_adc_dmic_con [] = {
1144+ { "Left Capture Input" , "ADC" , "Left Capture PGA" },
1145+ { "Right Capture Input" , "ADC" , "Right Capture PGA" },
1146+
1147+ { "ADCL" , NULL , "Left Capture Input" },
1148+ { "ADCR" , NULL , "Right Capture Input" },
1149+ };
1150+
1151+ /* IN1L as DMICDAT1 */
1152+ static const struct snd_soc_dapm_route cin_dmic1_con [] = {
1153+ { "Left Capture Input" , "DMIC" , "IN1L" },
1154+ { "Right Capture Input" , "DMIC" , "IN1L" },
1155+ };
1156+
1157+ /* IN1R as DMICDAT2 */
1158+ static const struct snd_soc_dapm_route cin_dmic2_con [] = {
1159+ { "Left Capture Input" , "DMIC" , "IN1R" },
1160+ { "Right Capture Input" , "DMIC" , "IN1R" },
1161+ };
1162+
1163+ /* DMICDAT1 and DMICDAT2: mux between them, ADC still used for IN2 and IN3 */
1164+ static const struct snd_soc_dapm_route cin_2dmics_con [] = {
1165+ { "DMIC Mux" , "DMIC1" , "IN1L" },
1166+ { "DMIC Mux" , "DMIC2" , "IN1R" },
1167+
1168+ { "Left Capture Input" , "DMIC" , "DMIC Mux" },
1169+ { "Right Capture Input" , "DMIC" , "DMIC Mux" },
1170+ };
1171+
11101172static const struct snd_soc_dapm_route dac_intercon [] = {
11111173 { "DACL Mux" , "Left" , "AIFINL" },
11121174 { "DACL Mux" , "Right" , "AIFINR" },
@@ -2050,18 +2112,70 @@ static void wm8904_handle_retune_mobile_pdata(struct snd_soc_component *componen
20502112 "Failed to add ReTune Mobile control: %d\n" , ret );
20512113}
20522114
2115+ static void wm8904_handle_dmic_pdata (struct snd_soc_component * component )
2116+ {
2117+ struct snd_soc_dapm_context * dapm = snd_soc_component_get_dapm (component );
2118+ struct wm8904_priv * wm8904 = snd_soc_component_get_drvdata (component );
2119+ struct wm8904_pdata * pdata = wm8904 -> pdata ;
2120+ unsigned int dmic_src ;
2121+
2122+ if (!pdata -> in1l_as_dmicdat1 && !pdata -> in1r_as_dmicdat2 ) {
2123+ snd_soc_dapm_add_routes (dapm , cin_nodmic_con ,
2124+ ARRAY_SIZE (cin_nodmic_con ));
2125+ snd_soc_component_update_bits (component , WM8904_DIGITAL_MICROPHONE_0 ,
2126+ WM8904_DMIC_ENA_MASK , 0 );
2127+ return ;
2128+ }
2129+
2130+ /* Need a control and routing to switch between DMIC and ADC */
2131+ snd_soc_dapm_new_controls (dapm , wm8904_cin_dapm_widgets ,
2132+ ARRAY_SIZE (wm8904_cin_dapm_widgets ));
2133+ snd_soc_dapm_add_routes (dapm , cin_adc_dmic_con ,
2134+ ARRAY_SIZE (cin_adc_dmic_con ));
2135+
2136+ if (pdata -> in1l_as_dmicdat1 && pdata -> in1r_as_dmicdat2 ) {
2137+ /* Need a control and routing to mux between DMICDAT1 and 2 */
2138+ dev_dbg (component -> dev , "DMICDAT1 and DMICDAT2 in use\n" );
2139+ snd_soc_dapm_new_controls (dapm , wm8904_dmic_dapm_widgets ,
2140+ ARRAY_SIZE (wm8904_dmic_dapm_widgets ));
2141+ snd_soc_dapm_add_routes (dapm , cin_2dmics_con ,
2142+ ARRAY_SIZE (cin_2dmics_con ));
2143+ return ;
2144+ }
2145+
2146+ /* Either DMICDAT1 or DMICDAT2 is in use, not both */
2147+ if (pdata -> in1l_as_dmicdat1 ) {
2148+ dmic_src = 0 ;
2149+ snd_soc_dapm_add_routes (dapm , cin_dmic1_con ,
2150+ ARRAY_SIZE (cin_dmic1_con ));
2151+ } else {
2152+ dmic_src = 1 ;
2153+ snd_soc_dapm_add_routes (dapm , cin_dmic2_con ,
2154+ ARRAY_SIZE (cin_dmic2_con ));
2155+ }
2156+ dev_dbg (component -> dev , "DMIC_SRC (0 or 1): %d\n" , dmic_src );
2157+ snd_soc_component_update_bits (component , WM8904_DIGITAL_MICROPHONE_0 ,
2158+ WM8904_DMIC_SRC_MASK ,
2159+ dmic_src << WM8904_DMIC_SRC_SHIFT );
2160+ }
2161+
20532162static void wm8904_handle_pdata (struct snd_soc_component * component )
20542163{
2164+ struct snd_soc_dapm_context * dapm = snd_soc_component_get_dapm (component );
20552165 struct wm8904_priv * wm8904 = snd_soc_component_get_drvdata (component );
20562166 struct wm8904_pdata * pdata = wm8904 -> pdata ;
20572167 int ret , i ;
20582168
20592169 if (!pdata ) {
2170+ snd_soc_dapm_add_routes (dapm , cin_nodmic_con ,
2171+ ARRAY_SIZE (cin_nodmic_con ));
20602172 snd_soc_add_component_controls (component , wm8904_eq_controls ,
2061- ARRAY_SIZE (wm8904_eq_controls ));
2173+ ARRAY_SIZE (wm8904_eq_controls ));
20622174 return ;
20632175 }
20642176
2177+ wm8904_handle_dmic_pdata (component );
2178+
20652179 dev_dbg (component -> dev , "%d DRC configurations\n" , pdata -> num_drc_cfgs );
20662180
20672181 if (pdata -> num_drc_cfgs ) {
@@ -2117,10 +2231,11 @@ static int wm8904_probe(struct snd_soc_component *component)
21172231 return - EINVAL ;
21182232 }
21192233
2120- wm8904_handle_pdata (component );
2121-
21222234 wm8904_add_widgets (component );
21232235
2236+ /* This can add dependent widgets, so it is done after add_widgets */
2237+ wm8904_handle_pdata (component );
2238+
21242239 return 0 ;
21252240}
21262241
0 commit comments