const hda_nid_t *capsrc_nids;
hda_nid_t dig_in_nid; /* digital-in NID; optional */
hda_nid_t mixer_nid; /* analog-mixer NID */
+ DECLARE_BITMAP(vol_ctls, 0x20 << 1);
+ DECLARE_BITMAP(sw_ctls, 0x20 << 1);
/* capture setup for dynamic dual-adc switch */
hda_nid_t cur_adc;
void (*automute_hook)(struct hda_codec *codec);
/* for pin sensing */
- unsigned int jack_present: 1;
+ unsigned int hp_jack_present:1;
unsigned int line_jack_present:1;
unsigned int master_mute:1;
unsigned int auto_mic:1;
unsigned int auto_mic_valid_imux:1; /* valid imux for auto-mic */
- unsigned int automute:1; /* HP automute enabled */
- unsigned int detect_line:1; /* Line-out detection enabled */
- unsigned int automute_lines:1; /* automute line-out as well */
- unsigned int automute_hp_lo:1; /* both HP and LO available */
+ unsigned int automute_speaker:1; /* automute speaker outputs */
+ unsigned int automute_lo:1; /* automute LO outputs */
+ unsigned int detect_hp:1; /* Headphone detection enabled */
+ 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 */
/* other flags */
unsigned int no_analog :1; /* digital I/O only */
/* for PLL fix */
hda_nid_t pll_nid;
unsigned int pll_coef_idx, pll_coef_bit;
+ unsigned int coef0;
/* fix-up list */
int fixup_id;
}
}
-/* Toggle internal speakers muting */
-static void update_speakers(struct hda_codec *codec)
+/* Toggle outputs muting */
+static void update_outputs(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
int on;
do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
spec->autocfg.hp_pins, spec->master_mute, true);
- if (!spec->automute)
+ if (!spec->automute_speaker)
on = 0;
else
- on = spec->jack_present | spec->line_jack_present;
+ on = spec->hp_jack_present | spec->line_jack_present;
on |= spec->master_mute;
do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins),
spec->autocfg.speaker_pins, on, false);
if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] ||
spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0])
return;
- if (!spec->automute_lines || !spec->automute)
+ if (!spec->automute_lo)
on = 0;
else
- on = spec->jack_present;
+ on = spec->hp_jack_present;
on |= spec->master_mute;
do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
spec->autocfg.line_out_pins, on, false);
}
-static void call_update_speakers(struct hda_codec *codec)
+static void call_update_outputs(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
if (spec->automute_hook)
spec->automute_hook(codec);
else
- update_speakers(codec);
+ update_outputs(codec);
}
/* standard HP-automute helper */
{
struct alc_spec *spec = codec->spec;
- spec->jack_present =
+ spec->hp_jack_present =
detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
spec->autocfg.hp_pins);
- if (!spec->automute)
+ if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo))
return;
- call_update_speakers(codec);
+ call_update_outputs(codec);
}
/* standard line-out-automute helper */
{
struct alc_spec *spec = codec->spec;
+ /* check LO jack only when it's different from HP */
+ if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0])
+ return;
+
spec->line_jack_present =
detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
spec->autocfg.line_out_pins);
- if (!spec->automute || !spec->detect_line)
+ if (!spec->automute_speaker || !spec->detect_lo)
return;
- call_update_speakers(codec);
+ call_update_outputs(codec);
}
#define get_connection_index(codec, mux, nid) \
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
- if (spec->automute_hp_lo) {
+ if (spec->automute_speaker_possible && spec->automute_lo_possible) {
uinfo->value.enumerated.items = 3;
texts = texts3;
} else {
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct alc_spec *spec = codec->spec;
- unsigned int val;
- if (!spec->automute)
- val = 0;
- else if (!spec->automute_lines)
- val = 1;
- else
- val = 2;
+ unsigned int val = 0;
+ if (spec->automute_speaker)
+ val++;
+ if (spec->automute_lo)
+ val++;
+
ucontrol->value.enumerated.item[0] = val;
return 0;
}
switch (ucontrol->value.enumerated.item[0]) {
case 0:
- if (!spec->automute)
+ if (!spec->automute_speaker && !spec->automute_lo)
return 0;
- spec->automute = 0;
+ spec->automute_speaker = 0;
+ spec->automute_lo = 0;
break;
case 1:
- if (spec->automute && !spec->automute_lines)
- return 0;
- spec->automute = 1;
- spec->automute_lines = 0;
+ if (spec->automute_speaker_possible) {
+ if (!spec->automute_lo && spec->automute_speaker)
+ return 0;
+ spec->automute_speaker = 1;
+ spec->automute_lo = 0;
+ } else if (spec->automute_lo_possible) {
+ if (spec->automute_lo)
+ return 0;
+ spec->automute_lo = 1;
+ } else
+ return -EINVAL;
break;
case 2:
- if (!spec->automute_hp_lo)
+ if (!spec->automute_lo_possible || !spec->automute_speaker_possible)
return -EINVAL;
- if (spec->automute && spec->automute_lines)
+ if (spec->automute_speaker && spec->automute_lo)
return 0;
- spec->automute = 1;
- spec->automute_lines = 1;
+ spec->automute_speaker = 1;
+ spec->automute_lo = 1;
break;
default:
return -EINVAL;
}
- call_update_speakers(codec);
+ call_update_outputs(codec);
return 1;
}
* Check the availability of HP/line-out auto-mute;
* Set up appropriately if really supported
*/
-static void alc_init_auto_hp(struct hda_codec *codec)
+static void alc_init_automute(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
present++;
if (present < 2) /* need two different output types */
return;
- if (present == 3)
- spec->automute_hp_lo = 1; /* both HP and LO automute */
if (!cfg->speaker_pins[0] &&
cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
cfg->hp_outs = cfg->line_outs;
}
+ spec->automute_mode = ALC_AUTOMUTE_PIN;
+
for (i = 0; i < cfg->hp_outs; i++) {
hda_nid_t nid = cfg->hp_pins[i];
if (!is_jack_detectable(codec, nid))
snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_UNSOLICITED_ENABLE,
AC_USRSP_EN | ALC_HP_EVENT);
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_PIN;
- }
- if (spec->automute && cfg->line_out_pins[0] &&
- cfg->speaker_pins[0] &&
- cfg->line_out_pins[0] != cfg->hp_pins[0] &&
- cfg->line_out_pins[0] != cfg->speaker_pins[0]) {
- for (i = 0; i < cfg->line_outs; i++) {
- hda_nid_t nid = cfg->line_out_pins[i];
- if (!is_jack_detectable(codec, nid))
- continue;
- snd_printdd("realtek: Enable Line-Out auto-muting "
- "on NID 0x%x\n", nid);
- snd_hda_codec_write_cache(codec, nid, 0,
- AC_VERB_SET_UNSOLICITED_ENABLE,
- AC_USRSP_EN | ALC_FRONT_EVENT);
- spec->detect_line = 1;
+ spec->detect_hp = 1;
+ }
+
+ if (cfg->line_out_type == AUTO_PIN_LINE_OUT && cfg->line_outs) {
+ if (cfg->speaker_outs)
+ for (i = 0; i < cfg->line_outs; i++) {
+ hda_nid_t nid = cfg->line_out_pins[i];
+ if (!is_jack_detectable(codec, nid))
+ continue;
+ snd_printdd("realtek: Enable Line-Out "
+ "auto-muting on NID 0x%x\n", nid);
+ snd_hda_codec_write_cache(codec, nid, 0,
+ AC_VERB_SET_UNSOLICITED_ENABLE,
+ AC_USRSP_EN | ALC_FRONT_EVENT);
+ spec->detect_lo = 1;
}
- spec->automute_lines = spec->detect_line;
+ spec->automute_lo_possible = spec->detect_hp;
}
- if (spec->automute) {
+ spec->automute_speaker_possible = cfg->speaker_outs &&
+ (spec->detect_hp || spec->detect_lo);
+
+ spec->automute_lo = spec->automute_lo_possible;
+ spec->automute_speaker = spec->automute_speaker_possible;
+
+ if (spec->automute_speaker_possible || spec->automute_lo_possible) {
/* create a control for automute mode */
alc_add_automute_mode_enum(codec);
spec->unsol_event = alc_sku_unsol_event;
/* check the availabilities of auto-mute and auto-mic switches */
static void alc_auto_check_switches(struct hda_codec *codec)
{
- alc_init_auto_hp(codec);
+ alc_init_automute(codec);
alc_init_auto_mic(codec);
}
* 15 : 1 --> enable the function "Mute internal speaker
* when the external headphone out jack is plugged"
*/
- if (!spec->autocfg.hp_pins[0]) {
+ if (!spec->autocfg.hp_pins[0] &&
+ !(spec->autocfg.line_out_pins[0] &&
+ spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)) {
hda_nid_t nid;
tmp = (ass >> 11) & 0x3; /* HP to chassis */
if (tmp == 0)
coef_val);
}
+/* a special bypass for COEF 0; read the cached value at the second time */
+static unsigned int alc_get_coef0(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ if (!spec->coef0)
+ spec->coef0 = alc_read_coef_idx(codec, 0);
+ return spec->coef0;
+}
+
/*
* Digital I/O handling
*/
struct alc_spec *spec = codec->spec;
struct hda_pcm *info = spec->pcm_rec;
const struct hda_pcm_stream *p;
+ bool have_multi_adcs;
int i;
codec->num_pcms = 1;
/* If the use of more than one ADC is requested for the current
* model, configure a second analog capture-only PCM.
*/
+ have_multi_adcs = (spec->num_adc_nids > 1) &&
+ !spec->dyn_adc_switch && !spec->auto_mic &&
+ (!spec->input_mux || spec->input_mux->num_items > 1);
/* Additional Analaog capture for index #2 */
- if (spec->alt_dac_nid || spec->num_adc_nids > 1) {
+ if (spec->alt_dac_nid || have_multi_adcs) {
codec->num_pcms = 3;
info = spec->pcm_rec + 2;
info->name = spec->stream_name_analog;
alc_pcm_null_stream;
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
}
- if (spec->num_adc_nids > 1) {
+ if (have_multi_adcs) {
p = spec->stream_analog_alt_capture;
if (!p)
p = &alc_pcm_analog_alt_capture;
return 0;
}
+/*
+ * Rename codecs appropriately from COEF value
+ */
+struct alc_codec_rename_table {
+ unsigned int vendor_id;
+ unsigned short coef_mask;
+ unsigned short coef_bits;
+ const char *name;
+};
+
+static struct alc_codec_rename_table rename_tbl[] = {
+ { 0x10ec0269, 0xfff0, 0x3010, "ALC277" },
+ { 0x10ec0269, 0xf0f0, 0x2010, "ALC259" },
+ { 0x10ec0269, 0xf0f0, 0x3010, "ALC258" },
+ { 0x10ec0269, 0x00f0, 0x0010, "ALC269VB" },
+ { 0x10ec0269, 0xffff, 0xa023, "ALC259" },
+ { 0x10ec0269, 0xffff, 0x6023, "ALC281X" },
+ { 0x10ec0269, 0x00f0, 0x0020, "ALC269VC" },
+ { 0x10ec0887, 0x00f0, 0x0030, "ALC887-VD" },
+ { 0x10ec0888, 0x00f0, 0x0030, "ALC888-VD" },
+ { 0x10ec0888, 0xf0f0, 0x3020, "ALC886" },
+ { 0x10ec0899, 0x2000, 0x2000, "ALC899" },
+ { 0x10ec0892, 0xffff, 0x8020, "ALC661" },
+ { 0x10ec0892, 0xffff, 0x8011, "ALC661" },
+ { 0x10ec0892, 0xffff, 0x4011, "ALC656" },
+ { } /* terminator */
+};
+
+static int alc_codec_rename_from_preset(struct hda_codec *codec)
+{
+ const struct alc_codec_rename_table *p;
+
+ for (p = rename_tbl; p->vendor_id; p++) {
+ if (p->vendor_id != codec->vendor_id)
+ continue;
+ if ((alc_get_coef0(codec) & p->coef_mask) == p->coef_bits)
+ return alc_codec_rename(codec, p->name);
+ }
+ return 0;
+}
+
/*
* Automatic parse of I/O pins from the BIOS configuration
*/
}
}
- alc_auto_fill_extra_dacs(codec, cfg->hp_outs, cfg->hp_pins,
+ if (cfg->line_out_type != AUTO_PIN_HP_OUT)
+ alc_auto_fill_extra_dacs(codec, cfg->hp_outs, cfg->hp_pins,
spec->multiout.hp_out_nid);
- alc_auto_fill_extra_dacs(codec, cfg->speaker_outs, cfg->speaker_pins,
+ if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
+ alc_auto_fill_extra_dacs(codec, cfg->speaker_outs, cfg->speaker_pins,
spec->multiout.extra_out_nid);
return 0;
}
+static inline unsigned int get_ctl_pos(unsigned int data)
+{
+ hda_nid_t nid = get_amp_nid_(data);
+ unsigned int dir = get_amp_direction_(data);
+ return (nid << 1) | dir;
+}
+
+#define is_ctl_used(bits, data) \
+ test_bit(get_ctl_pos(data), bits)
+#define mark_ctl_usage(bits, data) \
+ set_bit(get_ctl_pos(data), bits)
+
static int alc_auto_add_vol_ctl(struct hda_codec *codec,
const char *pfx, int cidx,
hda_nid_t nid, unsigned int chs)
{
+ struct alc_spec *spec = codec->spec;
+ unsigned int val;
if (!nid)
return 0;
+ val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT);
+ if (is_ctl_used(spec->vol_ctls, val) && chs != 2) /* exclude LFE */
+ return 0;
+ mark_ctl_usage(spec->vol_ctls, val);
return __add_pb_vol_ctrl(codec->spec, ALC_CTL_WIDGET_VOL, pfx, cidx,
- HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
+ val);
}
#define alc_auto_add_stereo_vol(codec, pfx, cidx, nid) \
const char *pfx, int cidx,
hda_nid_t nid, unsigned int chs)
{
+ struct alc_spec *spec = codec->spec;
int wid_type;
int type;
unsigned long val;
type = ALC_CTL_BIND_MUTE;
val = HDA_COMPOSE_AMP_VAL(nid, chs, 2, HDA_INPUT);
}
+ if (is_ctl_used(spec->sw_ctls, val) && chs != 2) /* exclude LFE */
+ return 0;
+ mark_ctl_usage(spec->sw_ctls, val);
return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val);
}
int err;
if (!dac) {
+ unsigned int val;
/* the corresponding DAC is already occupied */
if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
return 0; /* no way */
/* create a switch only */
- return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
- HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+ val = HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT);
+ if (is_ctl_used(spec->sw_ctls, val))
+ return 0; /* already created */
+ mark_ctl_usage(spec->sw_ctls, val);
+ return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, val);
}
sw = alc_look_for_out_mute_nid(codec, pin, dac);
if (!num_pins || !pins[0])
return 0;
- if (num_pins == 1)
- return alc_auto_create_extra_out(codec, *pins, *dacs, pfx);
+ if (num_pins == 1) {
+ hda_nid_t dac = *dacs;
+ if (!dac)
+ dac = spec->multiout.dac_nids[0];
+ return alc_auto_create_extra_out(codec, *pins, dac, pfx);
+ }
if (dacs[num_pins - 1]) {
/* OK, we have a multi-output system with individual volumes */
int i;
hda_nid_t pin, dac;
- for (i = 0; i < spec->autocfg.speaker_outs; i++) {
+ for (i = 0; i < spec->autocfg.hp_outs; i++) {
+ if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
+ break;
pin = spec->autocfg.hp_pins[i];
if (!pin)
break;
alc_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
}
for (i = 0; i < spec->autocfg.speaker_outs; i++) {
+ if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
+ break;
pin = spec->autocfg.speaker_pins[i];
if (!pin)
break;
return 0; /* can't find valid BIOS pin config */
}
- if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && cfg->hp_outs > 0) {
+ if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT &&
+ cfg->line_outs <= cfg->hp_outs) {
/* use HP as primary out */
cfg->speaker_outs = cfg->line_outs;
memcpy(cfg->speaker_pins, cfg->line_out_pins,
if (board_config == ALC_MODEL_AUTO) {
/* automatic parse from the BIOS config */
err = alc880_parse_auto_config(codec);
- if (err < 0) {
- alc_free(codec);
- return err;
- }
+ if (err < 0)
+ goto error;
#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
else if (!err) {
printk(KERN_INFO
if (!spec->no_analog) {
err = snd_hda_attach_beep_device(codec, 0x1);
- if (err < 0) {
- alc_free(codec);
- return err;
- }
+ if (err < 0)
+ goto error;
set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
}
#endif
return 0;
+
+ error:
+ alc_free(codec);
+ return err;
}
if (board_config == ALC_MODEL_AUTO) {
/* automatic parse from the BIOS config */
err = alc260_parse_auto_config(codec);
- if (err < 0) {
- alc_free(codec);
- return err;
- }
+ if (err < 0)
+ goto error;
#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
else if (!err) {
printk(KERN_INFO
if (!spec->no_analog) {
err = snd_hda_attach_beep_device(codec, 0x1);
- if (err < 0) {
- alc_free(codec);
- return err;
- }
+ if (err < 0)
+ goto error;
set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
}
#endif
return 0;
+
+ error:
+ alc_free(codec);
+ return err;
}
PINFIX_LENOVO_Y530,
PINFIX_PB_M5210,
PINFIX_ACER_ASPIRE_7736,
+ PINFIX_ASUS_W90V,
};
static const struct alc_fixup alc882_fixups[] = {
.type = ALC_FIXUP_SKU,
.v.sku = ALC_FIXUP_SKU_IGNORE,
},
+ [PINFIX_ASUS_W90V] = {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
+ { 0x16, 0x99130110 }, /* fix sequence for CLFE */
+ { }
+ }
+ },
};
static const struct snd_pci_quirk alc882_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
+ SND_PCI_QUIRK(0x1043, 0x1873, "ASUS W90V", PINFIX_ASUS_W90V),
SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530),
SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736),
break;
}
+ err = alc_codec_rename_from_preset(codec);
+ if (err < 0)
+ goto error;
+
board_config = alc_board_config(codec, ALC882_MODEL_LAST,
alc882_models, alc882_cfg_tbl);
if (board_config == ALC_MODEL_AUTO) {
/* automatic parse from the BIOS config */
err = alc882_parse_auto_config(codec);
- if (err < 0) {
- alc_free(codec);
- return err;
- }
+ if (err < 0)
+ goto error;
#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
else if (!err) {
printk(KERN_INFO
if (!spec->no_analog && has_cdefine_beep(codec)) {
err = snd_hda_attach_beep_device(codec, 0x1);
- if (err < 0) {
- alc_free(codec);
- return err;
- }
+ if (err < 0)
+ goto error;
set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
}
#endif
return 0;
+
+ error:
+ alc_free(codec);
+ return err;
}
if (board_config == ALC_MODEL_AUTO) {
/* automatic parse from the BIOS config */
err = alc262_parse_auto_config(codec);
- if (err < 0) {
- alc_free(codec);
- return err;
- }
+ if (err < 0)
+ goto error;
#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
else if (!err) {
printk(KERN_INFO
if (!spec->no_analog && has_cdefine_beep(codec)) {
err = snd_hda_attach_beep_device(codec, 0x1);
- if (err < 0) {
- alc_free(codec);
- return err;
- }
+ if (err < 0)
+ goto error;
set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
}
#endif
return 0;
+
+ error:
+ alc_free(codec);
+ return err;
}
/*
/* automatic parse from the BIOS config */
err = alc268_parse_auto_config(codec);
- if (err < 0) {
- alc_free(codec);
- return err;
- }
+ if (err < 0)
+ goto error;
has_beep = 0;
for (i = 0; i < spec->num_mixers; i++) {
if (has_beep) {
err = snd_hda_attach_beep_device(codec, 0x1);
- if (err < 0) {
- alc_free(codec);
- return err;
- }
+ if (err < 0)
+ goto error;
if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
/* override the amp caps for beep generator */
snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
alc_init_jacks(codec);
return 0;
+
+ error:
+ alc_free(codec);
+ return err;
}
/*
static void alc269_shutup(struct hda_codec *codec)
{
- if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017)
+ if ((alc_get_coef0(codec) & 0x00ff) == 0x017)
alc269_toggle_power_output(codec, 0);
- if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
+ if ((alc_get_coef0(codec) & 0x00ff) == 0x018) {
alc269_toggle_power_output(codec, 0);
msleep(150);
}
#ifdef CONFIG_PM
static int alc269_resume(struct hda_codec *codec)
{
- if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
+ if ((alc_get_coef0(codec) & 0x00ff) == 0x018) {
alc269_toggle_power_output(codec, 0);
msleep(150);
}
codec->patch_ops.init(codec);
- if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
+ if ((alc_get_coef0(codec) & 0x00ff) == 0x017) {
alc269_toggle_power_output(codec, 1);
msleep(200);
}
- if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018)
+ if ((alc_get_coef0(codec) & 0x00ff) == 0x018)
alc269_toggle_power_output(codec, 1);
snd_hda_codec_resume_amp(codec);
static void alc269_quanta_automute(struct hda_codec *codec)
{
- update_speakers(codec);
+ update_outputs(codec);
snd_hda_codec_write(codec, 0x20, 0,
AC_VERB_SET_COEF_INDEX, 0x0c);
{
int val;
- if ((alc_read_coef_idx(codec, 0) & 0x00ff) < 0x015) {
+ if ((alc_get_coef0(codec) & 0x00ff) < 0x015) {
alc_write_coef_idx(codec, 0xf, 0x960b);
alc_write_coef_idx(codec, 0xe, 0x8817);
}
- if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x016) {
+ if ((alc_get_coef0(codec) & 0x00ff) == 0x016) {
alc_write_coef_idx(codec, 0xf, 0x960b);
alc_write_coef_idx(codec, 0xe, 0x8814);
}
- if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
+ if ((alc_get_coef0(codec) & 0x00ff) == 0x017) {
val = alc_read_coef_idx(codec, 0x04);
/* Power up output pin */
alc_write_coef_idx(codec, 0x04, val | (1<<11));
}
- if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
+ if ((alc_get_coef0(codec) & 0x00ff) == 0x018) {
val = alc_read_coef_idx(codec, 0xd);
if ((val & 0x0c00) >> 10 != 0x1) {
/* Capless ramp up clock control */
static int patch_alc269(struct hda_codec *codec)
{
struct alc_spec *spec;
- int err;
+ int err = 0;
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (spec == NULL)
alc_auto_parse_customize_define(codec);
+ err = alc_codec_rename_from_preset(codec);
+ if (err < 0)
+ goto error;
+
if (codec->vendor_id == 0x10ec0269) {
- unsigned int coef;
spec->codec_variant = ALC269_TYPE_ALC269VA;
- coef = alc_read_coef_idx(codec, 0);
- if ((coef & 0x00f0) == 0x0010) {
+ switch (alc_get_coef0(codec) & 0x00f0) {
+ case 0x0010:
if (codec->bus->pci->subsystem_vendor == 0x1025 &&
- spec->cdefine.platform_type == 1) {
- alc_codec_rename(codec, "ALC271X");
- } else if ((coef & 0xf000) == 0x2000) {
- alc_codec_rename(codec, "ALC259");
- } else if ((coef & 0xf000) == 0x3000) {
- alc_codec_rename(codec, "ALC258");
- } else if ((coef & 0xfff0) == 0x3010) {
- alc_codec_rename(codec, "ALC277");
- } else {
- alc_codec_rename(codec, "ALC269VB");
- }
+ spec->cdefine.platform_type == 1)
+ err = alc_codec_rename(codec, "ALC271X");
spec->codec_variant = ALC269_TYPE_ALC269VB;
- } else if ((coef & 0x00f0) == 0x0020) {
- if (coef == 0xa023)
- alc_codec_rename(codec, "ALC259");
- else if (coef == 0x6023)
- alc_codec_rename(codec, "ALC281X");
- else if (codec->bus->pci->subsystem_vendor == 0x17aa &&
- codec->bus->pci->subsystem_device == 0x21f3)
- alc_codec_rename(codec, "ALC3202");
- else
- alc_codec_rename(codec, "ALC269VC");
+ break;
+ case 0x0020:
+ if (codec->bus->pci->subsystem_vendor == 0x17aa &&
+ codec->bus->pci->subsystem_device == 0x21f3)
+ err = alc_codec_rename(codec, "ALC3202");
spec->codec_variant = ALC269_TYPE_ALC269VC;
- } else
+ break;
+ default:
alc_fix_pll_init(codec, 0x20, 0x04, 15);
+ }
+ if (err < 0)
+ goto error;
alc269_fill_coef(codec);
}
/* automatic parse from the BIOS config */
err = alc269_parse_auto_config(codec);
- if (err < 0) {
- alc_free(codec);
- return err;
- }
+ if (err < 0)
+ goto error;
if (!spec->no_analog && !spec->adc_nids) {
alc_auto_fill_adc_caps(codec);
if (!spec->no_analog && has_cdefine_beep(codec)) {
err = snd_hda_attach_beep_device(codec, 0x1);
- if (err < 0) {
- alc_free(codec);
- return err;
- }
+ if (err < 0)
+ goto error;
set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
}
#endif
return 0;
+
+ error:
+ alc_free(codec);
+ return err;
}
/*
/* automatic parse from the BIOS config */
err = alc861_parse_auto_config(codec);
- if (err < 0) {
- alc_free(codec);
- return err;
- }
+ if (err < 0)
+ goto error;
if (!spec->no_analog && !spec->adc_nids) {
alc_auto_fill_adc_caps(codec);
if (!spec->no_analog) {
err = snd_hda_attach_beep_device(codec, 0x23);
- if (err < 0) {
- alc_free(codec);
- return err;
- }
+ if (err < 0)
+ goto error;
set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
}
#endif
return 0;
+
+ error:
+ alc_free(codec);
+ return err;
}
/*
/* automatic parse from the BIOS config */
err = alc861vd_parse_auto_config(codec);
- if (err < 0) {
- alc_free(codec);
- return err;
- }
+ if (err < 0)
+ goto error;
if (codec->vendor_id == 0x10ec0660) {
/* always turn on EAPD */
if (!spec->no_analog) {
err = snd_hda_attach_beep_device(codec, 0x23);
- if (err < 0) {
- alc_free(codec);
- return err;
- }
+ if (err < 0)
+ goto error;
set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
}
#endif
return 0;
+
+ error:
+ alc_free(codec);
+ return err;
}
/*
static int patch_alc662(struct hda_codec *codec)
{
struct alc_spec *spec;
- int err;
- int coef;
+ int err = 0;
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (!spec)
alc_fix_pll_init(codec, 0x20, 0x04, 15);
- coef = alc_read_coef_idx(codec, 0);
- if (coef == 0x8020 || coef == 0x8011)
- alc_codec_rename(codec, "ALC661");
- else if (coef & (1 << 14) &&
- codec->bus->pci->subsystem_vendor == 0x1025 &&
- spec->cdefine.platform_type == 1)
- alc_codec_rename(codec, "ALC272X");
- else if (coef == 0x4011)
- alc_codec_rename(codec, "ALC656");
+ err = alc_codec_rename_from_preset(codec);
+ if (err < 0)
+ goto error;
+
+ if ((alc_get_coef0(codec) & (1 << 14)) &&
+ codec->bus->pci->subsystem_vendor == 0x1025 &&
+ spec->cdefine.platform_type == 1) {
+ if (alc_codec_rename(codec, "ALC272X") < 0)
+ goto error;
+ }
alc_pick_fixup(codec, alc662_fixup_models,
alc662_fixup_tbl, alc662_fixups);
alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
/* automatic parse from the BIOS config */
err = alc662_parse_auto_config(codec);
- if (err < 0) {
- alc_free(codec);
- return err;
- }
+ if (err < 0)
+ goto error;
if (!spec->no_analog && !spec->adc_nids) {
alc_auto_fill_adc_caps(codec);
if (!spec->no_analog && has_cdefine_beep(codec)) {
err = snd_hda_attach_beep_device(codec, 0x1);
- if (err < 0) {
- alc_free(codec);
- return err;
- }
+ if (err < 0)
+ goto error;
switch (codec->vendor_id) {
case 0x10ec0662:
set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
#endif
return 0;
-}
-static int patch_alc888(struct hda_codec *codec)
-{
- if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){
- kfree(codec->chip_name);
- if (codec->vendor_id == 0x10ec0887)
- codec->chip_name = kstrdup("ALC887-VD", GFP_KERNEL);
- else
- codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
- if (!codec->chip_name) {
- alc_free(codec);
- return -ENOMEM;
- }
- return patch_alc662(codec);
- }
- return patch_alc882(codec);
-}
-
-static int patch_alc899(struct hda_codec *codec)
-{
- if ((alc_read_coef_idx(codec, 0) & 0x2000) != 0x2000) {
- kfree(codec->chip_name);
- codec->chip_name = kstrdup("ALC898", GFP_KERNEL);
- }
- return patch_alc882(codec);
+ error:
+ alc_free(codec);
+ return err;
}
/*
.patch = patch_alc882 },
{ .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
.patch = patch_alc662 },
+ { .id = 0x10ec0662, .rev = 0x100300, .name = "ALC662 rev3",
+ .patch = patch_alc662 },
{ .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
{ .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
{ .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
{ .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
.patch = patch_alc882 },
{ .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
- { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc888 },
+ { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 },
{ .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
.patch = patch_alc882 },
- { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
+ { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc882 },
{ .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
{ .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
- { .id = 0x10ec0899, .name = "ALC899", .patch = patch_alc899 },
+ { .id = 0x10ec0899, .name = "ALC898", .patch = patch_alc882 },
{} /* terminator */
};