Linux Sound subsystem development
 help / color / mirror / Atom feed
From: "eziogale@gmail.com" <eziogale@gmail.com>
To: Takashi Iwai ` <tiwai@suse.com>, Jaroslav Kysela ` <perex@perex.cz>
Cc: linux-sound@vger.kernel.org, alsa-devel@alsa-project.org
Subject: ca0132: add generic parser fallback for broken DSP path
Date: Sun, 10 May 2026 11:38:49 +0200	[thread overview]
Message-ID: <a1dd5dfd-8678-4dd9-b6af-68a1e078168a@gmail.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 570 bytes --]

Some CA0132 implementations (e.g. Gigabyte GA-Z170X-Gaming G1)
produce white noise when using the DSP firmware path. Add a
QUIRK_GENERIC path that uses the standard HDA generic parser
instead, with custom pin configs that disable the broken auto-mute
from HP jack detection.

Also applies VREF_50 on the mic pin and adds an init_hook for
suspend/resume stability.

Kernel version: 6.18.24
The PCI SSID this was tested on: `1458:a046`
it's been tested with PulseAudio and speaker-test
That the DSP path (QUIRK_SBZ) remains unchanged for cards that work with it.

Thanks


[-- Attachment #2: ca0132-generic-parser.patch --]
[-- Type: text/x-patch, Size: 5164 bytes --]

--- /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;
 }

                 reply	other threads:[~2026-05-10  9:38 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=a1dd5dfd-8678-4dd9-b6af-68a1e078168a@gmail.com \
    --to=eziogale@gmail.com \
    --cc=alsa-devel@alsa-project.org \
    --cc=linux-sound@vger.kernel.org \
    --cc=perex@perex.cz \
    --cc=tiwai@suse.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox