@@ -844,6 +844,26 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
844
844
return 0 ;
845
845
}
846
846
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
+
847
867
static const char * input_mode_text [] = {
848
868
"Single-Ended" , "Differential Line" , "Differential Mic"
849
869
};
@@ -963,6 +983,15 @@ SND_SOC_DAPM_AIF_OUT("AIFOUTL", "Capture", 0, SND_SOC_NOPM, 0, 0),
963
983
SND_SOC_DAPM_AIF_OUT ("AIFOUTR" , "Capture" , 1 , SND_SOC_NOPM , 0 , 0 ),
964
984
};
965
985
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
+
966
995
static const struct snd_soc_dapm_widget wm8904_dac_dapm_widgets [] = {
967
996
SND_SOC_DAPM_AIF_IN ("AIFINL" , "Playback" , 0 , SND_SOC_NOPM , 0 , 0 ),
968
997
SND_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[] = {
1101
1130
{ "AIFOUTR" , NULL , "AIFOUTR Mux" },
1102
1131
1103
1132
{ "ADCL" , NULL , "CLK_DSP" },
1104
- { "ADCL" , NULL , "Left Capture PGA" },
1105
-
1106
1133
{ "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" },
1107
1139
{ "ADCR" , NULL , "Right Capture PGA" },
1108
1140
};
1109
1141
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
+
1110
1172
static const struct snd_soc_dapm_route dac_intercon [] = {
1111
1173
{ "DACL Mux" , "Left" , "AIFINL" },
1112
1174
{ "DACL Mux" , "Right" , "AIFINR" },
@@ -2050,18 +2112,70 @@ static void wm8904_handle_retune_mobile_pdata(struct snd_soc_component *componen
2050
2112
"Failed to add ReTune Mobile control: %d\n" , ret );
2051
2113
}
2052
2114
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
+
2053
2162
static void wm8904_handle_pdata (struct snd_soc_component * component )
2054
2163
{
2164
+ struct snd_soc_dapm_context * dapm = snd_soc_component_get_dapm (component );
2055
2165
struct wm8904_priv * wm8904 = snd_soc_component_get_drvdata (component );
2056
2166
struct wm8904_pdata * pdata = wm8904 -> pdata ;
2057
2167
int ret , i ;
2058
2168
2059
2169
if (!pdata ) {
2170
+ snd_soc_dapm_add_routes (dapm , cin_nodmic_con ,
2171
+ ARRAY_SIZE (cin_nodmic_con ));
2060
2172
snd_soc_add_component_controls (component , wm8904_eq_controls ,
2061
- ARRAY_SIZE (wm8904_eq_controls ));
2173
+ ARRAY_SIZE (wm8904_eq_controls ));
2062
2174
return ;
2063
2175
}
2064
2176
2177
+ wm8904_handle_dmic_pdata (component );
2178
+
2065
2179
dev_dbg (component -> dev , "%d DRC configurations\n" , pdata -> num_drc_cfgs );
2066
2180
2067
2181
if (pdata -> num_drc_cfgs ) {
@@ -2117,10 +2231,11 @@ static int wm8904_probe(struct snd_soc_component *component)
2117
2231
return - EINVAL ;
2118
2232
}
2119
2233
2120
- wm8904_handle_pdata (component );
2121
-
2122
2234
wm8904_add_widgets (component );
2123
2235
2236
+ /* This can add dependent widgets, so it is done after add_widgets */
2237
+ wm8904_handle_pdata (component );
2238
+
2124
2239
return 0 ;
2125
2240
}
2126
2241
0 commit comments