ASoC: cs42l73: Add DAPM events for power down.
authorPaul Handrigan <Paul.Handrigan@cirrus.com>
Fri, 7 Dec 2012 20:53:43 +0000 (14:53 -0600)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Mon, 10 Dec 2012 03:26:46 +0000 (12:26 +0900)
Add power down delays between setting PDN and MCLKDIS for spk amp, spklo amp, and ear amp.

Signed-off-by: Paul Handrigan <Paul.Handrigan@cirrus.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
sound/soc/codecs/cs42l73.c

index 4766795..fb9b178 100644 (file)
@@ -40,6 +40,7 @@ struct  cs42l73_private {
        u32 sysclk;
        u8 mclksel;
        u32 mclk;
+       int shutdwn_delay;
 };
 
 static const struct reg_default cs42l73_reg_defaults[] = {
@@ -588,6 +589,57 @@ static const struct snd_kcontrol_new cs42l73_snd_controls[] = {
        SOC_ENUM("XSPOUT Mono/Stereo Select", xsp_output_mux_enum),
 };
 
+static int cs42l73_spklo_spk_amp_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMD:
+               /* 150 ms delay between setting PDN and MCLKDIS */
+               priv->shutdwn_delay = 150;
+               break;
+       default:
+               pr_err("Invalid event = 0x%x\n", event);
+       }
+       return 0;
+}
+
+static int cs42l73_ear_amp_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMD:
+               /* 50 ms delay between setting PDN and MCLKDIS */
+               if (priv->shutdwn_delay < 50)
+                       priv->shutdwn_delay = 50;
+               break;
+       default:
+               pr_err("Invalid event = 0x%x\n", event);
+       }
+       return 0;
+}
+
+
+static int cs42l73_hp_amp_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMD:
+               /* 30 ms delay between setting PDN and MCLKDIS */
+               if (priv->shutdwn_delay < 30)
+                       priv->shutdwn_delay = 30;
+               break;
+       default:
+               pr_err("Invalid event = 0x%x\n", event);
+       }
+       return 0;
+}
+
 static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = {
        SND_SOC_DAPM_INPUT("DMICA"),
        SND_SOC_DAPM_INPUT("DMICB"),
@@ -676,16 +728,20 @@ static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = {
        SND_SOC_DAPM_PGA("SPK DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
        SND_SOC_DAPM_PGA("ESL DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
 
-       SND_SOC_DAPM_SWITCH("HP Amp", CS42L73_PWRCTL3, 0, 1,
-                           &hp_amp_ctl),
+       SND_SOC_DAPM_SWITCH_E("HP Amp",  CS42L73_PWRCTL3, 0, 1,
+                           &hp_amp_ctl, cs42l73_hp_amp_event,
+                       SND_SOC_DAPM_POST_PMD),
        SND_SOC_DAPM_SWITCH("LO Amp", CS42L73_PWRCTL3, 1, 1,
                            &lo_amp_ctl),
-       SND_SOC_DAPM_SWITCH("SPK Amp", CS42L73_PWRCTL3, 2, 1,
-                           &spk_amp_ctl),
-       SND_SOC_DAPM_SWITCH("EAR Amp", CS42L73_PWRCTL3, 3, 1,
-                           &ear_amp_ctl),
-       SND_SOC_DAPM_SWITCH("SPKLO Amp", CS42L73_PWRCTL3, 4, 1,
-                           &spklo_amp_ctl),
+       SND_SOC_DAPM_SWITCH_E("SPK Amp", CS42L73_PWRCTL3, 2, 1,
+                       &spk_amp_ctl, cs42l73_spklo_spk_amp_event,
+                       SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SWITCH_E("EAR Amp", CS42L73_PWRCTL3, 3, 1,
+                           &ear_amp_ctl, cs42l73_ear_amp_event,
+                       SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SWITCH_E("SPKLO Amp", CS42L73_PWRCTL3, 4, 1,
+                           &spklo_amp_ctl, cs42l73_spklo_spk_amp_event,
+                       SND_SOC_DAPM_POST_PMD),
 
        SND_SOC_DAPM_OUTPUT("HPOUTA"),
        SND_SOC_DAPM_OUTPUT("HPOUTB"),
@@ -1171,6 +1227,14 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec,
 
        case SND_SOC_BIAS_OFF:
                snd_soc_update_bits(codec, CS42L73_PWRCTL1, PDN, 1);
+               if (cs42l73->shutdwn_delay > 0) {
+                       mdelay(cs42l73->shutdwn_delay);
+                       cs42l73->shutdwn_delay = 0;
+               } else {
+                       mdelay(15); /* Min amount of time requred to power
+                                    * down.
+                                    */
+               }
                snd_soc_update_bits(codec, CS42L73_DMMCC, MCLKDIS, 1);
                break;
        }