ALSA: hda: Add powerdown for Analog Devices HDA codecs
authorDaniel T Chen <crimsun@ubuntu.com>
Sun, 27 Dec 2009 23:48:29 +0000 (18:48 -0500)
committerTakashi Iwai <tiwai@suse.de>
Mon, 28 Dec 2009 11:15:17 +0000 (12:15 +0100)
This patch ports powerdown fixes to AD198x. Currently we only turn off
Front and HP for suspend, but this is easily extended for additional
nids.

Signed-off-by: Daniel T Chen <crimsun@ubuntu.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/patch_analog.c

index 45ee352..cecd3c1 100644 (file)
@@ -441,6 +441,11 @@ static int ad198x_build_pcms(struct hda_codec *codec)
        return 0;
 }
 
+static inline void ad198x_shutup(struct hda_codec *codec)
+{
+       snd_hda_shutup_pins(codec);
+}
+
 static void ad198x_free_kctls(struct hda_codec *codec)
 {
        struct ad198x_spec *spec = codec->spec;
@@ -454,6 +459,46 @@ static void ad198x_free_kctls(struct hda_codec *codec)
        snd_array_free(&spec->kctls);
 }
 
+static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front,
+                               hda_nid_t hp)
+{
+       struct ad198x_spec *spec = codec->spec;
+       snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE,
+                           !spec->inv_eapd ? 0x00 : 0x02);
+       snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE,
+                           !spec->inv_eapd ? 0x00 : 0x02);
+}
+
+static void ad198x_power_eapd(struct hda_codec *codec)
+{
+       /* We currently only handle front, HP */
+       switch (codec->vendor_id) {
+       case 0x11d41882:
+       case 0x11d4882a:
+       case 0x11d41884:
+       case 0x11d41984:
+       case 0x11d41883:
+       case 0x11d4184a:
+       case 0x11d4194a:
+       case 0x11d4194b:
+               ad198x_power_eapd_write(codec, 0x12, 0x11);
+               break;
+       case 0x11d41981:
+       case 0x11d41983:
+               ad198x_power_eapd_write(codec, 0x05, 0x06);
+               break;
+       case 0x11d41986:
+               ad198x_power_eapd_write(codec, 0x1b, 0x1a);
+               break;
+       case 0x11d41988:
+       case 0x11d4198b:
+       case 0x11d4989a:
+       case 0x11d4989b:
+               ad198x_power_eapd_write(codec, 0x29, 0x22);
+               break;
+       }
+}
+
 static void ad198x_free(struct hda_codec *codec)
 {
        struct ad198x_spec *spec = codec->spec;
@@ -461,11 +506,29 @@ static void ad198x_free(struct hda_codec *codec)
        if (!spec)
                return;
 
+       ad198x_shutup(codec);
        ad198x_free_kctls(codec);
        kfree(spec);
        snd_hda_detach_beep_device(codec);
 }
 
+#ifdef SND_HDA_NEEDS_RESUME
+static int ad198x_suspend(struct hda_codec *codec, pm_message_t state)
+{
+       ad198x_shutup(codec);
+       ad198x_power_eapd(codec);
+       return 0;
+}
+
+static int ad198x_resume(struct hda_codec *codec)
+{
+       ad198x_init(codec);
+       snd_hda_codec_resume_amp(codec);
+       snd_hda_codec_resume_cache(codec);
+       return 0;
+}
+#endif
+
 static struct hda_codec_ops ad198x_patch_ops = {
        .build_controls = ad198x_build_controls,
        .build_pcms = ad198x_build_pcms,
@@ -474,6 +537,11 @@ static struct hda_codec_ops ad198x_patch_ops = {
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        .check_power_status = ad198x_check_power_status,
 #endif
+#ifdef SND_HDA_NEEDS_RESUME
+       .suspend = ad198x_suspend,
+       .resume = ad198x_resume,
+#endif
+       .reboot_notify = ad198x_shutup,
 };