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