In the WM8903, most muxes are implemented separately for the L and R paths, such that for each channel, there is a soc_enum, and kcontrol_new containing a SOC_DAPM_ENUM, a widget of type SND_SOC_DAPM_MUX, and of course a separate register bit for each. In other words, 1 mono muxes.
I couldn't find any obvious cases where other codecs deviated from this.
However, the DMIC mux in the wm8903 is a single register bit that controls both channels. In other words, a single stereo mux. I'm having trouble working out how to represent this to DAPM.
I ended up with the patch below (note: not against mainline yet), which seems to work OK, but ends up showing two controls in alsamixer rather than just one. A least when one control is changed, the other reflects the change, so they stay in sync.
I tried other setups, such as a single widget of type SND_SOC_DAPM_MUX, and having the DAPM routes for that connect to both ADCL and ADCR paths, but (a) that confused the ASoC core, such that controls for subsequent paths in the list were not created, and those related to the ADC input paths would not work, and (b) I suspect that if it worked, it'd produce non-optimal HW programming in the case where only a single ADC channel was actually used, since the mux would imply it was hooked up to both, so both ADCs would be powered even though only one was needed.
So, is there a way to correctly represent this while only exposing a single control for it?
Thanks!
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index ae1cadf..bbc9aff 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -636,6 +636,13 @@ static const struct soc_enum lsidetone_enum = static const struct soc_enum rsidetone_enum = SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 0, 3, sidetone_text);
+static const char *dsp_text[] = { + "ADC", "DMIC" +}; + +static const struct soc_enum dsp_enum = + SOC_ENUM_SINGLE(WM8903_CLOCK_RATE_TEST_4, 9, 2, dsp_text); + static const char *aif_text[] = { "Left", "Right" }; @@ -769,6 +776,9 @@ static const struct snd_kcontrol_new lsidetone_mux = static const struct snd_kcontrol_new rsidetone_mux = SOC_DAPM_ENUM("DACR Sidetone Mux", rsidetone_enum);
+static const struct snd_kcontrol_new dsp_mux = + SOC_DAPM_ENUM("DSP Mux", dsp_enum); + static const struct snd_kcontrol_new lcapture_mux = SOC_DAPM_ENUM("Left Capture Mux", lcapture_enum);
@@ -819,6 +829,7 @@ SND_SOC_DAPM_INPUT("IN2L"), SND_SOC_DAPM_INPUT("IN2R"), SND_SOC_DAPM_INPUT("IN3L"), SND_SOC_DAPM_INPUT("IN3R"), +SND_SOC_DAPM_INPUT("DMICDAT"),
SND_SOC_DAPM_OUTPUT("HPOUTL"), SND_SOC_DAPM_OUTPUT("HPOUTR"), @@ -847,6 +858,12 @@ SND_SOC_DAPM_PGA("Right Input PGA", WM8903_POWER_MANAGEMENT_0, 0, 0, NULL, 0), SND_SOC_DAPM_ADC("ADCL", NULL, WM8903_POWER_MANAGEMENT_6, 1, 0), SND_SOC_DAPM_ADC("ADCR", NULL, WM8903_POWER_MANAGEMENT_6, 0, 0),
+SND_SOC_DAPM_ADC("DMICL", NULL, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_ADC("DMICR", NULL, SND_SOC_NOPM, 0, 0), + +SND_SOC_DAPM_MUX("Left DSP Mux", SND_SOC_NOPM, 0, 0, &dsp_mux), +SND_SOC_DAPM_MUX("Right DSP Mux", SND_SOC_NOPM, 0, 0, &dsp_mux), + SND_SOC_DAPM_MUX("Left Capture Mux", SND_SOC_NOPM, 0, 0, &lcapture_mux), SND_SOC_DAPM_MUX("Right Capture Mux", SND_SOC_NOPM, 0, 0, &rcapture_mux),
@@ -975,11 +992,17 @@ static const struct snd_soc_dapm_route intercon[] = { { "Left Input PGA", NULL, "Left Input Mode Mux" }, { "Right Input PGA", NULL, "Right Input Mode Mux" },
- { "Left Capture Mux", "Left", "ADCL" }, - { "Left Capture Mux", "Right", "ADCR" }, + { "Left DSP Mux", "ADC", "ADCL" }, + { "Left DSP Mux", "DMIC", "DMICL" }, + + { "Right DSP Mux", "ADC", "ADCR" }, + { "Right DSP Mux", "DMIC", "DMICR" },
- { "Right Capture Mux", "Left", "ADCL" }, - { "Right Capture Mux", "Right", "ADCR" }, + { "Left Capture Mux", "Left", "Left DSP Mux" }, + { "Left Capture Mux", "Right", "Right DSP Mux" }, + + { "Right Capture Mux", "Left", "Left DSP Mux" }, + { "Right Capture Mux", "Right", "Right DSP Mux" },
{ "AIFTXL", NULL, "Left Capture Mux" }, { "AIFTXR", NULL, "Right Capture Mux" }, @@ -989,6 +1012,11 @@ static const struct snd_soc_dapm_route intercon[] = { { "ADCR", NULL, "Right Input PGA" }, { "ADCR", NULL, "CLK_DSP" },
+ { "DMICL", NULL, "DMICDAT" }, + { "DMICL", NULL, "CLK_DSP" }, + { "DMICR", NULL, "DMICDAT" }, + { "DMICR", NULL, "CLK_DSP" }, + { "Left Playback Mux", "Left", "AIFRXL" }, { "Left Playback Mux", "Right", "AIFRXR" },