Commit 54643897 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branch 'asoc/topic/wm8994' into asoc-next

parents f57019aa 2da1c4bf
...@@ -182,6 +182,11 @@ struct wm8994_pdata { ...@@ -182,6 +182,11 @@ struct wm8994_pdata {
*/ */
int micdet_delay; 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 /* IRQ for microphone detection if brought out directly as a
* signal. * signal.
*/ */
......
...@@ -2668,6 +2668,10 @@ ...@@ -2668,6 +2668,10 @@
/* /*
* R772 (0x304) - AIF1ADC LRCLK * R772 (0x304) - AIF1ADC LRCLK
*/ */
#define WM8958_AIF1_LRCLK_INV 0x1000 /* AIF1_LRCLK_INV */
#define WM8958_AIF1_LRCLK_INV_MASK 0x1000 /* AIF1_LRCLK_INV */
#define WM8958_AIF1_LRCLK_INV_SHIFT 12 /* AIF1_LRCLK_INV */
#define WM8958_AIF1_LRCLK_INV_WIDTH 1 /* AIF1_LRCLK_INV */
#define WM8994_AIF1ADC_LRCLK_DIR 0x0800 /* AIF1ADC_LRCLK_DIR */ #define WM8994_AIF1ADC_LRCLK_DIR 0x0800 /* AIF1ADC_LRCLK_DIR */
#define WM8994_AIF1ADC_LRCLK_DIR_MASK 0x0800 /* AIF1ADC_LRCLK_DIR */ #define WM8994_AIF1ADC_LRCLK_DIR_MASK 0x0800 /* AIF1ADC_LRCLK_DIR */
#define WM8994_AIF1ADC_LRCLK_DIR_SHIFT 11 /* AIF1ADC_LRCLK_DIR */ #define WM8994_AIF1ADC_LRCLK_DIR_SHIFT 11 /* AIF1ADC_LRCLK_DIR */
...@@ -2679,6 +2683,10 @@ ...@@ -2679,6 +2683,10 @@
/* /*
* R773 (0x305) - AIF1DAC LRCLK * R773 (0x305) - AIF1DAC LRCLK
*/ */
#define WM8958_AIF1_LRCLK_INV 0x1000 /* AIF1_LRCLK_INV */
#define WM8958_AIF1_LRCLK_INV_MASK 0x1000 /* AIF1_LRCLK_INV */
#define WM8958_AIF1_LRCLK_INV_SHIFT 12 /* AIF1_LRCLK_INV */
#define WM8958_AIF1_LRCLK_INV_WIDTH 1 /* AIF1_LRCLK_INV */
#define WM8994_AIF1DAC_LRCLK_DIR 0x0800 /* AIF1DAC_LRCLK_DIR */ #define WM8994_AIF1DAC_LRCLK_DIR 0x0800 /* AIF1DAC_LRCLK_DIR */
#define WM8994_AIF1DAC_LRCLK_DIR_MASK 0x0800 /* AIF1DAC_LRCLK_DIR */ #define WM8994_AIF1DAC_LRCLK_DIR_MASK 0x0800 /* AIF1DAC_LRCLK_DIR */
#define WM8994_AIF1DAC_LRCLK_DIR_SHIFT 11 /* AIF1DAC_LRCLK_DIR */ #define WM8994_AIF1DAC_LRCLK_DIR_SHIFT 11 /* AIF1DAC_LRCLK_DIR */
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/gcd.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
...@@ -1498,6 +1499,24 @@ static const char *aif1dac_text[] = { ...@@ -1498,6 +1499,24 @@ static const char *aif1dac_text[] = {
"AIF1DACDAT", "AIF3DACDAT", "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 = static const struct soc_enum aif1dac_enum =
SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 0, 2, aif1dac_text); SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 0, 2, aif1dac_text);
...@@ -1744,6 +1763,9 @@ SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8994_POWER_MANAGEMENT_4, 2, 0), ...@@ -1744,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("ADCL", NULL, SND_SOC_NOPM, 1, 0),
SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 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), SND_SOC_DAPM_POST("Debug log", post_ev),
}; };
...@@ -1875,9 +1897,9 @@ static const struct snd_soc_dapm_route intercon[] = { ...@@ -1875,9 +1897,9 @@ static const struct snd_soc_dapm_route intercon[] = {
{ "AIF1DAC2L", NULL, "AIF1DAC Mux" }, { "AIF1DAC2L", NULL, "AIF1DAC Mux" },
{ "AIF1DAC2R", NULL, "AIF1DAC Mux" }, { "AIF1DAC2R", NULL, "AIF1DAC Mux" },
{ "AIF1DAC Mux", "AIF1DACDAT", "AIF1DACDAT" }, { "AIF1DAC Mux", "AIF1DACDAT", "AIF1 Loopback" },
{ "AIF1DAC Mux", "AIF3DACDAT", "AIF3DACDAT" }, { "AIF1DAC Mux", "AIF3DACDAT", "AIF3DACDAT" },
{ "AIF2DAC Mux", "AIF2DACDAT", "AIF2DACDAT" }, { "AIF2DAC Mux", "AIF2DACDAT", "AIF2 Loopback" },
{ "AIF2DAC Mux", "AIF3DACDAT", "AIF3DACDAT" }, { "AIF2DAC Mux", "AIF3DACDAT", "AIF3DACDAT" },
{ "AIF2ADC Mux", "AIF2ADCDAT", "AIF2ADCL" }, { "AIF2ADC Mux", "AIF2ADCDAT", "AIF2ADCL" },
{ "AIF2ADC Mux", "AIF2ADCDAT", "AIF2ADCR" }, { "AIF2ADC Mux", "AIF2ADCDAT", "AIF2ADCR" },
...@@ -1928,6 +1950,12 @@ static const struct snd_soc_dapm_route intercon[] = { ...@@ -1928,6 +1950,12 @@ static const struct snd_soc_dapm_route intercon[] = {
{ "AIF3ADCDAT", "AIF2DACDAT", "AIF2DACL" }, { "AIF3ADCDAT", "AIF2DACDAT", "AIF2DACL" },
{ "AIF3ADCDAT", "AIF2DACDAT", "AIF2DACR" }, { "AIF3ADCDAT", "AIF2DACDAT", "AIF2DACR" },
/* Loopback */
{ "AIF1 Loopback", "ADCDAT", "AIF1ADCDAT" },
{ "AIF1 Loopback", "None", "AIF1DACDAT" },
{ "AIF2 Loopback", "ADCDAT", "AIF2ADCDAT" },
{ "AIF2 Loopback", "None", "AIF2DACDAT" },
/* Sidetone */ /* Sidetone */
{ "Left Sidetone", "ADC/DMIC1", "ADCL Mux" }, { "Left Sidetone", "ADC/DMIC1", "ADCL Mux" },
{ "Left Sidetone", "DMIC2", "DMIC2L" }, { "Left Sidetone", "DMIC2", "DMIC2L" },
...@@ -2010,15 +2038,16 @@ struct fll_div { ...@@ -2010,15 +2038,16 @@ struct fll_div {
u16 outdiv; u16 outdiv;
u16 n; u16 n;
u16 k; u16 k;
u16 lambda;
u16 clk_ref_div; u16 clk_ref_div;
u16 fll_fratio; u16 fll_fratio;
}; };
static int wm8994_get_fll_config(struct fll_div *fll, static int wm8994_get_fll_config(struct wm8994 *control, struct fll_div *fll,
int freq_in, int freq_out) int freq_in, int freq_out)
{ {
u64 Kpart; u64 Kpart;
unsigned int K, Ndiv, Nmod; unsigned int K, Ndiv, Nmod, gcd_fll;
pr_debug("FLL input=%dHz, output=%dHz\n", freq_in, freq_out); pr_debug("FLL input=%dHz, output=%dHz\n", freq_in, freq_out);
...@@ -2067,6 +2096,8 @@ static int wm8994_get_fll_config(struct fll_div *fll, ...@@ -2067,6 +2096,8 @@ static int wm8994_get_fll_config(struct fll_div *fll,
Nmod = freq_out % freq_in; Nmod = freq_out % freq_in;
pr_debug("Nmod=%d\n", Nmod); pr_debug("Nmod=%d\n", Nmod);
switch (control->type) {
case WM8994:
/* Calculate fractional part - scale up so we can round. */ /* Calculate fractional part - scale up so we can round. */
Kpart = FIXED_FLL_SIZE * (long long)Nmod; Kpart = FIXED_FLL_SIZE * (long long)Nmod;
...@@ -2079,8 +2110,18 @@ static int wm8994_get_fll_config(struct fll_div *fll, ...@@ -2079,8 +2110,18 @@ static int wm8994_get_fll_config(struct fll_div *fll,
/* Move down to proper range now rounding is done */ /* Move down to proper range now rounding is done */
fll->k = K / 10; fll->k = K / 10;
fll->lambda = 0;
pr_debug("N=%x K=%x\n", fll->n, fll->k); pr_debug("N=%x K=%x\n", fll->n, fll->k);
break;
default:
gcd_fll = gcd(freq_out, freq_in);
fll->k = (freq_out - (freq_in * fll->n)) / gcd_fll;
fll->lambda = freq_in / gcd_fll;
}
return 0; return 0;
} }
...@@ -2144,9 +2185,9 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, ...@@ -2144,9 +2185,9 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
* analysis bugs spewing warnings. * analysis bugs spewing warnings.
*/ */
if (freq_out) if (freq_out)
ret = wm8994_get_fll_config(&fll, freq_in, freq_out); ret = wm8994_get_fll_config(control, &fll, freq_in, freq_out);
else else
ret = wm8994_get_fll_config(&fll, wm8994->fll[id].in, ret = wm8994_get_fll_config(control, &fll, wm8994->fll[id].in,
wm8994->fll[id].out); wm8994->fll[id].out);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -2191,6 +2232,17 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, ...@@ -2191,6 +2232,17 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
WM8994_FLL1_N_MASK, WM8994_FLL1_N_MASK,
fll.n << WM8994_FLL1_N_SHIFT); fll.n << WM8994_FLL1_N_SHIFT);
if (fll.lambda) {
snd_soc_update_bits(codec, WM8958_FLL1_EFS_1 + reg_offset,
WM8958_FLL1_LAMBDA_MASK,
fll.lambda);
snd_soc_update_bits(codec, WM8958_FLL1_EFS_2 + reg_offset,
WM8958_FLL1_EFS_ENA, WM8958_FLL1_EFS_ENA);
} else {
snd_soc_update_bits(codec, WM8958_FLL1_EFS_2 + reg_offset,
WM8958_FLL1_EFS_ENA, 0);
}
snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset, snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset,
WM8994_FLL1_FRC_NCO | WM8958_FLL1_BYP | WM8994_FLL1_FRC_NCO | WM8958_FLL1_BYP |
WM8994_FLL1_REFCLK_DIV_MASK | WM8994_FLL1_REFCLK_DIV_MASK |
...@@ -2555,17 +2607,24 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) ...@@ -2555,17 +2607,24 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
struct wm8994 *control = wm8994->wm8994; struct wm8994 *control = wm8994->wm8994;
int ms_reg; int ms_reg;
int aif1_reg; int aif1_reg;
int dac_reg;
int adc_reg;
int ms = 0; int ms = 0;
int aif1 = 0; int aif1 = 0;
int lrclk = 0;
switch (dai->id) { switch (dai->id) {
case 1: case 1:
ms_reg = WM8994_AIF1_MASTER_SLAVE; ms_reg = WM8994_AIF1_MASTER_SLAVE;
aif1_reg = WM8994_AIF1_CONTROL_1; aif1_reg = WM8994_AIF1_CONTROL_1;
dac_reg = WM8994_AIF1DAC_LRCLK;
adc_reg = WM8994_AIF1ADC_LRCLK;
break; break;
case 2: case 2:
ms_reg = WM8994_AIF2_MASTER_SLAVE; ms_reg = WM8994_AIF2_MASTER_SLAVE;
aif1_reg = WM8994_AIF2_CONTROL_1; aif1_reg = WM8994_AIF2_CONTROL_1;
dac_reg = WM8994_AIF1DAC_LRCLK;
adc_reg = WM8994_AIF1ADC_LRCLK;
break; break;
default: default:
return -EINVAL; return -EINVAL;
...@@ -2584,6 +2643,7 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) ...@@ -2584,6 +2643,7 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_DSP_B: case SND_SOC_DAIFMT_DSP_B:
aif1 |= WM8994_AIF1_LRCLK_INV; aif1 |= WM8994_AIF1_LRCLK_INV;
lrclk |= WM8958_AIF1_LRCLK_INV;
case SND_SOC_DAIFMT_DSP_A: case SND_SOC_DAIFMT_DSP_A:
aif1 |= 0x18; aif1 |= 0x18;
break; break;
...@@ -2622,12 +2682,14 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) ...@@ -2622,12 +2682,14 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
break; break;
case SND_SOC_DAIFMT_IB_IF: case SND_SOC_DAIFMT_IB_IF:
aif1 |= WM8994_AIF1_BCLK_INV | WM8994_AIF1_LRCLK_INV; aif1 |= WM8994_AIF1_BCLK_INV | WM8994_AIF1_LRCLK_INV;
lrclk |= WM8958_AIF1_LRCLK_INV;
break; break;
case SND_SOC_DAIFMT_IB_NF: case SND_SOC_DAIFMT_IB_NF:
aif1 |= WM8994_AIF1_BCLK_INV; aif1 |= WM8994_AIF1_BCLK_INV;
break; break;
case SND_SOC_DAIFMT_NB_IF: case SND_SOC_DAIFMT_NB_IF:
aif1 |= WM8994_AIF1_LRCLK_INV; aif1 |= WM8994_AIF1_LRCLK_INV;
lrclk |= WM8958_AIF1_LRCLK_INV;
break; break;
default: default:
return -EINVAL; return -EINVAL;
...@@ -2658,6 +2720,10 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) ...@@ -2658,6 +2720,10 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
aif1); aif1);
snd_soc_update_bits(codec, ms_reg, WM8994_AIF1_MSTR, snd_soc_update_bits(codec, ms_reg, WM8994_AIF1_MSTR,
ms); ms);
snd_soc_update_bits(codec, dac_reg,
WM8958_AIF1_LRCLK_INV, lrclk);
snd_soc_update_bits(codec, adc_reg,
WM8958_AIF1_LRCLK_INV, lrclk);
return 0; return 0;
} }
...@@ -3096,24 +3162,7 @@ static int wm8994_codec_suspend(struct snd_soc_codec *codec) ...@@ -3096,24 +3162,7 @@ static int wm8994_codec_suspend(struct snd_soc_codec *codec)
static int wm8994_codec_resume(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_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994 *control = wm8994->wm8994;
int i, ret; int i, ret;
unsigned int val, mask;
if (control->revision < 4) {
/* force a HW read */
ret = regmap_read(control->regmap,
WM8994_POWER_MANAGEMENT_5, &val);
/* modify the cache only */
codec->cache_only = 1;
mask = WM8994_DAC1R_ENA | WM8994_DAC1L_ENA |
WM8994_DAC2R_ENA | WM8994_DAC2L_ENA;
val &= mask;
snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5,
mask, val);
codec->cache_only = 0;
}
for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) { for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
if (!wm8994->fll_suspend[i].out) if (!wm8994->fll_suspend[i].out)
...@@ -3495,6 +3544,31 @@ static void wm8958_button_det(struct snd_soc_codec *codec, u16 status) ...@@ -3495,6 +3544,31 @@ static void wm8958_button_det(struct snd_soc_codec *codec, u16 status)
wm8994->btn_mask); wm8994->btn_mask);
} }
static void wm8958_open_circuit_work(struct work_struct *work)
{
struct wm8994_priv *wm8994 = container_of(work,
struct wm8994_priv,
open_circuit_work.work);
struct device *dev = wm8994->wm8994->dev;
wm1811_micd_stop(wm8994->hubs.codec);
mutex_lock(&wm8994->accdet_lock);
dev_dbg(dev, "Reporting open circuit\n");
wm8994->jack_mic = false;
wm8994->mic_detecting = true;
wm8958_micd_set_rate(wm8994->hubs.codec);
snd_soc_jack_report(wm8994->micdet[0].jack, 0,
wm8994->btn_mask |
SND_JACK_HEADSET);
mutex_unlock(&wm8994->accdet_lock);
}
static void wm8958_mic_id(void *data, u16 status) static void wm8958_mic_id(void *data, u16 status)
{ {
struct snd_soc_codec *codec = data; struct snd_soc_codec *codec = data;
...@@ -3504,16 +3578,9 @@ static void wm8958_mic_id(void *data, u16 status) ...@@ -3504,16 +3578,9 @@ static void wm8958_mic_id(void *data, u16 status)
if (!(status & WM8958_MICD_STS)) { if (!(status & WM8958_MICD_STS)) {
/* If nothing present then clear our statuses */ /* If nothing present then clear our statuses */
dev_dbg(codec->dev, "Detected open circuit\n"); dev_dbg(codec->dev, "Detected open circuit\n");
wm8994->jack_mic = false;
wm8994->mic_detecting = true;
wm1811_micd_stop(codec); schedule_delayed_work(&wm8994->open_circuit_work,
msecs_to_jiffies(2500));
wm8958_micd_set_rate(codec);
snd_soc_jack_report(wm8994->micdet[0].jack, 0,
wm8994->btn_mask |
SND_JACK_HEADSET);
return; return;
} }
...@@ -3598,6 +3665,8 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data) ...@@ -3598,6 +3665,8 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
pm_runtime_get_sync(codec->dev); pm_runtime_get_sync(codec->dev);
cancel_delayed_work_sync(&wm8994->mic_complete_work);
mutex_lock(&wm8994->accdet_lock); mutex_lock(&wm8994->accdet_lock);
reg = snd_soc_read(codec, WM1811_JACKDET_CTRL); reg = snd_soc_read(codec, WM1811_JACKDET_CTRL);
...@@ -3780,11 +3849,33 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, ...@@ -3780,11 +3849,33 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
} }
EXPORT_SYMBOL_GPL(wm8958_mic_detect); 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) static irqreturn_t wm8958_mic_irq(int irq, void *data)
{ {
struct wm8994_priv *wm8994 = data; struct wm8994_priv *wm8994 = data;
struct snd_soc_codec *codec = wm8994->hubs.codec; 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 * Jack detection may have detected a removal simulataneously
...@@ -3794,6 +3885,9 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) ...@@ -3794,6 +3885,9 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
if (!(snd_soc_read(codec, WM8958_MIC_DETECT_1) & WM8958_MICD_ENA)) if (!(snd_soc_read(codec, WM8958_MIC_DETECT_1) & WM8958_MICD_ENA))
return IRQ_HANDLED; 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); pm_runtime_get_sync(codec->dev);
/* We may occasionally read a detection without an impedence /* We may occasionally read a detection without an impedence
...@@ -3846,8 +3940,12 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) ...@@ -3846,8 +3940,12 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
goto out; goto out;
} }
wm8994->mic_status = reg;
id_delay = wm8994->wm8994->pdata.mic_id_delay;
if (wm8994->mic_detecting) 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 else
wm8958_button_det(codec, reg); wm8958_button_det(codec, reg);
...@@ -3899,6 +3997,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) ...@@ -3899,6 +3997,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
mutex_init(&wm8994->accdet_lock); mutex_init(&wm8994->accdet_lock);
INIT_DELAYED_WORK(&wm8994->jackdet_bootstrap, INIT_DELAYED_WORK(&wm8994->jackdet_bootstrap,
wm1811_jackdet_bootstrap); wm1811_jackdet_bootstrap);
INIT_DELAYED_WORK(&wm8994->open_circuit_work,
wm8958_open_circuit_work);
switch (control->type) { switch (control->type) {
case WM8994: case WM8994:
...@@ -3911,6 +4011,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) ...@@ -3911,6 +4011,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
break; break;
} }
INIT_DELAYED_WORK(&wm8994->mic_complete_work, wm8958_mic_work);
for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
init_completion(&wm8994->fll_locked[i]); init_completion(&wm8994->fll_locked[i]);
......
...@@ -134,6 +134,9 @@ struct wm8994_priv { ...@@ -134,6 +134,9 @@ struct wm8994_priv {
struct mutex accdet_lock; struct mutex accdet_lock;
struct wm8994_micdet micdet[2]; struct wm8994_micdet micdet[2];
struct delayed_work mic_work; struct delayed_work mic_work;
struct delayed_work open_circuit_work;
struct delayed_work mic_complete_work;
u16 mic_status;
bool mic_detecting; bool mic_detecting;
bool jack_mic; bool jack_mic;
int btn_mask; int btn_mask;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment