diff options
author | Takashi Iwai <tiwai@suse.de> | 2013-07-05 08:14:14 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2013-07-05 08:14:14 -0400 |
commit | 632408adfe70be6706cb89522b0d5b3dce188d84 (patch) | |
tree | a5f7f53186d212806a228871f44b124bd1a0c0c9 | |
parent | 0f7dbda0ec3bc4d778d7acf741b220fbf4318a20 (diff) |
ALSA: hda - Remove static quirks for AD1986A codec
Finally all the static quirks in patch_analog.c are reduced by this
patch. As machines with AD1986A codec are all old and often their
BIOS are buggy, we need to keep at least a few static pin conifgs.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | sound/pci/hda/patch_analog.c | 1069 |
1 files changed, 57 insertions, 1012 deletions
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 3b23280ff3a6..0cbdd87dde6d 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -32,7 +32,6 @@ | |||
32 | #include "hda_jack.h" | 32 | #include "hda_jack.h" |
33 | #include "hda_generic.h" | 33 | #include "hda_generic.h" |
34 | 34 | ||
35 | #define ENABLE_AD_STATIC_QUIRKS | ||
36 | 35 | ||
37 | struct ad198x_spec { | 36 | struct ad198x_spec { |
38 | struct hda_gen_spec gen; | 37 | struct hda_gen_spec gen; |
@@ -43,114 +42,8 @@ struct ad198x_spec { | |||
43 | hda_nid_t eapd_nid; | 42 | hda_nid_t eapd_nid; |
44 | 43 | ||
45 | unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */ | 44 | unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */ |
46 | |||
47 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
48 | const struct snd_kcontrol_new *mixers[6]; | ||
49 | int num_mixers; | ||
50 | const struct hda_verb *init_verbs[6]; /* initialization verbs | ||
51 | * don't forget NULL termination! | ||
52 | */ | ||
53 | unsigned int num_init_verbs; | ||
54 | |||
55 | /* playback */ | ||
56 | struct hda_multi_out multiout; /* playback set-up | ||
57 | * max_channels, dacs must be set | ||
58 | * dig_out_nid and hp_nid are optional | ||
59 | */ | ||
60 | unsigned int cur_eapd; | ||
61 | unsigned int need_dac_fix; | ||
62 | |||
63 | /* capture */ | ||
64 | unsigned int num_adc_nids; | ||
65 | const hda_nid_t *adc_nids; | ||
66 | hda_nid_t dig_in_nid; /* digital-in NID; optional */ | ||
67 | |||
68 | /* capture source */ | ||
69 | const struct hda_input_mux *input_mux; | ||
70 | const hda_nid_t *capsrc_nids; | ||
71 | unsigned int cur_mux[3]; | ||
72 | |||
73 | /* channel model */ | ||
74 | const struct hda_channel_mode *channel_mode; | ||
75 | int num_channel_mode; | ||
76 | |||
77 | /* PCM information */ | ||
78 | struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */ | ||
79 | |||
80 | unsigned int spdif_route; | ||
81 | |||
82 | unsigned int jack_present: 1; | ||
83 | unsigned int inv_jack_detect: 1;/* inverted jack-detection */ | ||
84 | unsigned int analog_beep: 1; /* analog beep input present */ | ||
85 | unsigned int avoid_init_slave_vol:1; | ||
86 | |||
87 | #ifdef CONFIG_PM | ||
88 | struct hda_loopback_check loopback; | ||
89 | #endif | ||
90 | /* for virtual master */ | ||
91 | hda_nid_t vmaster_nid; | ||
92 | const char * const *slave_vols; | ||
93 | const char * const *slave_sws; | ||
94 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
95 | }; | 45 | }; |
96 | 46 | ||
97 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
98 | /* | ||
99 | * input MUX handling (common part) | ||
100 | */ | ||
101 | static int ad198x_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | ||
102 | { | ||
103 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
104 | struct ad198x_spec *spec = codec->spec; | ||
105 | |||
106 | return snd_hda_input_mux_info(spec->input_mux, uinfo); | ||
107 | } | ||
108 | |||
109 | static int ad198x_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
110 | { | ||
111 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
112 | struct ad198x_spec *spec = codec->spec; | ||
113 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
114 | |||
115 | ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static int ad198x_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
120 | { | ||
121 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
122 | struct ad198x_spec *spec = codec->spec; | ||
123 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
124 | |||
125 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, | ||
126 | spec->capsrc_nids[adc_idx], | ||
127 | &spec->cur_mux[adc_idx]); | ||
128 | } | ||
129 | |||
130 | /* | ||
131 | * initialization (common callbacks) | ||
132 | */ | ||
133 | static int ad198x_init(struct hda_codec *codec) | ||
134 | { | ||
135 | struct ad198x_spec *spec = codec->spec; | ||
136 | int i; | ||
137 | |||
138 | for (i = 0; i < spec->num_init_verbs; i++) | ||
139 | snd_hda_sequence_write(codec, spec->init_verbs[i]); | ||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static const char * const ad_slave_pfxs[] = { | ||
144 | "Front", "Surround", "Center", "LFE", "Side", | ||
145 | "Headphone", "Mono", "Speaker", "IEC958", | ||
146 | NULL | ||
147 | }; | ||
148 | |||
149 | static const char * const ad1988_6stack_fp_slave_pfxs[] = { | ||
150 | "Front", "Surround", "Center", "LFE", "Side", "IEC958", | ||
151 | NULL | ||
152 | }; | ||
153 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
154 | 47 | ||
155 | #ifdef CONFIG_SND_HDA_INPUT_BEEP | 48 | #ifdef CONFIG_SND_HDA_INPUT_BEEP |
156 | /* additional beep mixers; the actual parameters are overwritten at build */ | 49 | /* additional beep mixers; the actual parameters are overwritten at build */ |
@@ -160,12 +53,6 @@ static const struct snd_kcontrol_new ad_beep_mixer[] = { | |||
160 | { } /* end */ | 53 | { } /* end */ |
161 | }; | 54 | }; |
162 | 55 | ||
163 | static const struct snd_kcontrol_new ad_beep2_mixer[] = { | ||
164 | HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0, 0, HDA_OUTPUT), | ||
165 | HDA_CODEC_MUTE_BEEP("Digital Beep Playback Switch", 0, 0, HDA_OUTPUT), | ||
166 | { } /* end */ | ||
167 | }; | ||
168 | |||
169 | #define set_beep_amp(spec, nid, idx, dir) \ | 56 | #define set_beep_amp(spec, nid, idx, dir) \ |
170 | ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */ | 57 | ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */ |
171 | #else | 58 | #else |
@@ -181,8 +68,7 @@ static int create_beep_ctls(struct hda_codec *codec) | |||
181 | if (!spec->beep_amp) | 68 | if (!spec->beep_amp) |
182 | return 0; | 69 | return 0; |
183 | 70 | ||
184 | knew = spec->analog_beep ? ad_beep2_mixer : ad_beep_mixer; | 71 | for (knew = ad_beep_mixer ; knew->name; knew++) { |
185 | for ( ; knew->name; knew++) { | ||
186 | int err; | 72 | int err; |
187 | struct snd_kcontrol *kctl; | 73 | struct snd_kcontrol *kctl; |
188 | kctl = snd_ctl_new1(knew, codec); | 74 | kctl = snd_ctl_new1(knew, codec); |
@@ -199,268 +85,6 @@ static int create_beep_ctls(struct hda_codec *codec) | |||
199 | #define create_beep_ctls(codec) 0 | 85 | #define create_beep_ctls(codec) 0 |
200 | #endif | 86 | #endif |
201 | 87 | ||
202 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
203 | static int ad198x_build_controls(struct hda_codec *codec) | ||
204 | { | ||
205 | struct ad198x_spec *spec = codec->spec; | ||
206 | struct snd_kcontrol *kctl; | ||
207 | unsigned int i; | ||
208 | int err; | ||
209 | |||
210 | for (i = 0; i < spec->num_mixers; i++) { | ||
211 | err = snd_hda_add_new_ctls(codec, spec->mixers[i]); | ||
212 | if (err < 0) | ||
213 | return err; | ||
214 | } | ||
215 | if (spec->multiout.dig_out_nid) { | ||
216 | err = snd_hda_create_spdif_out_ctls(codec, | ||
217 | spec->multiout.dig_out_nid, | ||
218 | spec->multiout.dig_out_nid); | ||
219 | if (err < 0) | ||
220 | return err; | ||
221 | err = snd_hda_create_spdif_share_sw(codec, | ||
222 | &spec->multiout); | ||
223 | if (err < 0) | ||
224 | return err; | ||
225 | spec->multiout.share_spdif = 1; | ||
226 | } | ||
227 | if (spec->dig_in_nid) { | ||
228 | err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); | ||
229 | if (err < 0) | ||
230 | return err; | ||
231 | } | ||
232 | |||
233 | /* create beep controls if needed */ | ||
234 | err = create_beep_ctls(codec); | ||
235 | if (err < 0) | ||
236 | return err; | ||
237 | |||
238 | /* if we have no master control, let's create it */ | ||
239 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { | ||
240 | unsigned int vmaster_tlv[4]; | ||
241 | snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, | ||
242 | HDA_OUTPUT, vmaster_tlv); | ||
243 | err = __snd_hda_add_vmaster(codec, "Master Playback Volume", | ||
244 | vmaster_tlv, | ||
245 | (spec->slave_vols ? | ||
246 | spec->slave_vols : ad_slave_pfxs), | ||
247 | "Playback Volume", | ||
248 | !spec->avoid_init_slave_vol, NULL); | ||
249 | if (err < 0) | ||
250 | return err; | ||
251 | } | ||
252 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { | ||
253 | err = snd_hda_add_vmaster(codec, "Master Playback Switch", | ||
254 | NULL, | ||
255 | (spec->slave_sws ? | ||
256 | spec->slave_sws : ad_slave_pfxs), | ||
257 | "Playback Switch"); | ||
258 | if (err < 0) | ||
259 | return err; | ||
260 | } | ||
261 | |||
262 | /* assign Capture Source enums to NID */ | ||
263 | kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); | ||
264 | if (!kctl) | ||
265 | kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); | ||
266 | for (i = 0; kctl && i < kctl->count; i++) { | ||
267 | err = snd_hda_add_nid(codec, kctl, i, spec->capsrc_nids[i]); | ||
268 | if (err < 0) | ||
269 | return err; | ||
270 | } | ||
271 | |||
272 | /* assign IEC958 enums to NID */ | ||
273 | kctl = snd_hda_find_mixer_ctl(codec, | ||
274 | SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source"); | ||
275 | if (kctl) { | ||
276 | err = snd_hda_add_nid(codec, kctl, 0, | ||
277 | spec->multiout.dig_out_nid); | ||
278 | if (err < 0) | ||
279 | return err; | ||
280 | } | ||
281 | |||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | #ifdef CONFIG_PM | ||
286 | static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid) | ||
287 | { | ||
288 | struct ad198x_spec *spec = codec->spec; | ||
289 | return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); | ||
290 | } | ||
291 | #endif | ||
292 | |||
293 | /* | ||
294 | * Analog playback callbacks | ||
295 | */ | ||
296 | static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
297 | struct hda_codec *codec, | ||
298 | struct snd_pcm_substream *substream) | ||
299 | { | ||
300 | struct ad198x_spec *spec = codec->spec; | ||
301 | return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, | ||
302 | hinfo); | ||
303 | } | ||
304 | |||
305 | static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
306 | struct hda_codec *codec, | ||
307 | unsigned int stream_tag, | ||
308 | unsigned int format, | ||
309 | struct snd_pcm_substream *substream) | ||
310 | { | ||
311 | struct ad198x_spec *spec = codec->spec; | ||
312 | return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, | ||
313 | format, substream); | ||
314 | } | ||
315 | |||
316 | static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
317 | struct hda_codec *codec, | ||
318 | struct snd_pcm_substream *substream) | ||
319 | { | ||
320 | struct ad198x_spec *spec = codec->spec; | ||
321 | return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); | ||
322 | } | ||
323 | |||
324 | /* | ||
325 | * Digital out | ||
326 | */ | ||
327 | static int ad198x_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
328 | struct hda_codec *codec, | ||
329 | struct snd_pcm_substream *substream) | ||
330 | { | ||
331 | struct ad198x_spec *spec = codec->spec; | ||
332 | return snd_hda_multi_out_dig_open(codec, &spec->multiout); | ||
333 | } | ||
334 | |||
335 | static int ad198x_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, | ||
336 | struct hda_codec *codec, | ||
337 | struct snd_pcm_substream *substream) | ||
338 | { | ||
339 | struct ad198x_spec *spec = codec->spec; | ||
340 | return snd_hda_multi_out_dig_close(codec, &spec->multiout); | ||
341 | } | ||
342 | |||
343 | static int ad198x_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
344 | struct hda_codec *codec, | ||
345 | unsigned int stream_tag, | ||
346 | unsigned int format, | ||
347 | struct snd_pcm_substream *substream) | ||
348 | { | ||
349 | struct ad198x_spec *spec = codec->spec; | ||
350 | return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, | ||
351 | format, substream); | ||
352 | } | ||
353 | |||
354 | static int ad198x_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
355 | struct hda_codec *codec, | ||
356 | struct snd_pcm_substream *substream) | ||
357 | { | ||
358 | struct ad198x_spec *spec = codec->spec; | ||
359 | return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); | ||
360 | } | ||
361 | |||
362 | /* | ||
363 | * Analog capture | ||
364 | */ | ||
365 | static int ad198x_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
366 | struct hda_codec *codec, | ||
367 | unsigned int stream_tag, | ||
368 | unsigned int format, | ||
369 | struct snd_pcm_substream *substream) | ||
370 | { | ||
371 | struct ad198x_spec *spec = codec->spec; | ||
372 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], | ||
373 | stream_tag, 0, format); | ||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
378 | struct hda_codec *codec, | ||
379 | struct snd_pcm_substream *substream) | ||
380 | { | ||
381 | struct ad198x_spec *spec = codec->spec; | ||
382 | snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); | ||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | /* | ||
387 | */ | ||
388 | static const struct hda_pcm_stream ad198x_pcm_analog_playback = { | ||
389 | .substreams = 1, | ||
390 | .channels_min = 2, | ||
391 | .channels_max = 6, /* changed later */ | ||
392 | .nid = 0, /* fill later */ | ||
393 | .ops = { | ||
394 | .open = ad198x_playback_pcm_open, | ||
395 | .prepare = ad198x_playback_pcm_prepare, | ||
396 | .cleanup = ad198x_playback_pcm_cleanup, | ||
397 | }, | ||
398 | }; | ||
399 | |||
400 | static const struct hda_pcm_stream ad198x_pcm_analog_capture = { | ||
401 | .substreams = 1, | ||
402 | .channels_min = 2, | ||
403 | .channels_max = 2, | ||
404 | .nid = 0, /* fill later */ | ||
405 | .ops = { | ||
406 | .prepare = ad198x_capture_pcm_prepare, | ||
407 | .cleanup = ad198x_capture_pcm_cleanup | ||
408 | }, | ||
409 | }; | ||
410 | |||
411 | static const struct hda_pcm_stream ad198x_pcm_digital_playback = { | ||
412 | .substreams = 1, | ||
413 | .channels_min = 2, | ||
414 | .channels_max = 2, | ||
415 | .nid = 0, /* fill later */ | ||
416 | .ops = { | ||
417 | .open = ad198x_dig_playback_pcm_open, | ||
418 | .close = ad198x_dig_playback_pcm_close, | ||
419 | .prepare = ad198x_dig_playback_pcm_prepare, | ||
420 | .cleanup = ad198x_dig_playback_pcm_cleanup | ||
421 | }, | ||
422 | }; | ||
423 | |||
424 | static const struct hda_pcm_stream ad198x_pcm_digital_capture = { | ||
425 | .substreams = 1, | ||
426 | .channels_min = 2, | ||
427 | .channels_max = 2, | ||
428 | /* NID is set in alc_build_pcms */ | ||
429 | }; | ||
430 | |||
431 | static int ad198x_build_pcms(struct hda_codec *codec) | ||
432 | { | ||
433 | struct ad198x_spec *spec = codec->spec; | ||
434 | struct hda_pcm *info = spec->pcm_rec; | ||
435 | |||
436 | codec->num_pcms = 1; | ||
437 | codec->pcm_info = info; | ||
438 | |||
439 | info->name = "AD198x Analog"; | ||
440 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_analog_playback; | ||
441 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels; | ||
442 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; | ||
443 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_analog_capture; | ||
444 | info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids; | ||
445 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; | ||
446 | |||
447 | if (spec->multiout.dig_out_nid) { | ||
448 | info++; | ||
449 | codec->num_pcms++; | ||
450 | codec->spdif_status_reset = 1; | ||
451 | info->name = "AD198x Digital"; | ||
452 | info->pcm_type = HDA_PCM_TYPE_SPDIF; | ||
453 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback; | ||
454 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; | ||
455 | if (spec->dig_in_nid) { | ||
456 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_digital_capture; | ||
457 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; | ||
458 | } | ||
459 | } | ||
460 | |||
461 | return 0; | ||
462 | } | ||
463 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
464 | 88 | ||
465 | static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front, | 89 | static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front, |
466 | hda_nid_t hp) | 90 | hda_nid_t hp) |
@@ -507,18 +131,6 @@ static void ad198x_shutup(struct hda_codec *codec) | |||
507 | ad198x_power_eapd(codec); | 131 | ad198x_power_eapd(codec); |
508 | } | 132 | } |
509 | 133 | ||
510 | static void ad198x_free(struct hda_codec *codec) | ||
511 | { | ||
512 | struct ad198x_spec *spec = codec->spec; | ||
513 | |||
514 | if (!spec) | ||
515 | return; | ||
516 | |||
517 | snd_hda_gen_spec_free(&spec->gen); | ||
518 | kfree(spec); | ||
519 | snd_hda_detach_beep_device(codec); | ||
520 | } | ||
521 | |||
522 | #ifdef CONFIG_PM | 134 | #ifdef CONFIG_PM |
523 | static int ad198x_suspend(struct hda_codec *codec) | 135 | static int ad198x_suspend(struct hda_codec *codec) |
524 | { | 136 | { |
@@ -527,65 +139,6 @@ static int ad198x_suspend(struct hda_codec *codec) | |||
527 | } | 139 | } |
528 | #endif | 140 | #endif |
529 | 141 | ||
530 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
531 | static const struct hda_codec_ops ad198x_patch_ops = { | ||
532 | .build_controls = ad198x_build_controls, | ||
533 | .build_pcms = ad198x_build_pcms, | ||
534 | .init = ad198x_init, | ||
535 | .free = ad198x_free, | ||
536 | #ifdef CONFIG_PM | ||
537 | .check_power_status = ad198x_check_power_status, | ||
538 | .suspend = ad198x_suspend, | ||
539 | #endif | ||
540 | .reboot_notify = ad198x_shutup, | ||
541 | }; | ||
542 | |||
543 | |||
544 | /* | ||
545 | * EAPD control | ||
546 | * the private value = nid | ||
547 | */ | ||
548 | #define ad198x_eapd_info snd_ctl_boolean_mono_info | ||
549 | |||
550 | static int ad198x_eapd_get(struct snd_kcontrol *kcontrol, | ||
551 | struct snd_ctl_elem_value *ucontrol) | ||
552 | { | ||
553 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
554 | struct ad198x_spec *spec = codec->spec; | ||
555 | if (codec->inv_eapd) | ||
556 | ucontrol->value.integer.value[0] = ! spec->cur_eapd; | ||
557 | else | ||
558 | ucontrol->value.integer.value[0] = spec->cur_eapd; | ||
559 | return 0; | ||
560 | } | ||
561 | |||
562 | static int ad198x_eapd_put(struct snd_kcontrol *kcontrol, | ||
563 | struct snd_ctl_elem_value *ucontrol) | ||
564 | { | ||
565 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
566 | struct ad198x_spec *spec = codec->spec; | ||
567 | hda_nid_t nid = kcontrol->private_value & 0xff; | ||
568 | unsigned int eapd; | ||
569 | eapd = !!ucontrol->value.integer.value[0]; | ||
570 | if (codec->inv_eapd) | ||
571 | eapd = !eapd; | ||
572 | if (eapd == spec->cur_eapd) | ||
573 | return 0; | ||
574 | spec->cur_eapd = eapd; | ||
575 | snd_hda_codec_write_cache(codec, nid, | ||
576 | 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
577 | eapd ? 0x02 : 0x00); | ||
578 | return 1; | ||
579 | } | ||
580 | |||
581 | static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol, | ||
582 | struct snd_ctl_elem_info *uinfo); | ||
583 | static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol, | ||
584 | struct snd_ctl_elem_value *ucontrol); | ||
585 | static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, | ||
586 | struct snd_ctl_elem_value *ucontrol); | ||
587 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
588 | |||
589 | 142 | ||
590 | /* | 143 | /* |
591 | * Automatic parse of I/O pins from the BIOS configuration | 144 | * Automatic parse of I/O pins from the BIOS configuration |
@@ -646,446 +199,6 @@ static int ad198x_parse_auto_config(struct hda_codec *codec) | |||
646 | * AD1986A specific | 199 | * AD1986A specific |
647 | */ | 200 | */ |
648 | 201 | ||
649 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
650 | #define AD1986A_SPDIF_OUT 0x02 | ||
651 | #define AD1986A_FRONT_DAC 0x03 | ||
652 | #define AD1986A_SURR_DAC 0x04 | ||
653 | #define AD1986A_CLFE_DAC 0x05 | ||
654 | #define AD1986A_ADC 0x06 | ||
655 | |||
656 | static const hda_nid_t ad1986a_dac_nids[3] = { | ||
657 | AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC | ||
658 | }; | ||
659 | static const hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC }; | ||
660 | static const hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 }; | ||
661 | |||
662 | static const struct hda_input_mux ad1986a_capture_source = { | ||
663 | .num_items = 7, | ||
664 | .items = { | ||
665 | { "Mic", 0x0 }, | ||
666 | { "CD", 0x1 }, | ||
667 | { "Aux", 0x3 }, | ||
668 | { "Line", 0x4 }, | ||
669 | { "Mix", 0x5 }, | ||
670 | { "Mono", 0x6 }, | ||
671 | { "Phone", 0x7 }, | ||
672 | }, | ||
673 | }; | ||
674 | |||
675 | |||
676 | static const struct hda_bind_ctls ad1986a_bind_pcm_vol = { | ||
677 | .ops = &snd_hda_bind_vol, | ||
678 | .values = { | ||
679 | HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT), | ||
680 | HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT), | ||
681 | HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT), | ||
682 | 0 | ||
683 | }, | ||
684 | }; | ||
685 | |||
686 | static const struct hda_bind_ctls ad1986a_bind_pcm_sw = { | ||
687 | .ops = &snd_hda_bind_sw, | ||
688 | .values = { | ||
689 | HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT), | ||
690 | HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT), | ||
691 | HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT), | ||
692 | 0 | ||
693 | }, | ||
694 | }; | ||
695 | |||
696 | /* | ||
697 | * mixers | ||
698 | */ | ||
699 | static const struct snd_kcontrol_new ad1986a_mixers[] = { | ||
700 | /* | ||
701 | * bind volumes/mutes of 3 DACs as a single PCM control for simplicity | ||
702 | */ | ||
703 | HDA_BIND_VOL("PCM Playback Volume", &ad1986a_bind_pcm_vol), | ||
704 | HDA_BIND_SW("PCM Playback Switch", &ad1986a_bind_pcm_sw), | ||
705 | HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
706 | HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
707 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT), | ||
708 | HDA_CODEC_MUTE("Surround Playback Switch", 0x1c, 0x0, HDA_OUTPUT), | ||
709 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x1d, 1, 0x0, HDA_OUTPUT), | ||
710 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x1d, 2, 0x0, HDA_OUTPUT), | ||
711 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x1d, 1, 0x0, HDA_OUTPUT), | ||
712 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x1d, 2, 0x0, HDA_OUTPUT), | ||
713 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT), | ||
714 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT), | ||
715 | HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT), | ||
716 | HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
717 | HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT), | ||
718 | HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT), | ||
719 | HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT), | ||
720 | HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT), | ||
721 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
722 | HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||
723 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT), | ||
724 | HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT), | ||
725 | HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), | ||
726 | HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), | ||
727 | HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), | ||
728 | { | ||
729 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
730 | .name = "Capture Source", | ||
731 | .info = ad198x_mux_enum_info, | ||
732 | .get = ad198x_mux_enum_get, | ||
733 | .put = ad198x_mux_enum_put, | ||
734 | }, | ||
735 | HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT), | ||
736 | { } /* end */ | ||
737 | }; | ||
738 | |||
739 | /* additional mixers for 3stack mode */ | ||
740 | static const struct snd_kcontrol_new ad1986a_3st_mixers[] = { | ||
741 | { | ||
742 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
743 | .name = "Channel Mode", | ||
744 | .info = ad198x_ch_mode_info, | ||
745 | .get = ad198x_ch_mode_get, | ||
746 | .put = ad198x_ch_mode_put, | ||
747 | }, | ||
748 | { } /* end */ | ||
749 | }; | ||
750 | |||
751 | /* laptop model - 2ch only */ | ||
752 | static const hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC }; | ||
753 | |||
754 | /* master controls both pins 0x1a and 0x1b */ | ||
755 | static const struct hda_bind_ctls ad1986a_laptop_master_vol = { | ||
756 | .ops = &snd_hda_bind_vol, | ||
757 | .values = { | ||
758 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), | ||
759 | HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), | ||
760 | 0, | ||
761 | }, | ||
762 | }; | ||
763 | |||
764 | static const struct hda_bind_ctls ad1986a_laptop_master_sw = { | ||
765 | .ops = &snd_hda_bind_sw, | ||
766 | .values = { | ||
767 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), | ||
768 | HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), | ||
769 | 0, | ||
770 | }, | ||
771 | }; | ||
772 | |||
773 | static const struct snd_kcontrol_new ad1986a_laptop_mixers[] = { | ||
774 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
775 | HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), | ||
776 | HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), | ||
777 | HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), | ||
778 | HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT), | ||
779 | HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
780 | HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT), | ||
781 | HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT), | ||
782 | HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT), | ||
783 | HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT), | ||
784 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
785 | HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||
786 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT), | ||
787 | /* | ||
788 | HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT), | ||
789 | HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */ | ||
790 | HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), | ||
791 | HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), | ||
792 | { | ||
793 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
794 | .name = "Capture Source", | ||
795 | .info = ad198x_mux_enum_info, | ||
796 | .get = ad198x_mux_enum_get, | ||
797 | .put = ad198x_mux_enum_put, | ||
798 | }, | ||
799 | { } /* end */ | ||
800 | }; | ||
801 | |||
802 | /* laptop-eapd model - 2ch only */ | ||
803 | |||
804 | static const struct hda_input_mux ad1986a_laptop_eapd_capture_source = { | ||
805 | .num_items = 3, | ||
806 | .items = { | ||
807 | { "Mic", 0x0 }, | ||
808 | { "Internal Mic", 0x4 }, | ||
809 | { "Mix", 0x5 }, | ||
810 | }, | ||
811 | }; | ||
812 | |||
813 | static const struct hda_input_mux ad1986a_automic_capture_source = { | ||
814 | .num_items = 2, | ||
815 | .items = { | ||
816 | { "Mic", 0x0 }, | ||
817 | { "Mix", 0x5 }, | ||
818 | }, | ||
819 | }; | ||
820 | |||
821 | static const struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = { | ||
822 | HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), | ||
823 | HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), | ||
824 | { } /* end */ | ||
825 | }; | ||
826 | |||
827 | static const struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { | ||
828 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
829 | HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), | ||
830 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
831 | HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||
832 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT), | ||
833 | HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), | ||
834 | HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), | ||
835 | { | ||
836 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
837 | .name = "Capture Source", | ||
838 | .info = ad198x_mux_enum_info, | ||
839 | .get = ad198x_mux_enum_get, | ||
840 | .put = ad198x_mux_enum_put, | ||
841 | }, | ||
842 | { | ||
843 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
844 | .name = "External Amplifier", | ||
845 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, | ||
846 | .info = ad198x_eapd_info, | ||
847 | .get = ad198x_eapd_get, | ||
848 | .put = ad198x_eapd_put, | ||
849 | .private_value = 0x1b, /* port-D */ | ||
850 | }, | ||
851 | { } /* end */ | ||
852 | }; | ||
853 | |||
854 | static const struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = { | ||
855 | HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT), | ||
856 | HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT), | ||
857 | { } /* end */ | ||
858 | }; | ||
859 | |||
860 | /* laptop-automute - 2ch only */ | ||
861 | |||
862 | static void ad1986a_update_hp(struct hda_codec *codec) | ||
863 | { | ||
864 | struct ad198x_spec *spec = codec->spec; | ||
865 | unsigned int mute; | ||
866 | |||
867 | if (spec->jack_present) | ||
868 | mute = HDA_AMP_MUTE; /* mute internal speaker */ | ||
869 | else | ||
870 | /* unmute internal speaker if necessary */ | ||
871 | mute = snd_hda_codec_amp_read(codec, 0x1a, 0, HDA_OUTPUT, 0); | ||
872 | snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, | ||
873 | HDA_AMP_MUTE, mute); | ||
874 | } | ||
875 | |||
876 | static void ad1986a_hp_automute(struct hda_codec *codec) | ||
877 | { | ||
878 | struct ad198x_spec *spec = codec->spec; | ||
879 | |||
880 | spec->jack_present = snd_hda_jack_detect(codec, 0x1a); | ||
881 | if (spec->inv_jack_detect) | ||
882 | spec->jack_present = !spec->jack_present; | ||
883 | ad1986a_update_hp(codec); | ||
884 | } | ||
885 | |||
886 | #define AD1986A_HP_EVENT 0x37 | ||
887 | |||
888 | static void ad1986a_hp_unsol_event(struct hda_codec *codec, unsigned int res) | ||
889 | { | ||
890 | if ((res >> 26) != AD1986A_HP_EVENT) | ||
891 | return; | ||
892 | ad1986a_hp_automute(codec); | ||
893 | } | ||
894 | |||
895 | static int ad1986a_hp_init(struct hda_codec *codec) | ||
896 | { | ||
897 | ad198x_init(codec); | ||
898 | ad1986a_hp_automute(codec); | ||
899 | return 0; | ||
900 | } | ||
901 | |||
902 | /* bind hp and internal speaker mute (with plug check) */ | ||
903 | static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol, | ||
904 | struct snd_ctl_elem_value *ucontrol) | ||
905 | { | ||
906 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
907 | int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); | ||
908 | if (change) | ||
909 | ad1986a_update_hp(codec); | ||
910 | return change; | ||
911 | } | ||
912 | |||
913 | static const struct snd_kcontrol_new ad1986a_automute_master_mixers[] = { | ||
914 | HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), | ||
915 | { | ||
916 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
917 | .name = "Master Playback Switch", | ||
918 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
919 | .info = snd_hda_mixer_amp_switch_info, | ||
920 | .get = snd_hda_mixer_amp_switch_get, | ||
921 | .put = ad1986a_hp_master_sw_put, | ||
922 | .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), | ||
923 | }, | ||
924 | { } /* end */ | ||
925 | }; | ||
926 | |||
927 | |||
928 | /* | ||
929 | * initialization verbs | ||
930 | */ | ||
931 | static const struct hda_verb ad1986a_init_verbs[] = { | ||
932 | /* Front, Surround, CLFE DAC; mute as default */ | ||
933 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
934 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
935 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
936 | /* Downmix - off */ | ||
937 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
938 | /* HP, Line-Out, Surround, CLFE selectors */ | ||
939 | {0x0a, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
940 | {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
941 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
942 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
943 | /* Mono selector */ | ||
944 | {0x0e, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
945 | /* Mic selector: Mic 1/2 pin */ | ||
946 | {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
947 | /* Line-in selector: Line-in */ | ||
948 | {0x10, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
949 | /* Mic 1/2 swap */ | ||
950 | {0x11, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
951 | /* Record selector: mic */ | ||
952 | {0x12, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
953 | /* Mic, Phone, CD, Aux, Line-In amp; mute as default */ | ||
954 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
955 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
956 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
957 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
958 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
959 | /* PC beep */ | ||
960 | {0x18, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
961 | /* HP, Line-Out, Surround, CLFE, Mono pins; mute as default */ | ||
962 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
963 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
964 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
965 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
966 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
967 | /* HP Pin */ | ||
968 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | ||
969 | /* Front, Surround, CLFE Pins */ | ||
970 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
971 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
972 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
973 | /* Mono Pin */ | ||
974 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
975 | /* Mic Pin */ | ||
976 | {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
977 | /* Line, Aux, CD, Beep-In Pin */ | ||
978 | {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
979 | {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
980 | {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
981 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
982 | {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
983 | { } /* end */ | ||
984 | }; | ||
985 | |||
986 | static const struct hda_verb ad1986a_ch2_init[] = { | ||
987 | /* Surround out -> Line In */ | ||
988 | { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, | ||
989 | /* Line-in selectors */ | ||
990 | { 0x10, AC_VERB_SET_CONNECT_SEL, 0x1 }, | ||
991 | /* CLFE -> Mic in */ | ||
992 | { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, | ||
993 | /* Mic selector, mix C/LFE (backmic) and Mic (frontmic) */ | ||
994 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 }, | ||
995 | { } /* end */ | ||
996 | }; | ||
997 | |||
998 | static const struct hda_verb ad1986a_ch4_init[] = { | ||
999 | /* Surround out -> Surround */ | ||
1000 | { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
1001 | { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 }, | ||
1002 | /* CLFE -> Mic in */ | ||
1003 | { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, | ||
1004 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 }, | ||
1005 | { } /* end */ | ||
1006 | }; | ||
1007 | |||
1008 | static const struct hda_verb ad1986a_ch6_init[] = { | ||
1009 | /* Surround out -> Surround out */ | ||
1010 | { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
1011 | { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 }, | ||
1012 | /* CLFE -> CLFE */ | ||
1013 | { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
1014 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x0 }, | ||
1015 | { } /* end */ | ||
1016 | }; | ||
1017 | |||
1018 | static const struct hda_channel_mode ad1986a_modes[3] = { | ||
1019 | { 2, ad1986a_ch2_init }, | ||
1020 | { 4, ad1986a_ch4_init }, | ||
1021 | { 6, ad1986a_ch6_init }, | ||
1022 | }; | ||
1023 | |||
1024 | /* eapd initialization */ | ||
1025 | static const struct hda_verb ad1986a_eapd_init_verbs[] = { | ||
1026 | {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, | ||
1027 | {} | ||
1028 | }; | ||
1029 | |||
1030 | /* pin sensing on HP jack */ | ||
1031 | static const struct hda_verb ad1986a_hp_init_verbs[] = { | ||
1032 | {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT}, | ||
1033 | {} | ||
1034 | }; | ||
1035 | |||
1036 | |||
1037 | /* models */ | ||
1038 | enum { | ||
1039 | AD1986A_AUTO, | ||
1040 | AD1986A_6STACK, | ||
1041 | AD1986A_3STACK, | ||
1042 | AD1986A_LAPTOP, | ||
1043 | AD1986A_LAPTOP_EAPD, | ||
1044 | AD1986A_LAPTOP_AUTOMUTE, | ||
1045 | AD1986A_MODELS | ||
1046 | }; | ||
1047 | |||
1048 | static const char * const ad1986a_models[AD1986A_MODELS] = { | ||
1049 | [AD1986A_AUTO] = "auto", | ||
1050 | [AD1986A_6STACK] = "6stack", | ||
1051 | [AD1986A_3STACK] = "3stack", | ||
1052 | [AD1986A_LAPTOP] = "laptop", | ||
1053 | [AD1986A_LAPTOP_EAPD] = "laptop-eapd", | ||
1054 | [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute", | ||
1055 | }; | ||
1056 | |||
1057 | static const struct snd_pci_quirk ad1986a_cfg_tbl[] = { | ||
1058 | SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD), | ||
1059 | SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK), | ||
1060 | SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP), | ||
1061 | SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK), | ||
1062 | SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK), | ||
1063 | SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK), | ||
1064 | SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK), | ||
1065 | SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), | ||
1066 | SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), | ||
1067 | SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK), | ||
1068 | {} | ||
1069 | }; | ||
1070 | |||
1071 | #ifdef CONFIG_PM | ||
1072 | static const struct hda_amp_list ad1986a_loopbacks[] = { | ||
1073 | { 0x13, HDA_OUTPUT, 0 }, /* Mic */ | ||
1074 | { 0x14, HDA_OUTPUT, 0 }, /* Phone */ | ||
1075 | { 0x15, HDA_OUTPUT, 0 }, /* CD */ | ||
1076 | { 0x16, HDA_OUTPUT, 0 }, /* Aux */ | ||
1077 | { 0x17, HDA_OUTPUT, 0 }, /* Line */ | ||
1078 | { } /* end */ | ||
1079 | }; | ||
1080 | #endif | ||
1081 | |||
1082 | static int is_jack_available(struct hda_codec *codec, hda_nid_t nid) | ||
1083 | { | ||
1084 | unsigned int conf = snd_hda_codec_get_pincfg(codec, nid); | ||
1085 | return get_defcfg_connect(conf) != AC_JACK_PORT_NONE; | ||
1086 | } | ||
1087 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
1088 | |||
1089 | static int alloc_ad_spec(struct hda_codec *codec) | 202 | static int alloc_ad_spec(struct hda_codec *codec) |
1090 | { | 203 | { |
1091 | struct ad198x_spec *spec; | 204 | struct ad198x_spec *spec; |
@@ -1114,6 +227,9 @@ enum { | |||
1114 | AD1986A_FIXUP_INV_JACK_DETECT, | 227 | AD1986A_FIXUP_INV_JACK_DETECT, |
1115 | AD1986A_FIXUP_ULTRA, | 228 | AD1986A_FIXUP_ULTRA, |
1116 | AD1986A_FIXUP_SAMSUNG, | 229 | AD1986A_FIXUP_SAMSUNG, |
230 | AD1986A_FIXUP_3STACK, | ||
231 | AD1986A_FIXUP_LAPTOP, | ||
232 | AD1986A_FIXUP_LAPTOP_IMIC, | ||
1117 | }; | 233 | }; |
1118 | 234 | ||
1119 | static const struct hda_fixup ad1986a_fixups[] = { | 235 | static const struct hda_fixup ad1986a_fixups[] = { |
@@ -1139,18 +255,68 @@ static const struct hda_fixup ad1986a_fixups[] = { | |||
1139 | {} | 255 | {} |
1140 | }, | 256 | }, |
1141 | }, | 257 | }, |
258 | [AD1986A_FIXUP_3STACK] = { | ||
259 | .type = HDA_FIXUP_PINS, | ||
260 | .v.pins = (const struct hda_pintbl[]) { | ||
261 | { 0x1a, 0x02214021 }, /* headphone */ | ||
262 | { 0x1b, 0x01014011 }, /* front */ | ||
263 | { 0x1c, 0x01013012 }, /* surround */ | ||
264 | { 0x1d, 0x01019015 }, /* clfe */ | ||
265 | { 0x1e, 0x411111f0 }, /* N/A */ | ||
266 | { 0x1f, 0x02a190f0 }, /* mic */ | ||
267 | { 0x20, 0x018130f0 }, /* line-in */ | ||
268 | {} | ||
269 | }, | ||
270 | }, | ||
271 | [AD1986A_FIXUP_LAPTOP] = { | ||
272 | .type = HDA_FIXUP_PINS, | ||
273 | .v.pins = (const struct hda_pintbl[]) { | ||
274 | { 0x1a, 0x02214021 }, /* headphone */ | ||
275 | { 0x1b, 0x90170110 }, /* speaker */ | ||
276 | { 0x1c, 0x411111f0 }, /* N/A */ | ||
277 | { 0x1d, 0x411111f0 }, /* N/A */ | ||
278 | { 0x1e, 0x411111f0 }, /* N/A */ | ||
279 | { 0x1f, 0x02a191f0 }, /* mic */ | ||
280 | { 0x20, 0x411111f0 }, /* N/A */ | ||
281 | {} | ||
282 | }, | ||
283 | }, | ||
284 | [AD1986A_FIXUP_LAPTOP_IMIC] = { | ||
285 | .type = HDA_FIXUP_PINS, | ||
286 | .v.pins = (const struct hda_pintbl[]) { | ||
287 | { 0x1d, 0x90a7013e }, /* int mic */ | ||
288 | {} | ||
289 | }, | ||
290 | .chained_before = 1, | ||
291 | .chain_id = AD1986A_FIXUP_LAPTOP, | ||
292 | }, | ||
1142 | }; | 293 | }; |
1143 | 294 | ||
1144 | static const struct snd_pci_quirk ad1986a_fixup_tbl[] = { | 295 | static const struct snd_pci_quirk ad1986a_fixup_tbl[] = { |
296 | SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_FIXUP_LAPTOP_IMIC), | ||
297 | SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8100, "ASUS P5", AD1986A_FIXUP_3STACK), | ||
298 | SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8200, "ASUS M2", AD1986A_FIXUP_3STACK), | ||
299 | SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_FIXUP_3STACK), | ||
300 | SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_FIXUP_LAPTOP), | ||
1145 | SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_FIXUP_SAMSUNG), | 301 | SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_FIXUP_SAMSUNG), |
1146 | SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_FIXUP_ULTRA), | 302 | SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_FIXUP_ULTRA), |
1147 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT), | 303 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT), |
304 | SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_FIXUP_3STACK), | ||
305 | SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_FIXUP_3STACK), | ||
306 | {} | ||
307 | }; | ||
308 | |||
309 | static const struct hda_model_fixup ad1986a_fixup_models[] = { | ||
310 | { .id = AD1986A_FIXUP_3STACK, .name = "3stack" }, | ||
311 | { .id = AD1986A_FIXUP_LAPTOP, .name = "laptop" }, | ||
312 | { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-imic" }, | ||
313 | { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-eapd" }, /* alias */ | ||
1148 | {} | 314 | {} |
1149 | }; | 315 | }; |
1150 | 316 | ||
1151 | /* | 317 | /* |
1152 | */ | 318 | */ |
1153 | static int ad1986a_parse_auto_config(struct hda_codec *codec) | 319 | static int patch_ad1986a(struct hda_codec *codec) |
1154 | { | 320 | { |
1155 | int err; | 321 | int err; |
1156 | struct ad198x_spec *spec; | 322 | struct ad198x_spec *spec; |
@@ -1175,7 +341,8 @@ static int ad1986a_parse_auto_config(struct hda_codec *codec) | |||
1175 | */ | 341 | */ |
1176 | spec->gen.multiout.no_share_stream = 1; | 342 | spec->gen.multiout.no_share_stream = 1; |
1177 | 343 | ||
1178 | snd_hda_pick_fixup(codec, NULL, ad1986a_fixup_tbl, ad1986a_fixups); | 344 | snd_hda_pick_fixup(codec, ad1986a_fixup_models, ad1986a_fixup_tbl, |
345 | ad1986a_fixups); | ||
1179 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); | 346 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); |
1180 | 347 | ||
1181 | err = ad198x_parse_auto_config(codec); | 348 | err = ad198x_parse_auto_config(codec); |
@@ -1189,128 +356,6 @@ static int ad1986a_parse_auto_config(struct hda_codec *codec) | |||
1189 | return 0; | 356 | return 0; |
1190 | } | 357 | } |
1191 | 358 | ||
1192 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
1193 | static int patch_ad1986a(struct hda_codec *codec) | ||
1194 | { | ||
1195 | struct ad198x_spec *spec; | ||
1196 | int err, board_config; | ||
1197 | |||
1198 | board_config = snd_hda_check_board_config(codec, AD1986A_MODELS, | ||
1199 | ad1986a_models, | ||
1200 | ad1986a_cfg_tbl); | ||
1201 | if (board_config < 0) { | ||
1202 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
1203 | codec->chip_name); | ||
1204 | board_config = AD1986A_AUTO; | ||
1205 | } | ||
1206 | |||
1207 | if (board_config == AD1986A_AUTO) | ||
1208 | return ad1986a_parse_auto_config(codec); | ||
1209 | |||
1210 | err = alloc_ad_spec(codec); | ||
1211 | if (err < 0) | ||
1212 | return err; | ||
1213 | spec = codec->spec; | ||
1214 | |||
1215 | err = snd_hda_attach_beep_device(codec, 0x19); | ||
1216 | if (err < 0) { | ||
1217 | ad198x_free(codec); | ||
1218 | return err; | ||
1219 | } | ||
1220 | set_beep_amp(spec, 0x18, 0, HDA_OUTPUT); | ||
1221 | |||
1222 | spec->multiout.max_channels = 6; | ||
1223 | spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids); | ||
1224 | spec->multiout.dac_nids = ad1986a_dac_nids; | ||
1225 | spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT; | ||
1226 | spec->num_adc_nids = 1; | ||
1227 | spec->adc_nids = ad1986a_adc_nids; | ||
1228 | spec->capsrc_nids = ad1986a_capsrc_nids; | ||
1229 | spec->input_mux = &ad1986a_capture_source; | ||
1230 | spec->num_mixers = 1; | ||
1231 | spec->mixers[0] = ad1986a_mixers; | ||
1232 | spec->num_init_verbs = 1; | ||
1233 | spec->init_verbs[0] = ad1986a_init_verbs; | ||
1234 | #ifdef CONFIG_PM | ||
1235 | spec->loopback.amplist = ad1986a_loopbacks; | ||
1236 | #endif | ||
1237 | spec->vmaster_nid = 0x1b; | ||
1238 | codec->inv_eapd = 1; /* AD1986A has the inverted EAPD implementation */ | ||
1239 | |||
1240 | codec->patch_ops = ad198x_patch_ops; | ||
1241 | |||
1242 | /* override some parameters */ | ||
1243 | switch (board_config) { | ||
1244 | case AD1986A_3STACK: | ||
1245 | spec->num_mixers = 2; | ||
1246 | spec->mixers[1] = ad1986a_3st_mixers; | ||
1247 | spec->num_init_verbs = 2; | ||
1248 | spec->init_verbs[1] = ad1986a_ch2_init; | ||
1249 | spec->channel_mode = ad1986a_modes; | ||
1250 | spec->num_channel_mode = ARRAY_SIZE(ad1986a_modes); | ||
1251 | spec->need_dac_fix = 1; | ||
1252 | spec->multiout.max_channels = 2; | ||
1253 | spec->multiout.num_dacs = 1; | ||
1254 | break; | ||
1255 | case AD1986A_LAPTOP: | ||
1256 | spec->mixers[0] = ad1986a_laptop_mixers; | ||
1257 | spec->multiout.max_channels = 2; | ||
1258 | spec->multiout.num_dacs = 1; | ||
1259 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | ||
1260 | break; | ||
1261 | case AD1986A_LAPTOP_EAPD: | ||
1262 | spec->num_mixers = 3; | ||
1263 | spec->mixers[0] = ad1986a_laptop_master_mixers; | ||
1264 | spec->mixers[1] = ad1986a_laptop_eapd_mixers; | ||
1265 | spec->mixers[2] = ad1986a_laptop_intmic_mixers; | ||
1266 | spec->num_init_verbs = 2; | ||
1267 | spec->init_verbs[1] = ad1986a_eapd_init_verbs; | ||
1268 | spec->multiout.max_channels = 2; | ||
1269 | spec->multiout.num_dacs = 1; | ||
1270 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | ||
1271 | if (!is_jack_available(codec, 0x25)) | ||
1272 | spec->multiout.dig_out_nid = 0; | ||
1273 | spec->input_mux = &ad1986a_laptop_eapd_capture_source; | ||
1274 | break; | ||
1275 | case AD1986A_LAPTOP_AUTOMUTE: | ||
1276 | spec->num_mixers = 3; | ||
1277 | spec->mixers[0] = ad1986a_automute_master_mixers; | ||
1278 | spec->mixers[1] = ad1986a_laptop_eapd_mixers; | ||
1279 | spec->mixers[2] = ad1986a_laptop_intmic_mixers; | ||
1280 | spec->num_init_verbs = 3; | ||
1281 | spec->init_verbs[1] = ad1986a_eapd_init_verbs; | ||
1282 | spec->init_verbs[2] = ad1986a_hp_init_verbs; | ||
1283 | spec->multiout.max_channels = 2; | ||
1284 | spec->multiout.num_dacs = 1; | ||
1285 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | ||
1286 | if (!is_jack_available(codec, 0x25)) | ||
1287 | spec->multiout.dig_out_nid = 0; | ||
1288 | spec->input_mux = &ad1986a_laptop_eapd_capture_source; | ||
1289 | codec->patch_ops.unsol_event = ad1986a_hp_unsol_event; | ||
1290 | codec->patch_ops.init = ad1986a_hp_init; | ||
1291 | /* Lenovo N100 seems to report the reversed bit | ||
1292 | * for HP jack-sensing | ||
1293 | */ | ||
1294 | spec->inv_jack_detect = 1; | ||
1295 | break; | ||
1296 | } | ||
1297 | |||
1298 | /* AD1986A has a hardware problem that it can't share a stream | ||
1299 | * with multiple output pins. The copy of front to surrounds | ||
1300 | * causes noisy or silent outputs at a certain timing, e.g. | ||
1301 | * changing the volume. | ||
1302 | * So, let's disable the shared stream. | ||
1303 | */ | ||
1304 | spec->multiout.no_share_stream = 1; | ||
1305 | |||
1306 | codec->no_trigger_sense = 1; | ||
1307 | codec->no_sticky_stream = 1; | ||
1308 | |||
1309 | return 0; | ||
1310 | } | ||
1311 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
1312 | #define patch_ad1986a ad1986a_parse_auto_config | ||
1313 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
1314 | 359 | ||
1315 | /* | 360 | /* |
1316 | * AD1983 specific | 361 | * AD1983 specific |