^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * HD audio interface patch for AD1882, AD1884, AD1981HD, AD1983, AD1984,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * AD1986A, AD1988
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (c) 2005-2007 Takashi Iwai <tiwai@suse.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <sound/core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <sound/hda_codec.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include "hda_local.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "hda_auto_parser.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include "hda_beep.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include "hda_jack.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include "hda_generic.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) struct ad198x_spec {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) struct hda_gen_spec gen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) /* for auto parser */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) int smux_paths[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) unsigned int cur_smux;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) hda_nid_t eapd_nid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) int num_smux_conns;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #ifdef CONFIG_SND_HDA_INPUT_BEEP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) /* additional beep mixers; the actual parameters are overwritten at build */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static const struct snd_kcontrol_new ad_beep_mixer[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_OUTPUT),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) { } /* end */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define set_beep_amp(spec, nid, idx, dir) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define set_beep_amp(spec, nid, idx, dir) /* NOP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #ifdef CONFIG_SND_HDA_INPUT_BEEP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) static int create_beep_ctls(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) struct ad198x_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) const struct snd_kcontrol_new *knew;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (!spec->beep_amp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) for (knew = ad_beep_mixer ; knew->name; knew++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) struct snd_kcontrol *kctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) kctl = snd_ctl_new1(knew, codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) if (!kctl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) kctl->private_value = spec->beep_amp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) err = snd_hda_ctl_add(codec, 0, kctl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) #define create_beep_ctls(codec) 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) hda_nid_t hp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if (snd_hda_query_pin_caps(codec, front) & AC_PINCAP_EAPD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) !codec->inv_eapd ? 0x00 : 0x02);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) if (snd_hda_query_pin_caps(codec, hp) & AC_PINCAP_EAPD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) !codec->inv_eapd ? 0x00 : 0x02);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) static void ad198x_power_eapd(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) /* We currently only handle front, HP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) switch (codec->core.vendor_id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) case 0x11d41882:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) case 0x11d4882a:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) case 0x11d41884:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) case 0x11d41984:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) case 0x11d41883:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) case 0x11d4184a:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) case 0x11d4194a:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) case 0x11d4194b:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) case 0x11d41988:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) case 0x11d4198b:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) case 0x11d4989a:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) case 0x11d4989b:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) ad198x_power_eapd_write(codec, 0x12, 0x11);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) case 0x11d41981:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) case 0x11d41983:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) ad198x_power_eapd_write(codec, 0x05, 0x06);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) case 0x11d41986:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) ad198x_power_eapd_write(codec, 0x1b, 0x1a);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) static void ad198x_shutup(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) snd_hda_shutup_pins(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) ad198x_power_eapd(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) #ifdef CONFIG_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) static int ad198x_suspend(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) ad198x_shutup(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) /* follow EAPD via vmaster hook */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) static void ad_vmaster_eapd_hook(void *private_data, int enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) struct hda_codec *codec = private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) struct ad198x_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (!spec->eapd_nid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) if (codec->inv_eapd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) enabled = !enabled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) snd_hda_codec_write_cache(codec, spec->eapd_nid, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) AC_VERB_SET_EAPD_BTLENABLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) enabled ? 0x02 : 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) * Automatic parse of I/O pins from the BIOS configuration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) static int ad198x_auto_build_controls(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) err = snd_hda_gen_build_controls(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) err = create_beep_ctls(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) static const struct hda_codec_ops ad198x_auto_patch_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) .build_controls = ad198x_auto_build_controls,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) .build_pcms = snd_hda_gen_build_pcms,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) .init = snd_hda_gen_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) .free = snd_hda_gen_free,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) .unsol_event = snd_hda_jack_unsol_event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) #ifdef CONFIG_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) .check_power_status = snd_hda_gen_check_power_status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) .suspend = ad198x_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) .reboot_notify = ad198x_shutup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) static int ad198x_parse_auto_config(struct hda_codec *codec, bool indep_hp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) struct ad198x_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) struct auto_pin_cfg *cfg = &spec->gen.autocfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) codec->spdif_status_reset = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) codec->no_trigger_sense = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) codec->no_sticky_stream = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) spec->gen.indep_hp = indep_hp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) if (!spec->gen.add_stereo_mix_input)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) err = snd_hda_gen_parse_auto_config(codec, cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) * AD1986A specific
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) static int alloc_ad_spec(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) struct ad198x_spec *spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) spec = kzalloc(sizeof(*spec), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) if (!spec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) codec->spec = spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) snd_hda_gen_spec_init(&spec->gen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) codec->patch_ops = ad198x_auto_patch_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) * AD1986A fixup codes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) /* Lenovo N100 seems to report the reversed bit for HP jack-sensing */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) static void ad_fixup_inv_jack_detect(struct hda_codec *codec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) const struct hda_fixup *fix, int action)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) struct ad198x_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) if (action == HDA_FIXUP_ACT_PRE_PROBE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) codec->inv_jack_detect = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) spec->gen.keep_eapd_on = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) spec->eapd_nid = 0x1b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) /* Toshiba Satellite L40 implements EAPD in a standard way unlike others */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) static void ad1986a_fixup_eapd(struct hda_codec *codec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) const struct hda_fixup *fix, int action)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) struct ad198x_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) if (action == HDA_FIXUP_ACT_PRE_PROBE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) codec->inv_eapd = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) spec->gen.keep_eapd_on = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) spec->eapd_nid = 0x1b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) /* enable stereo-mix input for avoiding regression on KDE (bko#88251) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) static void ad1986a_fixup_eapd_mix_in(struct hda_codec *codec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) const struct hda_fixup *fix, int action)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) struct ad198x_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) if (action == HDA_FIXUP_ACT_PRE_PROBE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) ad1986a_fixup_eapd(codec, fix, action);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) enum {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) AD1986A_FIXUP_INV_JACK_DETECT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) AD1986A_FIXUP_ULTRA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) AD1986A_FIXUP_SAMSUNG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) AD1986A_FIXUP_3STACK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) AD1986A_FIXUP_LAPTOP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) AD1986A_FIXUP_LAPTOP_IMIC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) AD1986A_FIXUP_EAPD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) AD1986A_FIXUP_EAPD_MIX_IN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) AD1986A_FIXUP_EASYNOTE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) static const struct hda_fixup ad1986a_fixups[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) [AD1986A_FIXUP_INV_JACK_DETECT] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) .type = HDA_FIXUP_FUNC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) .v.func = ad_fixup_inv_jack_detect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) [AD1986A_FIXUP_ULTRA] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) .type = HDA_FIXUP_PINS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) .v.pins = (const struct hda_pintbl[]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) { 0x1b, 0x90170110 }, /* speaker */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) { 0x1d, 0x90a7013e }, /* int mic */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) [AD1986A_FIXUP_SAMSUNG] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) .type = HDA_FIXUP_PINS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) .v.pins = (const struct hda_pintbl[]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) { 0x1b, 0x90170110 }, /* speaker */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) { 0x1d, 0x90a7013e }, /* int mic */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) { 0x20, 0x411111f0 }, /* N/A */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) { 0x24, 0x411111f0 }, /* N/A */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) [AD1986A_FIXUP_3STACK] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) .type = HDA_FIXUP_PINS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) .v.pins = (const struct hda_pintbl[]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) { 0x1a, 0x02214021 }, /* headphone */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) { 0x1b, 0x01014011 }, /* front */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) { 0x1c, 0x01813030 }, /* line-in */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) { 0x1d, 0x01a19020 }, /* rear mic */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) { 0x1e, 0x411111f0 }, /* N/A */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) { 0x1f, 0x02a190f0 }, /* mic */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) { 0x20, 0x411111f0 }, /* N/A */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) [AD1986A_FIXUP_LAPTOP] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) .type = HDA_FIXUP_PINS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) .v.pins = (const struct hda_pintbl[]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) { 0x1a, 0x02214021 }, /* headphone */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) { 0x1b, 0x90170110 }, /* speaker */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) { 0x1c, 0x411111f0 }, /* N/A */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) { 0x1d, 0x411111f0 }, /* N/A */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) { 0x1e, 0x411111f0 }, /* N/A */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) { 0x1f, 0x02a191f0 }, /* mic */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) { 0x20, 0x411111f0 }, /* N/A */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) [AD1986A_FIXUP_LAPTOP_IMIC] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) .type = HDA_FIXUP_PINS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) .v.pins = (const struct hda_pintbl[]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) { 0x1d, 0x90a7013e }, /* int mic */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) .chained_before = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) .chain_id = AD1986A_FIXUP_LAPTOP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) [AD1986A_FIXUP_EAPD] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) .type = HDA_FIXUP_FUNC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) .v.func = ad1986a_fixup_eapd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) [AD1986A_FIXUP_EAPD_MIX_IN] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) .type = HDA_FIXUP_FUNC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) .v.func = ad1986a_fixup_eapd_mix_in,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) [AD1986A_FIXUP_EASYNOTE] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) .type = HDA_FIXUP_PINS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) .v.pins = (const struct hda_pintbl[]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) { 0x1a, 0x0421402f }, /* headphone */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) { 0x1b, 0x90170110 }, /* speaker */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) { 0x1c, 0x411111f0 }, /* N/A */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) { 0x1d, 0x90a70130 }, /* int mic */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) { 0x1e, 0x411111f0 }, /* N/A */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) { 0x1f, 0x04a19040 }, /* mic */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) { 0x20, 0x411111f0 }, /* N/A */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) { 0x21, 0x411111f0 }, /* N/A */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) { 0x22, 0x411111f0 }, /* N/A */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) { 0x23, 0x411111f0 }, /* N/A */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) { 0x24, 0x411111f0 }, /* N/A */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) { 0x25, 0x411111f0 }, /* N/A */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) .chained = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) .chain_id = AD1986A_FIXUP_EAPD_MIX_IN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) static const struct snd_pci_quirk ad1986a_fixup_tbl[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_FIXUP_LAPTOP_IMIC),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9V", AD1986A_FIXUP_LAPTOP_IMIC),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) SND_PCI_QUIRK(0x1043, 0x1443, "ASUS Z99He", AD1986A_FIXUP_EAPD),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8JN", AD1986A_FIXUP_EAPD),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8100, "ASUS P5", AD1986A_FIXUP_3STACK),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8200, "ASUS M2", AD1986A_FIXUP_3STACK),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_FIXUP_3STACK),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40", AD1986A_FIXUP_EAPD),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_FIXUP_LAPTOP),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_FIXUP_SAMSUNG),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_FIXUP_ULTRA),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) SND_PCI_QUIRK(0x1631, 0xc022, "PackardBell EasyNote MX65", AD1986A_FIXUP_EASYNOTE),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_FIXUP_3STACK),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_FIXUP_3STACK),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) static const struct hda_model_fixup ad1986a_fixup_models[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) { .id = AD1986A_FIXUP_3STACK, .name = "3stack" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) { .id = AD1986A_FIXUP_LAPTOP, .name = "laptop" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-imic" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-eapd" }, /* alias */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) { .id = AD1986A_FIXUP_EAPD, .name = "eapd" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) static int patch_ad1986a(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) struct ad198x_spec *spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) static const hda_nid_t preferred_pairs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 0x1a, 0x03,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) 0x1b, 0x03,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) 0x1c, 0x04,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) 0x1d, 0x05,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) 0x1e, 0x03,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) err = alloc_ad_spec(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) /* AD1986A has the inverted EAPD implementation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) codec->inv_eapd = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) spec->gen.mixer_nid = 0x07;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) spec->gen.beep_nid = 0x19;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) /* AD1986A has a hardware problem that it can't share a stream
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) * with multiple output pins. The copy of front to surrounds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) * causes noisy or silent outputs at a certain timing, e.g.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) * changing the volume.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) * So, let's disable the shared stream.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) spec->gen.multiout.no_share_stream = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) /* give fixed DAC/pin pairs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) spec->gen.preferred_dacs = preferred_pairs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) /* AD1986A can't manage the dynamic pin on/off smoothly */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) spec->gen.auto_mute_via_amp = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) snd_hda_pick_fixup(codec, ad1986a_fixup_models, ad1986a_fixup_tbl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) ad1986a_fixups);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) err = ad198x_parse_auto_config(codec, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) snd_hda_gen_free(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) * AD1983 specific
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) * SPDIF mux control for AD1983 auto-parser
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) static int ad1983_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) struct snd_ctl_elem_info *uinfo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) struct ad198x_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) static const char * const texts2[] = { "PCM", "ADC" };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) static const char * const texts3[] = { "PCM", "ADC1", "ADC2" };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) int num_conns = spec->num_smux_conns;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) if (num_conns == 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) return snd_hda_enum_helper_info(kcontrol, uinfo, 2, texts2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) else if (num_conns == 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) static int ad1983_auto_smux_enum_get(struct snd_kcontrol *kcontrol,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) struct ad198x_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) ucontrol->value.enumerated.item[0] = spec->cur_smux;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) static int ad1983_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) struct ad198x_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) unsigned int val = ucontrol->value.enumerated.item[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) int num_conns = spec->num_smux_conns;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) if (val >= num_conns)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) if (spec->cur_smux == val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) spec->cur_smux = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) snd_hda_codec_write_cache(codec, dig_out, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) AC_VERB_SET_CONNECT_SEL, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) static const struct snd_kcontrol_new ad1983_auto_smux_mixer = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) .name = "IEC958 Playback Source",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) .info = ad1983_auto_smux_enum_info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) .get = ad1983_auto_smux_enum_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) .put = ad1983_auto_smux_enum_put,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) static int ad1983_add_spdif_mux_ctl(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) struct ad198x_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) int num_conns;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) if (!dig_out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) num_conns = snd_hda_get_num_conns(codec, dig_out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) if (num_conns != 2 && num_conns != 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) spec->num_smux_conns = num_conns;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1983_auto_smux_mixer))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) static int patch_ad1983(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) static const hda_nid_t conn_0c[] = { 0x08 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) static const hda_nid_t conn_0d[] = { 0x09 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) struct ad198x_spec *spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) err = alloc_ad_spec(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) spec->gen.mixer_nid = 0x0e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) spec->gen.beep_nid = 0x10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) /* limit the loopback routes not to confuse the parser */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) snd_hda_override_conn_list(codec, 0x0c, ARRAY_SIZE(conn_0c), conn_0c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) snd_hda_override_conn_list(codec, 0x0d, ARRAY_SIZE(conn_0d), conn_0d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) err = ad198x_parse_auto_config(codec, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) err = ad1983_add_spdif_mux_ctl(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) snd_hda_gen_free(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) * AD1981 HD specific
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) static void ad1981_fixup_hp_eapd(struct hda_codec *codec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) const struct hda_fixup *fix, int action)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) struct ad198x_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) if (action == HDA_FIXUP_ACT_PRE_PROBE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) spec->eapd_nid = 0x05;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) /* set the upper-limit for mixer amp to 0dB for avoiding the possible
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) * damage by overloading
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) static void ad1981_fixup_amp_override(struct hda_codec *codec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) const struct hda_fixup *fix, int action)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) if (action == HDA_FIXUP_ACT_PRE_PROBE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) (1 << AC_AMPCAP_MUTE_SHIFT));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) enum {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) AD1981_FIXUP_AMP_OVERRIDE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) AD1981_FIXUP_HP_EAPD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) static const struct hda_fixup ad1981_fixups[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) [AD1981_FIXUP_AMP_OVERRIDE] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) .type = HDA_FIXUP_FUNC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) .v.func = ad1981_fixup_amp_override,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) [AD1981_FIXUP_HP_EAPD] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) .type = HDA_FIXUP_FUNC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) .v.func = ad1981_fixup_hp_eapd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) .chained = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) .chain_id = AD1981_FIXUP_AMP_OVERRIDE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) static const struct snd_pci_quirk ad1981_fixup_tbl[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) SND_PCI_QUIRK_VENDOR(0x1014, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1981_FIXUP_HP_EAPD),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) /* HP nx6320 (reversed SSID, H/W bug) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_FIXUP_HP_EAPD),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) static int patch_ad1981(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) struct ad198x_spec *spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) err = alloc_ad_spec(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) spec->gen.mixer_nid = 0x0e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) spec->gen.beep_nid = 0x10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) snd_hda_pick_fixup(codec, NULL, ad1981_fixup_tbl, ad1981_fixups);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) err = ad198x_parse_auto_config(codec, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) err = ad1983_add_spdif_mux_ctl(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) snd_hda_gen_free(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) * AD1988
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) * Output pins and routes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) * Pin Mix Sel DAC (*)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) * port-A 0x11 (mute/hp) <- 0x22 <- 0x37 <- 03/04/06
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) * port-B 0x14 (mute/hp) <- 0x2b <- 0x30 <- 03/04/06
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) * port-C 0x15 (mute) <- 0x2c <- 0x31 <- 05/0a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) * port-D 0x12 (mute/hp) <- 0x29 <- 04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) * port-E 0x17 (mute/hp) <- 0x26 <- 0x32 <- 05/0a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) * port-F 0x16 (mute) <- 0x2a <- 06
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) * port-G 0x24 (mute) <- 0x27 <- 05
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) * port-H 0x25 (mute) <- 0x28 <- 0a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) * mono 0x13 (mute/amp)<- 0x1e <- 0x36 <- 03/04/06
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) * DAC0 = 03h, DAC1 = 04h, DAC2 = 05h, DAC3 = 06h, DAC4 = 0ah
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) * (*) DAC2/3/4 are swapped to DAC3/4/2 on AD198A rev.2 due to a h/w bug.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) * Input pins and routes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) * pin boost mix input # / adc input #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) * port-A 0x11 -> 0x38 -> mix 2, ADC 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) * port-B 0x14 -> 0x39 -> mix 0, ADC 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) * port-C 0x15 -> 0x3a -> 33:0 - mix 1, ADC 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) * port-D 0x12 -> 0x3d -> mix 3, ADC 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) * port-E 0x17 -> 0x3c -> 34:0 - mix 4, ADC 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) * port-F 0x16 -> 0x3b -> mix 5, ADC 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) * port-G 0x24 -> N/A -> 33:1 - mix 1, 34:1 - mix 4, ADC 6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) * port-H 0x25 -> N/A -> 33:2 - mix 1, 34:2 - mix 4, ADC 7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) * DAC assignment
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) * 6stack - front/surr/CLFE/side/opt DACs - 04/06/05/0a/03
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) * 3stack - front/surr/CLFE/opt DACs - 04/05/0a/03
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) * Inputs of Analog Mix (0x20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) * 0:Port-B (front mic)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) * 1:Port-C/G/H (line-in)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) * 2:Port-A
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) * 3:Port-D (line-in/2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) * 4:Port-E/G/H (mic-in)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) * 5:Port-F (mic2-in)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) * 6:CD
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) * 7:Beep
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) * ADC selection
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) * 0:Port-A
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) * 1:Port-B (front mic-in)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) * 2:Port-C (line-in)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) * 3:Port-F (mic2-in)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) * 4:Port-E (mic-in)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) * 5:CD
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) * 6:Port-G
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) * 7:Port-H
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) * 8:Port-D (line-in/2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) * 9:Mix
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) * Proposed pin assignments by the datasheet
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) * 6-stack
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) * Port-A front headphone
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) * B front mic-in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) * C rear line-in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) * D rear front-out
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) * E rear mic-in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) * F rear surround
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) * G rear CLFE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) * H rear side
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) * 3-stack
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) * Port-A front headphone
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) * B front mic
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) * C rear line-in/surround
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) * D rear front-out
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) * E rear mic-in/CLFE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) * laptop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) * Port-A headphone
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) * B mic-in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) * C docking station
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) * D internal speaker (with EAPD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) * E/F quad mic array
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) struct snd_ctl_elem_info *uinfo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) struct ad198x_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) static const char * const texts[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) "PCM", "ADC1", "ADC2", "ADC3",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) int num_conns = spec->num_smux_conns;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) if (num_conns > 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) num_conns = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) return snd_hda_enum_helper_info(kcontrol, uinfo, num_conns, texts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) static int ad1988_auto_smux_enum_get(struct snd_kcontrol *kcontrol,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) struct ad198x_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) ucontrol->value.enumerated.item[0] = spec->cur_smux;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) static int ad1988_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) struct ad198x_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) unsigned int val = ucontrol->value.enumerated.item[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) struct nid_path *path;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) int num_conns = spec->num_smux_conns;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) if (val >= num_conns)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) if (spec->cur_smux == val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) mutex_lock(&codec->control_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) path = snd_hda_get_path_from_idx(codec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) spec->smux_paths[spec->cur_smux]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) if (path)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) snd_hda_activate_path(codec, path, false, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) path = snd_hda_get_path_from_idx(codec, spec->smux_paths[val]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) if (path)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) snd_hda_activate_path(codec, path, true, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) spec->cur_smux = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) mutex_unlock(&codec->control_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) static const struct snd_kcontrol_new ad1988_auto_smux_mixer = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) .name = "IEC958 Playback Source",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) .info = ad1988_auto_smux_enum_info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) .get = ad1988_auto_smux_enum_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) .put = ad1988_auto_smux_enum_put,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) static int ad1988_auto_init(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) struct ad198x_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) int i, err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) err = snd_hda_gen_init(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) if (!spec->gen.autocfg.dig_outs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) for (i = 0; i < 4; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) struct nid_path *path;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) path = snd_hda_get_path_from_idx(codec, spec->smux_paths[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) if (path)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) snd_hda_activate_path(codec, path, path->active, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) static int ad1988_add_spdif_mux_ctl(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) struct ad198x_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) int i, num_conns;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) /* we create four static faked paths, since AD codecs have odd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) * widget connections regarding the SPDIF out source
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) static const struct nid_path fake_paths[4] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) .depth = 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) .path = { 0x02, 0x1d, 0x1b },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) .idx = { 0, 0, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) .multi = { 0, 0, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) .depth = 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) .path = { 0x08, 0x0b, 0x1d, 0x1b },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) .idx = { 0, 0, 1, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) .multi = { 0, 1, 0, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) .depth = 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) .path = { 0x09, 0x0b, 0x1d, 0x1b },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) .idx = { 0, 1, 1, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) .multi = { 0, 1, 0, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) .depth = 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) .path = { 0x0f, 0x0b, 0x1d, 0x1b },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) .idx = { 0, 2, 1, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) .multi = { 0, 1, 0, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) /* SPDIF source mux appears to be present only on AD1988A */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) if (!spec->gen.autocfg.dig_outs ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) get_wcaps_type(get_wcaps(codec, 0x1d)) != AC_WID_AUD_MIX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) if (num_conns != 3 && num_conns != 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) spec->num_smux_conns = num_conns;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) for (i = 0; i < num_conns; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) struct nid_path *path = snd_array_new(&spec->gen.paths);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) if (!path)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) *path = fake_paths[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) if (!i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) path->active = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) spec->smux_paths[i] = snd_hda_get_path_idx(codec, path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1988_auto_smux_mixer))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) codec->patch_ops.init = ad1988_auto_init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) enum {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) AD1988_FIXUP_6STACK_DIG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) static const struct hda_fixup ad1988_fixups[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) [AD1988_FIXUP_6STACK_DIG] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) .type = HDA_FIXUP_PINS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) .v.pins = (const struct hda_pintbl[]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) { 0x11, 0x02214130 }, /* front-hp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) { 0x12, 0x01014010 }, /* line-out */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) { 0x14, 0x02a19122 }, /* front-mic */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) { 0x15, 0x01813021 }, /* line-in */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) { 0x16, 0x01011012 }, /* line-out */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) { 0x17, 0x01a19020 }, /* mic */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) { 0x1b, 0x0145f1f0 }, /* SPDIF */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) { 0x24, 0x01016011 }, /* line-out */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) { 0x25, 0x01012013 }, /* line-out */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) static const struct hda_model_fixup ad1988_fixup_models[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) { .id = AD1988_FIXUP_6STACK_DIG, .name = "6stack-dig" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) static int patch_ad1988(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) struct ad198x_spec *spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) err = alloc_ad_spec(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) spec->gen.mixer_nid = 0x20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) spec->gen.mixer_merge_nid = 0x21;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) spec->gen.beep_nid = 0x10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) snd_hda_pick_fixup(codec, ad1988_fixup_models, NULL, ad1988_fixups);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) err = ad198x_parse_auto_config(codec, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) err = ad1988_add_spdif_mux_ctl(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) snd_hda_gen_free(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) * AD1884 / AD1984
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) * port-B - front line/mic-in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) * port-E - aux in/out
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) * port-F - aux in/out
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) * port-C - rear line/mic-in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) * port-D - rear line/hp-out
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) * port-A - front line/hp-out
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) * AD1984 = AD1884 + two digital mic-ins
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) * AD1883 / AD1884A / AD1984A / AD1984B
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) * port-B (0x14) - front mic-in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) * port-E (0x1c) - rear mic-in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) * port-F (0x16) - CD / ext out
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) * port-C (0x15) - rear line-in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) * port-D (0x12) - rear line-out
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) * port-A (0x11) - front hp-out
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) * AD1984A = AD1884A + digital-mic
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) * AD1883 = equivalent with AD1984A
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) * AD1984B = AD1984A + extra SPDIF-out
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) /* set the upper-limit for mixer amp to 0dB for avoiding the possible
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) * damage by overloading
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) static void ad1884_fixup_amp_override(struct hda_codec *codec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) const struct hda_fixup *fix, int action)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) if (action == HDA_FIXUP_ACT_PRE_PROBE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) (1 << AC_AMPCAP_MUTE_SHIFT));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) /* toggle GPIO1 according to the mute state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) static void ad1884_vmaster_hp_gpio_hook(void *private_data, int enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) struct hda_codec *codec = private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) struct ad198x_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) if (spec->eapd_nid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) ad_vmaster_eapd_hook(private_data, enabled);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) snd_hda_codec_write_cache(codec, 0x01, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) AC_VERB_SET_GPIO_DATA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) enabled ? 0x00 : 0x02);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) static void ad1884_fixup_hp_eapd(struct hda_codec *codec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) const struct hda_fixup *fix, int action)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) struct ad198x_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) switch (action) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) case HDA_FIXUP_ACT_PRE_PROBE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) spec->gen.vmaster_mute.hook = ad1884_vmaster_hp_gpio_hook;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) spec->gen.own_eapd_ctl = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) snd_hda_codec_write_cache(codec, 0x01, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) AC_VERB_SET_GPIO_MASK, 0x02);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) snd_hda_codec_write_cache(codec, 0x01, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) AC_VERB_SET_GPIO_DIRECTION, 0x02);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) snd_hda_codec_write_cache(codec, 0x01, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) AC_VERB_SET_GPIO_DATA, 0x02);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) case HDA_FIXUP_ACT_PROBE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) spec->eapd_nid = spec->gen.autocfg.line_out_pins[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) spec->eapd_nid = spec->gen.autocfg.speaker_pins[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) static void ad1884_fixup_thinkpad(struct hda_codec *codec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) const struct hda_fixup *fix, int action)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) struct ad198x_spec *spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) if (action == HDA_FIXUP_ACT_PRE_PROBE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) spec->gen.keep_eapd_on = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) spec->eapd_nid = 0x12;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) /* Analog PC Beeper - allow firmware/ACPI beeps */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) spec->beep_amp = HDA_COMPOSE_AMP_VAL(0x20, 3, 3, HDA_INPUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) spec->gen.beep_nid = 0; /* no digital beep */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) /* set magic COEFs for dmic */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) static const struct hda_verb ad1884_dmic_init_verbs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) {0x01, AC_VERB_SET_PROC_COEF, 0x08},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) enum {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) AD1884_FIXUP_AMP_OVERRIDE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) AD1884_FIXUP_HP_EAPD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) AD1884_FIXUP_DMIC_COEF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) AD1884_FIXUP_THINKPAD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) AD1884_FIXUP_HP_TOUCHSMART,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) static const struct hda_fixup ad1884_fixups[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) [AD1884_FIXUP_AMP_OVERRIDE] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) .type = HDA_FIXUP_FUNC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) .v.func = ad1884_fixup_amp_override,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) [AD1884_FIXUP_HP_EAPD] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) .type = HDA_FIXUP_FUNC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) .v.func = ad1884_fixup_hp_eapd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) .chained = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) .chain_id = AD1884_FIXUP_AMP_OVERRIDE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) [AD1884_FIXUP_DMIC_COEF] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) .type = HDA_FIXUP_VERBS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) .v.verbs = ad1884_dmic_init_verbs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) [AD1884_FIXUP_THINKPAD] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) .type = HDA_FIXUP_FUNC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) .v.func = ad1884_fixup_thinkpad,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) .chained = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) .chain_id = AD1884_FIXUP_DMIC_COEF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) [AD1884_FIXUP_HP_TOUCHSMART] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) .type = HDA_FIXUP_VERBS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) .v.verbs = ad1884_dmic_init_verbs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) .chained = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) .chain_id = AD1884_FIXUP_HP_EAPD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) static const struct snd_pci_quirk ad1884_fixup_tbl[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) SND_PCI_QUIRK(0x103c, 0x2a82, "HP Touchsmart", AD1884_FIXUP_HP_TOUCHSMART),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1884_FIXUP_THINKPAD),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) static int patch_ad1884(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) struct ad198x_spec *spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) err = alloc_ad_spec(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) spec->gen.mixer_nid = 0x20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) spec->gen.mixer_merge_nid = 0x21;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) spec->gen.beep_nid = 0x10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) snd_hda_pick_fixup(codec, NULL, ad1884_fixup_tbl, ad1884_fixups);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) err = ad198x_parse_auto_config(codec, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) err = ad1983_add_spdif_mux_ctl(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) snd_hda_gen_free(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) * AD1882 / AD1882A
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) * port-A - front hp-out
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) * port-B - front mic-in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) * port-C - rear line-in, shared surr-out (3stack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) * port-D - rear line-out
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) * port-E - rear mic-in, shared clfe-out (3stack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) * port-F - rear surr-out (6stack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) * port-G - rear clfe-out (6stack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) static int patch_ad1882(struct hda_codec *codec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) struct ad198x_spec *spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) err = alloc_ad_spec(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) spec = codec->spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) spec->gen.mixer_nid = 0x20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) spec->gen.mixer_merge_nid = 0x21;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) spec->gen.beep_nid = 0x10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) err = ad198x_parse_auto_config(codec, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) err = ad1988_add_spdif_mux_ctl(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) snd_hda_gen_free(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) * patch entries
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) static const struct hda_device_id snd_hda_id_analog[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) HDA_CODEC_ENTRY(0x11d4184a, "AD1884A", patch_ad1884),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) HDA_CODEC_ENTRY(0x11d41882, "AD1882", patch_ad1882),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) HDA_CODEC_ENTRY(0x11d41883, "AD1883", patch_ad1884),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) HDA_CODEC_ENTRY(0x11d41884, "AD1884", patch_ad1884),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) HDA_CODEC_ENTRY(0x11d4194a, "AD1984A", patch_ad1884),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) HDA_CODEC_ENTRY(0x11d4194b, "AD1984B", patch_ad1884),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) HDA_CODEC_ENTRY(0x11d41981, "AD1981", patch_ad1981),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) HDA_CODEC_ENTRY(0x11d41983, "AD1983", patch_ad1983),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) HDA_CODEC_ENTRY(0x11d41984, "AD1984", patch_ad1884),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) HDA_CODEC_ENTRY(0x11d41986, "AD1986A", patch_ad1986a),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) HDA_CODEC_ENTRY(0x11d41988, "AD1988", patch_ad1988),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) HDA_CODEC_ENTRY(0x11d4198b, "AD1988B", patch_ad1988),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) HDA_CODEC_ENTRY(0x11d4882a, "AD1882A", patch_ad1882),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) HDA_CODEC_ENTRY(0x11d4989a, "AD1989A", patch_ad1988),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) HDA_CODEC_ENTRY(0x11d4989b, "AD1989B", patch_ad1988),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) {} /* terminator */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_analog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) MODULE_DESCRIPTION("Analog Devices HD-audio codec");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) static struct hda_codec_driver analog_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) .id = snd_hda_id_analog,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) module_hda_codec_driver(analog_driver);