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