diff options
Diffstat (limited to 'sound/pci/hda/patch_realtek.c')
| -rw-r--r-- | sound/pci/hda/patch_realtek.c | 207 | 
1 files changed, 198 insertions, 9 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index c1ddfd2fac52..b000b36ac3c6 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1058,6 +1058,9 @@ static const struct snd_pci_quirk beep_white_list[] = {  	SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1),  	SND_PCI_QUIRK(0x1458, 0xa002, "GA-MA790X", 1),  	SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1), +	/* blacklist -- no beep available */ +	SND_PCI_QUIRK(0x17aa, 0x309e, "Lenovo ThinkCentre M73", 0), +	SND_PCI_QUIRK(0x17aa, 0x30a3, "Lenovo ThinkCentre M93", 0),  	{}  }; @@ -2841,7 +2844,8 @@ static int patch_alc268(struct hda_codec *codec)  		return err;  	spec = codec->spec; -	spec->gen.beep_nid = 0x01; +	if (has_cdefine_beep(codec)) +		spec->gen.beep_nid = 0x01;  	spec->shutup = alc_eapd_shutup; @@ -3755,6 +3759,72 @@ static void alc269_x101_hp_automute_hook(struct hda_codec *codec,  			    vref);  } +/* + * Magic sequence to make Huawei Matebook X right speaker working (bko#197801) + */ +struct hda_alc298_mbxinit { +	unsigned char value_0x23; +	unsigned char value_0x25; +}; + +static void alc298_huawei_mbx_stereo_seq(struct hda_codec *codec, +					 const struct hda_alc298_mbxinit *initval, +					 bool first) +{ +	snd_hda_codec_write(codec, 0x06, 0, AC_VERB_SET_DIGI_CONVERT_3, 0x0); +	alc_write_coef_idx(codec, 0x26, 0xb000); + +	if (first) +		snd_hda_codec_write(codec, 0x21, 0, AC_VERB_GET_PIN_SENSE, 0x0); + +	snd_hda_codec_write(codec, 0x6, 0, AC_VERB_SET_DIGI_CONVERT_3, 0x80); +	alc_write_coef_idx(codec, 0x26, 0xf000); +	alc_write_coef_idx(codec, 0x23, initval->value_0x23); + +	if (initval->value_0x23 != 0x1e) +		alc_write_coef_idx(codec, 0x25, initval->value_0x25); + +	snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0x26); +	snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, 0xb010); +} + +static void alc298_fixup_huawei_mbx_stereo(struct hda_codec *codec, +					   const struct hda_fixup *fix, +					   int action) +{ +	/* Initialization magic */ +	static const struct hda_alc298_mbxinit dac_init[] = { +		{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00}, +		{0x10, 0x00}, {0x1a, 0x40}, {0x1b, 0x82}, {0x1c, 0x00}, +		{0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00}, +		{0x20, 0xc2}, {0x21, 0xc8}, {0x22, 0x26}, {0x23, 0x24}, +		{0x27, 0xff}, {0x28, 0xff}, {0x29, 0xff}, {0x2a, 0x8f}, +		{0x2b, 0x02}, {0x2c, 0x48}, {0x2d, 0x34}, {0x2e, 0x00}, +		{0x2f, 0x00}, +		{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00}, +		{0x34, 0x00}, {0x35, 0x01}, {0x36, 0x93}, {0x37, 0x0c}, +		{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0xf8}, {0x38, 0x80}, +		{} +	}; +	const struct hda_alc298_mbxinit *seq; + +	if (action != HDA_FIXUP_ACT_INIT) +		return; + +	/* Start */ +	snd_hda_codec_write(codec, 0x06, 0, AC_VERB_SET_DIGI_CONVERT_3, 0x00); +	snd_hda_codec_write(codec, 0x06, 0, AC_VERB_SET_DIGI_CONVERT_3, 0x80); +	alc_write_coef_idx(codec, 0x26, 0xf000); +	alc_write_coef_idx(codec, 0x22, 0x31); +	alc_write_coef_idx(codec, 0x23, 0x0b); +	alc_write_coef_idx(codec, 0x25, 0x00); +	snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0x26); +	snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, 0xb010); + +	for (seq = dac_init; seq->value_0x23; seq++) +		alc298_huawei_mbx_stereo_seq(codec, seq, seq == dac_init); +} +  static void alc269_fixup_x101_headset_mic(struct hda_codec *codec,  				     const struct hda_fixup *fix, int action)  { @@ -5747,6 +5817,7 @@ enum {  	ALC292_FIXUP_DELL_E7X,  	ALC292_FIXUP_DISABLE_AAMIX,  	ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK, +	ALC298_FIXUP_ALIENWARE_MIC_NO_PRESENCE,  	ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,  	ALC298_FIXUP_DELL_AIO_MIC_NO_PRESENCE,  	ALC275_FIXUP_DELL_XPS, @@ -5780,6 +5851,7 @@ enum {  	ALC255_FIXUP_DUMMY_LINEOUT_VERB,  	ALC255_FIXUP_DELL_HEADSET_MIC,  	ALC256_FIXUP_HUAWEI_MACH_WX9_PINS, +	ALC298_FIXUP_HUAWEI_MBX_STEREO,  	ALC295_FIXUP_HP_X360,  	ALC221_FIXUP_HP_HEADSET_MIC,  	ALC285_FIXUP_LENOVO_HEADPHONE_NOISE, @@ -5800,6 +5872,7 @@ enum {  	ALC256_FIXUP_ASUS_MIC_NO_PRESENCE,  	ALC299_FIXUP_PREDATOR_SPK,  	ALC294_FIXUP_ASUS_INTSPK_HEADSET_MIC, +	ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE,  };  static const struct hda_fixup alc269_fixups[] = { @@ -6089,6 +6162,12 @@ static const struct hda_fixup alc269_fixups[] = {  		.chained = true,  		.chain_id = ALC255_FIXUP_MIC_MUTE_LED  	}, +	[ALC298_FIXUP_HUAWEI_MBX_STEREO] = { +		.type = HDA_FIXUP_FUNC, +		.v.func = alc298_fixup_huawei_mbx_stereo, +		.chained = true, +		.chain_id = ALC255_FIXUP_MIC_MUTE_LED +	},  	[ALC269_FIXUP_ASUS_X101_FUNC] = {  		.type = HDA_FIXUP_FUNC,  		.v.func = alc269_fixup_x101_headset_mic, @@ -6429,6 +6508,15 @@ static const struct hda_fixup alc269_fixups[] = {  		.chained = true,  		.chain_id = ALC292_FIXUP_DISABLE_AAMIX  	}, +	[ALC298_FIXUP_ALIENWARE_MIC_NO_PRESENCE] = { +		.type = HDA_FIXUP_PINS, +		.v.pins = (const struct hda_pintbl[]) { +			{ 0x18, 0x01a1913c }, /* headset mic w/o jack detect */ +			{ } +		}, +		.chained_before = true, +		.chain_id = ALC269_FIXUP_HEADSET_MODE, +	},  	[ALC298_FIXUP_DELL1_MIC_NO_PRESENCE] = {  		.type = HDA_FIXUP_PINS,  		.v.pins = (const struct hda_pintbl[]) { @@ -6850,6 +6938,16 @@ static const struct hda_fixup alc269_fixups[] = {  		.chained = true,  		.chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC  	}, +	[ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE] = { +		.type = HDA_FIXUP_PINS, +		.v.pins = (const struct hda_pintbl[]) { +			{ 0x19, 0x04a11040 }, +			{ 0x21, 0x04211020 }, +			{ } +		}, +		.chained = true, +		.chain_id = ALC256_FIXUP_ASUS_HEADSET_MODE +	},  };  static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -7113,6 +7211,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {  	SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),  	SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MACH-WX9", ALC256_FIXUP_HUAWEI_MACH_WX9_PINS),  	SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */ +	SND_PCI_QUIRK(0x10ec, 0x118c, "Medion EE4254 MD62100", ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE),  #if 0  	/* Below is a quirk table taken from the old code. @@ -7280,6 +7379,8 @@ static const struct hda_model_fixup alc269_fixup_models[] = {  	{.id = ALC225_FIXUP_HEADSET_JACK, .name = "alc-headset-jack"},  	{.id = ALC295_FIXUP_CHROME_BOOK, .name = "alc-chrome-book"},  	{.id = ALC299_FIXUP_PREDATOR_SPK, .name = "predator-spk"}, +	{.id = ALC298_FIXUP_HUAWEI_MBX_STEREO, .name = "huawei-mbx-stereo"}, +	{.id = ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE, .name = "alc256-medion-headset"},  	{}  };  #define ALC225_STANDARD_PINS \ @@ -7590,10 +7691,6 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {  		{0x12, 0x90a60120},  		{0x14, 0x90170110},  		{0x21, 0x0321101f}), -	SND_HDA_PIN_QUIRK(0x10ec0289, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE, -		{0x12, 0xb7a60130}, -		{0x14, 0x90170110}, -		{0x21, 0x04211020}),  	SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,  		ALC290_STANDARD_PINS,  		{0x15, 0x04211040}, @@ -7696,6 +7793,11 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {  		{0x17, 0x90170110},  		{0x1a, 0x03011020},  		{0x21, 0x03211030}), +	SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_ALIENWARE_MIC_NO_PRESENCE, +		{0x12, 0xb7a60140}, +		{0x17, 0x90170110}, +		{0x1a, 0x03a11030}, +		{0x21, 0x03211020}),  	SND_HDA_PIN_QUIRK(0x10ec0299, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,  		ALC225_STANDARD_PINS,  		{0x12, 0xb7a60130}, @@ -7703,6 +7805,19 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {  	{}  }; +/* This is the fallback pin_fixup_tbl for alc269 family, to make the tbl match + * more machines, don't need to match all valid pins, just need to match + * all the pins defined in the tbl. Just because of this reason, it is possible + * that a single machine matches multiple tbls, so there is one limitation: + *   at most one tbl is allowed to define for the same vendor and same codec + */ +static const struct snd_hda_pin_quirk alc269_fallback_pin_fixup_tbl[] = { +	SND_HDA_PIN_QUIRK(0x10ec0289, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE, +		{0x19, 0x40000000}, +		{0x1b, 0x40000000}), +	{} +}; +  static void alc269_fill_coef(struct hda_codec *codec)  {  	struct alc_spec *spec = codec->spec; @@ -7892,7 +8007,8 @@ static int patch_alc269(struct hda_codec *codec)  	snd_hda_pick_fixup(codec, alc269_fixup_models,  		       alc269_fixup_tbl, alc269_fixups); -	snd_hda_pick_pin_fixup(codec, alc269_pin_fixup_tbl, alc269_fixups); +	snd_hda_pick_pin_fixup(codec, alc269_pin_fixup_tbl, alc269_fixups, true); +	snd_hda_pick_pin_fixup(codec, alc269_fallback_pin_fixup_tbl, alc269_fixups, false);  	snd_hda_pick_fixup(codec, NULL,	alc269_fixup_vendor_tbl,  			   alc269_fixups);  	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); @@ -8026,7 +8142,8 @@ static int patch_alc861(struct hda_codec *codec)  		return err;  	spec = codec->spec; -	spec->gen.beep_nid = 0x23; +	if (has_cdefine_beep(codec)) +		spec->gen.beep_nid = 0x23;  #ifdef CONFIG_PM  	spec->power_hook = alc_power_eapd; @@ -8127,7 +8244,8 @@ static int patch_alc861vd(struct hda_codec *codec)  		return err;  	spec = codec->spec; -	spec->gen.beep_nid = 0x23; +	if (has_cdefine_beep(codec)) +		spec->gen.beep_nid = 0x23;  	spec->shutup = alc_eapd_shutup; @@ -8267,6 +8385,45 @@ static void alc662_fixup_usi_headset_mic(struct hda_codec *codec,  	}  } +static void alc662_aspire_ethos_mute_speakers(struct hda_codec *codec, +					struct hda_jack_callback *cb) +{ +	/* surround speakers at 0x1b already get muted automatically when +	 * headphones are plugged in, but we have to mute/unmute the remaining +	 * channels manually: +	 * 0x15 - front left/front right +	 * 0x18 - front center/ LFE +	 */ +	if (snd_hda_jack_detect_state(codec, 0x1b) == HDA_JACK_PRESENT) { +		snd_hda_set_pin_ctl_cache(codec, 0x15, 0); +		snd_hda_set_pin_ctl_cache(codec, 0x18, 0); +	} else { +		snd_hda_set_pin_ctl_cache(codec, 0x15, PIN_OUT); +		snd_hda_set_pin_ctl_cache(codec, 0x18, PIN_OUT); +	} +} + +static void alc662_fixup_aspire_ethos_hp(struct hda_codec *codec, +					const struct hda_fixup *fix, int action) +{ +    /* Pin 0x1b: shared headphones jack and surround speakers */ +	if (!is_jack_detectable(codec, 0x1b)) +		return; + +	switch (action) { +	case HDA_FIXUP_ACT_PRE_PROBE: +		snd_hda_jack_detect_enable_callback(codec, 0x1b, +				alc662_aspire_ethos_mute_speakers); +		break; +	case HDA_FIXUP_ACT_INIT: +		/* Make sure to start in a correct state, i.e. if +		 * headphones have been plugged in before powering up the system +		 */ +		alc662_aspire_ethos_mute_speakers(codec, NULL); +		break; +	} +} +  static struct coef_fw alc668_coefs[] = {  	WRITE_COEF(0x01, 0xbebe), WRITE_COEF(0x02, 0xaaaa), WRITE_COEF(0x03,    0x0),  	WRITE_COEF(0x04, 0x0180), WRITE_COEF(0x06,    0x0), WRITE_COEF(0x07, 0x0f80), @@ -8338,6 +8495,9 @@ enum {  	ALC662_FIXUP_USI_FUNC,  	ALC662_FIXUP_USI_HEADSET_MODE,  	ALC662_FIXUP_LENOVO_MULTI_CODECS, +	ALC669_FIXUP_ACER_ASPIRE_ETHOS, +	ALC669_FIXUP_ACER_ASPIRE_ETHOS_SUBWOOFER, +	ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET,  };  static const struct hda_fixup alc662_fixups[] = { @@ -8664,6 +8824,33 @@ static const struct hda_fixup alc662_fixups[] = {  		.type = HDA_FIXUP_FUNC,  		.v.func = alc233_alc662_fixup_lenovo_dual_codecs,  	}, +	[ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET] = { +		.type = HDA_FIXUP_FUNC, +		.v.func = alc662_fixup_aspire_ethos_hp, +	}, +	[ALC669_FIXUP_ACER_ASPIRE_ETHOS_SUBWOOFER] = { +		.type = HDA_FIXUP_VERBS, +		/* subwoofer needs an extra GPIO setting to become audible */ +		.v.verbs = (const struct hda_verb[]) { +			{0x01, AC_VERB_SET_GPIO_MASK, 0x02}, +			{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, +			{0x01, AC_VERB_SET_GPIO_DATA, 0x00}, +			{ } +		}, +		.chained = true, +		.chain_id = ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET +	}, +	[ALC669_FIXUP_ACER_ASPIRE_ETHOS] = { +		.type = HDA_FIXUP_PINS, +		.v.pins = (const struct hda_pintbl[]) { +			{ 0x15, 0x92130110 }, /* front speakers */ +			{ 0x18, 0x99130111 }, /* center/subwoofer */ +			{ 0x1b, 0x11130012 }, /* surround plus jack for HP */ +			{ } +		}, +		.chained = true, +		.chain_id = ALC669_FIXUP_ACER_ASPIRE_ETHOS_SUBWOOFER +	},  };  static const struct snd_pci_quirk alc662_fixup_tbl[] = { @@ -8709,6 +8896,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {  	SND_PCI_QUIRK(0x19da, 0xa130, "Zotac Z68", ALC662_FIXUP_ZOTAC_Z68),  	SND_PCI_QUIRK(0x1b0a, 0x01b8, "ACER Veriton", ALC662_FIXUP_ACER_VERITON),  	SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T), +	SND_PCI_QUIRK(0x1025, 0x0566, "Acer Aspire Ethos 8951G", ALC669_FIXUP_ACER_ASPIRE_ETHOS),  #if 0  	/* Below is a quirk table taken from the old code. @@ -8802,6 +8990,7 @@ static const struct hda_model_fixup alc662_fixup_models[] = {  	{.id = ALC892_FIXUP_ASROCK_MOBO, .name = "asrock-mobo"},  	{.id = ALC662_FIXUP_USI_HEADSET_MODE, .name = "usi-headset"},  	{.id = ALC662_FIXUP_LENOVO_MULTI_CODECS, .name = "dual-codecs"}, +	{.id = ALC669_FIXUP_ACER_ASPIRE_ETHOS, .name = "aspire-ethos"},  	{}  }; @@ -8877,7 +9066,7 @@ static int patch_alc662(struct hda_codec *codec)  	snd_hda_pick_fixup(codec, alc662_fixup_models,  		       alc662_fixup_tbl, alc662_fixups); -	snd_hda_pick_pin_fixup(codec, alc662_pin_fixup_tbl, alc662_fixups); +	snd_hda_pick_pin_fixup(codec, alc662_pin_fixup_tbl, alc662_fixups, true);  	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);  	alc_auto_parse_customize_define(codec);  |