]> Pileus Git - ~andy/linux/blobdiff - sound/soc/codecs/wm8994.c
Merge tag 'v3.4-rc7' into for-3.5
[~andy/linux] / sound / soc / codecs / wm8994.c
index 6c1fe3afd4b59311686ce3c9e2940cf5d223b1ed..2f9870aa0cf111a8efef48ee633426063e0eabe7 100644 (file)
@@ -70,8 +70,8 @@ static const struct wm8958_micd_rate micdet_rates[] = {
 static const struct wm8958_micd_rate jackdet_rates[] = {
        { 32768,       true,  0, 1 },
        { 32768,       false, 0, 1 },
-       { 44100 * 256, true,  7, 10 },
-       { 44100 * 256, false, 7, 10 },
+       { 44100 * 256, true,  10, 10 },
+       { 44100 * 256, false, 7, 8 },
 };
 
 static void wm8958_micd_set_rate(struct snd_soc_codec *codec)
@@ -82,7 +82,8 @@ static void wm8958_micd_set_rate(struct snd_soc_codec *codec)
        const struct wm8958_micd_rate *rates;
        int num_rates;
 
-       if (wm8994->jack_cb != wm8958_default_micdet)
+       if (!(wm8994->pdata && wm8994->pdata->micd_rates) &&
+           wm8994->jack_cb != wm8958_default_micdet)
                return;
 
        idle = !wm8994->jack_mic;
@@ -118,6 +119,10 @@ static void wm8958_micd_set_rate(struct snd_soc_codec *codec)
        val = rates[best].start << WM8958_MICD_BIAS_STARTTIME_SHIFT
                | rates[best].rate << WM8958_MICD_RATE_SHIFT;
 
+       dev_dbg(codec->dev, "MICD rate %d,%d for %dHz %s\n",
+               rates[best].start, rates[best].rate, sysclk,
+               idle ? "idle" : "active");
+
        snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
                            WM8958_MICD_BIAS_STARTTIME_MASK |
                            WM8958_MICD_RATE_MASK, val);
@@ -398,7 +403,7 @@ static void wm8994_set_retune_mobile(struct snd_soc_codec *codec, int block)
                wm8994->dac_rates[iface]);
 
        /* The EQ will be disabled while reconfiguring it, remember the
-        * current configuration. 
+        * current configuration.
         */
        save = snd_soc_read(codec, base);
        save &= WM8994_AIF1DAC1_EQ_ENA;
@@ -686,6 +691,9 @@ 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)
+               return;
+
        if (!wm8994->jackdet || !wm8994->jack_cb)
                return;
 
