aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/hda_codec.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2013-01-24 11:23:35 -0500
committerTakashi Iwai <tiwai@suse.de>2013-01-24 11:23:35 -0500
commit9419ab6b72325e20789a61004cf68dc9e909a009 (patch)
treef9c7a7ddaec6208153716ae798e4374ae49f06a0 /sound/pci/hda/hda_codec.c
parent25368c47aee6d909923001918041f2e94bfa02ef (diff)
ALSA: hda - Add power state filtering
Add a hook to struct hda_codec for filtering the target power state of each widget when powering up/down. The current hackish EAPD check is implemented as the default hook pointer, too. This allows codec drivers to implement own power filter. In the upcoming changes, the generic parser will have the better power filter based on the active paths. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/hda_codec.c')
-rw-r--r--sound/pci/hda/hda_codec.c39
1 files changed, 25 insertions, 14 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index e4e0501ab84a..19ff923b2431 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -1276,6 +1276,8 @@ static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec,
1276 1276
1277static unsigned int hda_set_power_state(struct hda_codec *codec, 1277static unsigned int hda_set_power_state(struct hda_codec *codec,
1278 unsigned int power_state); 1278 unsigned int power_state);
1279static unsigned int default_power_filter(struct hda_codec *codec, hda_nid_t nid,
1280 unsigned int power_state);
1279 1281
1280/** 1282/**
1281 * snd_hda_codec_new - create a HDA codec 1283 * snd_hda_codec_new - create a HDA codec
@@ -1396,6 +1398,7 @@ int snd_hda_codec_new(struct hda_bus *bus,
1396#endif 1398#endif
1397 codec->epss = snd_hda_codec_get_supported_ps(codec, fg, 1399 codec->epss = snd_hda_codec_get_supported_ps(codec, fg,
1398 AC_PWRST_EPSS); 1400 AC_PWRST_EPSS);
1401 codec->power_filter = default_power_filter;
1399 1402
1400 /* power-up all before initialization */ 1403 /* power-up all before initialization */
1401 hda_set_power_state(codec, AC_PWRST_D0); 1404 hda_set_power_state(codec, AC_PWRST_D0);
@@ -3649,29 +3652,23 @@ void snd_hda_codec_flush_cache(struct hda_codec *codec)
3649EXPORT_SYMBOL_HDA(snd_hda_codec_flush_cache); 3652EXPORT_SYMBOL_HDA(snd_hda_codec_flush_cache);
3650 3653
3651void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg, 3654void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
3652 unsigned int power_state, 3655 unsigned int power_state)
3653 bool eapd_workaround)
3654{ 3656{
3655 hda_nid_t nid = codec->start_nid; 3657 hda_nid_t nid = codec->start_nid;
3656 int i; 3658 int i;
3657 3659
3658 for (i = 0; i < codec->num_nodes; i++, nid++) { 3660 for (i = 0; i < codec->num_nodes; i++, nid++) {
3659 unsigned int wcaps = get_wcaps(codec, nid); 3661 unsigned int wcaps = get_wcaps(codec, nid);
3662 unsigned int state = power_state;
3660 if (!(wcaps & AC_WCAP_POWER)) 3663 if (!(wcaps & AC_WCAP_POWER))
3661 continue; 3664 continue;
3662 /* don't power down the widget if it controls eapd and 3665 if (codec->power_filter) {
3663 * EAPD_BTLENABLE is set. 3666 state = codec->power_filter(codec, nid, power_state);
3664 */ 3667 if (state != power_state && power_state == AC_PWRST_D3)
3665 if (eapd_workaround && power_state == AC_PWRST_D3 &&
3666 get_wcaps_type(wcaps) == AC_WID_PIN &&
3667 (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) {
3668 int eapd = snd_hda_codec_read(codec, nid, 0,
3669 AC_VERB_GET_EAPD_BTLENABLE, 0);
3670 if (eapd & 0x02)
3671 continue; 3668 continue;
3672 } 3669 }
3673 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, 3670 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE,
3674 power_state); 3671 state);
3675 } 3672 }
3676} 3673}
3677EXPORT_SYMBOL_HDA(snd_hda_codec_set_power_to_all); 3674EXPORT_SYMBOL_HDA(snd_hda_codec_set_power_to_all);
@@ -3718,6 +3715,21 @@ static unsigned int hda_sync_power_state(struct hda_codec *codec,
3718 return state; 3715 return state;
3719} 3716}
3720 3717
3718/* don't power down the widget if it controls eapd and EAPD_BTLENABLE is set */
3719static unsigned int default_power_filter(struct hda_codec *codec, hda_nid_t nid,
3720 unsigned int power_state)
3721{
3722 if (power_state == AC_PWRST_D3 &&
3723 get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_PIN &&
3724 (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) {
3725 int eapd = snd_hda_codec_read(codec, nid, 0,
3726 AC_VERB_GET_EAPD_BTLENABLE, 0);
3727 if (eapd & 0x02)
3728 return AC_PWRST_D0;
3729 }
3730 return power_state;
3731}
3732
3721/* 3733/*
3722 * set power state of the codec, and return the power state 3734 * set power state of the codec, and return the power state
3723 */ 3735 */
@@ -3743,8 +3755,7 @@ static unsigned int hda_set_power_state(struct hda_codec *codec,
3743 snd_hda_codec_read(codec, fg, 0, 3755 snd_hda_codec_read(codec, fg, 0,
3744 AC_VERB_SET_POWER_STATE, 3756 AC_VERB_SET_POWER_STATE,
3745 power_state); 3757 power_state);
3746 snd_hda_codec_set_power_to_all(codec, fg, power_state, 3758 snd_hda_codec_set_power_to_all(codec, fg, power_state);
3747 true);
3748 } 3759 }
3749 state = hda_sync_power_state(codec, fg, power_state); 3760 state = hda_sync_power_state(codec, fg, power_state);
3750 if (!(state & AC_PWRST_ERROR)) 3761 if (!(state & AC_PWRST_ERROR))