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>
This commit is contained in:
Takashi Iwai 2012-02-01 10:33:23 +01:00
parent 924339239f
commit e9d010c2e8
1 changed files with 21 additions and 6 deletions

View File

@ -199,6 +199,9 @@ struct via_spec {
unsigned int no_pin_power_ctl;
enum VIA_HDA_CODEC codec_type;
/* analog low-power control */
bool alc_mode;
/* smart51 setup */
unsigned int smart51_nums;
hda_nid_t smart51_pins[2];
@ -758,6 +761,7 @@ static int via_pin_power_ctl_put(struct snd_kcontrol *kcontrol,
return 0;
spec->no_pin_power_ctl = val;
set_widgets_power_state(codec);
analog_low_current_mode(codec);
return 1;
}
@ -1045,13 +1049,19 @@ static bool is_aa_path_mute(struct hda_codec *codec)
}
/* enter/exit analog low-current mode */
static void analog_low_current_mode(struct hda_codec *codec)
static void __analog_low_current_mode(struct hda_codec *codec, bool force)
{
struct via_spec *spec = codec->spec;
bool enable;
unsigned int verb, parm;
enable = is_aa_path_mute(codec) && !spec->opened_streams;
if (spec->no_pin_power_ctl)
enable = false;
else
enable = is_aa_path_mute(codec) && !spec->opened_streams;
if (enable == spec->alc_mode && !force)
return;
spec->alc_mode = enable;
/* decide low current mode's verb & parameter */
switch (spec->codec_type) {
@ -1083,6 +1093,11 @@ static void analog_low_current_mode(struct hda_codec *codec)
snd_hda_codec_write(codec, codec->afg, 0, verb, parm);
}
static void analog_low_current_mode(struct hda_codec *codec)
{
return __analog_low_current_mode(codec, false);
}
/*
* generic initialization of ADC, input mixers and output mixers
*/
@ -1508,10 +1523,6 @@ static int via_build_controls(struct hda_codec *codec)
return err;
}
/* init power states */
set_widgets_power_state(codec);
analog_low_current_mode(codec);
via_free_kctls(codec); /* no longer needed */
err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
@ -2782,6 +2793,10 @@ static int via_init(struct hda_codec *codec)
for (i = 0; i < spec->num_iverbs; i++)
snd_hda_sequence_write(codec, spec->init_verbs[i]);
/* init power states */
set_widgets_power_state(codec);
__analog_low_current_mode(codec, true);
via_auto_init_multi_out(codec);
via_auto_init_hp_out(codec);
via_auto_init_speaker_out(codec);