@@ -784,7 +792,7 @@ static void vmid_reference(struct snd_soc_codec *codec)
 
                switch (wm8994->vmid_mode) {
                default:
-                       WARN_ON(0 == "Invalid VMID mode");
+                       WARN_ON(NULL == "Invalid VMID mode");
                case WM8994_VMID_NORMAL:
                        /* Startup bias, VMID ramp & buffer */
                        snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
@@ -937,27 +945,12 @@ static int vmid_event(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
-static void wm8994_update_class_w(struct snd_soc_codec *codec)
+static bool wm8994_check_class_w_digital(struct snd_soc_codec *codec)
 {
-       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-       int enable = 1;
        int source = 0;  /* GCC flow analysis can't track enable */
        int reg, reg_r;
 
-       /* Only support direct DAC->headphone paths */
-       reg = snd_soc_read(codec, WM8994_OUTPUT_MIXER_1);
-       if (!(reg & WM8994_DAC1L_TO_HPOUT1L)) {
-               dev_vdbg(codec->dev, "HPL connected to output mixer\n");
-               enable = 0;
-       }
-
-       reg = snd_soc_read(codec, WM8994_OUTPUT_MIXER_2);
-       if (!(reg & WM8994_DAC1R_TO_HPOUT1R)) {
-               dev_vdbg(codec->dev, "HPR connected to output mixer\n");
-               enable = 0;
-       }
-
-       /* We also need the same setting for L/R and only one path */
+       /* We also need the same AIF source for L/R and only one path */
        reg = snd_soc_read(codec, WM8994_DAC1_LEFT_MIXER_ROUTING);
        switch (reg) {
        case WM8994_AIF2DACL_TO_DAC1L:
@@ -974,30 +967,20 @@ static void wm8994_update_class_w(struct snd_soc_codec *codec)
                break;
        default:
                dev_vdbg(codec->dev, "DAC mixer setting: %x\n", reg);
-               enable = 0;
-               break;
+               return false;
        }
 
        reg_r = snd_soc_read(codec, WM8994_DAC1_RIGHT_MIXER_ROUTING);
        if (reg_r != reg) {
                dev_vdbg(codec->dev, "Left and right DAC mixers different\n");
-               enable = 0;
+               return false;
        }
 
-       if (enable) {
-               dev_dbg(codec->dev, "Class W enabled\n");
-               snd_soc_update_bits(codec, WM8994_CLASS_W_1,
-                                   WM8994_CP_DYN_PWR |
-                                   WM8994_CP_DYN_SRC_SEL_MASK,
-                                   source | WM8994_CP_DYN_PWR);
-               wm8994->hubs.class_w = true;
-               
-       } else {
-               dev_dbg(codec->dev, "Class W disabled\n");
-               snd_soc_update_bits(codec, WM8994_CLASS_W_1,
-                                   WM8994_CP_DYN_PWR, 0);
-               wm8994->hubs.class_w = false;
-       }
+       /* Set the source up */
+       snd_soc_update_bits(codec, WM8994_CLASS_W_1,
+                           WM8994_CP_DYN_SRC_SEL_MASK, source);
+
+       return true;
 }
 
 static int aif1clk_ev(struct snd_soc_dapm_widget *w,
@@ -1280,45 +1263,6 @@ static int dac_ev(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
-static const char *hp_mux_text[] = {
-       "Mixer",
-       "DAC",
-};
-
-#define WM8994_HP_ENUM(xname, xenum) \
-{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
-       .info = snd_soc_info_enum_double, \
-       .get = snd_soc_dapm_get_enum_double, \
-       .put = wm8994_put_hp_enum, \
-       .private_value = (unsigned long)&xenum }
-
-static int wm8994_put_hp_enum(struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *w = wlist->widgets[0];
-       struct snd_soc_codec *codec = w->codec;
-       int ret;
-
-       ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
-
-       wm8994_update_class_w(codec);
-
-       return ret;
-}
-
-static const struct soc_enum hpl_enum =
-       SOC_ENUM_SINGLE(WM8994_OUTPUT_MIXER_1, 8, 2, hp_mux_text);
-
-static const struct snd_kcontrol_new hpl_mux =
-       WM8994_HP_ENUM("Left Headphone Mux", hpl_enum);
-
-static const struct soc_enum hpr_enum =
-       SOC_ENUM_SINGLE(WM8994_OUTPUT_MIXER_2, 8, 2, hp_mux_text);
-
-static const struct snd_kcontrol_new hpr_mux =
-       WM8994_HP_ENUM("Right Headphone Mux", hpr_enum);
-
 static const char *adc_mux_text[] = {
        "ADC",
        "DMIC",
@@ -1430,7 +1374,7 @@ static int wm8994_put_class_w(struct snd_kcontrol *kcontrol,
 
        ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
 
-       wm8994_update_class_w(codec);
+       wm_hubs_update_class_w(codec);
 
        return ret;
 }
@@ -1524,7 +1468,7 @@ static const struct snd_kcontrol_new wm8958_aif3adc_mux =
        SOC_DAPM_ENUM("AIF3ADC Mux", wm8958_aif3adc_enum);
 
 static const char *mono_pcm_out_text[] = {
-       "None", "AIF2ADCL", "AIF2ADCR", 
+       "None", "AIF2ADCL", "AIF2ADCR",
 };
 
 static const struct soc_enum mono_pcm_out_enum =
@@ -1573,9 +1517,9 @@ SND_SOC_DAPM_MIXER_E("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0,
 SND_SOC_DAPM_MIXER_E("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0,
                     right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer),
                     late_enable_ev, SND_SOC_DAPM_PRE_PMU),
-SND_SOC_DAPM_MUX_E("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux,
+SND_SOC_DAPM_MUX_E("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpl_mux,
                   late_enable_ev, SND_SOC_DAPM_PRE_PMU),
-SND_SOC_DAPM_MUX_E("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux,
+SND_SOC_DAPM_MUX_E("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpr_mux,
                   late_enable_ev, SND_SOC_DAPM_PRE_PMU),
 
 SND_SOC_DAPM_POST("Late Disable PGA", late_disable_ev)
@@ -1591,8 +1535,8 @@ SND_SOC_DAPM_MIXER("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0,
                   left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)),
 SND_SOC_DAPM_MIXER("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0,
                   right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)),
-SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux),
-SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux),
+SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpl_mux),
+SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpr_mux),
 };
 
 static const struct snd_soc_dapm_widget wm8994_dac_revd_widgets[] = {
@@ -1732,6 +1676,7 @@ SND_SOC_DAPM_MUX("AIF3ADC Mux", SND_SOC_NOPM, 0, 0, &wm8994_aif3adc_mux),
 };
 
 static const struct snd_soc_dapm_widget wm8958_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("AIF3", WM8994_POWER_MANAGEMENT_6, 5, 1, NULL, 0),
 SND_SOC_DAPM_MUX("Mono PCM Out Mux", SND_SOC_NOPM, 0, 0, &mono_pcm_out_mux),
 SND_SOC_DAPM_MUX("AIF2DACL Mux", SND_SOC_NOPM, 0, 0, &aif2dacl_src_mux),
 SND_SOC_DAPM_MUX("AIF2DACR Mux", SND_SOC_NOPM, 0, 0, &aif2dacr_src_mux),
