diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 8fefc961ec0663ef4d8147e52058c942bb94a2df..45a20c573aa3d50ae026470fe53f65aeb1e71b37 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -401,13 +401,19 @@ static const __devinitconst struct reg_default wm1811_reva_patch[] = { */ 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; const struct reg_default *regmap_patch = NULL; const char *devname; int ret, i, patch_regs; 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); /* Add the on-chip regulators first for bootstrapping */ @@ -604,24 +610,21 @@ static __devinit int wm8994_device_init(struct wm8994 *wm8994, int irq) } } - if (pdata) { - wm8994->irq_base = pdata->irq_base; - wm8994->gpio_base = pdata->gpio_base; - - /* GPIO configuration is only applied if it's non-zero */ - for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) { - if (pdata->gpio_defaults[i]) { - wm8994_set_bits(wm8994, WM8994_GPIO_1 + i, - 0xffff, - pdata->gpio_defaults[i]); - } + wm8994->irq_base = pdata->irq_base; + wm8994->gpio_base = pdata->gpio_base; + + /* GPIO configuration is only applied if it's non-zero */ + for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) { + if (pdata->gpio_defaults[i]) { + wm8994_set_bits(wm8994, WM8994_GPIO_1 + 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) - pulls |= WM8994_SPKMODE_PU; - } + if (pdata->spkmode_pu) + pulls |= WM8994_SPKMODE_PU; /* Disable unneeded pulls */ wm8994_set_bits(wm8994, WM8994_PULL_CONTROL_2, diff --git a/include/linux/mfd/wm8994/core.h b/include/linux/mfd/wm8994/core.h index 1f173306bf0508ddeb3a18de8175fac44c857ee3..ae5c249530b4e7f527a22f44e242d4d4bce66419 100644 --- a/include/linux/mfd/wm8994/core.h +++ b/include/linux/mfd/wm8994/core.h @@ -19,6 +19,8 @@ #include #include +#include + enum wm8994_type { WM8994 = 0, WM8958 = 1, @@ -55,6 +57,8 @@ struct regulator_bulk_data; struct wm8994 { struct mutex irq_lock; + struct wm8994_pdata pdata; + enum wm8994_type type; int revision; int cust_id; diff --git a/include/linux/mfd/wm8994/pdata.h b/include/linux/mfd/wm8994/pdata.h index fc87be4fdc2501a8106b18664102c793ccdb588b..8e21a094836d21566bec6f08c027ad5c765fa715 100644 --- a/include/linux/mfd/wm8994/pdata.h +++ b/include/linux/mfd/wm8994/pdata.h @@ -176,6 +176,11 @@ struct wm8994_pdata { unsigned int lineout1fb: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 * signal. */ diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c index 00121ba3659718ab4c4af6ff5135373762de4765..b0710d817a65964dd5418502e366f310d36b6dd7 100644 --- a/sound/soc/codecs/wm8958-dsp2.c +++ b/sound/soc/codecs/wm8958-dsp2.c @@ -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) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; int i; /* 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) WM8958_DSP2_ENA, WM8958_DSP2_ENA); /* 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 - = &pdata->mbc_cfgs[wm8994->mbc_cfg]; + = &control->pdata.mbc_cfgs[wm8994->mbc_cfg]; for (i = 0; i < ARRAY_SIZE(cfg->coeff_regs); i++) 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) 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_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; int i, ena; if (wm8994->mbc_vss) @@ -249,26 +249,26 @@ static void wm8958_dsp_start_vss(struct snd_soc_codec *codec, int path) WM8958_DSP2_ENA, WM8958_DSP2_ENA); /* 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 - = &pdata->mbc_cfgs[wm8994->mbc_cfg]; + = &control->pdata.mbc_cfgs[wm8994->mbc_cfg]; for (i = 0; i < ARRAY_SIZE(cfg->combined_regs); i++) snd_soc_write(codec, i + 0x2800, cfg->combined_regs[i]); } - if (pdata && pdata->num_vss_cfgs) { + if (control->pdata.num_vss_cfgs) { 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++) 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 - = &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++) 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) 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_pdata *pdata = wm8994->pdata; + struct wm8994 *control = wm8994->wm8994; int i; 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) WM8958_DSP2_ENA, WM8958_DSP2_ENA); /* 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 - = &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++) snd_soc_write(codec, i + 0x2200, @@ -458,7 +458,7 @@ static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); 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 reg; @@ -467,7 +467,7 @@ static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol, if (reg < 0 || reg & WM8958_DSP2CLK_ENA) return -EBUSY; - if (value >= pdata->num_mbc_cfgs) + if (value >= control->pdata.num_mbc_cfgs) return -EINVAL; wm8994->mbc_cfg = value; @@ -548,7 +548,7 @@ static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); 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 reg; @@ -557,7 +557,7 @@ static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol, if (reg < 0 || reg & WM8958_DSP2CLK_ENA) return -EBUSY; - if (value >= pdata->num_vss_cfgs) + if (value >= control->pdata.num_vss_cfgs) return -EINVAL; wm8994->vss_cfg = value; @@ -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 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 reg; @@ -590,7 +590,7 @@ static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol, if (reg < 0 || reg & WM8958_DSP2CLK_ENA) return -EBUSY; - if (value >= pdata->num_vss_hpf_cfgs) + if (value >= control->pdata.num_vss_hpf_cfgs) return -EINVAL; wm8994->vss_hpf_cfg = value; @@ -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 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 reg; @@ -757,7 +757,7 @@ static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol, if (reg < 0 || reg & WM8958_DSP2CLK_ENA) return -EBUSY; - if (value >= pdata->num_enh_eq_cfgs) + if (value >= control->pdata.num_enh_eq_cfgs) return -EINVAL; wm8994->enh_eq_cfg = value; @@ -883,13 +883,6 @@ static void wm8958_mbc_vss_loaded(const struct firmware *fw, void *context) wm8994->mbc_vss = 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_enh_eq.wfw", codec->dev, GFP_KERNEL, - codec, wm8958_enh_eq_loaded); } 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 wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - if (wm8958_dsp2_fw(codec, "MBC", fw, true) != 0) - return; - - mutex_lock(&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); + if (fw && (wm8958_dsp2_fw(codec, "MBC", fw, true) == 0)) { + mutex_lock(&codec->mutex); + wm8994->mbc = fw; + mutex_unlock(&codec->mutex); + } } void wm8958_dsp2_init(struct snd_soc_codec *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; wm8994->dsp_active = -1; @@ -932,9 +918,12 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, "wm8958_mbc.wfw", codec->dev, GFP_KERNEL, codec, wm8958_mbc_loaded); - - if (!pdata) - return; + request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + "wm8958_mbc_vss.wfw", codec->dev, GFP_KERNEL, + 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) { struct snd_kcontrol_new control[] = { diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index b2b2b37131bddc4acfb8fb0e51a9bba220da9907..60b34ff8179b032bd87b520cd8280b0f8b05cd63 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -91,8 +91,6 @@ static int wm8994_retune_mobile_base[] = { WM8994_AIF2_EQ_GAINS_1, }; -static void wm8958_default_micdet(u16 status, void *data); - static const struct wm8958_micd_rate micdet_rates[] = { { 32768, true, 1, 4 }, { 32768, false, 1, 1 }, @@ -110,15 +108,12 @@ static const struct wm8958_micd_rate jackdet_rates[] = { static void wm8958_micd_set_rate(struct snd_soc_codec *codec) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + struct wm8994 *control = wm8994->wm8994; int best, i, sysclk, val; bool idle; const struct wm8958_micd_rate *rates; int num_rates; - if (!(wm8994->pdata && wm8994->pdata->micd_rates) && - wm8994->jack_cb != wm8958_default_micdet) - return; - idle = !wm8994->jack_mic; sysclk = snd_soc_read(codec, WM8994_CLOCKING_1); @@ -127,9 +122,9 @@ static void wm8958_micd_set_rate(struct snd_soc_codec *codec) else sysclk = wm8994->aifclk[0]; - if (wm8994->pdata && wm8994->pdata->micd_rates) { - rates = wm8994->pdata->micd_rates; - num_rates = wm8994->pdata->num_micd_rates; + if (control->pdata.micd_rates) { + rates = control->pdata.micd_rates; + num_rates = control->pdata.num_micd_rates; } else if (wm8994->jackdet) { rates = jackdet_rates; num_rates = ARRAY_SIZE(jackdet_rates); @@ -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) { 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 cfg = wm8994->drc_cfg[drc]; int save, i; @@ -362,7 +358,8 @@ static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); 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 value = ucontrol->value.integer.value[0]; @@ -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) { 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 iface, best, best_val, save, i, cfg; @@ -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 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 value = ucontrol->value.integer.value[0]; @@ -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); - if (!wm8994->jackdet || !wm8994->jack_cb) + if (!wm8994->jackdet || !wm8994->micdet[0].jack) return; if (wm8994->active_refcount) @@ -862,7 +861,7 @@ static void vmid_reference(struct snd_soc_codec *codec) WM8994_BIAS_SRC | WM8994_STARTUP_BIAS_ENA | WM8994_VMID_BUF_ENA | - (0x3 << WM8994_VMID_RAMP_SHIFT)); + (0x2 << WM8994_VMID_RAMP_SHIFT)); /* Main bias enable, VMID=2x40k */ snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, @@ -870,7 +869,7 @@ static void vmid_reference(struct snd_soc_codec *codec) WM8994_VMID_SEL_MASK, WM8994_BIAS_ENA | 0x2); - msleep(50); + msleep(300); snd_soc_update_bits(codec, WM8994_ANTIPOP_2, WM8994_VMID_RAMP_MASK | @@ -939,16 +938,10 @@ static void vmid_dereference(struct snd_soc_codec *codec) WM8994_BIAS_SRC | WM8994_VMID_DISCH); - switch (wm8994->vmid_mode) { - case WM8994_VMID_FORCE: - msleep(350); - break; - default: - break; - } + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, + WM8994_VMID_SEL_MASK, 0); - snd_soc_update_bits(codec, WM8994_ADDITIONAL_CONTROL, - WM8994_VROI, WM8994_VROI); + msleep(400); /* Active discharge */ snd_soc_update_bits(codec, WM8994_ANTIPOP_1, @@ -957,17 +950,12 @@ static void vmid_dereference(struct snd_soc_codec *codec) WM8994_LINEOUT1_DISCH | WM8994_LINEOUT2_DISCH); - msleep(150); - snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_3, WM8994_LINEOUT1N_ENA | WM8994_LINEOUT1P_ENA | WM8994_LINEOUT2N_ENA | WM8994_LINEOUT2P_ENA, 0); - snd_soc_update_bits(codec, WM8994_ADDITIONAL_CONTROL, - WM8994_VROI, 0); - /* Switch off startup biases */ snd_soc_update_bits(codec, WM8994_ANTIPOP_2, WM8994_BIAS_SRC | @@ -976,10 +964,7 @@ static void vmid_dereference(struct snd_soc_codec *codec) WM8994_VMID_RAMP_MASK, 0); snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, - WM8994_BIAS_ENA | WM8994_VMID_SEL_MASK, 0); - - snd_soc_update_bits(codec, WM8994_ANTIPOP_2, - WM8994_VMID_RAMP_MASK, 0); + WM8994_VMID_SEL_MASK, 0); } pm_runtime_put(codec->dev); @@ -2277,6 +2262,18 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, 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; } @@ -2365,6 +2362,18 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, 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; } @@ -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) { 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[] = { SOC_ENUM_EXT("AIF1.1 EQ Mode", wm8994->retune_mobile_enum, @@ -3149,7 +3159,8 @@ static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994) static void wm8994_handle_pdata(struct wm8994_priv *wm8994) { 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; if (!pdata) @@ -3389,38 +3400,80 @@ static irqreturn_t wm8994_mic_irq(int irq, void *data) return IRQ_HANDLED; } -/* Default microphone detection handler for WM8958 - the user can - * override this if they wish. - */ -static void wm8958_default_micdet(u16 status, void *data) +static void wm1811_micd_stop(struct snd_soc_codec *codec) +{ + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + + 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); 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 */ if (!(status & WM8958_MICD_STS)) { - if (!wm8994->jackdet) { - /* If nothing present then clear our statuses */ - dev_dbg(codec->dev, "Detected open circuit\n"); - wm8994->jack_mic = false; - wm8994->mic_detecting = true; + /* If nothing present then clear our statuses */ + dev_dbg(codec->dev, "Detected open circuit\n"); + wm8994->jack_mic = false; + wm8994->mic_detecting = true; - wm8958_micd_set_rate(codec); + wm1811_micd_stop(codec); - snd_soc_jack_report(wm8994->micdet[0].jack, 0, - wm8994->btn_mask | - SND_JACK_HEADSET); - } + wm8958_micd_set_rate(codec); + + snd_soc_jack_report(wm8994->micdet[0].jack, 0, + wm8994->btn_mask | + SND_JACK_HEADSET); return; } /* If the measurement is showing a high impedence we've got a * microphone. */ - if (wm8994->mic_detecting && (status & 0x600)) { + if (status & 0x600) { dev_dbg(codec->dev, "Detected microphone\n"); wm8994->mic_detecting = false; @@ -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"); wm8994->mic_detecting = false; wm8958_micd_set_rate(codec); /* If we have jackdet that will detect removal */ - if (wm8994->jackdet) { - 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"); - } + wm1811_micd_stop(codec); snd_soc_jack_report(wm8994->micdet[0].jack, SND_JACK_HEADPHONE, SND_JACK_HEADSET); } +} - /* Report short circuit as a button */ - if (wm8994->jack_mic) { - report = 0; - if (status & 0x4) - report |= SND_JACK_BTN_0; +/* Deferred mic detection to allow for extra settling time */ +static void wm1811_mic_work(struct work_struct *work) +{ + struct wm8994_priv *wm8994 = container_of(work, struct wm8994_priv, + mic_work.work); + struct wm8994 *control = wm8994->wm8994; + struct snd_soc_codec *codec = wm8994->hubs.codec; - if (status & 0x8) - report |= SND_JACK_BTN_1; + pm_runtime_get_sync(codec->dev); - if (status & 0x10) - report |= SND_JACK_BTN_2; + /* If required for an external cap force MICBIAS on */ + if (control->pdata.jd_ext_cap) { + snd_soc_dapm_force_enable_pin(&codec->dapm, + "MICBIAS2"); + snd_soc_dapm_sync(&codec->dapm); + } - if (status & 0x20) - report |= SND_JACK_BTN_3; + mutex_lock(&wm8994->accdet_lock); - if (status & 0x40) - report |= SND_JACK_BTN_4; + dev_dbg(codec->dev, "Starting mic detection\n"); - if (status & 0x80) - report |= SND_JACK_BTN_5; + /* Use a user-supplied callback if we have one */ + 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, - wm8994->btn_mask); + snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, + 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) { struct wm8994_priv *wm8994 = data; + struct wm8994 *control = wm8994->wm8994; struct snd_soc_codec *codec = wm8994->hubs.codec; - int reg; + int reg, delay; bool present; pm_runtime_get_sync(codec->dev); @@ -3521,18 +3577,14 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data) snd_soc_update_bits(codec, WM1811_JACKDET_CTRL, WM1811_JACKDET_DB, 0); - /* - * 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_update_bits(codec, WM8958_MIC_DETECT_1, - WM8958_MICD_ENA, WM8958_MICD_ENA); + delay = control->pdata.micdet_delay; + schedule_delayed_work(&wm8994->mic_work, + msecs_to_jiffies(delay)); } else { dev_dbg(codec->dev, "Jack not detected\n"); + cancel_delayed_work_sync(&wm8994->mic_work); + snd_soc_update_bits(codec, WM8958_MICBIAS2, WM8958_MICB2_DISCH, WM8958_MICB2_DISCH); @@ -3549,14 +3601,9 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data) mutex_unlock(&wm8994->accdet_lock); - /* If required for an external cap force MICBIAS on */ - if (wm8994->pdata->jd_ext_cap) { - if (present) - snd_soc_dapm_force_enable_pin(&codec->dapm, - "MICBIAS2"); - else - snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS2"); - } + /* Turn off MICBIAS if it was on for an external cap */ + if (control->pdata.jd_ext_cap && !present) + snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS2"); if (present) snd_soc_jack_report(wm8994->micdet[0].jack, @@ -3599,7 +3646,8 @@ static void wm1811_jackdet_bootstrap(struct work_struct *work) * detection algorithm. */ 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 *control = wm8994->wm8994; @@ -3614,27 +3662,32 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *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_sync(&codec->dapm); wm8994->micdet[0].jack = jack; - wm8994->jack_cb = cb; - wm8994->jack_cb_data = cb_data; - wm8994->mic_detecting = true; - wm8994->jack_mic = false; + if (det_cb) { + 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); /* Detect microphones and short circuits by default */ - if (wm8994->pdata->micd_lvl_sel) - micd_lvl_sel = wm8994->pdata->micd_lvl_sel; + if (control->pdata.micd_lvl_sel) + micd_lvl_sel = control->pdata.micd_lvl_sel; else micd_lvl_sel = 0x41; @@ -3728,10 +3781,22 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) trace_snd_soc_jack_irq(dev_name(codec->dev)); #endif - if (wm8994->jack_cb) - wm8994->jack_cb(reg, wm8994->jack_cb_data); + /* Avoid a transient report when the accessory is being removed */ + 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 - dev_warn(codec->dev, "Accessory detection with no callback\n"); + wm8958_button_det(codec, reg); out: pm_runtime_put(codec->dev); @@ -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); mutex_init(&wm8994->accdet_lock); - INIT_DELAYED_WORK(&wm8994->mic_work, wm8994_mic_work); INIT_DELAYED_WORK(&wm8994->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++) init_completion(&wm8994->fll_locked[i]); - if (wm8994->pdata && wm8994->pdata->micdet_irq) - wm8994->micdet_irq = wm8994->pdata->micdet_irq; + wm8994->micdet_irq = control->pdata.micdet_irq; pm_runtime_enable(codec->dev); pm_runtime_idle(codec->dev); @@ -3800,8 +3874,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) switch (control->type) { case WM8994: /* Single ended line outputs should have VMID on. */ - if (!wm8994->pdata->lineout1_diff || - !wm8994->pdata->lineout2_diff) + if (!control->pdata.lineout1_diff || + !control->pdata.lineout2_diff) codec->dapm.idle_bias_off = 0; switch (wm8994->revision) { @@ -3839,20 +3913,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) wm8994->hubs.no_cache_dac_hp_direct = true; wm8994->fll_byp = true; - switch (control->cust_id) { - case 0: - 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; - } + wm8994->hubs.dcs_codes_l = -9; + wm8994->hubs.dcs_codes_r = -7; snd_soc_update_bits(codec, WM8994_ANALOGUE_HP_1, WM1811_HPOUT1_ATTN, WM1811_HPOUT1_ATTN); @@ -4236,7 +4298,6 @@ static int __devinit wm8994_probe(struct platform_device *pdev) platform_set_drvdata(pdev, wm8994); 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, wm8994_dai, ARRAY_SIZE(wm8994_dai)); @@ -4266,7 +4327,7 @@ static int wm8994_resume(struct device *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, WM1811_JACKDET_MODE_MASK, WM1811_JACKDET_MODE_AUDIO); diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index ccbce5791e95829b5d98ce472ac50d922e6e4703..45f192702024485fa23e87567eeda19bf0080e22 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h @@ -39,12 +39,14 @@ enum wm8994_vmid_mode { 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 micbias); 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); @@ -138,12 +140,13 @@ struct wm8994_priv { int jackdet_mode; struct delayed_work jackdet_bootstrap; - wm8958_micdet_cb jack_cb; - void *jack_cb_data; 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; - struct wm8994_pdata *pdata; unsigned int aif1clk_enable:1; unsigned int aif2clk_enable:1; diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c index 0908bb05a5e711e03b21d51585ed7d5077a9ef5d..de4cfdf5fdfce9c879f564a2b0a4916147e7dcef 100644 --- a/sound/soc/samsung/littlemill.c +++ b/sound/soc/samsung/littlemill.c @@ -270,7 +270,7 @@ static int littlemill_late_probe(struct snd_soc_card *card) return ret; /* 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 */ wm8994_mic_detect(codec, &littlemill_headset, 1);