1 // SPDX-License-Identifier: GPL-2.0-or-later
2 //
3 // Realtek ALC880 codec
4 //
5
6 #include <linux/init.h>
7 #include <linux/module.h>
8 #include "realtek.h"
9
alc880_unsol_event(struct hda_codec * codec,unsigned int res)10 static void alc880_unsol_event(struct hda_codec *codec, unsigned int res)
11 {
12 /* For some reason, the res given from ALC880 is broken.
13 Here we adjust it properly. */
14 snd_hda_jack_unsol_event(codec, res >> 2);
15 }
16
alc880_parse_auto_config(struct hda_codec * codec)17 static int alc880_parse_auto_config(struct hda_codec *codec)
18 {
19 static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
20 static const hda_nid_t alc880_ssids[] = { 0x15, 0x1b, 0x14, 0 };
21 return alc_parse_auto_config(codec, alc880_ignore, alc880_ssids);
22 }
23
24 /*
25 * ALC880 fix-ups
26 */
27 enum {
28 ALC880_FIXUP_GPIO1,
29 ALC880_FIXUP_GPIO2,
30 ALC880_FIXUP_MEDION_RIM,
31 ALC880_FIXUP_LG,
32 ALC880_FIXUP_LG_LW25,
33 ALC880_FIXUP_W810,
34 ALC880_FIXUP_EAPD_COEF,
35 ALC880_FIXUP_TCL_S700,
36 ALC880_FIXUP_VOL_KNOB,
37 ALC880_FIXUP_FUJITSU,
38 ALC880_FIXUP_F1734,
39 ALC880_FIXUP_UNIWILL,
40 ALC880_FIXUP_UNIWILL_DIG,
41 ALC880_FIXUP_Z71V,
42 ALC880_FIXUP_ASUS_W5A,
43 ALC880_FIXUP_3ST_BASE,
44 ALC880_FIXUP_3ST,
45 ALC880_FIXUP_3ST_DIG,
46 ALC880_FIXUP_5ST_BASE,
47 ALC880_FIXUP_5ST,
48 ALC880_FIXUP_5ST_DIG,
49 ALC880_FIXUP_6ST_BASE,
50 ALC880_FIXUP_6ST,
51 ALC880_FIXUP_6ST_DIG,
52 ALC880_FIXUP_6ST_AUTOMUTE,
53 };
54
55 /* enable the volume-knob widget support on NID 0x21 */
alc880_fixup_vol_knob(struct hda_codec * codec,const struct hda_fixup * fix,int action)56 static void alc880_fixup_vol_knob(struct hda_codec *codec,
57 const struct hda_fixup *fix, int action)
58 {
59 if (action == HDA_FIXUP_ACT_PROBE)
60 snd_hda_jack_detect_enable_callback(codec, 0x21,
61 alc_update_knob_master);
62 }
63
64 static const struct hda_fixup alc880_fixups[] = {
65 [ALC880_FIXUP_GPIO1] = {
66 .type = HDA_FIXUP_FUNC,
67 .v.func = alc_fixup_gpio1,
68 },
69 [ALC880_FIXUP_GPIO2] = {
70 .type = HDA_FIXUP_FUNC,
71 .v.func = alc_fixup_gpio2,
72 },
73 [ALC880_FIXUP_MEDION_RIM] = {
74 .type = HDA_FIXUP_VERBS,
75 .v.verbs = (const struct hda_verb[]) {
76 { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
77 { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 },
78 { }
79 },
80 .chained = true,
81 .chain_id = ALC880_FIXUP_GPIO2,
82 },
83 [ALC880_FIXUP_LG] = {
84 .type = HDA_FIXUP_PINS,
85 .v.pins = (const struct hda_pintbl[]) {
86 /* disable bogus unused pins */
87 { 0x16, 0x411111f0 },
88 { 0x18, 0x411111f0 },
89 { 0x1a, 0x411111f0 },
90 { }
91 }
92 },
93 [ALC880_FIXUP_LG_LW25] = {
94 .type = HDA_FIXUP_PINS,
95 .v.pins = (const struct hda_pintbl[]) {
96 { 0x1a, 0x0181344f }, /* line-in */
97 { 0x1b, 0x0321403f }, /* headphone */
98 { }
99 }
100 },
101 [ALC880_FIXUP_W810] = {
102 .type = HDA_FIXUP_PINS,
103 .v.pins = (const struct hda_pintbl[]) {
104 /* disable bogus unused pins */
105 { 0x17, 0x411111f0 },
106 { }
107 },
108 .chained = true,
109 .chain_id = ALC880_FIXUP_GPIO2,
110 },
111 [ALC880_FIXUP_EAPD_COEF] = {
112 .type = HDA_FIXUP_VERBS,
113 .v.verbs = (const struct hda_verb[]) {
114 /* change to EAPD mode */
115 { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
116 { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 },
117 {}
118 },
119 },
120 [ALC880_FIXUP_TCL_S700] = {
121 .type = HDA_FIXUP_VERBS,
122 .v.verbs = (const struct hda_verb[]) {
123 /* change to EAPD mode */
124 { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
125 { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
126 {}
127 },
128 .chained = true,
129 .chain_id = ALC880_FIXUP_GPIO2,
130 },
131 [ALC880_FIXUP_VOL_KNOB] = {
132 .type = HDA_FIXUP_FUNC,
133 .v.func = alc880_fixup_vol_knob,
134 },
135 [ALC880_FIXUP_FUJITSU] = {
136 /* override all pins as BIOS on old Amilo is broken */
137 .type = HDA_FIXUP_PINS,
138 .v.pins = (const struct hda_pintbl[]) {
139 { 0x14, 0x0121401f }, /* HP */
140 { 0x15, 0x99030120 }, /* speaker */
141 { 0x16, 0x99030130 }, /* bass speaker */
142 { 0x17, 0x411111f0 }, /* N/A */
143 { 0x18, 0x411111f0 }, /* N/A */
144 { 0x19, 0x01a19950 }, /* mic-in */
145 { 0x1a, 0x411111f0 }, /* N/A */
146 { 0x1b, 0x411111f0 }, /* N/A */
147 { 0x1c, 0x411111f0 }, /* N/A */
148 { 0x1d, 0x411111f0 }, /* N/A */
149 { 0x1e, 0x01454140 }, /* SPDIF out */
150 { }
151 },
152 .chained = true,
153 .chain_id = ALC880_FIXUP_VOL_KNOB,
154 },
155 [ALC880_FIXUP_F1734] = {
156 /* almost compatible with FUJITSU, but no bass and SPDIF */
157 .type = HDA_FIXUP_PINS,
158 .v.pins = (const struct hda_pintbl[]) {
159 { 0x14, 0x0121401f }, /* HP */
160 { 0x15, 0x99030120 }, /* speaker */
161 { 0x16, 0x411111f0 }, /* N/A */
162 { 0x17, 0x411111f0 }, /* N/A */
163 { 0x18, 0x411111f0 }, /* N/A */
164 { 0x19, 0x01a19950 }, /* mic-in */
165 { 0x1a, 0x411111f0 }, /* N/A */
166 { 0x1b, 0x411111f0 }, /* N/A */
167 { 0x1c, 0x411111f0 }, /* N/A */
168 { 0x1d, 0x411111f0 }, /* N/A */
169 { 0x1e, 0x411111f0 }, /* N/A */
170 { }
171 },
172 .chained = true,
173 .chain_id = ALC880_FIXUP_VOL_KNOB,
174 },
175 [ALC880_FIXUP_UNIWILL] = {
176 /* need to fix HP and speaker pins to be parsed correctly */
177 .type = HDA_FIXUP_PINS,
178 .v.pins = (const struct hda_pintbl[]) {
179 { 0x14, 0x0121411f }, /* HP */
180 { 0x15, 0x99030120 }, /* speaker */
181 { 0x16, 0x99030130 }, /* bass speaker */
182 { }
183 },
184 },
185 [ALC880_FIXUP_UNIWILL_DIG] = {
186 .type = HDA_FIXUP_PINS,
187 .v.pins = (const struct hda_pintbl[]) {
188 /* disable bogus unused pins */
189 { 0x17, 0x411111f0 },
190 { 0x19, 0x411111f0 },
191 { 0x1b, 0x411111f0 },
192 { 0x1f, 0x411111f0 },
193 { }
194 }
195 },
196 [ALC880_FIXUP_Z71V] = {
197 .type = HDA_FIXUP_PINS,
198 .v.pins = (const struct hda_pintbl[]) {
199 /* set up the whole pins as BIOS is utterly broken */
200 { 0x14, 0x99030120 }, /* speaker */
201 { 0x15, 0x0121411f }, /* HP */
202 { 0x16, 0x411111f0 }, /* N/A */
203 { 0x17, 0x411111f0 }, /* N/A */
204 { 0x18, 0x01a19950 }, /* mic-in */
205 { 0x19, 0x411111f0 }, /* N/A */
206 { 0x1a, 0x01813031 }, /* line-in */
207 { 0x1b, 0x411111f0 }, /* N/A */
208 { 0x1c, 0x411111f0 }, /* N/A */
209 { 0x1d, 0x411111f0 }, /* N/A */
210 { 0x1e, 0x0144111e }, /* SPDIF */
211 { }
212 }
213 },
214 [ALC880_FIXUP_ASUS_W5A] = {
215 .type = HDA_FIXUP_PINS,
216 .v.pins = (const struct hda_pintbl[]) {
217 /* set up the whole pins as BIOS is utterly broken */
218 { 0x14, 0x0121411f }, /* HP */
219 { 0x15, 0x411111f0 }, /* N/A */
220 { 0x16, 0x411111f0 }, /* N/A */
221 { 0x17, 0x411111f0 }, /* N/A */
222 { 0x18, 0x90a60160 }, /* mic */
223 { 0x19, 0x411111f0 }, /* N/A */
224 { 0x1a, 0x411111f0 }, /* N/A */
225 { 0x1b, 0x411111f0 }, /* N/A */
226 { 0x1c, 0x411111f0 }, /* N/A */
227 { 0x1d, 0x411111f0 }, /* N/A */
228 { 0x1e, 0xb743111e }, /* SPDIF out */
229 { }
230 },
231 .chained = true,
232 .chain_id = ALC880_FIXUP_GPIO1,
233 },
234 [ALC880_FIXUP_3ST_BASE] = {
235 .type = HDA_FIXUP_PINS,
236 .v.pins = (const struct hda_pintbl[]) {
237 { 0x14, 0x01014010 }, /* line-out */
238 { 0x15, 0x411111f0 }, /* N/A */
239 { 0x16, 0x411111f0 }, /* N/A */
240 { 0x17, 0x411111f0 }, /* N/A */
241 { 0x18, 0x01a19c30 }, /* mic-in */
242 { 0x19, 0x0121411f }, /* HP */
243 { 0x1a, 0x01813031 }, /* line-in */
244 { 0x1b, 0x02a19c40 }, /* front-mic */
245 { 0x1c, 0x411111f0 }, /* N/A */
246 { 0x1d, 0x411111f0 }, /* N/A */
247 /* 0x1e is filled in below */
248 { 0x1f, 0x411111f0 }, /* N/A */
249 { }
250 }
251 },
252 [ALC880_FIXUP_3ST] = {
253 .type = HDA_FIXUP_PINS,
254 .v.pins = (const struct hda_pintbl[]) {
255 { 0x1e, 0x411111f0 }, /* N/A */
256 { }
257 },
258 .chained = true,
259 .chain_id = ALC880_FIXUP_3ST_BASE,
260 },
261 [ALC880_FIXUP_3ST_DIG] = {
262 .type = HDA_FIXUP_PINS,
263 .v.pins = (const struct hda_pintbl[]) {
264 { 0x1e, 0x0144111e }, /* SPDIF */
265 { }
266 },
267 .chained = true,
268 .chain_id = ALC880_FIXUP_3ST_BASE,
269 },
270 [ALC880_FIXUP_5ST_BASE] = {
271 .type = HDA_FIXUP_PINS,
272 .v.pins = (const struct hda_pintbl[]) {
273 { 0x14, 0x01014010 }, /* front */
274 { 0x15, 0x411111f0 }, /* N/A */
275 { 0x16, 0x01011411 }, /* CLFE */
276 { 0x17, 0x01016412 }, /* surr */
277 { 0x18, 0x01a19c30 }, /* mic-in */
278 { 0x19, 0x0121411f }, /* HP */
279 { 0x1a, 0x01813031 }, /* line-in */
280 { 0x1b, 0x02a19c40 }, /* front-mic */
281 { 0x1c, 0x411111f0 }, /* N/A */
282 { 0x1d, 0x411111f0 }, /* N/A */
283 /* 0x1e is filled in below */
284 { 0x1f, 0x411111f0 }, /* N/A */
285 { }
286 }
287 },
288 [ALC880_FIXUP_5ST] = {
289 .type = HDA_FIXUP_PINS,
290 .v.pins = (const struct hda_pintbl[]) {
291 { 0x1e, 0x411111f0 }, /* N/A */
292 { }
293 },
294 .chained = true,
295 .chain_id = ALC880_FIXUP_5ST_BASE,
296 },
297 [ALC880_FIXUP_5ST_DIG] = {
298 .type = HDA_FIXUP_PINS,
299 .v.pins = (const struct hda_pintbl[]) {
300 { 0x1e, 0x0144111e }, /* SPDIF */
301 { }
302 },
303 .chained = true,
304 .chain_id = ALC880_FIXUP_5ST_BASE,
305 },
306 [ALC880_FIXUP_6ST_BASE] = {
307 .type = HDA_FIXUP_PINS,
308 .v.pins = (const struct hda_pintbl[]) {
309 { 0x14, 0x01014010 }, /* front */
310 { 0x15, 0x01016412 }, /* surr */
311 { 0x16, 0x01011411 }, /* CLFE */
312 { 0x17, 0x01012414 }, /* side */
313 { 0x18, 0x01a19c30 }, /* mic-in */
314 { 0x19, 0x02a19c40 }, /* front-mic */
315 { 0x1a, 0x01813031 }, /* line-in */
316 { 0x1b, 0x0121411f }, /* HP */
317 { 0x1c, 0x411111f0 }, /* N/A */
318 { 0x1d, 0x411111f0 }, /* N/A */
319 /* 0x1e is filled in below */
320 { 0x1f, 0x411111f0 }, /* N/A */
321 { }
322 }
323 },
324 [ALC880_FIXUP_6ST] = {
325 .type = HDA_FIXUP_PINS,
326 .v.pins = (const struct hda_pintbl[]) {
327 { 0x1e, 0x411111f0 }, /* N/A */
328 { }
329 },
330 .chained = true,
331 .chain_id = ALC880_FIXUP_6ST_BASE,
332 },
333 [ALC880_FIXUP_6ST_DIG] = {
334 .type = HDA_FIXUP_PINS,
335 .v.pins = (const struct hda_pintbl[]) {
336 { 0x1e, 0x0144111e }, /* SPDIF */
337 { }
338 },
339 .chained = true,
340 .chain_id = ALC880_FIXUP_6ST_BASE,
341 },
342 [ALC880_FIXUP_6ST_AUTOMUTE] = {
343 .type = HDA_FIXUP_PINS,
344 .v.pins = (const struct hda_pintbl[]) {
345 { 0x1b, 0x0121401f }, /* HP with jack detect */
346 { }
347 },
348 .chained_before = true,
349 .chain_id = ALC880_FIXUP_6ST_BASE,
350 },
351 };
352
353 static const struct hda_quirk alc880_fixup_tbl[] = {
354 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_FIXUP_W810),
355 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS W5A", ALC880_FIXUP_ASUS_W5A),
356 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_FIXUP_Z71V),
357 SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_FIXUP_GPIO1),
358 SND_PCI_QUIRK(0x147b, 0x1045, "ABit AA8XE", ALC880_FIXUP_6ST_AUTOMUTE),
359 SND_PCI_QUIRK(0x1558, 0x5401, "Clevo GPIO2", ALC880_FIXUP_GPIO2),
360 SND_PCI_QUIRK_VENDOR(0x1558, "Clevo", ALC880_FIXUP_EAPD_COEF),
361 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_FIXUP_UNIWILL_DIG),
362 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_FIXUP_F1734),
363 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_FIXUP_UNIWILL),
364 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_FIXUP_VOL_KNOB),
365 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_FIXUP_W810),
366 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM),
367 SND_PCI_QUIRK(0x1631, 0xe011, "PB 13201056", ALC880_FIXUP_6ST_AUTOMUTE),
368 SND_PCI_QUIRK(0x1734, 0x107c, "FSC Amilo M1437", ALC880_FIXUP_FUJITSU),
369 SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FIXUP_FUJITSU),
370 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_FIXUP_F1734),
371 SND_PCI_QUIRK(0x1734, 0x10b0, "FSC Amilo Pi1556", ALC880_FIXUP_FUJITSU),
372 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_FIXUP_LG),
373 SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_FIXUP_LG),
374 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_FIXUP_LG),
375 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_FIXUP_LG_LW25),
376 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_FIXUP_TCL_S700),
377
378 /* Below is the copied entries from alc880_quirks.c.
379 * It's not quite sure whether BIOS sets the correct pin-config table
380 * on these machines, thus they are kept to be compatible with
381 * the old static quirks. Once when it's confirmed to work without
382 * these overrides, it'd be better to remove.
383 */
384 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_FIXUP_5ST_DIG),
385 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_FIXUP_6ST),
386 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_FIXUP_3ST_DIG),
387 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_FIXUP_6ST_DIG),
388 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_FIXUP_6ST_DIG),
389 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_FIXUP_6ST_DIG),
390 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_FIXUP_3ST_DIG),
391 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_FIXUP_3ST),
392 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_FIXUP_6ST_DIG),
393 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_FIXUP_3ST),
394 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_FIXUP_3ST),
395 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_FIXUP_5ST),
396 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_FIXUP_5ST),
397 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_FIXUP_5ST),
398 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_FIXUP_6ST_DIG),
399 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_FIXUP_6ST_DIG),
400 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_FIXUP_6ST_DIG),
401 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_FIXUP_6ST_DIG),
402 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_FIXUP_5ST_DIG),
403 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_FIXUP_5ST_DIG),
404 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_FIXUP_5ST_DIG),
405 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_FIXUP_6ST_DIG), /* broken BIOS */
406 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_FIXUP_6ST_DIG),
407 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_FIXUP_5ST_DIG),
408 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_FIXUP_5ST_DIG),
409 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_FIXUP_5ST_DIG),
410 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_FIXUP_3ST_DIG),
411 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_FIXUP_5ST_DIG),
412 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_FIXUP_3ST_DIG),
413 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_FIXUP_3ST_DIG),
414 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_FIXUP_5ST_DIG),
415 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_FIXUP_5ST_DIG),
416 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_FIXUP_5ST_DIG),
417 /* default Intel */
418 SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_FIXUP_3ST),
419 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_FIXUP_5ST_DIG),
420 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_FIXUP_6ST_DIG),
421 {}
422 };
423
424 static const struct hda_model_fixup alc880_fixup_models[] = {
425 {.id = ALC880_FIXUP_3ST, .name = "3stack"},
426 {.id = ALC880_FIXUP_3ST_DIG, .name = "3stack-digout"},
427 {.id = ALC880_FIXUP_5ST, .name = "5stack"},
428 {.id = ALC880_FIXUP_5ST_DIG, .name = "5stack-digout"},
429 {.id = ALC880_FIXUP_6ST, .name = "6stack"},
430 {.id = ALC880_FIXUP_6ST_DIG, .name = "6stack-digout"},
431 {.id = ALC880_FIXUP_6ST_AUTOMUTE, .name = "6stack-automute"},
432 {}
433 };
434
435
436 /*
437 * OK, here we have finally the probe for ALC880
438 */
alc880_probe(struct hda_codec * codec,const struct hda_device_id * id)439 static int alc880_probe(struct hda_codec *codec, const struct hda_device_id *id)
440 {
441 struct alc_spec *spec;
442 int err;
443
444 err = alc_alloc_spec(codec, 0x0b);
445 if (err < 0)
446 return err;
447
448 spec = codec->spec;
449 spec->gen.need_dac_fix = 1;
450 spec->gen.beep_nid = 0x01;
451
452 alc_pre_init(codec);
453
454 snd_hda_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl,
455 alc880_fixups);
456 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
457
458 /* automatic parse from the BIOS config */
459 err = alc880_parse_auto_config(codec);
460 if (err < 0)
461 goto error;
462
463 if (!spec->gen.no_analog) {
464 err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
465 if (err < 0)
466 goto error;
467 }
468
469 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
470
471 return 0;
472
473 error:
474 snd_hda_gen_remove(codec);
475 return err;
476 }
477
478 static const struct hda_codec_ops alc880_codec_ops = {
479 .probe = alc880_probe,
480 .remove = snd_hda_gen_remove,
481 .build_controls = alc_build_controls,
482 .build_pcms = snd_hda_gen_build_pcms,
483 .init = alc_init,
484 .unsol_event = alc880_unsol_event,
485 .resume = alc_resume,
486 .suspend = alc_suspend,
487 .check_power_status = snd_hda_gen_check_power_status,
488 .stream_pm = snd_hda_gen_stream_pm,
489 };
490
491 /*
492 * driver entries
493 */
494 static const struct hda_device_id snd_hda_id_alc880[] = {
495 HDA_CODEC_ID(0x10ec0880, "ALC880"),
496 {} /* terminator */
497 };
498 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc880);
499
500 MODULE_LICENSE("GPL");
501 MODULE_DESCRIPTION("Realtek ALC880 HD-audio codec");
502 MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
503
504 static struct hda_codec_driver alc880_driver = {
505 .id = snd_hda_id_alc880,
506 .ops = &alc880_codec_ops,
507 };
508
509 module_hda_codec_driver(alc880_driver);
510