Merge remote-tracking branch 'asoc/topic/wm8994' into asoc-next
This commit is contained in:
commit
5464389755
4 changed files with 161 additions and 43 deletions
|
@ -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 @@
|
||||||
/*
|
/*
|
||||||
* 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 @@
|
||||||
/*
|
/*
|
||||||
* 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 @@
|
||||||
#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[] = {
|
||||||
"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),
|
||||||
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[] = {
|
||||||
{ "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[] = {
|
||||||
{ "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 {
|
||||||
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,20 +2096,32 @@ 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);
|
||||||
|
|
||||||
/* Calculate fractional part - scale up so we can round. */
|
switch (control->type) {
|
||||||
Kpart = FIXED_FLL_SIZE * (long long)Nmod;
|
case WM8994:
|
||||||
|
/* Calculate fractional part - scale up so we can round. */
|
||||||
|
Kpart = FIXED_FLL_SIZE * (long long)Nmod;
|
||||||
|
|
||||||
do_div(Kpart, freq_in);
|
do_div(Kpart, freq_in);
|
||||||
|
|
||||||
K = Kpart & 0xFFFFFFFF;
|
K = Kpart & 0xFFFFFFFF;
|
||||||
|
|
||||||
if ((K % 10) >= 5)
|
if ((K % 10) >= 5)
|
||||||
K += 5;
|
K += 5;
|
||||||
|
|
||||||
/* 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,
|
||||||
* 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,
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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,
|
||||||
}
|
}
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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 {
|
||||||
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;
|
||||||
|
|
Loading…
Add table
Reference in a new issue