mirror of
https://github.com/torvalds/linux.git
synced 2024-11-01 01:31:44 +00:00
ALSA: hda - Apply 0x0f-VREF fix to all ASUS laptops with ALC861/660
It turned out that other ASUS laptops require the similar fix to enable the VREF on the pin 0x0f for the secret output amp, not only ASUS A6Rp. Moreover, it's required even when the pin is being used as the output. Thus, writing a fixed value doesn't work always. This patch applies the VREF-fix for all ASUS laptops with ALC861/660 in a fixup function that checks the current value and turns on only the VREF value no matter whether input or output direction is set. The automute function is modified as well to keep the pin VREF upon muting/unmuting via pin-control; otherwise the pin VREF is reset at plugging/unplugging a jack. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=42588 Cc: <stable@kernel.org> [v3.2+] Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
8422fa1103
commit
31150f2327
@ -177,6 +177,7 @@ struct alc_spec {
|
||||
unsigned int detect_lo:1; /* Line-out detection enabled */
|
||||
unsigned int automute_speaker_possible:1; /* there are speakers and either LO or HP */
|
||||
unsigned int automute_lo_possible:1; /* there are line outs and HP */
|
||||
unsigned int keep_vref_in_automute:1; /* Don't clear VREF in automute */
|
||||
|
||||
/* other flags */
|
||||
unsigned int no_analog :1; /* digital I/O only */
|
||||
@ -495,13 +496,24 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
|
||||
|
||||
for (i = 0; i < num_pins; i++) {
|
||||
hda_nid_t nid = pins[i];
|
||||
unsigned int val;
|
||||
if (!nid)
|
||||
break;
|
||||
switch (spec->automute_mode) {
|
||||
case ALC_AUTOMUTE_PIN:
|
||||
/* don't reset VREF value in case it's controlling
|
||||
* the amp (see alc861_fixup_asus_amp_vref_0f())
|
||||
*/
|
||||
if (spec->keep_vref_in_automute) {
|
||||
val = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
||||
val &= ~PIN_HP;
|
||||
} else
|
||||
val = 0;
|
||||
val |= pin_bits;
|
||||
snd_hda_codec_write(codec, nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
pin_bits);
|
||||
val);
|
||||
break;
|
||||
case ALC_AUTOMUTE_AMP:
|
||||
snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
|
||||
@ -5588,6 +5600,25 @@ enum {
|
||||
PINFIX_ASUS_A6RP,
|
||||
};
|
||||
|
||||
/* On some laptops, VREF of pin 0x0f is abused for controlling the main amp */
|
||||
static void alc861_fixup_asus_amp_vref_0f(struct hda_codec *codec,
|
||||
const struct alc_fixup *fix, int action)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
unsigned int val;
|
||||
|
||||
if (action != ALC_FIXUP_ACT_INIT)
|
||||
return;
|
||||
val = snd_hda_codec_read(codec, 0x0f, 0,
|
||||
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
||||
if (!(val & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN)))
|
||||
val |= AC_PINCTL_IN_EN;
|
||||
val |= AC_PINCTL_VREF_50;
|
||||
snd_hda_codec_write(codec, 0x0f, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, val);
|
||||
spec->keep_vref_in_automute = 1;
|
||||
}
|
||||
|
||||
static const struct alc_fixup alc861_fixups[] = {
|
||||
[PINFIX_FSC_AMILO_PI1505] = {
|
||||
.type = ALC_FIXUP_PINS,
|
||||
@ -5598,17 +5629,13 @@ static const struct alc_fixup alc861_fixups[] = {
|
||||
}
|
||||
},
|
||||
[PINFIX_ASUS_A6RP] = {
|
||||
.type = ALC_FIXUP_VERBS,
|
||||
.v.verbs = (const struct hda_verb[]) {
|
||||
/* node 0x0f VREF seems controlling the master output */
|
||||
{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
|
||||
{ }
|
||||
},
|
||||
.type = ALC_FIXUP_FUNC,
|
||||
.v.func = alc861_fixup_asus_amp_vref_0f,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct snd_pci_quirk alc861_fixup_tbl[] = {
|
||||
SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", PINFIX_ASUS_A6RP),
|
||||
SND_PCI_QUIRK_VENDOR(0x1043, "ASUS laptop", PINFIX_ASUS_A6RP),
|
||||
SND_PCI_QUIRK(0x1584, 0x2b01, "Haier W18", PINFIX_ASUS_A6RP),
|
||||
SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
|
||||
{}
|
||||
|
Loading…
Reference in New Issue
Block a user