Commit 06f1c663 authored by Mark Brown's avatar Mark Brown

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

parents 6f5716a2 98869f68
...@@ -401,13 +401,19 @@ static const __devinitconst struct reg_default wm1811_reva_patch[] = { ...@@ -401,13 +401,19 @@ static const __devinitconst struct reg_default wm1811_reva_patch[] = {
*/ */
static __devinit int wm8994_device_init(struct wm8994 *wm8994, int irq) static __devinit int wm8994_device_init(struct wm8994 *wm8994, int irq)
{ {
struct wm8994_pdata *pdata = wm8994->dev->platform_data; struct wm8994_pdata *pdata;
struct regmap_config *regmap_config; struct regmap_config *regmap_config;
const struct reg_default *regmap_patch = NULL; const struct reg_default *regmap_patch = NULL;
const char *devname; const char *devname;
int ret, i, patch_regs; int ret, i, patch_regs;
int pulls = 0; int pulls = 0;
if (dev_get_platdata(wm8994->dev)) {
pdata = dev_get_platdata(wm8994->dev);
wm8994->pdata = *pdata;
}
pdata = &wm8994->pdata;
dev_set_drvdata(wm8994->dev, wm8994); dev_set_drvdata(wm8994->dev, wm8994);
/* Add the on-chip regulators first for bootstrapping */ /* Add the on-chip regulators first for bootstrapping */
...@@ -604,24 +610,21 @@ static __devinit int wm8994_device_init(struct wm8994 *wm8994, int irq) ...@@ -604,24 +610,21 @@ static __devinit int wm8994_device_init(struct wm8994 *wm8994, int irq)
} }
} }
if (pdata) { wm8994->irq_base = pdata->irq_base;
wm8994->irq_base = pdata->irq_base; wm8994->gpio_base = pdata->gpio_base;
wm8994->gpio_base = pdata->gpio_base;
/* GPIO configuration is only applied if it's non-zero */
/* GPIO configuration is only applied if it's non-zero */ for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) {
for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) { if (pdata->gpio_defaults[i]) {
if (pdata->gpio_defaults[i]) { wm8994_set_bits(wm8994, WM8994_GPIO_1 + i,
wm8994_set_bits(wm8994, WM8994_GPIO_1 + i, 0xffff, pdata->gpio_defaults[i]);
0xffff,
pdata->gpio_defaults[i]);
}
} }
}
wm8994->ldo_ena_always_driven = pdata->ldo_ena_always_driven; wm8994->ldo_ena_always_driven = pdata->ldo_ena_always_driven;
if (pdata->spkmode_pu) if (pdata->spkmode_pu)
pulls |= WM8994_SPKMODE_PU; pulls |= WM8994_SPKMODE_PU;
}
/* Disable unneeded pulls */ /* Disable unneeded pulls */
wm8994_set_bits(wm8994, WM8994_PULL_CONTROL_2, wm8994_set_bits(wm8994, WM8994_PULL_CONTROL_2,
......
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/mfd/wm8994/pdata.h>
enum wm8994_type { enum wm8994_type {
WM8994 = 0, WM8994 = 0,
WM8958 = 1, WM8958 = 1,
...@@ -55,6 +57,8 @@ struct regulator_bulk_data; ...@@ -55,6 +57,8 @@ struct regulator_bulk_data;
struct wm8994 { struct wm8994 {
struct mutex irq_lock; struct mutex irq_lock;
struct wm8994_pdata pdata;
enum wm8994_type type; enum wm8994_type type;
int revision; int revision;
int cust_id; int cust_id;
......
...@@ -176,6 +176,11 @@ struct wm8994_pdata { ...@@ -176,6 +176,11 @@ struct wm8994_pdata {
unsigned int lineout1fb:1; unsigned int lineout1fb:1;
unsigned int lineout2fb:1; unsigned int lineout2fb:1;
/* Delay between detecting a jack and starting microphone
* detect (specified in ms)
*/
int micdet_delay;
/* IRQ for microphone detection if brought out directly as a /* IRQ for microphone detection if brought out directly as a
* signal. * signal.
*/ */
......
...@@ -195,7 +195,7 @@ static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name, ...@@ -195,7 +195,7 @@ static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name,
static void wm8958_dsp_start_mbc(struct snd_soc_codec *codec, int path) static void wm8958_dsp_start_mbc(struct snd_soc_codec *codec, int path)
{ {
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994_pdata *pdata = wm8994->pdata; struct wm8994 *control = wm8994->wm8994;
int i; int i;
/* If the DSP is already running then noop */ /* If the DSP is already running then noop */
...@@ -210,9 +210,9 @@ static void wm8958_dsp_start_mbc(struct snd_soc_codec *codec, int path) ...@@ -210,9 +210,9 @@ static void wm8958_dsp_start_mbc(struct snd_soc_codec *codec, int path)
WM8958_DSP2_ENA, WM8958_DSP2_ENA); WM8958_DSP2_ENA, WM8958_DSP2_ENA);
/* If we've got user supplied MBC settings use them */ /* If we've got user supplied MBC settings use them */
if (pdata && pdata->num_mbc_cfgs) { if (control->pdata.num_mbc_cfgs) {
struct wm8958_mbc_cfg *cfg struct wm8958_mbc_cfg *cfg
= &pdata->mbc_cfgs[wm8994->mbc_cfg]; = &control->pdata.mbc_cfgs[wm8994->mbc_cfg];
for (i = 0; i < ARRAY_SIZE(cfg->coeff_regs); i++) for (i = 0; i < ARRAY_SIZE(cfg->coeff_regs); i++)
snd_soc_write(codec, i + WM8958_MBC_BAND_1_K_1, snd_soc_write(codec, i + WM8958_MBC_BAND_1_K_1,
...@@ -239,7 +239,7 @@ static void wm8958_dsp_start_mbc(struct snd_soc_codec *codec, int path) ...@@ -239,7 +239,7 @@ static void wm8958_dsp_start_mbc(struct snd_soc_codec *codec, int path)
static void wm8958_dsp_start_vss(struct snd_soc_codec *codec, int path) static void wm8958_dsp_start_vss(struct snd_soc_codec *codec, int path)
{ {
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994_pdata *pdata = wm8994->pdata; struct wm8994 *control = wm8994->wm8994;
int i, ena; int i, ena;
if (wm8994->mbc_vss) if (wm8994->mbc_vss)
...@@ -249,26 +249,26 @@ static void wm8958_dsp_start_vss(struct snd_soc_codec *codec, int path) ...@@ -249,26 +249,26 @@ static void wm8958_dsp_start_vss(struct snd_soc_codec *codec, int path)
WM8958_DSP2_ENA, WM8958_DSP2_ENA); WM8958_DSP2_ENA, WM8958_DSP2_ENA);
/* If we've got user supplied settings use them */ /* If we've got user supplied settings use them */
if (pdata && pdata->num_mbc_cfgs) { if (control->pdata.num_mbc_cfgs) {
struct wm8958_mbc_cfg *cfg struct wm8958_mbc_cfg *cfg
= &pdata->mbc_cfgs[wm8994->mbc_cfg]; = &control->pdata.mbc_cfgs[wm8994->mbc_cfg];
for (i = 0; i < ARRAY_SIZE(cfg->combined_regs); i++) for (i = 0; i < ARRAY_SIZE(cfg->combined_regs); i++)
snd_soc_write(codec, i + 0x2800, snd_soc_write(codec, i + 0x2800,
cfg->combined_regs[i]); cfg->combined_regs[i]);
} }
if (pdata && pdata->num_vss_cfgs) { if (control->pdata.num_vss_cfgs) {
struct wm8958_vss_cfg *cfg struct wm8958_vss_cfg *cfg
= &pdata->vss_cfgs[wm8994->vss_cfg]; = &control->pdata.vss_cfgs[wm8994->vss_cfg];
for (i = 0; i < ARRAY_SIZE(cfg->regs); i++) for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
snd_soc_write(codec, i + 0x2600, cfg->regs[i]); snd_soc_write(codec, i + 0x2600, cfg->regs[i]);
} }
if (pdata && pdata->num_vss_hpf_cfgs) { if (control->pdata.num_vss_hpf_cfgs) {
struct wm8958_vss_hpf_cfg *cfg struct wm8958_vss_hpf_cfg *cfg
= &pdata->vss_hpf_cfgs[wm8994->vss_hpf_cfg]; = &control->pdata.vss_hpf_cfgs[wm8994->vss_hpf_cfg];
for (i = 0; i < ARRAY_SIZE(cfg->regs); i++) for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
snd_soc_write(codec, i + 0x2400, cfg->regs[i]); snd_soc_write(codec, i + 0x2400, cfg->regs[i]);
...@@ -300,7 +300,7 @@ static void wm8958_dsp_start_vss(struct snd_soc_codec *codec, int path) ...@@ -300,7 +300,7 @@ static void wm8958_dsp_start_vss(struct snd_soc_codec *codec, int path)
static void wm8958_dsp_start_enh_eq(struct snd_soc_codec *codec, int path) static void wm8958_dsp_start_enh_eq(struct snd_soc_codec *codec, int path)
{ {
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994_pdata *pdata = wm8994->pdata; struct wm8994 *control = wm8994->wm8994;
int i; int i;
wm8958_dsp2_fw(codec, "ENH_EQ", wm8994->enh_eq, false); wm8958_dsp2_fw(codec, "ENH_EQ", wm8994->enh_eq, false);
...@@ -309,9 +309,9 @@ static void wm8958_dsp_start_enh_eq(struct snd_soc_codec *codec, int path) ...@@ -309,9 +309,9 @@ static void wm8958_dsp_start_enh_eq(struct snd_soc_codec *codec, int path)
WM8958_DSP2_ENA, WM8958_DSP2_ENA); WM8958_DSP2_ENA, WM8958_DSP2_ENA);
/* If we've got user supplied settings use them */ /* If we've got user supplied settings use them */
if (pdata && pdata->num_enh_eq_cfgs) { if (control->pdata.num_enh_eq_cfgs) {
struct wm8958_enh_eq_cfg *cfg struct wm8958_enh_eq_cfg *cfg
= &pdata->enh_eq_cfgs[wm8994->enh_eq_cfg]; = &control->pdata.enh_eq_cfgs[wm8994->enh_eq_cfg];
for (i = 0; i < ARRAY_SIZE(cfg->regs); i++) for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
snd_soc_write(codec, i + 0x2200, snd_soc_write(codec, i + 0x2200,
...@@ -458,7 +458,7 @@ static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol, ...@@ -458,7 +458,7 @@ static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
{ {
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994_pdata *pdata = wm8994->pdata; struct wm8994 *control = wm8994->wm8994;
int value = ucontrol->value.integer.value[0]; int value = ucontrol->value.integer.value[0];
int reg; int reg;
...@@ -467,7 +467,7 @@ static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol, ...@@ -467,7 +467,7 @@ static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
if (reg < 0 || reg & WM8958_DSP2CLK_ENA) if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
return -EBUSY; return -EBUSY;
if (value >= pdata->num_mbc_cfgs) if (value >= control->pdata.num_mbc_cfgs)
return -EINVAL; return -EINVAL;
wm8994->mbc_cfg = value; wm8994->mbc_cfg = value;
...@@ -548,7 +548,7 @@ static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol, ...@@ -548,7 +548,7 @@ static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol,
{ {
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994_pdata *pdata = wm8994->pdata; struct wm8994 *control = wm8994->wm8994;
int value = ucontrol->value.integer.value[0]; int value = ucontrol->value.integer.value[0];
int reg; int reg;
...@@ -557,7 +557,7 @@ static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol, ...@@ -557,7 +557,7 @@ static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol,
if (reg < 0 || reg & WM8958_DSP2CLK_ENA) if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
return -EBUSY; return -EBUSY;
if (value >= pdata->num_vss_cfgs) if (value >= control->pdata.num_vss_cfgs)
return -EINVAL; return -EINVAL;
wm8994->vss_cfg = value; wm8994->vss_cfg = value;
...@@ -581,7 +581,7 @@ static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol, ...@@ -581,7 +581,7 @@ static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol,
{ {
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994_pdata *pdata = wm8994->pdata; struct wm8994 *control = wm8994->wm8994;
int value = ucontrol->value.integer.value[0]; int value = ucontrol->value.integer.value[0];
int reg; int reg;
...@@ -590,7 +590,7 @@ static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol, ...@@ -590,7 +590,7 @@ static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol,
if (reg < 0 || reg & WM8958_DSP2CLK_ENA) if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
return -EBUSY; return -EBUSY;
if (value >= pdata->num_vss_hpf_cfgs) if (value >= control->pdata.num_vss_hpf_cfgs)
return -EINVAL; return -EINVAL;
wm8994->vss_hpf_cfg = value; wm8994->vss_hpf_cfg = value;
...@@ -748,7 +748,7 @@ static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol, ...@@ -748,7 +748,7 @@ static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol,
{ {
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994_pdata *pdata = wm8994->pdata; struct wm8994 *control = wm8994->wm8994;
int value = ucontrol->value.integer.value[0]; int value = ucontrol->value.integer.value[0];
int reg; int reg;
...@@ -757,7 +757,7 @@ static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol, ...@@ -757,7 +757,7 @@ static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol,
if (reg < 0 || reg & WM8958_DSP2CLK_ENA) if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
return -EBUSY; return -EBUSY;
if (value >= pdata->num_enh_eq_cfgs) if (value >= control->pdata.num_enh_eq_cfgs)
return -EINVAL; return -EINVAL;
wm8994->enh_eq_cfg = value; wm8994->enh_eq_cfg = value;
...@@ -883,13 +883,6 @@ static void wm8958_mbc_vss_loaded(const struct firmware *fw, void *context) ...@@ -883,13 +883,6 @@ static void wm8958_mbc_vss_loaded(const struct firmware *fw, void *context)
wm8994->mbc_vss = fw; wm8994->mbc_vss = fw;
mutex_unlock(&codec->mutex); mutex_unlock(&codec->mutex);
} }
/* We can't have more than one request outstanding at once so
* we daisy chain.
*/
request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
"wm8958_enh_eq.wfw", codec->dev, GFP_KERNEL,
codec, wm8958_enh_eq_loaded);
} }
static void wm8958_mbc_loaded(const struct firmware *fw, void *context) static void wm8958_mbc_loaded(const struct firmware *fw, void *context)
...@@ -897,25 +890,18 @@ static void wm8958_mbc_loaded(const struct firmware *fw, void *context) ...@@ -897,25 +890,18 @@ static void wm8958_mbc_loaded(const struct firmware *fw, void *context)
struct snd_soc_codec *codec = context; struct snd_soc_codec *codec = context;
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
if (wm8958_dsp2_fw(codec, "MBC", fw, true) != 0) if (fw && (wm8958_dsp2_fw(codec, "MBC", fw, true) == 0)) {
return; mutex_lock(&codec->mutex);
wm8994->mbc = fw;
mutex_lock(&codec->mutex); mutex_unlock(&codec->mutex);
wm8994->mbc = fw; }
mutex_unlock(&codec->mutex);
/* We can't have more than one request outstanding at once so
* we daisy chain.
*/
request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
"wm8958_mbc_vss.wfw", codec->dev, GFP_KERNEL,
codec, wm8958_mbc_vss_loaded);
} }
void wm8958_dsp2_init(struct snd_soc_codec *codec) void wm8958_dsp2_init(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_pdata *pdata = wm8994->pdata; struct wm8994 *control = wm8994->wm8994;
struct wm8994_pdata *pdata = &control->pdata;
int ret, i; int ret, i;
wm8994->dsp_active = -1; wm8994->dsp_active = -1;
...@@ -932,9 +918,12 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) ...@@ -932,9 +918,12 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
"wm8958_mbc.wfw", codec->dev, GFP_KERNEL, "wm8958_mbc.wfw", codec->dev, GFP_KERNEL,
codec, wm8958_mbc_loaded); codec, wm8958_mbc_loaded);
request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
if (!pdata) "wm8958_mbc_vss.wfw", codec->dev, GFP_KERNEL,
return; codec, wm8958_mbc_vss_loaded);
request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
"wm8958_enh_eq.wfw", codec->dev, GFP_KERNEL,
codec, wm8958_enh_eq_loaded);
if (pdata->num_mbc_cfgs) { if (pdata->num_mbc_cfgs) {
struct snd_kcontrol_new control[] = { struct snd_kcontrol_new control[] = {
......
...@@ -91,8 +91,6 @@ static int wm8994_retune_mobile_base[] = { ...@@ -91,8 +91,6 @@ static int wm8994_retune_mobile_base[] = {
WM8994_AIF2_EQ_GAINS_1, WM8994_AIF2_EQ_GAINS_1,
}; };
static void wm8958_default_micdet(u16 status, void *data);
static const struct wm8958_micd_rate micdet_rates[] = { static const struct wm8958_micd_rate micdet_rates[] = {
{ 32768, true, 1, 4 }, { 32768, true, 1, 4 },
{ 32768, false, 1, 1 }, { 32768, false, 1, 1 },
...@@ -110,15 +108,12 @@ static const struct wm8958_micd_rate jackdet_rates[] = { ...@@ -110,15 +108,12 @@ static const struct wm8958_micd_rate jackdet_rates[] = {
static void wm8958_micd_set_rate(struct snd_soc_codec *codec) static void wm8958_micd_set_rate(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 best, i, sysclk, val; int best, i, sysclk, val;
bool idle; bool idle;
const struct wm8958_micd_rate *rates; const struct wm8958_micd_rate *rates;
int num_rates; int num_rates;
if (!(wm8994->pdata && wm8994->pdata->micd_rates) &&
wm8994->jack_cb != wm8958_default_micdet)
return;
idle = !wm8994->jack_mic; idle = !wm8994->jack_mic;
sysclk = snd_soc_read(codec, WM8994_CLOCKING_1); sysclk = snd_soc_read(codec, WM8994_CLOCKING_1);
...@@ -127,9 +122,9 @@ static void wm8958_micd_set_rate(struct snd_soc_codec *codec) ...@@ -127,9 +122,9 @@ static void wm8958_micd_set_rate(struct snd_soc_codec *codec)
else else
sysclk = wm8994->aifclk[0]; sysclk = wm8994->aifclk[0];
if (wm8994->pdata && wm8994->pdata->micd_rates) { if (control->pdata.micd_rates) {
rates = wm8994->pdata->micd_rates; rates = control->pdata.micd_rates;
num_rates = wm8994->pdata->num_micd_rates; num_rates = control->pdata.num_micd_rates;
} else if (wm8994->jackdet) { } else if (wm8994->jackdet) {
rates = jackdet_rates; rates = jackdet_rates;
num_rates = ARRAY_SIZE(jackdet_rates); num_rates = ARRAY_SIZE(jackdet_rates);
...@@ -326,7 +321,8 @@ static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol, ...@@ -326,7 +321,8 @@ static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol,
static void wm8994_set_drc(struct snd_soc_codec *codec, int drc) static void wm8994_set_drc(struct snd_soc_codec *codec, int drc)
{ {
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994_pdata *pdata = wm8994->pdata; struct wm8994 *control = wm8994->wm8994;
struct wm8994_pdata *pdata = &control->pdata;
int base = wm8994_drc_base[drc]; int base = wm8994_drc_base[drc];
int cfg = wm8994->drc_cfg[drc]; int cfg = wm8994->drc_cfg[drc];
int save, i; int save, i;
...@@ -362,7 +358,8 @@ static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol, ...@@ -362,7 +358,8 @@ static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol,
{ {
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994_pdata *pdata = wm8994->pdata; struct wm8994 *control = wm8994->wm8994;
struct wm8994_pdata *pdata = &control->pdata;
int drc = wm8994_get_drc(kcontrol->id.name); int drc = wm8994_get_drc(kcontrol->id.name);
int value = ucontrol->value.integer.value[0]; int value = ucontrol->value.integer.value[0];
...@@ -394,7 +391,8 @@ static int wm8994_get_drc_enum(struct snd_kcontrol *kcontrol, ...@@ -394,7 +391,8 @@ static int wm8994_get_drc_enum(struct snd_kcontrol *kcontrol,
static void wm8994_set_retune_mobile(struct snd_soc_codec *codec, int block) static void wm8994_set_retune_mobile(struct snd_soc_codec *codec, int block)
{ {
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994_pdata *pdata = wm8994->pdata; struct wm8994 *control = wm8994->wm8994;
struct wm8994_pdata *pdata = &control->pdata;
int base = wm8994_retune_mobile_base[block]; int base = wm8994_retune_mobile_base[block];
int iface, best, best_val, save, i, cfg; int iface, best, best_val, save, i, cfg;
...@@ -465,7 +463,8 @@ static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, ...@@ -465,7 +463,8 @@ static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
{ {
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994_pdata *pdata = wm8994->pdata; struct wm8994 *control = wm8994->wm8994;
struct wm8994_pdata *pdata = &control->pdata;
int block = wm8994_get_retune_mobile_block(kcontrol->id.name); int block = wm8994_get_retune_mobile_block(kcontrol->id.name);
int value = ucontrol->value.integer.value[0]; int value = ucontrol->value.integer.value[0];
...@@ -736,7 +735,7 @@ static void wm1811_jackdet_set_mode(struct snd_soc_codec *codec, u16 mode) ...@@ -736,7 +735,7 @@ static void wm1811_jackdet_set_mode(struct snd_soc_codec *codec, u16 mode)
{ {
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
if (!wm8994->jackdet || !wm8994->jack_cb) if (!wm8994->jackdet || !wm8994->micdet[0].jack)
return; return;
if (wm8994->active_refcount) if (wm8994->active_refcount)
...@@ -862,7 +861,7 @@ static void vmid_reference(struct snd_soc_codec *codec) ...@@ -862,7 +861,7 @@ static void vmid_reference(struct snd_soc_codec *codec)
WM8994_BIAS_SRC | WM8994_BIAS_SRC |
WM8994_STARTUP_BIAS_ENA | WM8994_STARTUP_BIAS_ENA |
WM8994_VMID_BUF_ENA | WM8994_VMID_BUF_ENA |
(0x3 << WM8994_VMID_RAMP_SHIFT)); (0x2 << WM8994_VMID_RAMP_SHIFT));
/* Main bias enable, VMID=2x40k */ /* Main bias enable, VMID=2x40k */
snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
...@@ -870,7 +869,7 @@ static void vmid_reference(struct snd_soc_codec *codec) ...@@ -870,7 +869,7 @@ static void vmid_reference(struct snd_soc_codec *codec)
WM8994_VMID_SEL_MASK, WM8994_VMID_SEL_MASK,
WM8994_BIAS_ENA | 0x2); WM8994_BIAS_ENA | 0x2);
msleep(50); msleep(300);
snd_soc_update_bits(codec, WM8994_ANTIPOP_2, snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
WM8994_VMID_RAMP_MASK | WM8994_VMID_RAMP_MASK |
...@@ -939,16 +938,10 @@ static void vmid_dereference(struct snd_soc_codec *codec) ...@@ -939,16 +938,10 @@ static void vmid_dereference(struct snd_soc_codec *codec)
WM8994_BIAS_SRC | WM8994_BIAS_SRC |
WM8994_VMID_DISCH); WM8994_VMID_DISCH);
switch (wm8994->vmid_mode) { snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
case WM8994_VMID_FORCE: WM8994_VMID_SEL_MASK, 0);
msleep(350);
break;
default:
break;
}
snd_soc_update_bits(codec, WM8994_ADDITIONAL_CONTROL, msleep(400);
WM8994_VROI, WM8994_VROI);
/* Active discharge */ /* Active discharge */
snd_soc_update_bits(codec, WM8994_ANTIPOP_1, snd_soc_update_bits(codec, WM8994_ANTIPOP_1,
...@@ -957,17 +950,12 @@ static void vmid_dereference(struct snd_soc_codec *codec) ...@@ -957,17 +950,12 @@ static void vmid_dereference(struct snd_soc_codec *codec)
WM8994_LINEOUT1_DISCH | WM8994_LINEOUT1_DISCH |
WM8994_LINEOUT2_DISCH); WM8994_LINEOUT2_DISCH);
msleep(150);
snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_3, snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_3,
WM8994_LINEOUT1N_ENA | WM8994_LINEOUT1N_ENA |
WM8994_LINEOUT1P_ENA | WM8994_LINEOUT1P_ENA |
WM8994_LINEOUT2N_ENA | WM8994_LINEOUT2N_ENA |
WM8994_LINEOUT2P_ENA, 0); WM8994_LINEOUT2P_ENA, 0);
snd_soc_update_bits(codec, WM8994_ADDITIONAL_CONTROL,
WM8994_VROI, 0);
/* Switch off startup biases */ /* Switch off startup biases */
snd_soc_update_bits(codec, WM8994_ANTIPOP_2, snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
WM8994_BIAS_SRC | WM8994_BIAS_SRC |
...@@ -976,10 +964,7 @@ static void vmid_dereference(struct snd_soc_codec *codec) ...@@ -976,10 +964,7 @@ static void vmid_dereference(struct snd_soc_codec *codec)
WM8994_VMID_RAMP_MASK, 0); WM8994_VMID_RAMP_MASK, 0);
snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
WM8994_BIAS_ENA | WM8994_VMID_SEL_MASK, 0); WM8994_VMID_SEL_MASK, 0);
snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
WM8994_VMID_RAMP_MASK, 0);
} }
pm_runtime_put(codec->dev); pm_runtime_put(codec->dev);
...@@ -2277,6 +2262,18 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, ...@@ -2277,6 +2262,18 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
configure_clock(codec); configure_clock(codec);
/*
* If SYSCLK will be less than 50kHz adjust AIFnCLK dividers
* for detection.
*/
if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) {
dev_dbg(codec->dev, "Configuring AIFs for 128fs\n");
snd_soc_update_bits(codec, WM8994_AIF1_RATE,
WM8994_AIF1CLK_RATE_MASK, 0x1);
snd_soc_update_bits(codec, WM8994_AIF2_RATE,
WM8994_AIF2CLK_RATE_MASK, 0x1);
}
return 0; return 0;
} }
...@@ -2365,6 +2362,18 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, ...@@ -2365,6 +2362,18 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
configure_clock(codec); configure_clock(codec);
/*
* If SYSCLK will be less than 50kHz adjust AIFnCLK dividers
* for detection.
*/
if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) {
dev_dbg(codec->dev, "Configuring AIFs for 128fs\n");
snd_soc_update_bits(codec, WM8994_AIF1_RATE,
WM8994_AIF1CLK_RATE_MASK, 0x1);
snd_soc_update_bits(codec, WM8994_AIF2_RATE,
WM8994_AIF2CLK_RATE_MASK, 0x1);
}
return 0; return 0;
} }
...@@ -3082,7 +3091,8 @@ static int wm8994_codec_resume(struct snd_soc_codec *codec) ...@@ -3082,7 +3091,8 @@ static int wm8994_codec_resume(struct snd_soc_codec *codec)
static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994) static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
{ {
struct snd_soc_codec *codec = wm8994->hubs.codec; struct snd_soc_codec *codec = wm8994->hubs.codec;
struct wm8994_pdata *pdata = wm8994->pdata; struct wm8994 *control = wm8994->wm8994;
struct wm8994_pdata *pdata = &control->pdata;
struct snd_kcontrol_new controls[] = { struct snd_kcontrol_new controls[] = {
SOC_ENUM_EXT("AIF1.1 EQ Mode", SOC_ENUM_EXT("AIF1.1 EQ Mode",
wm8994->retune_mobile_enum, wm8994->retune_mobile_enum,
...@@ -3149,7 +3159,8 @@ static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994) ...@@ -3149,7 +3159,8 @@ static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
static void wm8994_handle_pdata(struct wm8994_priv *wm8994) static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
{ {
struct snd_soc_codec *codec = wm8994->hubs.codec; struct snd_soc_codec *codec = wm8994->hubs.codec;
struct wm8994_pdata *pdata = wm8994->pdata; struct wm8994 *control = wm8994->wm8994;
struct wm8994_pdata *pdata = &control->pdata;
int ret, i; int ret, i;
if (!pdata) if (!pdata)
...@@ -3389,38 +3400,80 @@ static irqreturn_t wm8994_mic_irq(int irq, void *data) ...@@ -3389,38 +3400,80 @@ static irqreturn_t wm8994_mic_irq(int irq, void *data)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
/* Default microphone detection handler for WM8958 - the user can static void wm1811_micd_stop(struct snd_soc_codec *codec)
* override this if they wish. {
*/ struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
static void wm8958_default_micdet(u16 status, void *data)
if (!wm8994->jackdet)
return;
mutex_lock(&wm8994->accdet_lock);
snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, WM8958_MICD_ENA, 0);
wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_JACK);
mutex_unlock(&wm8994->accdet_lock);
if (wm8994->wm8994->pdata.jd_ext_cap)
snd_soc_dapm_disable_pin(&codec->dapm,
"MICBIAS2");
}
static void wm8958_button_det(struct snd_soc_codec *codec, u16 status)
{ {
struct snd_soc_codec *codec = data;
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
int report; int report;
dev_dbg(codec->dev, "MICDET %x\n", status); report = 0;
if (status & 0x4)
report |= SND_JACK_BTN_0;
if (status & 0x8)
report |= SND_JACK_BTN_1;
if (status & 0x10)
report |= SND_JACK_BTN_2;
if (status & 0x20)
report |= SND_JACK_BTN_3;
if (status & 0x40)
report |= SND_JACK_BTN_4;
if (status & 0x80)
report |= SND_JACK_BTN_5;
snd_soc_jack_report(wm8994->micdet[0].jack, report,
wm8994->btn_mask);
}
static void wm8958_mic_id(void *data, u16 status)
{
struct snd_soc_codec *codec = data;
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
/* Either nothing present or just starting detection */ /* Either nothing present or just starting detection */
if (!(status & WM8958_MICD_STS)) { if (!(status & WM8958_MICD_STS)) {
if (!wm8994->jackdet) { /* 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->jack_mic = false; wm8994->mic_detecting = true;
wm8994->mic_detecting = true;
wm8958_micd_set_rate(codec); wm1811_micd_stop(codec);
snd_soc_jack_report(wm8994->micdet[0].jack, 0, wm8958_micd_set_rate(codec);
wm8994->btn_mask |
SND_JACK_HEADSET); snd_soc_jack_report(wm8994->micdet[0].jack, 0,
} wm8994->btn_mask |
SND_JACK_HEADSET);
return; return;
} }
/* If the measurement is showing a high impedence we've got a /* If the measurement is showing a high impedence we've got a
* microphone. * microphone.
*/ */
if (wm8994->mic_detecting && (status & 0x600)) { if (status & 0x600) {
dev_dbg(codec->dev, "Detected microphone\n"); dev_dbg(codec->dev, "Detected microphone\n");
wm8994->mic_detecting = false; wm8994->mic_detecting = false;
...@@ -3433,64 +3486,67 @@ static void wm8958_default_micdet(u16 status, void *data) ...@@ -3433,64 +3486,67 @@ static void wm8958_default_micdet(u16 status, void *data)
} }
if (wm8994->mic_detecting && status & 0xfc) { if (status & 0xfc) {
dev_dbg(codec->dev, "Detected headphone\n"); dev_dbg(codec->dev, "Detected headphone\n");
wm8994->mic_detecting = false; wm8994->mic_detecting = false;
wm8958_micd_set_rate(codec); wm8958_micd_set_rate(codec);
/* If we have jackdet that will detect removal */ /* If we have jackdet that will detect removal */
if (wm8994->jackdet) { wm1811_micd_stop(codec);
mutex_lock(&wm8994->accdet_lock);
snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
WM8958_MICD_ENA, 0);
wm1811_jackdet_set_mode(codec,
WM1811_JACKDET_MODE_JACK);
mutex_unlock(&wm8994->accdet_lock);
if (wm8994->pdata->jd_ext_cap)
snd_soc_dapm_disable_pin(&codec->dapm,
"MICBIAS2");
}
snd_soc_jack_report(wm8994->micdet[0].jack, SND_JACK_HEADPHONE, snd_soc_jack_report(wm8994->micdet[0].jack, SND_JACK_HEADPHONE,
SND_JACK_HEADSET); SND_JACK_HEADSET);
} }
}
/* Report short circuit as a button */ /* Deferred mic detection to allow for extra settling time */
if (wm8994->jack_mic) { static void wm1811_mic_work(struct work_struct *work)
report = 0; {
if (status & 0x4) struct wm8994_priv *wm8994 = container_of(work, struct wm8994_priv,
report |= SND_JACK_BTN_0; mic_work.work);
struct wm8994 *control = wm8994->wm8994;
struct snd_soc_codec *codec = wm8994->hubs.codec;
if (status & 0x8) pm_runtime_get_sync(codec->dev);
report |= SND_JACK_BTN_1;
if (status & 0x10) /* If required for an external cap force MICBIAS on */
report |= SND_JACK_BTN_2; if (control->pdata.jd_ext_cap) {
snd_soc_dapm_force_enable_pin(&codec->dapm,
"MICBIAS2");
snd_soc_dapm_sync(&codec->dapm);
}
if (status & 0x20) mutex_lock(&wm8994->accdet_lock);
report |= SND_JACK_BTN_3;
if (status & 0x40) dev_dbg(codec->dev, "Starting mic detection\n");
report |= SND_JACK_BTN_4;
if (status & 0x80) /* Use a user-supplied callback if we have one */
report |= SND_JACK_BTN_5; if (wm8994->micd_cb) {
wm8994->micd_cb(wm8994->micd_cb_data);
} else {
/*
* Start off measument of microphone impedence to find out
* what's actually there.
*/
wm8994->mic_detecting = true;
wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_MIC);
snd_soc_jack_report(wm8994->micdet[0].jack, report, snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
wm8994->btn_mask); WM8958_MICD_ENA, WM8958_MICD_ENA);
} }
mutex_unlock(&wm8994->accdet_lock);
pm_runtime_put(codec->dev);
} }
static irqreturn_t wm1811_jackdet_irq(int irq, void *data) static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
{ {
struct wm8994_priv *wm8994 = data; struct wm8994_priv *wm8994 = data;
struct wm8994 *control = wm8994->wm8994;
struct snd_soc_codec *codec = wm8994->hubs.codec; struct snd_soc_codec *codec = wm8994->hubs.codec;
int reg; int reg, delay;
bool present; bool present;
pm_runtime_get_sync(codec->dev); pm_runtime_get_sync(codec->dev);
...@@ -3521,18 +3577,14 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data) ...@@ -3521,18 +3577,14 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
snd_soc_update_bits(codec, WM1811_JACKDET_CTRL, snd_soc_update_bits(codec, WM1811_JACKDET_CTRL,
WM1811_JACKDET_DB, 0); WM1811_JACKDET_DB, 0);
/* delay = control->pdata.micdet_delay;
* Start off measument of microphone impedence to find schedule_delayed_work(&wm8994->mic_work,
* out what's actually there. msecs_to_jiffies(delay));
*/
wm8994->mic_detecting = true;
wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_MIC);
snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
WM8958_MICD_ENA, WM8958_MICD_ENA);
} else { } else {
dev_dbg(codec->dev, "Jack not detected\n"); dev_dbg(codec->dev, "Jack not detected\n");
cancel_delayed_work_sync(&wm8994->mic_work);
snd_soc_update_bits(codec, WM8958_MICBIAS2, snd_soc_update_bits(codec, WM8958_MICBIAS2,
WM8958_MICB2_DISCH, WM8958_MICB2_DISCH); WM8958_MICB2_DISCH, WM8958_MICB2_DISCH);
...@@ -3549,14 +3601,9 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data) ...@@ -3549,14 +3601,9 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
mutex_unlock(&wm8994->accdet_lock); mutex_unlock(&wm8994->accdet_lock);
/* If required for an external cap force MICBIAS on */ /* Turn off MICBIAS if it was on for an external cap */
if (wm8994->pdata->jd_ext_cap) { if (control->pdata.jd_ext_cap && !present)
if (present) snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS2");
snd_soc_dapm_force_enable_pin(&codec->dapm,
"MICBIAS2");
else
snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS2");
}
if (present) if (present)
snd_soc_jack_report(wm8994->micdet[0].jack, snd_soc_jack_report(wm8994->micdet[0].jack,
...@@ -3599,7 +3646,8 @@ static void wm1811_jackdet_bootstrap(struct work_struct *work) ...@@ -3599,7 +3646,8 @@ static void wm1811_jackdet_bootstrap(struct work_struct *work)
* detection algorithm. * detection algorithm.
*/ */
int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
wm8958_micdet_cb cb, void *cb_data) wm1811_micdet_cb det_cb, void *det_cb_data,
wm1811_mic_id_cb id_cb, void *id_cb_data)
{ {
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; struct wm8994 *control = wm8994->wm8994;
...@@ -3614,27 +3662,32 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, ...@@ -3614,27 +3662,32 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
} }
if (jack) { if (jack) {
if (!cb) {
dev_dbg(codec->dev, "Using default micdet callback\n");
cb = wm8958_default_micdet;
cb_data = codec;
}
snd_soc_dapm_force_enable_pin(&codec->dapm, "CLK_SYS"); snd_soc_dapm_force_enable_pin(&codec->dapm, "CLK_SYS");
snd_soc_dapm_sync(&codec->dapm); snd_soc_dapm_sync(&codec->dapm);
wm8994->micdet[0].jack = jack; wm8994->micdet[0].jack = jack;
wm8994->jack_cb = cb;
wm8994->jack_cb_data = cb_data;
wm8994->mic_detecting = true; if (det_cb) {
wm8994->jack_mic = false; wm8994->micd_cb = det_cb;
wm8994->micd_cb_data = det_cb_data;
} else {
wm8994->mic_detecting = true;
wm8994->jack_mic = false;
}
if (id_cb) {
wm8994->mic_id_cb = id_cb;
wm8994->mic_id_cb_data = id_cb_data;
} else {
wm8994->mic_id_cb = wm8958_mic_id;
wm8994->mic_id_cb_data = codec;
}
wm8958_micd_set_rate(codec); wm8958_micd_set_rate(codec);
/* Detect microphones and short circuits by default */ /* Detect microphones and short circuits by default */
if (wm8994->pdata->micd_lvl_sel) if (control->pdata.micd_lvl_sel)
micd_lvl_sel = wm8994->pdata->micd_lvl_sel; micd_lvl_sel = control->pdata.micd_lvl_sel;
else else
micd_lvl_sel = 0x41; micd_lvl_sel = 0x41;
...@@ -3728,10 +3781,22 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) ...@@ -3728,10 +3781,22 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
trace_snd_soc_jack_irq(dev_name(codec->dev)); trace_snd_soc_jack_irq(dev_name(codec->dev));
#endif #endif
if (wm8994->jack_cb) /* Avoid a transient report when the accessory is being removed */
wm8994->jack_cb(reg, wm8994->jack_cb_data); if (wm8994->jackdet) {
reg = snd_soc_read(codec, WM1811_JACKDET_CTRL);
if (reg < 0) {
dev_err(codec->dev, "Failed to read jack status: %d\n",
reg);
} else if (!(reg & WM1811_JACKDET_LVL)) {
dev_dbg(codec->dev, "Ignoring removed jack\n");
return IRQ_HANDLED;
}
}
if (wm8994->mic_detecting)
wm8994->mic_id_cb(wm8994->mic_id_cb_data, reg);
else else
dev_warn(codec->dev, "Accessory detection with no callback\n"); wm8958_button_det(codec, reg);
out: out:
pm_runtime_put(codec->dev); pm_runtime_put(codec->dev);
...@@ -3779,15 +3844,24 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) ...@@ -3779,15 +3844,24 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP); snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
mutex_init(&wm8994->accdet_lock); mutex_init(&wm8994->accdet_lock);
INIT_DELAYED_WORK(&wm8994->mic_work, wm8994_mic_work);
INIT_DELAYED_WORK(&wm8994->jackdet_bootstrap, INIT_DELAYED_WORK(&wm8994->jackdet_bootstrap,
wm1811_jackdet_bootstrap); wm1811_jackdet_bootstrap);
switch (control->type) {
case WM8994:
INIT_DELAYED_WORK(&wm8994->mic_work, wm8994_mic_work);
break;
case WM1811:
INIT_DELAYED_WORK(&wm8994->mic_work, wm1811_mic_work);
break;
default:
break;
}
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]);
if (wm8994->pdata && wm8994->pdata->micdet_irq) wm8994->micdet_irq = control->pdata.micdet_irq;
wm8994->micdet_irq = wm8994->pdata->micdet_irq;
pm_runtime_enable(codec->dev); pm_runtime_enable(codec->dev);
pm_runtime_idle(codec->dev); pm_runtime_idle(codec->dev);
...@@ -3800,8 +3874,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) ...@@ -3800,8 +3874,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
switch (control->type) { switch (control->type) {
case WM8994: case WM8994:
/* Single ended line outputs should have VMID on. */ /* Single ended line outputs should have VMID on. */
if (!wm8994->pdata->lineout1_diff || if (!control->pdata.lineout1_diff ||
!wm8994->pdata->lineout2_diff) !control->pdata.lineout2_diff)
codec->dapm.idle_bias_off = 0; codec->dapm.idle_bias_off = 0;
switch (wm8994->revision) { switch (wm8994->revision) {
...@@ -3839,20 +3913,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) ...@@ -3839,20 +3913,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
wm8994->hubs.no_cache_dac_hp_direct = true; wm8994->hubs.no_cache_dac_hp_direct = true;
wm8994->fll_byp = true; wm8994->fll_byp = true;
switch (control->cust_id) { wm8994->hubs.dcs_codes_l = -9;
case 0: wm8994->hubs.dcs_codes_r = -7;
case 2:
wm8994->hubs.dcs_codes_l = -9;
wm8994->hubs.dcs_codes_r = -7;
break;
case 1:
case 3:
wm8994->hubs.dcs_codes_l = -8;
wm8994->hubs.dcs_codes_r = -7;
break;
default:
break;
}
snd_soc_update_bits(codec, WM8994_ANALOGUE_HP_1, snd_soc_update_bits(codec, WM8994_ANALOGUE_HP_1,
WM1811_HPOUT1_ATTN, WM1811_HPOUT1_ATTN); WM1811_HPOUT1_ATTN, WM1811_HPOUT1_ATTN);
...@@ -4236,7 +4298,6 @@ static int __devinit wm8994_probe(struct platform_device *pdev) ...@@ -4236,7 +4298,6 @@ static int __devinit wm8994_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, wm8994); platform_set_drvdata(pdev, wm8994);
wm8994->wm8994 = dev_get_drvdata(pdev->dev.parent); wm8994->wm8994 = dev_get_drvdata(pdev->dev.parent);
wm8994->pdata = dev_get_platdata(pdev->dev.parent);
return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8994, return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8994,
wm8994_dai, ARRAY_SIZE(wm8994_dai)); wm8994_dai, ARRAY_SIZE(wm8994_dai));
...@@ -4266,7 +4327,7 @@ static int wm8994_resume(struct device *dev) ...@@ -4266,7 +4327,7 @@ static int wm8994_resume(struct device *dev)
{ {
struct wm8994_priv *wm8994 = dev_get_drvdata(dev); struct wm8994_priv *wm8994 = dev_get_drvdata(dev);
if (wm8994->jackdet && wm8994->jack_cb) if (wm8994->jackdet && wm8994->jackdet_mode)
regmap_update_bits(wm8994->wm8994->regmap, WM8994_ANTIPOP_2, regmap_update_bits(wm8994->wm8994->regmap, WM8994_ANTIPOP_2,
WM1811_JACKDET_MODE_MASK, WM1811_JACKDET_MODE_MASK,
WM1811_JACKDET_MODE_AUDIO); WM1811_JACKDET_MODE_AUDIO);
......
...@@ -39,12 +39,14 @@ enum wm8994_vmid_mode { ...@@ -39,12 +39,14 @@ enum wm8994_vmid_mode {
WM8994_VMID_FORCE, WM8994_VMID_FORCE,
}; };
typedef void (*wm8958_micdet_cb)(u16 status, void *data); typedef void (*wm1811_micdet_cb)(void *data);
typedef void (*wm1811_mic_id_cb)(void *data, u16 status);
int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
int micbias); int micbias);
int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
wm8958_micdet_cb cb, void *cb_data); wm1811_micdet_cb cb, void *det_cb_data,
wm1811_mic_id_cb id_cb, void *id_cb_data);
int wm8994_vmid_mode(struct snd_soc_codec *codec, enum wm8994_vmid_mode mode); int wm8994_vmid_mode(struct snd_soc_codec *codec, enum wm8994_vmid_mode mode);
...@@ -138,12 +140,13 @@ struct wm8994_priv { ...@@ -138,12 +140,13 @@ struct wm8994_priv {
int jackdet_mode; int jackdet_mode;
struct delayed_work jackdet_bootstrap; struct delayed_work jackdet_bootstrap;
wm8958_micdet_cb jack_cb;
void *jack_cb_data;
int micdet_irq; int micdet_irq;
wm1811_micdet_cb micd_cb;
void *micd_cb_data;
wm1811_mic_id_cb mic_id_cb;
void *mic_id_cb_data;
int revision; int revision;
struct wm8994_pdata *pdata;
unsigned int aif1clk_enable:1; unsigned int aif1clk_enable:1;
unsigned int aif2clk_enable:1; unsigned int aif2clk_enable:1;
......
...@@ -270,7 +270,7 @@ static int littlemill_late_probe(struct snd_soc_card *card) ...@@ -270,7 +270,7 @@ static int littlemill_late_probe(struct snd_soc_card *card)
return ret; return ret;
/* This will check device compatibility itself */ /* This will check device compatibility itself */
wm8958_mic_detect(codec, &littlemill_headset, NULL, NULL); wm8958_mic_detect(codec, &littlemill_headset, NULL, NULL, NULL, NULL);
/* As will this */ /* As will this */
wm8994_mic_detect(codec, &littlemill_headset, 1); wm8994_mic_detect(codec, &littlemill_headset, 1);
......
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