@@ -1972,6 +1917,9 @@ static const struct snd_soc_dapm_route wm8958_intercon[] = {
        { "AIF2DACR Mux", "AIF2", "AIF2DAC Mux" },
        { "AIF2DACR Mux", "AIF3", "AIF3DACDAT" },
 
+       { "AIF3DACDAT", NULL, "AIF3" },
+       { "AIF3ADCDAT", NULL, "AIF3" },
+
        { "Mono PCM Out Mux", "AIF2ADCL", "AIF2ADCL" },
        { "Mono PCM Out Mux", "AIF2ADCR", "AIF2ADCR" },
 
@@ -2068,24 +2016,20 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
        struct wm8994 *control = wm8994->wm8994;
        int reg_offset, ret;
        struct fll_div fll;
-       u16 reg, aif1, aif2;
+       u16 reg, clk1, aif_reg, aif_src;
        unsigned long timeout;
        bool was_enabled;
 
-       aif1 = snd_soc_read(codec, WM8994_AIF1_CLOCKING_1)
-               & WM8994_AIF1CLK_ENA;
-
-       aif2 = snd_soc_read(codec, WM8994_AIF2_CLOCKING_1)
-               & WM8994_AIF2CLK_ENA;
-
        switch (id) {
        case WM8994_FLL1:
                reg_offset = 0;
                id = 0;
+               aif_src = 0x10;
                break;
        case WM8994_FLL2:
                reg_offset = 0x20;
                id = 1;
+               aif_src = 0x18;
                break;
        default:
                return -EINVAL;
@@ -2127,16 +2071,33 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
        if (ret < 0)
                return ret;
 
-       /* Gate the AIF clocks while we reclock */
-       snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1,
-                           WM8994_AIF1CLK_ENA, 0);
-       snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1,
-                           WM8994_AIF2CLK_ENA, 0);
+       /* Make sure that we're not providing SYSCLK right now */
+       clk1 = snd_soc_read(codec, WM8994_CLOCKING_1);
+       if (clk1 & WM8994_SYSCLK_SRC)
+               aif_reg = WM8994_AIF2_CLOCKING_1;
+       else
+               aif_reg = WM8994_AIF1_CLOCKING_1;
+       reg = snd_soc_read(codec, aif_reg);
+
+       if ((reg & WM8994_AIF1CLK_ENA) &&
+           (reg & WM8994_AIF1CLK_SRC_MASK) == aif_src) {
+               dev_err(codec->dev, "FLL%d is currently providing SYSCLK\n",
+                       id + 1);
+               return -EBUSY;
+       }
 
        /* We always need to disable the FLL while reconfiguring */
        snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_1 + reg_offset,
                            WM8994_FLL1_ENA, 0);
 
