[alsa-devel] [PATCH 1/5] ASoC: wm8994: Add digital loopback paths
There is loopback control within the audio interfaces, provide control of this as there are some obscure scenarios where this could be used in production.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/soc/codecs/wm8994.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-)
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 561c2f9..2081fa1 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -1499,6 +1499,24 @@ static const char *aif1dac_text[] = { "AIF1DACDAT", "AIF3DACDAT", };
+static const char *loopback_text[] = { + "None", "ADCDAT", +}; + +static const struct soc_enum aif1_loopback_enum = + SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, WM8994_AIF1_LOOPBACK_SHIFT, 2, + loopback_text); + +static const struct snd_kcontrol_new aif1_loopback = + SOC_DAPM_ENUM("AIF1 Loopback", aif1_loopback_enum); + +static const struct soc_enum aif2_loopback_enum = + SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, WM8994_AIF2_LOOPBACK_SHIFT, 2, + loopback_text); + +static const struct snd_kcontrol_new aif2_loopback = + SOC_DAPM_ENUM("AIF2 Loopback", aif2_loopback_enum); + static const struct soc_enum aif1dac_enum = SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 0, 2, aif1dac_text);
@@ -1745,6 +1763,9 @@ SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8994_POWER_MANAGEMENT_4, 2, 0), SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 1, 0), SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_MUX("AIF1 Loopback", SND_SOC_NOPM, 0, 0, &aif1_loopback), +SND_SOC_DAPM_MUX("AIF2 Loopback", SND_SOC_NOPM, 0, 0, &aif2_loopback), + SND_SOC_DAPM_POST("Debug log", post_ev), };
@@ -1876,9 +1897,9 @@ static const struct snd_soc_dapm_route intercon[] = { { "AIF1DAC2L", NULL, "AIF1DAC Mux" }, { "AIF1DAC2R", NULL, "AIF1DAC Mux" },
- { "AIF1DAC Mux", "AIF1DACDAT", "AIF1DACDAT" }, + { "AIF1DAC Mux", "AIF1DACDAT", "AIF1 Loopback" }, { "AIF1DAC Mux", "AIF3DACDAT", "AIF3DACDAT" }, - { "AIF2DAC Mux", "AIF2DACDAT", "AIF2DACDAT" }, + { "AIF2DAC Mux", "AIF2DACDAT", "AIF2 Loopback" }, { "AIF2DAC Mux", "AIF3DACDAT", "AIF3DACDAT" }, { "AIF2ADC Mux", "AIF2ADCDAT", "AIF2ADCL" }, { "AIF2ADC Mux", "AIF2ADCDAT", "AIF2ADCR" }, @@ -1929,6 +1950,12 @@ static const struct snd_soc_dapm_route intercon[] = { { "AIF3ADCDAT", "AIF2DACDAT", "AIF2DACL" }, { "AIF3ADCDAT", "AIF2DACDAT", "AIF2DACR" },
+ /* Loopback */ + { "AIF1 Loopback", "ADCDAT", "AIF1ADCDAT" }, + { "AIF1 Loopback", "None", "AIF1DACDAT" }, + { "AIF2 Loopback", "ADCDAT", "AIF2ADCDAT" }, + { "AIF2 Loopback", "None", "AIF2DACDAT" }, + /* Sidetone */ { "Left Sidetone", "ADC/DMIC1", "ADCL Mux" }, { "Left Sidetone", "DMIC2", "DMIC2L" },
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/soc/codecs/wm8994.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 2081fa1..7dd5045 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -3912,6 +3912,7 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) snd_soc_jack_report(wm8994->micdet[0].jack, 0, SND_JACK_MECHANICAL | SND_JACK_HEADSET | wm8994->btn_mask); + wm8994->mic_detecting = false; goto out; }
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/soc/codecs/wm8994.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 7dd5045..365e6f9 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -3906,7 +3906,7 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) ret); } else if (!(ret & WM1811_JACKDET_LVL)) { dev_dbg(codec->dev, "Ignoring removed jack\n"); - return IRQ_HANDLED; + goto out; } } else if (!(reg & WM8958_MICD_STS)) { snd_soc_jack_report(wm8994->micdet[0].jack, 0,
For systems which do not have a jack detection feature allow some debounce to be specified before we perform accessory identification, improving robustness without impacting button detection responsiveness.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- include/linux/mfd/wm8994/pdata.h | 5 +++++ sound/soc/codecs/wm8994.c | 35 +++++++++++++++++++++++++++++++++-- sound/soc/codecs/wm8994.h | 2 ++ 3 files changed, 40 insertions(+), 2 deletions(-)
diff --git a/include/linux/mfd/wm8994/pdata.h b/include/linux/mfd/wm8994/pdata.h index 90e9bf8..90c6052 100644 --- a/include/linux/mfd/wm8994/pdata.h +++ b/include/linux/mfd/wm8994/pdata.h @@ -182,6 +182,11 @@ struct wm8994_pdata { */ int micdet_delay;
+ /* Delay between microphone detect completing and reporting on + * insert (specified in ms) + */ + int mic_id_delay; + /* IRQ for microphone detection if brought out directly as a * signal. */ diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 365e6f9..d921463 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -3666,6 +3666,8 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
pm_runtime_get_sync(codec->dev);
+ cancel_delayed_work_sync(&wm8994->mic_complete_work); + mutex_lock(&wm8994->accdet_lock);
reg = snd_soc_read(codec, WM1811_JACKDET_CTRL); @@ -3848,11 +3850,33 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, } EXPORT_SYMBOL_GPL(wm8958_mic_detect);
+static void wm8958_mic_work(struct work_struct *work) +{ + struct wm8994_priv *wm8994 = container_of(work, + struct wm8994_priv, + mic_complete_work.work); + struct snd_soc_codec *codec = wm8994->hubs.codec; + + dev_crit(codec->dev, "MIC WORK %x\n", wm8994->mic_status); + + pm_runtime_get_sync(codec->dev); + + mutex_lock(&wm8994->accdet_lock); + + wm8994->mic_id_cb(wm8994->mic_id_cb_data, wm8994->mic_status); + + mutex_unlock(&wm8994->accdet_lock); + + pm_runtime_put(codec->dev); + + dev_crit(codec->dev, "MIC WORK %x DONE\n", wm8994->mic_status); +} + static irqreturn_t wm8958_mic_irq(int irq, void *data) { struct wm8994_priv *wm8994 = data; struct snd_soc_codec *codec = wm8994->hubs.codec; - int reg, count, ret; + int reg, count, ret, id_delay;
/* * Jack detection may have detected a removal simulataneously @@ -3862,6 +3886,7 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) if (!(snd_soc_read(codec, WM8958_MIC_DETECT_1) & WM8958_MICD_ENA)) return IRQ_HANDLED;
+ cancel_delayed_work_sync(&wm8994->mic_complete_work); cancel_delayed_work_sync(&wm8994->open_circuit_work);
pm_runtime_get_sync(codec->dev); @@ -3916,8 +3941,12 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) goto out; }
+ wm8994->mic_status = reg; + id_delay = wm8994->wm8994->pdata.mic_id_delay; + if (wm8994->mic_detecting) - wm8994->mic_id_cb(wm8994->mic_id_cb_data, reg); + schedule_delayed_work(&wm8994->mic_complete_work, + msecs_to_jiffies(id_delay)); else wm8958_button_det(codec, reg);
@@ -3983,6 +4012,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) break; }
+ INIT_DELAYED_WORK(&wm8994->mic_complete_work, wm8958_mic_work); + for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) init_completion(&wm8994->fll_locked[i]);
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index 9d19a91..6536f8d 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h @@ -135,6 +135,8 @@ struct wm8994_priv { struct wm8994_micdet micdet[2]; struct delayed_work mic_work; struct delayed_work open_circuit_work; + struct delayed_work mic_complete_work; + u16 mic_status; bool mic_detecting; bool jack_mic; int btn_mask;
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/soc/codecs/wm8994.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index d921463..9298552 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -3162,7 +3162,6 @@ static int wm8994_codec_suspend(struct snd_soc_codec *codec) static int wm8994_codec_resume(struct snd_soc_codec *codec) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994 *control = wm8994->wm8994; int i, ret;
for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
participants (2)
-
Mark Brown
-
Mark Brown