diff options
| author | Takashi Iwai <tiwai@suse.de> | 2012-02-01 04:33:23 -0500 |
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2012-02-02 04:18:09 -0500 |
| commit | e9d010c2e8f03952e67a6fd8aed0f0dc92084ccc (patch) | |
| tree | ef54a3c768f43e761577dd67d682cc680865981a | |
| parent | 924339239fd5ba3e505f9420d41f0939196f3530 (diff) | |
ALSA: hda - Allow analog low-current mode when dynamic power-control is on
VIA codecs have several different power-saving features, and one of
them is the analog low-current mode. But it turned out that the ALC
mode causes pop-noises at each on/off time on some machines. As a
quick workaround, disable the ALC when another power-saving feature,
the dynamic pin power-control, is turned off, too, since the dynamic
power-control is already exposed as a mixer enum element so that user
can turn it on/off freely.
Bugzilla: https://bugzilla.novell.com/show_bug.cgi?id=741128
Cc: <stable@kernel.org> [v3.1+]
Signed-off-by: Takashi Iwai <tiwai@suse.de>
| -rw-r--r-- | sound/pci/hda/patch_via.c | 27 |
1 files changed, 21 insertions, 6 deletions
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index de43cd92b0a5..79166fb8b074 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c | |||
| @@ -199,6 +199,9 @@ struct via_spec { | |||
| 199 | unsigned int no_pin_power_ctl; | 199 | unsigned int no_pin_power_ctl; |
| 200 | enum VIA_HDA_CODEC codec_type; | 200 | enum VIA_HDA_CODEC codec_type; |
| 201 | 201 | ||
| 202 | /* analog low-power control */ | ||
| 203 | bool alc_mode; | ||
| 204 | |||
| 202 | /* smart51 setup */ | 205 | /* smart51 setup */ |
| 203 | unsigned int smart51_nums; | 206 | unsigned int smart51_nums; |
| 204 | hda_nid_t smart51_pins[2]; | 207 | hda_nid_t smart51_pins[2]; |
| @@ -758,6 +761,7 @@ static int via_pin_power_ctl_put(struct snd_kcontrol *kcontrol, | |||
| 758 | return 0; | 761 | return 0; |
| 759 | spec->no_pin_power_ctl = val; | 762 | spec->no_pin_power_ctl = val; |
| 760 | set_widgets_power_state(codec); | 763 | set_widgets_power_state(codec); |
| 764 | analog_low_current_mode(codec); | ||
| 761 | return 1; | 765 | return 1; |
| 762 | } | 766 | } |
| 763 | 767 | ||
| @@ -1045,13 +1049,19 @@ static bool is_aa_path_mute(struct hda_codec *codec) | |||
| 1045 | } | 1049 | } |
| 1046 | 1050 | ||
| 1047 | /* enter/exit analog low-current mode */ | 1051 | /* enter/exit analog low-current mode */ |
| 1048 | static void analog_low_current_mode(struct hda_codec *codec) | 1052 | static void __analog_low_current_mode(struct hda_codec *codec, bool force) |
| 1049 | { | 1053 | { |
| 1050 | struct via_spec *spec = codec->spec; | 1054 | struct via_spec *spec = codec->spec; |
| 1051 | bool enable; | 1055 | bool enable; |
| 1052 | unsigned int verb, parm; | 1056 | unsigned int verb, parm; |
| 1053 | 1057 | ||
| 1054 | enable = is_aa_path_mute(codec) && !spec->opened_streams; | 1058 | if (spec->no_pin_power_ctl) |
| 1059 | enable = false; | ||
| 1060 | else | ||
| 1061 | enable = is_aa_path_mute(codec) && !spec->opened_streams; | ||
| 1062 | if (enable == spec->alc_mode && !force) | ||
| 1063 | return; | ||
| 1064 | spec->alc_mode = enable; | ||
| 1055 | 1065 | ||
| 1056 | /* decide low current mode's verb & parameter */ | 1066 | /* decide low current mode's verb & parameter */ |
| 1057 | switch (spec->codec_type) { | 1067 | switch (spec->codec_type) { |
| @@ -1083,6 +1093,11 @@ static void analog_low_current_mode(struct hda_codec *codec) | |||
| 1083 | snd_hda_codec_write(codec, codec->afg, 0, verb, parm); | 1093 | snd_hda_codec_write(codec, codec->afg, 0, verb, parm); |
| 1084 | } | 1094 | } |
| 1085 | 1095 | ||
| 1096 | static void analog_low_current_mode(struct hda_codec *codec) | ||
| 1097 | { | ||
| 1098 | return __analog_low_current_mode(codec, false); | ||
| 1099 | } | ||
| 1100 | |||
| 1086 | /* | 1101 | /* |
| 1087 | * generic initialization of ADC, input mixers and output mixers | 1102 | * generic initialization of ADC, input mixers and output mixers |
| 1088 | */ | 1103 | */ |
| @@ -1508,10 +1523,6 @@ static int via_build_controls(struct hda_codec *codec) | |||
| 1508 | return err; | 1523 | return err; |
| 1509 | } | 1524 | } |
| 1510 | 1525 | ||
| 1511 | /* init power states */ | ||
| 1512 | set_widgets_power_state(codec); | ||
| 1513 | analog_low_current_mode(codec); | ||
| 1514 | |||
| 1515 | via_free_kctls(codec); /* no longer needed */ | 1526 | via_free_kctls(codec); /* no longer needed */ |
| 1516 | 1527 | ||
| 1517 | err = snd_hda_jack_add_kctls(codec, &spec->autocfg); | 1528 | err = snd_hda_jack_add_kctls(codec, &spec->autocfg); |
| @@ -2782,6 +2793,10 @@ static int via_init(struct hda_codec *codec) | |||
| 2782 | for (i = 0; i < spec->num_iverbs; i++) | 2793 | for (i = 0; i < spec->num_iverbs; i++) |
| 2783 | snd_hda_sequence_write(codec, spec->init_verbs[i]); | 2794 | snd_hda_sequence_write(codec, spec->init_verbs[i]); |
| 2784 | 2795 | ||
| 2796 | /* init power states */ | ||
| 2797 | set_widgets_power_state(codec); | ||
| 2798 | __analog_low_current_mode(codec, true); | ||
| 2799 | |||
| 2785 | via_auto_init_multi_out(codec); | 2800 | via_auto_init_multi_out(codec); |
| 2786 | via_auto_init_hp_out(codec); | 2801 | via_auto_init_hp_out(codec); |
| 2787 | via_auto_init_speaker_out(codec); | 2802 | via_auto_init_speaker_out(codec); |
