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