[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-Id: <20250206163152.423199-6-francesco@dolcini.it>
Date: Thu, 6 Feb 2025 17:31:52 +0100
From: Francesco Dolcini <francesco@...cini.it>
To: Liam Girdwood <lgirdwood@...il.com>,
Mark Brown <broonie@...nel.org>,
Rob Herring <robh@...nel.org>,
Krzysztof Kozlowski <krzk+dt@...nel.org>,
Conor Dooley <conor+dt@...nel.org>,
Saravana Kannan <saravanak@...gle.com>,
Jaroslav Kysela <perex@...ex.cz>,
Takashi Iwai <tiwai@...e.com>,
patches@...nsource.cirrus.com
Cc: Ernest Van Hoecke <ernest.vanhoecke@...adex.com>,
linux-sound@...r.kernel.org,
devicetree@...r.kernel.org,
linux-kernel@...r.kernel.org,
Francesco Dolcini <francesco.dolcini@...adex.com>
Subject: [PATCH v1 5/5] ASoC: wm8904: add DMIC support
From: Ernest Van Hoecke <ernest.vanhoecke@...adex.com>
The WM8904 codec supports both ADC and DMIC inputs.
Get input pin functionality from the platform data and add the necessary
controls depending on the possible additional routing.
The ADC and DMIC share the IN1L/DMICDAT1 and IN1R/DMICDAT2 pins.
When both are connected to an analog input, only the ADC is used. When
both are connected to a DMIC, only the DMIC is used, and a mux is added
to select the DMIC source. When one line is a DMIC and the other an
analog input, the DMIC source is set from the platform data and a mux is
added to select whether to use the ADC or DMIC.
Signed-off-by: Ernest Van Hoecke <ernest.vanhoecke@...adex.com>
Signed-off-by: Francesco Dolcini <francesco.dolcini@...adex.com>
---
sound/soc/codecs/wm8904.c | 82 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 80 insertions(+), 2 deletions(-)
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index 899ef6679f7e..a024cfc136c3 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -844,6 +844,26 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
return 0;
}
+static const char * const dmic_text[] = {
+ "DMIC1", "DMIC2"
+};
+
+static SOC_ENUM_SINGLE_DECL(dmic_enum, WM8904_DIGITAL_MICROPHONE_0,
+ WM8904_DMIC_SRC_SHIFT, dmic_text);
+
+static const struct snd_kcontrol_new dmic_mux =
+ SOC_DAPM_ENUM("DMIC Mux", dmic_enum);
+
+static const char * const cin_text[] = {
+ "ADC", "DMIC"
+};
+
+static SOC_ENUM_SINGLE_DECL(cin_enum, WM8904_DIGITAL_MICROPHONE_0,
+ WM8904_DMIC_ENA_SHIFT, cin_text);
+
+static const struct snd_kcontrol_new cin_mux =
+ SOC_DAPM_ENUM("Capture Input", cin_enum);
+
static const char *input_mode_text[] = {
"Single-Ended", "Differential Line", "Differential Mic"
};
@@ -963,6 +983,15 @@ SND_SOC_DAPM_AIF_OUT("AIFOUTL", "Capture", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("AIFOUTR", "Capture", 1, SND_SOC_NOPM, 0, 0),
};
+static const struct snd_soc_dapm_widget wm8904_dmic_dapm_widgets[] = {
+SND_SOC_DAPM_MUX("DMIC Mux", SND_SOC_NOPM, 0, 0, &dmic_mux),
+};
+
+static const struct snd_soc_dapm_widget wm8904_cin_dapm_widgets[] = {
+SND_SOC_DAPM_MUX("Left Capture Input", SND_SOC_NOPM, 0, 0, &cin_mux),
+SND_SOC_DAPM_MUX("Right Capture Input", SND_SOC_NOPM, 0, 0, &cin_mux),
+};
+
static const struct snd_soc_dapm_widget wm8904_dac_dapm_widgets[] = {
SND_SOC_DAPM_AIF_IN("AIFINL", "Playback", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("AIFINR", "Playback", 1, SND_SOC_NOPM, 0, 0),
@@ -1107,6 +1136,24 @@ static const struct snd_soc_dapm_route adc_intercon[] = {
{ "ADCR", NULL, "Right Capture PGA" },
};
+static const struct snd_soc_dapm_route dmic_intercon[] = {
+ { "DMIC Mux", "DMIC1", "IN1L" },
+ { "DMIC Mux", "DMIC2", "IN1R" },
+
+ { "ADCL", NULL, "DMIC Mux" },
+ { "ADCR", NULL, "DMIC Mux" },
+};
+
+static const struct snd_soc_dapm_route cin_intercon[] = {
+ { "Left Capture Input", "ADC", "Left Capture PGA" },
+ { "Left Capture Input", "DMIC", "IN1L" },
+ { "Right Capture Input", "ADC", "Right Capture PGA" },
+ { "Right Capture Input", "DMIC", "IN1R" },
+
+ { "ADCL", NULL, "Left Capture Input" },
+ { "ADCR", NULL, "Right Capture Input" },
+};
+
static const struct snd_soc_dapm_route dac_intercon[] = {
{ "DACL Mux", "Left", "AIFINL" },
{ "DACL Mux", "Right", "AIFINR" },
@@ -2052,6 +2099,7 @@ static void wm8904_handle_retune_mobile_pdata(struct snd_soc_component *componen
static void wm8904_handle_pdata(struct snd_soc_component *component)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
struct wm8904_pdata *pdata = wm8904->pdata;
int ret, i;
@@ -2062,6 +2110,35 @@ static void wm8904_handle_pdata(struct snd_soc_component *component)
return;
}
+ if (pdata->in1l_as_dmicdat1 && pdata->in1r_as_dmicdat2) {
+ dev_dbg(component->dev, "Activating DMICDAT1 and DMICDAT2\n");
+ snd_soc_component_update_bits(component, WM8904_DIGITAL_MICROPHONE_0,
+ WM8904_DMIC_ENA_MASK,
+ 1 << WM8904_DMIC_ENA_SHIFT);
+
+ /* Need a control and routing to switch between DMIC1 and 2 */
+ snd_soc_dapm_new_controls(dapm, wm8904_dmic_dapm_widgets,
+ ARRAY_SIZE(wm8904_dmic_dapm_widgets));
+ snd_soc_dapm_add_routes(dapm, dmic_intercon,
+ ARRAY_SIZE(dmic_intercon));
+ } else if (pdata->in1l_as_dmicdat1 || pdata->in1r_as_dmicdat2) {
+ unsigned int dmic_src = pdata->in1l_as_dmicdat1 ? 0 : 1;
+
+ dev_dbg(component->dev, "DMIC_SRC (0 or 1): %d\n", dmic_src);
+ snd_soc_component_update_bits(component, WM8904_DIGITAL_MICROPHONE_0,
+ WM8904_DMIC_SRC_MASK,
+ dmic_src << WM8904_DMIC_SRC_SHIFT);
+
+ /* Need a control and routing to switch between DMIC and ADC */
+ snd_soc_dapm_new_controls(dapm, wm8904_cin_dapm_widgets,
+ ARRAY_SIZE(wm8904_cin_dapm_widgets));
+ snd_soc_dapm_add_routes(dapm, cin_intercon,
+ ARRAY_SIZE(cin_intercon));
+ } else {
+ snd_soc_component_update_bits(component, WM8904_DIGITAL_MICROPHONE_0,
+ WM8904_DMIC_ENA_MASK, 0);
+ }
+
dev_dbg(component->dev, "%d DRC configurations\n", pdata->num_drc_cfgs);
if (pdata->num_drc_cfgs) {
@@ -2117,10 +2194,11 @@ static int wm8904_probe(struct snd_soc_component *component)
return -EINVAL;
}
- wm8904_handle_pdata(component);
-
wm8904_add_widgets(component);
+ /* This can add dependent widgets, so it is done after add_widgets */
+ wm8904_handle_pdata(component);
+
return 0;
}
--
2.39.5
Powered by blists - more mailing lists