Commit 8ed99d97 authored by Takashi Iwai's avatar Takashi Iwai

ALSA: hda - Add dock-mic detection support to Realtek auto-parser

In addition to the normal mic jack, the mic (or line-in) jack on the
docking-station is checked also as a candidate for auto-selection.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent e35d9d6a
...@@ -360,6 +360,7 @@ struct alc_spec { ...@@ -360,6 +360,7 @@ struct alc_spec {
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; struct alc_mic_route ext_mic;
struct alc_mic_route dock_mic;
struct alc_mic_route int_mic; struct alc_mic_route int_mic;
/* channel model */ /* channel model */
...@@ -1057,6 +1058,7 @@ static int alc_init_jacks(struct hda_codec *codec) ...@@ -1057,6 +1058,7 @@ static int alc_init_jacks(struct hda_codec *codec)
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;
if (hp_nid) { if (hp_nid) {
err = snd_hda_input_jack_add(codec, hp_nid, err = snd_hda_input_jack_add(codec, hp_nid,
...@@ -1073,6 +1075,13 @@ static int alc_init_jacks(struct hda_codec *codec) ...@@ -1073,6 +1075,13 @@ static int alc_init_jacks(struct hda_codec *codec)
return err; return err;
snd_hda_input_jack_report(codec, mic_nid); snd_hda_input_jack_report(codec, mic_nid);
} }
if (dock_nid) {
err = snd_hda_input_jack_add(codec, dock_nid,
SND_JACK_MICROPHONE, NULL);
if (err < 0)
return err;
snd_hda_input_jack_report(codec, dock_nid);
}
#endif /* CONFIG_SND_HDA_INPUT_JACK */ #endif /* CONFIG_SND_HDA_INPUT_JACK */
return 0; return 0;
} }
...@@ -1217,7 +1226,7 @@ static void alc_dual_mic_adc_auto_switch(struct hda_codec *codec) ...@@ -1217,7 +1226,7 @@ static void alc_dual_mic_adc_auto_switch(struct hda_codec *codec)
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 *dead, *alive; struct alc_mic_route *dead1, *dead2, *alive;
unsigned int present, type; unsigned int present, type;
hda_nid_t cap_nid; hda_nid_t cap_nid;
...@@ -1235,13 +1244,24 @@ static void alc_mic_automute(struct hda_codec *codec) ...@@ -1235,13 +1244,24 @@ static void alc_mic_automute(struct hda_codec *codec)
cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0]; 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); present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
if (present) { if (present) {
alive = &spec->ext_mic; alive = &spec->ext_mic;
dead = &spec->int_mic; dead1 = &spec->int_mic;
} else { dead2 = &spec->dock_mic;
alive = &spec->int_mic; }
dead = &spec->ext_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)); type = get_wcaps_type(get_wcaps(codec, cap_nid));
...@@ -1250,9 +1270,14 @@ static void alc_mic_automute(struct hda_codec *codec) ...@@ -1250,9 +1270,14 @@ static void alc_mic_automute(struct hda_codec *codec)
snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT, snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
alive->mux_idx, alive->mux_idx,
HDA_AMP_MUTE, 0); HDA_AMP_MUTE, 0);
snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT, if (dead1->pin > 0)
dead->mux_idx, snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
HDA_AMP_MUTE, HDA_AMP_MUTE); 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 { } else {
/* MUX style (e.g. ALC880) */ /* MUX style (e.g. ALC880) */
snd_hda_codec_write_cache(codec, cap_nid, 0, snd_hda_codec_write_cache(codec, cap_nid, 0,
...@@ -1598,15 +1623,10 @@ static void alc_init_auto_mic(struct hda_codec *codec) ...@@ -1598,15 +1623,10 @@ static void alc_init_auto_mic(struct hda_codec *codec)
{ {
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg; struct auto_pin_cfg *cfg = &spec->autocfg;
hda_nid_t fixed, ext; hda_nid_t fixed, ext, dock;
int i; int i;
/* there must be only two mic inputs exclusively */ fixed = ext = dock = 0;
for (i = 0; i < cfg->num_inputs; i++)
if (cfg->inputs[i].type >= AUTO_PIN_LINE_IN)
return;
fixed = ext = 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;
unsigned int defcfg; unsigned int defcfg;
...@@ -1615,26 +1635,45 @@ static void alc_init_auto_mic(struct hda_codec *codec) ...@@ -1615,26 +1635,45 @@ static void alc_init_auto_mic(struct hda_codec *codec)
case INPUT_PIN_ATTR_INT: case INPUT_PIN_ATTR_INT:
if (fixed) if (fixed)
return; /* already occupied */ return; /* already occupied */
if (cfg->inputs[i].type != AUTO_PIN_MIC)
return; /* invalid type */
fixed = nid; fixed = nid;
break; break;
case INPUT_PIN_ATTR_UNUSED: case INPUT_PIN_ATTR_UNUSED:
return; /* invalid entry */ return; /* invalid entry */
case INPUT_PIN_ATTR_DOCK:
if (dock)
return; /* already occupied */
if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
return; /* invalid type */
dock = nid;
break;
default: default:
if (ext) if (ext)
return; /* already occupied */ return; /* already occupied */
if (cfg->inputs[i].type != AUTO_PIN_MIC)
return; /* invalid type */
ext = nid; ext = nid;
break; break;
} }
} }
if (!ext && dock) {
ext = dock;
dock = 0;
}
if (!ext || !fixed) if (!ext || !fixed)
return; return;
if (!is_jack_detectable(codec, ext)) if (!is_jack_detectable(codec, ext))
return; /* no unsol support */ return; /* no unsol support */
snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x\n", if (dock && !is_jack_detectable(codec, dock))
ext, fixed); return; /* no unsol support */
snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n",
ext, fixed, dock);
spec->ext_mic.pin = ext; spec->ext_mic.pin = ext;
spec->dock_mic.pin = dock;
spec->int_mic.pin = fixed; spec->int_mic.pin = fixed;
spec->ext_mic.mux_idx = MUX_IDX_UNDEF; /* set later */ 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->int_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
spec->auto_mic = 1; spec->auto_mic = 1;
snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0, snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0,
...@@ -5716,6 +5755,12 @@ static void fixup_automic_adc(struct hda_codec *codec) ...@@ -5716,6 +5755,12 @@ static void fixup_automic_adc(struct hda_codec *codec)
spec->capsrc_nids += i; spec->capsrc_nids += i;
spec->adc_nids += i; spec->adc_nids += i;
spec->num_adc_nids = 1; 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; return;
} }
snd_printd(KERN_INFO "hda_codec: %s: " snd_printd(KERN_INFO "hda_codec: %s: "
...@@ -5743,6 +5788,8 @@ static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin) ...@@ -5743,6 +5788,8 @@ static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
int i; int i;
if (!pin)
return 0;
for (i = 0; i < spec->num_adc_nids; i++) { for (i = 0; i < spec->num_adc_nids; i++) {
hda_nid_t cap = spec->capsrc_nids ? hda_nid_t cap = spec->capsrc_nids ?
spec->capsrc_nids[i] : spec->adc_nids[i]; spec->capsrc_nids[i] : spec->adc_nids[i];
...@@ -5783,6 +5830,7 @@ static void fixup_dual_adc_switch(struct hda_codec *codec) ...@@ -5783,6 +5830,7 @@ static void fixup_dual_adc_switch(struct hda_codec *codec)
{ {
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
init_capsrc_for_pin(codec, spec->ext_mic.pin); 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); init_capsrc_for_pin(codec, spec->int_mic.pin);
} }
......
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