1 // SPDX-License-Identifier: GPL-2.0-or-later
2 //
3 // Realtek ALC260 codec
4 //
5
6 #include <linux/init.h>
7 #include <linux/module.h>
8 #include "realtek.h"
9
alc260_parse_auto_config(struct hda_codec * codec)10 static int alc260_parse_auto_config(struct hda_codec *codec)
11 {
12 static const hda_nid_t alc260_ignore[] = { 0x17, 0 };
13 static const hda_nid_t alc260_ssids[] = { 0x10, 0x15, 0x0f, 0 };
14 return alc_parse_auto_config(codec, alc260_ignore, alc260_ssids);
15 }
16
17 /*
18 * Pin config fixes
19 */
20 enum {
21 ALC260_FIXUP_HP_DC5750,
22 ALC260_FIXUP_HP_PIN_0F,
23 ALC260_FIXUP_COEF,
24 ALC260_FIXUP_GPIO1,
25 ALC260_FIXUP_GPIO1_TOGGLE,
26 ALC260_FIXUP_REPLACER,
27 ALC260_FIXUP_HP_B1900,
28 ALC260_FIXUP_KN1,
29 ALC260_FIXUP_FSC_S7020,
30 ALC260_FIXUP_FSC_S7020_JWSE,
31 ALC260_FIXUP_VAIO_PINS,
32 };
33
alc260_gpio1_automute(struct hda_codec * codec)34 static void alc260_gpio1_automute(struct hda_codec *codec)
35 {
36 struct alc_spec *spec = codec->spec;
37
38 alc_update_gpio_data(codec, 0x01, spec->gen.hp_jack_present);
39 }
40
alc260_fixup_gpio1_toggle(struct hda_codec * codec,const struct hda_fixup * fix,int action)41 static void alc260_fixup_gpio1_toggle(struct hda_codec *codec,
42 const struct hda_fixup *fix, int action)
43 {
44 struct alc_spec *spec = codec->spec;
45 if (action == HDA_FIXUP_ACT_PROBE) {
46 /* although the machine has only one output pin, we need to
47 * toggle GPIO1 according to the jack state
48 */
49 spec->gen.automute_hook = alc260_gpio1_automute;
50 spec->gen.detect_hp = 1;
51 spec->gen.automute_speaker = 1;
52 spec->gen.autocfg.hp_pins[0] = 0x0f; /* copy it for automute */
53 snd_hda_jack_detect_enable_callback(codec, 0x0f,
54 snd_hda_gen_hp_automute);
55 alc_setup_gpio(codec, 0x01);
56 }
57 }
58
alc260_fixup_kn1(struct hda_codec * codec,const struct hda_fixup * fix,int action)59 static void alc260_fixup_kn1(struct hda_codec *codec,
60 const struct hda_fixup *fix, int action)
61 {
62 struct alc_spec *spec = codec->spec;
63 static const struct hda_pintbl pincfgs[] = {
64 { 0x0f, 0x02214000 }, /* HP/speaker */
65 { 0x12, 0x90a60160 }, /* int mic */
66 { 0x13, 0x02a19000 }, /* ext mic */
67 { 0x18, 0x01446000 }, /* SPDIF out */
68 /* disable bogus I/O pins */
69 { 0x10, 0x411111f0 },
70 { 0x11, 0x411111f0 },
71 { 0x14, 0x411111f0 },
72 { 0x15, 0x411111f0 },
73 { 0x16, 0x411111f0 },
74 { 0x17, 0x411111f0 },
75 { 0x19, 0x411111f0 },
76 { }
77 };
78
79 switch (action) {
80 case HDA_FIXUP_ACT_PRE_PROBE:
81 snd_hda_apply_pincfgs(codec, pincfgs);
82 spec->init_amp = ALC_INIT_NONE;
83 break;
84 }
85 }
86
alc260_fixup_fsc_s7020(struct hda_codec * codec,const struct hda_fixup * fix,int action)87 static void alc260_fixup_fsc_s7020(struct hda_codec *codec,
88 const struct hda_fixup *fix, int action)
89 {
90 struct alc_spec *spec = codec->spec;
91 if (action == HDA_FIXUP_ACT_PRE_PROBE)
92 spec->init_amp = ALC_INIT_NONE;
93 }
94
alc260_fixup_fsc_s7020_jwse(struct hda_codec * codec,const struct hda_fixup * fix,int action)95 static void alc260_fixup_fsc_s7020_jwse(struct hda_codec *codec,
96 const struct hda_fixup *fix, int action)
97 {
98 struct alc_spec *spec = codec->spec;
99 if (action == HDA_FIXUP_ACT_PRE_PROBE) {
100 spec->gen.add_jack_modes = 1;
101 spec->gen.hp_mic = 1;
102 }
103 }
104
105 static const struct hda_fixup alc260_fixups[] = {
106 [ALC260_FIXUP_HP_DC5750] = {
107 .type = HDA_FIXUP_PINS,
108 .v.pins = (const struct hda_pintbl[]) {
109 { 0x11, 0x90130110 }, /* speaker */
110 { }
111 }
112 },
113 [ALC260_FIXUP_HP_PIN_0F] = {
114 .type = HDA_FIXUP_PINS,
115 .v.pins = (const struct hda_pintbl[]) {
116 { 0x0f, 0x01214000 }, /* HP */
117 { }
118 }
119 },
120 [ALC260_FIXUP_COEF] = {
121 .type = HDA_FIXUP_VERBS,
122 .v.verbs = (const struct hda_verb[]) {
123 { 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 },
124 { 0x1a, AC_VERB_SET_PROC_COEF, 0x3040 },
125 { }
126 },
127 },
128 [ALC260_FIXUP_GPIO1] = {
129 .type = HDA_FIXUP_FUNC,
130 .v.func = alc_fixup_gpio1,
131 },
132 [ALC260_FIXUP_GPIO1_TOGGLE] = {
133 .type = HDA_FIXUP_FUNC,
134 .v.func = alc260_fixup_gpio1_toggle,
135 .chained = true,
136 .chain_id = ALC260_FIXUP_HP_PIN_0F,
137 },
138 [ALC260_FIXUP_REPLACER] = {
139 .type = HDA_FIXUP_VERBS,
140 .v.verbs = (const struct hda_verb[]) {
141 { 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 },
142 { 0x1a, AC_VERB_SET_PROC_COEF, 0x3050 },
143 { }
144 },
145 .chained = true,
146 .chain_id = ALC260_FIXUP_GPIO1_TOGGLE,
147 },
148 [ALC260_FIXUP_HP_B1900] = {
149 .type = HDA_FIXUP_FUNC,
150 .v.func = alc260_fixup_gpio1_toggle,
151 .chained = true,
152 .chain_id = ALC260_FIXUP_COEF,
153 },
154 [ALC260_FIXUP_KN1] = {
155 .type = HDA_FIXUP_FUNC,
156 .v.func = alc260_fixup_kn1,
157 },
158 [ALC260_FIXUP_FSC_S7020] = {
159 .type = HDA_FIXUP_FUNC,
160 .v.func = alc260_fixup_fsc_s7020,
161 },
162 [ALC260_FIXUP_FSC_S7020_JWSE] = {
163 .type = HDA_FIXUP_FUNC,
164 .v.func = alc260_fixup_fsc_s7020_jwse,
165 .chained = true,
166 .chain_id = ALC260_FIXUP_FSC_S7020,
167 },
168 [ALC260_FIXUP_VAIO_PINS] = {
169 .type = HDA_FIXUP_PINS,
170 .v.pins = (const struct hda_pintbl[]) {
171 /* Pin configs are missing completely on some VAIOs */
172 { 0x0f, 0x01211020 },
173 { 0x10, 0x0001003f },
174 { 0x11, 0x411111f0 },
175 { 0x12, 0x01a15930 },
176 { 0x13, 0x411111f0 },
177 { 0x14, 0x411111f0 },
178 { 0x15, 0x411111f0 },
179 { 0x16, 0x411111f0 },
180 { 0x17, 0x411111f0 },
181 { 0x18, 0x411111f0 },
182 { 0x19, 0x411111f0 },
183 { }
184 }
185 },
186 };
187
188 static const struct hda_quirk alc260_fixup_tbl[] = {
189 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_FIXUP_GPIO1),
190 SND_PCI_QUIRK(0x1025, 0x007f, "Acer Aspire 9500", ALC260_FIXUP_COEF),
191 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_FIXUP_GPIO1),
192 SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", ALC260_FIXUP_HP_DC5750),
193 SND_PCI_QUIRK(0x103c, 0x30ba, "HP Presario B1900", ALC260_FIXUP_HP_B1900),
194 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_FIXUP_VAIO_PINS),
195 SND_PCI_QUIRK(0x104d, 0x81e2, "Sony VAIO TX", ALC260_FIXUP_HP_PIN_0F),
196 SND_PCI_QUIRK(0x10cf, 0x1326, "FSC LifeBook S7020", ALC260_FIXUP_FSC_S7020),
197 SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FIXUP_GPIO1),
198 SND_PCI_QUIRK(0x152d, 0x0729, "Quanta KN1", ALC260_FIXUP_KN1),
199 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_FIXUP_REPLACER),
200 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_FIXUP_COEF),
201 {}
202 };
203
204 static const struct hda_model_fixup alc260_fixup_models[] = {
205 {.id = ALC260_FIXUP_GPIO1, .name = "gpio1"},
206 {.id = ALC260_FIXUP_COEF, .name = "coef"},
207 {.id = ALC260_FIXUP_FSC_S7020, .name = "fujitsu"},
208 {.id = ALC260_FIXUP_FSC_S7020_JWSE, .name = "fujitsu-jwse"},
209 {}
210 };
211
212 /*
213 */
alc260_probe(struct hda_codec * codec,const struct hda_device_id * id)214 static int alc260_probe(struct hda_codec *codec, const struct hda_device_id *id)
215 {
216 struct alc_spec *spec;
217 int err;
218
219 err = alc_alloc_spec(codec, 0x07);
220 if (err < 0)
221 return err;
222
223 spec = codec->spec;
224 /* as quite a few machines require HP amp for speaker outputs,
225 * it's easier to enable it unconditionally; even if it's unneeded,
226 * it's almost harmless.
227 */
228 spec->gen.prefer_hp_amp = 1;
229 spec->gen.beep_nid = 0x01;
230
231 spec->shutup = alc_eapd_shutup;
232
233 alc_pre_init(codec);
234
235 snd_hda_pick_fixup(codec, alc260_fixup_models, alc260_fixup_tbl,
236 alc260_fixups);
237 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
238
239 /* automatic parse from the BIOS config */
240 err = alc260_parse_auto_config(codec);
241 if (err < 0)
242 goto error;
243
244 if (!spec->gen.no_analog) {
245 err = set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
246 if (err < 0)
247 goto error;
248 }
249
250 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
251
252 return 0;
253
254 error:
255 snd_hda_gen_remove(codec);
256 return err;
257 }
258
259 static const struct hda_codec_ops alc260_codec_ops = {
260 .probe = alc260_probe,
261 .remove = snd_hda_gen_remove,
262 .build_controls = alc_build_controls,
263 .build_pcms = snd_hda_gen_build_pcms,
264 .init = alc_init,
265 .unsol_event = snd_hda_jack_unsol_event,
266 .resume = alc_resume,
267 .suspend = alc_suspend,
268 .check_power_status = snd_hda_gen_check_power_status,
269 .stream_pm = snd_hda_gen_stream_pm,
270 };
271
272 /*
273 * driver entries
274 */
275 static const struct hda_device_id snd_hda_id_alc260[] = {
276 HDA_CODEC_ID(0x10ec0260, "ALC260"),
277 {} /* terminator */
278 };
279 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc260);
280
281 MODULE_LICENSE("GPL");
282 MODULE_DESCRIPTION("Realtek ALC260 HD-audio codec");
283 MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
284
285 static struct hda_codec_driver alc260_driver = {
286 .id = snd_hda_id_alc260,
287 .ops = &alc260_codec_ops,
288 };
289
290 module_hda_codec_driver(alc260_driver);
291