summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwangdicheng <wangdicheng@kylinos.cn>2026-03-04 10:02:19 +0300
committerTakashi Iwai <tiwai@suse.de>2026-03-04 14:06:37 +0300
commit27b9bcad2bf77e12c08e36d8d72bd6ce0db46041 (patch)
tree3aa790be63337cc730ee2ad195ccb601e9564c66
parentdfd4b0d46e774d7fbd23a438ead45de08bde783e (diff)
downloadlinux-27b9bcad2bf77e12c08e36d8d72bd6ce0db46041.tar.xz
ALSA: hda/senary: Add hardware init verbs and fixup framework
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>
-rw-r--r--sound/hda/codecs/senarytech.c63
1 files changed, 61 insertions, 2 deletions
diff --git a/sound/hda/codecs/senarytech.c b/sound/hda/codecs/senarytech.c
index 6239a25bb8f3..f9a389df3a17 100644
--- a/sound/hda/codecs/senarytech.c
+++ b/sound/hda/codecs/senarytech.c
@@ -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)