|
@@ -170,10 +170,10 @@ struct alc_spec {
|
|
|
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 */
|
|
|
+ hda_nid_t inv_dmic_pin;
|
|
|
|
|
|
/* hooks */
|
|
|
void (*init_hook)(struct hda_codec *codec);
|
|
|
- void (*unsol_event)(struct hda_codec *codec, unsigned int res);
|
|
|
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
|
|
void (*power_hook)(struct hda_codec *codec);
|
|
|
#endif
|
|
@@ -201,6 +201,8 @@ struct alc_spec {
|
|
|
unsigned int vol_in_capsrc:1; /* use capsrc volume (ADC has no vol) */
|
|
|
unsigned int parse_flags; /* passed to snd_hda_parse_pin_defcfg() */
|
|
|
unsigned int shared_mic_hp:1; /* HP/Mic-in sharing */
|
|
|
+ unsigned int inv_dmic_fixup:1; /* has inverted digital-mic workaround */
|
|
|
+ unsigned int inv_dmic_muted:1; /* R-ch of inv d-mic is muted? */
|
|
|
|
|
|
/* auto-mute control */
|
|
|
int automute_mode;
|
|
@@ -298,6 +300,39 @@ static inline hda_nid_t get_capsrc(struct alc_spec *spec, int idx)
|
|
|
}
|
|
|
|
|
|
static void call_update_outputs(struct hda_codec *codec);
|
|
|
+static void alc_inv_dmic_sync(struct hda_codec *codec, bool force);
|
|
|
+
|
|
|
+/* for shared I/O, change the pin-control accordingly */
|
|
|
+static void update_shared_mic_hp(struct hda_codec *codec, bool set_as_mic)
|
|
|
+{
|
|
|
+ struct alc_spec *spec = codec->spec;
|
|
|
+ unsigned int val;
|
|
|
+ hda_nid_t pin = spec->autocfg.inputs[1].pin;
|
|
|
+ /* NOTE: this assumes that there are only two inputs, the
|
|
|
+ * first is the real internal mic and the second is HP/mic jack.
|
|
|
+ */
|
|
|
+
|
|
|
+ val = snd_hda_get_default_vref(codec, pin);
|
|
|
+
|
|
|
+ /* This pin does not have vref caps - let's enable vref on pin 0x18
|
|
|
+ instead, as suggested by Realtek */
|
|
|
+ if (val == AC_PINCTL_VREF_HIZ) {
|
|
|
+ const hda_nid_t vref_pin = 0x18;
|
|
|
+ /* Sanity check pin 0x18 */
|
|
|
+ if (get_wcaps_type(get_wcaps(codec, vref_pin)) == AC_WID_PIN &&
|
|
|
+ get_defcfg_connect(snd_hda_codec_get_pincfg(codec, vref_pin)) == AC_JACK_PORT_NONE) {
|
|
|
+ unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin);
|
|
|
+ if (vref_val != AC_PINCTL_VREF_HIZ)
|
|
|
+ snd_hda_set_pin_ctl(codec, vref_pin, PIN_IN | (set_as_mic ? vref_val : 0));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ val = set_as_mic ? val | PIN_IN : PIN_HP;
|
|
|
+ snd_hda_set_pin_ctl(codec, pin, val);
|
|
|
+
|
|
|
+ spec->automute_speaker = !set_as_mic;
|
|
|
+ call_update_outputs(codec);
|
|
|
+}
|
|
|
|
|
|
/* 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,
|
|
@@ -325,21 +360,8 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
|
|
|
return 0;
|
|
|
spec->cur_mux[adc_idx] = idx;
|
|
|
|
|
|
- /* for shared I/O, change the pin-control accordingly */
|
|
|
- if (spec->shared_mic_hp) {
|
|
|
- unsigned int val;
|
|
|
- hda_nid_t pin = spec->autocfg.inputs[1].pin;
|
|
|
- /* NOTE: this assumes that there are only two inputs, the
|
|
|
- * first is the real internal mic and the second is HP jack.
|
|
|
- */
|
|
|
- if (spec->cur_mux[adc_idx])
|
|
|
- val = snd_hda_get_default_vref(codec, pin) | PIN_IN;
|
|
|
- else
|
|
|
- val = PIN_HP;
|
|
|
- snd_hda_set_pin_ctl(codec, pin, val);
|
|
|
- spec->automute_speaker = !spec->cur_mux[adc_idx];
|
|
|
- call_update_outputs(codec);
|
|
|
- }
|
|
|
+ if (spec->shared_mic_hp)
|
|
|
+ update_shared_mic_hp(codec, spec->cur_mux[adc_idx]);
|
|
|
|
|
|
if (spec->dyn_adc_switch) {
|
|
|
alc_dyn_adc_pcm_resetup(codec, idx);
|
|
@@ -368,6 +390,7 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
|
|
|
AC_VERB_SET_CONNECT_SEL,
|
|
|
imux->items[idx].index);
|
|
|
}
|
|
|
+ alc_inv_dmic_sync(codec, true);
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
@@ -664,7 +687,7 @@ static void alc_update_knob_master(struct hda_codec *codec, hda_nid_t nid)
|
|
|
}
|
|
|
|
|
|
/* unsolicited event for HP jack sensing */
|
|
|
-static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
|
|
|
+static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
|
|
|
{
|
|
|
int action;
|
|
|
|
|
@@ -1000,11 +1023,9 @@ static void alc_init_automute(struct hda_codec *codec)
|
|
|
spec->automute_lo = spec->automute_lo_possible;
|
|
|
spec->automute_speaker = spec->automute_speaker_possible;
|
|
|
|
|
|
- if (spec->automute_speaker_possible || spec->automute_lo_possible) {
|
|
|
+ if (spec->automute_speaker_possible || spec->automute_lo_possible)
|
|
|
/* create a control for automute mode */
|
|
|
alc_add_automute_mode_enum(codec);
|
|
|
- spec->unsol_event = alc_sku_unsol_event;
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
/* return the position of NID in the list, or -1 if not found */
|
|
@@ -1167,7 +1188,6 @@ static void alc_init_auto_mic(struct hda_codec *codec)
|
|
|
|
|
|
snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n",
|
|
|
ext, fixed, dock);
|
|
|
- spec->unsol_event = alc_sku_unsol_event;
|
|
|
}
|
|
|
|
|
|
/* check the availabilities of auto-mute and auto-mic switches */
|
|
@@ -1556,14 +1576,14 @@ typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
|
|
|
|
|
|
static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
|
|
|
struct snd_ctl_elem_value *ucontrol,
|
|
|
- getput_call_t func, bool check_adc_switch)
|
|
|
+ getput_call_t func, bool is_put)
|
|
|
{
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
struct alc_spec *spec = codec->spec;
|
|
|
int i, err = 0;
|
|
|
|
|
|
mutex_lock(&codec->control_mutex);
|
|
|
- if (check_adc_switch && spec->dyn_adc_switch) {
|
|
|
+ if (is_put && spec->dyn_adc_switch) {
|
|
|
for (i = 0; i < spec->num_adc_nids; i++) {
|
|
|
kcontrol->private_value =
|
|
|
HDA_COMPOSE_AMP_VAL(spec->adc_nids[i],
|
|
@@ -1584,6 +1604,8 @@ static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
|
|
|
3, 0, HDA_INPUT);
|
|
|
err = func(kcontrol, ucontrol);
|
|
|
}
|
|
|
+ if (err >= 0 && is_put)
|
|
|
+ alc_inv_dmic_sync(codec, false);
|
|
|
error:
|
|
|
mutex_unlock(&codec->control_mutex);
|
|
|
return err;
|
|
@@ -1675,6 +1697,116 @@ DEFINE_CAPMIX_NOSRC(1);
|
|
|
DEFINE_CAPMIX_NOSRC(2);
|
|
|
DEFINE_CAPMIX_NOSRC(3);
|
|
|
|
|
|
+/*
|
|
|
+ * Inverted digital-mic handling
|
|
|
+ *
|
|
|
+ * First off, it's a bit tricky. The "Inverted Internal Mic Capture Switch"
|
|
|
+ * gives the additional mute only to the right channel of the digital mic
|
|
|
+ * capture stream. This is a workaround for avoiding the almost silence
|
|
|
+ * by summing the stereo stream from some (known to be ForteMedia)
|
|
|
+ * digital mic unit.
|
|
|
+ *
|
|
|
+ * The logic is to call alc_inv_dmic_sync() after each action (possibly)
|
|
|
+ * modifying ADC amp. When the mute flag is set, it mutes the R-channel
|
|
|
+ * without caching so that the cache can still keep the original value.
|
|
|
+ * The cached value is then restored when the flag is set off or any other
|
|
|
+ * than d-mic is used as the current input source.
|
|
|
+ */
|
|
|
+static void alc_inv_dmic_sync(struct hda_codec *codec, bool force)
|
|
|
+{
|
|
|
+ struct alc_spec *spec = codec->spec;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ if (!spec->inv_dmic_fixup)
|
|
|
+ return;
|
|
|
+ if (!spec->inv_dmic_muted && !force)
|
|
|
+ return;
|
|
|
+ for (i = 0; i < spec->num_adc_nids; i++) {
|
|
|
+ int src = spec->dyn_adc_switch ? 0 : i;
|
|
|
+ bool dmic_fixup = false;
|
|
|
+ hda_nid_t nid;
|
|
|
+ int parm, dir, v;
|
|
|
+
|
|
|
+ if (spec->inv_dmic_muted &&
|
|
|
+ spec->imux_pins[spec->cur_mux[src]] == spec->inv_dmic_pin)
|
|
|
+ dmic_fixup = true;
|
|
|
+ if (!dmic_fixup && !force)
|
|
|
+ continue;
|
|
|
+ if (spec->vol_in_capsrc) {
|
|
|
+ nid = spec->capsrc_nids[i];
|
|
|
+ parm = AC_AMP_SET_RIGHT | AC_AMP_SET_OUTPUT;
|
|
|
+ dir = HDA_OUTPUT;
|
|
|
+ } else {
|
|
|
+ nid = spec->adc_nids[i];
|
|
|
+ parm = AC_AMP_SET_RIGHT | AC_AMP_SET_INPUT;
|
|
|
+ dir = HDA_INPUT;
|
|
|
+ }
|
|
|
+ /* we care only right channel */
|
|
|
+ v = snd_hda_codec_amp_read(codec, nid, 1, dir, 0);
|
|
|
+ if (v & 0x80) /* if already muted, we don't need to touch */
|
|
|
+ continue;
|
|
|
+ if (dmic_fixup) /* add mute for d-mic */
|
|
|
+ v |= 0x80;
|
|
|
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
|
|
|
+ parm | v);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int alc_inv_dmic_sw_get(struct snd_kcontrol *kcontrol,
|
|
|
+ struct snd_ctl_elem_value *ucontrol)
|
|
|
+{
|
|
|
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
+ struct alc_spec *spec = codec->spec;
|
|
|
+
|
|
|
+ ucontrol->value.integer.value[0] = !spec->inv_dmic_muted;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int alc_inv_dmic_sw_put(struct snd_kcontrol *kcontrol,
|
|
|
+ struct snd_ctl_elem_value *ucontrol)
|
|
|
+{
|
|
|
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
+ struct alc_spec *spec = codec->spec;
|
|
|
+ unsigned int val = !ucontrol->value.integer.value[0];
|
|
|
+
|
|
|
+ if (val == spec->inv_dmic_muted)
|
|
|
+ return 0;
|
|
|
+ spec->inv_dmic_muted = val;
|
|
|
+ alc_inv_dmic_sync(codec, true);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static const struct snd_kcontrol_new alc_inv_dmic_sw = {
|
|
|
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
|
|
+ .info = snd_ctl_boolean_mono_info,
|
|
|
+ .get = alc_inv_dmic_sw_get,
|
|
|
+ .put = alc_inv_dmic_sw_put,
|
|
|
+};
|
|
|
+
|
|
|
+static int alc_add_inv_dmic_mixer(struct hda_codec *codec, hda_nid_t nid)
|
|
|
+{
|
|
|
+ struct alc_spec *spec = codec->spec;
|
|
|
+ struct snd_kcontrol_new *knew = alc_kcontrol_new(spec);
|
|
|
+ if (!knew)
|
|
|
+ return -ENOMEM;
|
|
|
+ *knew = alc_inv_dmic_sw;
|
|
|
+ knew->name = kstrdup("Inverted Internal Mic Capture Switch", GFP_KERNEL);
|
|
|
+ if (!knew->name)
|
|
|
+ return -ENOMEM;
|
|
|
+ spec->inv_dmic_fixup = 1;
|
|
|
+ spec->inv_dmic_muted = 0;
|
|
|
+ spec->inv_dmic_pin = nid;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* typically the digital mic is put at node 0x12 */
|
|
|
+static void alc_fixup_inv_dmic_0x12(struct hda_codec *codec,
|
|
|
+ const struct alc_fixup *fix, int action)
|
|
|
+{
|
|
|
+ if (action == ALC_FIXUP_ACT_PROBE)
|
|
|
+ alc_add_inv_dmic_mixer(codec, 0x12);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* virtual master controls
|
|
|
*/
|
|
@@ -1865,13 +1997,31 @@ static int __alc_build_controls(struct hda_codec *codec)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int alc_build_controls(struct hda_codec *codec)
|
|
|
+static int alc_build_jacks(struct hda_codec *codec)
|
|
|
{
|
|
|
struct alc_spec *spec = codec->spec;
|
|
|
+
|
|
|
+ if (spec->shared_mic_hp) {
|
|
|
+ int err;
|
|
|
+ int nid = spec->autocfg.inputs[1].pin;
|
|
|
+ err = snd_hda_jack_add_kctl(codec, nid, "Headphone Mic", 0);
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+ err = snd_hda_jack_detect_enable(codec, nid, 0);
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
+ return snd_hda_jack_add_kctls(codec, &spec->autocfg);
|
|
|
+}
|
|
|
+
|
|
|
+static int alc_build_controls(struct hda_codec *codec)
|
|
|
+{
|
|
|
int err = __alc_build_controls(codec);
|
|
|
if (err < 0)
|
|
|
return err;
|
|
|
- err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
|
|
|
+
|
|
|
+ err = alc_build_jacks(codec);
|
|
|
if (err < 0)
|
|
|
return err;
|
|
|
alc_apply_fixup(codec, ALC_FIXUP_ACT_BUILD);
|
|
@@ -1908,14 +2058,6 @@ static int alc_init(struct hda_codec *codec)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
|
|
|
-{
|
|
|
- struct alc_spec *spec = codec->spec;
|
|
|
-
|
|
|
- if (spec->unsol_event)
|
|
|
- spec->unsol_event(codec, res);
|
|
|
-}
|
|
|
-
|
|
|
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
|
|
static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
|
|
|
{
|
|
@@ -2300,7 +2442,7 @@ static void alc_power_eapd(struct hda_codec *codec)
|
|
|
alc_auto_setup_eapd(codec, false);
|
|
|
}
|
|
|
|
|
|
-static int alc_suspend(struct hda_codec *codec, pm_message_t state)
|
|
|
+static int alc_suspend(struct hda_codec *codec)
|
|
|
{
|
|
|
struct alc_spec *spec = codec->spec;
|
|
|
alc_shutup(codec);
|
|
@@ -2317,6 +2459,7 @@ static int alc_resume(struct hda_codec *codec)
|
|
|
codec->patch_ops.init(codec);
|
|
|
snd_hda_codec_resume_amp(codec);
|
|
|
snd_hda_codec_resume_cache(codec);
|
|
|
+ alc_inv_dmic_sync(codec, true);
|
|
|
hda_call_check_power_status(codec, 0x01);
|
|
|
return 0;
|
|
|
}
|
|
@@ -4116,14 +4259,12 @@ static void set_capture_mixer(struct hda_codec *codec)
|
|
|
*/
|
|
|
static void alc_auto_init_std(struct hda_codec *codec)
|
|
|
{
|
|
|
- struct alc_spec *spec = codec->spec;
|
|
|
alc_auto_init_multi_out(codec);
|
|
|
alc_auto_init_extra_out(codec);
|
|
|
alc_auto_init_analog_input(codec);
|
|
|
alc_auto_init_input_src(codec);
|
|
|
alc_auto_init_digital(codec);
|
|
|
- if (spec->unsol_event)
|
|
|
- alc_inithook(codec);
|
|
|
+ alc_inithook(codec);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -4724,7 +4865,6 @@ static void alc260_fixup_gpio1_toggle(struct hda_codec *codec,
|
|
|
spec->automute_speaker = 1;
|
|
|
spec->autocfg.hp_pins[0] = 0x0f; /* copy it for automute */
|
|
|
snd_hda_jack_detect_enable(codec, 0x0f, ALC_HP_EVENT);
|
|
|
- spec->unsol_event = alc_sku_unsol_event;
|
|
|
snd_hda_gen_add_verbs(&spec->gen, alc_gpio1_init_verbs);
|
|
|
}
|
|
|
}
|
|
@@ -4909,6 +5049,7 @@ enum {
|
|
|
ALC889_FIXUP_DAC_ROUTE,
|
|
|
ALC889_FIXUP_MBP_VREF,
|
|
|
ALC889_FIXUP_IMAC91_VREF,
|
|
|
+ ALC882_FIXUP_INV_DMIC,
|
|
|
};
|
|
|
|
|
|
static void alc889_fixup_coef(struct hda_codec *codec,
|
|
@@ -5212,6 +5353,10 @@ static const struct alc_fixup alc882_fixups[] = {
|
|
|
.chained = true,
|
|
|
.chain_id = ALC882_FIXUP_GPIO1,
|
|
|
},
|
|
|
+ [ALC882_FIXUP_INV_DMIC] = {
|
|
|
+ .type = ALC_FIXUP_FUNC,
|
|
|
+ .v.func = alc_fixup_inv_dmic_0x12,
|
|
|
+ },
|
|
|
};
|
|
|
|
|
|
static const struct snd_pci_quirk alc882_fixup_tbl[] = {
|
|
@@ -5286,6 +5431,7 @@ static const struct alc_model_fixup alc882_fixup_models[] = {
|
|
|
{.id = ALC882_FIXUP_ACER_ASPIRE_4930G, .name = "acer-aspire-4930g"},
|
|
|
{.id = ALC882_FIXUP_ACER_ASPIRE_8930G, .name = "acer-aspire-8930g"},
|
|
|
{.id = ALC883_FIXUP_ACER_EAPD, .name = "acer-aspire"},
|
|
|
+ {.id = ALC882_FIXUP_INV_DMIC, .name = "inv-dmic"},
|
|
|
{}
|
|
|
};
|
|
|
|
|
@@ -5373,6 +5519,7 @@ enum {
|
|
|
ALC262_FIXUP_LENOVO_3000,
|
|
|
ALC262_FIXUP_BENQ,
|
|
|
ALC262_FIXUP_BENQ_T31,
|
|
|
+ ALC262_FIXUP_INV_DMIC,
|
|
|
};
|
|
|
|
|
|
static const struct alc_fixup alc262_fixups[] = {
|
|
@@ -5424,6 +5571,10 @@ static const struct alc_fixup alc262_fixups[] = {
|
|
|
{}
|
|
|
}
|
|
|
},
|
|
|
+ [ALC262_FIXUP_INV_DMIC] = {
|
|
|
+ .type = ALC_FIXUP_FUNC,
|
|
|
+ .v.func = alc_fixup_inv_dmic_0x12,
|
|
|
+ },
|
|
|
};
|
|
|
|
|
|
static const struct snd_pci_quirk alc262_fixup_tbl[] = {
|
|
@@ -5438,6 +5589,10 @@ static const struct snd_pci_quirk alc262_fixup_tbl[] = {
|
|
|
{}
|
|
|
};
|
|
|
|
|
|
+static const struct alc_model_fixup alc262_fixup_models[] = {
|
|
|
+ {.id = ALC262_FIXUP_INV_DMIC, .name = "inv-dmic"},
|
|
|
+ {}
|
|
|
+};
|
|
|
|
|
|
/*
|
|
|
*/
|
|
@@ -5466,7 +5621,8 @@ static int patch_alc262(struct hda_codec *codec)
|
|
|
#endif
|
|
|
alc_fix_pll_init(codec, 0x20, 0x0a, 10);
|
|
|
|
|
|
- alc_pick_fixup(codec, NULL, alc262_fixup_tbl, alc262_fixups);
|
|
|
+ alc_pick_fixup(codec, alc262_fixup_models, alc262_fixup_tbl,
|
|
|
+ alc262_fixups);
|
|
|
alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
|
|
|
|
|
|
alc_auto_parse_customize_define(codec);
|
|
@@ -5522,6 +5678,22 @@ static const struct hda_verb alc268_beep_init_verbs[] = {
|
|
|
{ }
|
|
|
};
|
|
|
|
|
|
+enum {
|
|
|
+ ALC268_FIXUP_INV_DMIC,
|
|
|
+};
|
|
|
+
|
|
|
+static const struct alc_fixup alc268_fixups[] = {
|
|
|
+ [ALC268_FIXUP_INV_DMIC] = {
|
|
|
+ .type = ALC_FIXUP_FUNC,
|
|
|
+ .v.func = alc_fixup_inv_dmic_0x12,
|
|
|
+ },
|
|
|
+};
|
|
|
+
|
|
|
+static const struct alc_model_fixup alc268_fixup_models[] = {
|
|
|
+ {.id = ALC268_FIXUP_INV_DMIC, .name = "inv-dmic"},
|
|
|
+ {}
|
|
|
+};
|
|
|
+
|
|
|
/*
|
|
|
* BIOS auto configuration
|
|
|
*/
|
|
@@ -5553,6 +5725,9 @@ static int patch_alc268(struct hda_codec *codec)
|
|
|
|
|
|
spec = codec->spec;
|
|
|
|
|
|
+ alc_pick_fixup(codec, alc268_fixup_models, NULL, alc268_fixups);
|
|
|
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
|
|
|
+
|
|
|
/* automatic parse from the BIOS config */
|
|
|
err = alc268_parse_auto_config(codec);
|
|
|
if (err < 0)
|
|
@@ -5582,6 +5757,8 @@ static int patch_alc268(struct hda_codec *codec)
|
|
|
codec->patch_ops = alc_patch_ops;
|
|
|
spec->shutup = alc_eapd_shutup;
|
|
|
|
|
|
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
|
|
|
+
|
|
|
return 0;
|
|
|
|
|
|
error:
|
|
@@ -5704,6 +5881,15 @@ static int alc269_resume(struct hda_codec *codec)
|
|
|
}
|
|
|
#endif /* CONFIG_PM */
|
|
|
|
|
|
+static void alc269_fixup_pincfg_no_hp_to_lineout(struct hda_codec *codec,
|
|
|
+ const struct alc_fixup *fix, int action)
|
|
|
+{
|
|
|
+ struct alc_spec *spec = codec->spec;
|
|
|
+
|
|
|
+ if (action == ALC_FIXUP_ACT_PRE_PROBE)
|
|
|
+ spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
|
|
|
+}
|
|
|
+
|
|
|
static void alc269_fixup_hweq(struct hda_codec *codec,
|
|
|
const struct alc_fixup *fix, int action)
|
|
|
{
|
|
@@ -5810,6 +5996,7 @@ static void alc269_fixup_mic2_mute(struct hda_codec *codec,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+
|
|
|
enum {
|
|
|
ALC269_FIXUP_SONY_VAIO,
|
|
|
ALC275_FIXUP_SONY_VAIO_GPIO2,
|
|
@@ -5828,6 +6015,9 @@ enum {
|
|
|
ALC269VB_FIXUP_AMIC,
|
|
|
ALC269VB_FIXUP_DMIC,
|
|
|
ALC269_FIXUP_MIC2_MUTE_LED,
|
|
|
+ ALC269_FIXUP_INV_DMIC,
|
|
|
+ ALC269_FIXUP_LENOVO_DOCK,
|
|
|
+ ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT,
|
|
|
};
|
|
|
|
|
|
static const struct alc_fixup alc269_fixups[] = {
|
|
@@ -5952,12 +6142,33 @@ static const struct alc_fixup alc269_fixups[] = {
|
|
|
.type = ALC_FIXUP_FUNC,
|
|
|
.v.func = alc269_fixup_mic2_mute,
|
|
|
},
|
|
|
+ [ALC269_FIXUP_INV_DMIC] = {
|
|
|
+ .type = ALC_FIXUP_FUNC,
|
|
|
+ .v.func = alc_fixup_inv_dmic_0x12,
|
|
|
+ },
|
|
|
+ [ALC269_FIXUP_LENOVO_DOCK] = {
|
|
|
+ .type = ALC_FIXUP_PINS,
|
|
|
+ .v.pins = (const struct alc_pincfg[]) {
|
|
|
+ { 0x19, 0x23a11040 }, /* dock mic */
|
|
|
+ { 0x1b, 0x2121103f }, /* dock headphone */
|
|
|
+ { }
|
|
|
+ },
|
|
|
+ .chained = true,
|
|
|
+ .chain_id = ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT
|
|
|
+ },
|
|
|
+ [ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT] = {
|
|
|
+ .type = ALC_FIXUP_FUNC,
|
|
|
+ .v.func = alc269_fixup_pincfg_no_hp_to_lineout,
|
|
|
+ },
|
|
|
};
|
|
|
|
|
|
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
|
|
+ SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC),
|
|
|
+ SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC),
|
|
|
SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_MIC2_MUTE_LED),
|
|
|
SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_DMIC),
|
|
|
SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
|
|
|
+ SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC),
|
|
|
SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
|
|
|
SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
|
|
|
SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC),
|
|
@@ -5975,6 +6186,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
|
|
SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
|
|
|
SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE),
|
|
|
SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE),
|
|
|
+ SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK),
|
|
|
SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_QUANTA_MUTE),
|
|
|
SND_PCI_QUIRK(0x17aa, 0x3bf8, "Lenovo Ideapd", ALC269_FIXUP_PCM_44K),
|
|
|
SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
|
|
@@ -6033,6 +6245,10 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
|
|
static const struct alc_model_fixup alc269_fixup_models[] = {
|
|
|
{.id = ALC269_FIXUP_AMIC, .name = "laptop-amic"},
|
|
|
{.id = ALC269_FIXUP_DMIC, .name = "laptop-dmic"},
|
|
|
+ {.id = ALC269_FIXUP_STEREO_DMIC, .name = "alc269-dmic"},
|
|
|
+ {.id = ALC271_FIXUP_DMIC, .name = "alc271-dmic"},
|
|
|
+ {.id = ALC269_FIXUP_INV_DMIC, .name = "inv-dmic"},
|
|
|
+ {.id = ALC269_FIXUP_LENOVO_DOCK, .name = "lenovo-dock"},
|
|
|
{}
|
|
|
};
|
|
|
|
|
@@ -6329,12 +6545,6 @@ static const struct snd_pci_quirk alc861vd_fixup_tbl[] = {
|
|
|
{}
|
|
|
};
|
|
|
|
|
|
-static const struct hda_verb alc660vd_eapd_verbs[] = {
|
|
|
- {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
|
|
|
- {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
|
|
|
- { }
|
|
|
-};
|
|
|
-
|
|
|
/*
|
|
|
*/
|
|
|
static int patch_alc861vd(struct hda_codec *codec)
|
|
@@ -6356,11 +6566,6 @@ static int patch_alc861vd(struct hda_codec *codec)
|
|
|
if (err < 0)
|
|
|
goto error;
|
|
|
|
|
|
- if (codec->vendor_id == 0x10ec0660) {
|
|
|
- /* always turn on EAPD */
|
|
|
- snd_hda_gen_add_verbs(&spec->gen, alc660vd_eapd_verbs);
|
|
|
- }
|
|
|
-
|
|
|
if (!spec->no_analog) {
|
|
|
err = snd_hda_attach_beep_device(codec, 0x23);
|
|
|
if (err < 0)
|
|
@@ -6443,6 +6648,7 @@ enum {
|
|
|
ALC662_FIXUP_ASUS_MODE8,
|
|
|
ALC662_FIXUP_NO_JACK_DETECT,
|
|
|
ALC662_FIXUP_ZOTAC_Z68,
|
|
|
+ ALC662_FIXUP_INV_DMIC,
|
|
|
};
|
|
|
|
|
|
static const struct alc_fixup alc662_fixups[] = {
|
|
@@ -6599,12 +6805,17 @@ static const struct alc_fixup alc662_fixups[] = {
|
|
|
{ }
|
|
|
}
|
|
|
},
|
|
|
+ [ALC662_FIXUP_INV_DMIC] = {
|
|
|
+ .type = ALC_FIXUP_FUNC,
|
|
|
+ .v.func = alc_fixup_inv_dmic_0x12,
|
|
|
+ },
|
|
|
};
|
|
|
|
|
|
static const struct snd_pci_quirk alc662_fixup_tbl[] = {
|
|
|
SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2),
|
|
|
SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
|
|
|
SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
|
|
|
+ SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC),
|
|
|
SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
|
|
|
SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
|
|
|
SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT),
|
|
@@ -6685,6 +6896,7 @@ static const struct alc_model_fixup alc662_fixup_models[] = {
|
|
|
{.id = ALC662_FIXUP_ASUS_MODE6, .name = "asus-mode6"},
|
|
|
{.id = ALC662_FIXUP_ASUS_MODE7, .name = "asus-mode7"},
|
|
|
{.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"},
|
|
|
+ {.id = ALC662_FIXUP_INV_DMIC, .name = "inv-dmic"},
|
|
|
{}
|
|
|
};
|
|
|
|
|
@@ -6831,6 +7043,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = {
|
|
|
{ .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
|
|
|
{ .id = 0x10ec0276, .name = "ALC276", .patch = patch_alc269 },
|
|
|
{ .id = 0x10ec0280, .name = "ALC280", .patch = patch_alc269 },
|
|
|
+ { .id = 0x10ec0282, .name = "ALC282", .patch = patch_alc269 },
|
|
|
{ .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
|
|
|
.patch = patch_alc861 },
|
|
|
{ .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
|