brintos

brintos / linux-shallow public Read only

0
0
Text · 29.6 KiB · 1e9dadc Raw
1177 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * HD audio interface patch for AD1882, AD1884, AD1981HD, AD1983, AD1984,4 *   AD1986A, AD19885 *6 * Copyright (c) 2005-2007 Takashi Iwai <tiwai@suse.de>7 */8 9#include <linux/init.h>10#include <linux/slab.h>11#include <linux/module.h>12 13#include <sound/core.h>14#include <sound/hda_codec.h>15#include "hda_local.h"16#include "hda_auto_parser.h"17#include "hda_beep.h"18#include "hda_jack.h"19#include "hda_generic.h"20 21 22struct ad198x_spec {23	struct hda_gen_spec gen;24 25	/* for auto parser */26	int smux_paths[4];27	unsigned int cur_smux;28	hda_nid_t eapd_nid;29 30	unsigned int beep_amp;	/* beep amp value, set via set_beep_amp() */31	int num_smux_conns;32};33 34 35#ifdef CONFIG_SND_HDA_INPUT_BEEP36/* additional beep mixers; the actual parameters are overwritten at build */37static const struct snd_kcontrol_new ad_beep_mixer[] = {38	HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT),39	HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_OUTPUT),40	{ } /* end */41};42 43#define set_beep_amp(spec, nid, idx, dir) \44	((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */45#else46#define set_beep_amp(spec, nid, idx, dir) /* NOP */47#endif48 49#ifdef CONFIG_SND_HDA_INPUT_BEEP50static int create_beep_ctls(struct hda_codec *codec)51{52	struct ad198x_spec *spec = codec->spec;53	const struct snd_kcontrol_new *knew;54 55	if (!spec->beep_amp)56		return 0;57 58	for (knew = ad_beep_mixer ; knew->name; knew++) {59		int err;60		struct snd_kcontrol *kctl;61		kctl = snd_ctl_new1(knew, codec);62		if (!kctl)63			return -ENOMEM;64		kctl->private_value = spec->beep_amp;65		err = snd_hda_ctl_add(codec, 0, kctl);66		if (err < 0)67			return err;68	}69	return 0;70}71#else72#define create_beep_ctls(codec)		073#endif74 75static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front,76				hda_nid_t hp)77{78	if (snd_hda_query_pin_caps(codec, front) & AC_PINCAP_EAPD)79		snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE,80			    !codec->inv_eapd ? 0x00 : 0x02);81	if (snd_hda_query_pin_caps(codec, hp) & AC_PINCAP_EAPD)82		snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE,83			    !codec->inv_eapd ? 0x00 : 0x02);84}85 86static void ad198x_power_eapd(struct hda_codec *codec)87{88	/* We currently only handle front, HP */89	switch (codec->core.vendor_id) {90	case 0x11d41882:91	case 0x11d4882a:92	case 0x11d41884:93	case 0x11d41984:94	case 0x11d41883:95	case 0x11d4184a:96	case 0x11d4194a:97	case 0x11d4194b:98	case 0x11d41988:99	case 0x11d4198b:100	case 0x11d4989a:101	case 0x11d4989b:102		ad198x_power_eapd_write(codec, 0x12, 0x11);103		break;104	case 0x11d41981:105	case 0x11d41983:106		ad198x_power_eapd_write(codec, 0x05, 0x06);107		break;108	case 0x11d41986:109		ad198x_power_eapd_write(codec, 0x1b, 0x1a);110		break;111	}112}113 114static int ad198x_suspend(struct hda_codec *codec)115{116	snd_hda_shutup_pins(codec);117	ad198x_power_eapd(codec);118	return 0;119}120 121/* follow EAPD via vmaster hook */122static void ad_vmaster_eapd_hook(void *private_data, int enabled)123{124	struct hda_codec *codec = private_data;125	struct ad198x_spec *spec = codec->spec;126 127	if (!spec->eapd_nid)128		return;129	if (codec->inv_eapd)130		enabled = !enabled;131	snd_hda_codec_write_cache(codec, spec->eapd_nid, 0,132				   AC_VERB_SET_EAPD_BTLENABLE,133				   enabled ? 0x02 : 0x00);134}135 136/*137 * Automatic parse of I/O pins from the BIOS configuration138 */139 140static int ad198x_auto_build_controls(struct hda_codec *codec)141{142	int err;143 144	err = snd_hda_gen_build_controls(codec);145	if (err < 0)146		return err;147	err = create_beep_ctls(codec);148	if (err < 0)149		return err;150	return 0;151}152 153static const struct hda_codec_ops ad198x_auto_patch_ops = {154	.build_controls = ad198x_auto_build_controls,155	.build_pcms = snd_hda_gen_build_pcms,156	.init = snd_hda_gen_init,157	.free = snd_hda_gen_free,158	.unsol_event = snd_hda_jack_unsol_event,159	.check_power_status = snd_hda_gen_check_power_status,160	.suspend = ad198x_suspend,161};162 163 164static int ad198x_parse_auto_config(struct hda_codec *codec, bool indep_hp)165{166	struct ad198x_spec *spec = codec->spec;167	struct auto_pin_cfg *cfg = &spec->gen.autocfg;168	int err;169 170	codec->spdif_status_reset = 1;171	codec->no_trigger_sense = 1;172	codec->no_sticky_stream = 1;173 174	spec->gen.indep_hp = indep_hp;175	if (!spec->gen.add_stereo_mix_input)176		spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;177 178	err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);179	if (err < 0)180		return err;181	err = snd_hda_gen_parse_auto_config(codec, cfg);182	if (err < 0)183		return err;184 185	return 0;186}187 188/*189 * AD1986A specific190 */191 192static int alloc_ad_spec(struct hda_codec *codec)193{194	struct ad198x_spec *spec;195 196	spec = kzalloc(sizeof(*spec), GFP_KERNEL);197	if (!spec)198		return -ENOMEM;199	codec->spec = spec;200	snd_hda_gen_spec_init(&spec->gen);201	codec->patch_ops = ad198x_auto_patch_ops;202	return 0;203}204 205/*206 * AD1986A fixup codes207 */208 209/* Lenovo N100 seems to report the reversed bit for HP jack-sensing */210static void ad_fixup_inv_jack_detect(struct hda_codec *codec,211				     const struct hda_fixup *fix, int action)212{213	struct ad198x_spec *spec = codec->spec;214 215	if (action == HDA_FIXUP_ACT_PRE_PROBE) {216		codec->inv_jack_detect = 1;217		spec->gen.keep_eapd_on = 1;218		spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;219		spec->eapd_nid = 0x1b;220	}221}222 223/* Toshiba Satellite L40 implements EAPD in a standard way unlike others */224static void ad1986a_fixup_eapd(struct hda_codec *codec,225			       const struct hda_fixup *fix, int action)226{227	struct ad198x_spec *spec = codec->spec;228 229	if (action == HDA_FIXUP_ACT_PRE_PROBE) {230		codec->inv_eapd = 0;231		spec->gen.keep_eapd_on = 1;232		spec->eapd_nid = 0x1b;233	}234}235 236/* enable stereo-mix input for avoiding regression on KDE (bko#88251) */237static void ad1986a_fixup_eapd_mix_in(struct hda_codec *codec,238				      const struct hda_fixup *fix, int action)239{240	struct ad198x_spec *spec = codec->spec;241 242	if (action == HDA_FIXUP_ACT_PRE_PROBE) {243		ad1986a_fixup_eapd(codec, fix, action);244		spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_ENABLE;245	}246}247 248enum {249	AD1986A_FIXUP_INV_JACK_DETECT,250	AD1986A_FIXUP_ULTRA,251	AD1986A_FIXUP_SAMSUNG,252	AD1986A_FIXUP_3STACK,253	AD1986A_FIXUP_LAPTOP,254	AD1986A_FIXUP_LAPTOP_IMIC,255	AD1986A_FIXUP_EAPD,256	AD1986A_FIXUP_EAPD_MIX_IN,257	AD1986A_FIXUP_EASYNOTE,258};259 260static const struct hda_fixup ad1986a_fixups[] = {261	[AD1986A_FIXUP_INV_JACK_DETECT] = {262		.type = HDA_FIXUP_FUNC,263		.v.func = ad_fixup_inv_jack_detect,264	},265	[AD1986A_FIXUP_ULTRA] = {266		.type = HDA_FIXUP_PINS,267		.v.pins = (const struct hda_pintbl[]) {268			{ 0x1b, 0x90170110 }, /* speaker */269			{ 0x1d, 0x90a7013e }, /* int mic */270			{}271		},272	},273	[AD1986A_FIXUP_SAMSUNG] = {274		.type = HDA_FIXUP_PINS,275		.v.pins = (const struct hda_pintbl[]) {276			{ 0x1b, 0x90170110 }, /* speaker */277			{ 0x1d, 0x90a7013e }, /* int mic */278			{ 0x20, 0x411111f0 }, /* N/A */279			{ 0x24, 0x411111f0 }, /* N/A */280			{}281		},282	},283	[AD1986A_FIXUP_3STACK] = {284		.type = HDA_FIXUP_PINS,285		.v.pins = (const struct hda_pintbl[]) {286			{ 0x1a, 0x02214021 }, /* headphone */287			{ 0x1b, 0x01014011 }, /* front */288			{ 0x1c, 0x01813030 }, /* line-in */289			{ 0x1d, 0x01a19020 }, /* rear mic */290			{ 0x1e, 0x411111f0 }, /* N/A */291			{ 0x1f, 0x02a190f0 }, /* mic */292			{ 0x20, 0x411111f0 }, /* N/A */293			{}294		},295	},296	[AD1986A_FIXUP_LAPTOP] = {297		.type = HDA_FIXUP_PINS,298		.v.pins = (const struct hda_pintbl[]) {299			{ 0x1a, 0x02214021 }, /* headphone */300			{ 0x1b, 0x90170110 }, /* speaker */301			{ 0x1c, 0x411111f0 }, /* N/A */302			{ 0x1d, 0x411111f0 }, /* N/A */303			{ 0x1e, 0x411111f0 }, /* N/A */304			{ 0x1f, 0x02a191f0 }, /* mic */305			{ 0x20, 0x411111f0 }, /* N/A */306			{}307		},308	},309	[AD1986A_FIXUP_LAPTOP_IMIC] = {310		.type = HDA_FIXUP_PINS,311		.v.pins = (const struct hda_pintbl[]) {312			{ 0x1d, 0x90a7013e }, /* int mic */313			{}314		},315		.chained_before = 1,316		.chain_id = AD1986A_FIXUP_LAPTOP,317	},318	[AD1986A_FIXUP_EAPD] = {319		.type = HDA_FIXUP_FUNC,320		.v.func = ad1986a_fixup_eapd,321	},322	[AD1986A_FIXUP_EAPD_MIX_IN] = {323		.type = HDA_FIXUP_FUNC,324		.v.func = ad1986a_fixup_eapd_mix_in,325	},326	[AD1986A_FIXUP_EASYNOTE] = {327		.type = HDA_FIXUP_PINS,328		.v.pins = (const struct hda_pintbl[]) {329			{ 0x1a, 0x0421402f }, /* headphone */330			{ 0x1b, 0x90170110 }, /* speaker */331			{ 0x1c, 0x411111f0 }, /* N/A */332			{ 0x1d, 0x90a70130 }, /* int mic */333			{ 0x1e, 0x411111f0 }, /* N/A */334			{ 0x1f, 0x04a19040 }, /* mic */335			{ 0x20, 0x411111f0 }, /* N/A */336			{ 0x21, 0x411111f0 }, /* N/A */337			{ 0x22, 0x411111f0 }, /* N/A */338			{ 0x23, 0x411111f0 }, /* N/A */339			{ 0x24, 0x411111f0 }, /* N/A */340			{ 0x25, 0x411111f0 }, /* N/A */341			{}342		},343		.chained = true,344		.chain_id = AD1986A_FIXUP_EAPD_MIX_IN,345	},346};347 348static const struct snd_pci_quirk ad1986a_fixup_tbl[] = {349	SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_FIXUP_LAPTOP_IMIC),350	SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9V", AD1986A_FIXUP_LAPTOP_IMIC),351	SND_PCI_QUIRK(0x1043, 0x1443, "ASUS Z99He", AD1986A_FIXUP_EAPD),352	SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8JN", AD1986A_FIXUP_EAPD),353	SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8100, "ASUS P5", AD1986A_FIXUP_3STACK),354	SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8200, "ASUS M2", AD1986A_FIXUP_3STACK),355	SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_FIXUP_3STACK),356	SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40", AD1986A_FIXUP_EAPD),357	SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_FIXUP_LAPTOP),358	SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_FIXUP_SAMSUNG),359	SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_FIXUP_ULTRA),360	SND_PCI_QUIRK(0x1631, 0xc022, "PackardBell EasyNote MX65", AD1986A_FIXUP_EASYNOTE),361	SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT),362	SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_FIXUP_3STACK),363	SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_FIXUP_3STACK),364	{}365};366 367static const struct hda_model_fixup ad1986a_fixup_models[] = {368	{ .id = AD1986A_FIXUP_3STACK, .name = "3stack" },369	{ .id = AD1986A_FIXUP_LAPTOP, .name = "laptop" },370	{ .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-imic" },371	{ .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-eapd" }, /* alias */372	{ .id = AD1986A_FIXUP_EAPD, .name = "eapd" },373	{}374};375 376/*377 */378static int patch_ad1986a(struct hda_codec *codec)379{380	int err;381	struct ad198x_spec *spec;382	static const hda_nid_t preferred_pairs[] = {383		0x1a, 0x03,384		0x1b, 0x03,385		0x1c, 0x04,386		0x1d, 0x05,387		0x1e, 0x03,388		0389	};390 391	err = alloc_ad_spec(codec);392	if (err < 0)393		return err;394	spec = codec->spec;395 396	/* AD1986A has the inverted EAPD implementation */397	codec->inv_eapd = 1;398 399	spec->gen.mixer_nid = 0x07;400	spec->gen.beep_nid = 0x19;401	set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);402 403	/* AD1986A has a hardware problem that it can't share a stream404	 * with multiple output pins.  The copy of front to surrounds405	 * causes noisy or silent outputs at a certain timing, e.g.406	 * changing the volume.407	 * So, let's disable the shared stream.408	 */409	spec->gen.multiout.no_share_stream = 1;410	/* give fixed DAC/pin pairs */411	spec->gen.preferred_dacs = preferred_pairs;412 413	/* AD1986A can't manage the dynamic pin on/off smoothly */414	spec->gen.auto_mute_via_amp = 1;415 416	snd_hda_pick_fixup(codec, ad1986a_fixup_models, ad1986a_fixup_tbl,417			   ad1986a_fixups);418	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);419 420	err = ad198x_parse_auto_config(codec, false);421	if (err < 0) {422		snd_hda_gen_free(codec);423		return err;424	}425 426	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);427 428	return 0;429}430 431 432/*433 * AD1983 specific434 */435 436/*437 * SPDIF mux control for AD1983 auto-parser438 */439static int ad1983_auto_smux_enum_info(struct snd_kcontrol *kcontrol,440				      struct snd_ctl_elem_info *uinfo)441{442	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);443	struct ad198x_spec *spec = codec->spec;444	static const char * const texts2[] = { "PCM", "ADC" };445	static const char * const texts3[] = { "PCM", "ADC1", "ADC2" };446	int num_conns = spec->num_smux_conns;447 448	if (num_conns == 2)449		return snd_hda_enum_helper_info(kcontrol, uinfo, 2, texts2);450	else if (num_conns == 3)451		return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3);452	else453		return -EINVAL;454}455 456static int ad1983_auto_smux_enum_get(struct snd_kcontrol *kcontrol,457				     struct snd_ctl_elem_value *ucontrol)458{459	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);460	struct ad198x_spec *spec = codec->spec;461 462	ucontrol->value.enumerated.item[0] = spec->cur_smux;463	return 0;464}465 466static int ad1983_auto_smux_enum_put(struct snd_kcontrol *kcontrol,467				     struct snd_ctl_elem_value *ucontrol)468{469	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);470	struct ad198x_spec *spec = codec->spec;471	unsigned int val = ucontrol->value.enumerated.item[0];472	hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;473	int num_conns = spec->num_smux_conns;474 475	if (val >= num_conns)476		return -EINVAL;477	if (spec->cur_smux == val)478		return 0;479	spec->cur_smux = val;480	snd_hda_codec_write_cache(codec, dig_out, 0,481				  AC_VERB_SET_CONNECT_SEL, val);482	return 1;483}484 485static const struct snd_kcontrol_new ad1983_auto_smux_mixer = {486	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,487	.name = "IEC958 Playback Source",488	.info = ad1983_auto_smux_enum_info,489	.get = ad1983_auto_smux_enum_get,490	.put = ad1983_auto_smux_enum_put,491};492 493static int ad1983_add_spdif_mux_ctl(struct hda_codec *codec)494{495	struct ad198x_spec *spec = codec->spec;496	hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;497	int num_conns;498 499	if (!dig_out)500		return 0;501	num_conns = snd_hda_get_num_conns(codec, dig_out);502	if (num_conns != 2 && num_conns != 3)503		return 0;504	spec->num_smux_conns = num_conns;505	if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1983_auto_smux_mixer))506		return -ENOMEM;507	return 0;508}509 510static int patch_ad1983(struct hda_codec *codec)511{512	static const hda_nid_t conn_0c[] = { 0x08 };513	static const hda_nid_t conn_0d[] = { 0x09 };514	struct ad198x_spec *spec;515	int err;516 517	err = alloc_ad_spec(codec);518	if (err < 0)519		return err;520	spec = codec->spec;521 522	spec->gen.mixer_nid = 0x0e;523	spec->gen.beep_nid = 0x10;524	set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);525 526	/* limit the loopback routes not to confuse the parser */527	snd_hda_override_conn_list(codec, 0x0c, ARRAY_SIZE(conn_0c), conn_0c);528	snd_hda_override_conn_list(codec, 0x0d, ARRAY_SIZE(conn_0d), conn_0d);529 530	err = ad198x_parse_auto_config(codec, false);531	if (err < 0)532		goto error;533	err = ad1983_add_spdif_mux_ctl(codec);534	if (err < 0)535		goto error;536	return 0;537 538 error:539	snd_hda_gen_free(codec);540	return err;541}542 543 544/*545 * AD1981 HD specific546 */547 548static void ad1981_fixup_hp_eapd(struct hda_codec *codec,549				 const struct hda_fixup *fix, int action)550{551	struct ad198x_spec *spec = codec->spec;552 553	if (action == HDA_FIXUP_ACT_PRE_PROBE) {554		spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;555		spec->eapd_nid = 0x05;556	}557}558 559/* set the upper-limit for mixer amp to 0dB for avoiding the possible560 * damage by overloading561 */562static void ad1981_fixup_amp_override(struct hda_codec *codec,563				      const struct hda_fixup *fix, int action)564{565	if (action == HDA_FIXUP_ACT_PRE_PROBE)566		snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,567					  (0x17 << AC_AMPCAP_OFFSET_SHIFT) |568					  (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |569					  (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |570					  (1 << AC_AMPCAP_MUTE_SHIFT));571}572 573enum {574	AD1981_FIXUP_AMP_OVERRIDE,575	AD1981_FIXUP_HP_EAPD,576};577 578static const struct hda_fixup ad1981_fixups[] = {579	[AD1981_FIXUP_AMP_OVERRIDE] = {580		.type = HDA_FIXUP_FUNC,581		.v.func = ad1981_fixup_amp_override,582	},583	[AD1981_FIXUP_HP_EAPD] = {584		.type = HDA_FIXUP_FUNC,585		.v.func = ad1981_fixup_hp_eapd,586		.chained = true,587		.chain_id = AD1981_FIXUP_AMP_OVERRIDE,588	},589};590 591static const struct snd_pci_quirk ad1981_fixup_tbl[] = {592	SND_PCI_QUIRK_VENDOR(0x1014, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE),593	SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1981_FIXUP_HP_EAPD),594	SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE),595	/* HP nx6320 (reversed SSID, H/W bug) */596	SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_FIXUP_HP_EAPD),597	{}598};599 600static int patch_ad1981(struct hda_codec *codec)601{602	struct ad198x_spec *spec;603	int err;604 605	err = alloc_ad_spec(codec);606	if (err < 0)607		return -ENOMEM;608	spec = codec->spec;609 610	spec->gen.mixer_nid = 0x0e;611	spec->gen.beep_nid = 0x10;612	set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);613 614	snd_hda_pick_fixup(codec, NULL, ad1981_fixup_tbl, ad1981_fixups);615	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);616 617	err = ad198x_parse_auto_config(codec, false);618	if (err < 0)619		goto error;620	err = ad1983_add_spdif_mux_ctl(codec);621	if (err < 0)622		goto error;623 624	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);625 626	return 0;627 628 error:629	snd_hda_gen_free(codec);630	return err;631}632 633 634/*635 * AD1988636 *637 * Output pins and routes638 *639 *        Pin               Mix     Sel     DAC (*)640 * port-A 0x11 (mute/hp) <- 0x22 <- 0x37 <- 03/04/06641 * port-B 0x14 (mute/hp) <- 0x2b <- 0x30 <- 03/04/06642 * port-C 0x15 (mute)    <- 0x2c <- 0x31 <- 05/0a643 * port-D 0x12 (mute/hp) <- 0x29         <- 04644 * port-E 0x17 (mute/hp) <- 0x26 <- 0x32 <- 05/0a645 * port-F 0x16 (mute)    <- 0x2a         <- 06646 * port-G 0x24 (mute)    <- 0x27         <- 05647 * port-H 0x25 (mute)    <- 0x28         <- 0a648 * mono   0x13 (mute/amp)<- 0x1e <- 0x36 <- 03/04/06649 *650 * DAC0 = 03h, DAC1 = 04h, DAC2 = 05h, DAC3 = 06h, DAC4 = 0ah651 * (*) DAC2/3/4 are swapped to DAC3/4/2 on AD198A rev.2 due to a h/w bug.652 *653 * Input pins and routes654 *655 *        pin     boost   mix input # / adc input #656 * port-A 0x11 -> 0x38 -> mix 2, ADC 0657 * port-B 0x14 -> 0x39 -> mix 0, ADC 1658 * port-C 0x15 -> 0x3a -> 33:0 - mix 1, ADC 2659 * port-D 0x12 -> 0x3d -> mix 3, ADC 8660 * port-E 0x17 -> 0x3c -> 34:0 - mix 4, ADC 4661 * port-F 0x16 -> 0x3b -> mix 5, ADC 3662 * port-G 0x24 -> N/A  -> 33:1 - mix 1, 34:1 - mix 4, ADC 6663 * port-H 0x25 -> N/A  -> 33:2 - mix 1, 34:2 - mix 4, ADC 7664 *665 *666 * DAC assignment667 *   6stack - front/surr/CLFE/side/opt DACs - 04/06/05/0a/03668 *   3stack - front/surr/CLFE/opt DACs - 04/05/0a/03669 *670 * Inputs of Analog Mix (0x20)671 *   0:Port-B (front mic)672 *   1:Port-C/G/H (line-in)673 *   2:Port-A674 *   3:Port-D (line-in/2)675 *   4:Port-E/G/H (mic-in)676 *   5:Port-F (mic2-in)677 *   6:CD678 *   7:Beep679 *680 * ADC selection681 *   0:Port-A682 *   1:Port-B (front mic-in)683 *   2:Port-C (line-in)684 *   3:Port-F (mic2-in)685 *   4:Port-E (mic-in)686 *   5:CD687 *   6:Port-G688 *   7:Port-H689 *   8:Port-D (line-in/2)690 *   9:Mix691 *692 * Proposed pin assignments by the datasheet693 *694 * 6-stack695 * Port-A front headphone696 *      B front mic-in697 *      C rear line-in698 *      D rear front-out699 *      E rear mic-in700 *      F rear surround701 *      G rear CLFE702 *      H rear side703 *704 * 3-stack705 * Port-A front headphone706 *      B front mic707 *      C rear line-in/surround708 *      D rear front-out709 *      E rear mic-in/CLFE710 *711 * laptop712 * Port-A headphone713 *      B mic-in714 *      C docking station715 *      D internal speaker (with EAPD)716 *      E/F quad mic array717 */718 719static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol,720				      struct snd_ctl_elem_info *uinfo)721{722	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);723	struct ad198x_spec *spec = codec->spec;724	static const char * const texts[] = {725		"PCM", "ADC1", "ADC2", "ADC3",726	};727	int num_conns = spec->num_smux_conns;728 729	if (num_conns > 4)730		num_conns = 4;731	return snd_hda_enum_helper_info(kcontrol, uinfo, num_conns, texts);732}733 734static int ad1988_auto_smux_enum_get(struct snd_kcontrol *kcontrol,735				     struct snd_ctl_elem_value *ucontrol)736{737	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);738	struct ad198x_spec *spec = codec->spec;739 740	ucontrol->value.enumerated.item[0] = spec->cur_smux;741	return 0;742}743 744static int ad1988_auto_smux_enum_put(struct snd_kcontrol *kcontrol,745				     struct snd_ctl_elem_value *ucontrol)746{747	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);748	struct ad198x_spec *spec = codec->spec;749	unsigned int val = ucontrol->value.enumerated.item[0];750	struct nid_path *path;751	int num_conns = spec->num_smux_conns;752 753	if (val >= num_conns)754		return -EINVAL;755	if (spec->cur_smux == val)756		return 0;757 758	mutex_lock(&codec->control_mutex);759	path = snd_hda_get_path_from_idx(codec,760					 spec->smux_paths[spec->cur_smux]);761	if (path)762		snd_hda_activate_path(codec, path, false, true);763	path = snd_hda_get_path_from_idx(codec, spec->smux_paths[val]);764	if (path)765		snd_hda_activate_path(codec, path, true, true);766	spec->cur_smux = val;767	mutex_unlock(&codec->control_mutex);768	return 1;769}770 771static const struct snd_kcontrol_new ad1988_auto_smux_mixer = {772	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,773	.name = "IEC958 Playback Source",774	.info = ad1988_auto_smux_enum_info,775	.get = ad1988_auto_smux_enum_get,776	.put = ad1988_auto_smux_enum_put,777};778 779static int ad1988_auto_init(struct hda_codec *codec)780{781	struct ad198x_spec *spec = codec->spec;782	int i, err;783 784	err = snd_hda_gen_init(codec);785	if (err < 0)786		return err;787	if (!spec->gen.autocfg.dig_outs)788		return 0;789 790	for (i = 0; i < 4; i++) {791		struct nid_path *path;792		path = snd_hda_get_path_from_idx(codec, spec->smux_paths[i]);793		if (path)794			snd_hda_activate_path(codec, path, path->active, false);795	}796 797	return 0;798}799 800static int ad1988_add_spdif_mux_ctl(struct hda_codec *codec)801{802	struct ad198x_spec *spec = codec->spec;803	int i, num_conns;804	/* we create four static faked paths, since AD codecs have odd805	 * widget connections regarding the SPDIF out source806	 */807	static const struct nid_path fake_paths[4] = {808		{809			.depth = 3,810			.path = { 0x02, 0x1d, 0x1b },811			.idx = { 0, 0, 0 },812			.multi = { 0, 0, 0 },813		},814		{815			.depth = 4,816			.path = { 0x08, 0x0b, 0x1d, 0x1b },817			.idx = { 0, 0, 1, 0 },818			.multi = { 0, 1, 0, 0 },819		},820		{821			.depth = 4,822			.path = { 0x09, 0x0b, 0x1d, 0x1b },823			.idx = { 0, 1, 1, 0 },824			.multi = { 0, 1, 0, 0 },825		},826		{827			.depth = 4,828			.path = { 0x0f, 0x0b, 0x1d, 0x1b },829			.idx = { 0, 2, 1, 0 },830			.multi = { 0, 1, 0, 0 },831		},832	};833 834	/* SPDIF source mux appears to be present only on AD1988A */835	if (!spec->gen.autocfg.dig_outs ||836	    get_wcaps_type(get_wcaps(codec, 0x1d)) != AC_WID_AUD_MIX)837		return 0;838 839	num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;840	if (num_conns != 3 && num_conns != 4)841		return 0;842	spec->num_smux_conns = num_conns;843 844	for (i = 0; i < num_conns; i++) {845		struct nid_path *path = snd_array_new(&spec->gen.paths);846		if (!path)847			return -ENOMEM;848		*path = fake_paths[i];849		if (!i)850			path->active = 1;851		spec->smux_paths[i] = snd_hda_get_path_idx(codec, path);852	}853 854	if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1988_auto_smux_mixer))855		return -ENOMEM;856 857	codec->patch_ops.init = ad1988_auto_init;858 859	return 0;860}861 862/*863 */864 865enum {866	AD1988_FIXUP_6STACK_DIG,867};868 869static const struct hda_fixup ad1988_fixups[] = {870	[AD1988_FIXUP_6STACK_DIG] = {871		.type = HDA_FIXUP_PINS,872		.v.pins = (const struct hda_pintbl[]) {873			{ 0x11, 0x02214130 }, /* front-hp */874			{ 0x12, 0x01014010 }, /* line-out */875			{ 0x14, 0x02a19122 }, /* front-mic */876			{ 0x15, 0x01813021 }, /* line-in */877			{ 0x16, 0x01011012 }, /* line-out */878			{ 0x17, 0x01a19020 }, /* mic */879			{ 0x1b, 0x0145f1f0 }, /* SPDIF */880			{ 0x24, 0x01016011 }, /* line-out */881			{ 0x25, 0x01012013 }, /* line-out */882			{ }883		}884	},885};886 887static const struct hda_model_fixup ad1988_fixup_models[] = {888	{ .id = AD1988_FIXUP_6STACK_DIG, .name = "6stack-dig" },889	{}890};891 892static int patch_ad1988(struct hda_codec *codec)893{894	struct ad198x_spec *spec;895	int err;896 897	err = alloc_ad_spec(codec);898	if (err < 0)899		return err;900	spec = codec->spec;901 902	spec->gen.mixer_nid = 0x20;903	spec->gen.mixer_merge_nid = 0x21;904	spec->gen.beep_nid = 0x10;905	set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);906 907	snd_hda_pick_fixup(codec, ad1988_fixup_models, NULL, ad1988_fixups);908	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);909 910	err = ad198x_parse_auto_config(codec, true);911	if (err < 0)912		goto error;913	err = ad1988_add_spdif_mux_ctl(codec);914	if (err < 0)915		goto error;916 917	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);918 919	return 0;920 921 error:922	snd_hda_gen_free(codec);923	return err;924}925 926 927/*928 * AD1884 / AD1984929 *930 * port-B - front line/mic-in931 * port-E - aux in/out932 * port-F - aux in/out933 * port-C - rear line/mic-in934 * port-D - rear line/hp-out935 * port-A - front line/hp-out936 *937 * AD1984 = AD1884 + two digital mic-ins938 *939 * AD1883 / AD1884A / AD1984A / AD1984B940 *941 * port-B (0x14) - front mic-in942 * port-E (0x1c) - rear mic-in943 * port-F (0x16) - CD / ext out944 * port-C (0x15) - rear line-in945 * port-D (0x12) - rear line-out946 * port-A (0x11) - front hp-out947 *948 * AD1984A = AD1884A + digital-mic949 * AD1883 = equivalent with AD1984A950 * AD1984B = AD1984A + extra SPDIF-out951 */952 953/* set the upper-limit for mixer amp to 0dB for avoiding the possible954 * damage by overloading955 */956static void ad1884_fixup_amp_override(struct hda_codec *codec,957				      const struct hda_fixup *fix, int action)958{959	if (action == HDA_FIXUP_ACT_PRE_PROBE)960		snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,961					  (0x17 << AC_AMPCAP_OFFSET_SHIFT) |962					  (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |963					  (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |964					  (1 << AC_AMPCAP_MUTE_SHIFT));965}966 967/* toggle GPIO1 according to the mute state */968static void ad1884_vmaster_hp_gpio_hook(void *private_data, int enabled)969{970	struct hda_codec *codec = private_data;971	struct ad198x_spec *spec = codec->spec;972 973	if (spec->eapd_nid)974		ad_vmaster_eapd_hook(private_data, enabled);975	snd_hda_codec_write_cache(codec, 0x01, 0,976				   AC_VERB_SET_GPIO_DATA,977				   enabled ? 0x00 : 0x02);978}979 980static void ad1884_fixup_hp_eapd(struct hda_codec *codec,981				 const struct hda_fixup *fix, int action)982{983	struct ad198x_spec *spec = codec->spec;984 985	switch (action) {986	case HDA_FIXUP_ACT_PRE_PROBE:987		spec->gen.vmaster_mute.hook = ad1884_vmaster_hp_gpio_hook;988		spec->gen.own_eapd_ctl = 1;989		snd_hda_codec_write_cache(codec, 0x01, 0,990					  AC_VERB_SET_GPIO_MASK, 0x02);991		snd_hda_codec_write_cache(codec, 0x01, 0,992					  AC_VERB_SET_GPIO_DIRECTION, 0x02);993		snd_hda_codec_write_cache(codec, 0x01, 0,994					  AC_VERB_SET_GPIO_DATA, 0x02);995		break;996	case HDA_FIXUP_ACT_PROBE:997		if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)998			spec->eapd_nid = spec->gen.autocfg.line_out_pins[0];999		else1000			spec->eapd_nid = spec->gen.autocfg.speaker_pins[0];1001		break;1002	}1003}1004 1005static void ad1884_fixup_thinkpad(struct hda_codec *codec,1006				  const struct hda_fixup *fix, int action)1007{1008	struct ad198x_spec *spec = codec->spec;1009 1010	if (action == HDA_FIXUP_ACT_PRE_PROBE) {1011		spec->gen.keep_eapd_on = 1;1012		spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;1013		spec->eapd_nid = 0x12;1014		/* Analog PC Beeper - allow firmware/ACPI beeps */1015		spec->beep_amp = HDA_COMPOSE_AMP_VAL(0x20, 3, 3, HDA_INPUT);1016		spec->gen.beep_nid = 0; /* no digital beep */1017	}1018}1019 1020/* set magic COEFs for dmic */1021static const struct hda_verb ad1884_dmic_init_verbs[] = {1022	{0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},1023	{0x01, AC_VERB_SET_PROC_COEF, 0x08},1024	{}1025};1026 1027enum {1028	AD1884_FIXUP_AMP_OVERRIDE,1029	AD1884_FIXUP_HP_EAPD,1030	AD1884_FIXUP_DMIC_COEF,1031	AD1884_FIXUP_THINKPAD,1032	AD1884_FIXUP_HP_TOUCHSMART,1033};1034 1035static const struct hda_fixup ad1884_fixups[] = {1036	[AD1884_FIXUP_AMP_OVERRIDE] = {1037		.type = HDA_FIXUP_FUNC,1038		.v.func = ad1884_fixup_amp_override,1039	},1040	[AD1884_FIXUP_HP_EAPD] = {1041		.type = HDA_FIXUP_FUNC,1042		.v.func = ad1884_fixup_hp_eapd,1043		.chained = true,1044		.chain_id = AD1884_FIXUP_AMP_OVERRIDE,1045	},1046	[AD1884_FIXUP_DMIC_COEF] = {1047		.type = HDA_FIXUP_VERBS,1048		.v.verbs = ad1884_dmic_init_verbs,1049	},1050	[AD1884_FIXUP_THINKPAD] = {1051		.type = HDA_FIXUP_FUNC,1052		.v.func = ad1884_fixup_thinkpad,1053		.chained = true,1054		.chain_id = AD1884_FIXUP_DMIC_COEF,1055	},1056	[AD1884_FIXUP_HP_TOUCHSMART] = {1057		.type = HDA_FIXUP_VERBS,1058		.v.verbs = ad1884_dmic_init_verbs,1059		.chained = true,1060		.chain_id = AD1884_FIXUP_HP_EAPD,1061	},1062};1063 1064static const struct snd_pci_quirk ad1884_fixup_tbl[] = {1065	SND_PCI_QUIRK(0x103c, 0x2a82, "HP Touchsmart", AD1884_FIXUP_HP_TOUCHSMART),1066	SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD),1067	SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1884_FIXUP_THINKPAD),1068	{}1069};1070 1071 1072static int patch_ad1884(struct hda_codec *codec)1073{1074	struct ad198x_spec *spec;1075	int err;1076 1077	err = alloc_ad_spec(codec);1078	if (err < 0)1079		return err;1080	spec = codec->spec;1081 1082	spec->gen.mixer_nid = 0x20;1083	spec->gen.mixer_merge_nid = 0x21;1084	spec->gen.beep_nid = 0x10;1085	set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);1086 1087	snd_hda_pick_fixup(codec, NULL, ad1884_fixup_tbl, ad1884_fixups);1088	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);1089 1090	err = ad198x_parse_auto_config(codec, true);1091	if (err < 0)1092		goto error;1093	err = ad1983_add_spdif_mux_ctl(codec);1094	if (err < 0)1095		goto error;1096 1097	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);1098 1099	return 0;1100 1101 error:1102	snd_hda_gen_free(codec);1103	return err;1104}1105 1106/*1107 * AD1882 / AD1882A1108 *1109 * port-A - front hp-out1110 * port-B - front mic-in1111 * port-C - rear line-in, shared surr-out (3stack)1112 * port-D - rear line-out1113 * port-E - rear mic-in, shared clfe-out (3stack)1114 * port-F - rear surr-out (6stack)1115 * port-G - rear clfe-out (6stack)1116 */1117 1118static int patch_ad1882(struct hda_codec *codec)1119{1120	struct ad198x_spec *spec;1121	int err;1122 1123	err = alloc_ad_spec(codec);1124	if (err < 0)1125		return err;1126	spec = codec->spec;1127 1128	spec->gen.mixer_nid = 0x20;1129	spec->gen.mixer_merge_nid = 0x21;1130	spec->gen.beep_nid = 0x10;1131	set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);1132	err = ad198x_parse_auto_config(codec, true);1133	if (err < 0)1134		goto error;1135	err = ad1988_add_spdif_mux_ctl(codec);1136	if (err < 0)1137		goto error;1138	return 0;1139 1140 error:1141	snd_hda_gen_free(codec);1142	return err;1143}1144 1145 1146/*1147 * patch entries1148 */1149static const struct hda_device_id snd_hda_id_analog[] = {1150	HDA_CODEC_ENTRY(0x11d4184a, "AD1884A", patch_ad1884),1151	HDA_CODEC_ENTRY(0x11d41882, "AD1882", patch_ad1882),1152	HDA_CODEC_ENTRY(0x11d41883, "AD1883", patch_ad1884),1153	HDA_CODEC_ENTRY(0x11d41884, "AD1884", patch_ad1884),1154	HDA_CODEC_ENTRY(0x11d4194a, "AD1984A", patch_ad1884),1155	HDA_CODEC_ENTRY(0x11d4194b, "AD1984B", patch_ad1884),1156	HDA_CODEC_ENTRY(0x11d41981, "AD1981", patch_ad1981),1157	HDA_CODEC_ENTRY(0x11d41983, "AD1983", patch_ad1983),1158	HDA_CODEC_ENTRY(0x11d41984, "AD1984", patch_ad1884),1159	HDA_CODEC_ENTRY(0x11d41986, "AD1986A", patch_ad1986a),1160	HDA_CODEC_ENTRY(0x11d41988, "AD1988", patch_ad1988),1161	HDA_CODEC_ENTRY(0x11d4198b, "AD1988B", patch_ad1988),1162	HDA_CODEC_ENTRY(0x11d4882a, "AD1882A", patch_ad1882),1163	HDA_CODEC_ENTRY(0x11d4989a, "AD1989A", patch_ad1988),1164	HDA_CODEC_ENTRY(0x11d4989b, "AD1989B", patch_ad1988),1165	{} /* terminator */1166};1167MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_analog);1168 1169MODULE_LICENSE("GPL");1170MODULE_DESCRIPTION("Analog Devices HD-audio codec");1171 1172static struct hda_codec_driver analog_driver = {1173	.id = snd_hda_id_analog,1174};1175 1176module_hda_codec_driver(analog_driver);1177