Merge remote-tracking branches 'asoc/fix/da7219-pops' and 'asoc/fix/qcom' into asoc...
authorMark Brown <broonie@kernel.org>
Mon, 12 Dec 2016 15:52:37 +0000 (15:52 +0000)
committerMark Brown <broonie@kernel.org>
Mon, 12 Dec 2016 15:52:37 +0000 (15:52 +0000)
sound/soc/codecs/da7219-aad.c
sound/soc/codecs/da7219.c
sound/soc/codecs/da7219.h
sound/soc/qcom/lpass-platform.c

index 2b8914dd59908897cdabfcb5abfd8f757cabfaf7..6274d79c1353ed1ad342aeabf0b523d970c721ff 100644 (file)
@@ -204,10 +204,19 @@ static void da7219_aad_hptest_work(struct work_struct *work)
        snd_soc_update_bits(codec, DA7219_MIXOUT_R_CTRL,
                            DA7219_MIXOUT_R_AMP_EN_MASK,
                            DA7219_MIXOUT_R_AMP_EN_MASK);
-       snd_soc_write(codec, DA7219_HP_L_CTRL,
-                     DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK);
-       snd_soc_write(codec, DA7219_HP_R_CTRL,
-                     DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK);
+       snd_soc_update_bits(codec, DA7219_HP_L_CTRL,
+                           DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK,
+                           DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK);
+       snd_soc_update_bits(codec, DA7219_HP_R_CTRL,
+                           DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK,
+                           DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK);
+       msleep(DA7219_SETTLING_DELAY);
+       snd_soc_update_bits(codec, DA7219_HP_L_CTRL,
+                           DA7219_HP_L_AMP_MUTE_EN_MASK |
+                           DA7219_HP_L_AMP_MIN_GAIN_EN_MASK, 0);
+       snd_soc_update_bits(codec, DA7219_HP_R_CTRL,
+                           DA7219_HP_R_AMP_MUTE_EN_MASK |
+                           DA7219_HP_R_AMP_MIN_GAIN_EN_MASK, 0);
 
        /*
         * If we're running from the internal oscillator then give audio paths
@@ -244,6 +253,7 @@ static void da7219_aad_hptest_work(struct work_struct *work)
        regcache_mark_dirty(da7219->regmap);
        regcache_sync_region(da7219->regmap, DA7219_HP_L_CTRL,
                             DA7219_HP_R_CTRL);
+       msleep(DA7219_SETTLING_DELAY);
        regcache_sync_region(da7219->regmap, DA7219_MIXOUT_L_CTRL,
                             DA7219_MIXOUT_R_CTRL);
        regcache_sync_region(da7219->regmap, DA7219_DROUTING_ST_OUTFILT_1L,
index cf37936bfe3aaaf6b29cb1f78c9c54f80a2b40b7..99601627f83cf6fe0dc83249139058ce6b15611e 100644 (file)
@@ -823,6 +823,85 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w,
        }
 }
 
+static int da7219_settling_event(struct snd_soc_dapm_widget *w,
+                                struct snd_kcontrol *kcontrol, int event)
+{
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+       case SND_SOC_DAPM_POST_PMD:
+               msleep(DA7219_SETTLING_DELAY);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int da7219_mixout_event(struct snd_soc_dapm_widget *w,
+                              struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       u8 hp_ctrl, min_gain_mask;
+
+       switch (w->reg) {
+       case DA7219_MIXOUT_L_CTRL:
+               hp_ctrl = DA7219_HP_L_CTRL;
+               min_gain_mask = DA7219_HP_L_AMP_MIN_GAIN_EN_MASK;
+               break;
+       case DA7219_MIXOUT_R_CTRL:
+               hp_ctrl = DA7219_HP_R_CTRL;
+               min_gain_mask = DA7219_HP_R_AMP_MIN_GAIN_EN_MASK;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMD:
+               /* Enable minimum gain on HP to avoid pops */
+               snd_soc_update_bits(codec, hp_ctrl, min_gain_mask,
+                                   min_gain_mask);
+
+               msleep(DA7219_MIN_GAIN_DELAY);
+
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               /* Remove minimum gain on HP */
+               snd_soc_update_bits(codec, hp_ctrl, min_gain_mask, 0);
+
+               break;
+       }
+
+       return 0;
+}
+
+static int da7219_gain_ramp_event(struct snd_soc_dapm_widget *w,
+                                 struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+       case SND_SOC_DAPM_PRE_PMD:
+               /* Ensure nominal gain ramping for DAPM sequence */
+               da7219->gain_ramp_ctrl =
+                       snd_soc_read(codec, DA7219_GAIN_RAMP_CTRL);
+               snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL,
+                             DA7219_GAIN_RAMP_RATE_NOMINAL);
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+       case SND_SOC_DAPM_POST_PMD:
+               /* Restore previous gain ramp settings */
+               snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL,
+                             da7219->gain_ramp_ctrl);
+               break;
+       }
+
+       return 0;
+}
+
 
 /*
  * DAPM Widgets
@@ -907,30 +986,46 @@ static const struct snd_soc_dapm_widget da7219_dapm_widgets[] = {
                           ARRAY_SIZE(da7219_st_out_filtr_mix_controls)),
 
        /* DACs */
-       SND_SOC_DAPM_DAC("DACL", NULL, DA7219_DAC_L_CTRL, DA7219_DAC_L_EN_SHIFT,
-                        DA7219_NO_INVERT),
-       SND_SOC_DAPM_DAC("DACR", NULL, DA7219_DAC_R_CTRL, DA7219_DAC_R_EN_SHIFT,
-                        DA7219_NO_INVERT),
+       SND_SOC_DAPM_DAC_E("DACL", NULL, DA7219_DAC_L_CTRL,
+                          DA7219_DAC_L_EN_SHIFT, DA7219_NO_INVERT,
+                          da7219_settling_event,
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_DAC_E("DACR", NULL, DA7219_DAC_R_CTRL,
+                          DA7219_DAC_R_EN_SHIFT, DA7219_NO_INVERT,
+                          da7219_settling_event,
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
        /* Output PGAs */
-       SND_SOC_DAPM_PGA("Mixout Left PGA", DA7219_MIXOUT_L_CTRL,
-                        DA7219_MIXOUT_L_AMP_EN_SHIFT, DA7219_NO_INVERT,
-                        NULL, 0),
-       SND_SOC_DAPM_PGA("Mixout Right PGA", DA7219_MIXOUT_R_CTRL,
-                        DA7219_MIXOUT_R_AMP_EN_SHIFT, DA7219_NO_INVERT,
-                        NULL, 0),
-       SND_SOC_DAPM_PGA("Headphone Left PGA", DA7219_HP_L_CTRL,
-                        DA7219_HP_L_AMP_EN_SHIFT, DA7219_NO_INVERT, NULL, 0),
-       SND_SOC_DAPM_PGA("Headphone Right PGA", DA7219_HP_R_CTRL,
-                        DA7219_HP_R_AMP_EN_SHIFT, DA7219_NO_INVERT, NULL, 0),
+       SND_SOC_DAPM_PGA_E("Mixout Left PGA", DA7219_MIXOUT_L_CTRL,
+                          DA7219_MIXOUT_L_AMP_EN_SHIFT, DA7219_NO_INVERT,
+                          NULL, 0, da7219_mixout_event,
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_PGA_E("Mixout Right PGA", DA7219_MIXOUT_R_CTRL,
+                          DA7219_MIXOUT_R_AMP_EN_SHIFT, DA7219_NO_INVERT,
+                          NULL, 0, da7219_mixout_event,
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_SUPPLY_S("Headphone Left PGA", 1, DA7219_HP_L_CTRL,
+                             DA7219_HP_L_AMP_EN_SHIFT, DA7219_NO_INVERT,
+                             da7219_settling_event,
+                             SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S("Headphone Right PGA", 1, DA7219_HP_R_CTRL,
+                             DA7219_HP_R_AMP_EN_SHIFT, DA7219_NO_INVERT,
+                             da7219_settling_event,
+                             SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
        /* Output Supplies */
-       SND_SOC_DAPM_SUPPLY("Charge Pump", DA7219_CP_CTRL, DA7219_CP_EN_SHIFT,
-                           DA7219_NO_INVERT, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("Charge Pump", 0, DA7219_CP_CTRL,
+                             DA7219_CP_EN_SHIFT, DA7219_NO_INVERT,
+                             da7219_settling_event,
+                             SND_SOC_DAPM_POST_PMU),
 
        /* Outputs */
        SND_SOC_DAPM_OUTPUT("HPL"),
        SND_SOC_DAPM_OUTPUT("HPR"),
+
+       /* Pre/Post Power */
+       SND_SOC_DAPM_PRE("Pre Power Gain Ramp", da7219_gain_ramp_event),
+       SND_SOC_DAPM_POST("Post Power Gain Ramp", da7219_gain_ramp_event),
 };
 
 
@@ -1003,8 +1098,8 @@ static const struct snd_soc_dapm_route da7219_audio_map[] = {
        {"Mixout Left PGA", NULL, "DACL"},
        {"Mixout Right PGA", NULL, "DACR"},
 
-       {"Headphone Left PGA", NULL, "Mixout Left PGA"},
-       {"Headphone Right PGA", NULL, "Mixout Right PGA"},
+       {"HPL", NULL, "Mixout Left PGA"},
+       {"HPR", NULL, "Mixout Right PGA"},
 
        {"HPL", NULL, "Headphone Left PGA"},
        {"HPR", NULL, "Headphone Right PGA"},
@@ -1712,6 +1807,14 @@ static int da7219_probe(struct snd_soc_codec *codec)
                            DA7219_HP_R_AMP_RAMP_EN_MASK,
                            DA7219_HP_R_AMP_RAMP_EN_MASK);
 
+       /* Default minimum gain on HP to avoid pops during DAPM sequencing */
+       snd_soc_update_bits(codec, DA7219_HP_L_CTRL,
+                           DA7219_HP_L_AMP_MIN_GAIN_EN_MASK,
+                           DA7219_HP_L_AMP_MIN_GAIN_EN_MASK);
+       snd_soc_update_bits(codec, DA7219_HP_R_CTRL,
+                           DA7219_HP_R_AMP_MIN_GAIN_EN_MASK,
+                           DA7219_HP_R_AMP_MIN_GAIN_EN_MASK);
+
        /* Default infinite tone gen, start/stop by Kcontrol */
        snd_soc_write(codec, DA7219_TONE_GEN_CYCLES, DA7219_BEEP_CYCLES_MASK);
 
index 66d3bad8673928d2e1e988a808f3431584056900..6baba7455fa12a2759f8e103d75fa834d0eb0fd2 100644 (file)
 #define DA7219_SYS_STAT_CHECK_RETRIES  6
 #define DA7219_SYS_STAT_CHECK_DELAY    50
 
+/* Power up/down Delays */
+#define DA7219_SETTLING_DELAY  40
+#define DA7219_MIN_GAIN_DELAY  30
+
 enum da7219_clk_src {
        DA7219_CLKSRC_MCLK = 0,
        DA7219_CLKSRC_MCLK_SQR,
@@ -814,6 +818,7 @@ struct da7219_priv {
 
        bool master;
        bool alc_en;
+       u8 gain_ramp_ctrl;
 };
 
 #endif /* __DA7219_H */
index b392e51de94d173a20b130ad663b6af7c1e25f19..420d200f9a0533bd335224784c2e7933a0c8c3b1 100644 (file)
@@ -78,6 +78,9 @@ static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream)
        dma_ch = 0;
        if (v->alloc_dma_channel)
                dma_ch = v->alloc_dma_channel(drvdata, dir);
+       else
+               dma_ch = 0;
+
        if (dma_ch < 0)
                return dma_ch;