Commit ef403edb authored by Takashi Iwai's avatar Takashi Iwai

ALSA: hda - Don't access stereo amps for mono channel widgets

The current HDA generic parser initializes / modifies the amp values
always in stereo, but this seems causing the problem on ALC3229 codec
that has a few mono channel widgets: namely, these mono widgets react
to actions for both channels equally.

In the driver code, we do care the mono channel and create a control
only for the left channel (as defined in HD-audio spec) for such a
node.  When the control is updated, only the left channel value is
changed.  However, in the resume, the right channel value is also
restored from the initial value we took as stereo, and this overwrites
the left channel value.  This ends up being the silent output as the
right channel has been never touched and remains muted.

This patch covers the places where unconditional stereo amp accesses
are done and converts to the conditional accesses.

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=94581
Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 2ddee91a
...@@ -692,7 +692,23 @@ static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx) ...@@ -692,7 +692,23 @@ static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx)
{ {
unsigned int caps = query_amp_caps(codec, nid, dir); unsigned int caps = query_amp_caps(codec, nid, dir);
int val = get_amp_val_to_activate(codec, nid, dir, caps, false); int val = get_amp_val_to_activate(codec, nid, dir, caps, false);
if (get_wcaps(codec, nid) & AC_WCAP_STEREO)
snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val); snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val);
else
snd_hda_codec_amp_init(codec, nid, 0, dir, idx, 0xff, val);
}
/* update the amp, doing in stereo or mono depending on NID */
static int update_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx,
unsigned int mask, unsigned int val)
{
if (get_wcaps(codec, nid) & AC_WCAP_STEREO)
return snd_hda_codec_amp_stereo(codec, nid, dir, idx,
mask, val);
else
return snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
mask, val);
} }
/* calculate amp value mask we can modify; /* calculate amp value mask we can modify;
...@@ -732,7 +748,7 @@ static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir, ...@@ -732,7 +748,7 @@ static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir,
return; return;
val &= mask; val &= mask;
snd_hda_codec_amp_stereo(codec, nid, dir, idx, mask, val); update_amp(codec, nid, dir, idx, mask, val);
} }
static void activate_amp_out(struct hda_codec *codec, struct nid_path *path, static void activate_amp_out(struct hda_codec *codec, struct nid_path *path,
...@@ -4424,12 +4440,10 @@ static void mute_all_mixer_nid(struct hda_codec *codec, hda_nid_t mix) ...@@ -4424,12 +4440,10 @@ static void mute_all_mixer_nid(struct hda_codec *codec, hda_nid_t mix)
has_amp = nid_has_mute(codec, mix, HDA_INPUT); has_amp = nid_has_mute(codec, mix, HDA_INPUT);
for (i = 0; i < nums; i++) { for (i = 0; i < nums; i++) {
if (has_amp) if (has_amp)
snd_hda_codec_amp_stereo(codec, mix, update_amp(codec, mix, HDA_INPUT, i,
HDA_INPUT, i,
0xff, HDA_AMP_MUTE); 0xff, HDA_AMP_MUTE);
else if (nid_has_volume(codec, conn[i], HDA_OUTPUT)) else if (nid_has_volume(codec, conn[i], HDA_OUTPUT))
snd_hda_codec_amp_stereo(codec, conn[i], update_amp(codec, conn[i], HDA_OUTPUT, 0,
HDA_OUTPUT, 0,
0xff, HDA_AMP_MUTE); 0xff, HDA_AMP_MUTE);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment