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