+       if (wm8994->fll_byp && src == WM8994_FLL_SRC_BCLK &&
+           freq_in == freq_out && freq_out) {
+               dev_dbg(codec->dev, "Bypassing FLL%d\n", id + 1);
+               snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset,
+                                   WM8958_FLL1_BYP, WM8958_FLL1_BYP);
+               goto out;
+       }
+
        reg = (fll.outdiv << WM8994_FLL1_OUTDIV_SHIFT) |
                (fll.fll_fratio << WM8994_FLL1_FRATIO_SHIFT);
        snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_2 + reg_offset,
@@ -2151,6 +2112,7 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
                                    fll.n << WM8994_FLL1_N_SHIFT);
 
        snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset,
+                           WM8958_FLL1_BYP |
                            WM8994_FLL1_REFCLK_DIV_MASK |
                            WM8994_FLL1_REFCLK_SRC_MASK,
                            (fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT) |
@@ -2213,16 +2175,11 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
                }
        }
 
+out:
        wm8994->fll[id].in = freq_in;
        wm8994->fll[id].out = freq_out;
        wm8994->fll[id].src = src;
 
-       /* Enable any gated AIF clocks */
-       snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1,
-                           WM8994_AIF1CLK_ENA, aif1);
-       snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1,
-                           WM8994_AIF2CLK_ENA, aif2);
-
        configure_clock(codec);
 
        return 0;
@@ -2290,7 +2247,7 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
 
        case WM8994_SYSCLK_OPCLK:
                /* Special case - a division (times 10) is given and
-                * no effect on main clocking. 
+                * no effect on main clocking.
                 */
                if (freq) {
                        for (i = 0; i < ARRAY_SIZE(opclk_divs); i++)
@@ -2792,33 +2749,6 @@ static int wm8994_aif3_hw_params(struct snd_pcm_substream *substream,
        return snd_soc_update_bits(codec, aif1_reg, WM8994_AIF1_WL_MASK, aif1);
 }
 
-static void wm8994_aif_shutdown(struct snd_pcm_substream *substream,
-                               struct snd_soc_dai *dai)
-{
-       struct snd_soc_codec *codec = dai->codec;
-       int rate_reg = 0;
-
-       switch (dai->id) {
-       case 1:
-               rate_reg = WM8994_AIF1_RATE;
-               break;
-       case 2:
-               rate_reg = WM8994_AIF2_RATE;
-               break;
-       default:
-               break;
-       }
-
-       /* If the DAI is idle then configure the divider tree for the
-        * lowest output rate to save a little power if the clock is
-        * still active (eg, because it is system clock).
-        */
-       if (rate_reg && !dai->playback_active && !dai->capture_active)
-               snd_soc_update_bits(codec, rate_reg,
-                                   WM8994_AIF1_SR_MASK |
-                                   WM8994_AIF1CLK_RATE_MASK, 0x9);
-}
-
 static int wm8994_aif_mute(struct snd_soc_dai *codec_dai, int mute)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -2860,10 +2790,6 @@ static int wm8994_set_tristate(struct snd_soc_dai *codec_dai, int tristate)
                reg = WM8994_AIF2_MASTER_SLAVE;
                mask = WM8994_AIF2_TRI;
                break;
-       case 3:
-               reg = WM8994_POWER_MANAGEMENT_6;
-               mask = WM8994_AIF3_TRI;
-               break;
        default:
                return -EINVAL;
        }
