brintos

brintos / linux-shallow public Read only

0
0
Text · 31.7 KiB · a8ef4bb Raw
1248 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Universal Interface for Intel High Definition Audio Codec4 *5 * HD audio interface patch for VIA VT17xx/VT18xx/VT20xx codec6 *7 *  (C) 2006-2009 VIA Technology, Inc.8 *  (C) 2006-2008 Takashi Iwai <tiwai@suse.de>9 */10 11/* * * * * * * * * * * * * * Release History * * * * * * * * * * * * * * * * */12/*									     */13/* 2006-03-03  Lydia Wang  Create the basic patch to support VT1708 codec    */14/* 2006-03-14  Lydia Wang  Modify hard code for some pin widget nid	     */15/* 2006-08-02  Lydia Wang  Add support to VT1709 codec			     */16/* 2006-09-08  Lydia Wang  Fix internal loopback recording source select bug */17/* 2007-09-12  Lydia Wang  Add EAPD enable during driver initialization	     */18/* 2007-09-17  Lydia Wang  Add VT1708B codec support			    */19/* 2007-11-14  Lydia Wang  Add VT1708A codec HP and CD pin connect config    */20/* 2008-02-03  Lydia Wang  Fix Rear channels and Back channels inverse issue */21/* 2008-03-06  Lydia Wang  Add VT1702 codec and VT1708S codec support	     */22/* 2008-04-09  Lydia Wang  Add mute front speaker when HP plugin	     */23/* 2008-04-09  Lydia Wang  Add Independent HP feature			     */24/* 2008-05-28  Lydia Wang  Add second S/PDIF Out support for VT1702	     */25/* 2008-09-15  Logan Li	   Add VT1708S Mic Boost workaround/backdoor	     */26/* 2009-02-16  Logan Li	   Add support for VT1718S			     */27/* 2009-03-13  Logan Li	   Add support for VT1716S			     */28/* 2009-04-14  Lydai Wang  Add support for VT1828S and VT2020		     */29/* 2009-07-08  Lydia Wang  Add support for VT2002P			     */30/* 2009-07-21  Lydia Wang  Add support for VT1812			     */31/* 2009-09-19  Lydia Wang  Add support for VT1818S			     */32/*									     */33/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */34 35 36#include <linux/init.h>37#include <linux/delay.h>38#include <linux/slab.h>39#include <linux/module.h>40#include <sound/core.h>41#include <sound/asoundef.h>42#include <sound/hda_codec.h>43#include "hda_local.h"44#include "hda_auto_parser.h"45#include "hda_jack.h"46#include "hda_generic.h"47 48/* Pin Widget NID */49#define VT1708_HP_PIN_NID	0x2050#define VT1708_CD_PIN_NID	0x2451 52enum VIA_HDA_CODEC {53	UNKNOWN = -1,54	VT1708,55	VT1709_10CH,56	VT1709_6CH,57	VT1708B_8CH,58	VT1708B_4CH,59	VT1708S,60	VT1708BCE,61	VT1702,62	VT1718S,63	VT1716S,64	VT2002P,65	VT1812,66	VT1802,67	VT1705CF,68	VT1808,69	CODEC_TYPES,70};71 72#define VT2002P_COMPATIBLE(spec) \73	((spec)->codec_type == VT2002P ||\74	 (spec)->codec_type == VT1812 ||\75	 (spec)->codec_type == VT1802)76 77struct via_spec {78	struct hda_gen_spec gen;79 80	/* HP mode source */81	unsigned int dmic_enabled;82	enum VIA_HDA_CODEC codec_type;83 84	/* analog low-power control */85	bool alc_mode;86 87	/* work to check hp jack state */88	int hp_work_active;89	int vt1708_jack_detect;90};91 92static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec);93static void via_playback_pcm_hook(struct hda_pcm_stream *hinfo,94				  struct hda_codec *codec,95				  struct snd_pcm_substream *substream,96				  int action);97 98static const struct hda_codec_ops via_patch_ops; /* defined below */99 100static struct via_spec *via_new_spec(struct hda_codec *codec)101{102	struct via_spec *spec;103 104	spec = kzalloc(sizeof(*spec), GFP_KERNEL);105	if (spec == NULL)106		return NULL;107 108	codec->spec = spec;109	snd_hda_gen_spec_init(&spec->gen);110	spec->codec_type = get_codec_type(codec);111	/* VT1708BCE & VT1708S are almost same */112	if (spec->codec_type == VT1708BCE)113		spec->codec_type = VT1708S;114	spec->gen.indep_hp = 1;115	spec->gen.keep_eapd_on = 1;116	spec->gen.dac_min_mute = 1;117	spec->gen.pcm_playback_hook = via_playback_pcm_hook;118	spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;119	codec->power_save_node = 1;120	spec->gen.power_down_unused = 1;121	codec->patch_ops = via_patch_ops;122	return spec;123}124 125static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec)126{127	u32 vendor_id = codec->core.vendor_id;128	u16 ven_id = vendor_id >> 16;129	u16 dev_id = vendor_id & 0xffff;130	enum VIA_HDA_CODEC codec_type;131 132	/* get codec type */133	if (ven_id != 0x1106)134		codec_type = UNKNOWN;135	else if (dev_id >= 0x1708 && dev_id <= 0x170b)136		codec_type = VT1708;137	else if (dev_id >= 0xe710 && dev_id <= 0xe713)138		codec_type = VT1709_10CH;139	else if (dev_id >= 0xe714 && dev_id <= 0xe717)140		codec_type = VT1709_6CH;141	else if (dev_id >= 0xe720 && dev_id <= 0xe723) {142		codec_type = VT1708B_8CH;143		if (snd_hda_param_read(codec, 0x16, AC_PAR_CONNLIST_LEN) == 0x7)144			codec_type = VT1708BCE;145	} else if (dev_id >= 0xe724 && dev_id <= 0xe727)146		codec_type = VT1708B_4CH;147	else if ((dev_id & 0xfff) == 0x397148		 && (dev_id >> 12) < 8)149		codec_type = VT1708S;150	else if ((dev_id & 0xfff) == 0x398151		 && (dev_id >> 12) < 8)152		codec_type = VT1702;153	else if ((dev_id & 0xfff) == 0x428154		 && (dev_id >> 12) < 8)155		codec_type = VT1718S;156	else if (dev_id == 0x0433 || dev_id == 0xa721)157		codec_type = VT1716S;158	else if (dev_id == 0x0441 || dev_id == 0x4441)159		codec_type = VT1718S;160	else if (dev_id == 0x0438 || dev_id == 0x4438)161		codec_type = VT2002P;162	else if (dev_id == 0x0448)163		codec_type = VT1812;164	else if (dev_id == 0x0440)165		codec_type = VT1708S;166	else if ((dev_id & 0xfff) == 0x446)167		codec_type = VT1802;168	else if (dev_id == 0x4760)169		codec_type = VT1705CF;170	else if (dev_id == 0x4761 || dev_id == 0x4762)171		codec_type = VT1808;172	else173		codec_type = UNKNOWN;174	return codec_type;175};176 177static void analog_low_current_mode(struct hda_codec *codec);178static bool is_aa_path_mute(struct hda_codec *codec);179 180#define hp_detect_with_aa(codec) \181	(snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1 && \182	 !is_aa_path_mute(codec))183 184static void vt1708_stop_hp_work(struct hda_codec *codec)185{186	struct via_spec *spec = codec->spec;187	if (spec->codec_type != VT1708 || !spec->gen.autocfg.hp_outs)188		return;189	if (spec->hp_work_active) {190		snd_hda_codec_write(codec, 0x1, 0, 0xf81, 1);191		codec->jackpoll_interval = 0;192		cancel_delayed_work_sync(&codec->jackpoll_work);193		spec->hp_work_active = false;194	}195}196 197static void vt1708_update_hp_work(struct hda_codec *codec)198{199	struct via_spec *spec = codec->spec;200	if (spec->codec_type != VT1708 || !spec->gen.autocfg.hp_outs)201		return;202	if (spec->vt1708_jack_detect) {203		if (!spec->hp_work_active) {204			codec->jackpoll_interval = msecs_to_jiffies(100);205			snd_hda_codec_write(codec, 0x1, 0, 0xf81, 0);206			schedule_delayed_work(&codec->jackpoll_work, 0);207			spec->hp_work_active = true;208		}209	} else if (!hp_detect_with_aa(codec))210		vt1708_stop_hp_work(codec);211}212 213static int via_pin_power_ctl_info(struct snd_kcontrol *kcontrol,214				  struct snd_ctl_elem_info *uinfo)215{216	return snd_hda_enum_bool_helper_info(kcontrol, uinfo);217}218 219static int via_pin_power_ctl_get(struct snd_kcontrol *kcontrol,220				 struct snd_ctl_elem_value *ucontrol)221{222	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);223	struct via_spec *spec = codec->spec;224 225	ucontrol->value.enumerated.item[0] = spec->gen.power_down_unused;226	return 0;227}228 229static int via_pin_power_ctl_put(struct snd_kcontrol *kcontrol,230				 struct snd_ctl_elem_value *ucontrol)231{232	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);233	struct via_spec *spec = codec->spec;234	bool val = !!ucontrol->value.enumerated.item[0];235 236	if (val == spec->gen.power_down_unused)237		return 0;238	/* codec->power_save_node = val; */ /* widget PM seems yet broken */239	spec->gen.power_down_unused = val;240	analog_low_current_mode(codec);241	return 1;242}243 244static const struct snd_kcontrol_new via_pin_power_ctl_enum = {245	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,246	.name = "Dynamic Power-Control",247	.info = via_pin_power_ctl_info,248	.get = via_pin_power_ctl_get,249	.put = via_pin_power_ctl_put,250};251 252#ifdef CONFIG_SND_HDA_INPUT_BEEP253/* additional beep mixers; the actual parameters are overwritten at build */254static const struct snd_kcontrol_new via_beep_mixer[] = {255	HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT),256	HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT),257};258 259static int set_beep_amp(struct via_spec *spec, hda_nid_t nid,260			int idx, int dir)261{262	struct snd_kcontrol_new *knew;263	unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir);264	int i;265 266	spec->gen.beep_nid = nid;267	for (i = 0; i < ARRAY_SIZE(via_beep_mixer); i++) {268		knew = snd_hda_gen_add_kctl(&spec->gen, NULL,269					    &via_beep_mixer[i]);270		if (!knew)271			return -ENOMEM;272		knew->private_value = beep_amp;273	}274	return 0;275}276 277static int auto_parse_beep(struct hda_codec *codec)278{279	struct via_spec *spec = codec->spec;280	hda_nid_t nid;281 282	for_each_hda_codec_node(nid, codec)283		if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP)284			return set_beep_amp(spec, nid, 0, HDA_OUTPUT);285	return 0;286}287#else288#define auto_parse_beep(codec)	0289#endif290 291/* check AA path's mute status */292static bool is_aa_path_mute(struct hda_codec *codec)293{294	struct via_spec *spec = codec->spec;295	const struct hda_amp_list *p;296	int ch, v;297 298	p = spec->gen.loopback.amplist;299	if (!p)300		return true;301	for (; p->nid; p++) {302		for (ch = 0; ch < 2; ch++) {303			v = snd_hda_codec_amp_read(codec, p->nid, ch, p->dir,304						   p->idx);305			if (!(v & HDA_AMP_MUTE) && v > 0)306				return false;307		}308	}309	return true;310}311 312/* enter/exit analog low-current mode */313static void __analog_low_current_mode(struct hda_codec *codec, bool force)314{315	struct via_spec *spec = codec->spec;316	bool enable;317	unsigned int verb, parm;318 319	if (!codec->power_save_node)320		enable = false;321	else322		enable = is_aa_path_mute(codec) && !spec->gen.active_streams;323	if (enable == spec->alc_mode && !force)324		return;325	spec->alc_mode = enable;326 327	/* decide low current mode's verb & parameter */328	switch (spec->codec_type) {329	case VT1708B_8CH:330	case VT1708B_4CH:331		verb = 0xf70;332		parm = enable ? 0x02 : 0x00; /* 0x02: 2/3x, 0x00: 1x */333		break;334	case VT1708S:335	case VT1718S:336	case VT1716S:337		verb = 0xf73;338		parm = enable ? 0x51 : 0xe1; /* 0x51: 4/28x, 0xe1: 1x */339		break;340	case VT1702:341		verb = 0xf73;342		parm = enable ? 0x01 : 0x1d; /* 0x01: 4/40x, 0x1d: 1x */343		break;344	case VT2002P:345	case VT1812:346	case VT1802:347		verb = 0xf93;348		parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */349		break;350	case VT1705CF:351	case VT1808:352		verb = 0xf82;353		parm = enable ? 0x00 : 0xe0;  /* 0x00: 4/40x, 0xe0: 1x */354		break;355	default:356		return;		/* other codecs are not supported */357	}358	/* send verb */359	snd_hda_codec_write(codec, codec->core.afg, 0, verb, parm);360}361 362static void analog_low_current_mode(struct hda_codec *codec)363{364	return __analog_low_current_mode(codec, false);365}366 367static void via_playback_pcm_hook(struct hda_pcm_stream *hinfo,368				  struct hda_codec *codec,369				  struct snd_pcm_substream *substream,370				  int action)371{372	analog_low_current_mode(codec);373	vt1708_update_hp_work(codec);374}375 376static void via_free(struct hda_codec *codec)377{378	vt1708_stop_hp_work(codec);379	snd_hda_gen_free(codec);380}381 382static int via_suspend(struct hda_codec *codec)383{384	struct via_spec *spec = codec->spec;385	vt1708_stop_hp_work(codec);386 387	/* Fix pop noise on headphones */388	if (spec->codec_type == VT1802)389		snd_hda_shutup_pins(codec);390 391	return 0;392}393 394static int via_resume(struct hda_codec *codec)395{396	/* some delay here to make jack detection working (bko#98921) */397	msleep(10);398	codec->patch_ops.init(codec);399	snd_hda_regmap_sync(codec);400	return 0;401}402 403static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)404{405	struct via_spec *spec = codec->spec;406	analog_low_current_mode(codec);407	vt1708_update_hp_work(codec);408	return snd_hda_check_amp_list_power(codec, &spec->gen.loopback, nid);409}410 411/*412 */413 414static int via_init(struct hda_codec *codec);415 416static const struct hda_codec_ops via_patch_ops = {417	.build_controls = snd_hda_gen_build_controls,418	.build_pcms = snd_hda_gen_build_pcms,419	.init = via_init,420	.free = via_free,421	.unsol_event = snd_hda_jack_unsol_event,422	.suspend = via_suspend,423	.resume = via_resume,424	.check_power_status = via_check_power_status,425};426 427 428static const struct hda_verb vt1708_init_verbs[] = {429	/* power down jack detect function */430	{0x1, 0xf81, 0x1},431	{ }432};433static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid)434{435	unsigned int def_conf;436	unsigned char seqassoc;437 438	def_conf = snd_hda_codec_get_pincfg(codec, nid);439	seqassoc = (unsigned char) get_defcfg_association(def_conf);440	seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf);441	if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE442	    && (seqassoc == 0xf0 || seqassoc == 0xff)) {443		def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30));444		snd_hda_codec_set_pincfg(codec, nid, def_conf);445	}446}447 448static int vt1708_jack_detect_get(struct snd_kcontrol *kcontrol,449				     struct snd_ctl_elem_value *ucontrol)450{451	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);452	struct via_spec *spec = codec->spec;453 454	if (spec->codec_type != VT1708)455		return 0;456	ucontrol->value.integer.value[0] = spec->vt1708_jack_detect;457	return 0;458}459 460static int vt1708_jack_detect_put(struct snd_kcontrol *kcontrol,461				     struct snd_ctl_elem_value *ucontrol)462{463	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);464	struct via_spec *spec = codec->spec;465	int val;466 467	if (spec->codec_type != VT1708)468		return 0;469	val = !!ucontrol->value.integer.value[0];470	if (spec->vt1708_jack_detect == val)471		return 0;472	spec->vt1708_jack_detect = val;473	vt1708_update_hp_work(codec);474	return 1;475}476 477static const struct snd_kcontrol_new vt1708_jack_detect_ctl = {478	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,479	.name = "Jack Detect",480	.count = 1,481	.info = snd_ctl_boolean_mono_info,482	.get = vt1708_jack_detect_get,483	.put = vt1708_jack_detect_put,484};485 486static const struct badness_table via_main_out_badness = {487	.no_primary_dac = 0x10000,488	.no_dac = 0x4000,489	.shared_primary = 0x10000,490	.shared_surr = 0x20,491	.shared_clfe = 0x20,492	.shared_surr_main = 0x20,493};494static const struct badness_table via_extra_out_badness = {495	.no_primary_dac = 0x4000,496	.no_dac = 0x4000,497	.shared_primary = 0x12,498	.shared_surr = 0x20,499	.shared_clfe = 0x20,500	.shared_surr_main = 0x10,501};502 503static int via_parse_auto_config(struct hda_codec *codec)504{505	struct via_spec *spec = codec->spec;506	int err;507 508	spec->gen.main_out_badness = &via_main_out_badness;509	spec->gen.extra_out_badness = &via_extra_out_badness;510 511	err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0);512	if (err < 0)513		return err;514 515	err = auto_parse_beep(codec);516	if (err < 0)517		return err;518 519	err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);520	if (err < 0)521		return err;522 523	if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &via_pin_power_ctl_enum))524		return -ENOMEM;525 526	/* disable widget PM at start for compatibility */527	codec->power_save_node = 0;528	spec->gen.power_down_unused = 0;529	return 0;530}531 532static int via_init(struct hda_codec *codec)533{534	/* init power states */535	__analog_low_current_mode(codec, true);536 537	snd_hda_gen_init(codec);538 539	vt1708_update_hp_work(codec);540 541	return 0;542}543 544static int vt1708_build_controls(struct hda_codec *codec)545{546	/* In order not to create "Phantom Jack" controls,547	   temporary enable jackpoll */548	int err;549	int old_interval = codec->jackpoll_interval;550	codec->jackpoll_interval = msecs_to_jiffies(100);551	err = snd_hda_gen_build_controls(codec);552	codec->jackpoll_interval = old_interval;553	return err;554}555 556static int vt1708_build_pcms(struct hda_codec *codec)557{558	struct via_spec *spec = codec->spec;559	int i, err;560 561	err = snd_hda_gen_build_pcms(codec);562	if (err < 0 || codec->core.vendor_id != 0x11061708)563		return err;564 565	/* We got noisy outputs on the right channel on VT1708 when566	 * 24bit samples are used.  Until any workaround is found,567	 * disable the 24bit format, so far.568	 */569	for (i = 0; i < ARRAY_SIZE(spec->gen.pcm_rec); i++) {570		struct hda_pcm *info = spec->gen.pcm_rec[i];571		if (!info)572			continue;573		if (!info->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams ||574		    info->pcm_type != HDA_PCM_TYPE_AUDIO)575			continue;576		info->stream[SNDRV_PCM_STREAM_PLAYBACK].formats =577			SNDRV_PCM_FMTBIT_S16_LE;578	}579 580	return 0;581}582 583static int patch_vt1708(struct hda_codec *codec)584{585	struct via_spec *spec;586	int err;587 588	/* create a codec specific record */589	spec = via_new_spec(codec);590	if (spec == NULL)591		return -ENOMEM;592 593	/* override some patch_ops */594	codec->patch_ops.build_controls = vt1708_build_controls;595	codec->patch_ops.build_pcms = vt1708_build_pcms;596	spec->gen.mixer_nid = 0x17;597 598	/* set jackpoll_interval while parsing the codec */599	codec->jackpoll_interval = msecs_to_jiffies(100);600	spec->vt1708_jack_detect = 1;601 602	/* don't support the input jack switching due to lack of unsol event */603	/* (it may work with polling, though, but it needs testing) */604	spec->gen.suppress_auto_mic = 1;605	/* Some machines show the broken speaker mute */606	spec->gen.auto_mute_via_amp = 1;607 608	/* Add HP and CD pin config connect bit re-config action */609	vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID);610	vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID);611 612	err = snd_hda_add_verbs(codec, vt1708_init_verbs);613	if (err < 0)614		goto error;615 616	/* automatic parse from the BIOS config */617	err = via_parse_auto_config(codec);618	if (err < 0)619		goto error;620 621	/* add jack detect on/off control */622	if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1708_jack_detect_ctl)) {623		err = -ENOMEM;624		goto error;625	}626 627	/* clear jackpoll_interval again; it's set dynamically */628	codec->jackpoll_interval = 0;629 630	return 0;631 632 error:633	via_free(codec);634	return err;635}636 637static int patch_vt1709(struct hda_codec *codec)638{639	struct via_spec *spec;640	int err;641 642	/* create a codec specific record */643	spec = via_new_spec(codec);644	if (spec == NULL)645		return -ENOMEM;646 647	spec->gen.mixer_nid = 0x18;648 649	err = via_parse_auto_config(codec);650	if (err < 0)651		goto error;652 653	return 0;654 655 error:656	via_free(codec);657	return err;658}659 660static int patch_vt1708S(struct hda_codec *codec);661static int patch_vt1708B(struct hda_codec *codec)662{663	struct via_spec *spec;664	int err;665 666	if (get_codec_type(codec) == VT1708BCE)667		return patch_vt1708S(codec);668 669	/* create a codec specific record */670	spec = via_new_spec(codec);671	if (spec == NULL)672		return -ENOMEM;673 674	spec->gen.mixer_nid = 0x16;675 676	/* automatic parse from the BIOS config */677	err = via_parse_auto_config(codec);678	if (err < 0)679		goto error;680 681	return 0;682 683 error:684	via_free(codec);685	return err;686}687 688/* Patch for VT1708S */689static const struct hda_verb vt1708S_init_verbs[] = {690	/* Enable Mic Boost Volume backdoor */691	{0x1, 0xf98, 0x1},692	/* don't bybass mixer */693	{0x1, 0xf88, 0xc0},694	{ }695};696 697static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin,698			       int offset, int num_steps, int step_size)699{700	snd_hda_override_wcaps(codec, pin,701			       get_wcaps(codec, pin) | AC_WCAP_IN_AMP);702	snd_hda_override_amp_caps(codec, pin, HDA_INPUT,703				  (offset << AC_AMPCAP_OFFSET_SHIFT) |704				  (num_steps << AC_AMPCAP_NUM_STEPS_SHIFT) |705				  (step_size << AC_AMPCAP_STEP_SIZE_SHIFT) |706				  (0 << AC_AMPCAP_MUTE_SHIFT));707}708 709static int patch_vt1708S(struct hda_codec *codec)710{711	struct via_spec *spec;712	int err;713 714	/* create a codec specific record */715	spec = via_new_spec(codec);716	if (spec == NULL)717		return -ENOMEM;718 719	spec->gen.mixer_nid = 0x16;720	override_mic_boost(codec, 0x1a, 0, 3, 40);721	override_mic_boost(codec, 0x1e, 0, 3, 40);722 723	/* correct names for VT1708BCE */724	if (get_codec_type(codec) == VT1708BCE)725		snd_hda_codec_set_name(codec, "VT1708BCE");726	/* correct names for VT1705 */727	if (codec->core.vendor_id == 0x11064397)728		snd_hda_codec_set_name(codec, "VT1705");729 730	err = snd_hda_add_verbs(codec, vt1708S_init_verbs);731	if (err < 0)732		goto error;733 734	/* automatic parse from the BIOS config */735	err = via_parse_auto_config(codec);736	if (err < 0)737		goto error;738 739	return 0;740 741 error:742	via_free(codec);743	return err;744}745 746/* Patch for VT1702 */747 748static const struct hda_verb vt1702_init_verbs[] = {749	/* mixer enable */750	{0x1, 0xF88, 0x3},751	/* GPIO 0~2 */752	{0x1, 0xF82, 0x3F},753	{ }754};755 756static int patch_vt1702(struct hda_codec *codec)757{758	struct via_spec *spec;759	int err;760 761	/* create a codec specific record */762	spec = via_new_spec(codec);763	if (spec == NULL)764		return -ENOMEM;765 766	spec->gen.mixer_nid = 0x1a;767 768	/* limit AA path volume to 0 dB */769	snd_hda_override_amp_caps(codec, 0x1A, HDA_INPUT,770				  (0x17 << AC_AMPCAP_OFFSET_SHIFT) |771				  (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |772				  (0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) |773				  (1 << AC_AMPCAP_MUTE_SHIFT));774 775	err = snd_hda_add_verbs(codec, vt1702_init_verbs);776	if (err < 0)777		goto error;778 779	/* automatic parse from the BIOS config */780	err = via_parse_auto_config(codec);781	if (err < 0)782		goto error;783 784	return 0;785 786 error:787	via_free(codec);788	return err;789}790 791/* Patch for VT1718S */792 793static const struct hda_verb vt1718S_init_verbs[] = {794	/* Enable MW0 adjust Gain 5 */795	{0x1, 0xfb2, 0x10},796	/* Enable Boost Volume backdoor */797	{0x1, 0xf88, 0x8},798 799	{ }800};801 802/* Add a connection to the primary DAC from AA-mixer for some codecs803 * This isn't listed from the raw info, but the chip has a secret connection.804 */805static int add_secret_dac_path(struct hda_codec *codec)806{807	struct via_spec *spec = codec->spec;808	int i, nums;809	hda_nid_t conn[8];810	hda_nid_t nid;811 812	if (!spec->gen.mixer_nid)813		return 0;814	nums = snd_hda_get_connections(codec, spec->gen.mixer_nid, conn,815				       ARRAY_SIZE(conn) - 1);816	if (nums < 0)817		return nums;818 819	for (i = 0; i < nums; i++) {820		if (get_wcaps_type(get_wcaps(codec, conn[i])) == AC_WID_AUD_OUT)821			return 0;822	}823 824	/* find the primary DAC and add to the connection list */825	for_each_hda_codec_node(nid, codec) {826		unsigned int caps = get_wcaps(codec, nid);827		if (get_wcaps_type(caps) == AC_WID_AUD_OUT &&828		    !(caps & AC_WCAP_DIGITAL)) {829			conn[nums++] = nid;830			return snd_hda_override_conn_list(codec,831							  spec->gen.mixer_nid,832							  nums, conn);833		}834	}835	return 0;836}837 838 839static int patch_vt1718S(struct hda_codec *codec)840{841	struct via_spec *spec;842	int err;843 844	/* create a codec specific record */845	spec = via_new_spec(codec);846	if (spec == NULL)847		return -ENOMEM;848 849	spec->gen.mixer_nid = 0x21;850	override_mic_boost(codec, 0x2b, 0, 3, 40);851	override_mic_boost(codec, 0x29, 0, 3, 40);852	add_secret_dac_path(codec);853 854	err = snd_hda_add_verbs(codec, vt1718S_init_verbs);855	if (err < 0)856		goto error;857 858	/* automatic parse from the BIOS config */859	err = via_parse_auto_config(codec);860	if (err < 0)861		goto error;862 863	return 0;864 865 error:866	via_free(codec);867	return err;868}869 870/* Patch for VT1716S */871 872static int vt1716s_dmic_info(struct snd_kcontrol *kcontrol,873			    struct snd_ctl_elem_info *uinfo)874{875	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;876	uinfo->count = 1;877	uinfo->value.integer.min = 0;878	uinfo->value.integer.max = 1;879	return 0;880}881 882static int vt1716s_dmic_get(struct snd_kcontrol *kcontrol,883			   struct snd_ctl_elem_value *ucontrol)884{885	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);886	int index = 0;887 888	index = snd_hda_codec_read(codec, 0x26, 0,889					       AC_VERB_GET_CONNECT_SEL, 0);890	if (index != -1)891		*ucontrol->value.integer.value = index;892 893	return 0;894}895 896static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol,897			   struct snd_ctl_elem_value *ucontrol)898{899	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);900	struct via_spec *spec = codec->spec;901	int index = *ucontrol->value.integer.value;902 903	snd_hda_codec_write(codec, 0x26, 0,904					       AC_VERB_SET_CONNECT_SEL, index);905	spec->dmic_enabled = index;906	return 1;907}908 909static const struct snd_kcontrol_new vt1716s_dmic_mixer_vol =910	HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT);911static const struct snd_kcontrol_new vt1716s_dmic_mixer_sw = {912	 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,913	 .name = "Digital Mic Capture Switch",914	 .subdevice = HDA_SUBDEV_NID_FLAG | 0x26,915	 .count = 1,916	 .info = vt1716s_dmic_info,917	 .get = vt1716s_dmic_get,918	 .put = vt1716s_dmic_put,919};920 921 922/* mono-out mixer elements */923static const struct snd_kcontrol_new vt1716S_mono_out_mixer =924	HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT);925 926static const struct hda_verb vt1716S_init_verbs[] = {927	/* Enable Boost Volume backdoor */928	{0x1, 0xf8a, 0x80},929	/* don't bybass mixer */930	{0x1, 0xf88, 0xc0},931	/* Enable mono output */932	{0x1, 0xf90, 0x08},933	{ }934};935 936static int patch_vt1716S(struct hda_codec *codec)937{938	struct via_spec *spec;939	int err;940 941	/* create a codec specific record */942	spec = via_new_spec(codec);943	if (spec == NULL)944		return -ENOMEM;945 946	spec->gen.mixer_nid = 0x16;947	override_mic_boost(codec, 0x1a, 0, 3, 40);948	override_mic_boost(codec, 0x1e, 0, 3, 40);949 950	err = snd_hda_add_verbs(codec, vt1716S_init_verbs);951	if (err < 0)952		goto error;953 954	/* automatic parse from the BIOS config */955	err = via_parse_auto_config(codec);956	if (err < 0)957		goto error;958 959	if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716s_dmic_mixer_vol) ||960	    !snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716s_dmic_mixer_sw) ||961	    !snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716S_mono_out_mixer)) {962		err = -ENOMEM;963		goto error;964	}965 966	return 0;967 968 error:969	via_free(codec);970	return err;971}972 973/* for vt2002P */974 975static const struct hda_verb vt2002P_init_verbs[] = {976	/* Class-D speaker related verbs */977	{0x1, 0xfe0, 0x4},978	{0x1, 0xfe9, 0x80},979	{0x1, 0xfe2, 0x22},980	/* Enable Boost Volume backdoor */981	{0x1, 0xfb9, 0x24},982	/* Enable AOW0 to MW9 */983	{0x1, 0xfb8, 0x88},984	{ }985};986 987static const struct hda_verb vt1802_init_verbs[] = {988	/* Enable Boost Volume backdoor */989	{0x1, 0xfb9, 0x24},990	/* Enable AOW0 to MW9 */991	{0x1, 0xfb8, 0x88},992	{ }993};994 995/*996 * pin fix-up997 */998enum {999	VIA_FIXUP_INTMIC_BOOST,1000	VIA_FIXUP_ASUS_G75,1001	VIA_FIXUP_POWER_SAVE,1002};1003 1004static void via_fixup_intmic_boost(struct hda_codec *codec,1005				  const struct hda_fixup *fix, int action)1006{1007	if (action == HDA_FIXUP_ACT_PRE_PROBE)1008		override_mic_boost(codec, 0x30, 0, 2, 40);1009}1010 1011static void via_fixup_power_save(struct hda_codec *codec,1012				 const struct hda_fixup *fix, int action)1013{1014	if (action == HDA_FIXUP_ACT_PRE_PROBE)1015		codec->power_save_node = 0;1016}1017 1018static const struct hda_fixup via_fixups[] = {1019	[VIA_FIXUP_INTMIC_BOOST] = {1020		.type = HDA_FIXUP_FUNC,1021		.v.func = via_fixup_intmic_boost,1022	},1023	[VIA_FIXUP_ASUS_G75] = {1024		.type = HDA_FIXUP_PINS,1025		.v.pins = (const struct hda_pintbl[]) {1026			/* set 0x24 and 0x33 as speakers */1027			{ 0x24, 0x991301f0 },1028			{ 0x33, 0x991301f1 }, /* subwoofer */1029			{ }1030		}1031	},1032	[VIA_FIXUP_POWER_SAVE] = {1033		.type = HDA_FIXUP_FUNC,1034		.v.func = via_fixup_power_save,1035	},1036};1037 1038static const struct snd_pci_quirk vt2002p_fixups[] = {1039	SND_PCI_QUIRK(0x1043, 0x13f7, "Asus B23E", VIA_FIXUP_POWER_SAVE),1040	SND_PCI_QUIRK(0x1043, 0x1487, "Asus G75", VIA_FIXUP_ASUS_G75),1041	SND_PCI_QUIRK(0x1043, 0x8532, "Asus X202E", VIA_FIXUP_INTMIC_BOOST),1042	SND_PCI_QUIRK_VENDOR(0x1558, "Clevo", VIA_FIXUP_POWER_SAVE),1043	{}1044};1045 1046/* NIDs 0x24 and 0x33 on VT1802 have connections to non-existing NID 0x3e1047 * Replace this with mixer NID 0x1c1048 */1049static void fix_vt1802_connections(struct hda_codec *codec)1050{1051	static const hda_nid_t conn_24[] = { 0x14, 0x1c };1052	static const hda_nid_t conn_33[] = { 0x1c };1053 1054	snd_hda_override_conn_list(codec, 0x24, ARRAY_SIZE(conn_24), conn_24);1055	snd_hda_override_conn_list(codec, 0x33, ARRAY_SIZE(conn_33), conn_33);1056}1057 1058/* patch for vt2002P */1059static int patch_vt2002P(struct hda_codec *codec)1060{1061	struct via_spec *spec;1062	int err;1063 1064	/* create a codec specific record */1065	spec = via_new_spec(codec);1066	if (spec == NULL)1067		return -ENOMEM;1068 1069	spec->gen.mixer_nid = 0x21;1070	override_mic_boost(codec, 0x2b, 0, 3, 40);1071	override_mic_boost(codec, 0x29, 0, 3, 40);1072	if (spec->codec_type == VT1802)1073		fix_vt1802_connections(codec);1074	add_secret_dac_path(codec);1075 1076	snd_hda_pick_fixup(codec, NULL, vt2002p_fixups, via_fixups);1077	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);1078 1079	if (spec->codec_type == VT1802)1080		err = snd_hda_add_verbs(codec, vt1802_init_verbs);1081	else1082		err = snd_hda_add_verbs(codec, vt2002P_init_verbs);1083	if (err < 0)1084		goto error;1085 1086	/* automatic parse from the BIOS config */1087	err = via_parse_auto_config(codec);1088	if (err < 0)1089		goto error;1090 1091	return 0;1092 1093 error:1094	via_free(codec);1095	return err;1096}1097 1098/* for vt1812 */1099 1100static const struct hda_verb vt1812_init_verbs[] = {1101	/* Enable Boost Volume backdoor */1102	{0x1, 0xfb9, 0x24},1103	/* Enable AOW0 to MW9 */1104	{0x1, 0xfb8, 0xa8},1105	{ }1106};1107 1108/* patch for vt1812 */1109static int patch_vt1812(struct hda_codec *codec)1110{1111	struct via_spec *spec;1112	int err;1113 1114	/* create a codec specific record */1115	spec = via_new_spec(codec);1116	if (spec == NULL)1117		return -ENOMEM;1118 1119	spec->gen.mixer_nid = 0x21;1120	override_mic_boost(codec, 0x2b, 0, 3, 40);1121	override_mic_boost(codec, 0x29, 0, 3, 40);1122	add_secret_dac_path(codec);1123 1124	err = snd_hda_add_verbs(codec, vt1812_init_verbs);1125	if (err < 0)1126		goto error;1127 1128	/* automatic parse from the BIOS config */1129	err = via_parse_auto_config(codec);1130	if (err < 0)1131		goto error;1132 1133	return 0;1134 1135 error:1136	via_free(codec);1137	return err;1138}1139 1140/* patch for vt3476 */1141 1142static const struct hda_verb vt3476_init_verbs[] = {1143	/* Enable DMic 8/16/32K */1144	{0x1, 0xF7B, 0x30},1145	/* Enable Boost Volume backdoor */1146	{0x1, 0xFB9, 0x20},1147	/* Enable AOW-MW9 path */1148	{0x1, 0xFB8, 0x10},1149	{ }1150};1151 1152static int patch_vt3476(struct hda_codec *codec)1153{1154	struct via_spec *spec;1155	int err;1156 1157	/* create a codec specific record */1158	spec = via_new_spec(codec);1159	if (spec == NULL)1160		return -ENOMEM;1161 1162	spec->gen.mixer_nid = 0x3f;1163	add_secret_dac_path(codec);1164 1165	err = snd_hda_add_verbs(codec, vt3476_init_verbs);1166	if (err < 0)1167		goto error;1168 1169	/* automatic parse from the BIOS config */1170	err = via_parse_auto_config(codec);1171	if (err < 0)1172		goto error;1173 1174	return 0;1175 1176 error:1177	via_free(codec);1178	return err;1179}1180 1181/*1182 * patch entries1183 */1184static const struct hda_device_id snd_hda_id_via[] = {1185	HDA_CODEC_ENTRY(0x11061708, "VT1708", patch_vt1708),1186	HDA_CODEC_ENTRY(0x11061709, "VT1708", patch_vt1708),1187	HDA_CODEC_ENTRY(0x1106170a, "VT1708", patch_vt1708),1188	HDA_CODEC_ENTRY(0x1106170b, "VT1708", patch_vt1708),1189	HDA_CODEC_ENTRY(0x1106e710, "VT1709 10-Ch", patch_vt1709),1190	HDA_CODEC_ENTRY(0x1106e711, "VT1709 10-Ch", patch_vt1709),1191	HDA_CODEC_ENTRY(0x1106e712, "VT1709 10-Ch", patch_vt1709),1192	HDA_CODEC_ENTRY(0x1106e713, "VT1709 10-Ch", patch_vt1709),1193	HDA_CODEC_ENTRY(0x1106e714, "VT1709 6-Ch", patch_vt1709),1194	HDA_CODEC_ENTRY(0x1106e715, "VT1709 6-Ch", patch_vt1709),1195	HDA_CODEC_ENTRY(0x1106e716, "VT1709 6-Ch", patch_vt1709),1196	HDA_CODEC_ENTRY(0x1106e717, "VT1709 6-Ch", patch_vt1709),1197	HDA_CODEC_ENTRY(0x1106e720, "VT1708B 8-Ch", patch_vt1708B),1198	HDA_CODEC_ENTRY(0x1106e721, "VT1708B 8-Ch", patch_vt1708B),1199	HDA_CODEC_ENTRY(0x1106e722, "VT1708B 8-Ch", patch_vt1708B),1200	HDA_CODEC_ENTRY(0x1106e723, "VT1708B 8-Ch", patch_vt1708B),1201	HDA_CODEC_ENTRY(0x1106e724, "VT1708B 4-Ch", patch_vt1708B),1202	HDA_CODEC_ENTRY(0x1106e725, "VT1708B 4-Ch", patch_vt1708B),1203	HDA_CODEC_ENTRY(0x1106e726, "VT1708B 4-Ch", patch_vt1708B),1204	HDA_CODEC_ENTRY(0x1106e727, "VT1708B 4-Ch", patch_vt1708B),1205	HDA_CODEC_ENTRY(0x11060397, "VT1708S", patch_vt1708S),1206	HDA_CODEC_ENTRY(0x11061397, "VT1708S", patch_vt1708S),1207	HDA_CODEC_ENTRY(0x11062397, "VT1708S", patch_vt1708S),1208	HDA_CODEC_ENTRY(0x11063397, "VT1708S", patch_vt1708S),1209	HDA_CODEC_ENTRY(0x11064397, "VT1705", patch_vt1708S),1210	HDA_CODEC_ENTRY(0x11065397, "VT1708S", patch_vt1708S),1211	HDA_CODEC_ENTRY(0x11066397, "VT1708S", patch_vt1708S),1212	HDA_CODEC_ENTRY(0x11067397, "VT1708S", patch_vt1708S),1213	HDA_CODEC_ENTRY(0x11060398, "VT1702", patch_vt1702),1214	HDA_CODEC_ENTRY(0x11061398, "VT1702", patch_vt1702),1215	HDA_CODEC_ENTRY(0x11062398, "VT1702", patch_vt1702),1216	HDA_CODEC_ENTRY(0x11063398, "VT1702", patch_vt1702),1217	HDA_CODEC_ENTRY(0x11064398, "VT1702", patch_vt1702),1218	HDA_CODEC_ENTRY(0x11065398, "VT1702", patch_vt1702),1219	HDA_CODEC_ENTRY(0x11066398, "VT1702", patch_vt1702),1220	HDA_CODEC_ENTRY(0x11067398, "VT1702", patch_vt1702),1221	HDA_CODEC_ENTRY(0x11060428, "VT1718S", patch_vt1718S),1222	HDA_CODEC_ENTRY(0x11064428, "VT1718S", patch_vt1718S),1223	HDA_CODEC_ENTRY(0x11060441, "VT2020", patch_vt1718S),1224	HDA_CODEC_ENTRY(0x11064441, "VT1828S", patch_vt1718S),1225	HDA_CODEC_ENTRY(0x11060433, "VT1716S", patch_vt1716S),1226	HDA_CODEC_ENTRY(0x1106a721, "VT1716S", patch_vt1716S),1227	HDA_CODEC_ENTRY(0x11060438, "VT2002P", patch_vt2002P),1228	HDA_CODEC_ENTRY(0x11064438, "VT2002P", patch_vt2002P),1229	HDA_CODEC_ENTRY(0x11060448, "VT1812", patch_vt1812),1230	HDA_CODEC_ENTRY(0x11060440, "VT1818S", patch_vt1708S),1231	HDA_CODEC_ENTRY(0x11060446, "VT1802", patch_vt2002P),1232	HDA_CODEC_ENTRY(0x11068446, "VT1802", patch_vt2002P),1233	HDA_CODEC_ENTRY(0x11064760, "VT1705CF", patch_vt3476),1234	HDA_CODEC_ENTRY(0x11064761, "VT1708SCE", patch_vt3476),1235	HDA_CODEC_ENTRY(0x11064762, "VT1808", patch_vt3476),1236	{} /* terminator */1237};1238MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_via);1239 1240static struct hda_codec_driver via_driver = {1241	.id = snd_hda_id_via,1242};1243 1244MODULE_LICENSE("GPL");1245MODULE_DESCRIPTION("VIA HD-audio codec");1246 1247module_hda_codec_driver(via_driver);1248