1aeeb85f2STakashi Iwai // SPDX-License-Identifier: GPL-2.0-or-later
2aeeb85f2STakashi Iwai //
3aeeb85f2STakashi Iwai // Realtek ALC262 codec
4aeeb85f2STakashi Iwai //
5aeeb85f2STakashi Iwai
6aeeb85f2STakashi Iwai #include <linux/init.h>
7aeeb85f2STakashi Iwai #include <linux/module.h>
8aeeb85f2STakashi Iwai #include "realtek.h"
9aeeb85f2STakashi Iwai
alc262_parse_auto_config(struct hda_codec * codec)10aeeb85f2STakashi Iwai static int alc262_parse_auto_config(struct hda_codec *codec)
11aeeb85f2STakashi Iwai {
12aeeb85f2STakashi Iwai static const hda_nid_t alc262_ignore[] = { 0x1d, 0 };
13aeeb85f2STakashi Iwai static const hda_nid_t alc262_ssids[] = { 0x15, 0x1b, 0x14, 0 };
14aeeb85f2STakashi Iwai return alc_parse_auto_config(codec, alc262_ignore, alc262_ssids);
15aeeb85f2STakashi Iwai }
16aeeb85f2STakashi Iwai
17aeeb85f2STakashi Iwai /*
18aeeb85f2STakashi Iwai * Pin config fixes
19aeeb85f2STakashi Iwai */
20aeeb85f2STakashi Iwai enum {
21aeeb85f2STakashi Iwai ALC262_FIXUP_FSC_H270,
22aeeb85f2STakashi Iwai ALC262_FIXUP_FSC_S7110,
23aeeb85f2STakashi Iwai ALC262_FIXUP_HP_Z200,
24aeeb85f2STakashi Iwai ALC262_FIXUP_TYAN,
25aeeb85f2STakashi Iwai ALC262_FIXUP_LENOVO_3000,
26aeeb85f2STakashi Iwai ALC262_FIXUP_BENQ,
27aeeb85f2STakashi Iwai ALC262_FIXUP_BENQ_T31,
28aeeb85f2STakashi Iwai ALC262_FIXUP_INV_DMIC,
29aeeb85f2STakashi Iwai ALC262_FIXUP_INTEL_BAYLEYBAY,
30aeeb85f2STakashi Iwai };
31aeeb85f2STakashi Iwai
32aeeb85f2STakashi Iwai static const struct hda_fixup alc262_fixups[] = {
33aeeb85f2STakashi Iwai [ALC262_FIXUP_FSC_H270] = {
34aeeb85f2STakashi Iwai .type = HDA_FIXUP_PINS,
35aeeb85f2STakashi Iwai .v.pins = (const struct hda_pintbl[]) {
36aeeb85f2STakashi Iwai { 0x14, 0x99130110 }, /* speaker */
37aeeb85f2STakashi Iwai { 0x15, 0x0221142f }, /* front HP */
38aeeb85f2STakashi Iwai { 0x1b, 0x0121141f }, /* rear HP */
39aeeb85f2STakashi Iwai { }
40aeeb85f2STakashi Iwai }
41aeeb85f2STakashi Iwai },
42aeeb85f2STakashi Iwai [ALC262_FIXUP_FSC_S7110] = {
43aeeb85f2STakashi Iwai .type = HDA_FIXUP_PINS,
44aeeb85f2STakashi Iwai .v.pins = (const struct hda_pintbl[]) {
45aeeb85f2STakashi Iwai { 0x15, 0x90170110 }, /* speaker */
46aeeb85f2STakashi Iwai { }
47aeeb85f2STakashi Iwai },
48aeeb85f2STakashi Iwai .chained = true,
49aeeb85f2STakashi Iwai .chain_id = ALC262_FIXUP_BENQ,
50aeeb85f2STakashi Iwai },
51aeeb85f2STakashi Iwai [ALC262_FIXUP_HP_Z200] = {
52aeeb85f2STakashi Iwai .type = HDA_FIXUP_PINS,
53aeeb85f2STakashi Iwai .v.pins = (const struct hda_pintbl[]) {
54aeeb85f2STakashi Iwai { 0x16, 0x99130120 }, /* internal speaker */
55aeeb85f2STakashi Iwai { }
56aeeb85f2STakashi Iwai }
57aeeb85f2STakashi Iwai },
58aeeb85f2STakashi Iwai [ALC262_FIXUP_TYAN] = {
59aeeb85f2STakashi Iwai .type = HDA_FIXUP_PINS,
60aeeb85f2STakashi Iwai .v.pins = (const struct hda_pintbl[]) {
61aeeb85f2STakashi Iwai { 0x14, 0x1993e1f0 }, /* int AUX */
62aeeb85f2STakashi Iwai { }
63aeeb85f2STakashi Iwai }
64aeeb85f2STakashi Iwai },
65aeeb85f2STakashi Iwai [ALC262_FIXUP_LENOVO_3000] = {
66aeeb85f2STakashi Iwai .type = HDA_FIXUP_PINCTLS,
67aeeb85f2STakashi Iwai .v.pins = (const struct hda_pintbl[]) {
68aeeb85f2STakashi Iwai { 0x19, PIN_VREF50 },
69aeeb85f2STakashi Iwai {}
70aeeb85f2STakashi Iwai },
71aeeb85f2STakashi Iwai .chained = true,
72aeeb85f2STakashi Iwai .chain_id = ALC262_FIXUP_BENQ,
73aeeb85f2STakashi Iwai },
74aeeb85f2STakashi Iwai [ALC262_FIXUP_BENQ] = {
75aeeb85f2STakashi Iwai .type = HDA_FIXUP_VERBS,
76aeeb85f2STakashi Iwai .v.verbs = (const struct hda_verb[]) {
77aeeb85f2STakashi Iwai { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
78aeeb85f2STakashi Iwai { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
79aeeb85f2STakashi Iwai {}
80aeeb85f2STakashi Iwai }
81aeeb85f2STakashi Iwai },
82aeeb85f2STakashi Iwai [ALC262_FIXUP_BENQ_T31] = {
83aeeb85f2STakashi Iwai .type = HDA_FIXUP_VERBS,
84aeeb85f2STakashi Iwai .v.verbs = (const struct hda_verb[]) {
85aeeb85f2STakashi Iwai { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
86aeeb85f2STakashi Iwai { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
87aeeb85f2STakashi Iwai {}
88aeeb85f2STakashi Iwai }
89aeeb85f2STakashi Iwai },
90aeeb85f2STakashi Iwai [ALC262_FIXUP_INV_DMIC] = {
91aeeb85f2STakashi Iwai .type = HDA_FIXUP_FUNC,
92aeeb85f2STakashi Iwai .v.func = alc_fixup_inv_dmic,
93aeeb85f2STakashi Iwai },
94aeeb85f2STakashi Iwai [ALC262_FIXUP_INTEL_BAYLEYBAY] = {
95aeeb85f2STakashi Iwai .type = HDA_FIXUP_FUNC,
96aeeb85f2STakashi Iwai .v.func = alc_fixup_no_depop_delay,
97aeeb85f2STakashi Iwai },
98aeeb85f2STakashi Iwai };
99aeeb85f2STakashi Iwai
100aeeb85f2STakashi Iwai static const struct hda_quirk alc262_fixup_tbl[] = {
101aeeb85f2STakashi Iwai SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", ALC262_FIXUP_HP_Z200),
102aeeb85f2STakashi Iwai SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu Lifebook S7110", ALC262_FIXUP_FSC_S7110),
103aeeb85f2STakashi Iwai SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FIXUP_BENQ),
104aeeb85f2STakashi Iwai SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_FIXUP_TYAN),
105aeeb85f2STakashi Iwai SND_PCI_QUIRK(0x1734, 0x1141, "FSC ESPRIMO U9210", ALC262_FIXUP_FSC_H270),
106aeeb85f2STakashi Iwai SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", ALC262_FIXUP_FSC_H270),
107aeeb85f2STakashi Iwai SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000", ALC262_FIXUP_LENOVO_3000),
108aeeb85f2STakashi Iwai SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_FIXUP_BENQ),
109aeeb85f2STakashi Iwai SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_FIXUP_BENQ_T31),
110aeeb85f2STakashi Iwai SND_PCI_QUIRK(0x8086, 0x7270, "BayleyBay", ALC262_FIXUP_INTEL_BAYLEYBAY),
111aeeb85f2STakashi Iwai {}
112aeeb85f2STakashi Iwai };
113aeeb85f2STakashi Iwai
114aeeb85f2STakashi Iwai static const struct hda_model_fixup alc262_fixup_models[] = {
115aeeb85f2STakashi Iwai {.id = ALC262_FIXUP_INV_DMIC, .name = "inv-dmic"},
116aeeb85f2STakashi Iwai {.id = ALC262_FIXUP_FSC_H270, .name = "fsc-h270"},
117aeeb85f2STakashi Iwai {.id = ALC262_FIXUP_FSC_S7110, .name = "fsc-s7110"},
118aeeb85f2STakashi Iwai {.id = ALC262_FIXUP_HP_Z200, .name = "hp-z200"},
119aeeb85f2STakashi Iwai {.id = ALC262_FIXUP_TYAN, .name = "tyan"},
120aeeb85f2STakashi Iwai {.id = ALC262_FIXUP_LENOVO_3000, .name = "lenovo-3000"},
121aeeb85f2STakashi Iwai {.id = ALC262_FIXUP_BENQ, .name = "benq"},
122aeeb85f2STakashi Iwai {.id = ALC262_FIXUP_BENQ_T31, .name = "benq-t31"},
123aeeb85f2STakashi Iwai {.id = ALC262_FIXUP_INTEL_BAYLEYBAY, .name = "bayleybay"},
124aeeb85f2STakashi Iwai {}
125aeeb85f2STakashi Iwai };
126aeeb85f2STakashi Iwai
127aeeb85f2STakashi Iwai /*
128aeeb85f2STakashi Iwai */
alc262_probe(struct hda_codec * codec,const struct hda_device_id * id)129*e1d695b4STakashi Iwai static int alc262_probe(struct hda_codec *codec, const struct hda_device_id *id)
130aeeb85f2STakashi Iwai {
131aeeb85f2STakashi Iwai struct alc_spec *spec;
132aeeb85f2STakashi Iwai int err;
133aeeb85f2STakashi Iwai
134aeeb85f2STakashi Iwai err = alc_alloc_spec(codec, 0x0b);
135aeeb85f2STakashi Iwai if (err < 0)
136aeeb85f2STakashi Iwai return err;
137aeeb85f2STakashi Iwai
138aeeb85f2STakashi Iwai spec = codec->spec;
139aeeb85f2STakashi Iwai spec->gen.shared_mic_vref_pin = 0x18;
140aeeb85f2STakashi Iwai
141aeeb85f2STakashi Iwai spec->shutup = alc_eapd_shutup;
142aeeb85f2STakashi Iwai
143aeeb85f2STakashi Iwai #if 0
144aeeb85f2STakashi Iwai /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
145aeeb85f2STakashi Iwai * under-run
146aeeb85f2STakashi Iwai */
147aeeb85f2STakashi Iwai alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x80);
148aeeb85f2STakashi Iwai #endif
149aeeb85f2STakashi Iwai alc_fix_pll_init(codec, 0x20, 0x0a, 10);
150aeeb85f2STakashi Iwai
151aeeb85f2STakashi Iwai alc_pre_init(codec);
152aeeb85f2STakashi Iwai
153aeeb85f2STakashi Iwai snd_hda_pick_fixup(codec, alc262_fixup_models, alc262_fixup_tbl,
154aeeb85f2STakashi Iwai alc262_fixups);
155aeeb85f2STakashi Iwai snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
156aeeb85f2STakashi Iwai
157aeeb85f2STakashi Iwai alc_auto_parse_customize_define(codec);
158aeeb85f2STakashi Iwai
159aeeb85f2STakashi Iwai if (has_cdefine_beep(codec))
160aeeb85f2STakashi Iwai spec->gen.beep_nid = 0x01;
161aeeb85f2STakashi Iwai
162aeeb85f2STakashi Iwai /* automatic parse from the BIOS config */
163aeeb85f2STakashi Iwai err = alc262_parse_auto_config(codec);
164aeeb85f2STakashi Iwai if (err < 0)
165aeeb85f2STakashi Iwai goto error;
166aeeb85f2STakashi Iwai
167aeeb85f2STakashi Iwai if (!spec->gen.no_analog && spec->gen.beep_nid) {
168aeeb85f2STakashi Iwai err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
169aeeb85f2STakashi Iwai if (err < 0)
170aeeb85f2STakashi Iwai goto error;
171aeeb85f2STakashi Iwai }
172aeeb85f2STakashi Iwai
173aeeb85f2STakashi Iwai snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
174aeeb85f2STakashi Iwai
175aeeb85f2STakashi Iwai return 0;
176aeeb85f2STakashi Iwai
177aeeb85f2STakashi Iwai error:
178*e1d695b4STakashi Iwai snd_hda_gen_remove(codec);
179aeeb85f2STakashi Iwai return err;
180aeeb85f2STakashi Iwai }
181aeeb85f2STakashi Iwai
182*e1d695b4STakashi Iwai static const struct hda_codec_ops alc262_codec_ops = {
183*e1d695b4STakashi Iwai .probe = alc262_probe,
184*e1d695b4STakashi Iwai .remove = snd_hda_gen_remove,
185*e1d695b4STakashi Iwai .build_controls = alc_build_controls,
186*e1d695b4STakashi Iwai .build_pcms = snd_hda_gen_build_pcms,
187*e1d695b4STakashi Iwai .init = alc_init,
188*e1d695b4STakashi Iwai .unsol_event = snd_hda_jack_unsol_event,
189*e1d695b4STakashi Iwai .resume = alc_resume,
190*e1d695b4STakashi Iwai .suspend = alc_suspend,
191*e1d695b4STakashi Iwai .check_power_status = snd_hda_gen_check_power_status,
192*e1d695b4STakashi Iwai .stream_pm = snd_hda_gen_stream_pm,
193*e1d695b4STakashi Iwai };
194*e1d695b4STakashi Iwai
195aeeb85f2STakashi Iwai /*
196aeeb85f2STakashi Iwai * driver entries
197aeeb85f2STakashi Iwai */
198aeeb85f2STakashi Iwai static const struct hda_device_id snd_hda_id_alc262[] = {
199*e1d695b4STakashi Iwai HDA_CODEC_ID(0x10ec0262, "ALC262"),
200aeeb85f2STakashi Iwai {} /* terminator */
201aeeb85f2STakashi Iwai };
202aeeb85f2STakashi Iwai MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc262);
203aeeb85f2STakashi Iwai
204aeeb85f2STakashi Iwai MODULE_LICENSE("GPL");
205aeeb85f2STakashi Iwai MODULE_DESCRIPTION("Realtek ALC262 HD-audio codec");
206aeeb85f2STakashi Iwai MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
207aeeb85f2STakashi Iwai
208aeeb85f2STakashi Iwai static struct hda_codec_driver alc262_driver = {
209aeeb85f2STakashi Iwai .id = snd_hda_id_alc262,
210*e1d695b4STakashi Iwai .ops = &alc262_codec_ops,
211aeeb85f2STakashi Iwai };
212aeeb85f2STakashi Iwai
213aeeb85f2STakashi Iwai module_hda_codec_driver(alc262_driver);
214