Commit 21268961 authored by Takashi Iwai's avatar Takashi Iwai

ALSA: hda - More flexible dynamic-ADC switching for Realtek codecs

This patch changes the auto-parser and the auto-mic handling codes to
allow more flexible dynamic ADC-switching with Realtek codecs.

In the new code, the following strategy is taken:

- When a cap-src can't handle all input-sources, either skip it, or
  switch to the ADC-switching mode.  In ADC-switching mode, like the
  former dual-ADC mode for ALC275, it changes ADC on the fly according
  to the current input source.
- When auto-mic is possible, always assign imux.  If the mic pins are
  set statically via a quirk, rebuild imux according to the pins.
  In the auto-mic mode, the driver always changes the imux (although
  the imux isn't exposed as a mixer element).
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent a926757f
...@@ -276,14 +276,6 @@ enum { ...@@ -276,14 +276,6 @@ enum {
ALC_INIT_GPIO3, ALC_INIT_GPIO3,
}; };
struct alc_mic_route {
hda_nid_t pin;
unsigned char mux_idx;
unsigned char amix_idx;
};
#define MUX_IDX_UNDEF ((unsigned char)-1)
struct alc_customize_define { struct alc_customize_define {
unsigned int sku_cfg; unsigned int sku_cfg;
unsigned char port_connectivity; unsigned char port_connectivity;
...@@ -351,7 +343,6 @@ struct alc_spec { ...@@ -351,7 +343,6 @@ struct alc_spec {
hda_nid_t mixer_nid; /* analog-mixer NID */ hda_nid_t mixer_nid; /* analog-mixer NID */
/* capture setup for dynamic dual-adc switch */ /* capture setup for dynamic dual-adc switch */
unsigned int cur_adc_idx;
hda_nid_t cur_adc; hda_nid_t cur_adc;
unsigned int cur_adc_stream_tag; unsigned int cur_adc_stream_tag;
unsigned int cur_adc_format; unsigned int cur_adc_format;
...@@ -360,9 +351,9 @@ struct alc_spec { ...@@ -360,9 +351,9 @@ struct alc_spec {
unsigned int num_mux_defs; unsigned int num_mux_defs;
const struct hda_input_mux *input_mux; const struct hda_input_mux *input_mux;
unsigned int cur_mux[3]; unsigned int cur_mux[3];
struct alc_mic_route ext_mic; hda_nid_t ext_mic_pin;
struct alc_mic_route dock_mic; hda_nid_t dock_mic_pin;
struct alc_mic_route int_mic; hda_nid_t int_mic_pin;
/* channel model */ /* channel model */
const struct hda_channel_mode *channel_mode; const struct hda_channel_mode *channel_mode;
...@@ -382,6 +373,9 @@ struct alc_spec { ...@@ -382,6 +373,9 @@ struct alc_spec {
hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
hda_nid_t private_adc_nids[AUTO_CFG_MAX_OUTS]; hda_nid_t private_adc_nids[AUTO_CFG_MAX_OUTS];
hda_nid_t private_capsrc_nids[AUTO_CFG_MAX_OUTS]; hda_nid_t private_capsrc_nids[AUTO_CFG_MAX_OUTS];
hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS];
unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS];
int int_mic_idx, ext_mic_idx, dock_mic_idx; /* for auto-mic */
/* hooks */ /* hooks */
void (*init_hook)(struct hda_codec *codec); void (*init_hook)(struct hda_codec *codec);
...@@ -396,6 +390,7 @@ struct alc_spec { ...@@ -396,6 +390,7 @@ struct alc_spec {
unsigned int line_jack_present:1; unsigned int line_jack_present:1;
unsigned int master_mute:1; unsigned int master_mute:1;
unsigned int auto_mic: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 automute:1; /* HP automute enabled */
unsigned int detect_line:1; /* Line-out detection enabled */ unsigned int detect_line:1; /* Line-out detection enabled */
unsigned int automute_lines:1; /* automute line-out as well */ unsigned int automute_lines:1; /* automute line-out as well */
...@@ -403,7 +398,7 @@ struct alc_spec { ...@@ -403,7 +398,7 @@ struct alc_spec {
/* other flags */ /* other flags */
unsigned int no_analog :1; /* digital I/O only */ unsigned int no_analog :1; /* digital I/O only */
unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */ unsigned int dyn_adc_switch:1; /* switch ADCs (for ALC275) */
unsigned int single_input_src:1; unsigned int single_input_src:1;
unsigned int vol_in_capsrc:1; /* use capsrc volume (ADC has no vol) */ unsigned int vol_in_capsrc:1; /* use capsrc volume (ADC has no vol) */
...@@ -495,47 +490,81 @@ static int alc_mux_enum_get(struct snd_kcontrol *kcontrol, ...@@ -495,47 +490,81 @@ static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
return 0; return 0;
} }
static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, static bool alc_dyn_adc_pcm_resetup(struct hda_codec *codec, int cur)
struct snd_ctl_elem_value *ucontrol) {
struct alc_spec *spec = codec->spec;
hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]];
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, 1);
spec->cur_adc = new_adc;
snd_hda_codec_setup_stream(codec, new_adc,
spec->cur_adc_stream_tag, 0,
spec->cur_adc_format);
return true;
}
return false;
}
/* select the given imux item; either unmute exclusively or select the route */
static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
unsigned int idx, bool force)
{ {
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
const struct hda_input_mux *imux; const struct hda_input_mux *imux;
unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
unsigned int mux_idx; unsigned int mux_idx;
hda_nid_t nid = spec->capsrc_nids ? int i, type;
spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx]; hda_nid_t nid;
unsigned int type;
mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx; mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
imux = &spec->input_mux[mux_idx]; imux = &spec->input_mux[mux_idx];
if (!imux->num_items && mux_idx > 0) if (!imux->num_items && mux_idx > 0)
imux = &spec->input_mux[0]; imux = &spec->input_mux[0];
type = get_wcaps_type(get_wcaps(codec, nid));
if (type == AC_WID_AUD_MIX) {
/* Matrix-mixer style (e.g. ALC882) */
unsigned int *cur_val = &spec->cur_mux[adc_idx];
unsigned int i, idx;
idx = ucontrol->value.enumerated.item[0];
if (idx >= imux->num_items) if (idx >= imux->num_items)
idx = imux->num_items - 1; idx = imux->num_items - 1;
if (*cur_val == idx) if (spec->cur_mux[adc_idx] == idx && !force)
return 0; return 0;
spec->cur_mux[adc_idx] = idx;
if (spec->dyn_adc_switch) {
alc_dyn_adc_pcm_resetup(codec, idx);
adc_idx = spec->dyn_adc_idx[idx];
}
nid = spec->capsrc_nids ?
spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
/* no selection? */
if (snd_hda_get_conn_list(codec, nid, NULL) <= 1)
return 1;
type = get_wcaps_type(get_wcaps(codec, nid));
if (type == AC_WID_AUD_MIX) {
/* Matrix-mixer style (e.g. ALC882) */
for (i = 0; i < imux->num_items; i++) { for (i = 0; i < imux->num_items; i++) {
unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
imux->items[i].index, imux->items[i].index,
HDA_AMP_MUTE, v); HDA_AMP_MUTE, v);
} }
*cur_val = idx;
return 1;
} else { } else {
/* MUX style (e.g. ALC880) */ /* MUX style (e.g. ALC880) */
return snd_hda_input_mux_put(codec, imux, ucontrol, nid, snd_hda_codec_write_cache(codec, nid, 0,
&spec->cur_mux[adc_idx]); AC_VERB_SET_CONNECT_SEL,
imux->items[idx].index);
} }
return 1;
}
static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
return alc_mux_select(codec, adc_idx,
ucontrol->value.enumerated.item[0], false);
} }
/* /*
...@@ -1059,8 +1088,8 @@ static int alc_init_jacks(struct hda_codec *codec) ...@@ -1059,8 +1088,8 @@ static int alc_init_jacks(struct hda_codec *codec)
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
int err; int err;
unsigned int hp_nid = spec->autocfg.hp_pins[0]; unsigned int hp_nid = spec->autocfg.hp_pins[0];
unsigned int mic_nid = spec->ext_mic.pin; unsigned int mic_nid = spec->ext_mic_pin;
unsigned int dock_nid = spec->dock_mic.pin; unsigned int dock_nid = spec->dock_mic_pin;
if (hp_nid) { if (hp_nid) {
err = snd_hda_input_jack_add(codec, hp_nid, err = snd_hda_input_jack_add(codec, hp_nid,
...@@ -1199,93 +1228,29 @@ static void alc_line_automute(struct hda_codec *codec) ...@@ -1199,93 +1228,29 @@ static void alc_line_automute(struct hda_codec *codec)
#define get_connection_index(codec, mux, nid) \ #define get_connection_index(codec, mux, nid) \
snd_hda_get_conn_index(codec, mux, nid, 0) snd_hda_get_conn_index(codec, mux, nid, 0)
/* 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, 1);
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) static void alc_mic_automute(struct hda_codec *codec)
{ {
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
struct alc_mic_route *dead1, *dead2, *alive; hda_nid_t *pins = spec->imux_pins;
unsigned int present, type;
hda_nid_t cap_nid;
if (!spec->auto_mic) if (!spec->auto_mic || !spec->auto_mic_valid_imux)
return;
if (!spec->int_mic.pin || !spec->ext_mic.pin)
return; return;
if (snd_BUG_ON(!spec->adc_nids)) if (snd_BUG_ON(!spec->adc_nids))
return; return;
if (snd_BUG_ON(spec->int_mic_idx < 0 || spec->ext_mic_idx < 0))
if (spec->dual_adc_switch) {
alc_dual_mic_adc_auto_switch(codec);
return; return;
}
cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0];
alive = &spec->int_mic;
dead1 = &spec->ext_mic;
dead2 = &spec->dock_mic;
present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
if (present) {
alive = &spec->ext_mic;
dead1 = &spec->int_mic;
dead2 = &spec->dock_mic;
}
if (!present && spec->dock_mic.pin > 0) {
present = snd_hda_jack_detect(codec, spec->dock_mic.pin);
if (present) {
alive = &spec->dock_mic;
dead1 = &spec->int_mic;
dead2 = &spec->ext_mic;
}
snd_hda_input_jack_report(codec, spec->dock_mic.pin);
}
type = get_wcaps_type(get_wcaps(codec, cap_nid)); if (snd_hda_jack_detect(codec, pins[spec->ext_mic_idx]))
if (type == AC_WID_AUD_MIX) { alc_mux_select(codec, 0, spec->ext_mic_idx, false);
/* Matrix-mixer style (e.g. ALC882) */ else if (spec->dock_mic_idx >= 0 &&
snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT, snd_hda_jack_detect(codec, pins[spec->dock_mic_idx]))
alive->mux_idx, alc_mux_select(codec, 0, spec->dock_mic_idx, false);
HDA_AMP_MUTE, 0); else
if (dead1->pin > 0) alc_mux_select(codec, 0, spec->int_mic_idx, false);
snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
dead1->mux_idx,
HDA_AMP_MUTE, HDA_AMP_MUTE);
if (dead2->pin > 0)
snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
dead2->mux_idx,
HDA_AMP_MUTE, HDA_AMP_MUTE);
} else {
/* MUX style (e.g. ALC880) */
snd_hda_codec_write_cache(codec, cap_nid, 0,
AC_VERB_SET_CONNECT_SEL,
alive->mux_idx);
}
snd_hda_input_jack_report(codec, spec->ext_mic.pin);
/* FIXME: analog mixer */ snd_hda_input_jack_report(codec, pins[spec->ext_mic_idx]);
if (spec->dock_mic_idx >= 0)
snd_hda_input_jack_report(codec, pins[spec->dock_mic_idx]);
} }
/* unsolicited event for HP jack sensing */ /* unsolicited event for HP jack sensing */
...@@ -1602,6 +1567,87 @@ static void alc_init_auto_hp(struct hda_codec *codec) ...@@ -1602,6 +1567,87 @@ static void alc_init_auto_hp(struct hda_codec *codec)
} }
} }
static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
{
int i;
for (i = 0; i < nums; i++)
if (list[i] == nid)
return i;
return -1;
}
static bool alc_check_dyn_adc_switch(struct hda_codec *codec);
/* rebuild imux for matching with the given auto-mic pins (if not yet) */
static bool alc_rebuild_imux_for_auto_mic(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
struct hda_input_mux *imux;
static char * const texts[3] = {
"Mic", "Internal Mic", "Dock Mic"
};
int i;
if (!spec->auto_mic)
return false;
imux = &spec->private_imux[0];
if (spec->input_mux == imux)
return true;
spec->imux_pins[0] = spec->ext_mic_pin;
spec->imux_pins[1] = spec->int_mic_pin;
spec->imux_pins[2] = spec->dock_mic_pin;
for (i = 0; i < 3; i++) {
strcpy(imux->items[i].label, texts[i]);
if (spec->imux_pins[i])
imux->num_items = i + 1;
}
spec->num_mux_defs = 1;
spec->input_mux = imux;
return true;
}
/* check whether all auto-mic pins are valid; setup indices if OK */
static bool alc_auto_mic_check_imux(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
const struct hda_input_mux *imux;
if (!spec->auto_mic)
return false;
if (spec->auto_mic_valid_imux)
return true; /* already checked */
/* fill up imux indices */
if (!alc_check_dyn_adc_switch(codec)) {
spec->auto_mic = 0;
return false;
}
imux = spec->input_mux;
spec->ext_mic_idx = find_idx_in_nid_list(spec->ext_mic_pin,
spec->imux_pins, imux->num_items);
spec->int_mic_idx = find_idx_in_nid_list(spec->int_mic_pin,
spec->imux_pins, imux->num_items);
spec->dock_mic_idx = find_idx_in_nid_list(spec->dock_mic_pin,
spec->imux_pins, imux->num_items);
if (spec->ext_mic_idx < 0 || spec->int_mic_idx < 0) {
spec->auto_mic = 0;
return false; /* no corresponding imux */
}
snd_hda_codec_write_cache(codec, spec->ext_mic_pin, 0,
AC_VERB_SET_UNSOLICITED_ENABLE,
AC_USRSP_EN | ALC880_MIC_EVENT);
if (spec->dock_mic_pin)
snd_hda_codec_write_cache(codec, spec->dock_mic_pin, 0,
AC_VERB_SET_UNSOLICITED_ENABLE,
AC_USRSP_EN | ALC880_MIC_EVENT);
spec->auto_mic_valid_imux = 1;
spec->auto_mic = 1;
return true;
}
static void alc_init_auto_mic(struct hda_codec *codec) static void alc_init_auto_mic(struct hda_codec *codec)
{ {
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
...@@ -1609,6 +1655,8 @@ static void alc_init_auto_mic(struct hda_codec *codec) ...@@ -1609,6 +1655,8 @@ static void alc_init_auto_mic(struct hda_codec *codec)
hda_nid_t fixed, ext, dock; hda_nid_t fixed, ext, dock;
int i; int i;
spec->ext_mic_idx = spec->int_mic_idx = spec->dock_mic_idx = -1;
fixed = ext = dock = 0; fixed = ext = dock = 0;
for (i = 0; i < cfg->num_inputs; i++) { for (i = 0; i < cfg->num_inputs; i++) {
hda_nid_t nid = cfg->inputs[i].pin; hda_nid_t nid = cfg->inputs[i].pin;
...@@ -1650,18 +1698,18 @@ static void alc_init_auto_mic(struct hda_codec *codec) ...@@ -1650,18 +1698,18 @@ static void alc_init_auto_mic(struct hda_codec *codec)
return; /* no unsol support */ return; /* no unsol support */
if (dock && !is_jack_detectable(codec, dock)) if (dock && !is_jack_detectable(codec, dock))
return; /* no unsol support */ return; /* no unsol support */
/* check imux indices */
spec->ext_mic_pin = ext;
spec->int_mic_pin = fixed;
spec->dock_mic_pin = dock;
spec->auto_mic = 1;
if (!alc_auto_mic_check_imux(codec))
return;
snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n", snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n",
ext, fixed, dock); ext, fixed, dock);
spec->ext_mic.pin = ext;
spec->dock_mic.pin = dock;
spec->int_mic.pin = fixed;
spec->ext_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
spec->dock_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
spec->int_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
spec->auto_mic = 1;
snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0,
AC_VERB_SET_UNSOLICITED_ENABLE,
AC_USRSP_EN | ALC880_MIC_EVENT);
spec->unsol_event = alc_sku_unsol_event; spec->unsol_event = alc_sku_unsol_event;
} }
...@@ -1737,11 +1785,7 @@ static int alc_auto_parse_customize_define(struct hda_codec *codec) ...@@ -1737,11 +1785,7 @@ static int alc_auto_parse_customize_define(struct hda_codec *codec)
static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
{ {
int i; return find_idx_in_nid_list(nid, list, nums) >= 0;
for (i = 0; i < nums; i++)
if (list[i] == nid)
return true;
return false;
} }
/* check subsystem ID and set up device-specific initialization; /* check subsystem ID and set up device-specific initialization;
...@@ -1871,7 +1915,11 @@ static void alc_ssid_check(struct hda_codec *codec, ...@@ -1871,7 +1915,11 @@ static void alc_ssid_check(struct hda_codec *codec,
"Enable default setup for auto mode as fallback\n"); "Enable default setup for auto mode as fallback\n");
spec->init_amp = ALC_INIT_DEFAULT; spec->init_amp = ALC_INIT_DEFAULT;
} }
}
/* 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_auto_hp(codec);
alc_init_auto_mic(codec); alc_init_auto_mic(codec);
} }
...@@ -2722,10 +2770,10 @@ static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol, ...@@ -2722,10 +2770,10 @@ static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
{ {
struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
int i, err; int i, err = 0;
mutex_lock(&codec->control_mutex); mutex_lock(&codec->control_mutex);
if (check_adc_switch && spec->dual_adc_switch) { if (check_adc_switch && spec->dyn_adc_switch) {
for (i = 0; i < spec->num_adc_nids; i++) { for (i = 0; i < spec->num_adc_nids; i++) {
kcontrol->private_value = kcontrol->private_value =
HDA_COMPOSE_AMP_VAL(spec->adc_nids[i], HDA_COMPOSE_AMP_VAL(spec->adc_nids[i],
...@@ -2742,7 +2790,7 @@ static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol, ...@@ -2742,7 +2790,7 @@ static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
3, 0, HDA_OUTPUT); 3, 0, HDA_OUTPUT);
else else
kcontrol->private_value = kcontrol->private_value =
val = HDA_COMPOSE_AMP_VAL(spec->adc_nids[i], HDA_COMPOSE_AMP_VAL(spec->adc_nids[i],
3, 0, HDA_INPUT); 3, 0, HDA_INPUT);
err = func(kcontrol, ucontrol); err = func(kcontrol, ucontrol);
} }
...@@ -4299,21 +4347,21 @@ static int alc_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, ...@@ -4299,21 +4347,21 @@ static int alc_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
} }
/* analog capture with dynamic dual-adc changes */ /* analog capture with dynamic dual-adc changes */
static int dualmic_capture_pcm_prepare(struct hda_pcm_stream *hinfo, static int dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
struct hda_codec *codec, struct hda_codec *codec,
unsigned int stream_tag, unsigned int stream_tag,
unsigned int format, unsigned int format,
struct snd_pcm_substream *substream) struct snd_pcm_substream *substream)
{ {
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
spec->cur_adc = spec->adc_nids[spec->cur_adc_idx]; spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]];
spec->cur_adc_stream_tag = stream_tag; spec->cur_adc_stream_tag = stream_tag;
spec->cur_adc_format = format; spec->cur_adc_format = format;
snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
return 0; return 0;
} }
static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
struct hda_codec *codec, struct hda_codec *codec,
struct snd_pcm_substream *substream) struct snd_pcm_substream *substream)
{ {
...@@ -4323,14 +4371,14 @@ static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, ...@@ -4323,14 +4371,14 @@ static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
return 0; return 0;
} }
static const struct hda_pcm_stream dualmic_pcm_analog_capture = { static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = {
.substreams = 1, .substreams = 1,
.channels_min = 2, .channels_min = 2,
.channels_max = 2, .channels_max = 2,
.nid = 0, /* fill later */ .nid = 0, /* fill later */
.ops = { .ops = {
.prepare = dualmic_capture_pcm_prepare, .prepare = dyn_adc_capture_pcm_prepare,
.cleanup = dualmic_capture_pcm_cleanup .cleanup = dyn_adc_capture_pcm_cleanup
}, },
}; };
...@@ -4426,8 +4474,12 @@ static int alc_build_pcms(struct hda_codec *codec) ...@@ -4426,8 +4474,12 @@ static int alc_build_pcms(struct hda_codec *codec)
} }
if (spec->adc_nids) { if (spec->adc_nids) {
p = spec->stream_analog_capture; p = spec->stream_analog_capture;
if (!p) if (!p) {
if (spec->dyn_adc_switch)
p = &dyn_adc_pcm_analog_capture;
else
p = &alc_pcm_analog_capture; p = &alc_pcm_analog_capture;
}
info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
} }
...@@ -5452,7 +5504,6 @@ static int alc_auto_fill_adc_caps(struct hda_codec *codec) ...@@ -5452,7 +5504,6 @@ static int alc_auto_fill_adc_caps(struct hda_codec *codec)
break; break;
} }
spec->adc_nids = spec->private_adc_nids; spec->adc_nids = spec->private_adc_nids;
if (indep_capsrc)
spec->capsrc_nids = spec->private_capsrc_nids; spec->capsrc_nids = spec->private_capsrc_nids;
spec->num_adc_nids = nums; spec->num_adc_nids = nums;
return nums; return nums;
...@@ -5504,11 +5555,16 @@ static int alc_auto_create_input_ctls(struct hda_codec *codec) ...@@ -5504,11 +5555,16 @@ static int alc_auto_create_input_ctls(struct hda_codec *codec)
spec->capsrc_nids[c] : spec->adc_nids[c]; spec->capsrc_nids[c] : spec->adc_nids[c];
idx = get_connection_index(codec, cap, pin); idx = get_connection_index(codec, cap, pin);
if (idx >= 0) { if (idx >= 0) {
spec->imux_pins[imux->num_items] = pin;
snd_hda_add_imux_item(imux, label, idx, NULL); snd_hda_add_imux_item(imux, label, idx, NULL);
break; break;
} }
} }
} }
spec->num_mux_defs = 1;
spec->input_mux = imux;
return 0; return 0;
} }
...@@ -5613,13 +5669,10 @@ static int alc880_parse_auto_config(struct hda_codec *codec) ...@@ -5613,13 +5669,10 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
if (spec->kctls.list) if (spec->kctls.list)
add_mixer(spec, spec->kctls.list); add_mixer(spec, spec->kctls.list);
spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux[0];
if (!spec->dual_adc_switch)
alc_remove_invalid_adc_nids(codec); alc_remove_invalid_adc_nids(codec);
alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
alc_auto_check_switches(codec);
return 1; return 1;
} }
...@@ -5637,45 +5690,6 @@ static void alc880_auto_init(struct hda_codec *codec) ...@@ -5637,45 +5690,6 @@ static void alc880_auto_init(struct hda_codec *codec)
alc_inithook(codec); alc_inithook(codec);
} }
/* check the ADC/MUX contains all input pins; some ADC/MUX contains only
* one of two digital mic pins, e.g. on ALC272
*/
static void fixup_automic_adc(struct hda_codec *codec)
{
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 iidx, eidx;
iidx = get_connection_index(codec, cap, spec->int_mic.pin);
if (iidx < 0)
continue;
eidx = get_connection_index(codec, cap, spec->ext_mic.pin);
if (eidx < 0)
continue;
spec->int_mic.mux_idx = iidx;
spec->ext_mic.mux_idx = eidx;
if (spec->capsrc_nids)
spec->capsrc_nids += i;
spec->adc_nids += i;
spec->num_adc_nids = 1;
/* optional dock-mic */
eidx = get_connection_index(codec, cap, spec->dock_mic.pin);
if (eidx < 0)
spec->dock_mic.pin = 0;
else
spec->dock_mic.mux_idx = eidx;
return;
}
snd_printd(KERN_INFO "hda_codec: %s: "
"No ADC/MUX containing both 0x%x and 0x%x pins\n",
codec->chip_name, spec->int_mic.pin, spec->ext_mic.pin);
spec->auto_mic = 0; /* disable auto-mic to be sure */
}
/* select or unmute the given capsrc route */ /* select or unmute the given capsrc route */
static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap, static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap,
int idx) int idx)
...@@ -5683,7 +5697,7 @@ static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap, ...@@ -5683,7 +5697,7 @@ static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap,
if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) { if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx, snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
HDA_AMP_MUTE, 0); HDA_AMP_MUTE, 0);
} else { } else if (snd_hda_get_conn_list(codec, cap, NULL) > 1) {
snd_hda_codec_write_cache(codec, cap, 0, snd_hda_codec_write_cache(codec, cap, 0,
AC_VERB_SET_CONNECT_SEL, idx); AC_VERB_SET_CONNECT_SEL, idx);
} }
...@@ -5711,44 +5725,14 @@ static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin) ...@@ -5711,44 +5725,14 @@ static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
return -1; /* not found */ 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)
{
struct alc_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
int i;
/* search for the input pin; there must be only one */
if (cfg->num_inputs != 1)
return;
i = init_capsrc_for_pin(codec, cfg->inputs[0].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;
spec->single_input_src = 1;
}
}
/* 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->dock_mic.pin);
init_capsrc_for_pin(codec, spec->int_mic.pin);
}
/* initialize some special cases for input sources */ /* initialize some special cases for input sources */
static void alc_init_special_input_src(struct hda_codec *codec) static void alc_init_special_input_src(struct hda_codec *codec)
{ {
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
if (spec->dual_adc_switch) int i;
fixup_dual_adc_switch(codec);
else if (spec->single_input_src) for (i = 0; i < spec->autocfg.num_inputs; i++)
init_capsrc_for_pin(codec, spec->autocfg.inputs[0].pin); init_capsrc_for_pin(codec, spec->autocfg.inputs[i].pin);
} }
static void set_capture_mixer(struct hda_codec *codec) static void set_capture_mixer(struct hda_codec *codec)
...@@ -5777,16 +5761,14 @@ static void set_capture_mixer(struct hda_codec *codec) ...@@ -5777,16 +5761,14 @@ static void set_capture_mixer(struct hda_codec *codec)
if (spec->num_adc_nids > 0) { if (spec->num_adc_nids > 0) {
int mux = 0; int mux = 0;
int num_adcs = 0; int num_adcs = 0;
if (spec->dual_adc_switch)
num_adcs = 1; if (spec->input_mux && spec->input_mux->num_items > 1)
else if (spec->auto_mic)
fixup_automic_adc(codec);
else if (spec->input_mux) {
if (spec->input_mux->num_items > 1)
mux = 1; mux = 1;
else if (spec->input_mux->num_items == 1) if (spec->auto_mic) {
fixup_single_adc(codec); num_adcs = 1;
} mux = 0;
} else if (spec->dyn_adc_switch)
num_adcs = 1;
if (!num_adcs) { if (!num_adcs) {
if (spec->num_adc_nids > 3) if (spec->num_adc_nids > 3)
spec->num_adc_nids = 3; spec->num_adc_nids = 3;
...@@ -5798,35 +5780,92 @@ static void set_capture_mixer(struct hda_codec *codec) ...@@ -5798,35 +5780,92 @@ static void set_capture_mixer(struct hda_codec *codec)
} }
} }
/* check whether dynamic ADC-switching is available */
static bool alc_check_dyn_adc_switch(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
struct hda_input_mux *imux = &spec->private_imux[0];
int i, n, idx;
hda_nid_t cap, pin;
if (imux != spec->input_mux) /* no dynamic imux? */
return false;
for (n = 0; n < spec->num_adc_nids; n++) {
cap = spec->private_capsrc_nids[n];
for (i = 0; i < imux->num_items; i++) {
pin = spec->imux_pins[i];
if (!pin)
return false;
if (get_connection_index(codec, cap, pin) < 0)
break;
}
if (i >= imux->num_items)
return false; /* no ADC-switch is needed */
}
for (i = 0; i < imux->num_items; i++) {
pin = spec->imux_pins[i];
for (n = 0; n < spec->num_adc_nids; n++) {
cap = spec->private_capsrc_nids[n];
idx = get_connection_index(codec, cap, pin);
if (idx >= 0) {
imux->items[i].index = idx;
spec->dyn_adc_idx[i] = n;
break;
}
}
}
snd_printdd("realtek: enabling ADC switching\n");
spec->dyn_adc_switch = 1;
return true;
}
/* filter out invalid adc_nids (and capsrc_nids) that don't give all /* filter out invalid adc_nids (and capsrc_nids) that don't give all
* active input pins * active input pins
*/ */
static void alc_remove_invalid_adc_nids(struct hda_codec *codec) static void alc_remove_invalid_adc_nids(struct hda_codec *codec)
{ {
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg; const struct hda_input_mux *imux;
hda_nid_t adc_nids[ARRAY_SIZE(spec->private_adc_nids)]; hda_nid_t adc_nids[ARRAY_SIZE(spec->private_adc_nids)];
hda_nid_t capsrc_nids[ARRAY_SIZE(spec->private_adc_nids)]; hda_nid_t capsrc_nids[ARRAY_SIZE(spec->private_adc_nids)];
int i, n, nums; int i, n, nums;
imux = spec->input_mux;
if (!imux)
return;
if (spec->dyn_adc_switch)
return;
nums = 0; nums = 0;
for (n = 0; n < spec->num_adc_nids; n++) { for (n = 0; n < spec->num_adc_nids; n++) {
hda_nid_t cap = spec->private_capsrc_nids[n]; hda_nid_t cap = spec->private_capsrc_nids[n];
for (i = 0; i < cfg->num_inputs; i++) { int num_conns = snd_hda_get_conn_list(codec, cap, NULL);
hda_nid_t pin = cfg->inputs[i].pin; for (i = 0; i < imux->num_items; i++) {
hda_nid_t pin = spec->imux_pins[i];
if (pin) {
if (get_connection_index(codec, cap, pin) < 0) if (get_connection_index(codec, cap, pin) < 0)
break; break;
} else if (num_conns <= imux->items[i].index)
break;
} }
if (i >= cfg->num_inputs) { if (i >= imux->num_items) {
adc_nids[nums] = spec->private_adc_nids[n]; adc_nids[nums] = spec->private_adc_nids[n];
capsrc_nids[nums++] = cap; capsrc_nids[nums++] = cap;
} }
} }
if (!nums) { if (!nums) {
/* check whether ADC-switch is possible */
if (!alc_check_dyn_adc_switch(codec)) {
printk(KERN_WARNING "hda_codec: %s: no valid ADC found;" printk(KERN_WARNING "hda_codec: %s: no valid ADC found;"
" using fallback 0x%x\n", " using fallback 0x%x\n",
codec->chip_name, spec->private_adc_nids[0]); codec->chip_name, spec->private_adc_nids[0]);
spec->num_adc_nids = 1; spec->num_adc_nids = 1;
spec->auto_mic = 0;
return;
}
} else if (nums != spec->num_adc_nids) { } else if (nums != spec->num_adc_nids) {
memcpy(spec->private_adc_nids, adc_nids, memcpy(spec->private_adc_nids, adc_nids,
nums * sizeof(hda_nid_t)); nums * sizeof(hda_nid_t));
...@@ -5834,6 +5873,11 @@ static void alc_remove_invalid_adc_nids(struct hda_codec *codec) ...@@ -5834,6 +5873,11 @@ static void alc_remove_invalid_adc_nids(struct hda_codec *codec)
nums * sizeof(hda_nid_t)); nums * sizeof(hda_nid_t));
spec->num_adc_nids = nums; spec->num_adc_nids = nums;
} }
if (spec->auto_mic)
alc_auto_mic_check_imux(codec); /* check auto-mic setups */
else if (spec->input_mux->num_items == 1)
spec->num_adc_nids = 1; /* reduce to a single ADC */
} }
#ifdef CONFIG_SND_HDA_INPUT_BEEP #ifdef CONFIG_SND_HDA_INPUT_BEEP
...@@ -5915,6 +5959,7 @@ static int patch_alc880(struct hda_codec *codec) ...@@ -5915,6 +5959,7 @@ static int patch_alc880(struct hda_codec *codec)
if (!spec->adc_nids && spec->input_mux) { if (!spec->adc_nids && spec->input_mux) {
alc_auto_fill_adc_caps(codec); alc_auto_fill_adc_caps(codec);
alc_rebuild_imux_for_auto_mic(codec);
alc_remove_invalid_adc_nids(codec); alc_remove_invalid_adc_nids(codec);
} }
set_capture_mixer(codec); set_capture_mixer(codec);
...@@ -7160,13 +7205,10 @@ static int alc260_parse_auto_config(struct hda_codec *codec) ...@@ -7160,13 +7205,10 @@ static int alc260_parse_auto_config(struct hda_codec *codec)
if (spec->kctls.list) if (spec->kctls.list)
add_mixer(spec, spec->kctls.list); add_mixer(spec, spec->kctls.list);
spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux[0];
if (!spec->dual_adc_switch)
alc_remove_invalid_adc_nids(codec); alc_remove_invalid_adc_nids(codec);
alc_ssid_check(codec, 0x10, 0x15, 0x0f, 0); alc_ssid_check(codec, 0x10, 0x15, 0x0f, 0);
alc_auto_check_switches(codec);
return 1; return 1;
} }
...@@ -7450,6 +7492,7 @@ static int patch_alc260(struct hda_codec *codec) ...@@ -7450,6 +7492,7 @@ static int patch_alc260(struct hda_codec *codec)
if (!spec->adc_nids && spec->input_mux) { if (!spec->adc_nids && spec->input_mux) {
alc_auto_fill_adc_caps(codec); alc_auto_fill_adc_caps(codec);
alc_rebuild_imux_for_auto_mic(codec);
alc_remove_invalid_adc_nids(codec); alc_remove_invalid_adc_nids(codec);
} }
set_capture_mixer(codec); set_capture_mixer(codec);
...@@ -9704,10 +9747,8 @@ static void alc883_mode2_setup(struct hda_codec *codec) ...@@ -9704,10 +9747,8 @@ static void alc883_mode2_setup(struct hda_codec *codec)
spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x14;
spec->autocfg.speaker_pins[1] = 0x15; spec->autocfg.speaker_pins[1] = 0x15;
spec->autocfg.speaker_pins[2] = 0x16; spec->autocfg.speaker_pins[2] = 0x16;
spec->ext_mic.pin = 0x18; spec->ext_mic_pin = 0x18;
spec->int_mic.pin = 0x19; spec->int_mic_pin = 0x19;
spec->ext_mic.mux_idx = 0;
spec->int_mic.mux_idx = 1;
spec->auto_mic = 1; spec->auto_mic = 1;
spec->automute = 1; spec->automute = 1;
spec->automute_mode = ALC_AUTOMUTE_AMP; spec->automute_mode = ALC_AUTOMUTE_AMP;
...@@ -10780,67 +10821,41 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { ...@@ -10780,67 +10821,41 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
/* /*
* BIOS auto configuration * BIOS auto configuration
*/ */
static void alc_auto_init_input_src(struct hda_codec *codec) static void alc_auto_init_adc(struct hda_codec *codec, int adc_idx)
{ {
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
int c;
if (spec->dual_adc_switch)
return;
for (c = 0; c < spec->num_adc_nids; c++) {
hda_nid_t nid; hda_nid_t nid;
unsigned int mux_idx;
const struct hda_input_mux *imux;
int conns, mute, idx, item;
unsigned int wid_type;
nid = spec->capsrc_nids ? nid = spec->adc_nids[adc_idx];
spec->capsrc_nids[c] : spec->adc_nids[c];
/* mute ADC */ /* mute ADC */
if (query_amp_caps(codec, spec->adc_nids[c], HDA_INPUT) & if (query_amp_caps(codec, nid, HDA_INPUT) & AC_AMPCAP_MUTE) {
AC_AMPCAP_MUTE) snd_hda_codec_write(codec, nid, 0,
snd_hda_codec_write(codec, spec->adc_nids[c], 0,
AC_VERB_SET_AMP_GAIN_MUTE, AC_VERB_SET_AMP_GAIN_MUTE,
AMP_IN_MUTE(0)); AMP_IN_MUTE(0));
else if (query_amp_caps(codec, nid, HDA_OUTPUT) & return;
AC_AMPCAP_MUTE) }
if (!spec->capsrc_nids)
return;
nid = spec->capsrc_nids[adc_idx];
if (query_amp_caps(codec, nid, HDA_OUTPUT) & AC_AMPCAP_MUTE)
snd_hda_codec_write(codec, nid, 0, snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE, AC_VERB_SET_AMP_GAIN_MUTE,
AMP_OUT_MUTE); AMP_OUT_MUTE);
}
conns = snd_hda_get_conn_list(codec, nid, NULL); static void alc_auto_init_input_src(struct hda_codec *codec)
if (conns <= 0) {
continue; struct alc_spec *spec = codec->spec;
mux_idx = c >= spec->num_mux_defs ? 0 : c; int c, nums;
imux = &spec->input_mux[mux_idx];
if (!imux->num_items && mux_idx > 0) for (c = 0; c < spec->num_adc_nids; c++)
imux = &spec->input_mux[0]; alc_auto_init_adc(codec, c);
wid_type = get_wcaps_type(get_wcaps(codec, nid)); if (spec->dyn_adc_switch)
for (idx = 0; idx < conns; idx++) { nums = 1;
/* if the current connection is the selected one, else
* unmute it as default - otherwise mute it nums = spec->num_adc_nids;
*/ for (c = 0; c < nums; c++)
mute = AMP_IN_MUTE(idx); alc_mux_select(codec, 0, spec->cur_mux[c], true);
for (item = 0; item < imux->num_items; item++) {
if (imux->items[item].index == idx) {
if (spec->cur_mux[c] == item)
mute = AMP_IN_UNMUTE(idx);
break;
}
}
/* initialize the mute status if mute-amp is present */
if (query_amp_caps(codec, nid, HDA_INPUT) & AC_AMPCAP_MUTE)
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE,
mute);
if (wid_type == AC_WID_AUD_SEL &&
mute != AMP_IN_MUTE(idx))
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_CONNECT_SEL,
idx);
}
}
} }
/* add mic boosts if needed */ /* add mic boosts if needed */
...@@ -10920,17 +10935,14 @@ static int alc882_parse_auto_config(struct hda_codec *codec) ...@@ -10920,17 +10935,14 @@ static int alc882_parse_auto_config(struct hda_codec *codec)
if (spec->kctls.list) if (spec->kctls.list)
add_mixer(spec, spec->kctls.list); add_mixer(spec, spec->kctls.list);
spec->num_mux_defs = 1; err = alc_auto_add_mic_boost(codec);
spec->input_mux = &spec->private_imux[0]; if (err < 0)
return err;
if (!spec->dual_adc_switch)
alc_remove_invalid_adc_nids(codec); alc_remove_invalid_adc_nids(codec);
alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
alc_auto_check_switches(codec);
err = alc_auto_add_mic_boost(codec);
if (err < 0)
return err;
return 1; /* config found */ return 1; /* config found */
} }
...@@ -11019,6 +11031,7 @@ static int patch_alc882(struct hda_codec *codec) ...@@ -11019,6 +11031,7 @@ static int patch_alc882(struct hda_codec *codec)
if (!spec->adc_nids && spec->input_mux) { if (!spec->adc_nids && spec->input_mux) {
alc_auto_fill_adc_caps(codec); alc_auto_fill_adc_caps(codec);
alc_rebuild_imux_for_auto_mic(codec);
alc_remove_invalid_adc_nids(codec); alc_remove_invalid_adc_nids(codec);
} }
...@@ -11515,10 +11528,8 @@ static void alc262_toshiba_s06_setup(struct hda_codec *codec) ...@@ -11515,10 +11528,8 @@ static void alc262_toshiba_s06_setup(struct hda_codec *codec)
spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.hp_pins[0] = 0x15;
spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x14;
spec->ext_mic.pin = 0x18; spec->ext_mic_pin = 0x18;
spec->ext_mic.mux_idx = 0; spec->int_mic_pin = 0x12;
spec->int_mic.pin = 0x12;
spec->int_mic.mux_idx = 9;
spec->auto_mic = 1; spec->auto_mic = 1;
spec->automute = 1; spec->automute = 1;
spec->automute_mode = ALC_AUTOMUTE_PIN; spec->automute_mode = ALC_AUTOMUTE_PIN;
...@@ -12243,17 +12254,14 @@ static int alc262_parse_auto_config(struct hda_codec *codec) ...@@ -12243,17 +12254,14 @@ static int alc262_parse_auto_config(struct hda_codec *codec)
if (spec->kctls.list) if (spec->kctls.list)
add_mixer(spec, spec->kctls.list); add_mixer(spec, spec->kctls.list);
spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux[0];
if (!spec->dual_adc_switch)
alc_remove_invalid_adc_nids(codec);
err = alc_auto_add_mic_boost(codec); err = alc_auto_add_mic_boost(codec);
if (err < 0) if (err < 0)
return err; return err;
alc_remove_invalid_adc_nids(codec);
alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
alc_auto_check_switches(codec);
return 1; return 1;
} }
...@@ -12661,6 +12669,7 @@ static int patch_alc262(struct hda_codec *codec) ...@@ -12661,6 +12669,7 @@ static int patch_alc262(struct hda_codec *codec)
if (!spec->adc_nids && spec->input_mux) { if (!spec->adc_nids && spec->input_mux) {
alc_auto_fill_adc_caps(codec); alc_auto_fill_adc_caps(codec);
alc_rebuild_imux_for_auto_mic(codec);
alc_remove_invalid_adc_nids(codec); alc_remove_invalid_adc_nids(codec);
} }
if (!spec->cap_mixer && !spec->no_analog) if (!spec->cap_mixer && !spec->no_analog)
...@@ -12863,10 +12872,8 @@ static void alc268_acer_lc_setup(struct hda_codec *codec) ...@@ -12863,10 +12872,8 @@ static void alc268_acer_lc_setup(struct hda_codec *codec)
spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x14;
spec->automute = 1; spec->automute = 1;
spec->automute_mode = ALC_AUTOMUTE_AMP; spec->automute_mode = ALC_AUTOMUTE_AMP;
spec->ext_mic.pin = 0x18; spec->ext_mic_pin = 0x18;
spec->ext_mic.mux_idx = 0; spec->int_mic_pin = 0x12;
spec->int_mic.pin = 0x12;
spec->int_mic.mux_idx = 6;
spec->auto_mic = 1; spec->auto_mic = 1;
} }
...@@ -12896,10 +12903,8 @@ static void alc268_dell_setup(struct hda_codec *codec) ...@@ -12896,10 +12903,8 @@ static void alc268_dell_setup(struct hda_codec *codec)
spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.hp_pins[0] = 0x15;
spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x14;
spec->ext_mic.pin = 0x18; spec->ext_mic_pin = 0x18;
spec->ext_mic.mux_idx = 0; spec->int_mic_pin = 0x19;
spec->int_mic.pin = 0x19;
spec->int_mic.mux_idx = 1;
spec->auto_mic = 1; spec->auto_mic = 1;
spec->automute = 1; spec->automute = 1;
spec->automute_mode = ALC_AUTOMUTE_PIN; spec->automute_mode = ALC_AUTOMUTE_PIN;
...@@ -12928,10 +12933,8 @@ static void alc267_quanta_il1_setup(struct hda_codec *codec) ...@@ -12928,10 +12933,8 @@ static void alc267_quanta_il1_setup(struct hda_codec *codec)
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.hp_pins[0] = 0x15;
spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x14;
spec->ext_mic.pin = 0x18; spec->ext_mic_pin = 0x18;
spec->ext_mic.mux_idx = 0; spec->int_mic_pin = 0x19;
spec->int_mic.pin = 0x19;
spec->int_mic.mux_idx = 1;
spec->auto_mic = 1; spec->auto_mic = 1;
spec->automute = 1; spec->automute = 1;
spec->automute_mode = ALC_AUTOMUTE_PIN; spec->automute_mode = ALC_AUTOMUTE_PIN;
...@@ -13358,17 +13361,14 @@ static int alc268_parse_auto_config(struct hda_codec *codec) ...@@ -13358,17 +13361,14 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
add_verb(spec, alc268_beep_init_verbs); add_verb(spec, alc268_beep_init_verbs);
} }
spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux[0];
if (!spec->dual_adc_switch)
alc_remove_invalid_adc_nids(codec);
err = alc_auto_add_mic_boost(codec); err = alc_auto_add_mic_boost(codec);
if (err < 0) if (err < 0)
return err; return err;
alc_remove_invalid_adc_nids(codec);
alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
alc_auto_check_switches(codec);
return 1; return 1;
} }
...@@ -13668,6 +13668,7 @@ static int patch_alc268(struct hda_codec *codec) ...@@ -13668,6 +13668,7 @@ static int patch_alc268(struct hda_codec *codec)
if (!spec->no_analog && !spec->adc_nids && spec->input_mux) { if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
alc_auto_fill_adc_caps(codec); alc_auto_fill_adc_caps(codec);
alc_rebuild_imux_for_auto_mic(codec);
alc_remove_invalid_adc_nids(codec); alc_remove_invalid_adc_nids(codec);
} }
...@@ -13924,10 +13925,8 @@ static void alc269_quanta_fl1_setup(struct hda_codec *codec) ...@@ -13924,10 +13925,8 @@ static void alc269_quanta_fl1_setup(struct hda_codec *codec)
spec->automute_mixer_nid[0] = 0x0c; spec->automute_mixer_nid[0] = 0x0c;
spec->automute = 1; spec->automute = 1;
spec->automute_mode = ALC_AUTOMUTE_MIXER; spec->automute_mode = ALC_AUTOMUTE_MIXER;
spec->ext_mic.pin = 0x18; spec->ext_mic_pin = 0x18;
spec->ext_mic.mux_idx = 0; spec->int_mic_pin = 0x19;
spec->int_mic.pin = 0x19;
spec->int_mic.mux_idx = 1;
spec->auto_mic = 1; spec->auto_mic = 1;
} }
...@@ -14019,10 +14018,8 @@ static void alc269_laptop_amic_setup(struct hda_codec *codec) ...@@ -14019,10 +14018,8 @@ static void alc269_laptop_amic_setup(struct hda_codec *codec)
spec->automute_mixer_nid[0] = 0x0c; spec->automute_mixer_nid[0] = 0x0c;
spec->automute = 1; spec->automute = 1;
spec->automute_mode = ALC_AUTOMUTE_MIXER; spec->automute_mode = ALC_AUTOMUTE_MIXER;
spec->ext_mic.pin = 0x18; spec->ext_mic_pin = 0x18;
spec->ext_mic.mux_idx = 0; spec->int_mic_pin = 0x19;
spec->int_mic.pin = 0x19;
spec->int_mic.mux_idx = 1;
spec->auto_mic = 1; spec->auto_mic = 1;
} }
...@@ -14034,10 +14031,8 @@ static void alc269_laptop_dmic_setup(struct hda_codec *codec) ...@@ -14034,10 +14031,8 @@ static void alc269_laptop_dmic_setup(struct hda_codec *codec)
spec->automute_mixer_nid[0] = 0x0c; spec->automute_mixer_nid[0] = 0x0c;
spec->automute = 1; spec->automute = 1;
spec->automute_mode = ALC_AUTOMUTE_MIXER; spec->automute_mode = ALC_AUTOMUTE_MIXER;
spec->ext_mic.pin = 0x18; spec->ext_mic_pin = 0x18;
spec->ext_mic.mux_idx = 0; spec->int_mic_pin = 0x12;
spec->int_mic.pin = 0x12;
spec->int_mic.mux_idx = 5;
spec->auto_mic = 1; spec->auto_mic = 1;
} }
...@@ -14049,10 +14044,8 @@ static void alc269vb_laptop_amic_setup(struct hda_codec *codec) ...@@ -14049,10 +14044,8 @@ static void alc269vb_laptop_amic_setup(struct hda_codec *codec)
spec->automute_mixer_nid[0] = 0x0c; spec->automute_mixer_nid[0] = 0x0c;
spec->automute = 1; spec->automute = 1;
spec->automute_mode = ALC_AUTOMUTE_MIXER; spec->automute_mode = ALC_AUTOMUTE_MIXER;
spec->ext_mic.pin = 0x18; spec->ext_mic_pin = 0x18;
spec->ext_mic.mux_idx = 0; spec->int_mic_pin = 0x19;
spec->int_mic.pin = 0x19;
spec->int_mic.mux_idx = 1;
spec->auto_mic = 1; spec->auto_mic = 1;
} }
...@@ -14064,10 +14057,8 @@ static void alc269vb_laptop_dmic_setup(struct hda_codec *codec) ...@@ -14064,10 +14057,8 @@ static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
spec->automute_mixer_nid[0] = 0x0c; spec->automute_mixer_nid[0] = 0x0c;
spec->automute = 1; spec->automute = 1;
spec->automute_mode = ALC_AUTOMUTE_MIXER; spec->automute_mode = ALC_AUTOMUTE_MIXER;
spec->ext_mic.pin = 0x18; spec->ext_mic_pin = 0x18;
spec->ext_mic.mux_idx = 0; spec->int_mic_pin = 0x12;
spec->int_mic.pin = 0x12;
spec->int_mic.mux_idx = 6;
spec->auto_mic = 1; spec->auto_mic = 1;
} }
...@@ -14217,36 +14208,6 @@ static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid) ...@@ -14217,36 +14208,6 @@ static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
} }
#endif /* CONFIG_SND_HDA_POWER_SAVE */ #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;
}
/* different alc269-variants */ /* different alc269-variants */
enum { enum {
ALC269_TYPE_ALC269VA, ALC269_TYPE_ALC269VA,
...@@ -14282,17 +14243,13 @@ static int alc269_parse_auto_config(struct hda_codec *codec) ...@@ -14282,17 +14243,13 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
if (spec->kctls.list) if (spec->kctls.list)
add_mixer(spec, spec->kctls.list); add_mixer(spec, spec->kctls.list);
alc_remove_invalid_adc_nids(codec);
if (spec->codec_variant != ALC269_TYPE_ALC269VA) if (spec->codec_variant != ALC269_TYPE_ALC269VA)
alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21); alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21);
else else
alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
alc_auto_check_switches(codec);
spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux[0];
alc275_setup_dual_adc(codec);
if (!spec->dual_adc_switch)
alc_remove_invalid_adc_nids(codec);
err = alc_auto_add_mic_boost(codec); err = alc_auto_add_mic_boost(codec);
if (err < 0) if (err < 0)
...@@ -14819,6 +14776,7 @@ static int patch_alc269(struct hda_codec *codec) ...@@ -14819,6 +14776,7 @@ static int patch_alc269(struct hda_codec *codec)
if (!spec->adc_nids) { /* wasn't filled automatically? use default */ if (!spec->adc_nids) { /* wasn't filled automatically? use default */
alc_auto_fill_adc_caps(codec); alc_auto_fill_adc_caps(codec);
alc_rebuild_imux_for_auto_mic(codec);
alc_remove_invalid_adc_nids(codec); alc_remove_invalid_adc_nids(codec);
} }
...@@ -15616,13 +15574,10 @@ static int alc861_parse_auto_config(struct hda_codec *codec) ...@@ -15616,13 +15574,10 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
if (spec->kctls.list) if (spec->kctls.list)
add_mixer(spec, spec->kctls.list); add_mixer(spec, spec->kctls.list);
spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux[0];
if (!spec->dual_adc_switch)
alc_remove_invalid_adc_nids(codec); alc_remove_invalid_adc_nids(codec);
alc_ssid_check(codec, 0x0e, 0x0f, 0x0b, 0); alc_ssid_check(codec, 0x0e, 0x0f, 0x0b, 0);
alc_auto_check_switches(codec);
set_capture_mixer(codec); set_capture_mixer(codec);
...@@ -15871,6 +15826,12 @@ static int patch_alc861(struct hda_codec *codec) ...@@ -15871,6 +15826,12 @@ static int patch_alc861(struct hda_codec *codec)
if (board_config != ALC861_AUTO) if (board_config != ALC861_AUTO)
setup_preset(codec, &alc861_presets[board_config]); setup_preset(codec, &alc861_presets[board_config]);
if (!spec->adc_nids) {
alc_auto_fill_adc_caps(codec);
alc_rebuild_imux_for_auto_mic(codec);
alc_remove_invalid_adc_nids(codec);
}
if (!spec->cap_mixer) if (!spec->cap_mixer)
set_capture_mixer(codec); set_capture_mixer(codec);
set_beep_amp(spec, 0x23, 0, HDA_OUTPUT); set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
...@@ -16664,18 +16625,15 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec) ...@@ -16664,18 +16625,15 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec)
if (spec->kctls.list) if (spec->kctls.list)
add_mixer(spec, spec->kctls.list); add_mixer(spec, spec->kctls.list);
spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux[0];
if (!spec->dual_adc_switch)
alc_remove_invalid_adc_nids(codec); alc_remove_invalid_adc_nids(codec);
alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
alc_auto_check_switches(codec);
err = alc_auto_add_mic_boost(codec); err = alc_auto_add_mic_boost(codec);
if (err < 0) if (err < 0)
return err; return err;
alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
return 1; return 1;
} }
...@@ -16772,6 +16730,7 @@ static int patch_alc861vd(struct hda_codec *codec) ...@@ -16772,6 +16730,7 @@ static int patch_alc861vd(struct hda_codec *codec)
if (!spec->adc_nids) { if (!spec->adc_nids) {
alc_auto_fill_adc_caps(codec); alc_auto_fill_adc_caps(codec);
alc_rebuild_imux_for_auto_mic(codec);
alc_remove_invalid_adc_nids(codec); alc_remove_invalid_adc_nids(codec);
} }
...@@ -17539,10 +17498,8 @@ static void alc662_eeepc_setup(struct hda_codec *codec) ...@@ -17539,10 +17498,8 @@ static void alc662_eeepc_setup(struct hda_codec *codec)
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
alc262_hippo1_setup(codec); alc262_hippo1_setup(codec);
spec->ext_mic.pin = 0x18; spec->ext_mic_pin = 0x18;
spec->ext_mic.mux_idx = 0; spec->int_mic_pin = 0x19;
spec->int_mic.pin = 0x19;
spec->int_mic.mux_idx = 1;
spec->auto_mic = 1; spec->auto_mic = 1;
} }
...@@ -17564,10 +17521,8 @@ static void alc663_m51va_setup(struct hda_codec *codec) ...@@ -17564,10 +17521,8 @@ static void alc663_m51va_setup(struct hda_codec *codec)
spec->automute_mixer_nid[0] = 0x0c; spec->automute_mixer_nid[0] = 0x0c;
spec->automute = 1; spec->automute = 1;
spec->automute_mode = ALC_AUTOMUTE_MIXER; spec->automute_mode = ALC_AUTOMUTE_MIXER;
spec->ext_mic.pin = 0x18; spec->ext_mic_pin = 0x18;
spec->ext_mic.mux_idx = 0; spec->int_mic_pin = 0x12;
spec->int_mic.pin = 0x12;
spec->int_mic.mux_idx = 9;
spec->auto_mic = 1; spec->auto_mic = 1;
} }
...@@ -17580,10 +17535,8 @@ static void alc663_mode1_setup(struct hda_codec *codec) ...@@ -17580,10 +17535,8 @@ static void alc663_mode1_setup(struct hda_codec *codec)
spec->automute_mixer_nid[0] = 0x0c; spec->automute_mixer_nid[0] = 0x0c;
spec->automute = 1; spec->automute = 1;
spec->automute_mode = ALC_AUTOMUTE_MIXER; spec->automute_mode = ALC_AUTOMUTE_MIXER;
spec->ext_mic.pin = 0x18; spec->ext_mic_pin = 0x18;
spec->ext_mic.mux_idx = 0; spec->int_mic_pin = 0x19;
spec->int_mic.pin = 0x19;
spec->int_mic.mux_idx = 1;
spec->auto_mic = 1; spec->auto_mic = 1;
} }
...@@ -17595,10 +17548,8 @@ static void alc662_mode2_setup(struct hda_codec *codec) ...@@ -17595,10 +17548,8 @@ static void alc662_mode2_setup(struct hda_codec *codec)
spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x14;
spec->automute = 1; spec->automute = 1;
spec->automute_mode = ALC_AUTOMUTE_PIN; spec->automute_mode = ALC_AUTOMUTE_PIN;
spec->ext_mic.pin = 0x18; spec->ext_mic_pin = 0x18;
spec->ext_mic.mux_idx = 0; spec->int_mic_pin = 0x19;
spec->int_mic.pin = 0x19;
spec->int_mic.mux_idx = 1;
spec->auto_mic = 1; spec->auto_mic = 1;
} }
...@@ -17611,10 +17562,8 @@ static void alc663_mode3_setup(struct hda_codec *codec) ...@@ -17611,10 +17562,8 @@ static void alc663_mode3_setup(struct hda_codec *codec)
spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x14;
spec->automute = 1; spec->automute = 1;
spec->automute_mode = ALC_AUTOMUTE_PIN; spec->automute_mode = ALC_AUTOMUTE_PIN;
spec->ext_mic.pin = 0x18; spec->ext_mic_pin = 0x18;
spec->ext_mic.mux_idx = 0; spec->int_mic_pin = 0x19;
spec->int_mic.pin = 0x19;
spec->int_mic.mux_idx = 1;
spec->auto_mic = 1; spec->auto_mic = 1;
} }
...@@ -17629,10 +17578,8 @@ static void alc663_mode4_setup(struct hda_codec *codec) ...@@ -17629,10 +17578,8 @@ static void alc663_mode4_setup(struct hda_codec *codec)
spec->automute_mixer_nid[1] = 0x0e; spec->automute_mixer_nid[1] = 0x0e;
spec->automute = 1; spec->automute = 1;
spec->automute_mode = ALC_AUTOMUTE_MIXER; spec->automute_mode = ALC_AUTOMUTE_MIXER;
spec->ext_mic.pin = 0x18; spec->ext_mic_pin = 0x18;
spec->ext_mic.mux_idx = 0; spec->int_mic_pin = 0x19;
spec->int_mic.pin = 0x19;
spec->int_mic.mux_idx = 1;
spec->auto_mic = 1; spec->auto_mic = 1;
} }
...@@ -17647,10 +17594,8 @@ static void alc663_mode5_setup(struct hda_codec *codec) ...@@ -17647,10 +17594,8 @@ static void alc663_mode5_setup(struct hda_codec *codec)
spec->automute_mixer_nid[1] = 0x0e; spec->automute_mixer_nid[1] = 0x0e;
spec->automute = 1; spec->automute = 1;
spec->automute_mode = ALC_AUTOMUTE_MIXER; spec->automute_mode = ALC_AUTOMUTE_MIXER;
spec->ext_mic.pin = 0x18; spec->ext_mic_pin = 0x18;
spec->ext_mic.mux_idx = 0; spec->int_mic_pin = 0x19;
spec->int_mic.pin = 0x19;
spec->int_mic.mux_idx = 1;
spec->auto_mic = 1; spec->auto_mic = 1;
} }
...@@ -17664,10 +17609,8 @@ static void alc663_mode6_setup(struct hda_codec *codec) ...@@ -17664,10 +17609,8 @@ static void alc663_mode6_setup(struct hda_codec *codec)
spec->automute_mixer_nid[0] = 0x0c; spec->automute_mixer_nid[0] = 0x0c;
spec->automute = 1; spec->automute = 1;
spec->automute_mode = ALC_AUTOMUTE_MIXER; spec->automute_mode = ALC_AUTOMUTE_MIXER;
spec->ext_mic.pin = 0x18; spec->ext_mic_pin = 0x18;
spec->ext_mic.mux_idx = 0; spec->int_mic_pin = 0x19;
spec->int_mic.pin = 0x19;
spec->int_mic.mux_idx = 1;
spec->auto_mic = 1; spec->auto_mic = 1;
} }
...@@ -17681,10 +17624,8 @@ static void alc663_mode7_setup(struct hda_codec *codec) ...@@ -17681,10 +17624,8 @@ static void alc663_mode7_setup(struct hda_codec *codec)
spec->autocfg.speaker_pins[0] = 0x17; spec->autocfg.speaker_pins[0] = 0x17;
spec->automute = 1; spec->automute = 1;
spec->automute_mode = ALC_AUTOMUTE_PIN; spec->automute_mode = ALC_AUTOMUTE_PIN;
spec->ext_mic.pin = 0x18; spec->ext_mic_pin = 0x18;
spec->ext_mic.mux_idx = 0; spec->int_mic_pin = 0x19;
spec->int_mic.pin = 0x19;
spec->int_mic.mux_idx = 1;
spec->auto_mic = 1; spec->auto_mic = 1;
} }
...@@ -17698,10 +17639,8 @@ static void alc663_mode8_setup(struct hda_codec *codec) ...@@ -17698,10 +17639,8 @@ static void alc663_mode8_setup(struct hda_codec *codec)
spec->autocfg.speaker_pins[0] = 0x17; spec->autocfg.speaker_pins[0] = 0x17;
spec->automute = 1; spec->automute = 1;
spec->automute_mode = ALC_AUTOMUTE_PIN; spec->automute_mode = ALC_AUTOMUTE_PIN;
spec->ext_mic.pin = 0x18; spec->ext_mic_pin = 0x18;
spec->ext_mic.mux_idx = 0; spec->int_mic_pin = 0x12;
spec->int_mic.pin = 0x12;
spec->int_mic.mux_idx = 9;
spec->auto_mic = 1; spec->auto_mic = 1;
} }
...@@ -17715,10 +17654,8 @@ static void alc663_g71v_setup(struct hda_codec *codec) ...@@ -17715,10 +17654,8 @@ static void alc663_g71v_setup(struct hda_codec *codec)
spec->automute_mode = ALC_AUTOMUTE_AMP; spec->automute_mode = ALC_AUTOMUTE_AMP;
spec->detect_line = 1; spec->detect_line = 1;
spec->automute_lines = 1; spec->automute_lines = 1;
spec->ext_mic.pin = 0x18; spec->ext_mic_pin = 0x18;
spec->ext_mic.mux_idx = 0; spec->int_mic_pin = 0x12;
spec->int_mic.pin = 0x12;
spec->int_mic.mux_idx = 9;
spec->auto_mic = 1; spec->auto_mic = 1;
} }
...@@ -18779,21 +18716,18 @@ static int alc662_parse_auto_config(struct hda_codec *codec) ...@@ -18779,21 +18716,18 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
if (spec->kctls.list) if (spec->kctls.list)
add_mixer(spec, spec->kctls.list); add_mixer(spec, spec->kctls.list);
spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux[0];
if (!spec->dual_adc_switch)
alc_remove_invalid_adc_nids(codec); alc_remove_invalid_adc_nids(codec);
err = alc_auto_add_mic_boost(codec);
if (err < 0)
return err;
if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 || if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670) codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0x21); alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0x21);
else else
alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0); alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
alc_auto_check_switches(codec);
err = alc_auto_add_mic_boost(codec);
if (err < 0)
return err;
return 1; return 1;
} }
...@@ -18949,6 +18883,7 @@ static int patch_alc662(struct hda_codec *codec) ...@@ -18949,6 +18883,7 @@ static int patch_alc662(struct hda_codec *codec)
if (!spec->adc_nids) { if (!spec->adc_nids) {
alc_auto_fill_adc_caps(codec); alc_auto_fill_adc_caps(codec);
alc_rebuild_imux_for_auto_mic(codec);
alc_remove_invalid_adc_nids(codec); alc_remove_invalid_adc_nids(codec);
} }
...@@ -19036,36 +18971,32 @@ static const hda_nid_t alc680_adc_nids[3] = { ...@@ -19036,36 +18971,32 @@ static const hda_nid_t alc680_adc_nids[3] = {
/* /*
* Analog capture ADC cgange * Analog capture ADC cgange
*/ */
static void alc680_rec_autoswitch(struct hda_codec *codec) static hda_nid_t alc680_get_cur_adc(struct hda_codec *codec)
{ {
struct alc_spec *spec = codec->spec; static hda_nid_t pins[] = {0x18, 0x19};
struct auto_pin_cfg *cfg = &spec->autocfg; static hda_nid_t adcs[] = {0x08, 0x09};
int pin_found = 0;
int type_found = AUTO_PIN_LAST;
hda_nid_t nid;
int i; int i;
for (i = 0; i < cfg->num_inputs; i++) { for (i = 0; i < ARRAY_SIZE(pins); i++) {
nid = cfg->inputs[i].pin; if (!is_jack_detectable(codec, pins[i]))
if (!is_jack_detectable(codec, nid))
continue; continue;
if (snd_hda_jack_detect(codec, nid)) { if (snd_hda_jack_detect(codec, pins[i]))
if (cfg->inputs[i].type < type_found) { return adcs[i];
type_found = cfg->inputs[i].type;
pin_found = nid;
}
}
} }
return 0x07;
}
nid = 0x07; static void alc680_rec_autoswitch(struct hda_codec *codec)
if (pin_found) {
snd_hda_get_connections(codec, pin_found, &nid, 1); struct alc_spec *spec = codec->spec;
hda_nid_t nid = alc680_get_cur_adc(codec);
if (nid != spec->cur_adc) if (spec->cur_adc && nid != spec->cur_adc) {
__snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
spec->cur_adc = nid; spec->cur_adc = nid;
snd_hda_codec_setup_stream(codec, nid, spec->cur_adc_stream_tag, 0, snd_hda_codec_setup_stream(codec, nid,
spec->cur_adc_stream_tag, 0,
spec->cur_adc_format); spec->cur_adc_format);
}
} }
static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo, static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
...@@ -19075,12 +19006,12 @@ static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo, ...@@ -19075,12 +19006,12 @@ static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
struct snd_pcm_substream *substream) struct snd_pcm_substream *substream)
{ {
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
hda_nid_t nid = alc680_get_cur_adc(codec);
spec->cur_adc = 0x07; spec->cur_adc = nid;
spec->cur_adc_stream_tag = stream_tag; spec->cur_adc_stream_tag = stream_tag;
spec->cur_adc_format = format; spec->cur_adc_format = format;
snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
alc680_rec_autoswitch(codec);
return 0; return 0;
} }
...@@ -19088,9 +19019,9 @@ static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, ...@@ -19088,9 +19019,9 @@ static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
struct hda_codec *codec, struct hda_codec *codec,
struct snd_pcm_substream *substream) struct snd_pcm_substream *substream)
{ {
snd_hda_codec_cleanup_stream(codec, 0x07); struct alc_spec *spec = codec->spec;
snd_hda_codec_cleanup_stream(codec, 0x08); snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
snd_hda_codec_cleanup_stream(codec, 0x09); spec->cur_adc = 0;
return 0; return 0;
} }
...@@ -19332,6 +19263,10 @@ static int alc680_parse_auto_config(struct hda_codec *codec) ...@@ -19332,6 +19263,10 @@ static int alc680_parse_auto_config(struct hda_codec *codec)
if (err < 0) if (err < 0)
return err; return err;
err = alc_auto_create_input_ctls(codec);
if (err < 0)
return err;
spec->multiout.max_channels = 2; spec->multiout.max_channels = 2;
dig_only: dig_only:
...@@ -19340,6 +19275,10 @@ static int alc680_parse_auto_config(struct hda_codec *codec) ...@@ -19340,6 +19275,10 @@ static int alc680_parse_auto_config(struct hda_codec *codec)
if (spec->kctls.list) if (spec->kctls.list)
add_mixer(spec, spec->kctls.list); add_mixer(spec, spec->kctls.list);
alc_remove_invalid_adc_nids(codec);
alc_auto_check_switches(codec);
err = alc_auto_add_mic_boost(codec); err = alc_auto_add_mic_boost(codec);
if (err < 0) if (err < 0)
return err; return err;
...@@ -19354,6 +19293,7 @@ static void alc680_auto_init(struct hda_codec *codec) ...@@ -19354,6 +19293,7 @@ static void alc680_auto_init(struct hda_codec *codec)
alc680_auto_init_multi_out(codec); alc680_auto_init_multi_out(codec);
alc680_auto_init_hp_out(codec); alc680_auto_init_hp_out(codec);
alc_auto_init_analog_input(codec); alc_auto_init_analog_input(codec);
alc_auto_init_input_src(codec);
alc_auto_init_digital(codec); alc_auto_init_digital(codec);
if (spec->unsol_event) if (spec->unsol_event)
alc_inithook(codec); alc_inithook(codec);
...@@ -19427,11 +19367,14 @@ static int patch_alc680(struct hda_codec *codec) ...@@ -19427,11 +19367,14 @@ static int patch_alc680(struct hda_codec *codec)
} }
} }
if (board_config != ALC680_AUTO) if (board_config != ALC680_AUTO) {
setup_preset(codec, &alc680_presets[board_config]); setup_preset(codec, &alc680_presets[board_config]);
spec->stream_analog_capture = &alc680_pcm_analog_auto_capture;
}
if (!spec->adc_nids) { if (!spec->adc_nids) {
alc_auto_fill_adc_caps(codec); alc_auto_fill_adc_caps(codec);
alc_rebuild_imux_for_auto_mic(codec);
alc_remove_invalid_adc_nids(codec); alc_remove_invalid_adc_nids(codec);
} }
......
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