--- /home/ezio/tmp/kernel/linux-6.18.24/sound/hda/codecs/ca0132.c.0 2026-05-02 09:19:21.217137158 +0200 +++ /home/ezio/tmp/kernel/linux-6.18.24/sound/hda/codecs/ca0132.c 2026-05-10 11:21:41.933355825 +0200 @@ -24,6 +24,7 @@ #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" +#include "generic.h" #include "ca0132_regs.h" @@ -1060,6 +1061,8 @@ */ struct ca0132_spec { + struct hda_gen_spec gen; + const struct snd_kcontrol_new *mixers[5]; unsigned int num_mixers; const struct hda_verb *base_init_verbs; @@ -1175,6 +1178,7 @@ QUIRK_AE5, QUIRK_AE7, QUIRK_NONE = HDA_FIXUP_ID_NOT_SET, + QUIRK_GENERIC, }; #ifdef CONFIG_PCI @@ -1304,6 +1308,7 @@ SND_PCI_QUIRK(0x1458, 0xA016, "Recon3Di", QUIRK_R3DI), SND_PCI_QUIRK(0x1458, 0xA026, "Gigabyte G1.Sniper Z97", QUIRK_R3DI), SND_PCI_QUIRK(0x1458, 0xA036, "Gigabyte GA-Z170X-Gaming 7", QUIRK_R3DI), + SND_PCI_QUIRK(0x1458, 0xA046, "Gigabyte GA-Z170X-Gaming G1", QUIRK_GENERIC), SND_PCI_QUIRK(0x3842, 0x1038, "EVGA X99 Classified", QUIRK_R3DI), SND_PCI_QUIRK(0x3842, 0x104b, "EVGA X299 Dark", QUIRK_R3DI), SND_PCI_QUIRK(0x3842, 0x1055, "EVGA Z390 DARK", QUIRK_R3DI), @@ -1325,11 +1330,13 @@ { .id = QUIRK_R3D, .name = "r3d" }, { .id = QUIRK_AE5, .name = "ae5" }, { .id = QUIRK_AE7, .name = "ae7" }, + { .id = QUIRK_GENERIC, .name = "generic" }, {} }; /* Output selection quirk info structures. */ #define MAX_QUIRK_MMIO_GPIO_SET_VALS 3 + #define MAX_QUIRK_SCP_SET_VALS 2 struct ca0132_alt_out_set_info { unsigned int dac2port; /* ParamID 0x0d value. */ @@ -9821,7 +9828,7 @@ static int ca0132_prepare_verbs(struct hda_codec *codec) { /* Verbs + terminator (an empty element) */ -#define NUM_SPEC_VERBS 2 +#define NUM_SPEC_VERBS 3 struct ca0132_spec *spec = codec->spec; spec->chip_init_verbs = ca0132_init_verbs0; @@ -9842,6 +9849,11 @@ spec->spec_init_verbs[0].param = 0x78D; spec->spec_init_verbs[0].verb = 0x00; + /* VREF_50 for mic pin */ + spec->spec_init_verbs[1].nid = 0x12; + spec->spec_init_verbs[1].verb = AC_VERB_SET_PIN_WIDGET_CONTROL; + spec->spec_init_verbs[1].param = 0x21; /* IN | VREF_50 */ + /* Previously commented configuration */ /* spec->spec_init_verbs[2].nid = 0x0b; @@ -9882,10 +9894,20 @@ } } +static void ca0132_generic_init_hook(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + snd_hda_sequence_write(codec, spec->spec_init_verbs); +} + static void ca0132_codec_remove(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; + if (ca0132_quirk(spec) == QUIRK_GENERIC) { + snd_hda_gen_remove(codec); + return; + } if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO) return dbpro_free(codec); else @@ -9906,14 +9928,55 @@ codec->spec = spec; spec->codec = codec; + /* These must be set before any path is taken */ + codec->pcm_format_first = 1; + codec->no_sticky_stream = 1; + /* Detect codec quirk */ snd_hda_pick_fixup(codec, ca0132_quirk_models, ca0132_quirks, NULL); if (ca0132_quirk(spec) == QUIRK_SBZ) sbz_detect_quirk(codec); - codec->pcm_format_first = 1; - codec->no_sticky_stream = 1; + if (ca0132_quirk(spec) == QUIRK_GENERIC) { + struct auto_pin_cfg *cfg = &spec->gen.autocfg; + + snd_hda_gen_spec_init(&spec->gen); + + snd_hda_apply_pincfgs(codec, + (const struct hda_pintbl[]) { + { 0x0b, 0x41014111 }, + { 0x0c, 0x414520f0 }, /* SPDIF out */ + { 0x0d, 0x01014010 }, /* lineout */ + { 0x0e, 0x41c501f0 }, + { 0x0f, 0x411111f0 }, /* disabled */ + { 0x10, 0x411111f0 }, /* disabled */ + { 0x11, 0x41012014 }, + { 0x12, 0x37a790f0 }, /* mic */ + { 0x13, 0x77a701f0 }, + { 0x18, 0x500000f0 }, + {} + }); + ca0132_init_chip(codec); + + err = ca0132_prepare_verbs(codec); + if (err < 0) + goto error; + + err = snd_hda_parse_pin_def_config(codec, cfg, NULL); + if (err < 0) + goto error; + err = snd_hda_gen_parse_auto_config(codec, cfg); + if (err < 0) + goto error; + + spec->gen.init_hook = ca0132_generic_init_hook; + spec->gen.automute_speaker = 0; + spec->gen.automute_lo = 0; + + snd_hda_sequence_write(codec, spec->spec_init_verbs); + return 0; + } spec->dsp_state = DSP_DOWNLOAD_INIT; spec->num_mixers = 1; @@ -10014,6 +10077,10 @@ { struct ca0132_spec *spec = codec->spec; + if (ca0132_quirk(spec) == QUIRK_GENERIC) { + return snd_hda_gen_build_controls(codec); + } + if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO) return dbpro_build_controls(codec); else @@ -10024,6 +10091,10 @@ { struct ca0132_spec *spec = codec->spec; + if (ca0132_quirk(spec) == QUIRK_GENERIC) { + return snd_hda_gen_build_pcms(codec); + } + if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO) return dbpro_build_pcms(codec); else @@ -10034,6 +10105,10 @@ { struct ca0132_spec *spec = codec->spec; + if (ca0132_quirk(spec) == QUIRK_GENERIC) { + return snd_hda_gen_init(codec); + } + if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO) return dbpro_init(codec); else @@ -10044,6 +10119,9 @@ { struct ca0132_spec *spec = codec->spec; + if (ca0132_quirk(spec) == QUIRK_GENERIC) + return 0; + cancel_delayed_work_sync(&spec->unsol_hp_work); return 0; }