diff options
Diffstat (limited to 'sound/pci/hda/patch_analog.c')
-rw-r--r-- | sound/pci/hda/patch_analog.c | 599 |
1 files changed, 529 insertions, 70 deletions
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 1ada1b075c9a..32401bd8c229 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -23,6 +23,8 @@ | |||
23 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <linux/pci.h> | 25 | #include <linux/pci.h> |
26 | #include <linux/mutex.h> | ||
27 | |||
26 | #include <sound/core.h> | 28 | #include <sound/core.h> |
27 | #include "hda_codec.h" | 29 | #include "hda_codec.h" |
28 | #include "hda_local.h" | 30 | #include "hda_local.h" |
@@ -60,7 +62,7 @@ struct ad198x_spec { | |||
60 | /* PCM information */ | 62 | /* PCM information */ |
61 | struct hda_pcm pcm_rec[2]; /* used in alc_build_pcms() */ | 63 | struct hda_pcm pcm_rec[2]; /* used in alc_build_pcms() */ |
62 | 64 | ||
63 | struct semaphore amp_mutex; /* PCM volume/mute control mutex */ | 65 | struct mutex amp_mutex; /* PCM volume/mute control mutex */ |
64 | unsigned int spdif_route; | 66 | unsigned int spdif_route; |
65 | 67 | ||
66 | /* dynamic controls, init_verbs and input_mux */ | 68 | /* dynamic controls, init_verbs and input_mux */ |
@@ -308,7 +310,7 @@ static int ad198x_resume(struct hda_codec *codec) | |||
308 | struct ad198x_spec *spec = codec->spec; | 310 | struct ad198x_spec *spec = codec->spec; |
309 | int i; | 311 | int i; |
310 | 312 | ||
311 | ad198x_init(codec); | 313 | codec->patch_ops.init(codec); |
312 | for (i = 0; i < spec->num_mixers; i++) | 314 | for (i = 0; i < spec->num_mixers; i++) |
313 | snd_hda_resume_ctls(codec, spec->mixers[i]); | 315 | snd_hda_resume_ctls(codec, spec->mixers[i]); |
314 | if (spec->multiout.dig_out_nid) | 316 | if (spec->multiout.dig_out_nid) |
@@ -331,6 +333,61 @@ static struct hda_codec_ops ad198x_patch_ops = { | |||
331 | 333 | ||
332 | 334 | ||
333 | /* | 335 | /* |
336 | * EAPD control | ||
337 | * the private value = nid | (invert << 8) | ||
338 | */ | ||
339 | static int ad198x_eapd_info(struct snd_kcontrol *kcontrol, | ||
340 | struct snd_ctl_elem_info *uinfo) | ||
341 | { | ||
342 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
343 | uinfo->count = 1; | ||
344 | uinfo->value.integer.min = 0; | ||
345 | uinfo->value.integer.max = 1; | ||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | static int ad198x_eapd_get(struct snd_kcontrol *kcontrol, | ||
350 | struct snd_ctl_elem_value *ucontrol) | ||
351 | { | ||
352 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
353 | struct ad198x_spec *spec = codec->spec; | ||
354 | int invert = (kcontrol->private_value >> 8) & 1; | ||
355 | if (invert) | ||
356 | ucontrol->value.integer.value[0] = ! spec->cur_eapd; | ||
357 | else | ||
358 | ucontrol->value.integer.value[0] = spec->cur_eapd; | ||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | static int ad198x_eapd_put(struct snd_kcontrol *kcontrol, | ||
363 | struct snd_ctl_elem_value *ucontrol) | ||
364 | { | ||
365 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
366 | struct ad198x_spec *spec = codec->spec; | ||
367 | int invert = (kcontrol->private_value >> 8) & 1; | ||
368 | hda_nid_t nid = kcontrol->private_value & 0xff; | ||
369 | unsigned int eapd; | ||
370 | eapd = ucontrol->value.integer.value[0]; | ||
371 | if (invert) | ||
372 | eapd = !eapd; | ||
373 | if (eapd == spec->cur_eapd && ! codec->in_resume) | ||
374 | return 0; | ||
375 | spec->cur_eapd = eapd; | ||
376 | snd_hda_codec_write(codec, nid, | ||
377 | 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
378 | eapd ? 0x02 : 0x00); | ||
379 | return 1; | ||
380 | } | ||
381 | |||
382 | static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol, | ||
383 | struct snd_ctl_elem_info *uinfo); | ||
384 | static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol, | ||
385 | struct snd_ctl_elem_value *ucontrol); | ||
386 | static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, | ||
387 | struct snd_ctl_elem_value *ucontrol); | ||
388 | |||
389 | |||
390 | /* | ||
334 | * AD1986A specific | 391 | * AD1986A specific |
335 | */ | 392 | */ |
336 | 393 | ||
@@ -344,6 +401,7 @@ static hda_nid_t ad1986a_dac_nids[3] = { | |||
344 | AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC | 401 | AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC |
345 | }; | 402 | }; |
346 | static hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC }; | 403 | static hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC }; |
404 | static hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 }; | ||
347 | 405 | ||
348 | static struct hda_input_mux ad1986a_capture_source = { | 406 | static struct hda_input_mux ad1986a_capture_source = { |
349 | .num_items = 7, | 407 | .num_items = 7, |
@@ -371,9 +429,9 @@ static int ad1986a_pcm_amp_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl | |||
371 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 429 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
372 | struct ad198x_spec *ad = codec->spec; | 430 | struct ad198x_spec *ad = codec->spec; |
373 | 431 | ||
374 | down(&ad->amp_mutex); | 432 | mutex_lock(&ad->amp_mutex); |
375 | snd_hda_mixer_amp_volume_get(kcontrol, ucontrol); | 433 | snd_hda_mixer_amp_volume_get(kcontrol, ucontrol); |
376 | up(&ad->amp_mutex); | 434 | mutex_unlock(&ad->amp_mutex); |
377 | return 0; | 435 | return 0; |
378 | } | 436 | } |
379 | 437 | ||
@@ -383,13 +441,13 @@ static int ad1986a_pcm_amp_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl | |||
383 | struct ad198x_spec *ad = codec->spec; | 441 | struct ad198x_spec *ad = codec->spec; |
384 | int i, change = 0; | 442 | int i, change = 0; |
385 | 443 | ||
386 | down(&ad->amp_mutex); | 444 | mutex_lock(&ad->amp_mutex); |
387 | for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) { | 445 | for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) { |
388 | kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT); | 446 | kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT); |
389 | change |= snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); | 447 | change |= snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); |
390 | } | 448 | } |
391 | kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT); | 449 | kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT); |
392 | up(&ad->amp_mutex); | 450 | mutex_unlock(&ad->amp_mutex); |
393 | return change; | 451 | return change; |
394 | } | 452 | } |
395 | 453 | ||
@@ -400,9 +458,9 @@ static int ad1986a_pcm_amp_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
400 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 458 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
401 | struct ad198x_spec *ad = codec->spec; | 459 | struct ad198x_spec *ad = codec->spec; |
402 | 460 | ||
403 | down(&ad->amp_mutex); | 461 | mutex_lock(&ad->amp_mutex); |
404 | snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); | 462 | snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); |
405 | up(&ad->amp_mutex); | 463 | mutex_unlock(&ad->amp_mutex); |
406 | return 0; | 464 | return 0; |
407 | } | 465 | } |
408 | 466 | ||
@@ -412,13 +470,13 @@ static int ad1986a_pcm_amp_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
412 | struct ad198x_spec *ad = codec->spec; | 470 | struct ad198x_spec *ad = codec->spec; |
413 | int i, change = 0; | 471 | int i, change = 0; |
414 | 472 | ||
415 | down(&ad->amp_mutex); | 473 | mutex_lock(&ad->amp_mutex); |
416 | for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) { | 474 | for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) { |
417 | kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT); | 475 | kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT); |
418 | change |= snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); | 476 | change |= snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); |
419 | } | 477 | } |
420 | kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT); | 478 | kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT); |
421 | up(&ad->amp_mutex); | 479 | mutex_unlock(&ad->amp_mutex); |
422 | return change; | 480 | return change; |
423 | } | 481 | } |
424 | 482 | ||
@@ -477,6 +535,143 @@ static struct snd_kcontrol_new ad1986a_mixers[] = { | |||
477 | { } /* end */ | 535 | { } /* end */ |
478 | }; | 536 | }; |
479 | 537 | ||
538 | /* additional mixers for 3stack mode */ | ||
539 | static struct snd_kcontrol_new ad1986a_3st_mixers[] = { | ||
540 | { | ||
541 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
542 | .name = "Channel Mode", | ||
543 | .info = ad198x_ch_mode_info, | ||
544 | .get = ad198x_ch_mode_get, | ||
545 | .put = ad198x_ch_mode_put, | ||
546 | }, | ||
547 | { } /* end */ | ||
548 | }; | ||
549 | |||
550 | /* laptop model - 2ch only */ | ||
551 | static hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC }; | ||
552 | |||
553 | static struct snd_kcontrol_new ad1986a_laptop_mixers[] = { | ||
554 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
555 | HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), | ||
556 | HDA_CODEC_VOLUME("Master Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
557 | HDA_CODEC_MUTE("Master Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
558 | /* HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT), | ||
559 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT), */ | ||
560 | HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT), | ||
561 | HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
562 | HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT), | ||
563 | HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT), | ||
564 | HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT), | ||
565 | HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT), | ||
566 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
567 | HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||
568 | /* HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x18, 0x0, HDA_OUTPUT), | ||
569 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x18, 0x0, HDA_OUTPUT), | ||
570 | HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT), | ||
571 | HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */ | ||
572 | HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), | ||
573 | HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), | ||
574 | { | ||
575 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
576 | .name = "Capture Source", | ||
577 | .info = ad198x_mux_enum_info, | ||
578 | .get = ad198x_mux_enum_get, | ||
579 | .put = ad198x_mux_enum_put, | ||
580 | }, | ||
581 | { } /* end */ | ||
582 | }; | ||
583 | |||
584 | /* laptop-eapd model - 2ch only */ | ||
585 | |||
586 | /* master controls both pins 0x1a and 0x1b */ | ||
587 | static int ad1986a_laptop_master_vol_put(struct snd_kcontrol *kcontrol, | ||
588 | struct snd_ctl_elem_value *ucontrol) | ||
589 | { | ||
590 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
591 | long *valp = ucontrol->value.integer.value; | ||
592 | int change; | ||
593 | |||
594 | change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0, | ||
595 | 0x7f, valp[0] & 0x7f); | ||
596 | change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, | ||
597 | 0x7f, valp[1] & 0x7f); | ||
598 | snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, | ||
599 | 0x7f, valp[0] & 0x7f); | ||
600 | snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, | ||
601 | 0x7f, valp[1] & 0x7f); | ||
602 | return change; | ||
603 | } | ||
604 | |||
605 | static int ad1986a_laptop_master_sw_put(struct snd_kcontrol *kcontrol, | ||
606 | struct snd_ctl_elem_value *ucontrol) | ||
607 | { | ||
608 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
609 | long *valp = ucontrol->value.integer.value; | ||
610 | int change; | ||
611 | |||
612 | change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0, | ||
613 | 0x80, valp[0] ? 0 : 0x80); | ||
614 | change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, | ||
615 | 0x80, valp[1] ? 0 : 0x80); | ||
616 | snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, | ||
617 | 0x80, valp[0] ? 0 : 0x80); | ||
618 | snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, | ||
619 | 0x80, valp[1] ? 0 : 0x80); | ||
620 | return change; | ||
621 | } | ||
622 | |||
623 | static struct hda_input_mux ad1986a_laptop_eapd_capture_source = { | ||
624 | .num_items = 3, | ||
625 | .items = { | ||
626 | { "Mic", 0x0 }, | ||
627 | { "Internal Mic", 0x4 }, | ||
628 | { "Mix", 0x5 }, | ||
629 | }, | ||
630 | }; | ||
631 | |||
632 | static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { | ||
633 | { | ||
634 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
635 | .name = "Master Playback Volume", | ||
636 | .info = snd_hda_mixer_amp_volume_info, | ||
637 | .get = snd_hda_mixer_amp_volume_get, | ||
638 | .put = ad1986a_laptop_master_vol_put, | ||
639 | .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), | ||
640 | }, | ||
641 | { | ||
642 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
643 | .name = "Master Playback Switch", | ||
644 | .info = snd_hda_mixer_amp_switch_info, | ||
645 | .get = snd_hda_mixer_amp_switch_get, | ||
646 | .put = ad1986a_laptop_master_sw_put, | ||
647 | .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), | ||
648 | }, | ||
649 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
650 | HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), | ||
651 | HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x0, HDA_OUTPUT), | ||
652 | HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x0, HDA_OUTPUT), | ||
653 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
654 | HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||
655 | HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), | ||
656 | HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), | ||
657 | { | ||
658 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
659 | .name = "Capture Source", | ||
660 | .info = ad198x_mux_enum_info, | ||
661 | .get = ad198x_mux_enum_get, | ||
662 | .put = ad198x_mux_enum_put, | ||
663 | }, | ||
664 | { | ||
665 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
666 | .name = "External Amplifier", | ||
667 | .info = ad198x_eapd_info, | ||
668 | .get = ad198x_eapd_get, | ||
669 | .put = ad198x_eapd_put, | ||
670 | .private_value = 0x1b | (1 << 8), /* port-D, inversed */ | ||
671 | }, | ||
672 | { } /* end */ | ||
673 | }; | ||
674 | |||
480 | /* | 675 | /* |
481 | * initialization verbs | 676 | * initialization verbs |
482 | */ | 677 | */ |
@@ -535,16 +730,89 @@ static struct hda_verb ad1986a_init_verbs[] = { | |||
535 | { } /* end */ | 730 | { } /* end */ |
536 | }; | 731 | }; |
537 | 732 | ||
733 | /* additional verbs for 3-stack model */ | ||
734 | static struct hda_verb ad1986a_3st_init_verbs[] = { | ||
735 | /* Mic and line-in selectors */ | ||
736 | {0x0f, AC_VERB_SET_CONNECT_SEL, 0x2}, | ||
737 | {0x10, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
738 | { } /* end */ | ||
739 | }; | ||
740 | |||
741 | static struct hda_verb ad1986a_ch2_init[] = { | ||
742 | /* Surround out -> Line In */ | ||
743 | { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
744 | { 0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
745 | /* CLFE -> Mic in */ | ||
746 | { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
747 | { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
748 | { } /* end */ | ||
749 | }; | ||
750 | |||
751 | static struct hda_verb ad1986a_ch4_init[] = { | ||
752 | /* Surround out -> Surround */ | ||
753 | { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
754 | { 0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
755 | /* CLFE -> Mic in */ | ||
756 | { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
757 | { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
758 | { } /* end */ | ||
759 | }; | ||
760 | |||
761 | static struct hda_verb ad1986a_ch6_init[] = { | ||
762 | /* Surround out -> Surround out */ | ||
763 | { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
764 | { 0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
765 | /* CLFE -> CLFE */ | ||
766 | { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
767 | { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
768 | { } /* end */ | ||
769 | }; | ||
770 | |||
771 | static struct hda_channel_mode ad1986a_modes[3] = { | ||
772 | { 2, ad1986a_ch2_init }, | ||
773 | { 4, ad1986a_ch4_init }, | ||
774 | { 6, ad1986a_ch6_init }, | ||
775 | }; | ||
776 | |||
777 | /* eapd initialization */ | ||
778 | static struct hda_verb ad1986a_eapd_init_verbs[] = { | ||
779 | {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00}, | ||
780 | {} | ||
781 | }; | ||
782 | |||
783 | /* models */ | ||
784 | enum { AD1986A_6STACK, AD1986A_3STACK, AD1986A_LAPTOP, AD1986A_LAPTOP_EAPD }; | ||
785 | |||
786 | static struct hda_board_config ad1986a_cfg_tbl[] = { | ||
787 | { .modelname = "6stack", .config = AD1986A_6STACK }, | ||
788 | { .modelname = "3stack", .config = AD1986A_3STACK }, | ||
789 | { .pci_subvendor = 0x10de, .pci_subdevice = 0xcb84, | ||
790 | .config = AD1986A_3STACK }, /* ASUS A8N-VM CSM */ | ||
791 | { .modelname = "laptop", .config = AD1986A_LAPTOP }, | ||
792 | { .pci_subvendor = 0x144d, .pci_subdevice = 0xc01e, | ||
793 | .config = AD1986A_LAPTOP }, /* FSC V2060 */ | ||
794 | { .pci_subvendor = 0x17c0, .pci_subdevice = 0x2017, | ||
795 | .config = AD1986A_LAPTOP }, /* Samsung M50 */ | ||
796 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x818f, | ||
797 | .config = AD1986A_LAPTOP }, /* ASUS P5GV-MX */ | ||
798 | { .modelname = "laptop-eapd", .config = AD1986A_LAPTOP_EAPD }, | ||
799 | { .pci_subvendor = 0x144d, .pci_subdevice = 0xc024, | ||
800 | .config = AD1986A_LAPTOP_EAPD }, /* Samsung R65-T2300 Charis */ | ||
801 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1213, | ||
802 | .config = AD1986A_LAPTOP_EAPD }, /* ASUS A6J */ | ||
803 | {} | ||
804 | }; | ||
538 | 805 | ||
539 | static int patch_ad1986a(struct hda_codec *codec) | 806 | static int patch_ad1986a(struct hda_codec *codec) |
540 | { | 807 | { |
541 | struct ad198x_spec *spec; | 808 | struct ad198x_spec *spec; |
809 | int board_config; | ||
542 | 810 | ||
543 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 811 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
544 | if (spec == NULL) | 812 | if (spec == NULL) |
545 | return -ENOMEM; | 813 | return -ENOMEM; |
546 | 814 | ||
547 | init_MUTEX(&spec->amp_mutex); | 815 | mutex_init(&spec->amp_mutex); |
548 | codec->spec = spec; | 816 | codec->spec = spec; |
549 | 817 | ||
550 | spec->multiout.max_channels = 6; | 818 | spec->multiout.max_channels = 6; |
@@ -553,7 +821,7 @@ static int patch_ad1986a(struct hda_codec *codec) | |||
553 | spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT; | 821 | spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT; |
554 | spec->num_adc_nids = 1; | 822 | spec->num_adc_nids = 1; |
555 | spec->adc_nids = ad1986a_adc_nids; | 823 | spec->adc_nids = ad1986a_adc_nids; |
556 | spec->capsrc_nids = ad1986a_adc_nids; | 824 | spec->capsrc_nids = ad1986a_capsrc_nids; |
557 | spec->input_mux = &ad1986a_capture_source; | 825 | spec->input_mux = &ad1986a_capture_source; |
558 | spec->num_mixers = 1; | 826 | spec->num_mixers = 1; |
559 | spec->mixers[0] = ad1986a_mixers; | 827 | spec->mixers[0] = ad1986a_mixers; |
@@ -562,6 +830,35 @@ static int patch_ad1986a(struct hda_codec *codec) | |||
562 | 830 | ||
563 | codec->patch_ops = ad198x_patch_ops; | 831 | codec->patch_ops = ad198x_patch_ops; |
564 | 832 | ||
833 | /* override some parameters */ | ||
834 | board_config = snd_hda_check_board_config(codec, ad1986a_cfg_tbl); | ||
835 | switch (board_config) { | ||
836 | case AD1986A_3STACK: | ||
837 | spec->num_mixers = 2; | ||
838 | spec->mixers[1] = ad1986a_3st_mixers; | ||
839 | spec->num_init_verbs = 2; | ||
840 | spec->init_verbs[1] = ad1986a_3st_init_verbs; | ||
841 | spec->channel_mode = ad1986a_modes; | ||
842 | spec->num_channel_mode = ARRAY_SIZE(ad1986a_modes); | ||
843 | break; | ||
844 | case AD1986A_LAPTOP: | ||
845 | spec->mixers[0] = ad1986a_laptop_mixers; | ||
846 | spec->multiout.max_channels = 2; | ||
847 | spec->multiout.num_dacs = 1; | ||
848 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | ||
849 | break; | ||
850 | case AD1986A_LAPTOP_EAPD: | ||
851 | spec->mixers[0] = ad1986a_laptop_eapd_mixers; | ||
852 | spec->num_init_verbs = 2; | ||
853 | spec->init_verbs[1] = ad1986a_eapd_init_verbs; | ||
854 | spec->multiout.max_channels = 2; | ||
855 | spec->multiout.num_dacs = 1; | ||
856 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | ||
857 | spec->multiout.dig_out_nid = 0; | ||
858 | spec->input_mux = &ad1986a_laptop_eapd_capture_source; | ||
859 | break; | ||
860 | } | ||
861 | |||
565 | return 0; | 862 | return 0; |
566 | } | 863 | } |
567 | 864 | ||
@@ -575,6 +872,7 @@ static int patch_ad1986a(struct hda_codec *codec) | |||
575 | 872 | ||
576 | static hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC }; | 873 | static hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC }; |
577 | static hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC }; | 874 | static hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC }; |
875 | static hda_nid_t ad1983_capsrc_nids[1] = { 0x15 }; | ||
578 | 876 | ||
579 | static struct hda_input_mux ad1983_capture_source = { | 877 | static struct hda_input_mux ad1983_capture_source = { |
580 | .num_items = 4, | 878 | .num_items = 4, |
@@ -708,7 +1006,7 @@ static int patch_ad1983(struct hda_codec *codec) | |||
708 | if (spec == NULL) | 1006 | if (spec == NULL) |
709 | return -ENOMEM; | 1007 | return -ENOMEM; |
710 | 1008 | ||
711 | init_MUTEX(&spec->amp_mutex); | 1009 | mutex_init(&spec->amp_mutex); |
712 | codec->spec = spec; | 1010 | codec->spec = spec; |
713 | 1011 | ||
714 | spec->multiout.max_channels = 2; | 1012 | spec->multiout.max_channels = 2; |
@@ -717,7 +1015,7 @@ static int patch_ad1983(struct hda_codec *codec) | |||
717 | spec->multiout.dig_out_nid = AD1983_SPDIF_OUT; | 1015 | spec->multiout.dig_out_nid = AD1983_SPDIF_OUT; |
718 | spec->num_adc_nids = 1; | 1016 | spec->num_adc_nids = 1; |
719 | spec->adc_nids = ad1983_adc_nids; | 1017 | spec->adc_nids = ad1983_adc_nids; |
720 | spec->capsrc_nids = ad1983_adc_nids; | 1018 | spec->capsrc_nids = ad1983_capsrc_nids; |
721 | spec->input_mux = &ad1983_capture_source; | 1019 | spec->input_mux = &ad1983_capture_source; |
722 | spec->num_mixers = 1; | 1020 | spec->num_mixers = 1; |
723 | spec->mixers[0] = ad1983_mixers; | 1021 | spec->mixers[0] = ad1983_mixers; |
@@ -741,6 +1039,7 @@ static int patch_ad1983(struct hda_codec *codec) | |||
741 | 1039 | ||
742 | static hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC }; | 1040 | static hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC }; |
743 | static hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC }; | 1041 | static hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC }; |
1042 | static hda_nid_t ad1981_capsrc_nids[1] = { 0x15 }; | ||
744 | 1043 | ||
745 | /* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */ | 1044 | /* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */ |
746 | static struct hda_input_mux ad1981_capture_source = { | 1045 | static struct hda_input_mux ad1981_capture_source = { |
@@ -846,15 +1145,200 @@ static struct hda_verb ad1981_init_verbs[] = { | |||
846 | { } /* end */ | 1145 | { } /* end */ |
847 | }; | 1146 | }; |
848 | 1147 | ||
1148 | /* | ||
1149 | * Patch for HP nx6320 | ||
1150 | * | ||
1151 | * nx6320 uses EAPD in the reserve way - EAPD-on means the internal | ||
1152 | * speaker output enabled _and_ mute-LED off. | ||
1153 | */ | ||
1154 | |||
1155 | #define AD1981_HP_EVENT 0x37 | ||
1156 | #define AD1981_MIC_EVENT 0x38 | ||
1157 | |||
1158 | static struct hda_verb ad1981_hp_init_verbs[] = { | ||
1159 | {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* default off */ | ||
1160 | /* pin sensing on HP and Mic jacks */ | ||
1161 | {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT}, | ||
1162 | {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT}, | ||
1163 | {} | ||
1164 | }; | ||
1165 | |||
1166 | /* turn on/off EAPD (+ mute HP) as a master switch */ | ||
1167 | static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol, | ||
1168 | struct snd_ctl_elem_value *ucontrol) | ||
1169 | { | ||
1170 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1171 | struct ad198x_spec *spec = codec->spec; | ||
1172 | |||
1173 | if (! ad198x_eapd_put(kcontrol, ucontrol)) | ||
1174 | return 0; | ||
1175 | |||
1176 | /* toggle HP mute appropriately */ | ||
1177 | snd_hda_codec_amp_update(codec, 0x06, 0, HDA_OUTPUT, 0, | ||
1178 | 0x80, spec->cur_eapd ? 0 : 0x80); | ||
1179 | snd_hda_codec_amp_update(codec, 0x06, 1, HDA_OUTPUT, 0, | ||
1180 | 0x80, spec->cur_eapd ? 0 : 0x80); | ||
1181 | return 1; | ||
1182 | } | ||
1183 | |||
1184 | /* bind volumes of both NID 0x05 and 0x06 */ | ||
1185 | static int ad1981_hp_master_vol_put(struct snd_kcontrol *kcontrol, | ||
1186 | struct snd_ctl_elem_value *ucontrol) | ||
1187 | { | ||
1188 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1189 | long *valp = ucontrol->value.integer.value; | ||
1190 | int change; | ||
1191 | |||
1192 | change = snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, | ||
1193 | 0x7f, valp[0] & 0x7f); | ||
1194 | change |= snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, | ||
1195 | 0x7f, valp[1] & 0x7f); | ||
1196 | snd_hda_codec_amp_update(codec, 0x06, 0, HDA_OUTPUT, 0, | ||
1197 | 0x7f, valp[0] & 0x7f); | ||
1198 | snd_hda_codec_amp_update(codec, 0x06, 1, HDA_OUTPUT, 0, | ||
1199 | 0x7f, valp[1] & 0x7f); | ||
1200 | return change; | ||
1201 | } | ||
1202 | |||
1203 | /* mute internal speaker if HP is plugged */ | ||
1204 | static void ad1981_hp_automute(struct hda_codec *codec) | ||
1205 | { | ||
1206 | unsigned int present; | ||
1207 | |||
1208 | present = snd_hda_codec_read(codec, 0x06, 0, | ||
1209 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
1210 | snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, | ||
1211 | 0x80, present ? 0x80 : 0); | ||
1212 | snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, | ||
1213 | 0x80, present ? 0x80 : 0); | ||
1214 | } | ||
1215 | |||
1216 | /* toggle input of built-in and mic jack appropriately */ | ||
1217 | static void ad1981_hp_automic(struct hda_codec *codec) | ||
1218 | { | ||
1219 | static struct hda_verb mic_jack_on[] = { | ||
1220 | {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1221 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
1222 | {} | ||
1223 | }; | ||
1224 | static struct hda_verb mic_jack_off[] = { | ||
1225 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1226 | {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
1227 | {} | ||
1228 | }; | ||
1229 | unsigned int present; | ||
1230 | |||
1231 | present = snd_hda_codec_read(codec, 0x08, 0, | ||
1232 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
1233 | if (present) | ||
1234 | snd_hda_sequence_write(codec, mic_jack_on); | ||
1235 | else | ||
1236 | snd_hda_sequence_write(codec, mic_jack_off); | ||
1237 | } | ||
1238 | |||
1239 | /* unsolicited event for HP jack sensing */ | ||
1240 | static void ad1981_hp_unsol_event(struct hda_codec *codec, | ||
1241 | unsigned int res) | ||
1242 | { | ||
1243 | res >>= 26; | ||
1244 | switch (res) { | ||
1245 | case AD1981_HP_EVENT: | ||
1246 | ad1981_hp_automute(codec); | ||
1247 | break; | ||
1248 | case AD1981_MIC_EVENT: | ||
1249 | ad1981_hp_automic(codec); | ||
1250 | break; | ||
1251 | } | ||
1252 | } | ||
1253 | |||
1254 | static struct hda_input_mux ad1981_hp_capture_source = { | ||
1255 | .num_items = 3, | ||
1256 | .items = { | ||
1257 | { "Mic", 0x0 }, | ||
1258 | { "Docking-Station", 0x1 }, | ||
1259 | { "Mix", 0x2 }, | ||
1260 | }, | ||
1261 | }; | ||
1262 | |||
1263 | static struct snd_kcontrol_new ad1981_hp_mixers[] = { | ||
1264 | { | ||
1265 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1266 | .name = "Master Playback Volume", | ||
1267 | .info = snd_hda_mixer_amp_volume_info, | ||
1268 | .get = snd_hda_mixer_amp_volume_get, | ||
1269 | .put = ad1981_hp_master_vol_put, | ||
1270 | .private_value = HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), | ||
1271 | }, | ||
1272 | { | ||
1273 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1274 | .name = "Master Playback Switch", | ||
1275 | .info = ad198x_eapd_info, | ||
1276 | .get = ad198x_eapd_get, | ||
1277 | .put = ad1981_hp_master_sw_put, | ||
1278 | .private_value = 0x05, | ||
1279 | }, | ||
1280 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), | ||
1281 | HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
1282 | #if 0 | ||
1283 | /* FIXME: analog mic/line loopback doesn't work with my tests... | ||
1284 | * (although recording is OK) | ||
1285 | */ | ||
1286 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), | ||
1287 | HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
1288 | HDA_CODEC_VOLUME("Docking-Station Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
1289 | HDA_CODEC_MUTE("Docking-Station Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||
1290 | HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT), | ||
1291 | HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT), | ||
1292 | /* FIXME: does this laptop have analog CD connection? */ | ||
1293 | HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), | ||
1294 | HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), | ||
1295 | #endif | ||
1296 | HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT), | ||
1297 | HDA_CODEC_VOLUME("Internal Mic Boost", 0x18, 0x0, HDA_INPUT), | ||
1298 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), | ||
1299 | HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), | ||
1300 | { | ||
1301 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1302 | .name = "Capture Source", | ||
1303 | .info = ad198x_mux_enum_info, | ||
1304 | .get = ad198x_mux_enum_get, | ||
1305 | .put = ad198x_mux_enum_put, | ||
1306 | }, | ||
1307 | { } /* end */ | ||
1308 | }; | ||
1309 | |||
1310 | /* initialize jack-sensing, too */ | ||
1311 | static int ad1981_hp_init(struct hda_codec *codec) | ||
1312 | { | ||
1313 | ad198x_init(codec); | ||
1314 | ad1981_hp_automute(codec); | ||
1315 | ad1981_hp_automic(codec); | ||
1316 | return 0; | ||
1317 | } | ||
1318 | |||
1319 | /* models */ | ||
1320 | enum { AD1981_BASIC, AD1981_HP }; | ||
1321 | |||
1322 | static struct hda_board_config ad1981_cfg_tbl[] = { | ||
1323 | { .modelname = "hp", .config = AD1981_HP }, | ||
1324 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x30aa, | ||
1325 | .config = AD1981_HP }, /* HP nx6320 */ | ||
1326 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x309f, | ||
1327 | .config = AD1981_HP }, /* HP nx9420 AngelFire */ | ||
1328 | { .modelname = "basic", .config = AD1981_BASIC }, | ||
1329 | {} | ||
1330 | }; | ||
1331 | |||
849 | static int patch_ad1981(struct hda_codec *codec) | 1332 | static int patch_ad1981(struct hda_codec *codec) |
850 | { | 1333 | { |
851 | struct ad198x_spec *spec; | 1334 | struct ad198x_spec *spec; |
1335 | int board_config; | ||
852 | 1336 | ||
853 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 1337 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
854 | if (spec == NULL) | 1338 | if (spec == NULL) |
855 | return -ENOMEM; | 1339 | return -ENOMEM; |
856 | 1340 | ||
857 | init_MUTEX(&spec->amp_mutex); | 1341 | mutex_init(&spec->amp_mutex); |
858 | codec->spec = spec; | 1342 | codec->spec = spec; |
859 | 1343 | ||
860 | spec->multiout.max_channels = 2; | 1344 | spec->multiout.max_channels = 2; |
@@ -863,7 +1347,7 @@ static int patch_ad1981(struct hda_codec *codec) | |||
863 | spec->multiout.dig_out_nid = AD1981_SPDIF_OUT; | 1347 | spec->multiout.dig_out_nid = AD1981_SPDIF_OUT; |
864 | spec->num_adc_nids = 1; | 1348 | spec->num_adc_nids = 1; |
865 | spec->adc_nids = ad1981_adc_nids; | 1349 | spec->adc_nids = ad1981_adc_nids; |
866 | spec->capsrc_nids = ad1981_adc_nids; | 1350 | spec->capsrc_nids = ad1981_capsrc_nids; |
867 | spec->input_mux = &ad1981_capture_source; | 1351 | spec->input_mux = &ad1981_capture_source; |
868 | spec->num_mixers = 1; | 1352 | spec->num_mixers = 1; |
869 | spec->mixers[0] = ad1981_mixers; | 1353 | spec->mixers[0] = ad1981_mixers; |
@@ -873,6 +1357,21 @@ static int patch_ad1981(struct hda_codec *codec) | |||
873 | 1357 | ||
874 | codec->patch_ops = ad198x_patch_ops; | 1358 | codec->patch_ops = ad198x_patch_ops; |
875 | 1359 | ||
1360 | /* override some parameters */ | ||
1361 | board_config = snd_hda_check_board_config(codec, ad1981_cfg_tbl); | ||
1362 | switch (board_config) { | ||
1363 | case AD1981_HP: | ||
1364 | spec->mixers[0] = ad1981_hp_mixers; | ||
1365 | spec->num_init_verbs = 2; | ||
1366 | spec->init_verbs[1] = ad1981_hp_init_verbs; | ||
1367 | spec->multiout.dig_out_nid = 0; | ||
1368 | spec->input_mux = &ad1981_hp_capture_source; | ||
1369 | |||
1370 | codec->patch_ops.init = ad1981_hp_init; | ||
1371 | codec->patch_ops.unsol_event = ad1981_hp_unsol_event; | ||
1372 | break; | ||
1373 | } | ||
1374 | |||
876 | return 0; | 1375 | return 0; |
877 | } | 1376 | } |
878 | 1377 | ||
@@ -1060,44 +1559,6 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, | |||
1060 | spec->num_channel_mode, &spec->multiout.max_channels); | 1559 | spec->num_channel_mode, &spec->multiout.max_channels); |
1061 | } | 1560 | } |
1062 | 1561 | ||
1063 | /* | ||
1064 | * EAPD control | ||
1065 | */ | ||
1066 | static int ad1988_eapd_info(struct snd_kcontrol *kcontrol, | ||
1067 | struct snd_ctl_elem_info *uinfo) | ||
1068 | { | ||
1069 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
1070 | uinfo->count = 1; | ||
1071 | uinfo->value.integer.min = 0; | ||
1072 | uinfo->value.integer.max = 1; | ||
1073 | return 0; | ||
1074 | } | ||
1075 | |||
1076 | static int ad1988_eapd_get(struct snd_kcontrol *kcontrol, | ||
1077 | struct snd_ctl_elem_value *ucontrol) | ||
1078 | { | ||
1079 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1080 | struct ad198x_spec *spec = codec->spec; | ||
1081 | ucontrol->value.enumerated.item[0] = ! spec->cur_eapd; | ||
1082 | return 0; | ||
1083 | } | ||
1084 | |||
1085 | static int ad1988_eapd_put(struct snd_kcontrol *kcontrol, | ||
1086 | struct snd_ctl_elem_value *ucontrol) | ||
1087 | { | ||
1088 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1089 | struct ad198x_spec *spec = codec->spec; | ||
1090 | unsigned int eapd; | ||
1091 | eapd = ! ucontrol->value.enumerated.item[0]; | ||
1092 | if (eapd == spec->cur_eapd && ! codec->in_resume) | ||
1093 | return 0; | ||
1094 | spec->cur_eapd = eapd; | ||
1095 | snd_hda_codec_write(codec, 0x12 /* port-D */, | ||
1096 | 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
1097 | eapd ? 0x02 : 0x00); | ||
1098 | return 0; | ||
1099 | } | ||
1100 | |||
1101 | /* 6-stack mode */ | 1562 | /* 6-stack mode */ |
1102 | static struct snd_kcontrol_new ad1988_6stack_mixers1[] = { | 1563 | static struct snd_kcontrol_new ad1988_6stack_mixers1[] = { |
1103 | HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), | 1564 | HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), |
@@ -1220,9 +1681,10 @@ static struct snd_kcontrol_new ad1988_laptop_mixers[] = { | |||
1220 | { | 1681 | { |
1221 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1682 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1222 | .name = "External Amplifier", | 1683 | .name = "External Amplifier", |
1223 | .info = ad1988_eapd_info, | 1684 | .info = ad198x_eapd_info, |
1224 | .get = ad1988_eapd_get, | 1685 | .get = ad198x_eapd_get, |
1225 | .put = ad1988_eapd_put, | 1686 | .put = ad198x_eapd_put, |
1687 | .private_value = 0x12 | (1 << 8), /* port-D, inversed */ | ||
1226 | }, | 1688 | }, |
1227 | 1689 | ||
1228 | { } /* end */ | 1690 | { } /* end */ |
@@ -1795,14 +2257,11 @@ static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, | |||
1795 | 2257 | ||
1796 | idx = ad1988_pin_idx(pin); | 2258 | idx = ad1988_pin_idx(pin); |
1797 | nid = ad1988_idx_to_dac(codec, idx); | 2259 | nid = ad1988_idx_to_dac(codec, idx); |
1798 | if (! spec->multiout.dac_nids[0]) { | 2260 | /* specify the DAC as the extra output */ |
1799 | /* use this as the primary output */ | 2261 | if (! spec->multiout.hp_nid) |
1800 | spec->multiout.dac_nids[0] = nid; | ||
1801 | if (! spec->multiout.num_dacs) | ||
1802 | spec->multiout.num_dacs = 1; | ||
1803 | } else | ||
1804 | /* specify the DAC as the extra output */ | ||
1805 | spec->multiout.hp_nid = nid; | 2262 | spec->multiout.hp_nid = nid; |
2263 | else | ||
2264 | spec->multiout.extra_out_nid[0] = nid; | ||
1806 | /* control HP volume/switch on the output mixer amp */ | 2265 | /* control HP volume/switch on the output mixer amp */ |
1807 | sprintf(name, "%s Playback Volume", pfx); | 2266 | sprintf(name, "%s Playback Volume", pfx); |
1808 | if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name, | 2267 | if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name, |
@@ -1921,7 +2380,7 @@ static void ad1988_auto_init_extra_out(struct hda_codec *codec) | |||
1921 | struct ad198x_spec *spec = codec->spec; | 2380 | struct ad198x_spec *spec = codec->spec; |
1922 | hda_nid_t pin; | 2381 | hda_nid_t pin; |
1923 | 2382 | ||
1924 | pin = spec->autocfg.speaker_pin; | 2383 | pin = spec->autocfg.speaker_pins[0]; |
1925 | if (pin) /* connect to front */ | 2384 | if (pin) /* connect to front */ |
1926 | ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); | 2385 | ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); |
1927 | pin = spec->autocfg.hp_pin; | 2386 | pin = spec->autocfg.hp_pin; |
@@ -1970,13 +2429,13 @@ static int ad1988_parse_auto_config(struct hda_codec *codec) | |||
1970 | return err; | 2429 | return err; |
1971 | if ((err = ad1988_auto_fill_dac_nids(codec, &spec->autocfg)) < 0) | 2430 | if ((err = ad1988_auto_fill_dac_nids(codec, &spec->autocfg)) < 0) |
1972 | return err; | 2431 | return err; |
1973 | if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin && | 2432 | if (! spec->autocfg.line_outs) |
1974 | ! spec->autocfg.hp_pin) | ||
1975 | return 0; /* can't find valid BIOS pin config */ | 2433 | return 0; /* can't find valid BIOS pin config */ |
1976 | if ((err = ad1988_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || | 2434 | if ((err = ad1988_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || |
1977 | (err = ad1988_auto_create_extra_out(codec, spec->autocfg.speaker_pin, | 2435 | (err = ad1988_auto_create_extra_out(codec, |
2436 | spec->autocfg.speaker_pins[0], | ||
1978 | "Speaker")) < 0 || | 2437 | "Speaker")) < 0 || |
1979 | (err = ad1988_auto_create_extra_out(codec, spec->autocfg.speaker_pin, | 2438 | (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pin, |
1980 | "Headphone")) < 0 || | 2439 | "Headphone")) < 0 || |
1981 | (err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) | 2440 | (err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) |
1982 | return err; | 2441 | return err; |
@@ -2032,7 +2491,7 @@ static int patch_ad1988(struct hda_codec *codec) | |||
2032 | if (spec == NULL) | 2491 | if (spec == NULL) |
2033 | return -ENOMEM; | 2492 | return -ENOMEM; |
2034 | 2493 | ||
2035 | init_MUTEX(&spec->amp_mutex); | 2494 | mutex_init(&spec->amp_mutex); |
2036 | codec->spec = spec; | 2495 | codec->spec = spec; |
2037 | 2496 | ||
2038 | if (codec->revision_id == AD1988A_REV2) | 2497 | if (codec->revision_id == AD1988A_REV2) |