aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHector Martin <hector@marcansoft.com>2009-12-20 16:51:31 -0500
committerTakashi Iwai <tiwai@suse.de>2009-12-21 05:20:29 -0500
commitf5de24b06aa46427500d0fdbe8616b73a71d8c28 (patch)
tree97ce905a10b013357df2abf716af2e3795efa55e
parent556eea9a926bff8f014b4f80522b4de97ae84213 (diff)
ALSA: HDA: add powersaving hook for Realtek
The current Realtek code makes no specific provision for turning stuff off. The codec chip is placed into low-power mode generically, but this doesn't turn off any external hardware connected to it, in particular external amplifiers. This patch creates a hook function that is called by the codec suspend/resume functions. It ought to disable any external hardware in a device-specific way. I've implemented a generic ALC889 function that sets the EAPD pin properly, and used it for the Acer Aspire 8930G which can benefit from this feature. On my laptop, this results in ~0.5W extra savings. Signed-off-by: Hector Martin <hector@marcansoft.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/pci/hda/patch_realtek.c36
1 files changed, 36 insertions, 0 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index faeb74f28207..b3abe9ca826d 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -337,6 +337,9 @@ struct alc_spec {
337 /* hooks */ 337 /* hooks */
338 void (*init_hook)(struct hda_codec *codec); 338 void (*init_hook)(struct hda_codec *codec);
339 void (*unsol_event)(struct hda_codec *codec, unsigned int res); 339 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
340#ifdef CONFIG_SND_HDA_POWER_SAVE
341 void (*power_hook)(struct hda_codec *codec, int power);
342#endif
340 343
341 /* for pin sensing */ 344 /* for pin sensing */
342 unsigned int sense_updated: 1; 345 unsigned int sense_updated: 1;
@@ -388,6 +391,7 @@ struct alc_config_preset {
388 void (*init_hook)(struct hda_codec *); 391 void (*init_hook)(struct hda_codec *);
389#ifdef CONFIG_SND_HDA_POWER_SAVE 392#ifdef CONFIG_SND_HDA_POWER_SAVE
390 struct hda_amp_list *loopbacks; 393 struct hda_amp_list *loopbacks;
394 void (*power_hook)(struct hda_codec *codec, int power);
391#endif 395#endif
392}; 396};
393 397
@@ -900,6 +904,7 @@ static void setup_preset(struct hda_codec *codec,
900 spec->unsol_event = preset->unsol_event; 904 spec->unsol_event = preset->unsol_event;
901 spec->init_hook = preset->init_hook; 905 spec->init_hook = preset->init_hook;
902#ifdef CONFIG_SND_HDA_POWER_SAVE 906#ifdef CONFIG_SND_HDA_POWER_SAVE
907 spec->power_hook = preset->power_hook;
903 spec->loopback.amplist = preset->loopbacks; 908 spec->loopback.amplist = preset->loopbacks;
904#endif 909#endif
905 910
@@ -1826,6 +1831,16 @@ static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
1826 spec->autocfg.speaker_pins[2] = 0x1b; 1831 spec->autocfg.speaker_pins[2] = 0x1b;
1827} 1832}
1828 1833
1834#ifdef CONFIG_SND_HDA_POWER_SAVE
1835static void alc889_power_eapd(struct hda_codec *codec, int power)
1836{
1837 snd_hda_codec_write(codec, 0x14, 0,
1838 AC_VERB_SET_EAPD_BTLENABLE, power ? 2 : 0);
1839 snd_hda_codec_write(codec, 0x15, 0,
1840 AC_VERB_SET_EAPD_BTLENABLE, power ? 2 : 0);
1841}
1842#endif
1843
1829/* 1844/*
1830 * ALC880 3-stack model 1845 * ALC880 3-stack model
1831 * 1846 *
@@ -3619,12 +3634,29 @@ static void alc_free(struct hda_codec *codec)
3619 snd_hda_detach_beep_device(codec); 3634 snd_hda_detach_beep_device(codec);
3620} 3635}
3621 3636
3637#ifdef CONFIG_SND_HDA_POWER_SAVE
3638static int alc_suspend(struct hda_codec *codec, pm_message_t state)
3639{
3640 struct alc_spec *spec = codec->spec;
3641 if (spec && spec->power_hook)
3642 spec->power_hook(codec, 0);
3643 return 0;
3644}
3645#endif
3646
3622#ifdef SND_HDA_NEEDS_RESUME 3647#ifdef SND_HDA_NEEDS_RESUME
3623static int alc_resume(struct hda_codec *codec) 3648static int alc_resume(struct hda_codec *codec)
3624{ 3649{
3650#ifdef CONFIG_SND_HDA_POWER_SAVE
3651 struct alc_spec *spec = codec->spec;
3652#endif
3625 codec->patch_ops.init(codec); 3653 codec->patch_ops.init(codec);
3626 snd_hda_codec_resume_amp(codec); 3654 snd_hda_codec_resume_amp(codec);
3627 snd_hda_codec_resume_cache(codec); 3655 snd_hda_codec_resume_cache(codec);
3656#ifdef CONFIG_SND_HDA_POWER_SAVE
3657 if (spec && spec->power_hook)
3658 spec->power_hook(codec, 1);
3659#endif
3628 return 0; 3660 return 0;
3629} 3661}
3630#endif 3662#endif
@@ -3641,6 +3673,7 @@ static struct hda_codec_ops alc_patch_ops = {
3641 .resume = alc_resume, 3673 .resume = alc_resume,
3642#endif 3674#endif
3643#ifdef CONFIG_SND_HDA_POWER_SAVE 3675#ifdef CONFIG_SND_HDA_POWER_SAVE
3676 .suspend = alc_suspend,
3644 .check_power_status = alc_check_power_status, 3677 .check_power_status = alc_check_power_status,
3645#endif 3678#endif
3646}; 3679};
@@ -9420,6 +9453,9 @@ static struct alc_config_preset alc882_presets[] = {
9420 .unsol_event = alc_automute_amp_unsol_event, 9453 .unsol_event = alc_automute_amp_unsol_event,
9421 .setup = alc889_acer_aspire_8930g_setup, 9454 .setup = alc889_acer_aspire_8930g_setup,
9422 .init_hook = alc_automute_amp, 9455 .init_hook = alc_automute_amp,
9456#ifdef CONFIG_SND_HDA_POWER_SAVE
9457 .power_hook = alc889_power_eapd,
9458#endif
9423 }, 9459 },
9424 [ALC888_ACER_ASPIRE_7730G] = { 9460 [ALC888_ACER_ASPIRE_7730G] = {
9425 .mixers = { alc883_3ST_6ch_mixer, 9461 .mixers = { alc883_3ST_6ch_mixer,