xref: /linux/sound/hda/codecs/realtek/alc260.c (revision 177bf8620cf4ed290ee170a6c5966adc0924b336)
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