| // SPDX-License-Identifier: GPL-2.0-or-later |
| // |
| // Realtek ALC880 codec |
| // |
| |
| #include <linux/init.h> |
| #include <linux/module.h> |
| #include "realtek.h" |
| |
| static void alc880_unsol_event(struct hda_codec *codec, unsigned int res) |
| { |
| /* For some reason, the res given from ALC880 is broken. |
| Here we adjust it properly. */ |
| snd_hda_jack_unsol_event(codec, res >> 2); |
| } |
| |
| static int alc880_parse_auto_config(struct hda_codec *codec) |
| { |
| static const hda_nid_t alc880_ignore[] = { 0x1d, 0 }; |
| static const hda_nid_t alc880_ssids[] = { 0x15, 0x1b, 0x14, 0 }; |
| return alc_parse_auto_config(codec, alc880_ignore, alc880_ssids); |
| } |
| |
| /* |
| * ALC880 fix-ups |
| */ |
| enum { |
| ALC880_FIXUP_GPIO1, |
| ALC880_FIXUP_GPIO2, |
| ALC880_FIXUP_MEDION_RIM, |
| ALC880_FIXUP_LG, |
| ALC880_FIXUP_LG_LW25, |
| ALC880_FIXUP_W810, |
| ALC880_FIXUP_EAPD_COEF, |
| ALC880_FIXUP_TCL_S700, |
| ALC880_FIXUP_VOL_KNOB, |
| ALC880_FIXUP_FUJITSU, |
| ALC880_FIXUP_F1734, |
| ALC880_FIXUP_UNIWILL, |
| ALC880_FIXUP_UNIWILL_DIG, |
| ALC880_FIXUP_Z71V, |
| ALC880_FIXUP_ASUS_W5A, |
| ALC880_FIXUP_3ST_BASE, |
| ALC880_FIXUP_3ST, |
| ALC880_FIXUP_3ST_DIG, |
| ALC880_FIXUP_5ST_BASE, |
| ALC880_FIXUP_5ST, |
| ALC880_FIXUP_5ST_DIG, |
| ALC880_FIXUP_6ST_BASE, |
| ALC880_FIXUP_6ST, |
| ALC880_FIXUP_6ST_DIG, |
| ALC880_FIXUP_6ST_AUTOMUTE, |
| }; |
| |
| /* enable the volume-knob widget support on NID 0x21 */ |
| static void alc880_fixup_vol_knob(struct hda_codec *codec, |
| const struct hda_fixup *fix, int action) |
| { |
| if (action == HDA_FIXUP_ACT_PROBE) |
| snd_hda_jack_detect_enable_callback(codec, 0x21, |
| alc_update_knob_master); |
| } |
| |
| static const struct hda_fixup alc880_fixups[] = { |
| [ALC880_FIXUP_GPIO1] = { |
| .type = HDA_FIXUP_FUNC, |
| .v.func = alc_fixup_gpio1, |
| }, |
| [ALC880_FIXUP_GPIO2] = { |
| .type = HDA_FIXUP_FUNC, |
| .v.func = alc_fixup_gpio2, |
| }, |
| [ALC880_FIXUP_MEDION_RIM] = { |
| .type = HDA_FIXUP_VERBS, |
| .v.verbs = (const struct hda_verb[]) { |
| { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, |
| { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 }, |
| { } |
| }, |
| .chained = true, |
| .chain_id = ALC880_FIXUP_GPIO2, |
| }, |
| [ALC880_FIXUP_LG] = { |
| .type = HDA_FIXUP_PINS, |
| .v.pins = (const struct hda_pintbl[]) { |
| /* disable bogus unused pins */ |
| { 0x16, 0x411111f0 }, |
| { 0x18, 0x411111f0 }, |
| { 0x1a, 0x411111f0 }, |
| { } |
| } |
| }, |
| [ALC880_FIXUP_LG_LW25] = { |
| .type = HDA_FIXUP_PINS, |
| .v.pins = (const struct hda_pintbl[]) { |
| { 0x1a, 0x0181344f }, /* line-in */ |
| { 0x1b, 0x0321403f }, /* headphone */ |
| { } |
| } |
| }, |
| [ALC880_FIXUP_W810] = { |
| .type = HDA_FIXUP_PINS, |
| .v.pins = (const struct hda_pintbl[]) { |
| /* disable bogus unused pins */ |
| { 0x17, 0x411111f0 }, |
| { } |
| }, |
| .chained = true, |
| .chain_id = ALC880_FIXUP_GPIO2, |
| }, |
| [ALC880_FIXUP_EAPD_COEF] = { |
| .type = HDA_FIXUP_VERBS, |
| .v.verbs = (const struct hda_verb[]) { |
| /* change to EAPD mode */ |
| { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, |
| { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 }, |
| {} |
| }, |
| }, |
| [ALC880_FIXUP_TCL_S700] = { |
| .type = HDA_FIXUP_VERBS, |
| .v.verbs = (const struct hda_verb[]) { |
| /* change to EAPD mode */ |
| { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, |
| { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 }, |
| {} |
| }, |
| .chained = true, |
| .chain_id = ALC880_FIXUP_GPIO2, |
| }, |
| [ALC880_FIXUP_VOL_KNOB] = { |
| .type = HDA_FIXUP_FUNC, |
| .v.func = alc880_fixup_vol_knob, |
| }, |
| [ALC880_FIXUP_FUJITSU] = { |
| /* override all pins as BIOS on old Amilo is broken */ |
| .type = HDA_FIXUP_PINS, |
| .v.pins = (const struct hda_pintbl[]) { |
| { 0x14, 0x0121401f }, /* HP */ |
| { 0x15, 0x99030120 }, /* speaker */ |
| { 0x16, 0x99030130 }, /* bass speaker */ |
| { 0x17, 0x411111f0 }, /* N/A */ |
| { 0x18, 0x411111f0 }, /* N/A */ |
| { 0x19, 0x01a19950 }, /* mic-in */ |
| { 0x1a, 0x411111f0 }, /* N/A */ |
| { 0x1b, 0x411111f0 }, /* N/A */ |
| { 0x1c, 0x411111f0 }, /* N/A */ |
| { 0x1d, 0x411111f0 }, /* N/A */ |
| { 0x1e, 0x01454140 }, /* SPDIF out */ |
| { } |
| }, |
| .chained = true, |
| .chain_id = ALC880_FIXUP_VOL_KNOB, |
| }, |
| [ALC880_FIXUP_F1734] = { |
| /* almost compatible with FUJITSU, but no bass and SPDIF */ |
| .type = HDA_FIXUP_PINS, |
| .v.pins = (const struct hda_pintbl[]) { |
| { 0x14, 0x0121401f }, /* HP */ |
| { 0x15, 0x99030120 }, /* speaker */ |
| { 0x16, 0x411111f0 }, /* N/A */ |
| { 0x17, 0x411111f0 }, /* N/A */ |
| { 0x18, 0x411111f0 }, /* N/A */ |
| { 0x19, 0x01a19950 }, /* mic-in */ |
| { 0x1a, 0x411111f0 }, /* N/A */ |
| { 0x1b, 0x411111f0 }, /* N/A */ |
| { 0x1c, 0x411111f0 }, /* N/A */ |
| { 0x1d, 0x411111f0 }, /* N/A */ |
| { 0x1e, 0x411111f0 }, /* N/A */ |
| { } |
| }, |
| .chained = true, |
| .chain_id = ALC880_FIXUP_VOL_KNOB, |
| }, |
| [ALC880_FIXUP_UNIWILL] = { |
| /* need to fix HP and speaker pins to be parsed correctly */ |
| .type = HDA_FIXUP_PINS, |
| .v.pins = (const struct hda_pintbl[]) { |
| { 0x14, 0x0121411f }, /* HP */ |
| { 0x15, 0x99030120 }, /* speaker */ |
| { 0x16, 0x99030130 }, /* bass speaker */ |
| { } |
| }, |
| }, |
| [ALC880_FIXUP_UNIWILL_DIG] = { |
| .type = HDA_FIXUP_PINS, |
| .v.pins = (const struct hda_pintbl[]) { |
| /* disable bogus unused pins */ |
| { 0x17, 0x411111f0 }, |
| { 0x19, 0x411111f0 }, |
| { 0x1b, 0x411111f0 }, |
| { 0x1f, 0x411111f0 }, |
| { } |
| } |
| }, |
| [ALC880_FIXUP_Z71V] = { |
| .type = HDA_FIXUP_PINS, |
| .v.pins = (const struct hda_pintbl[]) { |
| /* set up the whole pins as BIOS is utterly broken */ |
| { 0x14, 0x99030120 }, /* speaker */ |
| { 0x15, 0x0121411f }, /* HP */ |
| { 0x16, 0x411111f0 }, /* N/A */ |
| { 0x17, 0x411111f0 }, /* N/A */ |
| { 0x18, 0x01a19950 }, /* mic-in */ |
| { 0x19, 0x411111f0 }, /* N/A */ |
| { 0x1a, 0x01813031 }, /* line-in */ |
| { 0x1b, 0x411111f0 }, /* N/A */ |
| { 0x1c, 0x411111f0 }, /* N/A */ |
| { 0x1d, 0x411111f0 }, /* N/A */ |
| { 0x1e, 0x0144111e }, /* SPDIF */ |
| { } |
| } |
| }, |
| [ALC880_FIXUP_ASUS_W5A] = { |
| .type = HDA_FIXUP_PINS, |
| .v.pins = (const struct hda_pintbl[]) { |
| /* set up the whole pins as BIOS is utterly broken */ |
| { 0x14, 0x0121411f }, /* HP */ |
| { 0x15, 0x411111f0 }, /* N/A */ |
| { 0x16, 0x411111f0 }, /* N/A */ |
| { 0x17, 0x411111f0 }, /* N/A */ |
| { 0x18, 0x90a60160 }, /* mic */ |
| { 0x19, 0x411111f0 }, /* N/A */ |
| { 0x1a, 0x411111f0 }, /* N/A */ |
| { 0x1b, 0x411111f0 }, /* N/A */ |
| { 0x1c, 0x411111f0 }, /* N/A */ |
| { 0x1d, 0x411111f0 }, /* N/A */ |
| { 0x1e, 0xb743111e }, /* SPDIF out */ |
| { } |
| }, |
| .chained = true, |
| .chain_id = ALC880_FIXUP_GPIO1, |
| }, |
| [ALC880_FIXUP_3ST_BASE] = { |
| .type = HDA_FIXUP_PINS, |
| .v.pins = (const struct hda_pintbl[]) { |
| { 0x14, 0x01014010 }, /* line-out */ |
| { 0x15, 0x411111f0 }, /* N/A */ |
| { 0x16, 0x411111f0 }, /* N/A */ |
| { 0x17, 0x411111f0 }, /* N/A */ |
| { 0x18, 0x01a19c30 }, /* mic-in */ |
| { 0x19, 0x0121411f }, /* HP */ |
| { 0x1a, 0x01813031 }, /* line-in */ |
| { 0x1b, 0x02a19c40 }, /* front-mic */ |
| { 0x1c, 0x411111f0 }, /* N/A */ |
| { 0x1d, 0x411111f0 }, /* N/A */ |
| /* 0x1e is filled in below */ |
| { 0x1f, 0x411111f0 }, /* N/A */ |
| { } |
| } |
| }, |
| [ALC880_FIXUP_3ST] = { |
| .type = HDA_FIXUP_PINS, |
| .v.pins = (const struct hda_pintbl[]) { |
| { 0x1e, 0x411111f0 }, /* N/A */ |
| { } |
| }, |
| .chained = true, |
| .chain_id = ALC880_FIXUP_3ST_BASE, |
| }, |
| [ALC880_FIXUP_3ST_DIG] = { |
| .type = HDA_FIXUP_PINS, |
| .v.pins = (const struct hda_pintbl[]) { |
| { 0x1e, 0x0144111e }, /* SPDIF */ |
| { } |
| }, |
| .chained = true, |
| .chain_id = ALC880_FIXUP_3ST_BASE, |
| }, |
| [ALC880_FIXUP_5ST_BASE] = { |
| .type = HDA_FIXUP_PINS, |
| .v.pins = (const struct hda_pintbl[]) { |
| { 0x14, 0x01014010 }, /* front */ |
| { 0x15, 0x411111f0 }, /* N/A */ |
| { 0x16, 0x01011411 }, /* CLFE */ |
| { 0x17, 0x01016412 }, /* surr */ |
| { 0x18, 0x01a19c30 }, /* mic-in */ |
| { 0x19, 0x0121411f }, /* HP */ |
| { 0x1a, 0x01813031 }, /* line-in */ |
| { 0x1b, 0x02a19c40 }, /* front-mic */ |
| { 0x1c, 0x411111f0 }, /* N/A */ |
| { 0x1d, 0x411111f0 }, /* N/A */ |
| /* 0x1e is filled in below */ |
| { 0x1f, 0x411111f0 }, /* N/A */ |
| { } |
| } |
| }, |
| [ALC880_FIXUP_5ST] = { |
| .type = HDA_FIXUP_PINS, |
| .v.pins = (const struct hda_pintbl[]) { |
| { 0x1e, 0x411111f0 }, /* N/A */ |
| { } |
| }, |
| .chained = true, |
| .chain_id = ALC880_FIXUP_5ST_BASE, |
| }, |
| [ALC880_FIXUP_5ST_DIG] = { |
| .type = HDA_FIXUP_PINS, |
| .v.pins = (const struct hda_pintbl[]) { |
| { 0x1e, 0x0144111e }, /* SPDIF */ |
| { } |
| }, |
| .chained = true, |
| .chain_id = ALC880_FIXUP_5ST_BASE, |
| }, |
| [ALC880_FIXUP_6ST_BASE] = { |
| .type = HDA_FIXUP_PINS, |
| .v.pins = (const struct hda_pintbl[]) { |
| { 0x14, 0x01014010 }, /* front */ |
| { 0x15, 0x01016412 }, /* surr */ |
| { 0x16, 0x01011411 }, /* CLFE */ |
| { 0x17, 0x01012414 }, /* side */ |
| { 0x18, 0x01a19c30 }, /* mic-in */ |
| { 0x19, 0x02a19c40 }, /* front-mic */ |
| { 0x1a, 0x01813031 }, /* line-in */ |
| { 0x1b, 0x0121411f }, /* HP */ |
| { 0x1c, 0x411111f0 }, /* N/A */ |
| { 0x1d, 0x411111f0 }, /* N/A */ |
| /* 0x1e is filled in below */ |
| { 0x1f, 0x411111f0 }, /* N/A */ |
| { } |
| } |
| }, |
| [ALC880_FIXUP_6ST] = { |
| .type = HDA_FIXUP_PINS, |
| .v.pins = (const struct hda_pintbl[]) { |
| { 0x1e, 0x411111f0 }, /* N/A */ |
| { } |
| }, |
| .chained = true, |
| .chain_id = ALC880_FIXUP_6ST_BASE, |
| }, |
| [ALC880_FIXUP_6ST_DIG] = { |
| .type = HDA_FIXUP_PINS, |
| .v.pins = (const struct hda_pintbl[]) { |
| { 0x1e, 0x0144111e }, /* SPDIF */ |
| { } |
| }, |
| .chained = true, |
| .chain_id = ALC880_FIXUP_6ST_BASE, |
| }, |
| [ALC880_FIXUP_6ST_AUTOMUTE] = { |
| .type = HDA_FIXUP_PINS, |
| .v.pins = (const struct hda_pintbl[]) { |
| { 0x1b, 0x0121401f }, /* HP with jack detect */ |
| { } |
| }, |
| .chained_before = true, |
| .chain_id = ALC880_FIXUP_6ST_BASE, |
| }, |
| }; |
| |
| static const struct hda_quirk alc880_fixup_tbl[] = { |
| SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_FIXUP_W810), |
| SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS W5A", ALC880_FIXUP_ASUS_W5A), |
| SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_FIXUP_Z71V), |
| SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_FIXUP_GPIO1), |
| SND_PCI_QUIRK(0x147b, 0x1045, "ABit AA8XE", ALC880_FIXUP_6ST_AUTOMUTE), |
| SND_PCI_QUIRK(0x1558, 0x5401, "Clevo GPIO2", ALC880_FIXUP_GPIO2), |
| SND_PCI_QUIRK_VENDOR(0x1558, "Clevo", ALC880_FIXUP_EAPD_COEF), |
| SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_FIXUP_UNIWILL_DIG), |
| SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_FIXUP_F1734), |
| SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_FIXUP_UNIWILL), |
| SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_FIXUP_VOL_KNOB), |
| SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_FIXUP_W810), |
| SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM), |
| SND_PCI_QUIRK(0x1631, 0xe011, "PB 13201056", ALC880_FIXUP_6ST_AUTOMUTE), |
| SND_PCI_QUIRK(0x1734, 0x107c, "FSC Amilo M1437", ALC880_FIXUP_FUJITSU), |
| SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FIXUP_FUJITSU), |
| SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_FIXUP_F1734), |
| SND_PCI_QUIRK(0x1734, 0x10b0, "FSC Amilo Pi1556", ALC880_FIXUP_FUJITSU), |
| SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_FIXUP_LG), |
| SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_FIXUP_LG), |
| SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_FIXUP_LG), |
| SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_FIXUP_LG_LW25), |
| SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_FIXUP_TCL_S700), |
| |
| /* Below is the copied entries from alc880_quirks.c. |
| * It's not quite sure whether BIOS sets the correct pin-config table |
| * on these machines, thus they are kept to be compatible with |
| * the old static quirks. Once when it's confirmed to work without |
| * these overrides, it'd be better to remove. |
| */ |
| SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_FIXUP_5ST_DIG), |
| SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_FIXUP_6ST), |
| SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_FIXUP_3ST_DIG), |
| SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_FIXUP_6ST_DIG), |
| SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_FIXUP_6ST_DIG), |
| SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_FIXUP_6ST_DIG), |
| SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_FIXUP_3ST_DIG), |
| SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_FIXUP_3ST), |
| SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_FIXUP_6ST_DIG), |
| SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_FIXUP_3ST), |
| SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_FIXUP_3ST), |
| SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_FIXUP_5ST), |
| SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_FIXUP_5ST), |
| SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_FIXUP_5ST), |
| SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_FIXUP_6ST_DIG), |
| SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_FIXUP_6ST_DIG), |
| SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_FIXUP_6ST_DIG), |
| SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_FIXUP_6ST_DIG), |
| SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_FIXUP_5ST_DIG), |
| SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_FIXUP_5ST_DIG), |
| SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_FIXUP_5ST_DIG), |
| SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_FIXUP_6ST_DIG), /* broken BIOS */ |
| SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_FIXUP_6ST_DIG), |
| SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_FIXUP_5ST_DIG), |
| SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_FIXUP_5ST_DIG), |
| SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_FIXUP_5ST_DIG), |
| SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_FIXUP_3ST_DIG), |
| SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_FIXUP_5ST_DIG), |
| SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_FIXUP_3ST_DIG), |
| SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_FIXUP_3ST_DIG), |
| SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_FIXUP_5ST_DIG), |
| SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_FIXUP_5ST_DIG), |
| SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_FIXUP_5ST_DIG), |
| /* default Intel */ |
| SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_FIXUP_3ST), |
| SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_FIXUP_5ST_DIG), |
| SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_FIXUP_6ST_DIG), |
| {} |
| }; |
| |
| static const struct hda_model_fixup alc880_fixup_models[] = { |
| {.id = ALC880_FIXUP_3ST, .name = "3stack"}, |
| {.id = ALC880_FIXUP_3ST_DIG, .name = "3stack-digout"}, |
| {.id = ALC880_FIXUP_5ST, .name = "5stack"}, |
| {.id = ALC880_FIXUP_5ST_DIG, .name = "5stack-digout"}, |
| {.id = ALC880_FIXUP_6ST, .name = "6stack"}, |
| {.id = ALC880_FIXUP_6ST_DIG, .name = "6stack-digout"}, |
| {.id = ALC880_FIXUP_6ST_AUTOMUTE, .name = "6stack-automute"}, |
| {} |
| }; |
| |
| |
| /* |
| * OK, here we have finally the probe for ALC880 |
| */ |
| static int alc880_probe(struct hda_codec *codec, const struct hda_device_id *id) |
| { |
| struct alc_spec *spec; |
| int err; |
| |
| err = alc_alloc_spec(codec, 0x0b); |
| if (err < 0) |
| return err; |
| |
| spec = codec->spec; |
| spec->gen.need_dac_fix = 1; |
| spec->gen.beep_nid = 0x01; |
| |
| alc_pre_init(codec); |
| |
| snd_hda_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl, |
| alc880_fixups); |
| snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); |
| |
| /* automatic parse from the BIOS config */ |
| err = alc880_parse_auto_config(codec); |
| if (err < 0) |
| goto error; |
| |
| if (!spec->gen.no_analog) { |
| err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); |
| if (err < 0) |
| goto error; |
| } |
| |
| snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); |
| |
| return 0; |
| |
| error: |
| snd_hda_gen_remove(codec); |
| return err; |
| } |
| |
| static const struct hda_codec_ops alc880_codec_ops = { |
| .probe = alc880_probe, |
| .remove = snd_hda_gen_remove, |
| .build_controls = alc_build_controls, |
| .build_pcms = snd_hda_gen_build_pcms, |
| .init = alc_init, |
| .unsol_event = alc880_unsol_event, |
| .resume = alc_resume, |
| .suspend = alc_suspend, |
| .check_power_status = snd_hda_gen_check_power_status, |
| .stream_pm = snd_hda_gen_stream_pm, |
| }; |
| |
| /* |
| * driver entries |
| */ |
| static const struct hda_device_id snd_hda_id_alc880[] = { |
| HDA_CODEC_ID(0x10ec0880, "ALC880"), |
| {} /* terminator */ |
| }; |
| MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc880); |
| |
| MODULE_LICENSE("GPL"); |
| MODULE_DESCRIPTION("Realtek ALC880 HD-audio codec"); |
| MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK"); |
| |
| static struct hda_codec_driver alc880_driver = { |
| .id = snd_hda_id_alc880, |
| .ops = &alc880_codec_ops, |
| }; |
| |
| module_hda_codec_driver(alc880_driver); |