Merge branch 'for-3.0' into for-3.1
[firefly-linux-kernel-4.4.55.git] / sound / soc / codecs / wm8994.c
index dc2350e6350b6c9489f8132c0507462e8c43ad15..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,
@@ -1146,13 +1142,33 @@ SND_SOC_DAPM_PGA_E("Late DAC2L Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
        late_enable_ev, SND_SOC_DAPM_PRE_PMU),
 SND_SOC_DAPM_PGA_E("Late DAC2R Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
        late_enable_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_PGA_E("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0,
+       late_enable_ev, SND_SOC_DAPM_PRE_PMU),
+
+SND_SOC_DAPM_MIXER_E("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0,
+                    left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer),
+                    late_enable_ev, SND_SOC_DAPM_PRE_PMU),
+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,
+                  late_enable_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_MUX_E("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux,
+                  late_enable_ev, SND_SOC_DAPM_PRE_PMU),
 
 SND_SOC_DAPM_POST("Late Disable PGA", late_disable_ev)
 };
 
 static const struct snd_soc_dapm_widget wm8994_lateclk_widgets[] = {
 SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, NULL, 0),
-SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, NULL, 0)
+SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0),
+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),
 };
 
 static const struct snd_soc_dapm_widget wm8994_dac_revd_widgets[] = {
@@ -1190,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),
 
@@ -1283,14 +1298,6 @@ SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8994_POWER_MANAGEMENT_4, 2, 0),
 SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 1, 0),
 SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0),
 
-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_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_POST("Debug log", post_ev),
 };
 
@@ -1509,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[] = {
@@ -1623,6 +1632,7 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
        int reg_offset, ret;
        struct fll_div fll;
        u16 reg, aif1, aif2;
+       unsigned long timeout;
 
        aif1 = snd_soc_read(codec, WM8994_AIF1_CLOCKING_1)
                & WM8994_AIF1CLK_ENA;
@@ -1704,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)
@@ -1713,6 +1726,16 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
                snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_1 + reg_offset,
                                    WM8994_FLL1_ENA | WM8994_FLL1_FRAC,
                                    reg);
+
+               if (wm8994->fll_locked_irq) {
+                       timeout = wait_for_completion_timeout(&wm8994->fll_locked[id],
+                                                             msecs_to_jiffies(10));
+                       if (timeout == 0)
+                               dev_warn(codec->dev,
+                                        "Timed out waiting for FLL lock\n");
+               } else {
+                       msleep(5);
+               }
        }
 
        wm8994->fll[id].in = freq_in;
@@ -1730,6 +1753,14 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
        return 0;
 }
 
+static irqreturn_t wm8994_fll_locked_irq(int irq, void *data)
+{
+       struct completion *completion = data;
+
+       complete(completion);
+
+       return IRQ_HANDLED;
+}
 
 static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 };
 
@@ -2269,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;
@@ -2335,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,
@@ -2344,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,
@@ -2761,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:
@@ -2847,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;
@@ -2865,6 +2934,9 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
        wm8994->pdata = dev_get_platdata(codec->dev->parent);
        wm8994->codec = codec;
 
+       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;
        else if (wm8994->pdata && wm8994->pdata->irq_base)
@@ -2918,6 +2990,15 @@ 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);
+       if (ret == 0)
+               wm8994->hubs.dcs_done_irq = true;
+
        switch (control->type) {
        case WM8994:
                if (wm8994->micdet_irq) {
@@ -2974,6 +3055,16 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                }
        }
 
+       wm8994->fll_locked_irq = true;
+       for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) {
+               ret = wm8994_request_irq(codec->control_data,
+                                        WM8994_IRQ_FLL1_LOCK + i,
+                                        wm8994_fll_locked_irq, "FLL lock",
+                                        &wm8994->fll_locked[i]);
+               if (ret != 0)
+                       wm8994->fll_locked_irq = false;
+       }
+
        /* Remember if AIFnLRCLK is configured as a GPIO.  This should be
         * configured on init - if a system wants to do this dynamically
         * at runtime we can deal with that then.
@@ -3049,10 +3140,18 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                            1 << WM8994_AIF2DAC_3D_GAIN_SHIFT,
                            1 << WM8994_AIF2DAC_3D_GAIN_SHIFT);
 
-       /* Unconditionally enable AIF1 ADC TDM mode; it only affects
-        * behaviour on idle TDM clock cycles. */
-       snd_soc_update_bits(codec, WM8994_AIF1_CONTROL_1,
-                           WM8994_AIF1ADC_TDM, WM8994_AIF1ADC_TDM);
+       /* Unconditionally enable AIF1 ADC TDM mode on chips which can
+        * use this; it only affects behaviour on idle TDM clock
+        * cycles. */
+       switch (control->type) {
+       case WM8994:
+       case WM8958:
+               snd_soc_update_bits(codec, WM8994_AIF1_CONTROL_1,
+                                   WM8994_AIF1ADC_TDM, WM8994_AIF1ADC_TDM);
+               break;
+       default:
+               break;
+       }
 
        wm8994_update_class_w(codec);
 
@@ -3151,6 +3250,12 @@ err_irq:
        wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994);
        if (wm8994->micdet_irq)
                free_irq(wm8994->micdet_irq, wm8994);
+       for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
+               wm8994_free_irq(codec->control_data, WM8994_IRQ_FLL1_LOCK + i,
+                               &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;
@@ -3160,11 +3265,20 @@ static int  wm8994_codec_remove(struct snd_soc_codec *codec)
 {
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        struct wm8994 *control = codec->control_data;
+       int i;
 
        wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        pm_runtime_disable(codec->dev);
 
+       for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
+               wm8994_free_irq(codec->control_data, WM8994_IRQ_FLL1_LOCK + i,
+                               &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);
+
        switch (control->type) {
        case WM8994:
                if (wm8994->micdet_irq)