]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ALSA: hda/senary: Add hardware init verbs and fixup framework
authorwangdicheng <wangdicheng@kylinos.cn>
Wed, 4 Mar 2026 07:02:19 +0000 (15:02 +0800)
committerTakashi Iwai <tiwai@suse.de>
Wed, 4 Mar 2026 11:06:37 +0000 (12:06 +0100)
Port the essential hardware initialization logic from the vendor driver
and introduce the standard HDA fixup framework to handle different
machine configurations.

Key changes:

1. Add hardware init verbs:
   - Implement `senary_init_verb` to send the vendor-specific
     initialization sequence required by the SN6186 chip.
   - Override pin capabilities for Node 0x19 to ensure proper headset
     microphone support.

2. Introduce fixup framework:
   - Define a default pin configuration table (`senary_pincfg_default`)
     to provide a fallback for devices with invalid BIOS configurations.
   - Establish a quirk table structure for future machine-specific
     fixes.
   - Since the standard quirk matching relies on Subsystem IDs, we
     manually apply the default fixup if `snd_hda_pick_fixup` does not
     find a specific match.

This ensures the chip is correctly initialized during probe and resume,
and provides a scalable mechanism for supporting specific hardware
quirks.

Signed-off-by: wangdicheng <wangdicheng@kylinos.cn>
Link: https://patch.msgid.link/20260304070219.450083-1-wangdich9700@163.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/hda/codecs/senarytech.c

index 6239a25bb8f32457cc62e3a412a07eec3e682628..f9a389df3a17597fb40893c84006a6e0f1cf691e 100644 (file)
@@ -36,6 +36,32 @@ struct senary_spec {
        unsigned int gpio_mic_led_mask;
 };
 
+enum {
+       SENARY_FIXUP_PINCFG_DEFAULT,
+};
+
+static const struct hda_pintbl senary_pincfg_default[] = {
+       { 0x16, 0x02211020 }, /* Headphone */
+       { 0x17, 0x40f001f0 }, /* Not used */
+       { 0x18, 0x05a1904d }, /* Mic */
+       { 0x19, 0x02a1104e }, /* Headset Mic */
+       { 0x1a, 0x01819030 }, /* Line-in */
+       { 0x1d, 0x01014010 }, /* Line-out */
+       {}
+};
+
+static const struct hda_fixup senary_fixups[] = {
+       [SENARY_FIXUP_PINCFG_DEFAULT] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = senary_pincfg_default,
+       },
+};
+
+/* Quirk table for specific machines can be added here */
+static const struct hda_quirk sn6186_fixups[] = {
+       {}
+};
+
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
 /* additional beep mixers; private_value will be overwritten */
 static const struct snd_kcontrol_new senary_beep_mixer[] = {
@@ -93,6 +119,19 @@ static void senary_auto_parse_eapd(struct hda_codec *codec)
        }
 }
 
+/* Hardware specific initialization verbs */
+static void senary_init_verb(struct hda_codec *codec)
+{
+       /* Vendor specific init sequence */
+       snd_hda_codec_write(codec, 0x1b, 0x0, 0x05a, 0xaa);
+       snd_hda_codec_write(codec, 0x1b, 0x0, 0x059, 0x48);
+       snd_hda_codec_write(codec, 0x1b, 0x0, 0x01b, 0x00);
+       snd_hda_codec_write(codec, 0x1b, 0x0, 0x01c, 0x00);
+
+       /* Override pin caps for headset mic */
+       snd_hda_override_pin_caps(codec, 0x19, 0x2124);
+}
+
 static void senary_auto_turn_eapd(struct hda_codec *codec, int num_pins,
                              const hda_nid_t *pins, bool on)
 {
@@ -136,6 +175,7 @@ static int senary_init(struct hda_codec *codec)
 
        snd_hda_gen_init(codec);
        senary_init_gpio_led(codec);
+       senary_init_verb(codec);
        if (!spec->dynamic_eapd)
                senary_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
        snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
@@ -181,11 +221,30 @@ static int senary_probe(struct hda_codec *codec, const struct hda_device_id *id)
        senary_auto_parse_eapd(codec);
        spec->gen.own_eapd_ctl = 1;
 
-       if (!spec->gen.vmaster_mute.hook)
-               spec->gen.vmaster_mute.hook = senary_auto_vmaster_hook;
+       /* Setup fixups based on codec vendor ID */
+       switch (codec->core.vendor_id) {
+       case 0x1fa86186:
+               codec->pin_amp_workaround = 1;
+               spec->gen.mixer_nid = 0x15;
+               snd_hda_pick_fixup(codec, NULL, sn6186_fixups, senary_fixups);
+
+               /* If no specific quirk found, apply the default pin configuration */
+               if (codec->fixup_id == HDA_FIXUP_ID_NOT_SET)
+                       codec->fixup_id = SENARY_FIXUP_PINCFG_DEFAULT;
+               break;
+       default:
+               snd_hda_pick_fixup(codec, NULL, sn6186_fixups, senary_fixups);
+               break;
+       }
 
        snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
 
+       /* Run hardware init verbs once during probe */
+       senary_init_verb(codec);
+
+       if (!spec->gen.vmaster_mute.hook)
+               spec->gen.vmaster_mute.hook = senary_auto_vmaster_hook;
+
        err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL,
                                       spec->parse_flags);
        if (err < 0)