Merge branch 'for-3.0' into for-3.1
[firefly-linux-kernel-4.4.55.git] / sound / soc / codecs / wm8994.c
index f89ae47f3c3217d859b8312ac136ddb84d299274..09e680ae88b244003fd6c63f1a7300e3b92bdfd3 100644 (file)
@@ -195,10 +195,6 @@ static int configure_aif_clock(struct snd_soc_codec *codec, int aif)
                        aif + 1, rate);
        }
 
-       if (rate && rate < 3000000)
-               dev_warn(codec->dev, "AIF%dCLK is %dHz, should be >=3MHz for optimal performance\n",
-                        aif + 1, rate);
-
        wm8994->aifclk[aif] = rate;
 
        snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1 + offset,
@@ -1210,7 +1206,6 @@ SND_SOC_DAPM_INPUT("DMIC1DAT"),
 SND_SOC_DAPM_INPUT("DMIC2DAT"),
 SND_SOC_DAPM_INPUT("Clock"),
 
-SND_SOC_DAPM_MICBIAS("MICBIAS", WM8994_MICBIAS, 2, 0),
 SND_SOC_DAPM_SUPPLY_S("MICBIAS Supply", 1, SND_SOC_NOPM, 0, 0, micbias_ev,
                      SND_SOC_DAPM_PRE_PMU),
 
@@ -1521,8 +1516,10 @@ static const struct snd_soc_dapm_route wm8994_revd_intercon[] = {
        { "AIF2DACDAT", NULL, "AIF1DACDAT" },
        { "AIF1ADCDAT", NULL, "AIF2ADCDAT" },
        { "AIF2ADCDAT", NULL, "AIF1ADCDAT" },
-       { "MICBIAS", NULL, "CLK_SYS" },
-       { "MICBIAS", NULL, "MICBIAS Supply" },
+       { "MICBIAS1", NULL, "CLK_SYS" },
+       { "MICBIAS1", NULL, "MICBIAS Supply" },
+       { "MICBIAS2", NULL, "CLK_SYS" },
+       { "MICBIAS2", NULL, "MICBIAS Supply" },
 };
 
 static const struct snd_soc_dapm_route wm8994_intercon[] = {
@@ -1717,6 +1714,9 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
                            (fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT) |
                            (src - 1));
 
+       /* Clear any pending completion from a previous failure */
+       try_wait_for_completion(&wm8994->fll_locked[id]);
+
        /* Enable (with fractional mode if required) */
        if (freq_out) {
                if (fll.k)
@@ -2300,6 +2300,33 @@ 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_AIF1_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;
@@ -2366,6 +2393,7 @@ static 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,
@@ -2375,6 +2403,7 @@ static 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,
@@ -2792,7 +2821,7 @@ static void wm8958_default_micdet(u16 status, void *data)
        report = SND_JACK_MICROPHONE;
 
        /* Everything else is buttons; just assign slots */
-       if (status & 0x1c0)
+       if (status & 0x1c)
                report |= SND_JACK_BTN_0;
 
 done:
@@ -2878,6 +2907,15 @@ out:
        return IRQ_HANDLED;
 }
 
+static irqreturn_t wm8994_fifo_error(int irq, void *data)
+{
+       struct snd_soc_codec *codec = data;
+
+       dev_err(codec->dev, "FIFO error\n");
+
+       return IRQ_HANDLED;
+}
+
 static int wm8994_codec_probe(struct snd_soc_codec *codec)
 {
        struct wm8994 *control;
@@ -2952,6 +2990,9 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                break;
        }
 
+       wm8994_request_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR,
+                          wm8994_fifo_error, "FIFO error", codec);
+
        ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_DCS_DONE,
                                 wm_hubs_dcs_done, "DC servo done",
                                 &wm8994->hubs);
@@ -3214,6 +3255,7 @@ err_irq:
                                &wm8994->fll_locked[i]);
        wm8994_free_irq(codec->control_data, WM8994_IRQ_DCS_DONE,
                        &wm8994->hubs);
+       wm8994_free_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR, codec);
 err:
        kfree(wm8994);
        return ret;
@@ -3235,6 +3277,7 @@ static int  wm8994_codec_remove(struct snd_soc_codec *codec)
 
        wm8994_free_irq(codec->control_data, WM8994_IRQ_DCS_DONE,
                        &wm8994->hubs);
+       wm8994_free_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR, codec);
 
        switch (control->type) {
        case WM8994: