diff options
Diffstat (limited to 'sound/pci/hda/patch_analog.c')
-rw-r--r-- | sound/pci/hda/patch_analog.c | 4528 |
1 files changed, 177 insertions, 4351 deletions
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index d97f0d61a15b..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 | }; | ||
96 | |||
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 | }; | 45 | }; |
148 | 46 | ||
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,537 +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 | /* re-connect the mic boost input according to the jack sensing */ | ||
861 | static void ad1986a_automic(struct hda_codec *codec) | ||
862 | { | ||
863 | unsigned int present; | ||
864 | present = snd_hda_jack_detect(codec, 0x1f); | ||
865 | /* 0 = 0x1f, 2 = 0x1d, 4 = mixed */ | ||
866 | snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_CONNECT_SEL, | ||
867 | present ? 0 : 2); | ||
868 | } | ||
869 | |||
870 | #define AD1986A_MIC_EVENT 0x36 | ||
871 | |||
872 | static void ad1986a_automic_unsol_event(struct hda_codec *codec, | ||
873 | unsigned int res) | ||
874 | { | ||
875 | if ((res >> 26) != AD1986A_MIC_EVENT) | ||
876 | return; | ||
877 | ad1986a_automic(codec); | ||
878 | } | ||
879 | |||
880 | static int ad1986a_automic_init(struct hda_codec *codec) | ||
881 | { | ||
882 | ad198x_init(codec); | ||
883 | ad1986a_automic(codec); | ||
884 | return 0; | ||
885 | } | ||
886 | |||
887 | /* laptop-automute - 2ch only */ | ||
888 | |||
889 | static void ad1986a_update_hp(struct hda_codec *codec) | ||
890 | { | ||
891 | struct ad198x_spec *spec = codec->spec; | ||
892 | unsigned int mute; | ||
893 | |||
894 | if (spec->jack_present) | ||
895 | mute = HDA_AMP_MUTE; /* mute internal speaker */ | ||
896 | else | ||
897 | /* unmute internal speaker if necessary */ | ||
898 | mute = snd_hda_codec_amp_read(codec, 0x1a, 0, HDA_OUTPUT, 0); | ||
899 | snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, | ||
900 | HDA_AMP_MUTE, mute); | ||
901 | } | ||
902 | |||
903 | static void ad1986a_hp_automute(struct hda_codec *codec) | ||
904 | { | ||
905 | struct ad198x_spec *spec = codec->spec; | ||
906 | |||
907 | spec->jack_present = snd_hda_jack_detect(codec, 0x1a); | ||
908 | if (spec->inv_jack_detect) | ||
909 | spec->jack_present = !spec->jack_present; | ||
910 | ad1986a_update_hp(codec); | ||
911 | } | ||
912 | |||
913 | #define AD1986A_HP_EVENT 0x37 | ||
914 | |||
915 | static void ad1986a_hp_unsol_event(struct hda_codec *codec, unsigned int res) | ||
916 | { | ||
917 | if ((res >> 26) != AD1986A_HP_EVENT) | ||
918 | return; | ||
919 | ad1986a_hp_automute(codec); | ||
920 | } | ||
921 | |||
922 | static int ad1986a_hp_init(struct hda_codec *codec) | ||
923 | { | ||
924 | ad198x_init(codec); | ||
925 | ad1986a_hp_automute(codec); | ||
926 | return 0; | ||
927 | } | ||
928 | |||
929 | /* bind hp and internal speaker mute (with plug check) */ | ||
930 | static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol, | ||
931 | struct snd_ctl_elem_value *ucontrol) | ||
932 | { | ||
933 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
934 | int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); | ||
935 | if (change) | ||
936 | ad1986a_update_hp(codec); | ||
937 | return change; | ||
938 | } | ||
939 | |||
940 | static const struct snd_kcontrol_new ad1986a_automute_master_mixers[] = { | ||
941 | HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), | ||
942 | { | ||
943 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
944 | .name = "Master Playback Switch", | ||
945 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
946 | .info = snd_hda_mixer_amp_switch_info, | ||
947 | .get = snd_hda_mixer_amp_switch_get, | ||
948 | .put = ad1986a_hp_master_sw_put, | ||
949 | .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), | ||
950 | }, | ||
951 | { } /* end */ | ||
952 | }; | ||
953 | |||
954 | |||
955 | /* | ||
956 | * initialization verbs | ||
957 | */ | ||
958 | static const struct hda_verb ad1986a_init_verbs[] = { | ||
959 | /* Front, Surround, CLFE DAC; mute as default */ | ||
960 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
961 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
962 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
963 | /* Downmix - off */ | ||
964 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
965 | /* HP, Line-Out, Surround, CLFE selectors */ | ||
966 | {0x0a, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
967 | {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
968 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
969 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
970 | /* Mono selector */ | ||
971 | {0x0e, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
972 | /* Mic selector: Mic 1/2 pin */ | ||
973 | {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
974 | /* Line-in selector: Line-in */ | ||
975 | {0x10, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
976 | /* Mic 1/2 swap */ | ||
977 | {0x11, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
978 | /* Record selector: mic */ | ||
979 | {0x12, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
980 | /* Mic, Phone, CD, Aux, Line-In amp; mute as default */ | ||
981 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
982 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
983 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
984 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
985 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
986 | /* PC beep */ | ||
987 | {0x18, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
988 | /* HP, Line-Out, Surround, CLFE, Mono pins; mute as default */ | ||
989 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
990 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
991 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
992 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
993 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
994 | /* HP Pin */ | ||
995 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | ||
996 | /* Front, Surround, CLFE Pins */ | ||
997 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
998 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
999 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
1000 | /* Mono Pin */ | ||
1001 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
1002 | /* Mic Pin */ | ||
1003 | {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
1004 | /* Line, Aux, CD, Beep-In Pin */ | ||
1005 | {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
1006 | {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
1007 | {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
1008 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
1009 | {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
1010 | { } /* end */ | ||
1011 | }; | ||
1012 | |||
1013 | static const struct hda_verb ad1986a_ch2_init[] = { | ||
1014 | /* Surround out -> Line In */ | ||
1015 | { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, | ||
1016 | /* Line-in selectors */ | ||
1017 | { 0x10, AC_VERB_SET_CONNECT_SEL, 0x1 }, | ||
1018 | /* CLFE -> Mic in */ | ||
1019 | { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, | ||
1020 | /* Mic selector, mix C/LFE (backmic) and Mic (frontmic) */ | ||
1021 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 }, | ||
1022 | { } /* end */ | ||
1023 | }; | ||
1024 | |||
1025 | static const struct hda_verb ad1986a_ch4_init[] = { | ||
1026 | /* Surround out -> Surround */ | ||
1027 | { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
1028 | { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 }, | ||
1029 | /* CLFE -> Mic in */ | ||
1030 | { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, | ||
1031 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 }, | ||
1032 | { } /* end */ | ||
1033 | }; | ||
1034 | |||
1035 | static const struct hda_verb ad1986a_ch6_init[] = { | ||
1036 | /* Surround out -> Surround out */ | ||
1037 | { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
1038 | { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 }, | ||
1039 | /* CLFE -> CLFE */ | ||
1040 | { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
1041 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x0 }, | ||
1042 | { } /* end */ | ||
1043 | }; | ||
1044 | |||
1045 | static const struct hda_channel_mode ad1986a_modes[3] = { | ||
1046 | { 2, ad1986a_ch2_init }, | ||
1047 | { 4, ad1986a_ch4_init }, | ||
1048 | { 6, ad1986a_ch6_init }, | ||
1049 | }; | ||
1050 | |||
1051 | /* eapd initialization */ | ||
1052 | static const struct hda_verb ad1986a_eapd_init_verbs[] = { | ||
1053 | {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, | ||
1054 | {} | ||
1055 | }; | ||
1056 | |||
1057 | static const struct hda_verb ad1986a_automic_verbs[] = { | ||
1058 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1059 | {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1060 | /*{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},*/ | ||
1061 | {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1062 | {0x1f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_MIC_EVENT}, | ||
1063 | {} | ||
1064 | }; | ||
1065 | |||
1066 | /* Ultra initialization */ | ||
1067 | static const struct hda_verb ad1986a_ultra_init[] = { | ||
1068 | /* eapd initialization */ | ||
1069 | { 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, | ||
1070 | /* CLFE -> Mic in */ | ||
1071 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2 }, | ||
1072 | { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
1073 | { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, | ||
1074 | { } /* end */ | ||
1075 | }; | ||
1076 | |||
1077 | /* pin sensing on HP jack */ | ||
1078 | static const struct hda_verb ad1986a_hp_init_verbs[] = { | ||
1079 | {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT}, | ||
1080 | {} | ||
1081 | }; | ||
1082 | |||
1083 | static void ad1986a_samsung_p50_unsol_event(struct hda_codec *codec, | ||
1084 | unsigned int res) | ||
1085 | { | ||
1086 | switch (res >> 26) { | ||
1087 | case AD1986A_HP_EVENT: | ||
1088 | ad1986a_hp_automute(codec); | ||
1089 | break; | ||
1090 | case AD1986A_MIC_EVENT: | ||
1091 | ad1986a_automic(codec); | ||
1092 | break; | ||
1093 | } | ||
1094 | } | ||
1095 | |||
1096 | static int ad1986a_samsung_p50_init(struct hda_codec *codec) | ||
1097 | { | ||
1098 | ad198x_init(codec); | ||
1099 | ad1986a_hp_automute(codec); | ||
1100 | ad1986a_automic(codec); | ||
1101 | return 0; | ||
1102 | } | ||
1103 | |||
1104 | |||
1105 | /* models */ | ||
1106 | enum { | ||
1107 | AD1986A_AUTO, | ||
1108 | AD1986A_6STACK, | ||
1109 | AD1986A_3STACK, | ||
1110 | AD1986A_LAPTOP, | ||
1111 | AD1986A_LAPTOP_EAPD, | ||
1112 | AD1986A_LAPTOP_AUTOMUTE, | ||
1113 | AD1986A_ULTRA, | ||
1114 | AD1986A_SAMSUNG, | ||
1115 | AD1986A_SAMSUNG_P50, | ||
1116 | AD1986A_MODELS | ||
1117 | }; | ||
1118 | |||
1119 | static const char * const ad1986a_models[AD1986A_MODELS] = { | ||
1120 | [AD1986A_AUTO] = "auto", | ||
1121 | [AD1986A_6STACK] = "6stack", | ||
1122 | [AD1986A_3STACK] = "3stack", | ||
1123 | [AD1986A_LAPTOP] = "laptop", | ||
1124 | [AD1986A_LAPTOP_EAPD] = "laptop-eapd", | ||
1125 | [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute", | ||
1126 | [AD1986A_ULTRA] = "ultra", | ||
1127 | [AD1986A_SAMSUNG] = "samsung", | ||
1128 | [AD1986A_SAMSUNG_P50] = "samsung-p50", | ||
1129 | }; | ||
1130 | |||
1131 | static const struct snd_pci_quirk ad1986a_cfg_tbl[] = { | ||
1132 | SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD), | ||
1133 | SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD), | ||
1134 | SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD), | ||
1135 | SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD), | ||
1136 | SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD), | ||
1137 | SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD), | ||
1138 | SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD), | ||
1139 | SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD), | ||
1140 | SND_PCI_QUIRK(0x1043, 0x1443, "ASUS VX1", AD1986A_LAPTOP), | ||
1141 | SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8J", AD1986A_3STACK), | ||
1142 | SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK), | ||
1143 | SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP), | ||
1144 | SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK), | ||
1145 | SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK), | ||
1146 | SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK), | ||
1147 | SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK), | ||
1148 | SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40-10Q", AD1986A_3STACK), | ||
1149 | SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK), | ||
1150 | SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), | ||
1151 | SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50), | ||
1152 | SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA), | ||
1153 | SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_SAMSUNG), | ||
1154 | SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK), | ||
1155 | SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), | ||
1156 | SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK), | ||
1157 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE), | ||
1158 | SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP), | ||
1159 | {} | ||
1160 | }; | ||
1161 | |||
1162 | #ifdef CONFIG_PM | ||
1163 | static const struct hda_amp_list ad1986a_loopbacks[] = { | ||
1164 | { 0x13, HDA_OUTPUT, 0 }, /* Mic */ | ||
1165 | { 0x14, HDA_OUTPUT, 0 }, /* Phone */ | ||
1166 | { 0x15, HDA_OUTPUT, 0 }, /* CD */ | ||
1167 | { 0x16, HDA_OUTPUT, 0 }, /* Aux */ | ||
1168 | { 0x17, HDA_OUTPUT, 0 }, /* Line */ | ||
1169 | { } /* end */ | ||
1170 | }; | ||
1171 | #endif | ||
1172 | |||
1173 | static int is_jack_available(struct hda_codec *codec, hda_nid_t nid) | ||
1174 | { | ||
1175 | unsigned int conf = snd_hda_codec_get_pincfg(codec, nid); | ||
1176 | return get_defcfg_connect(conf) != AC_JACK_PORT_NONE; | ||
1177 | } | ||
1178 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
1179 | |||
1180 | static int alloc_ad_spec(struct hda_codec *codec) | 202 | static int alloc_ad_spec(struct hda_codec *codec) |
1181 | { | 203 | { |
1182 | struct ad198x_spec *spec; | 204 | struct ad198x_spec *spec; |
@@ -1203,6 +225,11 @@ static void ad_fixup_inv_jack_detect(struct hda_codec *codec, | |||
1203 | 225 | ||
1204 | enum { | 226 | enum { |
1205 | AD1986A_FIXUP_INV_JACK_DETECT, | 227 | AD1986A_FIXUP_INV_JACK_DETECT, |
228 | AD1986A_FIXUP_ULTRA, | ||
229 | AD1986A_FIXUP_SAMSUNG, | ||
230 | AD1986A_FIXUP_3STACK, | ||
231 | AD1986A_FIXUP_LAPTOP, | ||
232 | AD1986A_FIXUP_LAPTOP_IMIC, | ||
1206 | }; | 233 | }; |
1207 | 234 | ||
1208 | static const struct hda_fixup ad1986a_fixups[] = { | 235 | static const struct hda_fixup ad1986a_fixups[] = { |
@@ -1210,16 +237,86 @@ static const struct hda_fixup ad1986a_fixups[] = { | |||
1210 | .type = HDA_FIXUP_FUNC, | 237 | .type = HDA_FIXUP_FUNC, |
1211 | .v.func = ad_fixup_inv_jack_detect, | 238 | .v.func = ad_fixup_inv_jack_detect, |
1212 | }, | 239 | }, |
240 | [AD1986A_FIXUP_ULTRA] = { | ||
241 | .type = HDA_FIXUP_PINS, | ||
242 | .v.pins = (const struct hda_pintbl[]) { | ||
243 | { 0x1b, 0x90170110 }, /* speaker */ | ||
244 | { 0x1d, 0x90a7013e }, /* int mic */ | ||
245 | {} | ||
246 | }, | ||
247 | }, | ||
248 | [AD1986A_FIXUP_SAMSUNG] = { | ||
249 | .type = HDA_FIXUP_PINS, | ||
250 | .v.pins = (const struct hda_pintbl[]) { | ||
251 | { 0x1b, 0x90170110 }, /* speaker */ | ||
252 | { 0x1d, 0x90a7013e }, /* int mic */ | ||
253 | { 0x20, 0x411111f0 }, /* N/A */ | ||
254 | { 0x24, 0x411111f0 }, /* N/A */ | ||
255 | {} | ||
256 | }, | ||
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 | }, | ||
1213 | }; | 293 | }; |
1214 | 294 | ||
1215 | 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), | ||
301 | SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_FIXUP_SAMSUNG), | ||
302 | SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_FIXUP_ULTRA), | ||
1216 | 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 */ | ||
1217 | {} | 314 | {} |
1218 | }; | 315 | }; |
1219 | 316 | ||
1220 | /* | 317 | /* |
1221 | */ | 318 | */ |
1222 | static int ad1986a_parse_auto_config(struct hda_codec *codec) | 319 | static int patch_ad1986a(struct hda_codec *codec) |
1223 | { | 320 | { |
1224 | int err; | 321 | int err; |
1225 | struct ad198x_spec *spec; | 322 | struct ad198x_spec *spec; |
@@ -1244,7 +341,8 @@ static int ad1986a_parse_auto_config(struct hda_codec *codec) | |||
1244 | */ | 341 | */ |
1245 | spec->gen.multiout.no_share_stream = 1; | 342 | spec->gen.multiout.no_share_stream = 1; |
1246 | 343 | ||
1247 | 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); | ||
1248 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); | 346 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); |
1249 | 347 | ||
1250 | err = ad198x_parse_auto_config(codec); | 348 | err = ad198x_parse_auto_config(codec); |
@@ -1258,330 +356,11 @@ static int ad1986a_parse_auto_config(struct hda_codec *codec) | |||
1258 | return 0; | 356 | return 0; |
1259 | } | 357 | } |
1260 | 358 | ||
1261 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
1262 | static int patch_ad1986a(struct hda_codec *codec) | ||
1263 | { | ||
1264 | struct ad198x_spec *spec; | ||
1265 | int err, board_config; | ||
1266 | |||
1267 | board_config = snd_hda_check_board_config(codec, AD1986A_MODELS, | ||
1268 | ad1986a_models, | ||
1269 | ad1986a_cfg_tbl); | ||
1270 | if (board_config < 0) { | ||
1271 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
1272 | codec->chip_name); | ||
1273 | board_config = AD1986A_AUTO; | ||
1274 | } | ||
1275 | |||
1276 | if (board_config == AD1986A_AUTO) | ||
1277 | return ad1986a_parse_auto_config(codec); | ||
1278 | |||
1279 | err = alloc_ad_spec(codec); | ||
1280 | if (err < 0) | ||
1281 | return err; | ||
1282 | spec = codec->spec; | ||
1283 | |||
1284 | err = snd_hda_attach_beep_device(codec, 0x19); | ||
1285 | if (err < 0) { | ||
1286 | ad198x_free(codec); | ||
1287 | return err; | ||
1288 | } | ||
1289 | set_beep_amp(spec, 0x18, 0, HDA_OUTPUT); | ||
1290 | |||
1291 | spec->multiout.max_channels = 6; | ||
1292 | spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids); | ||
1293 | spec->multiout.dac_nids = ad1986a_dac_nids; | ||
1294 | spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT; | ||
1295 | spec->num_adc_nids = 1; | ||
1296 | spec->adc_nids = ad1986a_adc_nids; | ||
1297 | spec->capsrc_nids = ad1986a_capsrc_nids; | ||
1298 | spec->input_mux = &ad1986a_capture_source; | ||
1299 | spec->num_mixers = 1; | ||
1300 | spec->mixers[0] = ad1986a_mixers; | ||
1301 | spec->num_init_verbs = 1; | ||
1302 | spec->init_verbs[0] = ad1986a_init_verbs; | ||
1303 | #ifdef CONFIG_PM | ||
1304 | spec->loopback.amplist = ad1986a_loopbacks; | ||
1305 | #endif | ||
1306 | spec->vmaster_nid = 0x1b; | ||
1307 | codec->inv_eapd = 1; /* AD1986A has the inverted EAPD implementation */ | ||
1308 | |||
1309 | codec->patch_ops = ad198x_patch_ops; | ||
1310 | |||
1311 | /* override some parameters */ | ||
1312 | switch (board_config) { | ||
1313 | case AD1986A_3STACK: | ||
1314 | spec->num_mixers = 2; | ||
1315 | spec->mixers[1] = ad1986a_3st_mixers; | ||
1316 | spec->num_init_verbs = 2; | ||
1317 | spec->init_verbs[1] = ad1986a_ch2_init; | ||
1318 | spec->channel_mode = ad1986a_modes; | ||
1319 | spec->num_channel_mode = ARRAY_SIZE(ad1986a_modes); | ||
1320 | spec->need_dac_fix = 1; | ||
1321 | spec->multiout.max_channels = 2; | ||
1322 | spec->multiout.num_dacs = 1; | ||
1323 | break; | ||
1324 | case AD1986A_LAPTOP: | ||
1325 | spec->mixers[0] = ad1986a_laptop_mixers; | ||
1326 | spec->multiout.max_channels = 2; | ||
1327 | spec->multiout.num_dacs = 1; | ||
1328 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | ||
1329 | break; | ||
1330 | case AD1986A_LAPTOP_EAPD: | ||
1331 | spec->num_mixers = 3; | ||
1332 | spec->mixers[0] = ad1986a_laptop_master_mixers; | ||
1333 | spec->mixers[1] = ad1986a_laptop_eapd_mixers; | ||
1334 | spec->mixers[2] = ad1986a_laptop_intmic_mixers; | ||
1335 | spec->num_init_verbs = 2; | ||
1336 | spec->init_verbs[1] = ad1986a_eapd_init_verbs; | ||
1337 | spec->multiout.max_channels = 2; | ||
1338 | spec->multiout.num_dacs = 1; | ||
1339 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | ||
1340 | if (!is_jack_available(codec, 0x25)) | ||
1341 | spec->multiout.dig_out_nid = 0; | ||
1342 | spec->input_mux = &ad1986a_laptop_eapd_capture_source; | ||
1343 | break; | ||
1344 | case AD1986A_SAMSUNG: | ||
1345 | spec->num_mixers = 2; | ||
1346 | spec->mixers[0] = ad1986a_laptop_master_mixers; | ||
1347 | spec->mixers[1] = ad1986a_laptop_eapd_mixers; | ||
1348 | spec->num_init_verbs = 3; | ||
1349 | spec->init_verbs[1] = ad1986a_eapd_init_verbs; | ||
1350 | spec->init_verbs[2] = ad1986a_automic_verbs; | ||
1351 | spec->multiout.max_channels = 2; | ||
1352 | spec->multiout.num_dacs = 1; | ||
1353 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | ||
1354 | if (!is_jack_available(codec, 0x25)) | ||
1355 | spec->multiout.dig_out_nid = 0; | ||
1356 | spec->input_mux = &ad1986a_automic_capture_source; | ||
1357 | codec->patch_ops.unsol_event = ad1986a_automic_unsol_event; | ||
1358 | codec->patch_ops.init = ad1986a_automic_init; | ||
1359 | break; | ||
1360 | case AD1986A_SAMSUNG_P50: | ||
1361 | spec->num_mixers = 2; | ||
1362 | spec->mixers[0] = ad1986a_automute_master_mixers; | ||
1363 | spec->mixers[1] = ad1986a_laptop_eapd_mixers; | ||
1364 | spec->num_init_verbs = 4; | ||
1365 | spec->init_verbs[1] = ad1986a_eapd_init_verbs; | ||
1366 | spec->init_verbs[2] = ad1986a_automic_verbs; | ||
1367 | spec->init_verbs[3] = ad1986a_hp_init_verbs; | ||
1368 | spec->multiout.max_channels = 2; | ||
1369 | spec->multiout.num_dacs = 1; | ||
1370 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | ||
1371 | if (!is_jack_available(codec, 0x25)) | ||
1372 | spec->multiout.dig_out_nid = 0; | ||
1373 | spec->input_mux = &ad1986a_automic_capture_source; | ||
1374 | codec->patch_ops.unsol_event = ad1986a_samsung_p50_unsol_event; | ||
1375 | codec->patch_ops.init = ad1986a_samsung_p50_init; | ||
1376 | break; | ||
1377 | case AD1986A_LAPTOP_AUTOMUTE: | ||
1378 | spec->num_mixers = 3; | ||
1379 | spec->mixers[0] = ad1986a_automute_master_mixers; | ||
1380 | spec->mixers[1] = ad1986a_laptop_eapd_mixers; | ||
1381 | spec->mixers[2] = ad1986a_laptop_intmic_mixers; | ||
1382 | spec->num_init_verbs = 3; | ||
1383 | spec->init_verbs[1] = ad1986a_eapd_init_verbs; | ||
1384 | spec->init_verbs[2] = ad1986a_hp_init_verbs; | ||
1385 | spec->multiout.max_channels = 2; | ||
1386 | spec->multiout.num_dacs = 1; | ||
1387 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | ||
1388 | if (!is_jack_available(codec, 0x25)) | ||
1389 | spec->multiout.dig_out_nid = 0; | ||
1390 | spec->input_mux = &ad1986a_laptop_eapd_capture_source; | ||
1391 | codec->patch_ops.unsol_event = ad1986a_hp_unsol_event; | ||
1392 | codec->patch_ops.init = ad1986a_hp_init; | ||
1393 | /* Lenovo N100 seems to report the reversed bit | ||
1394 | * for HP jack-sensing | ||
1395 | */ | ||
1396 | spec->inv_jack_detect = 1; | ||
1397 | break; | ||
1398 | case AD1986A_ULTRA: | ||
1399 | spec->mixers[0] = ad1986a_laptop_eapd_mixers; | ||
1400 | spec->num_init_verbs = 2; | ||
1401 | spec->init_verbs[1] = ad1986a_ultra_init; | ||
1402 | spec->multiout.max_channels = 2; | ||
1403 | spec->multiout.num_dacs = 1; | ||
1404 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | ||
1405 | spec->multiout.dig_out_nid = 0; | ||
1406 | break; | ||
1407 | } | ||
1408 | |||
1409 | /* AD1986A has a hardware problem that it can't share a stream | ||
1410 | * with multiple output pins. The copy of front to surrounds | ||
1411 | * causes noisy or silent outputs at a certain timing, e.g. | ||
1412 | * changing the volume. | ||
1413 | * So, let's disable the shared stream. | ||
1414 | */ | ||
1415 | spec->multiout.no_share_stream = 1; | ||
1416 | |||
1417 | codec->no_trigger_sense = 1; | ||
1418 | codec->no_sticky_stream = 1; | ||
1419 | |||
1420 | return 0; | ||
1421 | } | ||
1422 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
1423 | #define patch_ad1986a ad1986a_parse_auto_config | ||
1424 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
1425 | 359 | ||
1426 | /* | 360 | /* |
1427 | * AD1983 specific | 361 | * AD1983 specific |
1428 | */ | 362 | */ |
1429 | 363 | ||
1430 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
1431 | #define AD1983_SPDIF_OUT 0x02 | ||
1432 | #define AD1983_DAC 0x03 | ||
1433 | #define AD1983_ADC 0x04 | ||
1434 | |||
1435 | static const hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC }; | ||
1436 | static const hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC }; | ||
1437 | static const hda_nid_t ad1983_capsrc_nids[1] = { 0x15 }; | ||
1438 | |||
1439 | static const struct hda_input_mux ad1983_capture_source = { | ||
1440 | .num_items = 4, | ||
1441 | .items = { | ||
1442 | { "Mic", 0x0 }, | ||
1443 | { "Line", 0x1 }, | ||
1444 | { "Mix", 0x2 }, | ||
1445 | { "Mix Mono", 0x3 }, | ||
1446 | }, | ||
1447 | }; | ||
1448 | |||
1449 | /* | ||
1450 | * SPDIF playback route | ||
1451 | */ | ||
1452 | static int ad1983_spdif_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | ||
1453 | { | ||
1454 | static const char * const texts[] = { "PCM", "ADC" }; | ||
1455 | |||
1456 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
1457 | uinfo->count = 1; | ||
1458 | uinfo->value.enumerated.items = 2; | ||
1459 | if (uinfo->value.enumerated.item > 1) | ||
1460 | uinfo->value.enumerated.item = 1; | ||
1461 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
1462 | return 0; | ||
1463 | } | ||
1464 | |||
1465 | static int ad1983_spdif_route_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
1466 | { | ||
1467 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1468 | struct ad198x_spec *spec = codec->spec; | ||
1469 | |||
1470 | ucontrol->value.enumerated.item[0] = spec->spdif_route; | ||
1471 | return 0; | ||
1472 | } | ||
1473 | |||
1474 | static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
1475 | { | ||
1476 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1477 | struct ad198x_spec *spec = codec->spec; | ||
1478 | |||
1479 | if (ucontrol->value.enumerated.item[0] > 1) | ||
1480 | return -EINVAL; | ||
1481 | if (spec->spdif_route != ucontrol->value.enumerated.item[0]) { | ||
1482 | spec->spdif_route = ucontrol->value.enumerated.item[0]; | ||
1483 | snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0, | ||
1484 | AC_VERB_SET_CONNECT_SEL, | ||
1485 | spec->spdif_route); | ||
1486 | return 1; | ||
1487 | } | ||
1488 | return 0; | ||
1489 | } | ||
1490 | |||
1491 | static const struct snd_kcontrol_new ad1983_mixers[] = { | ||
1492 | HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT), | ||
1493 | HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT), | ||
1494 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT), | ||
1495 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT), | ||
1496 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT), | ||
1497 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT), | ||
1498 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), | ||
1499 | HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
1500 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), | ||
1501 | HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
1502 | HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
1503 | HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||
1504 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
1505 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), | ||
1506 | HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), | ||
1507 | { | ||
1508 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1509 | .name = "Capture Source", | ||
1510 | .info = ad198x_mux_enum_info, | ||
1511 | .get = ad198x_mux_enum_get, | ||
1512 | .put = ad198x_mux_enum_put, | ||
1513 | }, | ||
1514 | { | ||
1515 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1516 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
1517 | .info = ad1983_spdif_route_info, | ||
1518 | .get = ad1983_spdif_route_get, | ||
1519 | .put = ad1983_spdif_route_put, | ||
1520 | }, | ||
1521 | { } /* end */ | ||
1522 | }; | ||
1523 | |||
1524 | static const struct hda_verb ad1983_init_verbs[] = { | ||
1525 | /* Front, HP, Mono; mute as default */ | ||
1526 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1527 | {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1528 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1529 | /* Beep, PCM, Mic, Line-In: mute */ | ||
1530 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1531 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1532 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1533 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1534 | /* Front, HP selectors; from Mix */ | ||
1535 | {0x05, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
1536 | {0x06, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
1537 | /* Mono selector; from Mix */ | ||
1538 | {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03}, | ||
1539 | /* Mic selector; Mic */ | ||
1540 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1541 | /* Line-in selector: Line-in */ | ||
1542 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1543 | /* Mic boost: 0dB */ | ||
1544 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
1545 | /* Record selector: mic */ | ||
1546 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1547 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1548 | /* SPDIF route: PCM */ | ||
1549 | {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1550 | /* Front Pin */ | ||
1551 | {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
1552 | /* HP Pin */ | ||
1553 | {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | ||
1554 | /* Mono Pin */ | ||
1555 | {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
1556 | /* Mic Pin */ | ||
1557 | {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
1558 | /* Line Pin */ | ||
1559 | {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
1560 | { } /* end */ | ||
1561 | }; | ||
1562 | |||
1563 | #ifdef CONFIG_PM | ||
1564 | static const struct hda_amp_list ad1983_loopbacks[] = { | ||
1565 | { 0x12, HDA_OUTPUT, 0 }, /* Mic */ | ||
1566 | { 0x13, HDA_OUTPUT, 0 }, /* Line */ | ||
1567 | { } /* end */ | ||
1568 | }; | ||
1569 | #endif | ||
1570 | |||
1571 | /* models */ | ||
1572 | enum { | ||
1573 | AD1983_AUTO, | ||
1574 | AD1983_BASIC, | ||
1575 | AD1983_MODELS | ||
1576 | }; | ||
1577 | |||
1578 | static const char * const ad1983_models[AD1983_MODELS] = { | ||
1579 | [AD1983_AUTO] = "auto", | ||
1580 | [AD1983_BASIC] = "basic", | ||
1581 | }; | ||
1582 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
1583 | |||
1584 | |||
1585 | /* | 364 | /* |
1586 | * SPDIF mux control for AD1983 auto-parser | 365 | * SPDIF mux control for AD1983 auto-parser |
1587 | */ | 366 | */ |
@@ -1656,7 +435,7 @@ static int ad1983_add_spdif_mux_ctl(struct hda_codec *codec) | |||
1656 | return 0; | 435 | return 0; |
1657 | } | 436 | } |
1658 | 437 | ||
1659 | static int ad1983_parse_auto_config(struct hda_codec *codec) | 438 | static int patch_ad1983(struct hda_codec *codec) |
1660 | { | 439 | { |
1661 | struct ad198x_spec *spec; | 440 | struct ad198x_spec *spec; |
1662 | int err; | 441 | int err; |
@@ -1681,432 +460,11 @@ static int ad1983_parse_auto_config(struct hda_codec *codec) | |||
1681 | return err; | 460 | return err; |
1682 | } | 461 | } |
1683 | 462 | ||
1684 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
1685 | static int patch_ad1983(struct hda_codec *codec) | ||
1686 | { | ||
1687 | struct ad198x_spec *spec; | ||
1688 | int board_config; | ||
1689 | int err; | ||
1690 | |||
1691 | board_config = snd_hda_check_board_config(codec, AD1983_MODELS, | ||
1692 | ad1983_models, NULL); | ||
1693 | if (board_config < 0) { | ||
1694 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
1695 | codec->chip_name); | ||
1696 | board_config = AD1983_AUTO; | ||
1697 | } | ||
1698 | |||
1699 | if (board_config == AD1983_AUTO) | ||
1700 | return ad1983_parse_auto_config(codec); | ||
1701 | |||
1702 | err = alloc_ad_spec(codec); | ||
1703 | if (err < 0) | ||
1704 | return err; | ||
1705 | spec = codec->spec; | ||
1706 | |||
1707 | err = snd_hda_attach_beep_device(codec, 0x10); | ||
1708 | if (err < 0) { | ||
1709 | ad198x_free(codec); | ||
1710 | return err; | ||
1711 | } | ||
1712 | set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); | ||
1713 | |||
1714 | spec->multiout.max_channels = 2; | ||
1715 | spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids); | ||
1716 | spec->multiout.dac_nids = ad1983_dac_nids; | ||
1717 | spec->multiout.dig_out_nid = AD1983_SPDIF_OUT; | ||
1718 | spec->num_adc_nids = 1; | ||
1719 | spec->adc_nids = ad1983_adc_nids; | ||
1720 | spec->capsrc_nids = ad1983_capsrc_nids; | ||
1721 | spec->input_mux = &ad1983_capture_source; | ||
1722 | spec->num_mixers = 1; | ||
1723 | spec->mixers[0] = ad1983_mixers; | ||
1724 | spec->num_init_verbs = 1; | ||
1725 | spec->init_verbs[0] = ad1983_init_verbs; | ||
1726 | spec->spdif_route = 0; | ||
1727 | #ifdef CONFIG_PM | ||
1728 | spec->loopback.amplist = ad1983_loopbacks; | ||
1729 | #endif | ||
1730 | spec->vmaster_nid = 0x05; | ||
1731 | |||
1732 | codec->patch_ops = ad198x_patch_ops; | ||
1733 | |||
1734 | codec->no_trigger_sense = 1; | ||
1735 | codec->no_sticky_stream = 1; | ||
1736 | |||
1737 | return 0; | ||
1738 | } | ||
1739 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
1740 | #define patch_ad1983 ad1983_parse_auto_config | ||
1741 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
1742 | |||
1743 | 463 | ||
1744 | /* | 464 | /* |
1745 | * AD1981 HD specific | 465 | * AD1981 HD specific |
1746 | */ | 466 | */ |
1747 | 467 | ||
1748 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
1749 | #define AD1981_SPDIF_OUT 0x02 | ||
1750 | #define AD1981_DAC 0x03 | ||
1751 | #define AD1981_ADC 0x04 | ||
1752 | |||
1753 | static const hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC }; | ||
1754 | static const hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC }; | ||
1755 | static const hda_nid_t ad1981_capsrc_nids[1] = { 0x15 }; | ||
1756 | |||
1757 | /* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */ | ||
1758 | static const struct hda_input_mux ad1981_capture_source = { | ||
1759 | .num_items = 7, | ||
1760 | .items = { | ||
1761 | { "Front Mic", 0x0 }, | ||
1762 | { "Line", 0x1 }, | ||
1763 | { "Mix", 0x2 }, | ||
1764 | { "Mix Mono", 0x3 }, | ||
1765 | { "CD", 0x4 }, | ||
1766 | { "Mic", 0x6 }, | ||
1767 | { "Aux", 0x7 }, | ||
1768 | }, | ||
1769 | }; | ||
1770 | |||
1771 | static const struct snd_kcontrol_new ad1981_mixers[] = { | ||
1772 | HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT), | ||
1773 | HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT), | ||
1774 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT), | ||
1775 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT), | ||
1776 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT), | ||
1777 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT), | ||
1778 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), | ||
1779 | HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
1780 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), | ||
1781 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
1782 | HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
1783 | HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||
1784 | HDA_CODEC_VOLUME("Aux Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
1785 | HDA_CODEC_MUTE("Aux Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
1786 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT), | ||
1787 | HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT), | ||
1788 | HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), | ||
1789 | HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), | ||
1790 | HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x08, 0x0, HDA_INPUT), | ||
1791 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x0, HDA_INPUT), | ||
1792 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), | ||
1793 | HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), | ||
1794 | { | ||
1795 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1796 | .name = "Capture Source", | ||
1797 | .info = ad198x_mux_enum_info, | ||
1798 | .get = ad198x_mux_enum_get, | ||
1799 | .put = ad198x_mux_enum_put, | ||
1800 | }, | ||
1801 | /* identical with AD1983 */ | ||
1802 | { | ||
1803 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1804 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
1805 | .info = ad1983_spdif_route_info, | ||
1806 | .get = ad1983_spdif_route_get, | ||
1807 | .put = ad1983_spdif_route_put, | ||
1808 | }, | ||
1809 | { } /* end */ | ||
1810 | }; | ||
1811 | |||
1812 | static const struct hda_verb ad1981_init_verbs[] = { | ||
1813 | /* Front, HP, Mono; mute as default */ | ||
1814 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1815 | {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1816 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1817 | /* Beep, PCM, Front Mic, Line, Rear Mic, Aux, CD-In: mute */ | ||
1818 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1819 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1820 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1821 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1822 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1823 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1824 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1825 | /* Front, HP selectors; from Mix */ | ||
1826 | {0x05, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
1827 | {0x06, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
1828 | /* Mono selector; from Mix */ | ||
1829 | {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03}, | ||
1830 | /* Mic Mixer; select Front Mic */ | ||
1831 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
1832 | {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1833 | /* Mic boost: 0dB */ | ||
1834 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
1835 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
1836 | /* Record selector: Front mic */ | ||
1837 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1838 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1839 | /* SPDIF route: PCM */ | ||
1840 | {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1841 | /* Front Pin */ | ||
1842 | {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
1843 | /* HP Pin */ | ||
1844 | {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | ||
1845 | /* Mono Pin */ | ||
1846 | {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
1847 | /* Front & Rear Mic Pins */ | ||
1848 | {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
1849 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
1850 | /* Line Pin */ | ||
1851 | {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
1852 | /* Digital Beep */ | ||
1853 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
1854 | /* Line-Out as Input: disabled */ | ||
1855 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1856 | { } /* end */ | ||
1857 | }; | ||
1858 | |||
1859 | #ifdef CONFIG_PM | ||
1860 | static const struct hda_amp_list ad1981_loopbacks[] = { | ||
1861 | { 0x12, HDA_OUTPUT, 0 }, /* Front Mic */ | ||
1862 | { 0x13, HDA_OUTPUT, 0 }, /* Line */ | ||
1863 | { 0x1b, HDA_OUTPUT, 0 }, /* Aux */ | ||
1864 | { 0x1c, HDA_OUTPUT, 0 }, /* Mic */ | ||
1865 | { 0x1d, HDA_OUTPUT, 0 }, /* CD */ | ||
1866 | { } /* end */ | ||
1867 | }; | ||
1868 | #endif | ||
1869 | |||
1870 | /* | ||
1871 | * Patch for HP nx6320 | ||
1872 | * | ||
1873 | * nx6320 uses EAPD in the reverse way - EAPD-on means the internal | ||
1874 | * speaker output enabled _and_ mute-LED off. | ||
1875 | */ | ||
1876 | |||
1877 | #define AD1981_HP_EVENT 0x37 | ||
1878 | #define AD1981_MIC_EVENT 0x38 | ||
1879 | |||
1880 | static const struct hda_verb ad1981_hp_init_verbs[] = { | ||
1881 | {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* default off */ | ||
1882 | /* pin sensing on HP and Mic jacks */ | ||
1883 | {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT}, | ||
1884 | {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT}, | ||
1885 | {} | ||
1886 | }; | ||
1887 | |||
1888 | /* turn on/off EAPD (+ mute HP) as a master switch */ | ||
1889 | static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol, | ||
1890 | struct snd_ctl_elem_value *ucontrol) | ||
1891 | { | ||
1892 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1893 | struct ad198x_spec *spec = codec->spec; | ||
1894 | |||
1895 | if (! ad198x_eapd_put(kcontrol, ucontrol)) | ||
1896 | return 0; | ||
1897 | /* change speaker pin appropriately */ | ||
1898 | snd_hda_set_pin_ctl(codec, 0x05, spec->cur_eapd ? PIN_OUT : 0); | ||
1899 | /* toggle HP mute appropriately */ | ||
1900 | snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0, | ||
1901 | HDA_AMP_MUTE, | ||
1902 | spec->cur_eapd ? 0 : HDA_AMP_MUTE); | ||
1903 | return 1; | ||
1904 | } | ||
1905 | |||
1906 | /* bind volumes of both NID 0x05 and 0x06 */ | ||
1907 | static const struct hda_bind_ctls ad1981_hp_bind_master_vol = { | ||
1908 | .ops = &snd_hda_bind_vol, | ||
1909 | .values = { | ||
1910 | HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), | ||
1911 | HDA_COMPOSE_AMP_VAL(0x06, 3, 0, HDA_OUTPUT), | ||
1912 | 0 | ||
1913 | }, | ||
1914 | }; | ||
1915 | |||
1916 | /* mute internal speaker if HP is plugged */ | ||
1917 | static void ad1981_hp_automute(struct hda_codec *codec) | ||
1918 | { | ||
1919 | unsigned int present; | ||
1920 | |||
1921 | present = snd_hda_jack_detect(codec, 0x06); | ||
1922 | snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0, | ||
1923 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
1924 | } | ||
1925 | |||
1926 | /* toggle input of built-in and mic jack appropriately */ | ||
1927 | static void ad1981_hp_automic(struct hda_codec *codec) | ||
1928 | { | ||
1929 | static const struct hda_verb mic_jack_on[] = { | ||
1930 | {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1931 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
1932 | {} | ||
1933 | }; | ||
1934 | static const struct hda_verb mic_jack_off[] = { | ||
1935 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1936 | {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
1937 | {} | ||
1938 | }; | ||
1939 | unsigned int present; | ||
1940 | |||
1941 | present = snd_hda_jack_detect(codec, 0x08); | ||
1942 | if (present) | ||
1943 | snd_hda_sequence_write(codec, mic_jack_on); | ||
1944 | else | ||
1945 | snd_hda_sequence_write(codec, mic_jack_off); | ||
1946 | } | ||
1947 | |||
1948 | /* unsolicited event for HP jack sensing */ | ||
1949 | static void ad1981_hp_unsol_event(struct hda_codec *codec, | ||
1950 | unsigned int res) | ||
1951 | { | ||
1952 | res >>= 26; | ||
1953 | switch (res) { | ||
1954 | case AD1981_HP_EVENT: | ||
1955 | ad1981_hp_automute(codec); | ||
1956 | break; | ||
1957 | case AD1981_MIC_EVENT: | ||
1958 | ad1981_hp_automic(codec); | ||
1959 | break; | ||
1960 | } | ||
1961 | } | ||
1962 | |||
1963 | static const struct hda_input_mux ad1981_hp_capture_source = { | ||
1964 | .num_items = 3, | ||
1965 | .items = { | ||
1966 | { "Mic", 0x0 }, | ||
1967 | { "Dock Mic", 0x1 }, | ||
1968 | { "Mix", 0x2 }, | ||
1969 | }, | ||
1970 | }; | ||
1971 | |||
1972 | static const struct snd_kcontrol_new ad1981_hp_mixers[] = { | ||
1973 | HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol), | ||
1974 | { | ||
1975 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1976 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x05, | ||
1977 | .name = "Master Playback Switch", | ||
1978 | .info = ad198x_eapd_info, | ||
1979 | .get = ad198x_eapd_get, | ||
1980 | .put = ad1981_hp_master_sw_put, | ||
1981 | .private_value = 0x05, | ||
1982 | }, | ||
1983 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), | ||
1984 | HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
1985 | #if 0 | ||
1986 | /* FIXME: analog mic/line loopback doesn't work with my tests... | ||
1987 | * (although recording is OK) | ||
1988 | */ | ||
1989 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), | ||
1990 | HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
1991 | HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
1992 | HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||
1993 | HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT), | ||
1994 | HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT), | ||
1995 | /* FIXME: does this laptop have analog CD connection? */ | ||
1996 | HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), | ||
1997 | HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), | ||
1998 | #endif | ||
1999 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT), | ||
2000 | HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x18, 0x0, HDA_INPUT), | ||
2001 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), | ||
2002 | HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), | ||
2003 | { | ||
2004 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2005 | .name = "Capture Source", | ||
2006 | .info = ad198x_mux_enum_info, | ||
2007 | .get = ad198x_mux_enum_get, | ||
2008 | .put = ad198x_mux_enum_put, | ||
2009 | }, | ||
2010 | { } /* end */ | ||
2011 | }; | ||
2012 | |||
2013 | /* initialize jack-sensing, too */ | ||
2014 | static int ad1981_hp_init(struct hda_codec *codec) | ||
2015 | { | ||
2016 | ad198x_init(codec); | ||
2017 | ad1981_hp_automute(codec); | ||
2018 | ad1981_hp_automic(codec); | ||
2019 | return 0; | ||
2020 | } | ||
2021 | |||
2022 | /* configuration for Toshiba Laptops */ | ||
2023 | static const struct hda_verb ad1981_toshiba_init_verbs[] = { | ||
2024 | {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x01 }, /* default on */ | ||
2025 | /* pin sensing on HP and Mic jacks */ | ||
2026 | {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT}, | ||
2027 | {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT}, | ||
2028 | {} | ||
2029 | }; | ||
2030 | |||
2031 | static const struct snd_kcontrol_new ad1981_toshiba_mixers[] = { | ||
2032 | HDA_CODEC_VOLUME("Amp Volume", 0x1a, 0x0, HDA_OUTPUT), | ||
2033 | HDA_CODEC_MUTE("Amp Switch", 0x1a, 0x0, HDA_OUTPUT), | ||
2034 | { } | ||
2035 | }; | ||
2036 | |||
2037 | /* configuration for Lenovo Thinkpad T60 */ | ||
2038 | static const struct snd_kcontrol_new ad1981_thinkpad_mixers[] = { | ||
2039 | HDA_CODEC_VOLUME("Master Playback Volume", 0x05, 0x0, HDA_OUTPUT), | ||
2040 | HDA_CODEC_MUTE("Master Playback Switch", 0x05, 0x0, HDA_OUTPUT), | ||
2041 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), | ||
2042 | HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
2043 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), | ||
2044 | HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
2045 | HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), | ||
2046 | HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), | ||
2047 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT), | ||
2048 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), | ||
2049 | HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), | ||
2050 | { | ||
2051 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2052 | .name = "Capture Source", | ||
2053 | .info = ad198x_mux_enum_info, | ||
2054 | .get = ad198x_mux_enum_get, | ||
2055 | .put = ad198x_mux_enum_put, | ||
2056 | }, | ||
2057 | /* identical with AD1983 */ | ||
2058 | { | ||
2059 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2060 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
2061 | .info = ad1983_spdif_route_info, | ||
2062 | .get = ad1983_spdif_route_get, | ||
2063 | .put = ad1983_spdif_route_put, | ||
2064 | }, | ||
2065 | { } /* end */ | ||
2066 | }; | ||
2067 | |||
2068 | static const struct hda_input_mux ad1981_thinkpad_capture_source = { | ||
2069 | .num_items = 3, | ||
2070 | .items = { | ||
2071 | { "Mic", 0x0 }, | ||
2072 | { "Mix", 0x2 }, | ||
2073 | { "CD", 0x4 }, | ||
2074 | }, | ||
2075 | }; | ||
2076 | |||
2077 | /* models */ | ||
2078 | enum { | ||
2079 | AD1981_AUTO, | ||
2080 | AD1981_BASIC, | ||
2081 | AD1981_HP, | ||
2082 | AD1981_THINKPAD, | ||
2083 | AD1981_TOSHIBA, | ||
2084 | AD1981_MODELS | ||
2085 | }; | ||
2086 | |||
2087 | static const char * const ad1981_models[AD1981_MODELS] = { | ||
2088 | [AD1981_AUTO] = "auto", | ||
2089 | [AD1981_HP] = "hp", | ||
2090 | [AD1981_THINKPAD] = "thinkpad", | ||
2091 | [AD1981_BASIC] = "basic", | ||
2092 | [AD1981_TOSHIBA] = "toshiba" | ||
2093 | }; | ||
2094 | |||
2095 | static const struct snd_pci_quirk ad1981_cfg_tbl[] = { | ||
2096 | SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD), | ||
2097 | SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD), | ||
2098 | /* All HP models */ | ||
2099 | SND_PCI_QUIRK_VENDOR(0x103c, "HP nx", AD1981_HP), | ||
2100 | SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA), | ||
2101 | /* Lenovo Thinkpad T60/X60/Z6xx */ | ||
2102 | SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1981_THINKPAD), | ||
2103 | /* HP nx6320 (reversed SSID, H/W bug) */ | ||
2104 | SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP), | ||
2105 | {} | ||
2106 | }; | ||
2107 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
2108 | |||
2109 | |||
2110 | /* follow EAPD via vmaster hook */ | 468 | /* follow EAPD via vmaster hook */ |
2111 | static void ad_vmaster_eapd_hook(void *private_data, int enabled) | 469 | static void ad_vmaster_eapd_hook(void *private_data, int enabled) |
2112 | { | 470 | { |
@@ -2172,7 +530,7 @@ static const struct snd_pci_quirk ad1981_fixup_tbl[] = { | |||
2172 | {} | 530 | {} |
2173 | }; | 531 | }; |
2174 | 532 | ||
2175 | static int ad1981_parse_auto_config(struct hda_codec *codec) | 533 | static int patch_ad1981(struct hda_codec *codec) |
2176 | { | 534 | { |
2177 | struct ad198x_spec *spec; | 535 | struct ad198x_spec *spec; |
2178 | int err; | 536 | int err; |
@@ -2205,110 +563,6 @@ static int ad1981_parse_auto_config(struct hda_codec *codec) | |||
2205 | return err; | 563 | return err; |
2206 | } | 564 | } |
2207 | 565 | ||
2208 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
2209 | static int patch_ad1981(struct hda_codec *codec) | ||
2210 | { | ||
2211 | struct ad198x_spec *spec; | ||
2212 | int err, board_config; | ||
2213 | |||
2214 | board_config = snd_hda_check_board_config(codec, AD1981_MODELS, | ||
2215 | ad1981_models, | ||
2216 | ad1981_cfg_tbl); | ||
2217 | if (board_config < 0) { | ||
2218 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
2219 | codec->chip_name); | ||
2220 | board_config = AD1981_AUTO; | ||
2221 | } | ||
2222 | |||
2223 | if (board_config == AD1981_AUTO) | ||
2224 | return ad1981_parse_auto_config(codec); | ||
2225 | |||
2226 | err = alloc_ad_spec(codec); | ||
2227 | if (err < 0) | ||
2228 | return -ENOMEM; | ||
2229 | spec = codec->spec; | ||
2230 | |||
2231 | err = snd_hda_attach_beep_device(codec, 0x10); | ||
2232 | if (err < 0) { | ||
2233 | ad198x_free(codec); | ||
2234 | return err; | ||
2235 | } | ||
2236 | set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT); | ||
2237 | |||
2238 | spec->multiout.max_channels = 2; | ||
2239 | spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids); | ||
2240 | spec->multiout.dac_nids = ad1981_dac_nids; | ||
2241 | spec->multiout.dig_out_nid = AD1981_SPDIF_OUT; | ||
2242 | spec->num_adc_nids = 1; | ||
2243 | spec->adc_nids = ad1981_adc_nids; | ||
2244 | spec->capsrc_nids = ad1981_capsrc_nids; | ||
2245 | spec->input_mux = &ad1981_capture_source; | ||
2246 | spec->num_mixers = 1; | ||
2247 | spec->mixers[0] = ad1981_mixers; | ||
2248 | spec->num_init_verbs = 1; | ||
2249 | spec->init_verbs[0] = ad1981_init_verbs; | ||
2250 | spec->spdif_route = 0; | ||
2251 | #ifdef CONFIG_PM | ||
2252 | spec->loopback.amplist = ad1981_loopbacks; | ||
2253 | #endif | ||
2254 | spec->vmaster_nid = 0x05; | ||
2255 | |||
2256 | codec->patch_ops = ad198x_patch_ops; | ||
2257 | |||
2258 | /* override some parameters */ | ||
2259 | switch (board_config) { | ||
2260 | case AD1981_HP: | ||
2261 | spec->mixers[0] = ad1981_hp_mixers; | ||
2262 | spec->num_init_verbs = 2; | ||
2263 | spec->init_verbs[1] = ad1981_hp_init_verbs; | ||
2264 | if (!is_jack_available(codec, 0x0a)) | ||
2265 | spec->multiout.dig_out_nid = 0; | ||
2266 | spec->input_mux = &ad1981_hp_capture_source; | ||
2267 | |||
2268 | codec->patch_ops.init = ad1981_hp_init; | ||
2269 | codec->patch_ops.unsol_event = ad1981_hp_unsol_event; | ||
2270 | /* set the upper-limit for mixer amp to 0dB for avoiding the | ||
2271 | * possible damage by overloading | ||
2272 | */ | ||
2273 | snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT, | ||
2274 | (0x17 << AC_AMPCAP_OFFSET_SHIFT) | | ||
2275 | (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||
2276 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
2277 | (1 << AC_AMPCAP_MUTE_SHIFT)); | ||
2278 | break; | ||
2279 | case AD1981_THINKPAD: | ||
2280 | spec->mixers[0] = ad1981_thinkpad_mixers; | ||
2281 | spec->input_mux = &ad1981_thinkpad_capture_source; | ||
2282 | /* set the upper-limit for mixer amp to 0dB for avoiding the | ||
2283 | * possible damage by overloading | ||
2284 | */ | ||
2285 | snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT, | ||
2286 | (0x17 << AC_AMPCAP_OFFSET_SHIFT) | | ||
2287 | (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||
2288 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
2289 | (1 << AC_AMPCAP_MUTE_SHIFT)); | ||
2290 | break; | ||
2291 | case AD1981_TOSHIBA: | ||
2292 | spec->mixers[0] = ad1981_hp_mixers; | ||
2293 | spec->mixers[1] = ad1981_toshiba_mixers; | ||
2294 | spec->num_init_verbs = 2; | ||
2295 | spec->init_verbs[1] = ad1981_toshiba_init_verbs; | ||
2296 | spec->multiout.dig_out_nid = 0; | ||
2297 | spec->input_mux = &ad1981_hp_capture_source; | ||
2298 | codec->patch_ops.init = ad1981_hp_init; | ||
2299 | codec->patch_ops.unsol_event = ad1981_hp_unsol_event; | ||
2300 | break; | ||
2301 | } | ||
2302 | |||
2303 | codec->no_trigger_sense = 1; | ||
2304 | codec->no_sticky_stream = 1; | ||
2305 | |||
2306 | return 0; | ||
2307 | } | ||
2308 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
2309 | #define patch_ad1981 ad1981_parse_auto_config | ||
2310 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
2311 | |||
2312 | 566 | ||
2313 | /* | 567 | /* |
2314 | * AD1988 | 568 | * AD1988 |
@@ -2395,90 +649,7 @@ static int patch_ad1981(struct hda_codec *codec) | |||
2395 | * E/F quad mic array | 649 | * E/F quad mic array |
2396 | */ | 650 | */ |
2397 | 651 | ||
2398 | |||
2399 | #ifdef ENABLE_AD_STATIC_QUIRKS | 652 | #ifdef ENABLE_AD_STATIC_QUIRKS |
2400 | /* models */ | ||
2401 | enum { | ||
2402 | AD1988_AUTO, | ||
2403 | AD1988_6STACK, | ||
2404 | AD1988_6STACK_DIG, | ||
2405 | AD1988_3STACK, | ||
2406 | AD1988_3STACK_DIG, | ||
2407 | AD1988_LAPTOP, | ||
2408 | AD1988_LAPTOP_DIG, | ||
2409 | AD1988_MODEL_LAST, | ||
2410 | }; | ||
2411 | |||
2412 | /* reivision id to check workarounds */ | ||
2413 | #define AD1988A_REV2 0x100200 | ||
2414 | |||
2415 | #define is_rev2(codec) \ | ||
2416 | ((codec)->vendor_id == 0x11d41988 && \ | ||
2417 | (codec)->revision_id == AD1988A_REV2) | ||
2418 | |||
2419 | /* | ||
2420 | * mixers | ||
2421 | */ | ||
2422 | |||
2423 | static const hda_nid_t ad1988_6stack_dac_nids[4] = { | ||
2424 | 0x04, 0x06, 0x05, 0x0a | ||
2425 | }; | ||
2426 | |||
2427 | static const hda_nid_t ad1988_3stack_dac_nids[3] = { | ||
2428 | 0x04, 0x05, 0x0a | ||
2429 | }; | ||
2430 | |||
2431 | /* for AD1988A revision-2, DAC2-4 are swapped */ | ||
2432 | static const hda_nid_t ad1988_6stack_dac_nids_rev2[4] = { | ||
2433 | 0x04, 0x05, 0x0a, 0x06 | ||
2434 | }; | ||
2435 | |||
2436 | static const hda_nid_t ad1988_alt_dac_nid[1] = { | ||
2437 | 0x03 | ||
2438 | }; | ||
2439 | |||
2440 | static const hda_nid_t ad1988_3stack_dac_nids_rev2[3] = { | ||
2441 | 0x04, 0x0a, 0x06 | ||
2442 | }; | ||
2443 | |||
2444 | static const hda_nid_t ad1988_adc_nids[3] = { | ||
2445 | 0x08, 0x09, 0x0f | ||
2446 | }; | ||
2447 | |||
2448 | static const hda_nid_t ad1988_capsrc_nids[3] = { | ||
2449 | 0x0c, 0x0d, 0x0e | ||
2450 | }; | ||
2451 | |||
2452 | #define AD1988_SPDIF_OUT 0x02 | ||
2453 | #define AD1988_SPDIF_OUT_HDMI 0x0b | ||
2454 | #define AD1988_SPDIF_IN 0x07 | ||
2455 | |||
2456 | static const hda_nid_t ad1989b_slave_dig_outs[] = { | ||
2457 | AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI, 0 | ||
2458 | }; | ||
2459 | |||
2460 | static const struct hda_input_mux ad1988_6stack_capture_source = { | ||
2461 | .num_items = 5, | ||
2462 | .items = { | ||
2463 | { "Front Mic", 0x1 }, /* port-B */ | ||
2464 | { "Line", 0x2 }, /* port-C */ | ||
2465 | { "Mic", 0x4 }, /* port-E */ | ||
2466 | { "CD", 0x5 }, | ||
2467 | { "Mix", 0x9 }, | ||
2468 | }, | ||
2469 | }; | ||
2470 | |||
2471 | static const struct hda_input_mux ad1988_laptop_capture_source = { | ||
2472 | .num_items = 3, | ||
2473 | .items = { | ||
2474 | { "Mic/Line", 0x1 }, /* port-B */ | ||
2475 | { "CD", 0x5 }, | ||
2476 | { "Mix", 0x9 }, | ||
2477 | }, | ||
2478 | }; | ||
2479 | |||
2480 | /* | ||
2481 | */ | ||
2482 | static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol, | 653 | static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol, |
2483 | struct snd_ctl_elem_info *uinfo) | 654 | struct snd_ctl_elem_info *uinfo) |
2484 | { | 655 | { |
@@ -2509,569 +680,6 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, | |||
2509 | spec->multiout.num_dacs = spec->multiout.max_channels / 2; | 680 | spec->multiout.num_dacs = spec->multiout.max_channels / 2; |
2510 | return err; | 681 | return err; |
2511 | } | 682 | } |
2512 | |||
2513 | /* 6-stack mode */ | ||
2514 | static const struct snd_kcontrol_new ad1988_6stack_mixers1[] = { | ||
2515 | HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
2516 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT), | ||
2517 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT), | ||
2518 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT), | ||
2519 | HDA_CODEC_VOLUME("Side Playback Volume", 0x0a, 0x0, HDA_OUTPUT), | ||
2520 | { } /* end */ | ||
2521 | }; | ||
2522 | |||
2523 | static const struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = { | ||
2524 | HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
2525 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x05, 0x0, HDA_OUTPUT), | ||
2526 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), | ||
2527 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0a, 2, 0x0, HDA_OUTPUT), | ||
2528 | HDA_CODEC_VOLUME("Side Playback Volume", 0x06, 0x0, HDA_OUTPUT), | ||
2529 | { } /* end */ | ||
2530 | }; | ||
2531 | |||
2532 | static const struct snd_kcontrol_new ad1988_6stack_mixers2[] = { | ||
2533 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
2534 | HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT), | ||
2535 | HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT), | ||
2536 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT), | ||
2537 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT), | ||
2538 | HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT), | ||
2539 | HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT), | ||
2540 | HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), | ||
2541 | |||
2542 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT), | ||
2543 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT), | ||
2544 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT), | ||
2545 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT), | ||
2546 | HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT), | ||
2547 | HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT), | ||
2548 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT), | ||
2549 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT), | ||
2550 | |||
2551 | HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
2552 | HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
2553 | |||
2554 | HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), | ||
2555 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT), | ||
2556 | { } /* end */ | ||
2557 | }; | ||
2558 | |||
2559 | /* 3-stack mode */ | ||
2560 | static const struct snd_kcontrol_new ad1988_3stack_mixers1[] = { | ||
2561 | HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
2562 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT), | ||
2563 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT), | ||
2564 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT), | ||
2565 | { } /* end */ | ||
2566 | }; | ||
2567 | |||
2568 | static const struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = { | ||
2569 | HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
2570 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT), | ||
2571 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x06, 1, 0x0, HDA_OUTPUT), | ||
2572 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x06, 2, 0x0, HDA_OUTPUT), | ||
2573 | { } /* end */ | ||
2574 | }; | ||
2575 | |||
2576 | static const struct snd_kcontrol_new ad1988_3stack_mixers2[] = { | ||
2577 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
2578 | HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT), | ||
2579 | HDA_BIND_MUTE("Surround Playback Switch", 0x2c, 2, HDA_INPUT), | ||
2580 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x26, 1, 2, HDA_INPUT), | ||
2581 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x26, 2, 2, HDA_INPUT), | ||
2582 | HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT), | ||
2583 | HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), | ||
2584 | |||
2585 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT), | ||
2586 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT), | ||
2587 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT), | ||
2588 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT), | ||
2589 | HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT), | ||
2590 | HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT), | ||
2591 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT), | ||
2592 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT), | ||
2593 | |||
2594 | HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
2595 | HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
2596 | |||
2597 | HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), | ||
2598 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT), | ||
2599 | { | ||
2600 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2601 | .name = "Channel Mode", | ||
2602 | .info = ad198x_ch_mode_info, | ||
2603 | .get = ad198x_ch_mode_get, | ||
2604 | .put = ad198x_ch_mode_put, | ||
2605 | }, | ||
2606 | |||
2607 | { } /* end */ | ||
2608 | }; | ||
2609 | |||
2610 | /* laptop mode */ | ||
2611 | static const struct snd_kcontrol_new ad1988_laptop_mixers[] = { | ||
2612 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
2613 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
2614 | HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT), | ||
2615 | HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), | ||
2616 | |||
2617 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT), | ||
2618 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT), | ||
2619 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x0, HDA_INPUT), | ||
2620 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x0, HDA_INPUT), | ||
2621 | HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT), | ||
2622 | HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT), | ||
2623 | |||
2624 | HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
2625 | HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
2626 | |||
2627 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), | ||
2628 | |||
2629 | { | ||
2630 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2631 | .name = "External Amplifier", | ||
2632 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x12, | ||
2633 | .info = ad198x_eapd_info, | ||
2634 | .get = ad198x_eapd_get, | ||
2635 | .put = ad198x_eapd_put, | ||
2636 | .private_value = 0x12, /* port-D */ | ||
2637 | }, | ||
2638 | |||
2639 | { } /* end */ | ||
2640 | }; | ||
2641 | |||
2642 | /* capture */ | ||
2643 | static const struct snd_kcontrol_new ad1988_capture_mixers[] = { | ||
2644 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
2645 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
2646 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
2647 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
2648 | HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x0e, 0x0, HDA_OUTPUT), | ||
2649 | HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x0e, 0x0, HDA_OUTPUT), | ||
2650 | { | ||
2651 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2652 | /* The multiple "Capture Source" controls confuse alsamixer | ||
2653 | * So call somewhat different.. | ||
2654 | */ | ||
2655 | /* .name = "Capture Source", */ | ||
2656 | .name = "Input Source", | ||
2657 | .count = 3, | ||
2658 | .info = ad198x_mux_enum_info, | ||
2659 | .get = ad198x_mux_enum_get, | ||
2660 | .put = ad198x_mux_enum_put, | ||
2661 | }, | ||
2662 | { } /* end */ | ||
2663 | }; | ||
2664 | |||
2665 | static int ad1988_spdif_playback_source_info(struct snd_kcontrol *kcontrol, | ||
2666 | struct snd_ctl_elem_info *uinfo) | ||
2667 | { | ||
2668 | static const char * const texts[] = { | ||
2669 | "PCM", "ADC1", "ADC2", "ADC3" | ||
2670 | }; | ||
2671 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
2672 | uinfo->count = 1; | ||
2673 | uinfo->value.enumerated.items = 4; | ||
2674 | if (uinfo->value.enumerated.item >= 4) | ||
2675 | uinfo->value.enumerated.item = 3; | ||
2676 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
2677 | return 0; | ||
2678 | } | ||
2679 | |||
2680 | static int ad1988_spdif_playback_source_get(struct snd_kcontrol *kcontrol, | ||
2681 | struct snd_ctl_elem_value *ucontrol) | ||
2682 | { | ||
2683 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2684 | unsigned int sel; | ||
2685 | |||
2686 | sel = snd_hda_codec_read(codec, 0x1d, 0, AC_VERB_GET_AMP_GAIN_MUTE, | ||
2687 | AC_AMP_GET_INPUT); | ||
2688 | if (!(sel & 0x80)) | ||
2689 | ucontrol->value.enumerated.item[0] = 0; | ||
2690 | else { | ||
2691 | sel = snd_hda_codec_read(codec, 0x0b, 0, | ||
2692 | AC_VERB_GET_CONNECT_SEL, 0); | ||
2693 | if (sel < 3) | ||
2694 | sel++; | ||
2695 | else | ||
2696 | sel = 0; | ||
2697 | ucontrol->value.enumerated.item[0] = sel; | ||
2698 | } | ||
2699 | return 0; | ||
2700 | } | ||
2701 | |||
2702 | static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol, | ||
2703 | struct snd_ctl_elem_value *ucontrol) | ||
2704 | { | ||
2705 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2706 | unsigned int val, sel; | ||
2707 | int change; | ||
2708 | |||
2709 | val = ucontrol->value.enumerated.item[0]; | ||
2710 | if (val > 3) | ||
2711 | return -EINVAL; | ||
2712 | if (!val) { | ||
2713 | sel = snd_hda_codec_read(codec, 0x1d, 0, | ||
2714 | AC_VERB_GET_AMP_GAIN_MUTE, | ||
2715 | AC_AMP_GET_INPUT); | ||
2716 | change = sel & 0x80; | ||
2717 | if (change) { | ||
2718 | snd_hda_codec_write_cache(codec, 0x1d, 0, | ||
2719 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
2720 | AMP_IN_UNMUTE(0)); | ||
2721 | snd_hda_codec_write_cache(codec, 0x1d, 0, | ||
2722 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
2723 | AMP_IN_MUTE(1)); | ||
2724 | } | ||
2725 | } else { | ||
2726 | sel = snd_hda_codec_read(codec, 0x1d, 0, | ||
2727 | AC_VERB_GET_AMP_GAIN_MUTE, | ||
2728 | AC_AMP_GET_INPUT | 0x01); | ||
2729 | change = sel & 0x80; | ||
2730 | if (change) { | ||
2731 | snd_hda_codec_write_cache(codec, 0x1d, 0, | ||
2732 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
2733 | AMP_IN_MUTE(0)); | ||
2734 | snd_hda_codec_write_cache(codec, 0x1d, 0, | ||
2735 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
2736 | AMP_IN_UNMUTE(1)); | ||
2737 | } | ||
2738 | sel = snd_hda_codec_read(codec, 0x0b, 0, | ||
2739 | AC_VERB_GET_CONNECT_SEL, 0) + 1; | ||
2740 | change |= sel != val; | ||
2741 | if (change) | ||
2742 | snd_hda_codec_write_cache(codec, 0x0b, 0, | ||
2743 | AC_VERB_SET_CONNECT_SEL, | ||
2744 | val - 1); | ||
2745 | } | ||
2746 | return change; | ||
2747 | } | ||
2748 | |||
2749 | static const struct snd_kcontrol_new ad1988_spdif_out_mixers[] = { | ||
2750 | HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
2751 | { | ||
2752 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2753 | .name = "IEC958 Playback Source", | ||
2754 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, | ||
2755 | .info = ad1988_spdif_playback_source_info, | ||
2756 | .get = ad1988_spdif_playback_source_get, | ||
2757 | .put = ad1988_spdif_playback_source_put, | ||
2758 | }, | ||
2759 | { } /* end */ | ||
2760 | }; | ||
2761 | |||
2762 | static const struct snd_kcontrol_new ad1988_spdif_in_mixers[] = { | ||
2763 | HDA_CODEC_VOLUME("IEC958 Capture Volume", 0x1c, 0x0, HDA_INPUT), | ||
2764 | { } /* end */ | ||
2765 | }; | ||
2766 | |||
2767 | static const struct snd_kcontrol_new ad1989_spdif_out_mixers[] = { | ||
2768 | HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
2769 | HDA_CODEC_VOLUME("HDMI Playback Volume", 0x1d, 0x0, HDA_OUTPUT), | ||
2770 | { } /* end */ | ||
2771 | }; | ||
2772 | |||
2773 | /* | ||
2774 | * initialization verbs | ||
2775 | */ | ||
2776 | |||
2777 | /* | ||
2778 | * for 6-stack (+dig) | ||
2779 | */ | ||
2780 | static const struct hda_verb ad1988_6stack_init_verbs[] = { | ||
2781 | /* Front, Surround, CLFE, side DAC; unmute as default */ | ||
2782 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2783 | {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2784 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2785 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2786 | /* Port-A front headphon path */ | ||
2787 | {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ | ||
2788 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2789 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2790 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2791 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
2792 | /* Port-D line-out path */ | ||
2793 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2794 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2795 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2796 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2797 | /* Port-F surround path */ | ||
2798 | {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2799 | {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2800 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2801 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2802 | /* Port-G CLFE path */ | ||
2803 | {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2804 | {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2805 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2806 | {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2807 | /* Port-H side path */ | ||
2808 | {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2809 | {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2810 | {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2811 | {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2812 | /* Mono out path */ | ||
2813 | {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */ | ||
2814 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2815 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2816 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2817 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */ | ||
2818 | /* Port-B front mic-in path */ | ||
2819 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
2820 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
2821 | {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
2822 | /* Port-C line-in path */ | ||
2823 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
2824 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
2825 | {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
2826 | {0x33, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
2827 | /* Port-E mic-in path */ | ||
2828 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
2829 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
2830 | {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
2831 | {0x34, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
2832 | /* Analog CD Input */ | ||
2833 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
2834 | /* Analog Mix output amp */ | ||
2835 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ | ||
2836 | |||
2837 | { } | ||
2838 | }; | ||
2839 | |||
2840 | static const struct hda_verb ad1988_6stack_fp_init_verbs[] = { | ||
2841 | /* Headphone; unmute as default */ | ||
2842 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2843 | /* Port-A front headphon path */ | ||
2844 | {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ | ||
2845 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2846 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2847 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2848 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
2849 | |||
2850 | { } | ||
2851 | }; | ||
2852 | |||
2853 | static const struct hda_verb ad1988_capture_init_verbs[] = { | ||
2854 | /* mute analog mix */ | ||
2855 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2856 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2857 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
2858 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
2859 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
2860 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
2861 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, | ||
2862 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, | ||
2863 | /* select ADCs - front-mic */ | ||
2864 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
2865 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
2866 | {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
2867 | |||
2868 | { } | ||
2869 | }; | ||
2870 | |||
2871 | static const struct hda_verb ad1988_spdif_init_verbs[] = { | ||
2872 | /* SPDIF out sel */ | ||
2873 | {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */ | ||
2874 | {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */ | ||
2875 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
2876 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2877 | /* SPDIF out pin */ | ||
2878 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | ||
2879 | |||
2880 | { } | ||
2881 | }; | ||
2882 | |||
2883 | static const struct hda_verb ad1988_spdif_in_init_verbs[] = { | ||
2884 | /* unmute SPDIF input pin */ | ||
2885 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
2886 | { } | ||
2887 | }; | ||
2888 | |||
2889 | /* AD1989 has no ADC -> SPDIF route */ | ||
2890 | static const struct hda_verb ad1989_spdif_init_verbs[] = { | ||
2891 | /* SPDIF-1 out pin */ | ||
2892 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
2893 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | ||
2894 | /* SPDIF-2/HDMI out pin */ | ||
2895 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
2896 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | ||
2897 | { } | ||
2898 | }; | ||
2899 | |||
2900 | /* | ||
2901 | * verbs for 3stack (+dig) | ||
2902 | */ | ||
2903 | static const struct hda_verb ad1988_3stack_ch2_init[] = { | ||
2904 | /* set port-C to line-in */ | ||
2905 | { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
2906 | { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, | ||
2907 | /* set port-E to mic-in */ | ||
2908 | { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
2909 | { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, | ||
2910 | { } /* end */ | ||
2911 | }; | ||
2912 | |||
2913 | static const struct hda_verb ad1988_3stack_ch6_init[] = { | ||
2914 | /* set port-C to surround out */ | ||
2915 | { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
2916 | { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
2917 | /* set port-E to CLFE out */ | ||
2918 | { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
2919 | { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
2920 | { } /* end */ | ||
2921 | }; | ||
2922 | |||
2923 | static const struct hda_channel_mode ad1988_3stack_modes[2] = { | ||
2924 | { 2, ad1988_3stack_ch2_init }, | ||
2925 | { 6, ad1988_3stack_ch6_init }, | ||
2926 | }; | ||
2927 | |||
2928 | static const struct hda_verb ad1988_3stack_init_verbs[] = { | ||
2929 | /* Front, Surround, CLFE, side DAC; unmute as default */ | ||
2930 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2931 | {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2932 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2933 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2934 | /* Port-A front headphon path */ | ||
2935 | {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ | ||
2936 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2937 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2938 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2939 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
2940 | /* Port-D line-out path */ | ||
2941 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2942 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2943 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2944 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2945 | /* Mono out path */ | ||
2946 | {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */ | ||
2947 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2948 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2949 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2950 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */ | ||
2951 | /* Port-B front mic-in path */ | ||
2952 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
2953 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
2954 | {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
2955 | /* Port-C line-in/surround path - 6ch mode as default */ | ||
2956 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2957 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2958 | {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
2959 | {0x31, AC_VERB_SET_CONNECT_SEL, 0x0}, /* output sel: DAC 0x05 */ | ||
2960 | {0x33, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
2961 | /* Port-E mic-in/CLFE path - 6ch mode as default */ | ||
2962 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2963 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2964 | {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
2965 | {0x32, AC_VERB_SET_CONNECT_SEL, 0x1}, /* output sel: DAC 0x0a */ | ||
2966 | {0x34, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
2967 | /* mute analog mix */ | ||
2968 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2969 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2970 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
2971 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
2972 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
2973 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
2974 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, | ||
2975 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, | ||
2976 | /* select ADCs - front-mic */ | ||
2977 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
2978 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
2979 | {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
2980 | /* Analog Mix output amp */ | ||
2981 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ | ||
2982 | { } | ||
2983 | }; | ||
2984 | |||
2985 | /* | ||
2986 | * verbs for laptop mode (+dig) | ||
2987 | */ | ||
2988 | static const struct hda_verb ad1988_laptop_hp_on[] = { | ||
2989 | /* unmute port-A and mute port-D */ | ||
2990 | { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
2991 | { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
2992 | { } /* end */ | ||
2993 | }; | ||
2994 | static const struct hda_verb ad1988_laptop_hp_off[] = { | ||
2995 | /* mute port-A and unmute port-D */ | ||
2996 | { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
2997 | { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
2998 | { } /* end */ | ||
2999 | }; | ||
3000 | |||
3001 | #define AD1988_HP_EVENT 0x01 | ||
3002 | |||
3003 | static const struct hda_verb ad1988_laptop_init_verbs[] = { | ||
3004 | /* Front, Surround, CLFE, side DAC; unmute as default */ | ||
3005 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
3006 | {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
3007 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
3008 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
3009 | /* Port-A front headphon path */ | ||
3010 | {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ | ||
3011 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
3012 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
3013 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
3014 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
3015 | /* unsolicited event for pin-sense */ | ||
3016 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1988_HP_EVENT }, | ||
3017 | /* Port-D line-out path + EAPD */ | ||
3018 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
3019 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
3020 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
3021 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
3022 | {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x00}, /* EAPD-off */ | ||
3023 | /* Mono out path */ | ||
3024 | {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */ | ||
3025 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
3026 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
3027 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
3028 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */ | ||
3029 | /* Port-B mic-in path */ | ||
3030 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
3031 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
3032 | {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3033 | /* Port-C docking station - try to output */ | ||
3034 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
3035 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
3036 | {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3037 | {0x33, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
3038 | /* mute analog mix */ | ||
3039 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
3040 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
3041 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
3042 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
3043 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
3044 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
3045 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, | ||
3046 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, | ||
3047 | /* select ADCs - mic */ | ||
3048 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
3049 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
3050 | {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
3051 | /* Analog Mix output amp */ | ||
3052 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ | ||
3053 | { } | ||
3054 | }; | ||
3055 | |||
3056 | static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res) | ||
3057 | { | ||
3058 | if ((res >> 26) != AD1988_HP_EVENT) | ||
3059 | return; | ||
3060 | if (snd_hda_jack_detect(codec, 0x11)) | ||
3061 | snd_hda_sequence_write(codec, ad1988_laptop_hp_on); | ||
3062 | else | ||
3063 | snd_hda_sequence_write(codec, ad1988_laptop_hp_off); | ||
3064 | } | ||
3065 | |||
3066 | #ifdef CONFIG_PM | ||
3067 | static const struct hda_amp_list ad1988_loopbacks[] = { | ||
3068 | { 0x20, HDA_INPUT, 0 }, /* Front Mic */ | ||
3069 | { 0x20, HDA_INPUT, 1 }, /* Line */ | ||
3070 | { 0x20, HDA_INPUT, 4 }, /* Mic */ | ||
3071 | { 0x20, HDA_INPUT, 6 }, /* CD */ | ||
3072 | { } /* end */ | ||
3073 | }; | ||
3074 | #endif | ||
3075 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | 683 | #endif /* ENABLE_AD_STATIC_QUIRKS */ |
3076 | 684 | ||
3077 | static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol, | 685 | static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol, |
@@ -3220,7 +828,34 @@ static int ad1988_add_spdif_mux_ctl(struct hda_codec *codec) | |||
3220 | /* | 828 | /* |
3221 | */ | 829 | */ |
3222 | 830 | ||
3223 | static int ad1988_parse_auto_config(struct hda_codec *codec) | 831 | enum { |
832 | AD1988_FIXUP_6STACK_DIG, | ||
833 | }; | ||
834 | |||
835 | static const struct hda_fixup ad1988_fixups[] = { | ||
836 | [AD1988_FIXUP_6STACK_DIG] = { | ||
837 | .type = HDA_FIXUP_PINS, | ||
838 | .v.pins = (const struct hda_pintbl[]) { | ||
839 | { 0x11, 0x02214130 }, /* front-hp */ | ||
840 | { 0x12, 0x01014010 }, /* line-out */ | ||
841 | { 0x14, 0x02a19122 }, /* front-mic */ | ||
842 | { 0x15, 0x01813021 }, /* line-in */ | ||
843 | { 0x16, 0x01011012 }, /* line-out */ | ||
844 | { 0x17, 0x01a19020 }, /* mic */ | ||
845 | { 0x1b, 0x0145f1f0 }, /* SPDIF */ | ||
846 | { 0x24, 0x01016011 }, /* line-out */ | ||
847 | { 0x25, 0x01012013 }, /* line-out */ | ||
848 | { } | ||
849 | } | ||
850 | }, | ||
851 | }; | ||
852 | |||
853 | static const struct hda_model_fixup ad1988_fixup_models[] = { | ||
854 | { .id = AD1988_FIXUP_6STACK_DIG, .name = "6stack-dig" }, | ||
855 | {} | ||
856 | }; | ||
857 | |||
858 | static int patch_ad1988(struct hda_codec *codec) | ||
3224 | { | 859 | { |
3225 | struct ad198x_spec *spec; | 860 | struct ad198x_spec *spec; |
3226 | int err; | 861 | int err; |
@@ -3234,12 +869,19 @@ static int ad1988_parse_auto_config(struct hda_codec *codec) | |||
3234 | spec->gen.mixer_merge_nid = 0x21; | 869 | spec->gen.mixer_merge_nid = 0x21; |
3235 | spec->gen.beep_nid = 0x10; | 870 | spec->gen.beep_nid = 0x10; |
3236 | set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); | 871 | set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); |
872 | |||
873 | snd_hda_pick_fixup(codec, ad1988_fixup_models, NULL, ad1988_fixups); | ||
874 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); | ||
875 | |||
3237 | err = ad198x_parse_auto_config(codec); | 876 | err = ad198x_parse_auto_config(codec); |
3238 | if (err < 0) | 877 | if (err < 0) |
3239 | goto error; | 878 | goto error; |
3240 | err = ad1988_add_spdif_mux_ctl(codec); | 879 | err = ad1988_add_spdif_mux_ctl(codec); |
3241 | if (err < 0) | 880 | if (err < 0) |
3242 | goto error; | 881 | goto error; |
882 | |||
883 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); | ||
884 | |||
3243 | return 0; | 885 | return 0; |
3244 | 886 | ||
3245 | error: | 887 | error: |
@@ -3247,169 +889,6 @@ static int ad1988_parse_auto_config(struct hda_codec *codec) | |||
3247 | return err; | 889 | return err; |
3248 | } | 890 | } |
3249 | 891 | ||
3250 | /* | ||
3251 | */ | ||
3252 | |||
3253 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
3254 | static const char * const ad1988_models[AD1988_MODEL_LAST] = { | ||
3255 | [AD1988_6STACK] = "6stack", | ||
3256 | [AD1988_6STACK_DIG] = "6stack-dig", | ||
3257 | [AD1988_3STACK] = "3stack", | ||
3258 | [AD1988_3STACK_DIG] = "3stack-dig", | ||
3259 | [AD1988_LAPTOP] = "laptop", | ||
3260 | [AD1988_LAPTOP_DIG] = "laptop-dig", | ||
3261 | [AD1988_AUTO] = "auto", | ||
3262 | }; | ||
3263 | |||
3264 | static const struct snd_pci_quirk ad1988_cfg_tbl[] = { | ||
3265 | SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG), | ||
3266 | SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG), | ||
3267 | SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG), | ||
3268 | SND_PCI_QUIRK(0x1043, 0x82c0, "Asus M3N-HT Deluxe", AD1988_6STACK_DIG), | ||
3269 | SND_PCI_QUIRK(0x1043, 0x8311, "Asus P5Q-Premium/Pro", AD1988_6STACK_DIG), | ||
3270 | {} | ||
3271 | }; | ||
3272 | |||
3273 | static int patch_ad1988(struct hda_codec *codec) | ||
3274 | { | ||
3275 | struct ad198x_spec *spec; | ||
3276 | int err, board_config; | ||
3277 | |||
3278 | board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST, | ||
3279 | ad1988_models, ad1988_cfg_tbl); | ||
3280 | if (board_config < 0) { | ||
3281 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
3282 | codec->chip_name); | ||
3283 | board_config = AD1988_AUTO; | ||
3284 | } | ||
3285 | |||
3286 | if (board_config == AD1988_AUTO) | ||
3287 | return ad1988_parse_auto_config(codec); | ||
3288 | |||
3289 | err = alloc_ad_spec(codec); | ||
3290 | if (err < 0) | ||
3291 | return err; | ||
3292 | spec = codec->spec; | ||
3293 | |||
3294 | if (is_rev2(codec)) | ||
3295 | snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n"); | ||
3296 | |||
3297 | err = snd_hda_attach_beep_device(codec, 0x10); | ||
3298 | if (err < 0) { | ||
3299 | ad198x_free(codec); | ||
3300 | return err; | ||
3301 | } | ||
3302 | set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); | ||
3303 | |||
3304 | if (!spec->multiout.hp_nid) | ||
3305 | spec->multiout.hp_nid = ad1988_alt_dac_nid[0]; | ||
3306 | switch (board_config) { | ||
3307 | case AD1988_6STACK: | ||
3308 | case AD1988_6STACK_DIG: | ||
3309 | spec->multiout.max_channels = 8; | ||
3310 | spec->multiout.num_dacs = 4; | ||
3311 | if (is_rev2(codec)) | ||
3312 | spec->multiout.dac_nids = ad1988_6stack_dac_nids_rev2; | ||
3313 | else | ||
3314 | spec->multiout.dac_nids = ad1988_6stack_dac_nids; | ||
3315 | spec->input_mux = &ad1988_6stack_capture_source; | ||
3316 | spec->num_mixers = 2; | ||
3317 | if (is_rev2(codec)) | ||
3318 | spec->mixers[0] = ad1988_6stack_mixers1_rev2; | ||
3319 | else | ||
3320 | spec->mixers[0] = ad1988_6stack_mixers1; | ||
3321 | spec->mixers[1] = ad1988_6stack_mixers2; | ||
3322 | spec->num_init_verbs = 1; | ||
3323 | spec->init_verbs[0] = ad1988_6stack_init_verbs; | ||
3324 | if (board_config == AD1988_6STACK_DIG) { | ||
3325 | spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; | ||
3326 | spec->dig_in_nid = AD1988_SPDIF_IN; | ||
3327 | } | ||
3328 | break; | ||
3329 | case AD1988_3STACK: | ||
3330 | case AD1988_3STACK_DIG: | ||
3331 | spec->multiout.max_channels = 6; | ||
3332 | spec->multiout.num_dacs = 3; | ||
3333 | if (is_rev2(codec)) | ||
3334 | spec->multiout.dac_nids = ad1988_3stack_dac_nids_rev2; | ||
3335 | else | ||
3336 | spec->multiout.dac_nids = ad1988_3stack_dac_nids; | ||
3337 | spec->input_mux = &ad1988_6stack_capture_source; | ||
3338 | spec->channel_mode = ad1988_3stack_modes; | ||
3339 | spec->num_channel_mode = ARRAY_SIZE(ad1988_3stack_modes); | ||
3340 | spec->num_mixers = 2; | ||
3341 | if (is_rev2(codec)) | ||
3342 | spec->mixers[0] = ad1988_3stack_mixers1_rev2; | ||
3343 | else | ||
3344 | spec->mixers[0] = ad1988_3stack_mixers1; | ||
3345 | spec->mixers[1] = ad1988_3stack_mixers2; | ||
3346 | spec->num_init_verbs = 1; | ||
3347 | spec->init_verbs[0] = ad1988_3stack_init_verbs; | ||
3348 | if (board_config == AD1988_3STACK_DIG) | ||
3349 | spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; | ||
3350 | break; | ||
3351 | case AD1988_LAPTOP: | ||
3352 | case AD1988_LAPTOP_DIG: | ||
3353 | spec->multiout.max_channels = 2; | ||
3354 | spec->multiout.num_dacs = 1; | ||
3355 | spec->multiout.dac_nids = ad1988_3stack_dac_nids; | ||
3356 | spec->input_mux = &ad1988_laptop_capture_source; | ||
3357 | spec->num_mixers = 1; | ||
3358 | spec->mixers[0] = ad1988_laptop_mixers; | ||
3359 | codec->inv_eapd = 1; /* inverted EAPD */ | ||
3360 | spec->num_init_verbs = 1; | ||
3361 | spec->init_verbs[0] = ad1988_laptop_init_verbs; | ||
3362 | if (board_config == AD1988_LAPTOP_DIG) | ||
3363 | spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; | ||
3364 | break; | ||
3365 | } | ||
3366 | |||
3367 | spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids); | ||
3368 | spec->adc_nids = ad1988_adc_nids; | ||
3369 | spec->capsrc_nids = ad1988_capsrc_nids; | ||
3370 | spec->mixers[spec->num_mixers++] = ad1988_capture_mixers; | ||
3371 | spec->init_verbs[spec->num_init_verbs++] = ad1988_capture_init_verbs; | ||
3372 | if (spec->multiout.dig_out_nid) { | ||
3373 | if (codec->vendor_id >= 0x11d4989a) { | ||
3374 | spec->mixers[spec->num_mixers++] = | ||
3375 | ad1989_spdif_out_mixers; | ||
3376 | spec->init_verbs[spec->num_init_verbs++] = | ||
3377 | ad1989_spdif_init_verbs; | ||
3378 | codec->slave_dig_outs = ad1989b_slave_dig_outs; | ||
3379 | } else { | ||
3380 | spec->mixers[spec->num_mixers++] = | ||
3381 | ad1988_spdif_out_mixers; | ||
3382 | spec->init_verbs[spec->num_init_verbs++] = | ||
3383 | ad1988_spdif_init_verbs; | ||
3384 | } | ||
3385 | } | ||
3386 | if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) { | ||
3387 | spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers; | ||
3388 | spec->init_verbs[spec->num_init_verbs++] = | ||
3389 | ad1988_spdif_in_init_verbs; | ||
3390 | } | ||
3391 | |||
3392 | codec->patch_ops = ad198x_patch_ops; | ||
3393 | switch (board_config) { | ||
3394 | case AD1988_LAPTOP: | ||
3395 | case AD1988_LAPTOP_DIG: | ||
3396 | codec->patch_ops.unsol_event = ad1988_laptop_unsol_event; | ||
3397 | break; | ||
3398 | } | ||
3399 | #ifdef CONFIG_PM | ||
3400 | spec->loopback.amplist = ad1988_loopbacks; | ||
3401 | #endif | ||
3402 | spec->vmaster_nid = 0x04; | ||
3403 | |||
3404 | codec->no_trigger_sense = 1; | ||
3405 | codec->no_sticky_stream = 1; | ||
3406 | |||
3407 | return 0; | ||
3408 | } | ||
3409 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
3410 | #define patch_ad1988 ad1988_parse_auto_config | ||
3411 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
3412 | |||
3413 | 892 | ||
3414 | /* | 893 | /* |
3415 | * AD1884 / AD1984 | 894 | * AD1884 / AD1984 |
@@ -3423,167 +902,19 @@ static int patch_ad1988(struct hda_codec *codec) | |||
3423 | * | 902 | * |
3424 | * AD1984 = AD1884 + two digital mic-ins | 903 | * AD1984 = AD1884 + two digital mic-ins |
3425 | * | 904 | * |
3426 | * FIXME: | 905 | * AD1883 / AD1884A / AD1984A / AD1984B |
3427 | * For simplicity, we share the single DAC for both HP and line-outs | 906 | * |
3428 | * right now. The inidividual playbacks could be easily implemented, | 907 | * port-B (0x14) - front mic-in |
3429 | * but no build-up framework is given, so far. | 908 | * port-E (0x1c) - rear mic-in |
3430 | */ | 909 | * port-F (0x16) - CD / ext out |
3431 | 910 | * port-C (0x15) - rear line-in | |
3432 | #ifdef ENABLE_AD_STATIC_QUIRKS | 911 | * port-D (0x12) - rear line-out |
3433 | static const hda_nid_t ad1884_dac_nids[1] = { | 912 | * port-A (0x11) - front hp-out |
3434 | 0x04, | 913 | * |
3435 | }; | 914 | * AD1984A = AD1884A + digital-mic |
3436 | 915 | * AD1883 = equivalent with AD1984A | |
3437 | static const hda_nid_t ad1884_adc_nids[2] = { | 916 | * AD1984B = AD1984A + extra SPDIF-out |
3438 | 0x08, 0x09, | ||
3439 | }; | ||
3440 | |||
3441 | static const hda_nid_t ad1884_capsrc_nids[2] = { | ||
3442 | 0x0c, 0x0d, | ||
3443 | }; | ||
3444 | |||
3445 | #define AD1884_SPDIF_OUT 0x02 | ||
3446 | |||
3447 | static const struct hda_input_mux ad1884_capture_source = { | ||
3448 | .num_items = 4, | ||
3449 | .items = { | ||
3450 | { "Front Mic", 0x0 }, | ||
3451 | { "Mic", 0x1 }, | ||
3452 | { "CD", 0x2 }, | ||
3453 | { "Mix", 0x3 }, | ||
3454 | }, | ||
3455 | }; | ||
3456 | |||
3457 | static const struct snd_kcontrol_new ad1884_base_mixers[] = { | ||
3458 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
3459 | /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */ | ||
3460 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
3461 | HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
3462 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), | ||
3463 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), | ||
3464 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
3465 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
3466 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
3467 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
3468 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT), | ||
3469 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT), | ||
3470 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT), | ||
3471 | HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT), | ||
3472 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
3473 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
3474 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3475 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3476 | { | ||
3477 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3478 | /* The multiple "Capture Source" controls confuse alsamixer | ||
3479 | * So call somewhat different.. | ||
3480 | */ | ||
3481 | /* .name = "Capture Source", */ | ||
3482 | .name = "Input Source", | ||
3483 | .count = 2, | ||
3484 | .info = ad198x_mux_enum_info, | ||
3485 | .get = ad198x_mux_enum_get, | ||
3486 | .put = ad198x_mux_enum_put, | ||
3487 | }, | ||
3488 | /* SPDIF controls */ | ||
3489 | HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
3490 | { | ||
3491 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3492 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
3493 | /* identical with ad1983 */ | ||
3494 | .info = ad1983_spdif_route_info, | ||
3495 | .get = ad1983_spdif_route_get, | ||
3496 | .put = ad1983_spdif_route_put, | ||
3497 | }, | ||
3498 | { } /* end */ | ||
3499 | }; | ||
3500 | |||
3501 | static const struct snd_kcontrol_new ad1984_dmic_mixers[] = { | ||
3502 | HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT), | ||
3503 | HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT), | ||
3504 | HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0, | ||
3505 | HDA_INPUT), | ||
3506 | HDA_CODEC_MUTE_IDX("Digital Mic Capture Switch", 1, 0x06, 0x0, | ||
3507 | HDA_INPUT), | ||
3508 | { } /* end */ | ||
3509 | }; | ||
3510 | |||
3511 | /* | ||
3512 | * initialization verbs | ||
3513 | */ | 917 | */ |
3514 | static const struct hda_verb ad1884_init_verbs[] = { | ||
3515 | /* DACs; mute as default */ | ||
3516 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3517 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3518 | /* Port-A (HP) mixer */ | ||
3519 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3520 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3521 | /* Port-A pin */ | ||
3522 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
3523 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
3524 | /* HP selector - select DAC2 */ | ||
3525 | {0x22, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
3526 | /* Port-D (Line-out) mixer */ | ||
3527 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3528 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3529 | /* Port-D pin */ | ||
3530 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
3531 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
3532 | /* Mono-out mixer */ | ||
3533 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3534 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3535 | /* Mono-out pin */ | ||
3536 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
3537 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
3538 | /* Mono selector */ | ||
3539 | {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
3540 | /* Port-B (front mic) pin */ | ||
3541 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
3542 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3543 | /* Port-C (rear mic) pin */ | ||
3544 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
3545 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3546 | /* Analog mixer; mute as default */ | ||
3547 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
3548 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
3549 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
3550 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
3551 | /* Analog Mix output amp */ | ||
3552 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ | ||
3553 | /* SPDIF output selector */ | ||
3554 | {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */ | ||
3555 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | ||
3556 | { } /* end */ | ||
3557 | }; | ||
3558 | |||
3559 | #ifdef CONFIG_PM | ||
3560 | static const struct hda_amp_list ad1884_loopbacks[] = { | ||
3561 | { 0x20, HDA_INPUT, 0 }, /* Front Mic */ | ||
3562 | { 0x20, HDA_INPUT, 1 }, /* Mic */ | ||
3563 | { 0x20, HDA_INPUT, 2 }, /* CD */ | ||
3564 | { 0x20, HDA_INPUT, 4 }, /* Docking */ | ||
3565 | { } /* end */ | ||
3566 | }; | ||
3567 | #endif | ||
3568 | |||
3569 | static const char * const ad1884_slave_vols[] = { | ||
3570 | "PCM", "Mic", "Mono", "Front Mic", "Mic", "CD", | ||
3571 | "Internal Mic", "Dock Mic", /* "Beep", */ "IEC958", | ||
3572 | NULL | ||
3573 | }; | ||
3574 | |||
3575 | enum { | ||
3576 | AD1884_AUTO, | ||
3577 | AD1884_BASIC, | ||
3578 | AD1884_MODELS | ||
3579 | }; | ||
3580 | |||
3581 | static const char * const ad1884_models[AD1884_MODELS] = { | ||
3582 | [AD1884_AUTO] = "auto", | ||
3583 | [AD1884_BASIC] = "basic", | ||
3584 | }; | ||
3585 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
3586 | |||
3587 | 918 | ||
3588 | /* set the upper-limit for mixer amp to 0dB for avoiding the possible | 919 | /* set the upper-limit for mixer amp to 0dB for avoiding the possible |
3589 | * damage by overloading | 920 | * damage by overloading |
@@ -3599,14 +930,34 @@ static void ad1884_fixup_amp_override(struct hda_codec *codec, | |||
3599 | (1 << AC_AMPCAP_MUTE_SHIFT)); | 930 | (1 << AC_AMPCAP_MUTE_SHIFT)); |
3600 | } | 931 | } |
3601 | 932 | ||
933 | /* toggle GPIO1 according to the mute state */ | ||
934 | static void ad1884_vmaster_hp_gpio_hook(void *private_data, int enabled) | ||
935 | { | ||
936 | struct hda_codec *codec = private_data; | ||
937 | struct ad198x_spec *spec = codec->spec; | ||
938 | |||
939 | if (spec->eapd_nid) | ||
940 | ad_vmaster_eapd_hook(private_data, enabled); | ||
941 | snd_hda_codec_update_cache(codec, 0x01, 0, | ||
942 | AC_VERB_SET_GPIO_DATA, | ||
943 | enabled ? 0x00 : 0x02); | ||
944 | } | ||
945 | |||
3602 | static void ad1884_fixup_hp_eapd(struct hda_codec *codec, | 946 | static void ad1884_fixup_hp_eapd(struct hda_codec *codec, |
3603 | const struct hda_fixup *fix, int action) | 947 | const struct hda_fixup *fix, int action) |
3604 | { | 948 | { |
3605 | struct ad198x_spec *spec = codec->spec; | 949 | struct ad198x_spec *spec = codec->spec; |
950 | static const struct hda_verb gpio_init_verbs[] = { | ||
951 | {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, | ||
952 | {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, | ||
953 | {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, | ||
954 | {}, | ||
955 | }; | ||
3606 | 956 | ||
3607 | switch (action) { | 957 | switch (action) { |
3608 | case HDA_FIXUP_ACT_PRE_PROBE: | 958 | case HDA_FIXUP_ACT_PRE_PROBE: |
3609 | spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook; | 959 | spec->gen.vmaster_mute.hook = ad1884_vmaster_hp_gpio_hook; |
960 | snd_hda_sequence_write_cache(codec, gpio_init_verbs); | ||
3610 | break; | 961 | break; |
3611 | case HDA_FIXUP_ACT_PROBE: | 962 | case HDA_FIXUP_ACT_PROBE: |
3612 | if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) | 963 | if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) |
@@ -3617,9 +968,18 @@ static void ad1884_fixup_hp_eapd(struct hda_codec *codec, | |||
3617 | } | 968 | } |
3618 | } | 969 | } |
3619 | 970 | ||
971 | /* set magic COEFs for dmic */ | ||
972 | static const struct hda_verb ad1884_dmic_init_verbs[] = { | ||
973 | {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7}, | ||
974 | {0x01, AC_VERB_SET_PROC_COEF, 0x08}, | ||
975 | {} | ||
976 | }; | ||
977 | |||
3620 | enum { | 978 | enum { |
3621 | AD1884_FIXUP_AMP_OVERRIDE, | 979 | AD1884_FIXUP_AMP_OVERRIDE, |
3622 | AD1884_FIXUP_HP_EAPD, | 980 | AD1884_FIXUP_HP_EAPD, |
981 | AD1884_FIXUP_DMIC_COEF, | ||
982 | AD1884_FIXUP_HP_TOUCHSMART, | ||
3623 | }; | 983 | }; |
3624 | 984 | ||
3625 | static const struct hda_fixup ad1884_fixups[] = { | 985 | static const struct hda_fixup ad1884_fixups[] = { |
@@ -3633,15 +993,27 @@ static const struct hda_fixup ad1884_fixups[] = { | |||
3633 | .chained = true, | 993 | .chained = true, |
3634 | .chain_id = AD1884_FIXUP_AMP_OVERRIDE, | 994 | .chain_id = AD1884_FIXUP_AMP_OVERRIDE, |
3635 | }, | 995 | }, |
996 | [AD1884_FIXUP_DMIC_COEF] = { | ||
997 | .type = HDA_FIXUP_VERBS, | ||
998 | .v.verbs = ad1884_dmic_init_verbs, | ||
999 | }, | ||
1000 | [AD1884_FIXUP_HP_TOUCHSMART] = { | ||
1001 | .type = HDA_FIXUP_VERBS, | ||
1002 | .v.verbs = ad1884_dmic_init_verbs, | ||
1003 | .chained = true, | ||
1004 | .chain_id = AD1884_FIXUP_HP_EAPD, | ||
1005 | }, | ||
3636 | }; | 1006 | }; |
3637 | 1007 | ||
3638 | static const struct snd_pci_quirk ad1884_fixup_tbl[] = { | 1008 | static const struct snd_pci_quirk ad1884_fixup_tbl[] = { |
1009 | SND_PCI_QUIRK(0x103c, 0x2a82, "HP Touchsmart", AD1884_FIXUP_HP_TOUCHSMART), | ||
3639 | SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD), | 1010 | SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD), |
1011 | SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1884_FIXUP_DMIC_COEF), | ||
3640 | {} | 1012 | {} |
3641 | }; | 1013 | }; |
3642 | 1014 | ||
3643 | 1015 | ||
3644 | static int ad1884_parse_auto_config(struct hda_codec *codec) | 1016 | static int patch_ad1884(struct hda_codec *codec) |
3645 | { | 1017 | { |
3646 | struct ad198x_spec *spec; | 1018 | struct ad198x_spec *spec; |
3647 | int err; | 1019 | int err; |
@@ -3674,1170 +1046,6 @@ static int ad1884_parse_auto_config(struct hda_codec *codec) | |||
3674 | return err; | 1046 | return err; |
3675 | } | 1047 | } |
3676 | 1048 | ||
3677 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
3678 | static int patch_ad1884_basic(struct hda_codec *codec) | ||
3679 | { | ||
3680 | struct ad198x_spec *spec; | ||
3681 | int err; | ||
3682 | |||
3683 | err = alloc_ad_spec(codec); | ||
3684 | if (err < 0) | ||
3685 | return err; | ||
3686 | spec = codec->spec; | ||
3687 | |||
3688 | err = snd_hda_attach_beep_device(codec, 0x10); | ||
3689 | if (err < 0) { | ||
3690 | ad198x_free(codec); | ||
3691 | return err; | ||
3692 | } | ||
3693 | set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); | ||
3694 | |||
3695 | spec->multiout.max_channels = 2; | ||
3696 | spec->multiout.num_dacs = ARRAY_SIZE(ad1884_dac_nids); | ||
3697 | spec->multiout.dac_nids = ad1884_dac_nids; | ||
3698 | spec->multiout.dig_out_nid = AD1884_SPDIF_OUT; | ||
3699 | spec->num_adc_nids = ARRAY_SIZE(ad1884_adc_nids); | ||
3700 | spec->adc_nids = ad1884_adc_nids; | ||
3701 | spec->capsrc_nids = ad1884_capsrc_nids; | ||
3702 | spec->input_mux = &ad1884_capture_source; | ||
3703 | spec->num_mixers = 1; | ||
3704 | spec->mixers[0] = ad1884_base_mixers; | ||
3705 | spec->num_init_verbs = 1; | ||
3706 | spec->init_verbs[0] = ad1884_init_verbs; | ||
3707 | spec->spdif_route = 0; | ||
3708 | #ifdef CONFIG_PM | ||
3709 | spec->loopback.amplist = ad1884_loopbacks; | ||
3710 | #endif | ||
3711 | spec->vmaster_nid = 0x04; | ||
3712 | /* we need to cover all playback volumes */ | ||
3713 | spec->slave_vols = ad1884_slave_vols; | ||
3714 | /* slaves may contain input volumes, so we can't raise to 0dB blindly */ | ||
3715 | spec->avoid_init_slave_vol = 1; | ||
3716 | |||
3717 | codec->patch_ops = ad198x_patch_ops; | ||
3718 | |||
3719 | codec->no_trigger_sense = 1; | ||
3720 | codec->no_sticky_stream = 1; | ||
3721 | |||
3722 | return 0; | ||
3723 | } | ||
3724 | |||
3725 | static int patch_ad1884(struct hda_codec *codec) | ||
3726 | { | ||
3727 | int board_config; | ||
3728 | |||
3729 | board_config = snd_hda_check_board_config(codec, AD1884_MODELS, | ||
3730 | ad1884_models, NULL); | ||
3731 | if (board_config < 0) { | ||
3732 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
3733 | codec->chip_name); | ||
3734 | board_config = AD1884_AUTO; | ||
3735 | } | ||
3736 | |||
3737 | if (board_config == AD1884_AUTO) | ||
3738 | return ad1884_parse_auto_config(codec); | ||
3739 | else | ||
3740 | return patch_ad1884_basic(codec); | ||
3741 | } | ||
3742 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
3743 | #define patch_ad1884 ad1884_parse_auto_config | ||
3744 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
3745 | |||
3746 | |||
3747 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
3748 | /* | ||
3749 | * Lenovo Thinkpad T61/X61 | ||
3750 | */ | ||
3751 | static const struct hda_input_mux ad1984_thinkpad_capture_source = { | ||
3752 | .num_items = 4, | ||
3753 | .items = { | ||
3754 | { "Mic", 0x0 }, | ||
3755 | { "Internal Mic", 0x1 }, | ||
3756 | { "Mix", 0x3 }, | ||
3757 | { "Dock Mic", 0x4 }, | ||
3758 | }, | ||
3759 | }; | ||
3760 | |||
3761 | |||
3762 | /* | ||
3763 | * Dell Precision T3400 | ||
3764 | */ | ||
3765 | static const struct hda_input_mux ad1984_dell_desktop_capture_source = { | ||
3766 | .num_items = 3, | ||
3767 | .items = { | ||
3768 | { "Front Mic", 0x0 }, | ||
3769 | { "Line-In", 0x1 }, | ||
3770 | { "Mix", 0x3 }, | ||
3771 | }, | ||
3772 | }; | ||
3773 | |||
3774 | |||
3775 | static const struct snd_kcontrol_new ad1984_thinkpad_mixers[] = { | ||
3776 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
3777 | /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */ | ||
3778 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
3779 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
3780 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
3781 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
3782 | HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
3783 | HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
3784 | HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT), | ||
3785 | HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT), | ||
3786 | HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT), | ||
3787 | HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT), | ||
3788 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT), | ||
3789 | HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT), | ||
3790 | HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), | ||
3791 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
3792 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
3793 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3794 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3795 | { | ||
3796 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3797 | /* The multiple "Capture Source" controls confuse alsamixer | ||
3798 | * So call somewhat different.. | ||
3799 | */ | ||
3800 | /* .name = "Capture Source", */ | ||
3801 | .name = "Input Source", | ||
3802 | .count = 2, | ||
3803 | .info = ad198x_mux_enum_info, | ||
3804 | .get = ad198x_mux_enum_get, | ||
3805 | .put = ad198x_mux_enum_put, | ||
3806 | }, | ||
3807 | /* SPDIF controls */ | ||
3808 | HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
3809 | { | ||
3810 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3811 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
3812 | /* identical with ad1983 */ | ||
3813 | .info = ad1983_spdif_route_info, | ||
3814 | .get = ad1983_spdif_route_get, | ||
3815 | .put = ad1983_spdif_route_put, | ||
3816 | }, | ||
3817 | { } /* end */ | ||
3818 | }; | ||
3819 | |||
3820 | /* additional verbs */ | ||
3821 | static const struct hda_verb ad1984_thinkpad_init_verbs[] = { | ||
3822 | /* Port-E (docking station mic) pin */ | ||
3823 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
3824 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
3825 | /* docking mic boost */ | ||
3826 | {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3827 | /* Analog PC Beeper - allow firmware/ACPI beeps */ | ||
3828 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3) | 0x1a}, | ||
3829 | /* Analog mixer - docking mic; mute as default */ | ||
3830 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
3831 | /* enable EAPD bit */ | ||
3832 | {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, | ||
3833 | { } /* end */ | ||
3834 | }; | ||
3835 | |||
3836 | /* | ||
3837 | * Dell Precision T3400 | ||
3838 | */ | ||
3839 | static const struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = { | ||
3840 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
3841 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
3842 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
3843 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), | ||
3844 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), | ||
3845 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
3846 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
3847 | HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
3848 | HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
3849 | HDA_CODEC_VOLUME("Line-In Boost Volume", 0x15, 0x0, HDA_INPUT), | ||
3850 | HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT), | ||
3851 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
3852 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
3853 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3854 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3855 | { | ||
3856 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3857 | /* The multiple "Capture Source" controls confuse alsamixer | ||
3858 | * So call somewhat different.. | ||
3859 | */ | ||
3860 | /* .name = "Capture Source", */ | ||
3861 | .name = "Input Source", | ||
3862 | .count = 2, | ||
3863 | .info = ad198x_mux_enum_info, | ||
3864 | .get = ad198x_mux_enum_get, | ||
3865 | .put = ad198x_mux_enum_put, | ||
3866 | }, | ||
3867 | { } /* end */ | ||
3868 | }; | ||
3869 | |||
3870 | /* Digial MIC ADC NID 0x05 + 0x06 */ | ||
3871 | static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo, | ||
3872 | struct hda_codec *codec, | ||
3873 | unsigned int stream_tag, | ||
3874 | unsigned int format, | ||
3875 | struct snd_pcm_substream *substream) | ||
3876 | { | ||
3877 | snd_hda_codec_setup_stream(codec, 0x05 + substream->number, | ||
3878 | stream_tag, 0, format); | ||
3879 | return 0; | ||
3880 | } | ||
3881 | |||
3882 | static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo, | ||
3883 | struct hda_codec *codec, | ||
3884 | struct snd_pcm_substream *substream) | ||
3885 | { | ||
3886 | snd_hda_codec_cleanup_stream(codec, 0x05 + substream->number); | ||
3887 | return 0; | ||
3888 | } | ||
3889 | |||
3890 | static const struct hda_pcm_stream ad1984_pcm_dmic_capture = { | ||
3891 | .substreams = 2, | ||
3892 | .channels_min = 2, | ||
3893 | .channels_max = 2, | ||
3894 | .nid = 0x05, | ||
3895 | .ops = { | ||
3896 | .prepare = ad1984_pcm_dmic_prepare, | ||
3897 | .cleanup = ad1984_pcm_dmic_cleanup | ||
3898 | }, | ||
3899 | }; | ||
3900 | |||
3901 | static int ad1984_build_pcms(struct hda_codec *codec) | ||
3902 | { | ||
3903 | struct ad198x_spec *spec = codec->spec; | ||
3904 | struct hda_pcm *info; | ||
3905 | int err; | ||
3906 | |||
3907 | err = ad198x_build_pcms(codec); | ||
3908 | if (err < 0) | ||
3909 | return err; | ||
3910 | |||
3911 | info = spec->pcm_rec + codec->num_pcms; | ||
3912 | codec->num_pcms++; | ||
3913 | info->name = "AD1984 Digital Mic"; | ||
3914 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1984_pcm_dmic_capture; | ||
3915 | return 0; | ||
3916 | } | ||
3917 | |||
3918 | /* models */ | ||
3919 | enum { | ||
3920 | AD1984_AUTO, | ||
3921 | AD1984_BASIC, | ||
3922 | AD1984_THINKPAD, | ||
3923 | AD1984_DELL_DESKTOP, | ||
3924 | AD1984_MODELS | ||
3925 | }; | ||
3926 | |||
3927 | static const char * const ad1984_models[AD1984_MODELS] = { | ||
3928 | [AD1984_AUTO] = "auto", | ||
3929 | [AD1984_BASIC] = "basic", | ||
3930 | [AD1984_THINKPAD] = "thinkpad", | ||
3931 | [AD1984_DELL_DESKTOP] = "dell_desktop", | ||
3932 | }; | ||
3933 | |||
3934 | static const struct snd_pci_quirk ad1984_cfg_tbl[] = { | ||
3935 | /* Lenovo Thinkpad T61/X61 */ | ||
3936 | SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD), | ||
3937 | SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP), | ||
3938 | SND_PCI_QUIRK(0x1028, 0x0233, "Dell Latitude E6400", AD1984_DELL_DESKTOP), | ||
3939 | {} | ||
3940 | }; | ||
3941 | |||
3942 | static int patch_ad1984(struct hda_codec *codec) | ||
3943 | { | ||
3944 | struct ad198x_spec *spec; | ||
3945 | int board_config, err; | ||
3946 | |||
3947 | board_config = snd_hda_check_board_config(codec, AD1984_MODELS, | ||
3948 | ad1984_models, ad1984_cfg_tbl); | ||
3949 | if (board_config < 0) { | ||
3950 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
3951 | codec->chip_name); | ||
3952 | board_config = AD1984_AUTO; | ||
3953 | } | ||
3954 | |||
3955 | if (board_config == AD1984_AUTO) | ||
3956 | return ad1884_parse_auto_config(codec); | ||
3957 | |||
3958 | err = patch_ad1884_basic(codec); | ||
3959 | if (err < 0) | ||
3960 | return err; | ||
3961 | spec = codec->spec; | ||
3962 | |||
3963 | switch (board_config) { | ||
3964 | case AD1984_BASIC: | ||
3965 | /* additional digital mics */ | ||
3966 | spec->mixers[spec->num_mixers++] = ad1984_dmic_mixers; | ||
3967 | codec->patch_ops.build_pcms = ad1984_build_pcms; | ||
3968 | break; | ||
3969 | case AD1984_THINKPAD: | ||
3970 | if (codec->subsystem_id == 0x17aa20fb) { | ||
3971 | /* Thinpad X300 does not have the ability to do SPDIF, | ||
3972 | or attach to docking station to use SPDIF */ | ||
3973 | spec->multiout.dig_out_nid = 0; | ||
3974 | } else | ||
3975 | spec->multiout.dig_out_nid = AD1884_SPDIF_OUT; | ||
3976 | spec->input_mux = &ad1984_thinkpad_capture_source; | ||
3977 | spec->mixers[0] = ad1984_thinkpad_mixers; | ||
3978 | spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs; | ||
3979 | spec->analog_beep = 1; | ||
3980 | break; | ||
3981 | case AD1984_DELL_DESKTOP: | ||
3982 | spec->multiout.dig_out_nid = 0; | ||
3983 | spec->input_mux = &ad1984_dell_desktop_capture_source; | ||
3984 | spec->mixers[0] = ad1984_dell_desktop_mixers; | ||
3985 | break; | ||
3986 | } | ||
3987 | return 0; | ||
3988 | } | ||
3989 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
3990 | #define patch_ad1984 ad1884_parse_auto_config | ||
3991 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
3992 | |||
3993 | |||
3994 | /* | ||
3995 | * AD1883 / AD1884A / AD1984A / AD1984B | ||
3996 | * | ||
3997 | * port-B (0x14) - front mic-in | ||
3998 | * port-E (0x1c) - rear mic-in | ||
3999 | * port-F (0x16) - CD / ext out | ||
4000 | * port-C (0x15) - rear line-in | ||
4001 | * port-D (0x12) - rear line-out | ||
4002 | * port-A (0x11) - front hp-out | ||
4003 | * | ||
4004 | * AD1984A = AD1884A + digital-mic | ||
4005 | * AD1883 = equivalent with AD1984A | ||
4006 | * AD1984B = AD1984A + extra SPDIF-out | ||
4007 | * | ||
4008 | * FIXME: | ||
4009 | * We share the single DAC for both HP and line-outs (see AD1884/1984). | ||
4010 | */ | ||
4011 | |||
4012 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
4013 | static const hda_nid_t ad1884a_dac_nids[1] = { | ||
4014 | 0x03, | ||
4015 | }; | ||
4016 | |||
4017 | #define ad1884a_adc_nids ad1884_adc_nids | ||
4018 | #define ad1884a_capsrc_nids ad1884_capsrc_nids | ||
4019 | |||
4020 | #define AD1884A_SPDIF_OUT 0x02 | ||
4021 | |||
4022 | static const struct hda_input_mux ad1884a_capture_source = { | ||
4023 | .num_items = 5, | ||
4024 | .items = { | ||
4025 | { "Front Mic", 0x0 }, | ||
4026 | { "Mic", 0x4 }, | ||
4027 | { "Line", 0x1 }, | ||
4028 | { "CD", 0x2 }, | ||
4029 | { "Mix", 0x3 }, | ||
4030 | }, | ||
4031 | }; | ||
4032 | |||
4033 | static const struct snd_kcontrol_new ad1884a_base_mixers[] = { | ||
4034 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
4035 | HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
4036 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
4037 | HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
4038 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), | ||
4039 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), | ||
4040 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
4041 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
4042 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
4043 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
4044 | HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
4045 | HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
4046 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT), | ||
4047 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT), | ||
4048 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT), | ||
4049 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT), | ||
4050 | HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT), | ||
4051 | HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x0, HDA_INPUT), | ||
4052 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), | ||
4053 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4054 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4055 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
4056 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
4057 | { | ||
4058 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4059 | /* The multiple "Capture Source" controls confuse alsamixer | ||
4060 | * So call somewhat different.. | ||
4061 | */ | ||
4062 | /* .name = "Capture Source", */ | ||
4063 | .name = "Input Source", | ||
4064 | .count = 2, | ||
4065 | .info = ad198x_mux_enum_info, | ||
4066 | .get = ad198x_mux_enum_get, | ||
4067 | .put = ad198x_mux_enum_put, | ||
4068 | }, | ||
4069 | /* SPDIF controls */ | ||
4070 | HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
4071 | { | ||
4072 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4073 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
4074 | /* identical with ad1983 */ | ||
4075 | .info = ad1983_spdif_route_info, | ||
4076 | .get = ad1983_spdif_route_get, | ||
4077 | .put = ad1983_spdif_route_put, | ||
4078 | }, | ||
4079 | { } /* end */ | ||
4080 | }; | ||
4081 | |||
4082 | /* | ||
4083 | * initialization verbs | ||
4084 | */ | ||
4085 | static const struct hda_verb ad1884a_init_verbs[] = { | ||
4086 | /* DACs; unmute as default */ | ||
4087 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4088 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4089 | /* Port-A (HP) mixer - route only from analog mixer */ | ||
4090 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4091 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4092 | /* Port-A pin */ | ||
4093 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4094 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4095 | /* Port-D (Line-out) mixer - route only from analog mixer */ | ||
4096 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4097 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4098 | /* Port-D pin */ | ||
4099 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4100 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4101 | /* Mono-out mixer - route only from analog mixer */ | ||
4102 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4103 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4104 | /* Mono-out pin */ | ||
4105 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4106 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4107 | /* Port-B (front mic) pin */ | ||
4108 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4109 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4110 | /* Port-C (rear line-in) pin */ | ||
4111 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
4112 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4113 | /* Port-E (rear mic) pin */ | ||
4114 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4115 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4116 | {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* no boost */ | ||
4117 | /* Port-F (CD) pin */ | ||
4118 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
4119 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4120 | /* Analog mixer; mute as default */ | ||
4121 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4122 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
4123 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
4124 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
4125 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* aux */ | ||
4126 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
4127 | /* Analog Mix output amp */ | ||
4128 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4129 | /* capture sources */ | ||
4130 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
4131 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4132 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
4133 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4134 | /* SPDIF output amp */ | ||
4135 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | ||
4136 | { } /* end */ | ||
4137 | }; | ||
4138 | |||
4139 | #ifdef CONFIG_PM | ||
4140 | static const struct hda_amp_list ad1884a_loopbacks[] = { | ||
4141 | { 0x20, HDA_INPUT, 0 }, /* Front Mic */ | ||
4142 | { 0x20, HDA_INPUT, 1 }, /* Mic */ | ||
4143 | { 0x20, HDA_INPUT, 2 }, /* CD */ | ||
4144 | { 0x20, HDA_INPUT, 4 }, /* Docking */ | ||
4145 | { } /* end */ | ||
4146 | }; | ||
4147 | #endif | ||
4148 | |||
4149 | /* | ||
4150 | * Laptop model | ||
4151 | * | ||
4152 | * Port A: Headphone jack | ||
4153 | * Port B: MIC jack | ||
4154 | * Port C: Internal MIC | ||
4155 | * Port D: Dock Line Out (if enabled) | ||
4156 | * Port E: Dock Line In (if enabled) | ||
4157 | * Port F: Internal speakers | ||
4158 | */ | ||
4159 | |||
4160 | static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol, | ||
4161 | struct snd_ctl_elem_value *ucontrol) | ||
4162 | { | ||
4163 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
4164 | int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); | ||
4165 | int mute = (!ucontrol->value.integer.value[0] && | ||
4166 | !ucontrol->value.integer.value[1]); | ||
4167 | /* toggle GPIO1 according to the mute state */ | ||
4168 | snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, | ||
4169 | mute ? 0x02 : 0x0); | ||
4170 | return ret; | ||
4171 | } | ||
4172 | |||
4173 | static const struct snd_kcontrol_new ad1884a_laptop_mixers[] = { | ||
4174 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
4175 | { | ||
4176 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4177 | .name = "Master Playback Switch", | ||
4178 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
4179 | .info = snd_hda_mixer_amp_switch_info, | ||
4180 | .get = snd_hda_mixer_amp_switch_get, | ||
4181 | .put = ad1884a_mobile_master_sw_put, | ||
4182 | .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), | ||
4183 | }, | ||
4184 | HDA_CODEC_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
4185 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
4186 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
4187 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
4188 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
4189 | HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
4190 | HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
4191 | HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT), | ||
4192 | HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT), | ||
4193 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT), | ||
4194 | HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT), | ||
4195 | HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), | ||
4196 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4197 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4198 | { } /* end */ | ||
4199 | }; | ||
4200 | |||
4201 | static const struct snd_kcontrol_new ad1884a_mobile_mixers[] = { | ||
4202 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
4203 | /*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ | ||
4204 | { | ||
4205 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4206 | .name = "Master Playback Switch", | ||
4207 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
4208 | .info = snd_hda_mixer_amp_switch_info, | ||
4209 | .get = snd_hda_mixer_amp_switch_get, | ||
4210 | .put = ad1884a_mobile_master_sw_put, | ||
4211 | .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), | ||
4212 | }, | ||
4213 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
4214 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
4215 | HDA_CODEC_VOLUME("Mic Capture Volume", 0x14, 0x0, HDA_INPUT), | ||
4216 | HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x15, 0x0, HDA_INPUT), | ||
4217 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4218 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4219 | { } /* end */ | ||
4220 | }; | ||
4221 | |||
4222 | /* mute internal speaker if HP is plugged */ | ||
4223 | static void ad1884a_hp_automute(struct hda_codec *codec) | ||
4224 | { | ||
4225 | unsigned int present; | ||
4226 | |||
4227 | present = snd_hda_jack_detect(codec, 0x11); | ||
4228 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, | ||
4229 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
4230 | snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
4231 | present ? 0x00 : 0x02); | ||
4232 | } | ||
4233 | |||
4234 | /* switch to external mic if plugged */ | ||
4235 | static void ad1884a_hp_automic(struct hda_codec *codec) | ||
4236 | { | ||
4237 | unsigned int present; | ||
4238 | |||
4239 | present = snd_hda_jack_detect(codec, 0x14); | ||
4240 | snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, | ||
4241 | present ? 0 : 1); | ||
4242 | } | ||
4243 | |||
4244 | #define AD1884A_HP_EVENT 0x37 | ||
4245 | #define AD1884A_MIC_EVENT 0x36 | ||
4246 | |||
4247 | /* unsolicited event for HP jack sensing */ | ||
4248 | static void ad1884a_hp_unsol_event(struct hda_codec *codec, unsigned int res) | ||
4249 | { | ||
4250 | switch (res >> 26) { | ||
4251 | case AD1884A_HP_EVENT: | ||
4252 | ad1884a_hp_automute(codec); | ||
4253 | break; | ||
4254 | case AD1884A_MIC_EVENT: | ||
4255 | ad1884a_hp_automic(codec); | ||
4256 | break; | ||
4257 | } | ||
4258 | } | ||
4259 | |||
4260 | /* initialize jack-sensing, too */ | ||
4261 | static int ad1884a_hp_init(struct hda_codec *codec) | ||
4262 | { | ||
4263 | ad198x_init(codec); | ||
4264 | ad1884a_hp_automute(codec); | ||
4265 | ad1884a_hp_automic(codec); | ||
4266 | return 0; | ||
4267 | } | ||
4268 | |||
4269 | /* mute internal speaker if HP or docking HP is plugged */ | ||
4270 | static void ad1884a_laptop_automute(struct hda_codec *codec) | ||
4271 | { | ||
4272 | unsigned int present; | ||
4273 | |||
4274 | present = snd_hda_jack_detect(codec, 0x11); | ||
4275 | if (!present) | ||
4276 | present = snd_hda_jack_detect(codec, 0x12); | ||
4277 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, | ||
4278 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
4279 | snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
4280 | present ? 0x00 : 0x02); | ||
4281 | } | ||
4282 | |||
4283 | /* switch to external mic if plugged */ | ||
4284 | static void ad1884a_laptop_automic(struct hda_codec *codec) | ||
4285 | { | ||
4286 | unsigned int idx; | ||
4287 | |||
4288 | if (snd_hda_jack_detect(codec, 0x14)) | ||
4289 | idx = 0; | ||
4290 | else if (snd_hda_jack_detect(codec, 0x1c)) | ||
4291 | idx = 4; | ||
4292 | else | ||
4293 | idx = 1; | ||
4294 | snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, idx); | ||
4295 | } | ||
4296 | |||
4297 | /* unsolicited event for HP jack sensing */ | ||
4298 | static void ad1884a_laptop_unsol_event(struct hda_codec *codec, | ||
4299 | unsigned int res) | ||
4300 | { | ||
4301 | switch (res >> 26) { | ||
4302 | case AD1884A_HP_EVENT: | ||
4303 | ad1884a_laptop_automute(codec); | ||
4304 | break; | ||
4305 | case AD1884A_MIC_EVENT: | ||
4306 | ad1884a_laptop_automic(codec); | ||
4307 | break; | ||
4308 | } | ||
4309 | } | ||
4310 | |||
4311 | /* initialize jack-sensing, too */ | ||
4312 | static int ad1884a_laptop_init(struct hda_codec *codec) | ||
4313 | { | ||
4314 | ad198x_init(codec); | ||
4315 | ad1884a_laptop_automute(codec); | ||
4316 | ad1884a_laptop_automic(codec); | ||
4317 | return 0; | ||
4318 | } | ||
4319 | |||
4320 | /* additional verbs for laptop model */ | ||
4321 | static const struct hda_verb ad1884a_laptop_verbs[] = { | ||
4322 | /* Port-A (HP) pin - always unmuted */ | ||
4323 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4324 | /* Port-F (int speaker) mixer - route only from analog mixer */ | ||
4325 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4326 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4327 | /* Port-F (int speaker) pin */ | ||
4328 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
4329 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4330 | /* required for compaq 6530s/6531s speaker output */ | ||
4331 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
4332 | /* Port-C pin - internal mic-in */ | ||
4333 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4334 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ | ||
4335 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ | ||
4336 | /* Port-D (docking line-out) pin - default unmuted */ | ||
4337 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4338 | /* analog mix */ | ||
4339 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
4340 | /* unsolicited event for pin-sense */ | ||
4341 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
4342 | {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
4343 | {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, | ||
4344 | {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, | ||
4345 | /* allow to touch GPIO1 (for mute control) */ | ||
4346 | {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, | ||
4347 | {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, | ||
4348 | {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */ | ||
4349 | { } /* end */ | ||
4350 | }; | ||
4351 | |||
4352 | static const struct hda_verb ad1884a_mobile_verbs[] = { | ||
4353 | /* DACs; unmute as default */ | ||
4354 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4355 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4356 | /* Port-A (HP) mixer - route only from analog mixer */ | ||
4357 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4358 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4359 | /* Port-A pin */ | ||
4360 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4361 | /* Port-A (HP) pin - always unmuted */ | ||
4362 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4363 | /* Port-B (mic jack) pin */ | ||
4364 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4365 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ | ||
4366 | /* Port-C (int mic) pin */ | ||
4367 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4368 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ | ||
4369 | /* Port-F (int speaker) mixer - route only from analog mixer */ | ||
4370 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4371 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4372 | /* Port-F pin */ | ||
4373 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4374 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4375 | /* Analog mixer; mute as default */ | ||
4376 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4377 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
4378 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
4379 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
4380 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
4381 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
4382 | /* Analog Mix output amp */ | ||
4383 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4384 | /* capture sources */ | ||
4385 | /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */ | ||
4386 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4387 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
4388 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4389 | /* unsolicited event for pin-sense */ | ||
4390 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
4391 | {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, | ||
4392 | /* allow to touch GPIO1 (for mute control) */ | ||
4393 | {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, | ||
4394 | {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, | ||
4395 | {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */ | ||
4396 | { } /* end */ | ||
4397 | }; | ||
4398 | |||
4399 | /* | ||
4400 | * Thinkpad X300 | ||
4401 | * 0x11 - HP | ||
4402 | * 0x12 - speaker | ||
4403 | * 0x14 - mic-in | ||
4404 | * 0x17 - built-in mic | ||
4405 | */ | ||
4406 | |||
4407 | static const struct hda_verb ad1984a_thinkpad_verbs[] = { | ||
4408 | /* HP unmute */ | ||
4409 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4410 | /* analog mix */ | ||
4411 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
4412 | /* turn on EAPD */ | ||
4413 | {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, | ||
4414 | /* unsolicited event for pin-sense */ | ||
4415 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
4416 | /* internal mic - dmic */ | ||
4417 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
4418 | /* set magic COEFs for dmic */ | ||
4419 | {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7}, | ||
4420 | {0x01, AC_VERB_SET_PROC_COEF, 0x08}, | ||
4421 | { } /* end */ | ||
4422 | }; | ||
4423 | |||
4424 | static const struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = { | ||
4425 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
4426 | HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
4427 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
4428 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
4429 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
4430 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
4431 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT), | ||
4432 | HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT), | ||
4433 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4434 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4435 | { | ||
4436 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4437 | .name = "Capture Source", | ||
4438 | .info = ad198x_mux_enum_info, | ||
4439 | .get = ad198x_mux_enum_get, | ||
4440 | .put = ad198x_mux_enum_put, | ||
4441 | }, | ||
4442 | { } /* end */ | ||
4443 | }; | ||
4444 | |||
4445 | static const struct hda_input_mux ad1984a_thinkpad_capture_source = { | ||
4446 | .num_items = 3, | ||
4447 | .items = { | ||
4448 | { "Mic", 0x0 }, | ||
4449 | { "Internal Mic", 0x5 }, | ||
4450 | { "Mix", 0x3 }, | ||
4451 | }, | ||
4452 | }; | ||
4453 | |||
4454 | /* mute internal speaker if HP is plugged */ | ||
4455 | static void ad1984a_thinkpad_automute(struct hda_codec *codec) | ||
4456 | { | ||
4457 | unsigned int present; | ||
4458 | |||
4459 | present = snd_hda_jack_detect(codec, 0x11); | ||
4460 | snd_hda_codec_amp_stereo(codec, 0x12, HDA_OUTPUT, 0, | ||
4461 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
4462 | } | ||
4463 | |||
4464 | /* unsolicited event for HP jack sensing */ | ||
4465 | static void ad1984a_thinkpad_unsol_event(struct hda_codec *codec, | ||
4466 | unsigned int res) | ||
4467 | { | ||
4468 | if ((res >> 26) != AD1884A_HP_EVENT) | ||
4469 | return; | ||
4470 | ad1984a_thinkpad_automute(codec); | ||
4471 | } | ||
4472 | |||
4473 | /* initialize jack-sensing, too */ | ||
4474 | static int ad1984a_thinkpad_init(struct hda_codec *codec) | ||
4475 | { | ||
4476 | ad198x_init(codec); | ||
4477 | ad1984a_thinkpad_automute(codec); | ||
4478 | return 0; | ||
4479 | } | ||
4480 | |||
4481 | /* | ||
4482 | * Precision R5500 | ||
4483 | * 0x12 - HP/line-out | ||
4484 | * 0x13 - speaker (mono) | ||
4485 | * 0x15 - mic-in | ||
4486 | */ | ||
4487 | |||
4488 | static const struct hda_verb ad1984a_precision_verbs[] = { | ||
4489 | /* Unmute main output path */ | ||
4490 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4491 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x1f}, /* 0dB */ | ||
4492 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) + 0x17}, /* 0dB */ | ||
4493 | /* Analog mixer; mute as default */ | ||
4494 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4495 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
4496 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
4497 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
4498 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
4499 | /* Select mic as input */ | ||
4500 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
4501 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x27}, /* 0dB */ | ||
4502 | /* Configure as mic */ | ||
4503 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4504 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ | ||
4505 | /* HP unmute */ | ||
4506 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4507 | /* turn on EAPD */ | ||
4508 | {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, | ||
4509 | /* unsolicited event for pin-sense */ | ||
4510 | {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
4511 | { } /* end */ | ||
4512 | }; | ||
4513 | |||
4514 | static const struct snd_kcontrol_new ad1984a_precision_mixers[] = { | ||
4515 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
4516 | HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
4517 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
4518 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
4519 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
4520 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
4521 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT), | ||
4522 | HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
4523 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
4524 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4525 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4526 | { } /* end */ | ||
4527 | }; | ||
4528 | |||
4529 | |||
4530 | /* mute internal speaker if HP is plugged */ | ||
4531 | static void ad1984a_precision_automute(struct hda_codec *codec) | ||
4532 | { | ||
4533 | unsigned int present; | ||
4534 | |||
4535 | present = snd_hda_jack_detect(codec, 0x12); | ||
4536 | snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0, | ||
4537 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
4538 | } | ||
4539 | |||
4540 | |||
4541 | /* unsolicited event for HP jack sensing */ | ||
4542 | static void ad1984a_precision_unsol_event(struct hda_codec *codec, | ||
4543 | unsigned int res) | ||
4544 | { | ||
4545 | if ((res >> 26) != AD1884A_HP_EVENT) | ||
4546 | return; | ||
4547 | ad1984a_precision_automute(codec); | ||
4548 | } | ||
4549 | |||
4550 | /* initialize jack-sensing, too */ | ||
4551 | static int ad1984a_precision_init(struct hda_codec *codec) | ||
4552 | { | ||
4553 | ad198x_init(codec); | ||
4554 | ad1984a_precision_automute(codec); | ||
4555 | return 0; | ||
4556 | } | ||
4557 | |||
4558 | |||
4559 | /* | ||
4560 | * HP Touchsmart | ||
4561 | * port-A (0x11) - front hp-out | ||
4562 | * port-B (0x14) - unused | ||
4563 | * port-C (0x15) - unused | ||
4564 | * port-D (0x12) - rear line out | ||
4565 | * port-E (0x1c) - front mic-in | ||
4566 | * port-F (0x16) - Internal speakers | ||
4567 | * digital-mic (0x17) - Internal mic | ||
4568 | */ | ||
4569 | |||
4570 | static const struct hda_verb ad1984a_touchsmart_verbs[] = { | ||
4571 | /* DACs; unmute as default */ | ||
4572 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4573 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4574 | /* Port-A (HP) mixer - route only from analog mixer */ | ||
4575 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4576 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4577 | /* Port-A pin */ | ||
4578 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4579 | /* Port-A (HP) pin - always unmuted */ | ||
4580 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4581 | /* Port-E (int speaker) mixer - route only from analog mixer */ | ||
4582 | {0x25, AC_VERB_SET_AMP_GAIN_MUTE, 0x03}, | ||
4583 | /* Port-E pin */ | ||
4584 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
4585 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4586 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4587 | /* Port-F (int speaker) mixer - route only from analog mixer */ | ||
4588 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4589 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4590 | /* Port-F pin */ | ||
4591 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4592 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4593 | /* Analog mixer; mute as default */ | ||
4594 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4595 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
4596 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
4597 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
4598 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
4599 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
4600 | /* Analog Mix output amp */ | ||
4601 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4602 | /* capture sources */ | ||
4603 | /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */ | ||
4604 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4605 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
4606 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4607 | /* unsolicited event for pin-sense */ | ||
4608 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
4609 | {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, | ||
4610 | /* allow to touch GPIO1 (for mute control) */ | ||
4611 | {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, | ||
4612 | {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, | ||
4613 | {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */ | ||
4614 | /* internal mic - dmic */ | ||
4615 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
4616 | /* set magic COEFs for dmic */ | ||
4617 | {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7}, | ||
4618 | {0x01, AC_VERB_SET_PROC_COEF, 0x08}, | ||
4619 | { } /* end */ | ||
4620 | }; | ||
4621 | |||
4622 | static const struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = { | ||
4623 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
4624 | /* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ | ||
4625 | { | ||
4626 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4627 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
4628 | .name = "Master Playback Switch", | ||
4629 | .info = snd_hda_mixer_amp_switch_info, | ||
4630 | .get = snd_hda_mixer_amp_switch_get, | ||
4631 | .put = ad1884a_mobile_master_sw_put, | ||
4632 | .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), | ||
4633 | }, | ||
4634 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
4635 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
4636 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4637 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4638 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), | ||
4639 | HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT), | ||
4640 | { } /* end */ | ||
4641 | }; | ||
4642 | |||
4643 | /* switch to external mic if plugged */ | ||
4644 | static void ad1984a_touchsmart_automic(struct hda_codec *codec) | ||
4645 | { | ||
4646 | if (snd_hda_jack_detect(codec, 0x1c)) | ||
4647 | snd_hda_codec_write(codec, 0x0c, 0, | ||
4648 | AC_VERB_SET_CONNECT_SEL, 0x4); | ||
4649 | else | ||
4650 | snd_hda_codec_write(codec, 0x0c, 0, | ||
4651 | AC_VERB_SET_CONNECT_SEL, 0x5); | ||
4652 | } | ||
4653 | |||
4654 | |||
4655 | /* unsolicited event for HP jack sensing */ | ||
4656 | static void ad1984a_touchsmart_unsol_event(struct hda_codec *codec, | ||
4657 | unsigned int res) | ||
4658 | { | ||
4659 | switch (res >> 26) { | ||
4660 | case AD1884A_HP_EVENT: | ||
4661 | ad1884a_hp_automute(codec); | ||
4662 | break; | ||
4663 | case AD1884A_MIC_EVENT: | ||
4664 | ad1984a_touchsmart_automic(codec); | ||
4665 | break; | ||
4666 | } | ||
4667 | } | ||
4668 | |||
4669 | /* initialize jack-sensing, too */ | ||
4670 | static int ad1984a_touchsmart_init(struct hda_codec *codec) | ||
4671 | { | ||
4672 | ad198x_init(codec); | ||
4673 | ad1884a_hp_automute(codec); | ||
4674 | ad1984a_touchsmart_automic(codec); | ||
4675 | return 0; | ||
4676 | } | ||
4677 | |||
4678 | |||
4679 | /* | ||
4680 | */ | ||
4681 | |||
4682 | enum { | ||
4683 | AD1884A_AUTO, | ||
4684 | AD1884A_DESKTOP, | ||
4685 | AD1884A_LAPTOP, | ||
4686 | AD1884A_MOBILE, | ||
4687 | AD1884A_THINKPAD, | ||
4688 | AD1984A_TOUCHSMART, | ||
4689 | AD1984A_PRECISION, | ||
4690 | AD1884A_MODELS | ||
4691 | }; | ||
4692 | |||
4693 | static const char * const ad1884a_models[AD1884A_MODELS] = { | ||
4694 | [AD1884A_AUTO] = "auto", | ||
4695 | [AD1884A_DESKTOP] = "desktop", | ||
4696 | [AD1884A_LAPTOP] = "laptop", | ||
4697 | [AD1884A_MOBILE] = "mobile", | ||
4698 | [AD1884A_THINKPAD] = "thinkpad", | ||
4699 | [AD1984A_TOUCHSMART] = "touchsmart", | ||
4700 | [AD1984A_PRECISION] = "precision", | ||
4701 | }; | ||
4702 | |||
4703 | static const struct snd_pci_quirk ad1884a_cfg_tbl[] = { | ||
4704 | SND_PCI_QUIRK(0x1028, 0x04ac, "Precision R5500", AD1984A_PRECISION), | ||
4705 | SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE), | ||
4706 | SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP), | ||
4707 | SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE), | ||
4708 | SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x3070, "HP", AD1884A_MOBILE), | ||
4709 | SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30d0, "HP laptop", AD1884A_LAPTOP), | ||
4710 | SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP), | ||
4711 | SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP), | ||
4712 | SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x7010, "HP laptop", AD1884A_MOBILE), | ||
4713 | SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD), | ||
4714 | SND_PCI_QUIRK(0x103c, 0x2a82, "Touchsmart", AD1984A_TOUCHSMART), | ||
4715 | {} | ||
4716 | }; | ||
4717 | |||
4718 | static int patch_ad1884a(struct hda_codec *codec) | ||
4719 | { | ||
4720 | struct ad198x_spec *spec; | ||
4721 | int err, board_config; | ||
4722 | |||
4723 | board_config = snd_hda_check_board_config(codec, AD1884A_MODELS, | ||
4724 | ad1884a_models, | ||
4725 | ad1884a_cfg_tbl); | ||
4726 | if (board_config < 0) { | ||
4727 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
4728 | codec->chip_name); | ||
4729 | board_config = AD1884A_AUTO; | ||
4730 | } | ||
4731 | |||
4732 | if (board_config == AD1884A_AUTO) | ||
4733 | return ad1884_parse_auto_config(codec); | ||
4734 | |||
4735 | err = alloc_ad_spec(codec); | ||
4736 | if (err < 0) | ||
4737 | return err; | ||
4738 | spec = codec->spec; | ||
4739 | |||
4740 | err = snd_hda_attach_beep_device(codec, 0x10); | ||
4741 | if (err < 0) { | ||
4742 | ad198x_free(codec); | ||
4743 | return err; | ||
4744 | } | ||
4745 | set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); | ||
4746 | |||
4747 | spec->multiout.max_channels = 2; | ||
4748 | spec->multiout.num_dacs = ARRAY_SIZE(ad1884a_dac_nids); | ||
4749 | spec->multiout.dac_nids = ad1884a_dac_nids; | ||
4750 | spec->multiout.dig_out_nid = AD1884A_SPDIF_OUT; | ||
4751 | spec->num_adc_nids = ARRAY_SIZE(ad1884a_adc_nids); | ||
4752 | spec->adc_nids = ad1884a_adc_nids; | ||
4753 | spec->capsrc_nids = ad1884a_capsrc_nids; | ||
4754 | spec->input_mux = &ad1884a_capture_source; | ||
4755 | spec->num_mixers = 1; | ||
4756 | spec->mixers[0] = ad1884a_base_mixers; | ||
4757 | spec->num_init_verbs = 1; | ||
4758 | spec->init_verbs[0] = ad1884a_init_verbs; | ||
4759 | spec->spdif_route = 0; | ||
4760 | #ifdef CONFIG_PM | ||
4761 | spec->loopback.amplist = ad1884a_loopbacks; | ||
4762 | #endif | ||
4763 | codec->patch_ops = ad198x_patch_ops; | ||
4764 | |||
4765 | /* override some parameters */ | ||
4766 | switch (board_config) { | ||
4767 | case AD1884A_LAPTOP: | ||
4768 | spec->mixers[0] = ad1884a_laptop_mixers; | ||
4769 | spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs; | ||
4770 | spec->multiout.dig_out_nid = 0; | ||
4771 | codec->patch_ops.unsol_event = ad1884a_laptop_unsol_event; | ||
4772 | codec->patch_ops.init = ad1884a_laptop_init; | ||
4773 | /* set the upper-limit for mixer amp to 0dB for avoiding the | ||
4774 | * possible damage by overloading | ||
4775 | */ | ||
4776 | snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT, | ||
4777 | (0x17 << AC_AMPCAP_OFFSET_SHIFT) | | ||
4778 | (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||
4779 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
4780 | (1 << AC_AMPCAP_MUTE_SHIFT)); | ||
4781 | break; | ||
4782 | case AD1884A_MOBILE: | ||
4783 | spec->mixers[0] = ad1884a_mobile_mixers; | ||
4784 | spec->init_verbs[0] = ad1884a_mobile_verbs; | ||
4785 | spec->multiout.dig_out_nid = 0; | ||
4786 | codec->patch_ops.unsol_event = ad1884a_hp_unsol_event; | ||
4787 | codec->patch_ops.init = ad1884a_hp_init; | ||
4788 | /* set the upper-limit for mixer amp to 0dB for avoiding the | ||
4789 | * possible damage by overloading | ||
4790 | */ | ||
4791 | snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT, | ||
4792 | (0x17 << AC_AMPCAP_OFFSET_SHIFT) | | ||
4793 | (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||
4794 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
4795 | (1 << AC_AMPCAP_MUTE_SHIFT)); | ||
4796 | break; | ||
4797 | case AD1884A_THINKPAD: | ||
4798 | spec->mixers[0] = ad1984a_thinkpad_mixers; | ||
4799 | spec->init_verbs[spec->num_init_verbs++] = | ||
4800 | ad1984a_thinkpad_verbs; | ||
4801 | spec->multiout.dig_out_nid = 0; | ||
4802 | spec->input_mux = &ad1984a_thinkpad_capture_source; | ||
4803 | codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event; | ||
4804 | codec->patch_ops.init = ad1984a_thinkpad_init; | ||
4805 | break; | ||
4806 | case AD1984A_PRECISION: | ||
4807 | spec->mixers[0] = ad1984a_precision_mixers; | ||
4808 | spec->init_verbs[spec->num_init_verbs++] = | ||
4809 | ad1984a_precision_verbs; | ||
4810 | spec->multiout.dig_out_nid = 0; | ||
4811 | codec->patch_ops.unsol_event = ad1984a_precision_unsol_event; | ||
4812 | codec->patch_ops.init = ad1984a_precision_init; | ||
4813 | break; | ||
4814 | case AD1984A_TOUCHSMART: | ||
4815 | spec->mixers[0] = ad1984a_touchsmart_mixers; | ||
4816 | spec->init_verbs[0] = ad1984a_touchsmart_verbs; | ||
4817 | spec->multiout.dig_out_nid = 0; | ||
4818 | codec->patch_ops.unsol_event = ad1984a_touchsmart_unsol_event; | ||
4819 | codec->patch_ops.init = ad1984a_touchsmart_init; | ||
4820 | /* set the upper-limit for mixer amp to 0dB for avoiding the | ||
4821 | * possible damage by overloading | ||
4822 | */ | ||
4823 | snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT, | ||
4824 | (0x17 << AC_AMPCAP_OFFSET_SHIFT) | | ||
4825 | (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||
4826 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
4827 | (1 << AC_AMPCAP_MUTE_SHIFT)); | ||
4828 | break; | ||
4829 | } | ||
4830 | |||
4831 | codec->no_trigger_sense = 1; | ||
4832 | codec->no_sticky_stream = 1; | ||
4833 | |||
4834 | return 0; | ||
4835 | } | ||
4836 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
4837 | #define patch_ad1884a ad1884_parse_auto_config | ||
4838 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
4839 | |||
4840 | |||
4841 | /* | 1049 | /* |
4842 | * AD1882 / AD1882A | 1050 | * AD1882 / AD1882A |
4843 | * | 1051 | * |
@@ -4850,299 +1058,7 @@ static int patch_ad1884a(struct hda_codec *codec) | |||
4850 | * port-G - rear clfe-out (6stack) | 1058 | * port-G - rear clfe-out (6stack) |
4851 | */ | 1059 | */ |
4852 | 1060 | ||
4853 | #ifdef ENABLE_AD_STATIC_QUIRKS | 1061 | static int patch_ad1882(struct hda_codec *codec) |
4854 | static const hda_nid_t ad1882_dac_nids[3] = { | ||
4855 | 0x04, 0x03, 0x05 | ||
4856 | }; | ||
4857 | |||
4858 | static const hda_nid_t ad1882_adc_nids[2] = { | ||
4859 | 0x08, 0x09, | ||
4860 | }; | ||
4861 | |||
4862 | static const hda_nid_t ad1882_capsrc_nids[2] = { | ||
4863 | 0x0c, 0x0d, | ||
4864 | }; | ||
4865 | |||
4866 | #define AD1882_SPDIF_OUT 0x02 | ||
4867 | |||
4868 | /* list: 0x11, 0x39, 0x3a, 0x18, 0x3c, 0x3b, 0x12, 0x20 */ | ||
4869 | static const struct hda_input_mux ad1882_capture_source = { | ||
4870 | .num_items = 5, | ||
4871 | .items = { | ||
4872 | { "Front Mic", 0x1 }, | ||
4873 | { "Mic", 0x4 }, | ||
4874 | { "Line", 0x2 }, | ||
4875 | { "CD", 0x3 }, | ||
4876 | { "Mix", 0x7 }, | ||
4877 | }, | ||
4878 | }; | ||
4879 | |||
4880 | /* list: 0x11, 0x39, 0x3a, 0x3c, 0x18, 0x1f, 0x12, 0x20 */ | ||
4881 | static const struct hda_input_mux ad1882a_capture_source = { | ||
4882 | .num_items = 5, | ||
4883 | .items = { | ||
4884 | { "Front Mic", 0x1 }, | ||
4885 | { "Mic", 0x4}, | ||
4886 | { "Line", 0x2 }, | ||
4887 | { "Digital Mic", 0x06 }, | ||
4888 | { "Mix", 0x7 }, | ||
4889 | }, | ||
4890 | }; | ||
4891 | |||
4892 | static const struct snd_kcontrol_new ad1882_base_mixers[] = { | ||
4893 | HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
4894 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
4895 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT), | ||
4896 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT), | ||
4897 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
4898 | HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
4899 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), | ||
4900 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), | ||
4901 | |||
4902 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT), | ||
4903 | HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), | ||
4904 | HDA_CODEC_VOLUME("Line-In Boost Volume", 0x3a, 0x0, HDA_OUTPUT), | ||
4905 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4906 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4907 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
4908 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
4909 | { | ||
4910 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4911 | /* The multiple "Capture Source" controls confuse alsamixer | ||
4912 | * So call somewhat different.. | ||
4913 | */ | ||
4914 | /* .name = "Capture Source", */ | ||
4915 | .name = "Input Source", | ||
4916 | .count = 2, | ||
4917 | .info = ad198x_mux_enum_info, | ||
4918 | .get = ad198x_mux_enum_get, | ||
4919 | .put = ad198x_mux_enum_put, | ||
4920 | }, | ||
4921 | /* SPDIF controls */ | ||
4922 | HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
4923 | { | ||
4924 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4925 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
4926 | /* identical with ad1983 */ | ||
4927 | .info = ad1983_spdif_route_info, | ||
4928 | .get = ad1983_spdif_route_get, | ||
4929 | .put = ad1983_spdif_route_put, | ||
4930 | }, | ||
4931 | { } /* end */ | ||
4932 | }; | ||
4933 | |||
4934 | static const struct snd_kcontrol_new ad1882_loopback_mixers[] = { | ||
4935 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
4936 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
4937 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
4938 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
4939 | HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT), | ||
4940 | HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT), | ||
4941 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT), | ||
4942 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT), | ||
4943 | { } /* end */ | ||
4944 | }; | ||
4945 | |||
4946 | static const struct snd_kcontrol_new ad1882a_loopback_mixers[] = { | ||
4947 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
4948 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
4949 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT), | ||
4950 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT), | ||
4951 | HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
4952 | HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
4953 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT), | ||
4954 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT), | ||
4955 | HDA_CODEC_VOLUME("Digital Mic Boost Volume", 0x1f, 0x0, HDA_INPUT), | ||
4956 | { } /* end */ | ||
4957 | }; | ||
4958 | |||
4959 | static const struct snd_kcontrol_new ad1882_3stack_mixers[] = { | ||
4960 | HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
4961 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT), | ||
4962 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x17, 2, 0x0, HDA_OUTPUT), | ||
4963 | { | ||
4964 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4965 | .name = "Channel Mode", | ||
4966 | .info = ad198x_ch_mode_info, | ||
4967 | .get = ad198x_ch_mode_get, | ||
4968 | .put = ad198x_ch_mode_put, | ||
4969 | }, | ||
4970 | { } /* end */ | ||
4971 | }; | ||
4972 | |||
4973 | /* simple auto-mute control for AD1882 3-stack board */ | ||
4974 | #define AD1882_HP_EVENT 0x01 | ||
4975 | |||
4976 | static void ad1882_3stack_automute(struct hda_codec *codec) | ||
4977 | { | ||
4978 | bool mute = snd_hda_jack_detect(codec, 0x11); | ||
4979 | snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
4980 | mute ? 0 : PIN_OUT); | ||
4981 | } | ||
4982 | |||
4983 | static int ad1882_3stack_automute_init(struct hda_codec *codec) | ||
4984 | { | ||
4985 | ad198x_init(codec); | ||
4986 | ad1882_3stack_automute(codec); | ||
4987 | return 0; | ||
4988 | } | ||
4989 | |||
4990 | static void ad1882_3stack_unsol_event(struct hda_codec *codec, unsigned int res) | ||
4991 | { | ||
4992 | switch (res >> 26) { | ||
4993 | case AD1882_HP_EVENT: | ||
4994 | ad1882_3stack_automute(codec); | ||
4995 | break; | ||
4996 | } | ||
4997 | } | ||
4998 | |||
4999 | static const struct snd_kcontrol_new ad1882_6stack_mixers[] = { | ||
5000 | HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT), | ||
5001 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT), | ||
5002 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x24, 2, 0x0, HDA_OUTPUT), | ||
5003 | { } /* end */ | ||
5004 | }; | ||
5005 | |||
5006 | static const struct hda_verb ad1882_ch2_init[] = { | ||
5007 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
5008 | {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5009 | {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
5010 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
5011 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5012 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
5013 | { } /* end */ | ||
5014 | }; | ||
5015 | |||
5016 | static const struct hda_verb ad1882_ch4_init[] = { | ||
5017 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
5018 | {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5019 | {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5020 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
5021 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5022 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
5023 | { } /* end */ | ||
5024 | }; | ||
5025 | |||
5026 | static const struct hda_verb ad1882_ch6_init[] = { | ||
5027 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
5028 | {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5029 | {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5030 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
5031 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5032 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5033 | { } /* end */ | ||
5034 | }; | ||
5035 | |||
5036 | static const struct hda_channel_mode ad1882_modes[3] = { | ||
5037 | { 2, ad1882_ch2_init }, | ||
5038 | { 4, ad1882_ch4_init }, | ||
5039 | { 6, ad1882_ch6_init }, | ||
5040 | }; | ||
5041 | |||
5042 | /* | ||
5043 | * initialization verbs | ||
5044 | */ | ||
5045 | static const struct hda_verb ad1882_init_verbs[] = { | ||
5046 | /* DACs; mute as default */ | ||
5047 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
5048 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
5049 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
5050 | /* Port-A (HP) mixer */ | ||
5051 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5052 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5053 | /* Port-A pin */ | ||
5054 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
5055 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5056 | /* HP selector - select DAC2 */ | ||
5057 | {0x37, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
5058 | /* Port-D (Line-out) mixer */ | ||
5059 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5060 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5061 | /* Port-D pin */ | ||
5062 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
5063 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5064 | /* Mono-out mixer */ | ||
5065 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5066 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5067 | /* Mono-out pin */ | ||
5068 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
5069 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5070 | /* Port-B (front mic) pin */ | ||
5071 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
5072 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5073 | {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */ | ||
5074 | /* Port-C (line-in) pin */ | ||
5075 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
5076 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5077 | {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */ | ||
5078 | /* Port-C mixer - mute as input */ | ||
5079 | {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5080 | {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
5081 | /* Port-E (mic-in) pin */ | ||
5082 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
5083 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5084 | {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */ | ||
5085 | /* Port-E mixer - mute as input */ | ||
5086 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5087 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
5088 | /* Port-F (surround) */ | ||
5089 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
5090 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5091 | /* Port-G (CLFE) */ | ||
5092 | {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
5093 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5094 | /* Analog mixer; mute as default */ | ||
5095 | /* list: 0x39, 0x3a, 0x11, 0x12, 0x3c, 0x3b, 0x18, 0x1a */ | ||
5096 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5097 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
5098 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
5099 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
5100 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
5101 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
5102 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, | ||
5103 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, | ||
5104 | /* Analog Mix output amp */ | ||
5105 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ | ||
5106 | /* SPDIF output selector */ | ||
5107 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | ||
5108 | {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */ | ||
5109 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | ||
5110 | { } /* end */ | ||
5111 | }; | ||
5112 | |||
5113 | static const struct hda_verb ad1882_3stack_automute_verbs[] = { | ||
5114 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1882_HP_EVENT}, | ||
5115 | { } /* end */ | ||
5116 | }; | ||
5117 | |||
5118 | #ifdef CONFIG_PM | ||
5119 | static const struct hda_amp_list ad1882_loopbacks[] = { | ||
5120 | { 0x20, HDA_INPUT, 0 }, /* Front Mic */ | ||
5121 | { 0x20, HDA_INPUT, 1 }, /* Mic */ | ||
5122 | { 0x20, HDA_INPUT, 4 }, /* Line */ | ||
5123 | { 0x20, HDA_INPUT, 6 }, /* CD */ | ||
5124 | { } /* end */ | ||
5125 | }; | ||
5126 | #endif | ||
5127 | |||
5128 | /* models */ | ||
5129 | enum { | ||
5130 | AD1882_AUTO, | ||
5131 | AD1882_3STACK, | ||
5132 | AD1882_6STACK, | ||
5133 | AD1882_3STACK_AUTOMUTE, | ||
5134 | AD1882_MODELS | ||
5135 | }; | ||
5136 | |||
5137 | static const char * const ad1882_models[AD1986A_MODELS] = { | ||
5138 | [AD1882_AUTO] = "auto", | ||
5139 | [AD1882_3STACK] = "3stack", | ||
5140 | [AD1882_6STACK] = "6stack", | ||
5141 | [AD1882_3STACK_AUTOMUTE] = "3stack-automute", | ||
5142 | }; | ||
5143 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
5144 | |||
5145 | static int ad1882_parse_auto_config(struct hda_codec *codec) | ||
5146 | { | 1062 | { |
5147 | struct ad198x_spec *spec; | 1063 | struct ad198x_spec *spec; |
5148 | int err; | 1064 | int err; |
@@ -5169,110 +1085,20 @@ static int ad1882_parse_auto_config(struct hda_codec *codec) | |||
5169 | return err; | 1085 | return err; |
5170 | } | 1086 | } |
5171 | 1087 | ||
5172 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
5173 | static int patch_ad1882(struct hda_codec *codec) | ||
5174 | { | ||
5175 | struct ad198x_spec *spec; | ||
5176 | int err, board_config; | ||
5177 | |||
5178 | board_config = snd_hda_check_board_config(codec, AD1882_MODELS, | ||
5179 | ad1882_models, NULL); | ||
5180 | if (board_config < 0) { | ||
5181 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
5182 | codec->chip_name); | ||
5183 | board_config = AD1882_AUTO; | ||
5184 | } | ||
5185 | |||
5186 | if (board_config == AD1882_AUTO) | ||
5187 | return ad1882_parse_auto_config(codec); | ||
5188 | |||
5189 | err = alloc_ad_spec(codec); | ||
5190 | if (err < 0) | ||
5191 | return err; | ||
5192 | spec = codec->spec; | ||
5193 | |||
5194 | err = snd_hda_attach_beep_device(codec, 0x10); | ||
5195 | if (err < 0) { | ||
5196 | ad198x_free(codec); | ||
5197 | return err; | ||
5198 | } | ||
5199 | set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); | ||
5200 | |||
5201 | spec->multiout.max_channels = 6; | ||
5202 | spec->multiout.num_dacs = 3; | ||
5203 | spec->multiout.dac_nids = ad1882_dac_nids; | ||
5204 | spec->multiout.dig_out_nid = AD1882_SPDIF_OUT; | ||
5205 | spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids); | ||
5206 | spec->adc_nids = ad1882_adc_nids; | ||
5207 | spec->capsrc_nids = ad1882_capsrc_nids; | ||
5208 | if (codec->vendor_id == 0x11d41882) | ||
5209 | spec->input_mux = &ad1882_capture_source; | ||
5210 | else | ||
5211 | spec->input_mux = &ad1882a_capture_source; | ||
5212 | spec->num_mixers = 2; | ||
5213 | spec->mixers[0] = ad1882_base_mixers; | ||
5214 | if (codec->vendor_id == 0x11d41882) | ||
5215 | spec->mixers[1] = ad1882_loopback_mixers; | ||
5216 | else | ||
5217 | spec->mixers[1] = ad1882a_loopback_mixers; | ||
5218 | spec->num_init_verbs = 1; | ||
5219 | spec->init_verbs[0] = ad1882_init_verbs; | ||
5220 | spec->spdif_route = 0; | ||
5221 | #ifdef CONFIG_PM | ||
5222 | spec->loopback.amplist = ad1882_loopbacks; | ||
5223 | #endif | ||
5224 | spec->vmaster_nid = 0x04; | ||
5225 | |||
5226 | codec->patch_ops = ad198x_patch_ops; | ||
5227 | |||
5228 | /* override some parameters */ | ||
5229 | switch (board_config) { | ||
5230 | default: | ||
5231 | case AD1882_3STACK: | ||
5232 | case AD1882_3STACK_AUTOMUTE: | ||
5233 | spec->num_mixers = 3; | ||
5234 | spec->mixers[2] = ad1882_3stack_mixers; | ||
5235 | spec->channel_mode = ad1882_modes; | ||
5236 | spec->num_channel_mode = ARRAY_SIZE(ad1882_modes); | ||
5237 | spec->need_dac_fix = 1; | ||
5238 | spec->multiout.max_channels = 2; | ||
5239 | spec->multiout.num_dacs = 1; | ||
5240 | if (board_config != AD1882_3STACK) { | ||
5241 | spec->init_verbs[spec->num_init_verbs++] = | ||
5242 | ad1882_3stack_automute_verbs; | ||
5243 | codec->patch_ops.unsol_event = ad1882_3stack_unsol_event; | ||
5244 | codec->patch_ops.init = ad1882_3stack_automute_init; | ||
5245 | } | ||
5246 | break; | ||
5247 | case AD1882_6STACK: | ||
5248 | spec->num_mixers = 3; | ||
5249 | spec->mixers[2] = ad1882_6stack_mixers; | ||
5250 | break; | ||
5251 | } | ||
5252 | |||
5253 | codec->no_trigger_sense = 1; | ||
5254 | codec->no_sticky_stream = 1; | ||
5255 | |||
5256 | return 0; | ||
5257 | } | ||
5258 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
5259 | #define patch_ad1882 ad1882_parse_auto_config | ||
5260 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
5261 | |||
5262 | 1088 | ||
5263 | /* | 1089 | /* |
5264 | * patch entries | 1090 | * patch entries |
5265 | */ | 1091 | */ |
5266 | static const struct hda_codec_preset snd_hda_preset_analog[] = { | 1092 | static const struct hda_codec_preset snd_hda_preset_analog[] = { |
5267 | { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a }, | 1093 | { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884 }, |
5268 | { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 }, | 1094 | { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 }, |
5269 | { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a }, | 1095 | { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884 }, |
5270 | { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 }, | 1096 | { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 }, |
5271 | { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884a }, | 1097 | { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884 }, |
5272 | { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884a }, | 1098 | { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884 }, |
5273 | { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 }, | 1099 | { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 }, |
5274 | { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 }, | 1100 | { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 }, |
5275 | { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 }, | 1101 | { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1884 }, |
5276 | { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a }, | 1102 | { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a }, |
5277 | { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 }, | 1103 | { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 }, |
5278 | { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 }, | 1104 | { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 }, |