diff options
Diffstat (limited to 'sound/pci/hda/patch_realtek.c')
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 313 |
1 files changed, 263 insertions, 50 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index aa4c25e0f327..f141395dfee6 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -170,10 +170,10 @@ struct alc_spec { | |||
170 | hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS]; | 170 | hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS]; |
171 | unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS]; | 171 | unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS]; |
172 | int int_mic_idx, ext_mic_idx, dock_mic_idx; /* for auto-mic */ | 172 | int int_mic_idx, ext_mic_idx, dock_mic_idx; /* for auto-mic */ |
173 | hda_nid_t inv_dmic_pin; | ||
173 | 174 | ||
174 | /* hooks */ | 175 | /* hooks */ |
175 | void (*init_hook)(struct hda_codec *codec); | 176 | void (*init_hook)(struct hda_codec *codec); |
176 | void (*unsol_event)(struct hda_codec *codec, unsigned int res); | ||
177 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 177 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
178 | void (*power_hook)(struct hda_codec *codec); | 178 | void (*power_hook)(struct hda_codec *codec); |
179 | #endif | 179 | #endif |
@@ -201,6 +201,8 @@ struct alc_spec { | |||
201 | unsigned int vol_in_capsrc:1; /* use capsrc volume (ADC has no vol) */ | 201 | unsigned int vol_in_capsrc:1; /* use capsrc volume (ADC has no vol) */ |
202 | unsigned int parse_flags; /* passed to snd_hda_parse_pin_defcfg() */ | 202 | unsigned int parse_flags; /* passed to snd_hda_parse_pin_defcfg() */ |
203 | unsigned int shared_mic_hp:1; /* HP/Mic-in sharing */ | 203 | unsigned int shared_mic_hp:1; /* HP/Mic-in sharing */ |
204 | unsigned int inv_dmic_fixup:1; /* has inverted digital-mic workaround */ | ||
205 | unsigned int inv_dmic_muted:1; /* R-ch of inv d-mic is muted? */ | ||
204 | 206 | ||
205 | /* auto-mute control */ | 207 | /* auto-mute control */ |
206 | int automute_mode; | 208 | int automute_mode; |
@@ -298,6 +300,39 @@ static inline hda_nid_t get_capsrc(struct alc_spec *spec, int idx) | |||
298 | } | 300 | } |
299 | 301 | ||
300 | static void call_update_outputs(struct hda_codec *codec); | 302 | static void call_update_outputs(struct hda_codec *codec); |
303 | static void alc_inv_dmic_sync(struct hda_codec *codec, bool force); | ||
304 | |||
305 | /* for shared I/O, change the pin-control accordingly */ | ||
306 | static void update_shared_mic_hp(struct hda_codec *codec, bool set_as_mic) | ||
307 | { | ||
308 | struct alc_spec *spec = codec->spec; | ||
309 | unsigned int val; | ||
310 | hda_nid_t pin = spec->autocfg.inputs[1].pin; | ||
311 | /* NOTE: this assumes that there are only two inputs, the | ||
312 | * first is the real internal mic and the second is HP/mic jack. | ||
313 | */ | ||
314 | |||
315 | val = snd_hda_get_default_vref(codec, pin); | ||
316 | |||
317 | /* This pin does not have vref caps - let's enable vref on pin 0x18 | ||
318 | instead, as suggested by Realtek */ | ||
319 | if (val == AC_PINCTL_VREF_HIZ) { | ||
320 | const hda_nid_t vref_pin = 0x18; | ||
321 | /* Sanity check pin 0x18 */ | ||
322 | if (get_wcaps_type(get_wcaps(codec, vref_pin)) == AC_WID_PIN && | ||
323 | get_defcfg_connect(snd_hda_codec_get_pincfg(codec, vref_pin)) == AC_JACK_PORT_NONE) { | ||
324 | unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin); | ||
325 | if (vref_val != AC_PINCTL_VREF_HIZ) | ||
326 | snd_hda_set_pin_ctl(codec, vref_pin, PIN_IN | (set_as_mic ? vref_val : 0)); | ||
327 | } | ||
328 | } | ||
329 | |||
330 | val = set_as_mic ? val | PIN_IN : PIN_HP; | ||
331 | snd_hda_set_pin_ctl(codec, pin, val); | ||
332 | |||
333 | spec->automute_speaker = !set_as_mic; | ||
334 | call_update_outputs(codec); | ||
335 | } | ||
301 | 336 | ||
302 | /* select the given imux item; either unmute exclusively or select the route */ | 337 | /* select the given imux item; either unmute exclusively or select the route */ |
303 | static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx, | 338 | 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, | |||
325 | return 0; | 360 | return 0; |
326 | spec->cur_mux[adc_idx] = idx; | 361 | spec->cur_mux[adc_idx] = idx; |
327 | 362 | ||
328 | /* for shared I/O, change the pin-control accordingly */ | 363 | if (spec->shared_mic_hp) |
329 | if (spec->shared_mic_hp) { | 364 | update_shared_mic_hp(codec, spec->cur_mux[adc_idx]); |
330 | unsigned int val; | ||
331 | hda_nid_t pin = spec->autocfg.inputs[1].pin; | ||
332 | /* NOTE: this assumes that there are only two inputs, the | ||
333 | * first is the real internal mic and the second is HP jack. | ||
334 | */ | ||
335 | if (spec->cur_mux[adc_idx]) | ||
336 | val = snd_hda_get_default_vref(codec, pin) | PIN_IN; | ||
337 | else | ||
338 | val = PIN_HP; | ||
339 | snd_hda_set_pin_ctl(codec, pin, val); | ||
340 | spec->automute_speaker = !spec->cur_mux[adc_idx]; | ||
341 | call_update_outputs(codec); | ||
342 | } | ||
343 | 365 | ||
344 | if (spec->dyn_adc_switch) { | 366 | if (spec->dyn_adc_switch) { |
345 | alc_dyn_adc_pcm_resetup(codec, idx); | 367 | alc_dyn_adc_pcm_resetup(codec, idx); |
@@ -368,6 +390,7 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx, | |||
368 | AC_VERB_SET_CONNECT_SEL, | 390 | AC_VERB_SET_CONNECT_SEL, |
369 | imux->items[idx].index); | 391 | imux->items[idx].index); |
370 | } | 392 | } |
393 | alc_inv_dmic_sync(codec, true); | ||
371 | return 1; | 394 | return 1; |
372 | } | 395 | } |
373 | 396 | ||
@@ -664,7 +687,7 @@ static void alc_update_knob_master(struct hda_codec *codec, hda_nid_t nid) | |||
664 | } | 687 | } |
665 | 688 | ||
666 | /* unsolicited event for HP jack sensing */ | 689 | /* unsolicited event for HP jack sensing */ |
667 | static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) | 690 | static void alc_unsol_event(struct hda_codec *codec, unsigned int res) |
668 | { | 691 | { |
669 | int action; | 692 | int action; |
670 | 693 | ||
@@ -1000,11 +1023,9 @@ static void alc_init_automute(struct hda_codec *codec) | |||
1000 | spec->automute_lo = spec->automute_lo_possible; | 1023 | spec->automute_lo = spec->automute_lo_possible; |
1001 | spec->automute_speaker = spec->automute_speaker_possible; | 1024 | spec->automute_speaker = spec->automute_speaker_possible; |
1002 | 1025 | ||
1003 | if (spec->automute_speaker_possible || spec->automute_lo_possible) { | 1026 | if (spec->automute_speaker_possible || spec->automute_lo_possible) |
1004 | /* create a control for automute mode */ | 1027 | /* create a control for automute mode */ |
1005 | alc_add_automute_mode_enum(codec); | 1028 | alc_add_automute_mode_enum(codec); |
1006 | spec->unsol_event = alc_sku_unsol_event; | ||
1007 | } | ||
1008 | } | 1029 | } |
1009 | 1030 | ||
1010 | /* return the position of NID in the list, or -1 if not found */ | 1031 | /* 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) | |||
1167 | 1188 | ||
1168 | snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n", | 1189 | snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n", |
1169 | ext, fixed, dock); | 1190 | ext, fixed, dock); |
1170 | spec->unsol_event = alc_sku_unsol_event; | ||
1171 | } | 1191 | } |
1172 | 1192 | ||
1173 | /* check the availabilities of auto-mute and auto-mic switches */ | 1193 | /* check the availabilities of auto-mute and auto-mic switches */ |
@@ -1556,14 +1576,14 @@ typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol, | |||
1556 | 1576 | ||
1557 | static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol, | 1577 | static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol, |
1558 | struct snd_ctl_elem_value *ucontrol, | 1578 | struct snd_ctl_elem_value *ucontrol, |
1559 | getput_call_t func, bool check_adc_switch) | 1579 | getput_call_t func, bool is_put) |
1560 | { | 1580 | { |
1561 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 1581 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
1562 | struct alc_spec *spec = codec->spec; | 1582 | struct alc_spec *spec = codec->spec; |
1563 | int i, err = 0; | 1583 | int i, err = 0; |
1564 | 1584 | ||
1565 | mutex_lock(&codec->control_mutex); | 1585 | mutex_lock(&codec->control_mutex); |
1566 | if (check_adc_switch && spec->dyn_adc_switch) { | 1586 | if (is_put && spec->dyn_adc_switch) { |
1567 | for (i = 0; i < spec->num_adc_nids; i++) { | 1587 | for (i = 0; i < spec->num_adc_nids; i++) { |
1568 | kcontrol->private_value = | 1588 | kcontrol->private_value = |
1569 | HDA_COMPOSE_AMP_VAL(spec->adc_nids[i], | 1589 | HDA_COMPOSE_AMP_VAL(spec->adc_nids[i], |
@@ -1584,6 +1604,8 @@ static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol, | |||
1584 | 3, 0, HDA_INPUT); | 1604 | 3, 0, HDA_INPUT); |
1585 | err = func(kcontrol, ucontrol); | 1605 | err = func(kcontrol, ucontrol); |
1586 | } | 1606 | } |
1607 | if (err >= 0 && is_put) | ||
1608 | alc_inv_dmic_sync(codec, false); | ||
1587 | error: | 1609 | error: |
1588 | mutex_unlock(&codec->control_mutex); | 1610 | mutex_unlock(&codec->control_mutex); |
1589 | return err; | 1611 | return err; |
@@ -1676,6 +1698,116 @@ DEFINE_CAPMIX_NOSRC(2); | |||
1676 | DEFINE_CAPMIX_NOSRC(3); | 1698 | DEFINE_CAPMIX_NOSRC(3); |
1677 | 1699 | ||
1678 | /* | 1700 | /* |
1701 | * Inverted digital-mic handling | ||
1702 | * | ||
1703 | * First off, it's a bit tricky. The "Inverted Internal Mic Capture Switch" | ||
1704 | * gives the additional mute only to the right channel of the digital mic | ||
1705 | * capture stream. This is a workaround for avoiding the almost silence | ||
1706 | * by summing the stereo stream from some (known to be ForteMedia) | ||
1707 | * digital mic unit. | ||
1708 | * | ||
1709 | * The logic is to call alc_inv_dmic_sync() after each action (possibly) | ||
1710 | * modifying ADC amp. When the mute flag is set, it mutes the R-channel | ||
1711 | * without caching so that the cache can still keep the original value. | ||
1712 | * The cached value is then restored when the flag is set off or any other | ||
1713 | * than d-mic is used as the current input source. | ||
1714 | */ | ||
1715 | static void alc_inv_dmic_sync(struct hda_codec *codec, bool force) | ||
1716 | { | ||
1717 | struct alc_spec *spec = codec->spec; | ||
1718 | int i; | ||
1719 | |||
1720 | if (!spec->inv_dmic_fixup) | ||
1721 | return; | ||
1722 | if (!spec->inv_dmic_muted && !force) | ||
1723 | return; | ||
1724 | for (i = 0; i < spec->num_adc_nids; i++) { | ||
1725 | int src = spec->dyn_adc_switch ? 0 : i; | ||
1726 | bool dmic_fixup = false; | ||
1727 | hda_nid_t nid; | ||
1728 | int parm, dir, v; | ||
1729 | |||
1730 | if (spec->inv_dmic_muted && | ||
1731 | spec->imux_pins[spec->cur_mux[src]] == spec->inv_dmic_pin) | ||
1732 | dmic_fixup = true; | ||
1733 | if (!dmic_fixup && !force) | ||
1734 | continue; | ||
1735 | if (spec->vol_in_capsrc) { | ||
1736 | nid = spec->capsrc_nids[i]; | ||
1737 | parm = AC_AMP_SET_RIGHT | AC_AMP_SET_OUTPUT; | ||
1738 | dir = HDA_OUTPUT; | ||
1739 | } else { | ||
1740 | nid = spec->adc_nids[i]; | ||
1741 | parm = AC_AMP_SET_RIGHT | AC_AMP_SET_INPUT; | ||
1742 | dir = HDA_INPUT; | ||
1743 | } | ||
1744 | /* we care only right channel */ | ||
1745 | v = snd_hda_codec_amp_read(codec, nid, 1, dir, 0); | ||
1746 | if (v & 0x80) /* if already muted, we don't need to touch */ | ||
1747 | continue; | ||
1748 | if (dmic_fixup) /* add mute for d-mic */ | ||
1749 | v |= 0x80; | ||
1750 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
1751 | parm | v); | ||
1752 | } | ||
1753 | } | ||
1754 | |||
1755 | static int alc_inv_dmic_sw_get(struct snd_kcontrol *kcontrol, | ||
1756 | struct snd_ctl_elem_value *ucontrol) | ||
1757 | { | ||
1758 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1759 | struct alc_spec *spec = codec->spec; | ||
1760 | |||
1761 | ucontrol->value.integer.value[0] = !spec->inv_dmic_muted; | ||
1762 | return 0; | ||
1763 | } | ||
1764 | |||
1765 | static int alc_inv_dmic_sw_put(struct snd_kcontrol *kcontrol, | ||
1766 | struct snd_ctl_elem_value *ucontrol) | ||
1767 | { | ||
1768 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1769 | struct alc_spec *spec = codec->spec; | ||
1770 | unsigned int val = !ucontrol->value.integer.value[0]; | ||
1771 | |||
1772 | if (val == spec->inv_dmic_muted) | ||
1773 | return 0; | ||
1774 | spec->inv_dmic_muted = val; | ||
1775 | alc_inv_dmic_sync(codec, true); | ||
1776 | return 0; | ||
1777 | } | ||
1778 | |||
1779 | static const struct snd_kcontrol_new alc_inv_dmic_sw = { | ||
1780 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1781 | .info = snd_ctl_boolean_mono_info, | ||
1782 | .get = alc_inv_dmic_sw_get, | ||
1783 | .put = alc_inv_dmic_sw_put, | ||
1784 | }; | ||
1785 | |||
1786 | static int alc_add_inv_dmic_mixer(struct hda_codec *codec, hda_nid_t nid) | ||
1787 | { | ||
1788 | struct alc_spec *spec = codec->spec; | ||
1789 | struct snd_kcontrol_new *knew = alc_kcontrol_new(spec); | ||
1790 | if (!knew) | ||
1791 | return -ENOMEM; | ||
1792 | *knew = alc_inv_dmic_sw; | ||
1793 | knew->name = kstrdup("Inverted Internal Mic Capture Switch", GFP_KERNEL); | ||
1794 | if (!knew->name) | ||
1795 | return -ENOMEM; | ||
1796 | spec->inv_dmic_fixup = 1; | ||
1797 | spec->inv_dmic_muted = 0; | ||
1798 | spec->inv_dmic_pin = nid; | ||
1799 | return 0; | ||
1800 | } | ||
1801 | |||
1802 | /* typically the digital mic is put at node 0x12 */ | ||
1803 | static void alc_fixup_inv_dmic_0x12(struct hda_codec *codec, | ||
1804 | const struct alc_fixup *fix, int action) | ||
1805 | { | ||
1806 | if (action == ALC_FIXUP_ACT_PROBE) | ||
1807 | alc_add_inv_dmic_mixer(codec, 0x12); | ||
1808 | } | ||
1809 | |||
1810 | /* | ||
1679 | * virtual master controls | 1811 | * virtual master controls |
1680 | */ | 1812 | */ |
1681 | 1813 | ||
@@ -1865,13 +1997,31 @@ static int __alc_build_controls(struct hda_codec *codec) | |||
1865 | return 0; | 1997 | return 0; |
1866 | } | 1998 | } |
1867 | 1999 | ||
1868 | static int alc_build_controls(struct hda_codec *codec) | 2000 | static int alc_build_jacks(struct hda_codec *codec) |
1869 | { | 2001 | { |
1870 | struct alc_spec *spec = codec->spec; | 2002 | struct alc_spec *spec = codec->spec; |
2003 | |||
2004 | if (spec->shared_mic_hp) { | ||
2005 | int err; | ||
2006 | int nid = spec->autocfg.inputs[1].pin; | ||
2007 | err = snd_hda_jack_add_kctl(codec, nid, "Headphone Mic", 0); | ||
2008 | if (err < 0) | ||
2009 | return err; | ||
2010 | err = snd_hda_jack_detect_enable(codec, nid, 0); | ||
2011 | if (err < 0) | ||
2012 | return err; | ||
2013 | } | ||
2014 | |||
2015 | return snd_hda_jack_add_kctls(codec, &spec->autocfg); | ||
2016 | } | ||
2017 | |||
2018 | static int alc_build_controls(struct hda_codec *codec) | ||
2019 | { | ||
1871 | int err = __alc_build_controls(codec); | 2020 | int err = __alc_build_controls(codec); |
1872 | if (err < 0) | 2021 | if (err < 0) |
1873 | return err; | 2022 | return err; |
1874 | err = snd_hda_jack_add_kctls(codec, &spec->autocfg); | 2023 | |
2024 | err = alc_build_jacks(codec); | ||
1875 | if (err < 0) | 2025 | if (err < 0) |
1876 | return err; | 2026 | return err; |
1877 | alc_apply_fixup(codec, ALC_FIXUP_ACT_BUILD); | 2027 | alc_apply_fixup(codec, ALC_FIXUP_ACT_BUILD); |
@@ -1908,14 +2058,6 @@ static int alc_init(struct hda_codec *codec) | |||
1908 | return 0; | 2058 | return 0; |
1909 | } | 2059 | } |
1910 | 2060 | ||
1911 | static void alc_unsol_event(struct hda_codec *codec, unsigned int res) | ||
1912 | { | ||
1913 | struct alc_spec *spec = codec->spec; | ||
1914 | |||
1915 | if (spec->unsol_event) | ||
1916 | spec->unsol_event(codec, res); | ||
1917 | } | ||
1918 | |||
1919 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 2061 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
1920 | static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid) | 2062 | static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid) |
1921 | { | 2063 | { |
@@ -2300,7 +2442,7 @@ static void alc_power_eapd(struct hda_codec *codec) | |||
2300 | alc_auto_setup_eapd(codec, false); | 2442 | alc_auto_setup_eapd(codec, false); |
2301 | } | 2443 | } |
2302 | 2444 | ||
2303 | static int alc_suspend(struct hda_codec *codec, pm_message_t state) | 2445 | static int alc_suspend(struct hda_codec *codec) |
2304 | { | 2446 | { |
2305 | struct alc_spec *spec = codec->spec; | 2447 | struct alc_spec *spec = codec->spec; |
2306 | alc_shutup(codec); | 2448 | alc_shutup(codec); |
@@ -2317,6 +2459,7 @@ static int alc_resume(struct hda_codec *codec) | |||
2317 | codec->patch_ops.init(codec); | 2459 | codec->patch_ops.init(codec); |
2318 | snd_hda_codec_resume_amp(codec); | 2460 | snd_hda_codec_resume_amp(codec); |
2319 | snd_hda_codec_resume_cache(codec); | 2461 | snd_hda_codec_resume_cache(codec); |
2462 | alc_inv_dmic_sync(codec, true); | ||
2320 | hda_call_check_power_status(codec, 0x01); | 2463 | hda_call_check_power_status(codec, 0x01); |
2321 | return 0; | 2464 | return 0; |
2322 | } | 2465 | } |
@@ -4116,14 +4259,12 @@ static void set_capture_mixer(struct hda_codec *codec) | |||
4116 | */ | 4259 | */ |
4117 | static void alc_auto_init_std(struct hda_codec *codec) | 4260 | static void alc_auto_init_std(struct hda_codec *codec) |
4118 | { | 4261 | { |
4119 | struct alc_spec *spec = codec->spec; | ||
4120 | alc_auto_init_multi_out(codec); | 4262 | alc_auto_init_multi_out(codec); |
4121 | alc_auto_init_extra_out(codec); | 4263 | alc_auto_init_extra_out(codec); |
4122 | alc_auto_init_analog_input(codec); | 4264 | alc_auto_init_analog_input(codec); |
4123 | alc_auto_init_input_src(codec); | 4265 | alc_auto_init_input_src(codec); |
4124 | alc_auto_init_digital(codec); | 4266 | alc_auto_init_digital(codec); |
4125 | if (spec->unsol_event) | 4267 | alc_inithook(codec); |
4126 | alc_inithook(codec); | ||
4127 | } | 4268 | } |
4128 | 4269 | ||
4129 | /* | 4270 | /* |
@@ -4724,7 +4865,6 @@ static void alc260_fixup_gpio1_toggle(struct hda_codec *codec, | |||
4724 | spec->automute_speaker = 1; | 4865 | spec->automute_speaker = 1; |
4725 | spec->autocfg.hp_pins[0] = 0x0f; /* copy it for automute */ | 4866 | spec->autocfg.hp_pins[0] = 0x0f; /* copy it for automute */ |
4726 | snd_hda_jack_detect_enable(codec, 0x0f, ALC_HP_EVENT); | 4867 | snd_hda_jack_detect_enable(codec, 0x0f, ALC_HP_EVENT); |
4727 | spec->unsol_event = alc_sku_unsol_event; | ||
4728 | snd_hda_gen_add_verbs(&spec->gen, alc_gpio1_init_verbs); | 4868 | snd_hda_gen_add_verbs(&spec->gen, alc_gpio1_init_verbs); |
4729 | } | 4869 | } |
4730 | } | 4870 | } |
@@ -4909,6 +5049,7 @@ enum { | |||
4909 | ALC889_FIXUP_DAC_ROUTE, | 5049 | ALC889_FIXUP_DAC_ROUTE, |
4910 | ALC889_FIXUP_MBP_VREF, | 5050 | ALC889_FIXUP_MBP_VREF, |
4911 | ALC889_FIXUP_IMAC91_VREF, | 5051 | ALC889_FIXUP_IMAC91_VREF, |
5052 | ALC882_FIXUP_INV_DMIC, | ||
4912 | }; | 5053 | }; |
4913 | 5054 | ||
4914 | static void alc889_fixup_coef(struct hda_codec *codec, | 5055 | static void alc889_fixup_coef(struct hda_codec *codec, |
@@ -5212,6 +5353,10 @@ static const struct alc_fixup alc882_fixups[] = { | |||
5212 | .chained = true, | 5353 | .chained = true, |
5213 | .chain_id = ALC882_FIXUP_GPIO1, | 5354 | .chain_id = ALC882_FIXUP_GPIO1, |
5214 | }, | 5355 | }, |
5356 | [ALC882_FIXUP_INV_DMIC] = { | ||
5357 | .type = ALC_FIXUP_FUNC, | ||
5358 | .v.func = alc_fixup_inv_dmic_0x12, | ||
5359 | }, | ||
5215 | }; | 5360 | }; |
5216 | 5361 | ||
5217 | static const struct snd_pci_quirk alc882_fixup_tbl[] = { | 5362 | static const struct snd_pci_quirk alc882_fixup_tbl[] = { |
@@ -5286,6 +5431,7 @@ static const struct alc_model_fixup alc882_fixup_models[] = { | |||
5286 | {.id = ALC882_FIXUP_ACER_ASPIRE_4930G, .name = "acer-aspire-4930g"}, | 5431 | {.id = ALC882_FIXUP_ACER_ASPIRE_4930G, .name = "acer-aspire-4930g"}, |
5287 | {.id = ALC882_FIXUP_ACER_ASPIRE_8930G, .name = "acer-aspire-8930g"}, | 5432 | {.id = ALC882_FIXUP_ACER_ASPIRE_8930G, .name = "acer-aspire-8930g"}, |
5288 | {.id = ALC883_FIXUP_ACER_EAPD, .name = "acer-aspire"}, | 5433 | {.id = ALC883_FIXUP_ACER_EAPD, .name = "acer-aspire"}, |
5434 | {.id = ALC882_FIXUP_INV_DMIC, .name = "inv-dmic"}, | ||
5289 | {} | 5435 | {} |
5290 | }; | 5436 | }; |
5291 | 5437 | ||
@@ -5373,6 +5519,7 @@ enum { | |||
5373 | ALC262_FIXUP_LENOVO_3000, | 5519 | ALC262_FIXUP_LENOVO_3000, |
5374 | ALC262_FIXUP_BENQ, | 5520 | ALC262_FIXUP_BENQ, |
5375 | ALC262_FIXUP_BENQ_T31, | 5521 | ALC262_FIXUP_BENQ_T31, |
5522 | ALC262_FIXUP_INV_DMIC, | ||
5376 | }; | 5523 | }; |
5377 | 5524 | ||
5378 | static const struct alc_fixup alc262_fixups[] = { | 5525 | static const struct alc_fixup alc262_fixups[] = { |
@@ -5424,6 +5571,10 @@ static const struct alc_fixup alc262_fixups[] = { | |||
5424 | {} | 5571 | {} |
5425 | } | 5572 | } |
5426 | }, | 5573 | }, |
5574 | [ALC262_FIXUP_INV_DMIC] = { | ||
5575 | .type = ALC_FIXUP_FUNC, | ||
5576 | .v.func = alc_fixup_inv_dmic_0x12, | ||
5577 | }, | ||
5427 | }; | 5578 | }; |
5428 | 5579 | ||
5429 | static const struct snd_pci_quirk alc262_fixup_tbl[] = { | 5580 | static const struct snd_pci_quirk alc262_fixup_tbl[] = { |
@@ -5438,6 +5589,10 @@ static const struct snd_pci_quirk alc262_fixup_tbl[] = { | |||
5438 | {} | 5589 | {} |
5439 | }; | 5590 | }; |
5440 | 5591 | ||
5592 | static const struct alc_model_fixup alc262_fixup_models[] = { | ||
5593 | {.id = ALC262_FIXUP_INV_DMIC, .name = "inv-dmic"}, | ||
5594 | {} | ||
5595 | }; | ||
5441 | 5596 | ||
5442 | /* | 5597 | /* |
5443 | */ | 5598 | */ |
@@ -5466,7 +5621,8 @@ static int patch_alc262(struct hda_codec *codec) | |||
5466 | #endif | 5621 | #endif |
5467 | alc_fix_pll_init(codec, 0x20, 0x0a, 10); | 5622 | alc_fix_pll_init(codec, 0x20, 0x0a, 10); |
5468 | 5623 | ||
5469 | alc_pick_fixup(codec, NULL, alc262_fixup_tbl, alc262_fixups); | 5624 | alc_pick_fixup(codec, alc262_fixup_models, alc262_fixup_tbl, |
5625 | alc262_fixups); | ||
5470 | alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); | 5626 | alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); |
5471 | 5627 | ||
5472 | alc_auto_parse_customize_define(codec); | 5628 | alc_auto_parse_customize_define(codec); |
@@ -5522,6 +5678,22 @@ static const struct hda_verb alc268_beep_init_verbs[] = { | |||
5522 | { } | 5678 | { } |
5523 | }; | 5679 | }; |
5524 | 5680 | ||
5681 | enum { | ||
5682 | ALC268_FIXUP_INV_DMIC, | ||
5683 | }; | ||
5684 | |||
5685 | static const struct alc_fixup alc268_fixups[] = { | ||
5686 | [ALC268_FIXUP_INV_DMIC] = { | ||
5687 | .type = ALC_FIXUP_FUNC, | ||
5688 | .v.func = alc_fixup_inv_dmic_0x12, | ||
5689 | }, | ||
5690 | }; | ||
5691 | |||
5692 | static const struct alc_model_fixup alc268_fixup_models[] = { | ||
5693 | {.id = ALC268_FIXUP_INV_DMIC, .name = "inv-dmic"}, | ||
5694 | {} | ||
5695 | }; | ||
5696 | |||
5525 | /* | 5697 | /* |
5526 | * BIOS auto configuration | 5698 | * BIOS auto configuration |
5527 | */ | 5699 | */ |
@@ -5553,6 +5725,9 @@ static int patch_alc268(struct hda_codec *codec) | |||
5553 | 5725 | ||
5554 | spec = codec->spec; | 5726 | spec = codec->spec; |
5555 | 5727 | ||
5728 | alc_pick_fixup(codec, alc268_fixup_models, NULL, alc268_fixups); | ||
5729 | alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); | ||
5730 | |||
5556 | /* automatic parse from the BIOS config */ | 5731 | /* automatic parse from the BIOS config */ |
5557 | err = alc268_parse_auto_config(codec); | 5732 | err = alc268_parse_auto_config(codec); |
5558 | if (err < 0) | 5733 | if (err < 0) |
@@ -5582,6 +5757,8 @@ static int patch_alc268(struct hda_codec *codec) | |||
5582 | codec->patch_ops = alc_patch_ops; | 5757 | codec->patch_ops = alc_patch_ops; |
5583 | spec->shutup = alc_eapd_shutup; | 5758 | spec->shutup = alc_eapd_shutup; |
5584 | 5759 | ||
5760 | alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); | ||
5761 | |||
5585 | return 0; | 5762 | return 0; |
5586 | 5763 | ||
5587 | error: | 5764 | error: |
@@ -5704,6 +5881,15 @@ static int alc269_resume(struct hda_codec *codec) | |||
5704 | } | 5881 | } |
5705 | #endif /* CONFIG_PM */ | 5882 | #endif /* CONFIG_PM */ |
5706 | 5883 | ||
5884 | static void alc269_fixup_pincfg_no_hp_to_lineout(struct hda_codec *codec, | ||
5885 | const struct alc_fixup *fix, int action) | ||
5886 | { | ||
5887 | struct alc_spec *spec = codec->spec; | ||
5888 | |||
5889 | if (action == ALC_FIXUP_ACT_PRE_PROBE) | ||
5890 | spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP; | ||
5891 | } | ||
5892 | |||
5707 | static void alc269_fixup_hweq(struct hda_codec *codec, | 5893 | static void alc269_fixup_hweq(struct hda_codec *codec, |
5708 | const struct alc_fixup *fix, int action) | 5894 | const struct alc_fixup *fix, int action) |
5709 | { | 5895 | { |
@@ -5810,6 +5996,7 @@ static void alc269_fixup_mic2_mute(struct hda_codec *codec, | |||
5810 | } | 5996 | } |
5811 | } | 5997 | } |
5812 | 5998 | ||
5999 | |||
5813 | enum { | 6000 | enum { |
5814 | ALC269_FIXUP_SONY_VAIO, | 6001 | ALC269_FIXUP_SONY_VAIO, |
5815 | ALC275_FIXUP_SONY_VAIO_GPIO2, | 6002 | ALC275_FIXUP_SONY_VAIO_GPIO2, |
@@ -5828,6 +6015,9 @@ enum { | |||
5828 | ALC269VB_FIXUP_AMIC, | 6015 | ALC269VB_FIXUP_AMIC, |
5829 | ALC269VB_FIXUP_DMIC, | 6016 | ALC269VB_FIXUP_DMIC, |
5830 | ALC269_FIXUP_MIC2_MUTE_LED, | 6017 | ALC269_FIXUP_MIC2_MUTE_LED, |
6018 | ALC269_FIXUP_INV_DMIC, | ||
6019 | ALC269_FIXUP_LENOVO_DOCK, | ||
6020 | ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT, | ||
5831 | }; | 6021 | }; |
5832 | 6022 | ||
5833 | static const struct alc_fixup alc269_fixups[] = { | 6023 | static const struct alc_fixup alc269_fixups[] = { |
@@ -5952,12 +6142,33 @@ static const struct alc_fixup alc269_fixups[] = { | |||
5952 | .type = ALC_FIXUP_FUNC, | 6142 | .type = ALC_FIXUP_FUNC, |
5953 | .v.func = alc269_fixup_mic2_mute, | 6143 | .v.func = alc269_fixup_mic2_mute, |
5954 | }, | 6144 | }, |
6145 | [ALC269_FIXUP_INV_DMIC] = { | ||
6146 | .type = ALC_FIXUP_FUNC, | ||
6147 | .v.func = alc_fixup_inv_dmic_0x12, | ||
6148 | }, | ||
6149 | [ALC269_FIXUP_LENOVO_DOCK] = { | ||
6150 | .type = ALC_FIXUP_PINS, | ||
6151 | .v.pins = (const struct alc_pincfg[]) { | ||
6152 | { 0x19, 0x23a11040 }, /* dock mic */ | ||
6153 | { 0x1b, 0x2121103f }, /* dock headphone */ | ||
6154 | { } | ||
6155 | }, | ||
6156 | .chained = true, | ||
6157 | .chain_id = ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT | ||
6158 | }, | ||
6159 | [ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT] = { | ||
6160 | .type = ALC_FIXUP_FUNC, | ||
6161 | .v.func = alc269_fixup_pincfg_no_hp_to_lineout, | ||
6162 | }, | ||
5955 | }; | 6163 | }; |
5956 | 6164 | ||
5957 | static const struct snd_pci_quirk alc269_fixup_tbl[] = { | 6165 | static const struct snd_pci_quirk alc269_fixup_tbl[] = { |
6166 | SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC), | ||
6167 | SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC), | ||
5958 | SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_MIC2_MUTE_LED), | 6168 | SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_MIC2_MUTE_LED), |
5959 | SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_DMIC), | 6169 | SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_DMIC), |
5960 | SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW), | 6170 | SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW), |
6171 | SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC), | ||
5961 | SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC), | 6172 | SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC), |
5962 | SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC), | 6173 | SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC), |
5963 | SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC), | 6174 | SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC), |
@@ -5975,6 +6186,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
5975 | SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE), | 6186 | SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE), |
5976 | SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE), | 6187 | SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE), |
5977 | SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE), | 6188 | SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE), |
6189 | SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK), | ||
5978 | SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_QUANTA_MUTE), | 6190 | SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_QUANTA_MUTE), |
5979 | SND_PCI_QUIRK(0x17aa, 0x3bf8, "Lenovo Ideapd", ALC269_FIXUP_PCM_44K), | 6191 | SND_PCI_QUIRK(0x17aa, 0x3bf8, "Lenovo Ideapd", ALC269_FIXUP_PCM_44K), |
5980 | SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), | 6192 | SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), |
@@ -6033,6 +6245,10 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
6033 | static const struct alc_model_fixup alc269_fixup_models[] = { | 6245 | static const struct alc_model_fixup alc269_fixup_models[] = { |
6034 | {.id = ALC269_FIXUP_AMIC, .name = "laptop-amic"}, | 6246 | {.id = ALC269_FIXUP_AMIC, .name = "laptop-amic"}, |
6035 | {.id = ALC269_FIXUP_DMIC, .name = "laptop-dmic"}, | 6247 | {.id = ALC269_FIXUP_DMIC, .name = "laptop-dmic"}, |
6248 | {.id = ALC269_FIXUP_STEREO_DMIC, .name = "alc269-dmic"}, | ||
6249 | {.id = ALC271_FIXUP_DMIC, .name = "alc271-dmic"}, | ||
6250 | {.id = ALC269_FIXUP_INV_DMIC, .name = "inv-dmic"}, | ||
6251 | {.id = ALC269_FIXUP_LENOVO_DOCK, .name = "lenovo-dock"}, | ||
6036 | {} | 6252 | {} |
6037 | }; | 6253 | }; |
6038 | 6254 | ||
@@ -6329,12 +6545,6 @@ static const struct snd_pci_quirk alc861vd_fixup_tbl[] = { | |||
6329 | {} | 6545 | {} |
6330 | }; | 6546 | }; |
6331 | 6547 | ||
6332 | static const struct hda_verb alc660vd_eapd_verbs[] = { | ||
6333 | {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, | ||
6334 | {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, | ||
6335 | { } | ||
6336 | }; | ||
6337 | |||
6338 | /* | 6548 | /* |
6339 | */ | 6549 | */ |
6340 | static int patch_alc861vd(struct hda_codec *codec) | 6550 | static int patch_alc861vd(struct hda_codec *codec) |
@@ -6356,11 +6566,6 @@ static int patch_alc861vd(struct hda_codec *codec) | |||
6356 | if (err < 0) | 6566 | if (err < 0) |
6357 | goto error; | 6567 | goto error; |
6358 | 6568 | ||
6359 | if (codec->vendor_id == 0x10ec0660) { | ||
6360 | /* always turn on EAPD */ | ||
6361 | snd_hda_gen_add_verbs(&spec->gen, alc660vd_eapd_verbs); | ||
6362 | } | ||
6363 | |||
6364 | if (!spec->no_analog) { | 6569 | if (!spec->no_analog) { |
6365 | err = snd_hda_attach_beep_device(codec, 0x23); | 6570 | err = snd_hda_attach_beep_device(codec, 0x23); |
6366 | if (err < 0) | 6571 | if (err < 0) |
@@ -6443,6 +6648,7 @@ enum { | |||
6443 | ALC662_FIXUP_ASUS_MODE8, | 6648 | ALC662_FIXUP_ASUS_MODE8, |
6444 | ALC662_FIXUP_NO_JACK_DETECT, | 6649 | ALC662_FIXUP_NO_JACK_DETECT, |
6445 | ALC662_FIXUP_ZOTAC_Z68, | 6650 | ALC662_FIXUP_ZOTAC_Z68, |
6651 | ALC662_FIXUP_INV_DMIC, | ||
6446 | }; | 6652 | }; |
6447 | 6653 | ||
6448 | static const struct alc_fixup alc662_fixups[] = { | 6654 | static const struct alc_fixup alc662_fixups[] = { |
@@ -6599,12 +6805,17 @@ static const struct alc_fixup alc662_fixups[] = { | |||
6599 | { } | 6805 | { } |
6600 | } | 6806 | } |
6601 | }, | 6807 | }, |
6808 | [ALC662_FIXUP_INV_DMIC] = { | ||
6809 | .type = ALC_FIXUP_FUNC, | ||
6810 | .v.func = alc_fixup_inv_dmic_0x12, | ||
6811 | }, | ||
6602 | }; | 6812 | }; |
6603 | 6813 | ||
6604 | static const struct snd_pci_quirk alc662_fixup_tbl[] = { | 6814 | static const struct snd_pci_quirk alc662_fixup_tbl[] = { |
6605 | SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2), | 6815 | SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2), |
6606 | SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE), | 6816 | SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE), |
6607 | SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE), | 6817 | SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE), |
6818 | SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC), | ||
6608 | SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE), | 6819 | SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE), |
6609 | SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), | 6820 | SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), |
6610 | SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT), | 6821 | 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[] = { | |||
6685 | {.id = ALC662_FIXUP_ASUS_MODE6, .name = "asus-mode6"}, | 6896 | {.id = ALC662_FIXUP_ASUS_MODE6, .name = "asus-mode6"}, |
6686 | {.id = ALC662_FIXUP_ASUS_MODE7, .name = "asus-mode7"}, | 6897 | {.id = ALC662_FIXUP_ASUS_MODE7, .name = "asus-mode7"}, |
6687 | {.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"}, | 6898 | {.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"}, |
6899 | {.id = ALC662_FIXUP_INV_DMIC, .name = "inv-dmic"}, | ||
6688 | {} | 6900 | {} |
6689 | }; | 6901 | }; |
6690 | 6902 | ||
@@ -6831,6 +7043,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = { | |||
6831 | { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 }, | 7043 | { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 }, |
6832 | { .id = 0x10ec0276, .name = "ALC276", .patch = patch_alc269 }, | 7044 | { .id = 0x10ec0276, .name = "ALC276", .patch = patch_alc269 }, |
6833 | { .id = 0x10ec0280, .name = "ALC280", .patch = patch_alc269 }, | 7045 | { .id = 0x10ec0280, .name = "ALC280", .patch = patch_alc269 }, |
7046 | { .id = 0x10ec0282, .name = "ALC282", .patch = patch_alc269 }, | ||
6834 | { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", | 7047 | { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", |
6835 | .patch = patch_alc861 }, | 7048 | .patch = patch_alc861 }, |
6836 | { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd }, | 7049 | { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd }, |