Having two DMICs, a front DMIC and a rear DMIC, but only host audio input AUX port0 is used for these two Dmics. A "dmic_sel-gpios" property is used for a mixer control to switch the dmic signal source between the Front and Rear Dmic.
usage: amixer -c0 cset name='Dmic Mux' 'FrontMic' usage: amixer -c0 cset name='Dmic Mux' 'RearMic'
Refer to this one as an example, commit 3cfbf07c6d27 ("ASoC: qcom: sc7180: Modify machine driver for 2mic")
Signed-off-by: Ajye Huang ajye_huang@compal.corp-partner.google.com --- sound/soc/codecs/dmic.c | 52 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+)
diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c index 4fd6f97e5a49..5c56fbcdb3e6 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c @@ -28,8 +28,50 @@ struct dmic { int wakeup_delay; /* Delay after DMIC mode switch */ int modeswitch_delay; + struct gpio_desc *dmic_sel; + int dmic_switch; };
+static int dmic_sel_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); + struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); + struct dmic *dmic = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = dmic->dmic_switch; + return 0; +} + +static int dmic_sel_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); + struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); + struct dmic *dmic = snd_soc_component_get_drvdata(component); + + dmic->dmic_switch = ucontrol->value.integer.value[0]; + if (dmic->dmic_sel) { + gpiod_set_value(dmic->dmic_sel, dmic->dmic_switch); + dev_info(dapm->dev, "%s value %d\n", __func__, dmic->dmic_switch); + } else + dev_info(dapm->dev, "%s without dmic_sel-gpios\n", __func__); + + return 0; +} + +static const char * const dmic_mux_text[] = { + "FrontMic", + "RearMic", +}; + +static SOC_ENUM_SINGLE_DECL(dmic_enum, + SND_SOC_NOPM, 0, dmic_mux_text); + +static const struct snd_kcontrol_new dmic_mux_control = + SOC_DAPM_ENUM_EXT("DMIC Select Mux", dmic_enum, + dmic_sel_get, dmic_sel_set); + static int dmic_daiops_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { @@ -115,6 +157,11 @@ static int dmic_component_probe(struct snd_soc_component *component) if (dmic->modeswitch_delay > MAX_MODESWITCH_DELAY) dmic->modeswitch_delay = MAX_MODESWITCH_DELAY;
+ dmic->dmic_sel = devm_gpiod_get_optional(component->dev, + "dmic_sel", GPIOD_OUT_LOW); + if (IS_ERR(dmic->dmic_sel)) + return PTR_ERR(dmic->dmic_sel); + snd_soc_component_set_drvdata(component, dmic);
return 0; @@ -125,10 +172,15 @@ static const struct snd_soc_dapm_widget dmic_dapm_widgets[] = { SND_SOC_NOPM, 0, 0, dmic_aif_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_INPUT("DMic"), + SND_SOC_DAPM_MIC("DMIC", NULL), + SND_SOC_DAPM_MUX("Dmic Mux", SND_SOC_NOPM, 0, 0, &dmic_mux_control), };
static const struct snd_soc_dapm_route intercon[] = { {"DMIC AIF", NULL, "DMic"}, + /* digital mics */ + {"Dmic Mux", "FrontMic", "DMIC"}, + {"Dmic Mux", "RearMic", "DMIC"}, };
static const struct snd_soc_component_driver soc_dmic = {