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