mirror of
https://github.com/torvalds/linux
synced 2024-10-10 21:36:41 +00:00
ALSA: hda - More strict correction of invalid pinctl bits
Check more strictly about the validity of pinctl values in snd_hda_set_pin_ctl() and correct the wrong bits automatically. Also provide the helper function to correct pinctl bits to codec drivers. This automatically fixes the invalid pinctl writes that are found in a few Realtek fixups for NID 0x0f amp like ASUS A6Rp. Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
d7fdc00ae5
commit
62f3a2f718
|
@ -5275,23 +5275,61 @@ unsigned int snd_hda_get_default_vref(struct hda_codec *codec, hda_nid_t pin)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_HDA(snd_hda_get_default_vref);
|
EXPORT_SYMBOL_HDA(snd_hda_get_default_vref);
|
||||||
|
|
||||||
|
/* correct the pin ctl value for matching with the pin cap */
|
||||||
|
unsigned int snd_hda_correct_pin_ctl(struct hda_codec *codec,
|
||||||
|
hda_nid_t pin, unsigned int val)
|
||||||
|
{
|
||||||
|
static unsigned int cap_lists[][2] = {
|
||||||
|
{ AC_PINCTL_VREF_100, AC_PINCAP_VREF_100 },
|
||||||
|
{ AC_PINCTL_VREF_80, AC_PINCAP_VREF_80 },
|
||||||
|
{ AC_PINCTL_VREF_50, AC_PINCAP_VREF_50 },
|
||||||
|
{ AC_PINCTL_VREF_GRD, AC_PINCAP_VREF_GRD },
|
||||||
|
};
|
||||||
|
unsigned int cap;
|
||||||
|
|
||||||
|
if (!val)
|
||||||
|
return 0;
|
||||||
|
cap = snd_hda_query_pin_caps(codec, pin);
|
||||||
|
if (!cap)
|
||||||
|
return val; /* don't know what to do... */
|
||||||
|
|
||||||
|
if (val & AC_PINCTL_OUT_EN) {
|
||||||
|
if (!(cap & AC_PINCAP_OUT))
|
||||||
|
val &= ~(AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
|
||||||
|
else if ((val & AC_PINCTL_HP_EN) && !(cap & AC_PINCAP_HP_DRV))
|
||||||
|
val &= ~AC_PINCTL_HP_EN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val & AC_PINCTL_IN_EN) {
|
||||||
|
if (!(cap & AC_PINCAP_IN))
|
||||||
|
val &= ~(AC_PINCTL_IN_EN | AC_PINCTL_VREFEN);
|
||||||
|
else {
|
||||||
|
unsigned int vcap, vref;
|
||||||
|
int i;
|
||||||
|
vcap = (cap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
|
||||||
|
vref = val & AC_PINCTL_VREFEN;
|
||||||
|
for (i = 0; i < ARRAY_SIZE(cap_lists); i++) {
|
||||||
|
if (vref == cap_lists[i][0] &&
|
||||||
|
!(vcap & cap_lists[i][1])) {
|
||||||
|
if (i == ARRAY_SIZE(cap_lists) - 1)
|
||||||
|
vref = AC_PINCTL_VREF_HIZ;
|
||||||
|
else
|
||||||
|
vref = cap_lists[i + 1][0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val &= ~AC_PINCTL_VREFEN;
|
||||||
|
val |= vref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_HDA(snd_hda_correct_pin_ctl);
|
||||||
|
|
||||||
int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin,
|
int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin,
|
||||||
unsigned int val, bool cached)
|
unsigned int val, bool cached)
|
||||||
{
|
{
|
||||||
if (val) {
|
val = snd_hda_correct_pin_ctl(codec, pin, val);
|
||||||
unsigned int cap = snd_hda_query_pin_caps(codec, pin);
|
|
||||||
if (cap && (val & AC_PINCTL_OUT_EN)) {
|
|
||||||
if (!(cap & AC_PINCAP_OUT))
|
|
||||||
val &= ~(AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
|
|
||||||
else if ((val & AC_PINCTL_HP_EN) &&
|
|
||||||
!(cap & AC_PINCAP_HP_DRV))
|
|
||||||
val &= ~AC_PINCTL_HP_EN;
|
|
||||||
}
|
|
||||||
if (cap && (val & AC_PINCTL_IN_EN)) {
|
|
||||||
if (!(cap & AC_PINCAP_IN))
|
|
||||||
val &= ~(AC_PINCTL_IN_EN | AC_PINCTL_VREFEN);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
snd_hda_codec_set_pin_target(codec, pin, val);
|
snd_hda_codec_set_pin_target(codec, pin, val);
|
||||||
if (cached)
|
if (cached)
|
||||||
return snd_hda_codec_update_cache(codec, pin, 0,
|
return snd_hda_codec_update_cache(codec, pin, 0,
|
||||||
|
|
|
@ -490,6 +490,8 @@ struct hda_bus_unsolicited {
|
||||||
#define PIN_HP_AMP (AC_PINCTL_HP_EN)
|
#define PIN_HP_AMP (AC_PINCTL_HP_EN)
|
||||||
|
|
||||||
unsigned int snd_hda_get_default_vref(struct hda_codec *codec, hda_nid_t pin);
|
unsigned int snd_hda_get_default_vref(struct hda_codec *codec, hda_nid_t pin);
|
||||||
|
unsigned int snd_hda_correct_pin_ctl(struct hda_codec *codec,
|
||||||
|
hda_nid_t pin, unsigned int val);
|
||||||
int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin,
|
int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin,
|
||||||
unsigned int val, bool cached);
|
unsigned int val, bool cached);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue