|
@@ -256,6 +256,13 @@ enum {
|
|
|
ALC882_MODEL_LAST,
|
|
|
};
|
|
|
|
|
|
+/* ALC680 models */
|
|
|
+enum {
|
|
|
+ ALC680_BASE,
|
|
|
+ ALC680_AUTO,
|
|
|
+ ALC680_MODEL_LAST,
|
|
|
+};
|
|
|
+
|
|
|
/* for GPIO Poll */
|
|
|
#define GPIO_MASK 0x03
|
|
|
|
|
@@ -326,6 +333,12 @@ struct alc_spec {
|
|
|
hda_nid_t *capsrc_nids;
|
|
|
hda_nid_t dig_in_nid; /* digital-in NID; optional */
|
|
|
|
|
|
+ /* capture setup for dynamic dual-adc switch */
|
|
|
+ unsigned int cur_adc_idx;
|
|
|
+ hda_nid_t cur_adc;
|
|
|
+ unsigned int cur_adc_stream_tag;
|
|
|
+ unsigned int cur_adc_format;
|
|
|
+
|
|
|
/* capture source */
|
|
|
unsigned int num_mux_defs;
|
|
|
const struct hda_input_mux *input_mux;
|
|
@@ -367,6 +380,7 @@ struct alc_spec {
|
|
|
|
|
|
/* other flags */
|
|
|
unsigned int no_analog :1; /* digital I/O only */
|
|
|
+ unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */
|
|
|
int init_amp;
|
|
|
|
|
|
/* for virtual master */
|
|
@@ -833,9 +847,13 @@ static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
|
|
|
|
|
|
if (auto_pin_type <= AUTO_PIN_FRONT_MIC) {
|
|
|
unsigned int pincap;
|
|
|
+ unsigned int oldval;
|
|
|
+ oldval = snd_hda_codec_read(codec, nid, 0,
|
|
|
+ AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
|
|
pincap = snd_hda_query_pin_caps(codec, nid);
|
|
|
pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
|
|
|
- if (pincap & AC_PINCAP_VREF_80)
|
|
|
+ /* if the default pin setup is vref50, we give it priority */
|
|
|
+ if ((pincap & AC_PINCAP_VREF_80) && oldval != PIN_VREF50)
|
|
|
val = PIN_VREF80;
|
|
|
else if (pincap & AC_PINCAP_VREF_50)
|
|
|
val = PIN_VREF50;
|
|
@@ -1003,6 +1021,29 @@ static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
+/* switch the current ADC according to the jack state */
|
|
|
+static void alc_dual_mic_adc_auto_switch(struct hda_codec *codec)
|
|
|
+{
|
|
|
+ struct alc_spec *spec = codec->spec;
|
|
|
+ unsigned int present;
|
|
|
+ hda_nid_t new_adc;
|
|
|
+
|
|
|
+ present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
|
|
|
+ if (present)
|
|
|
+ spec->cur_adc_idx = 1;
|
|
|
+ else
|
|
|
+ spec->cur_adc_idx = 0;
|
|
|
+ new_adc = spec->adc_nids[spec->cur_adc_idx];
|
|
|
+ if (spec->cur_adc && spec->cur_adc != new_adc) {
|
|
|
+ /* stream is running, let's swap the current ADC */
|
|
|
+ snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
|
|
|
+ spec->cur_adc = new_adc;
|
|
|
+ snd_hda_codec_setup_stream(codec, new_adc,
|
|
|
+ spec->cur_adc_stream_tag, 0,
|
|
|
+ spec->cur_adc_format);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static void alc_mic_automute(struct hda_codec *codec)
|
|
|
{
|
|
|
struct alc_spec *spec = codec->spec;
|
|
@@ -1017,6 +1058,11 @@ static void alc_mic_automute(struct hda_codec *codec)
|
|
|
if (snd_BUG_ON(!spec->adc_nids))
|
|
|
return;
|
|
|
|
|
|
+ if (spec->dual_adc_switch) {
|
|
|
+ alc_dual_mic_adc_auto_switch(codec);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0];
|
|
|
|
|
|
present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
|
|
@@ -1499,6 +1545,63 @@ static int alc_read_coef_idx(struct hda_codec *codec,
|
|
|
return val;
|
|
|
}
|
|
|
|
|
|
+/* set right pin controls for digital I/O */
|
|
|
+static void alc_auto_init_digital(struct hda_codec *codec)
|
|
|
+{
|
|
|
+ struct alc_spec *spec = codec->spec;
|
|
|
+ int i;
|
|
|
+ hda_nid_t pin;
|
|
|
+
|
|
|
+ for (i = 0; i < spec->autocfg.dig_outs; i++) {
|
|
|
+ pin = spec->autocfg.dig_out_pins[i];
|
|
|
+ if (pin) {
|
|
|
+ snd_hda_codec_write(codec, pin, 0,
|
|
|
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
|
|
|
+ PIN_OUT);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ pin = spec->autocfg.dig_in_pin;
|
|
|
+ if (pin)
|
|
|
+ snd_hda_codec_write(codec, pin, 0,
|
|
|
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
|
|
|
+ PIN_IN);
|
|
|
+}
|
|
|
+
|
|
|
+/* parse digital I/Os and set up NIDs in BIOS auto-parse mode */
|
|
|
+static void alc_auto_parse_digital(struct hda_codec *codec)
|
|
|
+{
|
|
|
+ struct alc_spec *spec = codec->spec;
|
|
|
+ int i, err;
|
|
|
+ hda_nid_t dig_nid;
|
|
|
+
|
|
|
+ /* support multiple SPDIFs; the secondary is set up as a slave */
|
|
|
+ for (i = 0; i < spec->autocfg.dig_outs; i++) {
|
|
|
+ err = snd_hda_get_connections(codec,
|
|
|
+ spec->autocfg.dig_out_pins[i],
|
|
|
+ &dig_nid, 1);
|
|
|
+ if (err < 0)
|
|
|
+ continue;
|
|
|
+ if (!i) {
|
|
|
+ spec->multiout.dig_out_nid = dig_nid;
|
|
|
+ spec->dig_out_type = spec->autocfg.dig_out_type[0];
|
|
|
+ } else {
|
|
|
+ spec->multiout.slave_dig_outs = spec->slave_dig_outs;
|
|
|
+ if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
|
|
|
+ break;
|
|
|
+ spec->slave_dig_outs[i - 1] = dig_nid;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (spec->autocfg.dig_in_pin) {
|
|
|
+ hda_nid_t dig_nid;
|
|
|
+ err = snd_hda_get_connections(codec,
|
|
|
+ spec->autocfg.dig_in_pin,
|
|
|
+ &dig_nid, 1);
|
|
|
+ if (err > 0)
|
|
|
+ spec->dig_in_nid = dig_nid;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* ALC888
|
|
|
*/
|
|
@@ -3607,6 +3710,41 @@ static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/* analog capture with dynamic dual-adc changes */
|
|
|
+static int dualmic_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
|
|
|
+ struct hda_codec *codec,
|
|
|
+ unsigned int stream_tag,
|
|
|
+ unsigned int format,
|
|
|
+ struct snd_pcm_substream *substream)
|
|
|
+{
|
|
|
+ struct alc_spec *spec = codec->spec;
|
|
|
+ spec->cur_adc = spec->adc_nids[spec->cur_adc_idx];
|
|
|
+ spec->cur_adc_stream_tag = stream_tag;
|
|
|
+ spec->cur_adc_format = format;
|
|
|
+ snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
|
|
|
+ struct hda_codec *codec,
|
|
|
+ struct snd_pcm_substream *substream)
|
|
|
+{
|
|
|
+ struct alc_spec *spec = codec->spec;
|
|
|
+ snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
|
|
|
+ spec->cur_adc = 0;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static struct hda_pcm_stream dualmic_pcm_analog_capture = {
|
|
|
+ .substreams = 1,
|
|
|
+ .channels_min = 2,
|
|
|
+ .channels_max = 2,
|
|
|
+ .nid = 0, /* fill later */
|
|
|
+ .ops = {
|
|
|
+ .prepare = dualmic_capture_pcm_prepare,
|
|
|
+ .cleanup = dualmic_capture_pcm_cleanup
|
|
|
+ },
|
|
|
+};
|
|
|
|
|
|
/*
|
|
|
*/
|
|
@@ -4936,7 +5074,7 @@ static void alc880_auto_init_input_src(struct hda_codec *codec)
|
|
|
static int alc880_parse_auto_config(struct hda_codec *codec)
|
|
|
{
|
|
|
struct alc_spec *spec = codec->spec;
|
|
|
- int i, err;
|
|
|
+ int err;
|
|
|
static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
|
|
|
|
|
|
err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
|
|
@@ -4967,25 +5105,7 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
|
|
|
|
|
|
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
|
|
|
|
|
|
- /* check multiple SPDIF-out (for recent codecs) */
|
|
|
- for (i = 0; i < spec->autocfg.dig_outs; i++) {
|
|
|
- hda_nid_t dig_nid;
|
|
|
- err = snd_hda_get_connections(codec,
|
|
|
- spec->autocfg.dig_out_pins[i],
|
|
|
- &dig_nid, 1);
|
|
|
- if (err < 0)
|
|
|
- continue;
|
|
|
- if (!i)
|
|
|
- spec->multiout.dig_out_nid = dig_nid;
|
|
|
- else {
|
|
|
- spec->multiout.slave_dig_outs = spec->slave_dig_outs;
|
|
|
- if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
|
|
|
- break;
|
|
|
- spec->slave_dig_outs[i - 1] = dig_nid;
|
|
|
- }
|
|
|
- }
|
|
|
- if (spec->autocfg.dig_in_pin)
|
|
|
- spec->dig_in_nid = ALC880_DIGIN_NID;
|
|
|
+ alc_auto_parse_digital(codec);
|
|
|
|
|
|
if (spec->kctls.list)
|
|
|
add_mixer(spec, spec->kctls.list);
|
|
@@ -5008,6 +5128,7 @@ static void alc880_auto_init(struct hda_codec *codec)
|
|
|
alc880_auto_init_extra_out(codec);
|
|
|
alc880_auto_init_analog_input(codec);
|
|
|
alc880_auto_init_input_src(codec);
|
|
|
+ alc_auto_init_digital(codec);
|
|
|
if (spec->unsol_event)
|
|
|
alc_inithook(codec);
|
|
|
}
|
|
@@ -5045,6 +5166,39 @@ static void fixup_automic_adc(struct hda_codec *codec)
|
|
|
spec->auto_mic = 0; /* disable auto-mic to be sure */
|
|
|
}
|
|
|
|
|
|
+/* select or unmute the given capsrc route */
|
|
|
+static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap,
|
|
|
+ int idx)
|
|
|
+{
|
|
|
+ if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
|
|
|
+ snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
|
|
|
+ HDA_AMP_MUTE, 0);
|
|
|
+ } else {
|
|
|
+ snd_hda_codec_write_cache(codec, cap, 0,
|
|
|
+ AC_VERB_SET_CONNECT_SEL, idx);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* set the default connection to that pin */
|
|
|
+static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
|
|
|
+{
|
|
|
+ struct alc_spec *spec = codec->spec;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < spec->num_adc_nids; i++) {
|
|
|
+ hda_nid_t cap = spec->capsrc_nids ?
|
|
|
+ spec->capsrc_nids[i] : spec->adc_nids[i];
|
|
|
+ int idx;
|
|
|
+
|
|
|
+ idx = get_connection_index(codec, cap, pin);
|
|
|
+ if (idx < 0)
|
|
|
+ continue;
|
|
|
+ select_or_unmute_capsrc(codec, cap, idx);
|
|
|
+ return i; /* return the found index */
|
|
|
+ }
|
|
|
+ return -1; /* not found */
|
|
|
+}
|
|
|
+
|
|
|
/* choose the ADC/MUX containing the input pin and initialize the setup */
|
|
|
static void fixup_single_adc(struct hda_codec *codec)
|
|
|
{
|
|
@@ -5061,33 +5215,24 @@ static void fixup_single_adc(struct hda_codec *codec)
|
|
|
}
|
|
|
if (!pin)
|
|
|
return;
|
|
|
-
|
|
|
- /* set the default connection to that pin */
|
|
|
- for (i = 0; i < spec->num_adc_nids; i++) {
|
|
|
- hda_nid_t cap = spec->capsrc_nids ?
|
|
|
- spec->capsrc_nids[i] : spec->adc_nids[i];
|
|
|
- int idx;
|
|
|
-
|
|
|
- idx = get_connection_index(codec, cap, pin);
|
|
|
- if (idx < 0)
|
|
|
- continue;
|
|
|
+ i = init_capsrc_for_pin(codec, pin);
|
|
|
+ if (i >= 0) {
|
|
|
/* use only this ADC */
|
|
|
if (spec->capsrc_nids)
|
|
|
spec->capsrc_nids += i;
|
|
|
spec->adc_nids += i;
|
|
|
spec->num_adc_nids = 1;
|
|
|
- /* select or unmute this route */
|
|
|
- if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
|
|
|
- snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
|
|
|
- HDA_AMP_MUTE, 0);
|
|
|
- } else {
|
|
|
- snd_hda_codec_write_cache(codec, cap, 0,
|
|
|
- AC_VERB_SET_CONNECT_SEL, idx);
|
|
|
- }
|
|
|
- return;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/* initialize dual adcs */
|
|
|
+static void fixup_dual_adc_switch(struct hda_codec *codec)
|
|
|
+{
|
|
|
+ struct alc_spec *spec = codec->spec;
|
|
|
+ init_capsrc_for_pin(codec, spec->ext_mic.pin);
|
|
|
+ init_capsrc_for_pin(codec, spec->int_mic.pin);
|
|
|
+}
|
|
|
+
|
|
|
static void set_capture_mixer(struct hda_codec *codec)
|
|
|
{
|
|
|
struct alc_spec *spec = codec->spec;
|
|
@@ -5101,7 +5246,10 @@ static void set_capture_mixer(struct hda_codec *codec)
|
|
|
};
|
|
|
if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
|
|
|
int mux = 0;
|
|
|
- if (spec->auto_mic)
|
|
|
+ int num_adcs = spec->num_adc_nids;
|
|
|
+ if (spec->dual_adc_switch)
|
|
|
+ fixup_dual_adc_switch(codec);
|
|
|
+ else if (spec->auto_mic)
|
|
|
fixup_automic_adc(codec);
|
|
|
else if (spec->input_mux) {
|
|
|
if (spec->input_mux->num_items > 1)
|
|
@@ -5109,7 +5257,9 @@ static void set_capture_mixer(struct hda_codec *codec)
|
|
|
else if (spec->input_mux->num_items == 1)
|
|
|
fixup_single_adc(codec);
|
|
|
}
|
|
|
- spec->cap_mixer = caps[mux][spec->num_adc_nids - 1];
|
|
|
+ if (spec->dual_adc_switch)
|
|
|
+ num_adcs = 1;
|
|
|
+ spec->cap_mixer = caps[mux][num_adcs - 1];
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -5183,6 +5333,7 @@ static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids,
|
|
|
|
|
|
static struct snd_pci_quirk beep_white_list[] = {
|
|
|
SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
|
|
|
+ SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
|
|
|
{}
|
|
|
};
|
|
|
|
|
@@ -6624,6 +6775,7 @@ static void alc260_auto_init(struct hda_codec *codec)
|
|
|
alc260_auto_init_multi_out(codec);
|
|
|
alc260_auto_init_analog_input(codec);
|
|
|
alc260_auto_init_input_src(codec);
|
|
|
+ alc_auto_init_digital(codec);
|
|
|
if (spec->unsol_event)
|
|
|
alc_inithook(codec);
|
|
|
}
|
|
@@ -6639,6 +6791,29 @@ static struct hda_amp_list alc260_loopbacks[] = {
|
|
|
};
|
|
|
#endif
|
|
|
|
|
|
+/*
|
|
|
+ * Pin config fixes
|
|
|
+ */
|
|
|
+enum {
|
|
|
+ PINFIX_HP_DC5750,
|
|
|
+};
|
|
|
+
|
|
|
+static struct alc_pincfg alc260_hp_dc5750_pinfix[] = {
|
|
|
+ { 0x11, 0x90130110 }, /* speaker */
|
|
|
+ { }
|
|
|
+};
|
|
|
+
|
|
|
+static const struct alc_fixup alc260_fixups[] = {
|
|
|
+ [PINFIX_HP_DC5750] = {
|
|
|
+ .pins = alc260_hp_dc5750_pinfix
|
|
|
+ },
|
|
|
+};
|
|
|
+
|
|
|
+static struct snd_pci_quirk alc260_fixup_tbl[] = {
|
|
|
+ SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750),
|
|
|
+ {}
|
|
|
+};
|
|
|
+
|
|
|
/*
|
|
|
* ALC260 configurations
|
|
|
*/
|
|
@@ -6838,6 +7013,9 @@ static int patch_alc260(struct hda_codec *codec)
|
|
|
board_config = ALC260_AUTO;
|
|
|
}
|
|
|
|
|
|
+ if (board_config == ALC260_AUTO)
|
|
|
+ alc_pick_fixup(codec, alc260_fixup_tbl, alc260_fixups, 1);
|
|
|
+
|
|
|
if (board_config == ALC260_AUTO) {
|
|
|
/* automatic parse from the BIOS config */
|
|
|
err = alc260_parse_auto_config(codec);
|
|
@@ -6883,6 +7061,9 @@ static int patch_alc260(struct hda_codec *codec)
|
|
|
set_capture_mixer(codec);
|
|
|
set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
|
|
|
|
|
|
+ if (board_config == ALC260_AUTO)
|
|
|
+ alc_pick_fixup(codec, alc260_fixup_tbl, alc260_fixups, 0);
|
|
|
+
|
|
|
spec->vmaster_nid = 0x08;
|
|
|
|
|
|
codec->patch_ops = alc_patch_ops;
|
|
@@ -7003,7 +7184,7 @@ static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
|
|
|
.num_items = 4,
|
|
|
.items = {
|
|
|
{ "Mic", 0x0 },
|
|
|
- { "iMic", 0x1 },
|
|
|
+ { "Int Mic", 0x1 },
|
|
|
{ "Line", 0x2 },
|
|
|
{ "CD", 0x4 },
|
|
|
},
|
|
@@ -8573,8 +8754,8 @@ static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
|
|
|
HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
|
|
|
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
|
|
|
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
|
|
|
- HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT),
|
|
|
- HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT),
|
|
|
+ HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
|
|
|
+ HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
|
|
|
{ } /* end */
|
|
|
};
|
|
|
|
|
@@ -10265,7 +10446,8 @@ static struct alc_config_preset alc882_presets[] = {
|
|
|
* Pin config fixes
|
|
|
*/
|
|
|
enum {
|
|
|
- PINFIX_ABIT_AW9D_MAX
|
|
|
+ PINFIX_ABIT_AW9D_MAX,
|
|
|
+ PINFIX_PB_M5210,
|
|
|
};
|
|
|
|
|
|
static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
|
|
@@ -10275,13 +10457,22 @@ static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
|
|
|
{ }
|
|
|
};
|
|
|
|
|
|
+static const struct hda_verb pb_m5210_verbs[] = {
|
|
|
+ { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
|
|
|
+ {}
|
|
|
+};
|
|
|
+
|
|
|
static const struct alc_fixup alc882_fixups[] = {
|
|
|
[PINFIX_ABIT_AW9D_MAX] = {
|
|
|
.pins = alc882_abit_aw9d_pinfix
|
|
|
},
|
|
|
+ [PINFIX_PB_M5210] = {
|
|
|
+ .verbs = pb_m5210_verbs
|
|
|
+ },
|
|
|
};
|
|
|
|
|
|
static struct snd_pci_quirk alc882_fixup_tbl[] = {
|
|
|
+ SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
|
|
|
SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
|
|
|
{}
|
|
|
};
|
|
@@ -10446,7 +10637,7 @@ static int alc882_parse_auto_config(struct hda_codec *codec)
|
|
|
{
|
|
|
struct alc_spec *spec = codec->spec;
|
|
|
static hda_nid_t alc882_ignore[] = { 0x1d, 0 };
|
|
|
- int i, err;
|
|
|
+ int err;
|
|
|
|
|
|
err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
|
|
|
alc882_ignore);
|
|
@@ -10476,25 +10667,7 @@ static int alc882_parse_auto_config(struct hda_codec *codec)
|
|
|
|
|
|
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
|
|
|
|
|
|
- /* check multiple SPDIF-out (for recent codecs) */
|
|
|
- for (i = 0; i < spec->autocfg.dig_outs; i++) {
|
|
|
- hda_nid_t dig_nid;
|
|
|
- err = snd_hda_get_connections(codec,
|
|
|
- spec->autocfg.dig_out_pins[i],
|
|
|
- &dig_nid, 1);
|
|
|
- if (err < 0)
|
|
|
- continue;
|
|
|
- if (!i)
|
|
|
- spec->multiout.dig_out_nid = dig_nid;
|
|
|
- else {
|
|
|
- spec->multiout.slave_dig_outs = spec->slave_dig_outs;
|
|
|
- if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
|
|
|
- break;
|
|
|
- spec->slave_dig_outs[i - 1] = dig_nid;
|
|
|
- }
|
|
|
- }
|
|
|
- if (spec->autocfg.dig_in_pin)
|
|
|
- spec->dig_in_nid = ALC880_DIGIN_NID;
|
|
|
+ alc_auto_parse_digital(codec);
|
|
|
|
|
|
if (spec->kctls.list)
|
|
|
add_mixer(spec, spec->kctls.list);
|
|
@@ -10524,6 +10697,7 @@ static void alc882_auto_init(struct hda_codec *codec)
|
|
|
alc882_auto_init_hp_out(codec);
|
|
|
alc882_auto_init_analog_input(codec);
|
|
|
alc882_auto_init_input_src(codec);
|
|
|
+ alc_auto_init_digital(codec);
|
|
|
if (spec->unsol_event)
|
|
|
alc_inithook(codec);
|
|
|
}
|
|
@@ -12054,12 +12228,7 @@ static int alc262_parse_auto_config(struct hda_codec *codec)
|
|
|
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
|
|
|
|
|
|
dig_only:
|
|
|
- if (spec->autocfg.dig_outs) {
|
|
|
- spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
|
|
|
- spec->dig_out_type = spec->autocfg.dig_out_type[0];
|
|
|
- }
|
|
|
- if (spec->autocfg.dig_in_pin)
|
|
|
- spec->dig_in_nid = ALC262_DIGIN_NID;
|
|
|
+ alc_auto_parse_digital(codec);
|
|
|
|
|
|
if (spec->kctls.list)
|
|
|
add_mixer(spec, spec->kctls.list);
|
|
@@ -12091,6 +12260,7 @@ static void alc262_auto_init(struct hda_codec *codec)
|
|
|
alc262_auto_init_hp_out(codec);
|
|
|
alc262_auto_init_analog_input(codec);
|
|
|
alc262_auto_init_input_src(codec);
|
|
|
+ alc_auto_init_digital(codec);
|
|
|
if (spec->unsol_event)
|
|
|
alc_inithook(codec);
|
|
|
}
|
|
@@ -13024,10 +13194,14 @@ static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
|
|
|
dac = 0x02;
|
|
|
break;
|
|
|
case 0x15:
|
|
|
+ case 0x1a: /* ALC259/269 only */
|
|
|
+ case 0x1b: /* ALC259/269 only */
|
|
|
case 0x21: /* ALC269vb has this pin, too */
|
|
|
dac = 0x03;
|
|
|
break;
|
|
|
default:
|
|
|
+ snd_printd(KERN_WARNING "hda_codec: "
|
|
|
+ "ignoring pin 0x%x as unknown\n", nid);
|
|
|
return 0;
|
|
|
}
|
|
|
if (spec->multiout.dac_nids[0] != dac &&
|
|
@@ -13078,7 +13252,7 @@ static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
|
|
|
HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
|
|
|
if (err < 0)
|
|
|
return err;
|
|
|
- } else {
|
|
|
+ } else if (nid) {
|
|
|
err = alc268_new_analog_output(spec, nid, "Speaker", 0);
|
|
|
if (err < 0)
|
|
|
return err;
|
|
@@ -13227,10 +13401,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
|
|
|
|
|
|
dig_only:
|
|
|
/* digital only support output */
|
|
|
- if (spec->autocfg.dig_outs) {
|
|
|
- spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
|
|
|
- spec->dig_out_type = spec->autocfg.dig_out_type[0];
|
|
|
- }
|
|
|
+ alc_auto_parse_digital(codec);
|
|
|
if (spec->kctls.list)
|
|
|
add_mixer(spec, spec->kctls.list);
|
|
|
|
|
@@ -13260,6 +13431,7 @@ static void alc268_auto_init(struct hda_codec *codec)
|
|
|
alc268_auto_init_hp_out(codec);
|
|
|
alc268_auto_init_mono_speaker_out(codec);
|
|
|
alc268_auto_init_analog_input(codec);
|
|
|
+ alc_auto_init_digital(codec);
|
|
|
if (spec->unsol_event)
|
|
|
alc_inithook(codec);
|
|
|
}
|
|
@@ -14152,6 +14324,36 @@ static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
|
|
|
}
|
|
|
#endif /* CONFIG_SND_HDA_POWER_SAVE */
|
|
|
|
|
|
+static int alc275_setup_dual_adc(struct hda_codec *codec)
|
|
|
+{
|
|
|
+ struct alc_spec *spec = codec->spec;
|
|
|
+
|
|
|
+ if (codec->vendor_id != 0x10ec0275 || !spec->auto_mic)
|
|
|
+ return 0;
|
|
|
+ if ((spec->ext_mic.pin >= 0x18 && spec->int_mic.pin <= 0x13) ||
|
|
|
+ (spec->ext_mic.pin <= 0x12 && spec->int_mic.pin >= 0x18)) {
|
|
|
+ if (spec->ext_mic.pin <= 0x12) {
|
|
|
+ spec->private_adc_nids[0] = 0x08;
|
|
|
+ spec->private_adc_nids[1] = 0x11;
|
|
|
+ spec->private_capsrc_nids[0] = 0x23;
|
|
|
+ spec->private_capsrc_nids[1] = 0x22;
|
|
|
+ } else {
|
|
|
+ spec->private_adc_nids[0] = 0x11;
|
|
|
+ spec->private_adc_nids[1] = 0x08;
|
|
|
+ spec->private_capsrc_nids[0] = 0x22;
|
|
|
+ spec->private_capsrc_nids[1] = 0x23;
|
|
|
+ }
|
|
|
+ spec->adc_nids = spec->private_adc_nids;
|
|
|
+ spec->capsrc_nids = spec->private_capsrc_nids;
|
|
|
+ spec->num_adc_nids = 2;
|
|
|
+ spec->dual_adc_switch = 1;
|
|
|
+ snd_printdd("realtek: enabling dual ADC switchg (%02x:%02x)\n",
|
|
|
+ spec->adc_nids[0], spec->adc_nids[1]);
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* BIOS auto configuration
|
|
|
*/
|
|
@@ -14175,8 +14377,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
|
|
|
|
|
|
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
|
|
|
|
|
|
- if (spec->autocfg.dig_outs)
|
|
|
- spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
|
|
|
+ alc_auto_parse_digital(codec);
|
|
|
|
|
|
if (spec->kctls.list)
|
|
|
add_mixer(spec, spec->kctls.list);
|
|
@@ -14191,13 +14392,15 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
|
|
|
|
|
|
spec->num_mux_defs = 1;
|
|
|
spec->input_mux = &spec->private_imux[0];
|
|
|
- fillup_priv_adc_nids(codec, alc269_adc_candidates,
|
|
|
- sizeof(alc269_adc_candidates));
|
|
|
+
|
|
|
+ if (!alc275_setup_dual_adc(codec))
|
|
|
+ fillup_priv_adc_nids(codec, alc269_adc_candidates,
|
|
|
+ sizeof(alc269_adc_candidates));
|
|
|
|
|
|
/* set default input source */
|
|
|
- snd_hda_codec_write_cache(codec, spec->capsrc_nids[0],
|
|
|
- 0, AC_VERB_SET_CONNECT_SEL,
|
|
|
- spec->input_mux->items[0].index);
|
|
|
+ if (!spec->dual_adc_switch)
|
|
|
+ select_or_unmute_capsrc(codec, spec->capsrc_nids[0],
|
|
|
+ spec->input_mux->items[0].index);
|
|
|
|
|
|
err = alc_auto_add_mic_boost(codec);
|
|
|
if (err < 0)
|
|
@@ -14221,6 +14424,7 @@ static void alc269_auto_init(struct hda_codec *codec)
|
|
|
alc269_auto_init_multi_out(codec);
|
|
|
alc269_auto_init_hp_out(codec);
|
|
|
alc269_auto_init_analog_input(codec);
|
|
|
+ alc_auto_init_digital(codec);
|
|
|
if (spec->unsol_event)
|
|
|
alc_inithook(codec);
|
|
|
}
|
|
@@ -14493,6 +14697,10 @@ static int patch_alc269(struct hda_codec *codec)
|
|
|
*/
|
|
|
spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
|
|
|
spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
|
|
|
+ } else if (spec->dual_adc_switch) {
|
|
|
+ spec->stream_analog_playback = &alc269_pcm_analog_playback;
|
|
|
+ /* switch ADC dynamically */
|
|
|
+ spec->stream_analog_capture = &dualmic_pcm_analog_capture;
|
|
|
} else {
|
|
|
spec->stream_analog_playback = &alc269_pcm_analog_playback;
|
|
|
spec->stream_analog_capture = &alc269_pcm_analog_capture;
|
|
@@ -15378,8 +15586,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
|
|
|
|
|
|
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
|
|
|
|
|
|
- if (spec->autocfg.dig_outs)
|
|
|
- spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
|
|
|
+ alc_auto_parse_digital(codec);
|
|
|
|
|
|
if (spec->kctls.list)
|
|
|
add_mixer(spec, spec->kctls.list);
|
|
@@ -15405,6 +15612,7 @@ static void alc861_auto_init(struct hda_codec *codec)
|
|
|
alc861_auto_init_multi_out(codec);
|
|
|
alc861_auto_init_hp_out(codec);
|
|
|
alc861_auto_init_analog_input(codec);
|
|
|
+ alc_auto_init_digital(codec);
|
|
|
if (spec->unsol_event)
|
|
|
alc_inithook(codec);
|
|
|
}
|
|
@@ -16509,8 +16717,7 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec)
|
|
|
|
|
|
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
|
|
|
|
|
|
- if (spec->autocfg.dig_outs)
|
|
|
- spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
|
|
|
+ alc_auto_parse_digital(codec);
|
|
|
|
|
|
if (spec->kctls.list)
|
|
|
add_mixer(spec, spec->kctls.list);
|
|
@@ -16537,6 +16744,7 @@ static void alc861vd_auto_init(struct hda_codec *codec)
|
|
|
alc861vd_auto_init_hp_out(codec);
|
|
|
alc861vd_auto_init_analog_input(codec);
|
|
|
alc861vd_auto_init_input_src(codec);
|
|
|
+ alc_auto_init_digital(codec);
|
|
|
if (spec->unsol_event)
|
|
|
alc_inithook(codec);
|
|
|
}
|
|
@@ -18520,7 +18728,7 @@ static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
|
|
|
hda_nid_t dac)
|
|
|
{
|
|
|
int i, num;
|
|
|
- hda_nid_t srcs[4];
|
|
|
+ hda_nid_t srcs[HDA_MAX_CONNECTIONS];
|
|
|
|
|
|
alc_set_pin_output(codec, nid, pin_type);
|
|
|
/* need the manual connection? */
|
|
@@ -18624,8 +18832,7 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
|
|
|
|
|
|
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
|
|
|
|
|
|
- if (spec->autocfg.dig_outs)
|
|
|
- spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
|
|
|
+ alc_auto_parse_digital(codec);
|
|
|
|
|
|
if (spec->kctls.list)
|
|
|
add_mixer(spec, spec->kctls.list);
|
|
@@ -18635,7 +18842,7 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
|
|
|
|
|
|
add_verb(spec, alc662_init_verbs);
|
|
|
if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
|
|
|
- codec->vendor_id == 0x10ec0665)
|
|
|
+ codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
|
|
|
add_verb(spec, alc663_init_verbs);
|
|
|
|
|
|
if (codec->vendor_id == 0x10ec0272)
|
|
@@ -18662,6 +18869,7 @@ static void alc662_auto_init(struct hda_codec *codec)
|
|
|
alc662_auto_init_hp_out(codec);
|
|
|
alc662_auto_init_analog_input(codec);
|
|
|
alc662_auto_init_input_src(codec);
|
|
|
+ alc_auto_init_digital(codec);
|
|
|
if (spec->unsol_event)
|
|
|
alc_inithook(codec);
|
|
|
}
|
|
@@ -18780,6 +18988,333 @@ static int patch_alc888(struct hda_codec *codec)
|
|
|
return patch_alc882(codec);
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * ALC680 support
|
|
|
+ */
|
|
|
+#define ALC680_DIGOUT_NID ALC880_DIGOUT_NID
|
|
|
+#define alc680_modes alc260_modes
|
|
|
+
|
|
|
+static hda_nid_t alc680_dac_nids[3] = {
|
|
|
+ /* Lout1, Lout2, hp */
|
|
|
+ 0x02, 0x03, 0x04
|
|
|
+};
|
|
|
+
|
|
|
+static hda_nid_t alc680_adc_nids[3] = {
|
|
|
+ /* ADC0-2 */
|
|
|
+ /* DMIC, MIC, Line-in*/
|
|
|
+ 0x07, 0x08, 0x09
|
|
|
+};
|
|
|
+
|
|
|
+static struct snd_kcontrol_new alc680_base_mixer[] = {
|
|
|
+ /* output mixer control */
|
|
|
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
|
|
|
+ HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
|
|
|
+ HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT),
|
|
|
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT),
|
|
|
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
|
|
|
+ { }
|
|
|
+};
|
|
|
+
|
|
|
+static struct snd_kcontrol_new alc680_capture_mixer[] = {
|
|
|
+ HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
|
|
|
+ HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
|
|
|
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
|
|
|
+ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
|
|
|
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
|
|
|
+ HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
|
|
|
+ { } /* end */
|
|
|
+};
|
|
|
+
|
|
|
+/*
|
|
|
+ * generic initialization of ADC, input mixers and output mixers
|
|
|
+ */
|
|
|
+static struct hda_verb alc680_init_verbs[] = {
|
|
|
+ /* Unmute DAC0-1 and set vol = 0 */
|
|
|
+ {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
|
|
|
+ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
|
|
|
+ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
|
|
|
+
|
|
|
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
|
|
|
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
|
|
|
+ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
|
|
|
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
|
|
|
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
|
|
|
+
|
|
|
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
|
|
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
|
|
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
|
|
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
|
|
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
|
|
+ { }
|
|
|
+};
|
|
|
+
|
|
|
+/* create input playback/capture controls for the given pin */
|
|
|
+static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
|
|
|
+ const char *ctlname, int idx)
|
|
|
+{
|
|
|
+ hda_nid_t dac;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ switch (nid) {
|
|
|
+ case 0x14:
|
|
|
+ dac = 0x02;
|
|
|
+ break;
|
|
|
+ case 0x15:
|
|
|
+ dac = 0x03;
|
|
|
+ break;
|
|
|
+ case 0x16:
|
|
|
+ dac = 0x04;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ if (spec->multiout.dac_nids[0] != dac &&
|
|
|
+ spec->multiout.dac_nids[1] != dac) {
|
|
|
+ err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
|
|
|
+ HDA_COMPOSE_AMP_VAL(dac, 3, idx,
|
|
|
+ HDA_OUTPUT));
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
|
|
|
+ HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
|
|
|
+
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+ spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* add playback controls from the parsed DAC table */
|
|
|
+static int alc680_auto_create_multi_out_ctls(struct alc_spec *spec,
|
|
|
+ const struct auto_pin_cfg *cfg)
|
|
|
+{
|
|
|
+ hda_nid_t nid;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ spec->multiout.dac_nids = spec->private_dac_nids;
|
|
|
+
|
|
|
+ nid = cfg->line_out_pins[0];
|
|
|
+ if (nid) {
|
|
|
+ const char *name;
|
|
|
+ if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
|
|
|
+ name = "Speaker";
|
|
|
+ else
|
|
|
+ name = "Front";
|
|
|
+ err = alc680_new_analog_output(spec, nid, name, 0);
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
+ nid = cfg->speaker_pins[0];
|
|
|
+ if (nid) {
|
|
|
+ err = alc680_new_analog_output(spec, nid, "Speaker", 0);
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+ nid = cfg->hp_pins[0];
|
|
|
+ if (nid) {
|
|
|
+ err = alc680_new_analog_output(spec, nid, "Headphone", 0);
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void alc680_auto_set_output_and_unmute(struct hda_codec *codec,
|
|
|
+ hda_nid_t nid, int pin_type)
|
|
|
+{
|
|
|
+ alc_set_pin_output(codec, nid, pin_type);
|
|
|
+}
|
|
|
+
|
|
|
+static void alc680_auto_init_multi_out(struct hda_codec *codec)
|
|
|
+{
|
|
|
+ struct alc_spec *spec = codec->spec;
|
|
|
+ hda_nid_t nid = spec->autocfg.line_out_pins[0];
|
|
|
+ if (nid) {
|
|
|
+ int pin_type = get_pin_type(spec->autocfg.line_out_type);
|
|
|
+ alc680_auto_set_output_and_unmute(codec, nid, pin_type);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void alc680_auto_init_hp_out(struct hda_codec *codec)
|
|
|
+{
|
|
|
+ struct alc_spec *spec = codec->spec;
|
|
|
+ hda_nid_t pin;
|
|
|
+
|
|
|
+ pin = spec->autocfg.hp_pins[0];
|
|
|
+ if (pin)
|
|
|
+ alc680_auto_set_output_and_unmute(codec, pin, PIN_HP);
|
|
|
+ pin = spec->autocfg.speaker_pins[0];
|
|
|
+ if (pin)
|
|
|
+ alc680_auto_set_output_and_unmute(codec, pin, PIN_OUT);
|
|
|
+}
|
|
|
+
|
|
|
+/* pcm configuration: identical with ALC880 */
|
|
|
+#define alc680_pcm_analog_playback alc880_pcm_analog_playback
|
|
|
+#define alc680_pcm_analog_capture alc880_pcm_analog_capture
|
|
|
+#define alc680_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
|
|
|
+#define alc680_pcm_digital_playback alc880_pcm_digital_playback
|
|
|
+
|
|
|
+static struct hda_input_mux alc680_capture_source = {
|
|
|
+ .num_items = 1,
|
|
|
+ .items = {
|
|
|
+ { "Mic", 0x0 },
|
|
|
+ },
|
|
|
+};
|
|
|
+
|
|
|
+/*
|
|
|
+ * BIOS auto configuration
|
|
|
+ */
|
|
|
+static int alc680_parse_auto_config(struct hda_codec *codec)
|
|
|
+{
|
|
|
+ struct alc_spec *spec = codec->spec;
|
|
|
+ int err;
|
|
|
+ static hda_nid_t alc680_ignore[] = { 0 };
|
|
|
+
|
|
|
+ err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
|
|
|
+ alc680_ignore);
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+ if (!spec->autocfg.line_outs) {
|
|
|
+ if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
|
|
|
+ spec->multiout.max_channels = 2;
|
|
|
+ spec->no_analog = 1;
|
|
|
+ goto dig_only;
|
|
|
+ }
|
|
|
+ return 0; /* can't find valid BIOS pin config */
|
|
|
+ }
|
|
|
+ err = alc680_auto_create_multi_out_ctls(spec, &spec->autocfg);
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ spec->multiout.max_channels = 2;
|
|
|
+
|
|
|
+ dig_only:
|
|
|
+ /* digital only support output */
|
|
|
+ alc_auto_parse_digital(codec);
|
|
|
+ if (spec->kctls.list)
|
|
|
+ add_mixer(spec, spec->kctls.list);
|
|
|
+
|
|
|
+ add_verb(spec, alc680_init_verbs);
|
|
|
+ spec->num_mux_defs = 1;
|
|
|
+ spec->input_mux = &alc680_capture_source;
|
|
|
+
|
|
|
+ err = alc_auto_add_mic_boost(codec);
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+#define alc680_auto_init_analog_input alc882_auto_init_analog_input
|
|
|
+
|
|
|
+/* init callback for auto-configuration model -- overriding the default init */
|
|
|
+static void alc680_auto_init(struct hda_codec *codec)
|
|
|
+{
|
|
|
+ struct alc_spec *spec = codec->spec;
|
|
|
+ alc680_auto_init_multi_out(codec);
|
|
|
+ alc680_auto_init_hp_out(codec);
|
|
|
+ alc680_auto_init_analog_input(codec);
|
|
|
+ alc_auto_init_digital(codec);
|
|
|
+ if (spec->unsol_event)
|
|
|
+ alc_inithook(codec);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * configuration and preset
|
|
|
+ */
|
|
|
+static const char *alc680_models[ALC680_MODEL_LAST] = {
|
|
|
+ [ALC680_BASE] = "base",
|
|
|
+ [ALC680_AUTO] = "auto",
|
|
|
+};
|
|
|
+
|
|
|
+static struct snd_pci_quirk alc680_cfg_tbl[] = {
|
|
|
+ SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE),
|
|
|
+ {}
|
|
|
+};
|
|
|
+
|
|
|
+static struct alc_config_preset alc680_presets[] = {
|
|
|
+ [ALC680_BASE] = {
|
|
|
+ .mixers = { alc680_base_mixer },
|
|
|
+ .cap_mixer = alc680_capture_mixer,
|
|
|
+ .init_verbs = { alc680_init_verbs },
|
|
|
+ .num_dacs = ARRAY_SIZE(alc680_dac_nids),
|
|
|
+ .dac_nids = alc680_dac_nids,
|
|
|
+ .num_adc_nids = ARRAY_SIZE(alc680_adc_nids),
|
|
|
+ .adc_nids = alc680_adc_nids,
|
|
|
+ .hp_nid = 0x04,
|
|
|
+ .dig_out_nid = ALC680_DIGOUT_NID,
|
|
|
+ .num_channel_mode = ARRAY_SIZE(alc680_modes),
|
|
|
+ .channel_mode = alc680_modes,
|
|
|
+ .input_mux = &alc680_capture_source,
|
|
|
+ },
|
|
|
+};
|
|
|
+
|
|
|
+static int patch_alc680(struct hda_codec *codec)
|
|
|
+{
|
|
|
+ struct alc_spec *spec;
|
|
|
+ int board_config;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
|
|
+ if (spec == NULL)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ codec->spec = spec;
|
|
|
+
|
|
|
+ board_config = snd_hda_check_board_config(codec, ALC680_MODEL_LAST,
|
|
|
+ alc680_models,
|
|
|
+ alc680_cfg_tbl);
|
|
|
+
|
|
|
+ if (board_config < 0 || board_config >= ALC680_MODEL_LAST) {
|
|
|
+ printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
|
|
|
+ codec->chip_name);
|
|
|
+ board_config = ALC680_AUTO;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (board_config == ALC680_AUTO) {
|
|
|
+ /* automatic parse from the BIOS config */
|
|
|
+ err = alc680_parse_auto_config(codec);
|
|
|
+ if (err < 0) {
|
|
|
+ alc_free(codec);
|
|
|
+ return err;
|
|
|
+ } else if (!err) {
|
|
|
+ printk(KERN_INFO
|
|
|
+ "hda_codec: Cannot set up configuration "
|
|
|
+ "from BIOS. Using base mode...\n");
|
|
|
+ board_config = ALC680_BASE;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (board_config != ALC680_AUTO)
|
|
|
+ setup_preset(codec, &alc680_presets[board_config]);
|
|
|
+
|
|
|
+ spec->stream_analog_playback = &alc680_pcm_analog_playback;
|
|
|
+ spec->stream_analog_capture = &alc680_pcm_analog_capture;
|
|
|
+ spec->stream_analog_alt_capture = &alc680_pcm_analog_alt_capture;
|
|
|
+ spec->stream_digital_playback = &alc680_pcm_digital_playback;
|
|
|
+
|
|
|
+ if (!spec->adc_nids) {
|
|
|
+ spec->adc_nids = alc680_adc_nids;
|
|
|
+ spec->num_adc_nids = ARRAY_SIZE(alc680_adc_nids);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!spec->cap_mixer)
|
|
|
+ set_capture_mixer(codec);
|
|
|
+
|
|
|
+ spec->vmaster_nid = 0x02;
|
|
|
+
|
|
|
+ codec->patch_ops = alc_patch_ops;
|
|
|
+ if (board_config == ALC680_AUTO)
|
|
|
+ spec->init_hook = alc680_auto_init;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* patch entries
|
|
|
*/
|
|
@@ -18804,6 +19339,7 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = {
|
|
|
{ .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
|
|
|
{ .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
|
|
|
{ .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
|
|
|
+ { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
|
|
|
{ .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
|
|
|
{ .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
|
|
|
{ .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
|