@@ -2097,14 +2097,21 @@ static int create_extra_out(struct hda_codec *codec, int path_idx,
{
struct nid_path *path;
int err;
+ struct hda_gen_spec *spec = codec->spec;
path = snd_hda_get_path_from_idx(codec, path_idx);
if (!path)
return 0;
- err = add_stereo_vol(codec, pfx, cidx, path);
+ if ((strcmp(pfx, "Headphone") == 0) && spec->hs_mic_use_hp_sense)
+ err = add_stereo_vol(codec, "Headset", cidx, path);
+ else
+ err = add_stereo_vol(codec, pfx, cidx, path);
if (err < 0)
return err;
- err = add_stereo_sw(codec, pfx, cidx, path);
+ if ((strcmp(pfx, "Headphone") == 0) && spec->hs_mic_use_hp_sense)
+ err = add_stereo_sw(codec, "Headset", cidx, path);
+ else
+ err = add_stereo_sw(codec, pfx, cidx, path);
if (err < 0)
return err;
return 0;
@@ -4665,7 +4672,9 @@ static int check_auto_mic_availability(struct hda_codec *codec)
if (!spec->line_in_auto_switch &&
cfg->inputs[i].type != AUTO_PIN_MIC)
return 0; /* only mic is allowed */
- if (!is_jack_detectable(codec, nid))
+ if (!is_jack_detectable(codec, nid) &&
+ !(spec->hs_mic_use_hp_sense &&
+ cfg->inputs[i].is_headset_mic))
return 0; /* no unsol support */
break;
}
@@ -236,6 +236,7 @@ struct hda_gen_spec {
unsigned int indep_hp_enabled:1; /* independent HP enabled */
unsigned int have_aamix_ctl:1;
unsigned int hp_mic_jack_modes:1;
+ unsigned int hs_mic_use_hp_sense:1;
/* additional mute flags (only effective with auto_mute_via_amp=1) */
u64 mute_bits;
@@ -19,6 +19,7 @@
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"
+#include "hda_generic.h"
/**
* is_jack_detectable - Check whether the given pin is jack-detectable
@@ -157,7 +158,15 @@ static void jack_detect_update(struct hda_codec *codec,
if (jack->phantom_jack)
jack->pin_sense = AC_PINSENSE_PRESENCE;
else
- jack->pin_sense = read_pin_sense(codec, jack->nid);
+ jack->pin_sense = read_pin_sense(codec,
+ jack->sense_nid ? jack->sense_nid : jack->nid);
+
+ if (jack->slave_nid) {
+ struct hda_jack_tbl *slave =
+ snd_hda_jack_tbl_get(codec, jack->slave_nid);
+ if (slave)
+ slave->pin_sense = jack->pin_sense;
+ }
/* A gating jack indicates the jack is invalid if gating is unplugged */
if (jack->gating_jack && !snd_hda_jack_detect(codec, jack->gating_jack))
@@ -209,6 +218,8 @@ u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid)
jack_detect_update(codec, jack);
return jack->pin_sense;
}
+ if (jack->sense_nid)
+ return read_pin_sense(codec, jack->sense_nid);
return read_pin_sense(codec, nid);
}
EXPORT_SYMBOL_GPL(snd_hda_pin_sense);
@@ -384,7 +395,7 @@ static void hda_free_jack_priv(struct snd_jack *jack)
* will have the given name and index.
*/
static int __snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
- const char *name, bool phantom_jack)
+ const char *name, bool phantom_jack, hda_nid_t sense_nid)
{
struct hda_jack_tbl *jack;
int err, state, type;
@@ -405,6 +416,7 @@ static int __snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
jack->type = type;
jack->jack->private_data = jack;
jack->jack->private_free = hda_free_jack_priv;
+ jack->sense_nid = sense_nid;
state = snd_hda_jack_detect(codec, nid);
snd_jack_report(jack->jack, state ? jack->type : 0);
@@ -422,7 +434,7 @@ static int __snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
const char *name)
{
- return __snd_hda_jack_add_kctl(codec, nid, name, false);
+ return __snd_hda_jack_add_kctl(codec, nid, name, false, nid);
}
EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctl);
@@ -451,7 +463,7 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid,
if (phantom_jack)
/* Example final name: "Internal Mic Phantom Jack" */
strncat(name, " Phantom", sizeof(name) - strlen(name) - 1);
- err = __snd_hda_jack_add_kctl(codec, nid, name, phantom_jack);
+ err = __snd_hda_jack_add_kctl(codec, nid, name, phantom_jack, nid);
if (err < 0)
return err;
@@ -469,6 +481,9 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
{
const hda_nid_t *p;
+ struct hda_jack_tbl *jack;
+ hda_nid_t headset_mic_nid = 0;
+ struct hda_gen_spec *spec = codec->spec;
int i, err;
for (i = 0; i < cfg->num_inputs; i++) {
@@ -482,6 +497,13 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec,
err = add_jack_kctl(codec, cfg->inputs[i].pin,
cfg, "Headphone Mic");
} else
+ if (cfg->inputs[i].is_headset_mic &&
+ spec->hs_mic_use_hp_sense &&
+ !is_jack_detectable(codec, cfg->inputs[i].pin)) {
+ headset_mic_nid = cfg->inputs[i].pin;
+ err = __snd_hda_jack_add_kctl(codec, cfg->inputs[i].pin,
+ "Headset Mic", false, auto_cfg_hp_pins(cfg)[0]);
+ } else
err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg,
NULL);
if (err < 0)
@@ -489,7 +511,10 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec,
}
for (i = 0, p = cfg->line_out_pins; i < cfg->line_outs; i++, p++) {
- err = add_jack_kctl(codec, *p, cfg, NULL);
+ if ((cfg->line_outs == 2) && (i == 1))
+ err = add_jack_kctl(codec, *p, cfg, "External Subwoofer");
+ else
+ err = add_jack_kctl(codec, *p, cfg, NULL);
if (err < 0)
return err;
}
@@ -499,6 +524,11 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec,
err = add_jack_kctl(codec, *p, cfg, NULL);
if (err < 0)
return err;
+ if ((i == 0) && spec->hs_mic_use_hp_sense) {
+ jack = snd_hda_jack_tbl_get(codec, *p);
+ if (jack)
+ jack->slave_nid = headset_mic_nid;
+ }
}
for (i = 0, p = cfg->speaker_pins; i < cfg->speaker_outs; i++, p++) {
if (*p == *cfg->line_out_pins) /* might be duplicated */
@@ -41,6 +41,8 @@ struct hda_jack_tbl {
hda_nid_t gated_jack; /* gated is dependent on this jack */
int type;
struct snd_jack *jack;
+ hda_nid_t sense_nid;
+ hda_nid_t slave_nid;
};
struct hda_jack_tbl *
@@ -104,6 +104,7 @@ struct alc_spec {
hda_nid_t headphone_mic_pin;
int current_headset_mode;
int current_headset_type;
+ int alc668_combo_type;
/* hooks */
void (*init_hook)(struct hda_codec *codec);
@@ -3984,6 +3985,15 @@ static void alc_update_headset_mode(struct hda_codec *codec)
int new_headset_mode;
+ if (codec->core.vendor_id == 0x10ec0668 &&
+ spec->alc668_combo_type) {
+ if (spec->alc668_combo_type == ALC_HEADSET_MODE_HEADSET &&
+ spec->gen.auto_mic) {
+ snd_hda_gen_mic_autoswitch(codec, NULL);
+ mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]];
+ }
+ }
+
if (!snd_hda_jack_detect(codec, hp_pin))
new_headset_mode = ALC_HEADSET_MODE_UNPLUGGED;
else if (mux_pin == spec->headset_mic_pin)
@@ -6232,6 +6242,37 @@ static void alc_fixup_bass_chmap(struct hda_codec *codec,
}
}
+static void alc668_fixup_asus_headset(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ const struct hda_pintbl pincfgs[] = {
+ { 0x1a, 0x04110011 }, /* external subwoofer */
+ { 0x1b, 0x03a1113c }, /* headset mic */
+ { }
+ };
+
+ struct alc_spec *spec = codec->spec;
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ snd_hda_apply_pincfgs(codec, pincfgs);
+ spec->gen.hs_mic_use_hp_sense = 1;
+ spec->alc668_combo_type = ALC_HEADSET_MODE_HEADSET;
+ spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+ break;
+ case HDA_FIXUP_ACT_PROBE:
+ alc_probe_headset_mode(codec);
+ break;
+ case HDA_FIXUP_ACT_INIT:
+ spec->current_headset_mode = 0;
+ alc_update_headset_mode(codec);
+ break;
+ case HDA_FIXUP_ACT_BUILD:
+ alc_fixup_bass_chmap(codec, fix, action);
+ break;
+ }
+}
+
/* avoid D3 for keeping GPIO up */
static unsigned int gpio_led_power_filter(struct hda_codec *codec,
hda_nid_t nid,
@@ -6313,6 +6354,7 @@ enum {
ALC662_FIXUP_INV_DMIC,
ALC662_FIXUP_DELL_MIC_NO_PRESENCE,
ALC668_FIXUP_DELL_MIC_NO_PRESENCE,
+ ALC668_FIXUP_ASUS_HEADSET,
ALC662_FIXUP_HEADSET_MODE,
ALC668_FIXUP_HEADSET_MODE,
ALC662_FIXUP_BASS_MODE4_CHMAP,
@@ -6530,6 +6572,10 @@ static const struct hda_fixup alc662_fixups[] = {
.chained = true,
.chain_id = ALC668_FIXUP_HEADSET_MODE
},
+ [ALC668_FIXUP_ASUS_HEADSET] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc668_fixup_asus_headset,
+ },
[ALC668_FIXUP_HEADSET_MODE] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_headset_mode_alc668,
@@ -6667,6 +6713,7 @@ static const struct hda_model_fixup alc662_fixup_models[] = {
{.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"},
{.id = ALC662_FIXUP_INV_DMIC, .name = "inv-dmic"},
{.id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE, .name = "dell-headset-multi"},
+ {.id = ALC668_FIXUP_ASUS_HEADSET, .name = "asus-headset"},
{}
};