@@ -2900,7 +2826,6 @@ static const struct snd_soc_dai_ops wm8994_aif1_dai_ops = {
        .set_sysclk     = wm8994_set_dai_sysclk,
        .set_fmt        = wm8994_set_dai_fmt,
        .hw_params      = wm8994_hw_params,
-       .shutdown       = wm8994_aif_shutdown,
        .digital_mute   = wm8994_aif_mute,
        .set_pll        = wm8994_set_fll,
        .set_tristate   = wm8994_set_tristate,
@@ -2910,7 +2835,6 @@ static const struct snd_soc_dai_ops wm8994_aif2_dai_ops = {
        .set_sysclk     = wm8994_set_dai_sysclk,
        .set_fmt        = wm8994_set_dai_fmt,
        .hw_params      = wm8994_hw_params,
-       .shutdown       = wm8994_aif_shutdown,
        .digital_mute   = wm8994_aif_mute,
        .set_pll        = wm8994_set_fll,
        .set_tristate   = wm8994_set_tristate,
@@ -2918,7 +2842,6 @@ static const struct snd_soc_dai_ops wm8994_aif2_dai_ops = {
 
 static const struct snd_soc_dai_ops wm8994_aif3_dai_ops = {
        .hw_params      = wm8994_aif3_hw_params,
-       .set_tristate   = wm8994_set_tristate,
 };
 
 static struct snd_soc_dai_driver wm8994_dai[] = {
@@ -3126,14 +3049,14 @@ static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
 
                /* Expand the array... */
                t = krealloc(wm8994->retune_mobile_texts,
-                            sizeof(char *) * 
+                            sizeof(char *) *
                             (wm8994->num_retune_mobile_texts + 1),
                             GFP_KERNEL);
                if (t == NULL)
                        continue;
 
                /* ...store the new entry... */
-               t[wm8994->num_retune_mobile_texts] = 
+               t[wm8994->num_retune_mobile_texts] =
                        pdata->retune_mobile_cfgs[i].name;
 
                /* ...and remember the new version. */
@@ -3304,25 +3227,25 @@ int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
 }
 EXPORT_SYMBOL_GPL(wm8994_mic_detect);
 
-static irqreturn_t wm8994_mic_irq(int irq, void *data)
+static void wm8994_mic_work(struct work_struct *work)
 {
-       struct wm8994_priv *priv = data;
-       struct snd_soc_codec *codec = priv->codec;
-       int reg;
+       struct wm8994_priv *priv = container_of(work,
+                                               struct wm8994_priv,
+                                               mic_work.work);
+       struct regmap *regmap = priv->wm8994->regmap;
+       struct device *dev = priv->wm8994->dev;
+       unsigned int reg;
+       int ret;
        int report;
 
-#ifndef CONFIG_SND_SOC_WM8994_MODULE
-       trace_snd_soc_jack_irq(dev_name(codec->dev));
-#endif
-
-       reg = snd_soc_read(codec, WM8994_INTERRUPT_RAW_STATUS_2);
-       if (reg < 0) {
-               dev_err(codec->dev, "Failed to read microphone status: %d\n",
-                       reg);
-               return IRQ_HANDLED;
+       ret = regmap_read(regmap, WM8994_INTERRUPT_RAW_STATUS_2, &reg);
+       if (ret < 0) {
+               dev_err(dev, "Failed to read microphone status: %d\n",
+                       ret);
+               return;
        }
 
-       dev_dbg(codec->dev, "Microphone status: %x\n", reg);
+       dev_dbg(dev, "Microphone status: %x\n", reg);
 
        report = 0;
        if (reg & WM8994_MIC1_DET_STS) {
@@ -3361,6 +3284,20 @@ static irqreturn_t wm8994_mic_irq(int irq, void *data)
 
        snd_soc_jack_report(priv->micdet[1].jack, report,
                            SND_JACK_HEADSET | SND_JACK_BTN_0);
+}
+
+static irqreturn_t wm8994_mic_irq(int irq, void *data)
+{
+       struct wm8994_priv *priv = data;
+       struct snd_soc_codec *codec = priv->codec;
+
+#ifndef CONFIG_SND_SOC_WM8994_MODULE
+       trace_snd_soc_jack_irq(dev_name(codec->dev));
+#endif
+
+       pm_wakeup_event(codec->dev, 300);
+
+       schedule_delayed_work(&priv->mic_work, msecs_to_jiffies(250));
 
        return IRQ_HANDLED;
 }
@@ -3415,9 +3352,6 @@ static void wm8958_default_micdet(u16 status, void *data)
 
                wm8958_micd_set_rate(codec);
 
-               snd_soc_jack_report(wm8994->micdet[0].jack, SND_JACK_HEADPHONE,
-                                   SND_JACK_HEADSET);
-
                /* If we have jackdet that will detect removal */
                if (wm8994->jackdet) {
                        mutex_lock(&wm8994->accdet_lock);
@@ -3430,14 +3364,13 @@ static void wm8958_default_micdet(u16 status, void *data)
 
                        mutex_unlock(&wm8994->accdet_lock);
 
-                       if (wm8994->pdata->jd_ext_cap) {
-                               mutex_lock(&codec->mutex);
+                       if (wm8994->pdata->jd_ext_cap)
                                snd_soc_dapm_disable_pin(&codec->dapm,
                                                         "MICBIAS2");
-                               snd_soc_dapm_sync(&codec->dapm);
-                               mutex_unlock(&codec->mutex);
-                       }
                }
+
+               snd_soc_jack_report(wm8994->micdet[0].jack, SND_JACK_HEADPHONE,
+                                   SND_JACK_HEADSET);
        }
 
        /* Report short circuit as a button */
@@ -3489,6 +3422,8 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
        if (present) {
                dev_dbg(codec->dev, "Jack detected\n");
 
+               wm8958_micd_set_rate(codec);
+
                snd_soc_update_bits(codec, WM8958_MICBIAS2,
                                    WM8958_MICB2_DISCH, 0);
 
@@ -3526,16 +3461,11 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
 
        /* If required for an external cap force MICBIAS on */
        if (wm8994->pdata->jd_ext_cap) {
-               mutex_lock(&codec->mutex);
-
                if (present)
                        snd_soc_dapm_force_enable_pin(&codec->dapm,
                                                      "MICBIAS2");
                else
                        snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS2");
-
-               snd_soc_dapm_sync(&codec->dapm);
-               mutex_unlock(&codec->mutex);
        }
 
        if (present)
@@ -3740,6 +3670,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
        wm8994->codec = codec;
 
        mutex_init(&wm8994->accdet_lock);
+       INIT_DELAYED_WORK(&wm8994->mic_work, wm8994_mic_work);
 
        for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
                init_completion(&wm8994->fll_locked[i]);
@@ -3783,13 +3714,22 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
        case WM8958:
                wm8994->hubs.dcs_readback_mode = 1;
                wm8994->hubs.hp_startup_mode = 1;
+
+               switch (wm8994->revision) {
+               case 0:
+                       break;
+               default:
+                       wm8994->fll_byp = true;
+                       break;
+               }
                break;
 
        case WM1811:
                wm8994->hubs.dcs_readback_mode = 2;
                wm8994->hubs.no_series_update = 1;
                wm8994->hubs.hp_startup_mode = 1;
-               wm8994->hubs.no_cache_class_w = true;
+               wm8994->hubs.no_cache_dac_hp_direct = true;
+               wm8994->fll_byp = true;
 
                switch (wm8994->revision) {
                case 0:
@@ -4010,7 +3950,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                break;
        }
 
-       wm8994_update_class_w(codec);
+       wm8994->hubs.check_class_w_digital = wm8994_check_class_w_digital;
+       wm_hubs_update_class_w(codec);
 
        wm8994_handle_pdata(wm8994);
 
@@ -4075,7 +4016,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                                          ARRAY_SIZE(wm8994_dac_widgets));
                break;
        }
-               
 
        wm_hubs_add_analogue_routes(codec, 0, 0);
        snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
@@ -4140,7 +4080,7 @@ err_irq:
        return ret;
 }
 
-static int  wm8994_codec_remove(struct snd_soc_codec *codec)
+static int wm8994_codec_remove(struct snd_soc_codec *codec)
 {
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        struct wm8994 *control = wm8994->wm8994;
@@ -4181,14 +4121,10 @@ static int  wm8994_codec_remove(struct snd_soc_codec *codec)
                        free_irq(wm8994->micdet_irq, wm8994);
                break;
        }
-       if (wm8994->mbc)
-               release_firmware(wm8994->mbc);
-       if (wm8994->mbc_vss)
-               release_firmware(wm8994->mbc_vss);
-       if (wm8994->enh_eq)
-               release_firmware(wm8994->enh_eq);
+       release_firmware(wm8994->mbc);
+       release_firmware(wm8994->mbc_vss);
+       release_firmware(wm8994->enh_eq);
        kfree(wm8994->retune_mobile_texts);
-
        return 0;
 }