aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2013-07-05 08:14:14 -0400
committerTakashi Iwai <tiwai@suse.de>2013-07-05 08:14:14 -0400
commit632408adfe70be6706cb89522b0d5b3dce188d84 (patch)
treea5f7f53186d212806a228871f44b124bd1a0c0c9
parent0f7dbda0ec3bc4d778d7acf741b220fbf4318a20 (diff)
ALSA: hda - Remove static quirks for AD1986A codec
Finally all the static quirks in patch_analog.c are reduced by this patch. As machines with AD1986A codec are all old and often their BIOS are buggy, we need to keep at least a few static pin conifgs. Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/pci/hda/patch_analog.c1069
1 files changed, 57 insertions, 1012 deletions
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 3b23280ff3a6..0cbdd87dde6d 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -32,7 +32,6 @@
32#include "hda_jack.h" 32#include "hda_jack.h"
33#include "hda_generic.h" 33#include "hda_generic.h"
34 34
35#define ENABLE_AD_STATIC_QUIRKS
36 35
37struct ad198x_spec { 36struct ad198x_spec {
38 struct hda_gen_spec gen; 37 struct hda_gen_spec gen;
@@ -43,114 +42,8 @@ struct ad198x_spec {
43 hda_nid_t eapd_nid; 42 hda_nid_t eapd_nid;
44 43
45 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */ 44 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
46
47#ifdef ENABLE_AD_STATIC_QUIRKS
48 const struct snd_kcontrol_new *mixers[6];
49 int num_mixers;
50 const struct hda_verb *init_verbs[6]; /* initialization verbs
51 * don't forget NULL termination!
52 */
53 unsigned int num_init_verbs;
54
55 /* playback */
56 struct hda_multi_out multiout; /* playback set-up
57 * max_channels, dacs must be set
58 * dig_out_nid and hp_nid are optional
59 */
60 unsigned int cur_eapd;
61 unsigned int need_dac_fix;
62
63 /* capture */
64 unsigned int num_adc_nids;
65 const hda_nid_t *adc_nids;
66 hda_nid_t dig_in_nid; /* digital-in NID; optional */
67
68 /* capture source */
69 const struct hda_input_mux *input_mux;
70 const hda_nid_t *capsrc_nids;
71 unsigned int cur_mux[3];
72
73 /* channel model */
74 const struct hda_channel_mode *channel_mode;
75 int num_channel_mode;
76
77 /* PCM information */
78 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
79
80 unsigned int spdif_route;
81
82 unsigned int jack_present: 1;
83 unsigned int inv_jack_detect: 1;/* inverted jack-detection */
84 unsigned int analog_beep: 1; /* analog beep input present */
85 unsigned int avoid_init_slave_vol:1;
86
87#ifdef CONFIG_PM
88 struct hda_loopback_check loopback;
89#endif
90 /* for virtual master */
91 hda_nid_t vmaster_nid;
92 const char * const *slave_vols;
93 const char * const *slave_sws;
94#endif /* ENABLE_AD_STATIC_QUIRKS */
95}; 45};
96 46
97#ifdef ENABLE_AD_STATIC_QUIRKS
98/*
99 * input MUX handling (common part)
100 */
101static 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
109static 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
119static 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 */
133static 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
143static const char * const ad_slave_pfxs[] = {
144 "Front", "Surround", "Center", "LFE", "Side",
145 "Headphone", "Mono", "Speaker", "IEC958",
146 NULL
147};
148
149static 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
163static 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
203static 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
286static 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 */
296static 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
305static 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
316static 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 */
327static 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
335static 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
343static 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
354static 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 */
365static 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
377static 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 */
388static 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
400static 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
411static 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
424static 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
431static 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
465static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front, 89static 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
510static 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
523static int ad198x_suspend(struct hda_codec *codec) 135static 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
531static 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
550static 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
562static 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
581static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
582 struct snd_ctl_elem_info *uinfo);
583static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
584 struct snd_ctl_elem_value *ucontrol);
585static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
586 struct snd_ctl_elem_value *ucontrol);
587#endif /* ENABLE_AD_STATIC_QUIRKS */
588
589 142
590/* 143/*
591 * Automatic parse of I/O pins from the BIOS configuration 144 * Automatic parse of I/O pins from the BIOS configuration
@@ -646,446 +199,6 @@ static int ad198x_parse_auto_config(struct hda_codec *codec)
646 * AD1986A specific 199 * AD1986A specific
647 */ 200 */
648 201
649#ifdef ENABLE_AD_STATIC_QUIRKS
650#define AD1986A_SPDIF_OUT 0x02
651#define AD1986A_FRONT_DAC 0x03
652#define AD1986A_SURR_DAC 0x04
653#define AD1986A_CLFE_DAC 0x05
654#define AD1986A_ADC 0x06
655
656static const hda_nid_t ad1986a_dac_nids[3] = {
657 AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC
658};
659static const hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC };
660static const hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 };
661
662static 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
676static 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
686static 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 */
699static 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 */
740static 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 */
752static const hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC };
753
754/* master controls both pins 0x1a and 0x1b */
755static 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
764static 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
773static 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
804static 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
813static const struct hda_input_mux ad1986a_automic_capture_source = {
814 .num_items = 2,
815 .items = {
816 { "Mic", 0x0 },
817 { "Mix", 0x5 },
818 },
819};
820
821static 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
827static 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
854static const struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = {
855 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT),
856 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT),
857 { } /* end */
858};
859
860/* laptop-automute - 2ch only */
861
862static void ad1986a_update_hp(struct hda_codec *codec)
863{
864 struct ad198x_spec *spec = codec->spec;
865 unsigned int mute;
866
867 if (spec->jack_present)
868 mute = HDA_AMP_MUTE; /* mute internal speaker */
869 else
870 /* unmute internal speaker if necessary */
871 mute = snd_hda_codec_amp_read(codec, 0x1a, 0, HDA_OUTPUT, 0);
872 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
873 HDA_AMP_MUTE, mute);
874}
875
876static void ad1986a_hp_automute(struct hda_codec *codec)
877{
878 struct ad198x_spec *spec = codec->spec;
879
880 spec->jack_present = snd_hda_jack_detect(codec, 0x1a);
881 if (spec->inv_jack_detect)
882 spec->jack_present = !spec->jack_present;
883 ad1986a_update_hp(codec);
884}
885
886#define AD1986A_HP_EVENT 0x37
887
888static void ad1986a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
889{
890 if ((res >> 26) != AD1986A_HP_EVENT)
891 return;
892 ad1986a_hp_automute(codec);
893}
894
895static int ad1986a_hp_init(struct hda_codec *codec)
896{
897 ad198x_init(codec);
898 ad1986a_hp_automute(codec);
899 return 0;
900}
901
902/* bind hp and internal speaker mute (with plug check) */
903static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol,
904 struct snd_ctl_elem_value *ucontrol)
905{
906 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
907 int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
908 if (change)
909 ad1986a_update_hp(codec);
910 return change;
911}
912
913static const struct snd_kcontrol_new ad1986a_automute_master_mixers[] = {
914 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
915 {
916 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
917 .name = "Master Playback Switch",
918 .subdevice = HDA_SUBDEV_AMP_FLAG,
919 .info = snd_hda_mixer_amp_switch_info,
920 .get = snd_hda_mixer_amp_switch_get,
921 .put = ad1986a_hp_master_sw_put,
922 .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
923 },
924 { } /* end */
925};
926
927
928/*
929 * initialization verbs
930 */
931static const struct hda_verb ad1986a_init_verbs[] = {
932 /* Front, Surround, CLFE DAC; mute as default */
933 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
934 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
935 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
936 /* Downmix - off */
937 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
938 /* HP, Line-Out, Surround, CLFE selectors */
939 {0x0a, AC_VERB_SET_CONNECT_SEL, 0x0},
940 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0},
941 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
942 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
943 /* Mono selector */
944 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x0},
945 /* Mic selector: Mic 1/2 pin */
946 {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
947 /* Line-in selector: Line-in */
948 {0x10, AC_VERB_SET_CONNECT_SEL, 0x0},
949 /* Mic 1/2 swap */
950 {0x11, AC_VERB_SET_CONNECT_SEL, 0x0},
951 /* Record selector: mic */
952 {0x12, AC_VERB_SET_CONNECT_SEL, 0x0},
953 /* Mic, Phone, CD, Aux, Line-In amp; mute as default */
954 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
955 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
956 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
957 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
958 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
959 /* PC beep */
960 {0x18, AC_VERB_SET_CONNECT_SEL, 0x0},
961 /* HP, Line-Out, Surround, CLFE, Mono pins; mute as default */
962 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
963 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
964 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
965 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
966 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
967 /* HP Pin */
968 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
969 /* Front, Surround, CLFE Pins */
970 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
971 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
972 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
973 /* Mono Pin */
974 {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
975 /* Mic Pin */
976 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
977 /* Line, Aux, CD, Beep-In Pin */
978 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
979 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
980 {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
981 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
982 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
983 { } /* end */
984};
985
986static const struct hda_verb ad1986a_ch2_init[] = {
987 /* Surround out -> Line In */
988 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
989 /* Line-in selectors */
990 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x1 },
991 /* CLFE -> Mic in */
992 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
993 /* Mic selector, mix C/LFE (backmic) and Mic (frontmic) */
994 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
995 { } /* end */
996};
997
998static const struct hda_verb ad1986a_ch4_init[] = {
999 /* Surround out -> Surround */
1000 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1001 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
1002 /* CLFE -> Mic in */
1003 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1004 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
1005 { } /* end */
1006};
1007
1008static const struct hda_verb ad1986a_ch6_init[] = {
1009 /* Surround out -> Surround out */
1010 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1011 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
1012 /* CLFE -> CLFE */
1013 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1014 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x0 },
1015 { } /* end */
1016};
1017
1018static const struct hda_channel_mode ad1986a_modes[3] = {
1019 { 2, ad1986a_ch2_init },
1020 { 4, ad1986a_ch4_init },
1021 { 6, ad1986a_ch6_init },
1022};
1023
1024/* eapd initialization */
1025static const struct hda_verb ad1986a_eapd_init_verbs[] = {
1026 {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
1027 {}
1028};
1029
1030/* pin sensing on HP jack */
1031static const struct hda_verb ad1986a_hp_init_verbs[] = {
1032 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT},
1033 {}
1034};
1035
1036
1037/* models */
1038enum {
1039 AD1986A_AUTO,
1040 AD1986A_6STACK,
1041 AD1986A_3STACK,
1042 AD1986A_LAPTOP,
1043 AD1986A_LAPTOP_EAPD,
1044 AD1986A_LAPTOP_AUTOMUTE,
1045 AD1986A_MODELS
1046};
1047
1048static const char * const ad1986a_models[AD1986A_MODELS] = {
1049 [AD1986A_AUTO] = "auto",
1050 [AD1986A_6STACK] = "6stack",
1051 [AD1986A_3STACK] = "3stack",
1052 [AD1986A_LAPTOP] = "laptop",
1053 [AD1986A_LAPTOP_EAPD] = "laptop-eapd",
1054 [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute",
1055};
1056
1057static const struct snd_pci_quirk ad1986a_cfg_tbl[] = {
1058 SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD),
1059 SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK),
1060 SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP),
1061 SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK),
1062 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK),
1063 SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK),
1064 SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK),
1065 SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
1066 SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP),
1067 SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK),
1068 {}
1069};
1070
1071#ifdef CONFIG_PM
1072static const struct hda_amp_list ad1986a_loopbacks[] = {
1073 { 0x13, HDA_OUTPUT, 0 }, /* Mic */
1074 { 0x14, HDA_OUTPUT, 0 }, /* Phone */
1075 { 0x15, HDA_OUTPUT, 0 }, /* CD */
1076 { 0x16, HDA_OUTPUT, 0 }, /* Aux */
1077 { 0x17, HDA_OUTPUT, 0 }, /* Line */
1078 { } /* end */
1079};
1080#endif
1081
1082static int is_jack_available(struct hda_codec *codec, hda_nid_t nid)
1083{
1084 unsigned int conf = snd_hda_codec_get_pincfg(codec, nid);
1085 return get_defcfg_connect(conf) != AC_JACK_PORT_NONE;
1086}
1087#endif /* ENABLE_AD_STATIC_QUIRKS */
1088
1089static int alloc_ad_spec(struct hda_codec *codec) 202static int alloc_ad_spec(struct hda_codec *codec)
1090{ 203{
1091 struct ad198x_spec *spec; 204 struct ad198x_spec *spec;
@@ -1114,6 +227,9 @@ enum {
1114 AD1986A_FIXUP_INV_JACK_DETECT, 227 AD1986A_FIXUP_INV_JACK_DETECT,
1115 AD1986A_FIXUP_ULTRA, 228 AD1986A_FIXUP_ULTRA,
1116 AD1986A_FIXUP_SAMSUNG, 229 AD1986A_FIXUP_SAMSUNG,
230 AD1986A_FIXUP_3STACK,
231 AD1986A_FIXUP_LAPTOP,
232 AD1986A_FIXUP_LAPTOP_IMIC,
1117}; 233};
1118 234
1119static const struct hda_fixup ad1986a_fixups[] = { 235static const struct hda_fixup ad1986a_fixups[] = {
@@ -1139,18 +255,68 @@ static const struct hda_fixup ad1986a_fixups[] = {
1139 {} 255 {}
1140 }, 256 },
1141 }, 257 },
258 [AD1986A_FIXUP_3STACK] = {
259 .type = HDA_FIXUP_PINS,
260 .v.pins = (const struct hda_pintbl[]) {
261 { 0x1a, 0x02214021 }, /* headphone */
262 { 0x1b, 0x01014011 }, /* front */
263 { 0x1c, 0x01013012 }, /* surround */
264 { 0x1d, 0x01019015 }, /* clfe */
265 { 0x1e, 0x411111f0 }, /* N/A */
266 { 0x1f, 0x02a190f0 }, /* mic */
267 { 0x20, 0x018130f0 }, /* line-in */
268 {}
269 },
270 },
271 [AD1986A_FIXUP_LAPTOP] = {
272 .type = HDA_FIXUP_PINS,
273 .v.pins = (const struct hda_pintbl[]) {
274 { 0x1a, 0x02214021 }, /* headphone */
275 { 0x1b, 0x90170110 }, /* speaker */
276 { 0x1c, 0x411111f0 }, /* N/A */
277 { 0x1d, 0x411111f0 }, /* N/A */
278 { 0x1e, 0x411111f0 }, /* N/A */
279 { 0x1f, 0x02a191f0 }, /* mic */
280 { 0x20, 0x411111f0 }, /* N/A */
281 {}
282 },
283 },
284 [AD1986A_FIXUP_LAPTOP_IMIC] = {
285 .type = HDA_FIXUP_PINS,
286 .v.pins = (const struct hda_pintbl[]) {
287 { 0x1d, 0x90a7013e }, /* int mic */
288 {}
289 },
290 .chained_before = 1,
291 .chain_id = AD1986A_FIXUP_LAPTOP,
292 },
1142}; 293};
1143 294
1144static const struct snd_pci_quirk ad1986a_fixup_tbl[] = { 295static const struct snd_pci_quirk ad1986a_fixup_tbl[] = {
296 SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_FIXUP_LAPTOP_IMIC),
297 SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8100, "ASUS P5", AD1986A_FIXUP_3STACK),
298 SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8200, "ASUS M2", AD1986A_FIXUP_3STACK),
299 SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_FIXUP_3STACK),
300 SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_FIXUP_LAPTOP),
1145 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_FIXUP_SAMSUNG), 301 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_FIXUP_SAMSUNG),
1146 SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_FIXUP_ULTRA), 302 SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_FIXUP_ULTRA),
1147 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT), 303 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT),
304 SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_FIXUP_3STACK),
305 SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_FIXUP_3STACK),
306 {}
307};
308
309static const struct hda_model_fixup ad1986a_fixup_models[] = {
310 { .id = AD1986A_FIXUP_3STACK, .name = "3stack" },
311 { .id = AD1986A_FIXUP_LAPTOP, .name = "laptop" },
312 { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-imic" },
313 { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-eapd" }, /* alias */
1148 {} 314 {}
1149}; 315};
1150 316
1151/* 317/*
1152 */ 318 */
1153static int ad1986a_parse_auto_config(struct hda_codec *codec) 319static int patch_ad1986a(struct hda_codec *codec)
1154{ 320{
1155 int err; 321 int err;
1156 struct ad198x_spec *spec; 322 struct ad198x_spec *spec;
@@ -1175,7 +341,8 @@ static int ad1986a_parse_auto_config(struct hda_codec *codec)
1175 */ 341 */
1176 spec->gen.multiout.no_share_stream = 1; 342 spec->gen.multiout.no_share_stream = 1;
1177 343
1178 snd_hda_pick_fixup(codec, NULL, ad1986a_fixup_tbl, ad1986a_fixups); 344 snd_hda_pick_fixup(codec, ad1986a_fixup_models, ad1986a_fixup_tbl,
345 ad1986a_fixups);
1179 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); 346 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
1180 347
1181 err = ad198x_parse_auto_config(codec); 348 err = ad198x_parse_auto_config(codec);
@@ -1189,128 +356,6 @@ static int ad1986a_parse_auto_config(struct hda_codec *codec)
1189 return 0; 356 return 0;
1190} 357}
1191 358
1192#ifdef ENABLE_AD_STATIC_QUIRKS
1193static int patch_ad1986a(struct hda_codec *codec)
1194{
1195 struct ad198x_spec *spec;
1196 int err, board_config;
1197
1198 board_config = snd_hda_check_board_config(codec, AD1986A_MODELS,
1199 ad1986a_models,
1200 ad1986a_cfg_tbl);
1201 if (board_config < 0) {
1202 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
1203 codec->chip_name);
1204 board_config = AD1986A_AUTO;
1205 }
1206
1207 if (board_config == AD1986A_AUTO)
1208 return ad1986a_parse_auto_config(codec);
1209
1210 err = alloc_ad_spec(codec);
1211 if (err < 0)
1212 return err;
1213 spec = codec->spec;
1214
1215 err = snd_hda_attach_beep_device(codec, 0x19);
1216 if (err < 0) {
1217 ad198x_free(codec);
1218 return err;
1219 }
1220 set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);
1221
1222 spec->multiout.max_channels = 6;
1223 spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids);
1224 spec->multiout.dac_nids = ad1986a_dac_nids;
1225 spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT;
1226 spec->num_adc_nids = 1;
1227 spec->adc_nids = ad1986a_adc_nids;
1228 spec->capsrc_nids = ad1986a_capsrc_nids;
1229 spec->input_mux = &ad1986a_capture_source;
1230 spec->num_mixers = 1;
1231 spec->mixers[0] = ad1986a_mixers;
1232 spec->num_init_verbs = 1;
1233 spec->init_verbs[0] = ad1986a_init_verbs;
1234#ifdef CONFIG_PM
1235 spec->loopback.amplist = ad1986a_loopbacks;
1236#endif
1237 spec->vmaster_nid = 0x1b;
1238 codec->inv_eapd = 1; /* AD1986A has the inverted EAPD implementation */
1239
1240 codec->patch_ops = ad198x_patch_ops;
1241
1242 /* override some parameters */
1243 switch (board_config) {
1244 case AD1986A_3STACK:
1245 spec->num_mixers = 2;
1246 spec->mixers[1] = ad1986a_3st_mixers;
1247 spec->num_init_verbs = 2;
1248 spec->init_verbs[1] = ad1986a_ch2_init;
1249 spec->channel_mode = ad1986a_modes;
1250 spec->num_channel_mode = ARRAY_SIZE(ad1986a_modes);
1251 spec->need_dac_fix = 1;
1252 spec->multiout.max_channels = 2;
1253 spec->multiout.num_dacs = 1;
1254 break;
1255 case AD1986A_LAPTOP:
1256 spec->mixers[0] = ad1986a_laptop_mixers;
1257 spec->multiout.max_channels = 2;
1258 spec->multiout.num_dacs = 1;
1259 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1260 break;
1261 case AD1986A_LAPTOP_EAPD:
1262 spec->num_mixers = 3;
1263 spec->mixers[0] = ad1986a_laptop_master_mixers;
1264 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1265 spec->mixers[2] = ad1986a_laptop_intmic_mixers;
1266 spec->num_init_verbs = 2;
1267 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1268 spec->multiout.max_channels = 2;
1269 spec->multiout.num_dacs = 1;
1270 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1271 if (!is_jack_available(codec, 0x25))
1272 spec->multiout.dig_out_nid = 0;
1273 spec->input_mux = &ad1986a_laptop_eapd_capture_source;
1274 break;
1275 case AD1986A_LAPTOP_AUTOMUTE:
1276 spec->num_mixers = 3;
1277 spec->mixers[0] = ad1986a_automute_master_mixers;
1278 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1279 spec->mixers[2] = ad1986a_laptop_intmic_mixers;
1280 spec->num_init_verbs = 3;
1281 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1282 spec->init_verbs[2] = ad1986a_hp_init_verbs;
1283 spec->multiout.max_channels = 2;
1284 spec->multiout.num_dacs = 1;
1285 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1286 if (!is_jack_available(codec, 0x25))
1287 spec->multiout.dig_out_nid = 0;
1288 spec->input_mux = &ad1986a_laptop_eapd_capture_source;
1289 codec->patch_ops.unsol_event = ad1986a_hp_unsol_event;
1290 codec->patch_ops.init = ad1986a_hp_init;
1291 /* Lenovo N100 seems to report the reversed bit
1292 * for HP jack-sensing
1293 */
1294 spec->inv_jack_detect = 1;
1295 break;
1296 }
1297
1298 /* AD1986A has a hardware problem that it can't share a stream
1299 * with multiple output pins. The copy of front to surrounds
1300 * causes noisy or silent outputs at a certain timing, e.g.
1301 * changing the volume.
1302 * So, let's disable the shared stream.
1303 */
1304 spec->multiout.no_share_stream = 1;
1305
1306 codec->no_trigger_sense = 1;
1307 codec->no_sticky_stream = 1;
1308
1309 return 0;
1310}
1311#else /* ENABLE_AD_STATIC_QUIRKS */
1312#define patch_ad1986a ad1986a_parse_auto_config
1313#endif /* ENABLE_AD_STATIC_QUIRKS */
1314 359
1315/* 360/*
1316 * AD1983 specific 361 * AD1983 specific