diff options
Diffstat (limited to 'sound/pci/hda')
-rw-r--r-- | sound/pci/hda/Makefile | 27 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.c | 735 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 113 | ||||
-rw-r--r-- | sound/pci/hda/hda_generic.c | 100 | ||||
-rw-r--r-- | sound/pci/hda/hda_hwdep.c | 122 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel.c | 382 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 193 | ||||
-rw-r--r-- | sound/pci/hda/hda_patch.h | 16 | ||||
-rw-r--r-- | sound/pci/hda/hda_proc.c | 30 | ||||
-rw-r--r-- | sound/pci/hda/patch_analog.c | 524 | ||||
-rw-r--r-- | sound/pci/hda/patch_atihdmi.c | 16 | ||||
-rw-r--r-- | sound/pci/hda/patch_cmedia.c | 24 | ||||
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 156 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 1840 | ||||
-rw-r--r-- | sound/pci/hda/patch_si3054.c | 20 | ||||
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 1000 | ||||
-rw-r--r-- | sound/pci/hda/patch_via.c | 80 |
17 files changed, 3842 insertions, 1536 deletions
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index b2484bbdcc1d..ab0c726d648e 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile | |||
@@ -1,19 +1,18 @@ | |||
1 | snd-hda-intel-objs := hda_intel.o | 1 | snd-hda-intel-y := hda_intel.o |
2 | # since snd-hda-intel is the only driver using hda-codec, | 2 | # since snd-hda-intel is the only driver using hda-codec, |
3 | # merge it into a single module although it was originally | 3 | # merge it into a single module although it was originally |
4 | # designed to be individual modules | 4 | # designed to be individual modules |
5 | snd-hda-intel-objs += hda_codec.o \ | 5 | snd-hda-intel-y += hda_codec.o |
6 | hda_generic.o \ | 6 | snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o |
7 | patch_realtek.o \ | 7 | snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o |
8 | patch_cmedia.o \ | 8 | snd-hda-intel-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o |
9 | patch_analog.o \ | 9 | snd-hda-intel-$(CONFIG_SND_HDA_CODEC_REALTEK) += patch_realtek.o |
10 | patch_sigmatel.o \ | 10 | snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CMEDIA) += patch_cmedia.o |
11 | patch_si3054.o \ | 11 | snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ANALOG) += patch_analog.o |
12 | patch_atihdmi.o \ | 12 | snd-hda-intel-$(CONFIG_SND_HDA_CODEC_SIGMATEL) += patch_sigmatel.o |
13 | patch_conexant.o \ | 13 | snd-hda-intel-$(CONFIG_SND_HDA_CODEC_SI3054) += patch_si3054.o |
14 | patch_via.o | 14 | snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ATIHDMI) += patch_atihdmi.o |
15 | ifdef CONFIG_PROC_FS | 15 | snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CONEXANT) += patch_conexant.o |
16 | snd-hda-intel-objs += hda_proc.o | 16 | snd-hda-intel-$(CONFIG_SND_HDA_CODEC_VIA) += patch_via.o |
17 | endif | ||
18 | 17 | ||
19 | obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o | 18 | obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o |
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index f87f8f088956..187533e477c6 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -31,7 +31,15 @@ | |||
31 | #include <sound/tlv.h> | 31 | #include <sound/tlv.h> |
32 | #include <sound/initval.h> | 32 | #include <sound/initval.h> |
33 | #include "hda_local.h" | 33 | #include "hda_local.h" |
34 | 34 | #include <sound/hda_hwdep.h> | |
35 | |||
36 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
37 | /* define this option here to hide as static */ | ||
38 | static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; | ||
39 | module_param(power_save, int, 0644); | ||
40 | MODULE_PARM_DESC(power_save, "Automatic power-saving timeout " | ||
41 | "(in second, 0 = disable)."); | ||
42 | #endif | ||
35 | 43 | ||
36 | /* | 44 | /* |
37 | * vendor / preset table | 45 | * vendor / preset table |
@@ -59,6 +67,13 @@ static struct hda_vendor_id hda_vendor_ids[] = { | |||
59 | #include "hda_patch.h" | 67 | #include "hda_patch.h" |
60 | 68 | ||
61 | 69 | ||
70 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
71 | static void hda_power_work(struct work_struct *work); | ||
72 | static void hda_keep_power_on(struct hda_codec *codec); | ||
73 | #else | ||
74 | static inline void hda_keep_power_on(struct hda_codec *codec) {} | ||
75 | #endif | ||
76 | |||
62 | /** | 77 | /** |
63 | * snd_hda_codec_read - send a command and get the response | 78 | * snd_hda_codec_read - send a command and get the response |
64 | * @codec: the HDA codec | 79 | * @codec: the HDA codec |
@@ -76,12 +91,14 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, | |||
76 | unsigned int verb, unsigned int parm) | 91 | unsigned int verb, unsigned int parm) |
77 | { | 92 | { |
78 | unsigned int res; | 93 | unsigned int res; |
94 | snd_hda_power_up(codec); | ||
79 | mutex_lock(&codec->bus->cmd_mutex); | 95 | mutex_lock(&codec->bus->cmd_mutex); |
80 | if (!codec->bus->ops.command(codec, nid, direct, verb, parm)) | 96 | if (!codec->bus->ops.command(codec, nid, direct, verb, parm)) |
81 | res = codec->bus->ops.get_response(codec); | 97 | res = codec->bus->ops.get_response(codec); |
82 | else | 98 | else |
83 | res = (unsigned int)-1; | 99 | res = (unsigned int)-1; |
84 | mutex_unlock(&codec->bus->cmd_mutex); | 100 | mutex_unlock(&codec->bus->cmd_mutex); |
101 | snd_hda_power_down(codec); | ||
85 | return res; | 102 | return res; |
86 | } | 103 | } |
87 | 104 | ||
@@ -101,9 +118,11 @@ int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, | |||
101 | unsigned int verb, unsigned int parm) | 118 | unsigned int verb, unsigned int parm) |
102 | { | 119 | { |
103 | int err; | 120 | int err; |
121 | snd_hda_power_up(codec); | ||
104 | mutex_lock(&codec->bus->cmd_mutex); | 122 | mutex_lock(&codec->bus->cmd_mutex); |
105 | err = codec->bus->ops.command(codec, nid, direct, verb, parm); | 123 | err = codec->bus->ops.command(codec, nid, direct, verb, parm); |
106 | mutex_unlock(&codec->bus->cmd_mutex); | 124 | mutex_unlock(&codec->bus->cmd_mutex); |
125 | snd_hda_power_down(codec); | ||
107 | return err; | 126 | return err; |
108 | } | 127 | } |
109 | 128 | ||
@@ -136,6 +155,8 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, | |||
136 | unsigned int parm; | 155 | unsigned int parm; |
137 | 156 | ||
138 | parm = snd_hda_param_read(codec, nid, AC_PAR_NODE_COUNT); | 157 | parm = snd_hda_param_read(codec, nid, AC_PAR_NODE_COUNT); |
158 | if (parm == -1) | ||
159 | return 0; | ||
139 | *start_id = (parm >> 16) & 0x7fff; | 160 | *start_id = (parm >> 16) & 0x7fff; |
140 | return (int)(parm & 0x7fff); | 161 | return (int)(parm & 0x7fff); |
141 | } | 162 | } |
@@ -387,6 +408,13 @@ int __devinit snd_hda_bus_new(struct snd_card *card, | |||
387 | return 0; | 408 | return 0; |
388 | } | 409 | } |
389 | 410 | ||
411 | #ifdef CONFIG_SND_HDA_GENERIC | ||
412 | #define is_generic_config(codec) \ | ||
413 | (codec->bus->modelname && !strcmp(codec->bus->modelname, "generic")) | ||
414 | #else | ||
415 | #define is_generic_config(codec) 0 | ||
416 | #endif | ||
417 | |||
390 | /* | 418 | /* |
391 | * find a matching codec preset | 419 | * find a matching codec preset |
392 | */ | 420 | */ |
@@ -395,7 +423,7 @@ find_codec_preset(struct hda_codec *codec) | |||
395 | { | 423 | { |
396 | const struct hda_codec_preset **tbl, *preset; | 424 | const struct hda_codec_preset **tbl, *preset; |
397 | 425 | ||
398 | if (codec->bus->modelname && !strcmp(codec->bus->modelname, "generic")) | 426 | if (is_generic_config(codec)) |
399 | return NULL; /* use the generic parser */ | 427 | return NULL; /* use the generic parser */ |
400 | 428 | ||
401 | for (tbl = hda_preset_tables; *tbl; tbl++) { | 429 | for (tbl = hda_preset_tables; *tbl; tbl++) { |
@@ -486,6 +514,10 @@ static int read_widget_caps(struct hda_codec *codec, hda_nid_t fg_node) | |||
486 | } | 514 | } |
487 | 515 | ||
488 | 516 | ||
517 | static void init_hda_cache(struct hda_cache_rec *cache, | ||
518 | unsigned int record_size); | ||
519 | static void free_hda_cache(struct hda_cache_rec *cache); | ||
520 | |||
489 | /* | 521 | /* |
490 | * codec destructor | 522 | * codec destructor |
491 | */ | 523 | */ |
@@ -493,17 +525,20 @@ static void snd_hda_codec_free(struct hda_codec *codec) | |||
493 | { | 525 | { |
494 | if (!codec) | 526 | if (!codec) |
495 | return; | 527 | return; |
528 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
529 | cancel_delayed_work(&codec->power_work); | ||
530 | flush_scheduled_work(); | ||
531 | #endif | ||
496 | list_del(&codec->list); | 532 | list_del(&codec->list); |
497 | codec->bus->caddr_tbl[codec->addr] = NULL; | 533 | codec->bus->caddr_tbl[codec->addr] = NULL; |
498 | if (codec->patch_ops.free) | 534 | if (codec->patch_ops.free) |
499 | codec->patch_ops.free(codec); | 535 | codec->patch_ops.free(codec); |
500 | kfree(codec->amp_info); | 536 | free_hda_cache(&codec->amp_cache); |
537 | free_hda_cache(&codec->cmd_cache); | ||
501 | kfree(codec->wcaps); | 538 | kfree(codec->wcaps); |
502 | kfree(codec); | 539 | kfree(codec); |
503 | } | 540 | } |
504 | 541 | ||
505 | static void init_amp_hash(struct hda_codec *codec); | ||
506 | |||
507 | /** | 542 | /** |
508 | * snd_hda_codec_new - create a HDA codec | 543 | * snd_hda_codec_new - create a HDA codec |
509 | * @bus: the bus to assign | 544 | * @bus: the bus to assign |
@@ -537,7 +572,17 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, | |||
537 | codec->bus = bus; | 572 | codec->bus = bus; |
538 | codec->addr = codec_addr; | 573 | codec->addr = codec_addr; |
539 | mutex_init(&codec->spdif_mutex); | 574 | mutex_init(&codec->spdif_mutex); |
540 | init_amp_hash(codec); | 575 | init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); |
576 | init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); | ||
577 | |||
578 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
579 | INIT_DELAYED_WORK(&codec->power_work, hda_power_work); | ||
580 | /* snd_hda_codec_new() marks the codec as power-up, and leave it as is. | ||
581 | * the caller has to power down appropriatley after initialization | ||
582 | * phase. | ||
583 | */ | ||
584 | hda_keep_power_on(codec); | ||
585 | #endif | ||
541 | 586 | ||
542 | list_add_tail(&codec->list, &bus->codec_list); | 587 | list_add_tail(&codec->list, &bus->codec_list); |
543 | bus->caddr_tbl[codec_addr] = codec; | 588 | bus->caddr_tbl[codec_addr] = codec; |
@@ -581,10 +626,26 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, | |||
581 | snd_hda_get_codec_name(codec, bus->card->mixername, | 626 | snd_hda_get_codec_name(codec, bus->card->mixername, |
582 | sizeof(bus->card->mixername)); | 627 | sizeof(bus->card->mixername)); |
583 | 628 | ||
584 | if (codec->preset && codec->preset->patch) | 629 | #ifdef CONFIG_SND_HDA_GENERIC |
585 | err = codec->preset->patch(codec); | 630 | if (is_generic_config(codec)) { |
586 | else | ||
587 | err = snd_hda_parse_generic_codec(codec); | 631 | err = snd_hda_parse_generic_codec(codec); |
632 | goto patched; | ||
633 | } | ||
634 | #endif | ||
635 | if (codec->preset && codec->preset->patch) { | ||
636 | err = codec->preset->patch(codec); | ||
637 | goto patched; | ||
638 | } | ||
639 | |||
640 | /* call the default parser */ | ||
641 | #ifdef CONFIG_SND_HDA_GENERIC | ||
642 | err = snd_hda_parse_generic_codec(codec); | ||
643 | #else | ||
644 | printk(KERN_ERR "hda-codec: No codec parser is available\n"); | ||
645 | err = -ENODEV; | ||
646 | #endif | ||
647 | |||
648 | patched: | ||
588 | if (err < 0) { | 649 | if (err < 0) { |
589 | snd_hda_codec_free(codec); | 650 | snd_hda_codec_free(codec); |
590 | return err; | 651 | return err; |
@@ -594,6 +655,9 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, | |||
594 | init_unsol_queue(bus); | 655 | init_unsol_queue(bus); |
595 | 656 | ||
596 | snd_hda_codec_proc_new(codec); | 657 | snd_hda_codec_proc_new(codec); |
658 | #ifdef CONFIG_SND_HDA_HWDEP | ||
659 | snd_hda_create_hwdep(codec); | ||
660 | #endif | ||
597 | 661 | ||
598 | sprintf(component, "HDA:%08x", codec->vendor_id); | 662 | sprintf(component, "HDA:%08x", codec->vendor_id); |
599 | snd_component_add(codec->bus->card, component); | 663 | snd_component_add(codec->bus->card, component); |
@@ -637,59 +701,72 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, | |||
637 | #define INFO_AMP_VOL(ch) (1 << (1 + (ch))) | 701 | #define INFO_AMP_VOL(ch) (1 << (1 + (ch))) |
638 | 702 | ||
639 | /* initialize the hash table */ | 703 | /* initialize the hash table */ |
640 | static void __devinit init_amp_hash(struct hda_codec *codec) | 704 | static void __devinit init_hda_cache(struct hda_cache_rec *cache, |
705 | unsigned int record_size) | ||
706 | { | ||
707 | memset(cache, 0, sizeof(*cache)); | ||
708 | memset(cache->hash, 0xff, sizeof(cache->hash)); | ||
709 | cache->record_size = record_size; | ||
710 | } | ||
711 | |||
712 | static void free_hda_cache(struct hda_cache_rec *cache) | ||
641 | { | 713 | { |
642 | memset(codec->amp_hash, 0xff, sizeof(codec->amp_hash)); | 714 | kfree(cache->buffer); |
643 | codec->num_amp_entries = 0; | ||
644 | codec->amp_info_size = 0; | ||
645 | codec->amp_info = NULL; | ||
646 | } | 715 | } |
647 | 716 | ||
648 | /* query the hash. allocate an entry if not found. */ | 717 | /* query the hash. allocate an entry if not found. */ |
649 | static struct hda_amp_info *get_alloc_amp_hash(struct hda_codec *codec, u32 key) | 718 | static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, |
719 | u32 key) | ||
650 | { | 720 | { |
651 | u16 idx = key % (u16)ARRAY_SIZE(codec->amp_hash); | 721 | u16 idx = key % (u16)ARRAY_SIZE(cache->hash); |
652 | u16 cur = codec->amp_hash[idx]; | 722 | u16 cur = cache->hash[idx]; |
653 | struct hda_amp_info *info; | 723 | struct hda_cache_head *info; |
654 | 724 | ||
655 | while (cur != 0xffff) { | 725 | while (cur != 0xffff) { |
656 | info = &codec->amp_info[cur]; | 726 | info = (struct hda_cache_head *)(cache->buffer + |
727 | cur * cache->record_size); | ||
657 | if (info->key == key) | 728 | if (info->key == key) |
658 | return info; | 729 | return info; |
659 | cur = info->next; | 730 | cur = info->next; |
660 | } | 731 | } |
661 | 732 | ||
662 | /* add a new hash entry */ | 733 | /* add a new hash entry */ |
663 | if (codec->num_amp_entries >= codec->amp_info_size) { | 734 | if (cache->num_entries >= cache->size) { |
664 | /* reallocate the array */ | 735 | /* reallocate the array */ |
665 | int new_size = codec->amp_info_size + 64; | 736 | unsigned int new_size = cache->size + 64; |
666 | struct hda_amp_info *new_info; | 737 | void *new_buffer; |
667 | new_info = kcalloc(new_size, sizeof(struct hda_amp_info), | 738 | new_buffer = kcalloc(new_size, cache->record_size, GFP_KERNEL); |
668 | GFP_KERNEL); | 739 | if (!new_buffer) { |
669 | if (!new_info) { | ||
670 | snd_printk(KERN_ERR "hda_codec: " | 740 | snd_printk(KERN_ERR "hda_codec: " |
671 | "can't malloc amp_info\n"); | 741 | "can't malloc amp_info\n"); |
672 | return NULL; | 742 | return NULL; |
673 | } | 743 | } |
674 | if (codec->amp_info) { | 744 | if (cache->buffer) { |
675 | memcpy(new_info, codec->amp_info, | 745 | memcpy(new_buffer, cache->buffer, |
676 | codec->amp_info_size * | 746 | cache->size * cache->record_size); |
677 | sizeof(struct hda_amp_info)); | 747 | kfree(cache->buffer); |
678 | kfree(codec->amp_info); | ||
679 | } | 748 | } |
680 | codec->amp_info_size = new_size; | 749 | cache->size = new_size; |
681 | codec->amp_info = new_info; | 750 | cache->buffer = new_buffer; |
682 | } | 751 | } |
683 | cur = codec->num_amp_entries++; | 752 | cur = cache->num_entries++; |
684 | info = &codec->amp_info[cur]; | 753 | info = (struct hda_cache_head *)(cache->buffer + |
754 | cur * cache->record_size); | ||
685 | info->key = key; | 755 | info->key = key; |
686 | info->status = 0; /* not initialized yet */ | 756 | info->val = 0; |
687 | info->next = codec->amp_hash[idx]; | 757 | info->next = cache->hash[idx]; |
688 | codec->amp_hash[idx] = cur; | 758 | cache->hash[idx] = cur; |
689 | 759 | ||
690 | return info; | 760 | return info; |
691 | } | 761 | } |
692 | 762 | ||
763 | /* query and allocate an amp hash entry */ | ||
764 | static inline struct hda_amp_info * | ||
765 | get_alloc_amp_hash(struct hda_codec *codec, u32 key) | ||
766 | { | ||
767 | return (struct hda_amp_info *)get_alloc_hash(&codec->amp_cache, key); | ||
768 | } | ||
769 | |||
693 | /* | 770 | /* |
694 | * query AMP capabilities for the given widget and direction | 771 | * query AMP capabilities for the given widget and direction |
695 | */ | 772 | */ |
@@ -700,7 +777,7 @@ static u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) | |||
700 | info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, 0)); | 777 | info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, 0)); |
701 | if (!info) | 778 | if (!info) |
702 | return 0; | 779 | return 0; |
703 | if (!(info->status & INFO_AMP_CAPS)) { | 780 | if (!(info->head.val & INFO_AMP_CAPS)) { |
704 | if (!(get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD)) | 781 | if (!(get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD)) |
705 | nid = codec->afg; | 782 | nid = codec->afg; |
706 | info->amp_caps = snd_hda_param_read(codec, nid, | 783 | info->amp_caps = snd_hda_param_read(codec, nid, |
@@ -708,7 +785,7 @@ static u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) | |||
708 | AC_PAR_AMP_OUT_CAP : | 785 | AC_PAR_AMP_OUT_CAP : |
709 | AC_PAR_AMP_IN_CAP); | 786 | AC_PAR_AMP_IN_CAP); |
710 | if (info->amp_caps) | 787 | if (info->amp_caps) |
711 | info->status |= INFO_AMP_CAPS; | 788 | info->head.val |= INFO_AMP_CAPS; |
712 | } | 789 | } |
713 | return info->amp_caps; | 790 | return info->amp_caps; |
714 | } | 791 | } |
@@ -722,7 +799,7 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, | |||
722 | if (!info) | 799 | if (!info) |
723 | return -EINVAL; | 800 | return -EINVAL; |
724 | info->amp_caps = caps; | 801 | info->amp_caps = caps; |
725 | info->status |= INFO_AMP_CAPS; | 802 | info->head.val |= INFO_AMP_CAPS; |
726 | return 0; | 803 | return 0; |
727 | } | 804 | } |
728 | 805 | ||
@@ -736,7 +813,7 @@ static unsigned int get_vol_mute(struct hda_codec *codec, | |||
736 | { | 813 | { |
737 | u32 val, parm; | 814 | u32 val, parm; |
738 | 815 | ||
739 | if (info->status & INFO_AMP_VOL(ch)) | 816 | if (info->head.val & INFO_AMP_VOL(ch)) |
740 | return info->vol[ch]; | 817 | return info->vol[ch]; |
741 | 818 | ||
742 | parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT; | 819 | parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT; |
@@ -745,7 +822,7 @@ static unsigned int get_vol_mute(struct hda_codec *codec, | |||
745 | val = snd_hda_codec_read(codec, nid, 0, | 822 | val = snd_hda_codec_read(codec, nid, 0, |
746 | AC_VERB_GET_AMP_GAIN_MUTE, parm); | 823 | AC_VERB_GET_AMP_GAIN_MUTE, parm); |
747 | info->vol[ch] = val & 0xff; | 824 | info->vol[ch] = val & 0xff; |
748 | info->status |= INFO_AMP_VOL(ch); | 825 | info->head.val |= INFO_AMP_VOL(ch); |
749 | return info->vol[ch]; | 826 | return info->vol[ch]; |
750 | } | 827 | } |
751 | 828 | ||
@@ -792,12 +869,50 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, | |||
792 | return 0; | 869 | return 0; |
793 | val &= mask; | 870 | val &= mask; |
794 | val |= get_vol_mute(codec, info, nid, ch, direction, idx) & ~mask; | 871 | val |= get_vol_mute(codec, info, nid, ch, direction, idx) & ~mask; |
795 | if (info->vol[ch] == val && !codec->in_resume) | 872 | if (info->vol[ch] == val) |
796 | return 0; | 873 | return 0; |
797 | put_vol_mute(codec, info, nid, ch, direction, idx, val); | 874 | put_vol_mute(codec, info, nid, ch, direction, idx, val); |
798 | return 1; | 875 | return 1; |
799 | } | 876 | } |
800 | 877 | ||
878 | /* | ||
879 | * update the AMP stereo with the same mask and value | ||
880 | */ | ||
881 | int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, | ||
882 | int direction, int idx, int mask, int val) | ||
883 | { | ||
884 | int ch, ret = 0; | ||
885 | for (ch = 0; ch < 2; ch++) | ||
886 | ret |= snd_hda_codec_amp_update(codec, nid, ch, direction, | ||
887 | idx, mask, val); | ||
888 | return ret; | ||
889 | } | ||
890 | |||
891 | #ifdef SND_HDA_NEEDS_RESUME | ||
892 | /* resume the all amp commands from the cache */ | ||
893 | void snd_hda_codec_resume_amp(struct hda_codec *codec) | ||
894 | { | ||
895 | struct hda_amp_info *buffer = codec->amp_cache.buffer; | ||
896 | int i; | ||
897 | |||
898 | for (i = 0; i < codec->amp_cache.size; i++, buffer++) { | ||
899 | u32 key = buffer->head.key; | ||
900 | hda_nid_t nid; | ||
901 | unsigned int idx, dir, ch; | ||
902 | if (!key) | ||
903 | continue; | ||
904 | nid = key & 0xff; | ||
905 | idx = (key >> 16) & 0xff; | ||
906 | dir = (key >> 24) & 0xff; | ||
907 | for (ch = 0; ch < 2; ch++) { | ||
908 | if (!(buffer->head.val & INFO_AMP_VOL(ch))) | ||
909 | continue; | ||
910 | put_vol_mute(codec, buffer, nid, ch, dir, idx, | ||
911 | buffer->vol[ch]); | ||
912 | } | ||
913 | } | ||
914 | } | ||
915 | #endif /* SND_HDA_NEEDS_RESUME */ | ||
801 | 916 | ||
802 | /* | 917 | /* |
803 | * AMP control callbacks | 918 | * AMP control callbacks |
@@ -844,9 +959,11 @@ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, | |||
844 | long *valp = ucontrol->value.integer.value; | 959 | long *valp = ucontrol->value.integer.value; |
845 | 960 | ||
846 | if (chs & 1) | 961 | if (chs & 1) |
847 | *valp++ = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x7f; | 962 | *valp++ = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) |
963 | & HDA_AMP_VOLMASK; | ||
848 | if (chs & 2) | 964 | if (chs & 2) |
849 | *valp = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x7f; | 965 | *valp = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) |
966 | & HDA_AMP_VOLMASK; | ||
850 | return 0; | 967 | return 0; |
851 | } | 968 | } |
852 | 969 | ||
@@ -861,6 +978,7 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, | |||
861 | long *valp = ucontrol->value.integer.value; | 978 | long *valp = ucontrol->value.integer.value; |
862 | int change = 0; | 979 | int change = 0; |
863 | 980 | ||
981 | snd_hda_power_up(codec); | ||
864 | if (chs & 1) { | 982 | if (chs & 1) { |
865 | change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, | 983 | change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, |
866 | 0x7f, *valp); | 984 | 0x7f, *valp); |
@@ -869,6 +987,7 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, | |||
869 | if (chs & 2) | 987 | if (chs & 2) |
870 | change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, | 988 | change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, |
871 | 0x7f, *valp); | 989 | 0x7f, *valp); |
990 | snd_hda_power_down(codec); | ||
872 | return change; | 991 | return change; |
873 | } | 992 | } |
874 | 993 | ||
@@ -923,10 +1042,10 @@ int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, | |||
923 | 1042 | ||
924 | if (chs & 1) | 1043 | if (chs & 1) |
925 | *valp++ = (snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & | 1044 | *valp++ = (snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & |
926 | 0x80) ? 0 : 1; | 1045 | HDA_AMP_MUTE) ? 0 : 1; |
927 | if (chs & 2) | 1046 | if (chs & 2) |
928 | *valp = (snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & | 1047 | *valp = (snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & |
929 | 0x80) ? 0 : 1; | 1048 | HDA_AMP_MUTE) ? 0 : 1; |
930 | return 0; | 1049 | return 0; |
931 | } | 1050 | } |
932 | 1051 | ||
@@ -941,15 +1060,22 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, | |||
941 | long *valp = ucontrol->value.integer.value; | 1060 | long *valp = ucontrol->value.integer.value; |
942 | int change = 0; | 1061 | int change = 0; |
943 | 1062 | ||
1063 | snd_hda_power_up(codec); | ||
944 | if (chs & 1) { | 1064 | if (chs & 1) { |
945 | change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, | 1065 | change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, |
946 | 0x80, *valp ? 0 : 0x80); | 1066 | HDA_AMP_MUTE, |
1067 | *valp ? 0 : HDA_AMP_MUTE); | ||
947 | valp++; | 1068 | valp++; |
948 | } | 1069 | } |
949 | if (chs & 2) | 1070 | if (chs & 2) |
950 | change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, | 1071 | change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, |
951 | 0x80, *valp ? 0 : 0x80); | 1072 | HDA_AMP_MUTE, |
952 | 1073 | *valp ? 0 : HDA_AMP_MUTE); | |
1074 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1075 | if (codec->patch_ops.check_power_status) | ||
1076 | codec->patch_ops.check_power_status(codec, nid); | ||
1077 | #endif | ||
1078 | snd_hda_power_down(codec); | ||
953 | return change; | 1079 | return change; |
954 | } | 1080 | } |
955 | 1081 | ||
@@ -1002,6 +1128,93 @@ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, | |||
1002 | } | 1128 | } |
1003 | 1129 | ||
1004 | /* | 1130 | /* |
1131 | * generic bound volume/swtich controls | ||
1132 | */ | ||
1133 | int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol, | ||
1134 | struct snd_ctl_elem_info *uinfo) | ||
1135 | { | ||
1136 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1137 | struct hda_bind_ctls *c; | ||
1138 | int err; | ||
1139 | |||
1140 | c = (struct hda_bind_ctls *)kcontrol->private_value; | ||
1141 | mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ | ||
1142 | kcontrol->private_value = *c->values; | ||
1143 | err = c->ops->info(kcontrol, uinfo); | ||
1144 | kcontrol->private_value = (long)c; | ||
1145 | mutex_unlock(&codec->spdif_mutex); | ||
1146 | return err; | ||
1147 | } | ||
1148 | |||
1149 | int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, | ||
1150 | struct snd_ctl_elem_value *ucontrol) | ||
1151 | { | ||
1152 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1153 | struct hda_bind_ctls *c; | ||
1154 | int err; | ||
1155 | |||
1156 | c = (struct hda_bind_ctls *)kcontrol->private_value; | ||
1157 | mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ | ||
1158 | kcontrol->private_value = *c->values; | ||
1159 | err = c->ops->get(kcontrol, ucontrol); | ||
1160 | kcontrol->private_value = (long)c; | ||
1161 | mutex_unlock(&codec->spdif_mutex); | ||
1162 | return err; | ||
1163 | } | ||
1164 | |||
1165 | int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, | ||
1166 | struct snd_ctl_elem_value *ucontrol) | ||
1167 | { | ||
1168 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1169 | struct hda_bind_ctls *c; | ||
1170 | unsigned long *vals; | ||
1171 | int err = 0, change = 0; | ||
1172 | |||
1173 | c = (struct hda_bind_ctls *)kcontrol->private_value; | ||
1174 | mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ | ||
1175 | for (vals = c->values; *vals; vals++) { | ||
1176 | kcontrol->private_value = *vals; | ||
1177 | err = c->ops->put(kcontrol, ucontrol); | ||
1178 | if (err < 0) | ||
1179 | break; | ||
1180 | change |= err; | ||
1181 | } | ||
1182 | kcontrol->private_value = (long)c; | ||
1183 | mutex_unlock(&codec->spdif_mutex); | ||
1184 | return err < 0 ? err : change; | ||
1185 | } | ||
1186 | |||
1187 | int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, | ||
1188 | unsigned int size, unsigned int __user *tlv) | ||
1189 | { | ||
1190 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1191 | struct hda_bind_ctls *c; | ||
1192 | int err; | ||
1193 | |||
1194 | c = (struct hda_bind_ctls *)kcontrol->private_value; | ||
1195 | mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ | ||
1196 | kcontrol->private_value = *c->values; | ||
1197 | err = c->ops->tlv(kcontrol, op_flag, size, tlv); | ||
1198 | kcontrol->private_value = (long)c; | ||
1199 | mutex_unlock(&codec->spdif_mutex); | ||
1200 | return err; | ||
1201 | } | ||
1202 | |||
1203 | struct hda_ctl_ops snd_hda_bind_vol = { | ||
1204 | .info = snd_hda_mixer_amp_volume_info, | ||
1205 | .get = snd_hda_mixer_amp_volume_get, | ||
1206 | .put = snd_hda_mixer_amp_volume_put, | ||
1207 | .tlv = snd_hda_mixer_amp_tlv | ||
1208 | }; | ||
1209 | |||
1210 | struct hda_ctl_ops snd_hda_bind_sw = { | ||
1211 | .info = snd_hda_mixer_amp_switch_info, | ||
1212 | .get = snd_hda_mixer_amp_switch_get, | ||
1213 | .put = snd_hda_mixer_amp_switch_put, | ||
1214 | .tlv = snd_hda_mixer_amp_tlv | ||
1215 | }; | ||
1216 | |||
1217 | /* | ||
1005 | * SPDIF out controls | 1218 | * SPDIF out controls |
1006 | */ | 1219 | */ |
1007 | 1220 | ||
@@ -1118,26 +1331,20 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol, | |||
1118 | change = codec->spdif_ctls != val; | 1331 | change = codec->spdif_ctls != val; |
1119 | codec->spdif_ctls = val; | 1332 | codec->spdif_ctls = val; |
1120 | 1333 | ||
1121 | if (change || codec->in_resume) { | 1334 | if (change) { |
1122 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, | 1335 | snd_hda_codec_write_cache(codec, nid, 0, |
1123 | val & 0xff); | 1336 | AC_VERB_SET_DIGI_CONVERT_1, |
1124 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_2, | 1337 | val & 0xff); |
1125 | val >> 8); | 1338 | snd_hda_codec_write_cache(codec, nid, 0, |
1339 | AC_VERB_SET_DIGI_CONVERT_2, | ||
1340 | val >> 8); | ||
1126 | } | 1341 | } |
1127 | 1342 | ||
1128 | mutex_unlock(&codec->spdif_mutex); | 1343 | mutex_unlock(&codec->spdif_mutex); |
1129 | return change; | 1344 | return change; |
1130 | } | 1345 | } |
1131 | 1346 | ||
1132 | static int snd_hda_spdif_out_switch_info(struct snd_kcontrol *kcontrol, | 1347 | #define snd_hda_spdif_out_switch_info snd_ctl_boolean_mono_info |
1133 | struct snd_ctl_elem_info *uinfo) | ||
1134 | { | ||
1135 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
1136 | uinfo->count = 1; | ||
1137 | uinfo->value.integer.min = 0; | ||
1138 | uinfo->value.integer.max = 1; | ||
1139 | return 0; | ||
1140 | } | ||
1141 | 1348 | ||
1142 | static int snd_hda_spdif_out_switch_get(struct snd_kcontrol *kcontrol, | 1349 | static int snd_hda_spdif_out_switch_get(struct snd_kcontrol *kcontrol, |
1143 | struct snd_ctl_elem_value *ucontrol) | 1350 | struct snd_ctl_elem_value *ucontrol) |
@@ -1161,17 +1368,16 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol, | |||
1161 | if (ucontrol->value.integer.value[0]) | 1368 | if (ucontrol->value.integer.value[0]) |
1162 | val |= AC_DIG1_ENABLE; | 1369 | val |= AC_DIG1_ENABLE; |
1163 | change = codec->spdif_ctls != val; | 1370 | change = codec->spdif_ctls != val; |
1164 | if (change || codec->in_resume) { | 1371 | if (change) { |
1165 | codec->spdif_ctls = val; | 1372 | codec->spdif_ctls = val; |
1166 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, | 1373 | snd_hda_codec_write_cache(codec, nid, 0, |
1167 | val & 0xff); | 1374 | AC_VERB_SET_DIGI_CONVERT_1, |
1375 | val & 0xff); | ||
1168 | /* unmute amp switch (if any) */ | 1376 | /* unmute amp switch (if any) */ |
1169 | if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) && | 1377 | if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) && |
1170 | (val & AC_DIG1_ENABLE)) | 1378 | (val & AC_DIG1_ENABLE)) |
1171 | snd_hda_codec_write(codec, nid, 0, | 1379 | snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, |
1172 | AC_VERB_SET_AMP_GAIN_MUTE, | 1380 | HDA_AMP_MUTE, 0); |
1173 | AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | | ||
1174 | AC_AMP_SET_OUTPUT); | ||
1175 | } | 1381 | } |
1176 | mutex_unlock(&codec->spdif_mutex); | 1382 | mutex_unlock(&codec->spdif_mutex); |
1177 | return change; | 1383 | return change; |
@@ -1219,8 +1425,7 @@ static struct snd_kcontrol_new dig_mixes[] = { | |||
1219 | * | 1425 | * |
1220 | * Returns 0 if successful, or a negative error code. | 1426 | * Returns 0 if successful, or a negative error code. |
1221 | */ | 1427 | */ |
1222 | int __devinit snd_hda_create_spdif_out_ctls(struct hda_codec *codec, | 1428 | int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) |
1223 | hda_nid_t nid) | ||
1224 | { | 1429 | { |
1225 | int err; | 1430 | int err; |
1226 | struct snd_kcontrol *kctl; | 1431 | struct snd_kcontrol *kctl; |
@@ -1264,10 +1469,10 @@ static int snd_hda_spdif_in_switch_put(struct snd_kcontrol *kcontrol, | |||
1264 | 1469 | ||
1265 | mutex_lock(&codec->spdif_mutex); | 1470 | mutex_lock(&codec->spdif_mutex); |
1266 | change = codec->spdif_in_enable != val; | 1471 | change = codec->spdif_in_enable != val; |
1267 | if (change || codec->in_resume) { | 1472 | if (change) { |
1268 | codec->spdif_in_enable = val; | 1473 | codec->spdif_in_enable = val; |
1269 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, | 1474 | snd_hda_codec_write_cache(codec, nid, 0, |
1270 | val); | 1475 | AC_VERB_SET_DIGI_CONVERT_1, val); |
1271 | } | 1476 | } |
1272 | mutex_unlock(&codec->spdif_mutex); | 1477 | mutex_unlock(&codec->spdif_mutex); |
1273 | return change; | 1478 | return change; |
@@ -1318,8 +1523,7 @@ static struct snd_kcontrol_new dig_in_ctls[] = { | |||
1318 | * | 1523 | * |
1319 | * Returns 0 if successful, or a negative error code. | 1524 | * Returns 0 if successful, or a negative error code. |
1320 | */ | 1525 | */ |
1321 | int __devinit snd_hda_create_spdif_in_ctls(struct hda_codec *codec, | 1526 | int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) |
1322 | hda_nid_t nid) | ||
1323 | { | 1527 | { |
1324 | int err; | 1528 | int err; |
1325 | struct snd_kcontrol *kctl; | 1529 | struct snd_kcontrol *kctl; |
@@ -1338,6 +1542,79 @@ int __devinit snd_hda_create_spdif_in_ctls(struct hda_codec *codec, | |||
1338 | return 0; | 1542 | return 0; |
1339 | } | 1543 | } |
1340 | 1544 | ||
1545 | #ifdef SND_HDA_NEEDS_RESUME | ||
1546 | /* | ||
1547 | * command cache | ||
1548 | */ | ||
1549 | |||
1550 | /* build a 32bit cache key with the widget id and the command parameter */ | ||
1551 | #define build_cmd_cache_key(nid, verb) ((verb << 8) | nid) | ||
1552 | #define get_cmd_cache_nid(key) ((key) & 0xff) | ||
1553 | #define get_cmd_cache_cmd(key) (((key) >> 8) & 0xffff) | ||
1554 | |||
1555 | /** | ||
1556 | * snd_hda_codec_write_cache - send a single command with caching | ||
1557 | * @codec: the HDA codec | ||
1558 | * @nid: NID to send the command | ||
1559 | * @direct: direct flag | ||
1560 | * @verb: the verb to send | ||
1561 | * @parm: the parameter for the verb | ||
1562 | * | ||
1563 | * Send a single command without waiting for response. | ||
1564 | * | ||
1565 | * Returns 0 if successful, or a negative error code. | ||
1566 | */ | ||
1567 | int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, | ||
1568 | int direct, unsigned int verb, unsigned int parm) | ||
1569 | { | ||
1570 | int err; | ||
1571 | snd_hda_power_up(codec); | ||
1572 | mutex_lock(&codec->bus->cmd_mutex); | ||
1573 | err = codec->bus->ops.command(codec, nid, direct, verb, parm); | ||
1574 | if (!err) { | ||
1575 | struct hda_cache_head *c; | ||
1576 | u32 key = build_cmd_cache_key(nid, verb); | ||
1577 | c = get_alloc_hash(&codec->cmd_cache, key); | ||
1578 | if (c) | ||
1579 | c->val = parm; | ||
1580 | } | ||
1581 | mutex_unlock(&codec->bus->cmd_mutex); | ||
1582 | snd_hda_power_down(codec); | ||
1583 | return err; | ||
1584 | } | ||
1585 | |||
1586 | /* resume the all commands from the cache */ | ||
1587 | void snd_hda_codec_resume_cache(struct hda_codec *codec) | ||
1588 | { | ||
1589 | struct hda_cache_head *buffer = codec->cmd_cache.buffer; | ||
1590 | int i; | ||
1591 | |||
1592 | for (i = 0; i < codec->cmd_cache.size; i++, buffer++) { | ||
1593 | u32 key = buffer->key; | ||
1594 | if (!key) | ||
1595 | continue; | ||
1596 | snd_hda_codec_write(codec, get_cmd_cache_nid(key), 0, | ||
1597 | get_cmd_cache_cmd(key), buffer->val); | ||
1598 | } | ||
1599 | } | ||
1600 | |||
1601 | /** | ||
1602 | * snd_hda_sequence_write_cache - sequence writes with caching | ||
1603 | * @codec: the HDA codec | ||
1604 | * @seq: VERB array to send | ||
1605 | * | ||
1606 | * Send the commands sequentially from the given array. | ||
1607 | * Thte commands are recorded on cache for power-save and resume. | ||
1608 | * The array must be terminated with NID=0. | ||
1609 | */ | ||
1610 | void snd_hda_sequence_write_cache(struct hda_codec *codec, | ||
1611 | const struct hda_verb *seq) | ||
1612 | { | ||
1613 | for (; seq->nid; seq++) | ||
1614 | snd_hda_codec_write_cache(codec, seq->nid, 0, seq->verb, | ||
1615 | seq->param); | ||
1616 | } | ||
1617 | #endif /* SND_HDA_NEEDS_RESUME */ | ||
1341 | 1618 | ||
1342 | /* | 1619 | /* |
1343 | * set power state of the codec | 1620 | * set power state of the codec |
@@ -1345,23 +1622,86 @@ int __devinit snd_hda_create_spdif_in_ctls(struct hda_codec *codec, | |||
1345 | static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, | 1622 | static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, |
1346 | unsigned int power_state) | 1623 | unsigned int power_state) |
1347 | { | 1624 | { |
1348 | hda_nid_t nid, nid_start; | 1625 | hda_nid_t nid; |
1349 | int nodes; | 1626 | int i; |
1350 | 1627 | ||
1351 | snd_hda_codec_write(codec, fg, 0, AC_VERB_SET_POWER_STATE, | 1628 | snd_hda_codec_write(codec, fg, 0, AC_VERB_SET_POWER_STATE, |
1352 | power_state); | 1629 | power_state); |
1353 | 1630 | ||
1354 | nodes = snd_hda_get_sub_nodes(codec, fg, &nid_start); | 1631 | nid = codec->start_nid; |
1355 | for (nid = nid_start; nid < nodes + nid_start; nid++) { | 1632 | for (i = 0; i < codec->num_nodes; i++, nid++) { |
1356 | if (get_wcaps(codec, nid) & AC_WCAP_POWER) | 1633 | if (get_wcaps(codec, nid) & AC_WCAP_POWER) { |
1634 | unsigned int pincap; | ||
1635 | /* | ||
1636 | * don't power down the widget if it controls eapd | ||
1637 | * and EAPD_BTLENABLE is set. | ||
1638 | */ | ||
1639 | pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); | ||
1640 | if (pincap & AC_PINCAP_EAPD) { | ||
1641 | int eapd = snd_hda_codec_read(codec, nid, | ||
1642 | 0, AC_VERB_GET_EAPD_BTLENABLE, 0); | ||
1643 | eapd &= 0x02; | ||
1644 | if (power_state == AC_PWRST_D3 && eapd) | ||
1645 | continue; | ||
1646 | } | ||
1357 | snd_hda_codec_write(codec, nid, 0, | 1647 | snd_hda_codec_write(codec, nid, 0, |
1358 | AC_VERB_SET_POWER_STATE, | 1648 | AC_VERB_SET_POWER_STATE, |
1359 | power_state); | 1649 | power_state); |
1650 | } | ||
1360 | } | 1651 | } |
1361 | 1652 | ||
1362 | if (power_state == AC_PWRST_D0) | 1653 | if (power_state == AC_PWRST_D0) { |
1654 | unsigned long end_time; | ||
1655 | int state; | ||
1363 | msleep(10); | 1656 | msleep(10); |
1657 | /* wait until the codec reachs to D0 */ | ||
1658 | end_time = jiffies + msecs_to_jiffies(500); | ||
1659 | do { | ||
1660 | state = snd_hda_codec_read(codec, fg, 0, | ||
1661 | AC_VERB_GET_POWER_STATE, 0); | ||
1662 | if (state == power_state) | ||
1663 | break; | ||
1664 | msleep(1); | ||
1665 | } while (time_after_eq(end_time, jiffies)); | ||
1666 | } | ||
1667 | } | ||
1668 | |||
1669 | #ifdef SND_HDA_NEEDS_RESUME | ||
1670 | /* | ||
1671 | * call suspend and power-down; used both from PM and power-save | ||
1672 | */ | ||
1673 | static void hda_call_codec_suspend(struct hda_codec *codec) | ||
1674 | { | ||
1675 | if (codec->patch_ops.suspend) | ||
1676 | codec->patch_ops.suspend(codec, PMSG_SUSPEND); | ||
1677 | hda_set_power_state(codec, | ||
1678 | codec->afg ? codec->afg : codec->mfg, | ||
1679 | AC_PWRST_D3); | ||
1680 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1681 | cancel_delayed_work(&codec->power_work); | ||
1682 | codec->power_on = 0; | ||
1683 | codec->power_transition = 0; | ||
1684 | #endif | ||
1685 | } | ||
1686 | |||
1687 | /* | ||
1688 | * kick up codec; used both from PM and power-save | ||
1689 | */ | ||
1690 | static void hda_call_codec_resume(struct hda_codec *codec) | ||
1691 | { | ||
1692 | hda_set_power_state(codec, | ||
1693 | codec->afg ? codec->afg : codec->mfg, | ||
1694 | AC_PWRST_D0); | ||
1695 | if (codec->patch_ops.resume) | ||
1696 | codec->patch_ops.resume(codec); | ||
1697 | else { | ||
1698 | if (codec->patch_ops.init) | ||
1699 | codec->patch_ops.init(codec); | ||
1700 | snd_hda_codec_resume_amp(codec); | ||
1701 | snd_hda_codec_resume_cache(codec); | ||
1702 | } | ||
1364 | } | 1703 | } |
1704 | #endif /* SND_HDA_NEEDS_RESUME */ | ||
1365 | 1705 | ||
1366 | 1706 | ||
1367 | /** | 1707 | /** |
@@ -1376,28 +1716,24 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus) | |||
1376 | { | 1716 | { |
1377 | struct hda_codec *codec; | 1717 | struct hda_codec *codec; |
1378 | 1718 | ||
1379 | /* build controls */ | ||
1380 | list_for_each_entry(codec, &bus->codec_list, list) { | 1719 | list_for_each_entry(codec, &bus->codec_list, list) { |
1381 | int err; | 1720 | int err = 0; |
1382 | if (!codec->patch_ops.build_controls) | 1721 | /* fake as if already powered-on */ |
1383 | continue; | 1722 | hda_keep_power_on(codec); |
1384 | err = codec->patch_ops.build_controls(codec); | 1723 | /* then fire up */ |
1385 | if (err < 0) | ||
1386 | return err; | ||
1387 | } | ||
1388 | |||
1389 | /* initialize */ | ||
1390 | list_for_each_entry(codec, &bus->codec_list, list) { | ||
1391 | int err; | ||
1392 | hda_set_power_state(codec, | 1724 | hda_set_power_state(codec, |
1393 | codec->afg ? codec->afg : codec->mfg, | 1725 | codec->afg ? codec->afg : codec->mfg, |
1394 | AC_PWRST_D0); | 1726 | AC_PWRST_D0); |
1395 | if (!codec->patch_ops.init) | 1727 | /* continue to initialize... */ |
1396 | continue; | 1728 | if (codec->patch_ops.init) |
1397 | err = codec->patch_ops.init(codec); | 1729 | err = codec->patch_ops.init(codec); |
1730 | if (!err && codec->patch_ops.build_controls) | ||
1731 | err = codec->patch_ops.build_controls(codec); | ||
1732 | snd_hda_power_down(codec); | ||
1398 | if (err < 0) | 1733 | if (err < 0) |
1399 | return err; | 1734 | return err; |
1400 | } | 1735 | } |
1736 | |||
1401 | return 0; | 1737 | return 0; |
1402 | } | 1738 | } |
1403 | 1739 | ||
@@ -1789,9 +2125,9 @@ int __devinit snd_hda_build_pcms(struct hda_bus *bus) | |||
1789 | * | 2125 | * |
1790 | * If no entries are matching, the function returns a negative value. | 2126 | * If no entries are matching, the function returns a negative value. |
1791 | */ | 2127 | */ |
1792 | int __devinit snd_hda_check_board_config(struct hda_codec *codec, | 2128 | int snd_hda_check_board_config(struct hda_codec *codec, |
1793 | int num_configs, const char **models, | 2129 | int num_configs, const char **models, |
1794 | const struct snd_pci_quirk *tbl) | 2130 | const struct snd_pci_quirk *tbl) |
1795 | { | 2131 | { |
1796 | if (codec->bus->modelname && models) { | 2132 | if (codec->bus->modelname && models) { |
1797 | int i; | 2133 | int i; |
@@ -1841,10 +2177,9 @@ int __devinit snd_hda_check_board_config(struct hda_codec *codec, | |||
1841 | * | 2177 | * |
1842 | * Returns 0 if successful, or a negative error code. | 2178 | * Returns 0 if successful, or a negative error code. |
1843 | */ | 2179 | */ |
1844 | int __devinit snd_hda_add_new_ctls(struct hda_codec *codec, | 2180 | int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) |
1845 | struct snd_kcontrol_new *knew) | ||
1846 | { | 2181 | { |
1847 | int err; | 2182 | int err; |
1848 | 2183 | ||
1849 | for (; knew->name; knew++) { | 2184 | for (; knew->name; knew++) { |
1850 | struct snd_kcontrol *kctl; | 2185 | struct snd_kcontrol *kctl; |
@@ -1867,6 +2202,93 @@ int __devinit snd_hda_add_new_ctls(struct hda_codec *codec, | |||
1867 | return 0; | 2202 | return 0; |
1868 | } | 2203 | } |
1869 | 2204 | ||
2205 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
2206 | static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, | ||
2207 | unsigned int power_state); | ||
2208 | |||
2209 | static void hda_power_work(struct work_struct *work) | ||
2210 | { | ||
2211 | struct hda_codec *codec = | ||
2212 | container_of(work, struct hda_codec, power_work.work); | ||
2213 | |||
2214 | if (!codec->power_on || codec->power_count) { | ||
2215 | codec->power_transition = 0; | ||
2216 | return; | ||
2217 | } | ||
2218 | |||
2219 | hda_call_codec_suspend(codec); | ||
2220 | if (codec->bus->ops.pm_notify) | ||
2221 | codec->bus->ops.pm_notify(codec); | ||
2222 | } | ||
2223 | |||
2224 | static void hda_keep_power_on(struct hda_codec *codec) | ||
2225 | { | ||
2226 | codec->power_count++; | ||
2227 | codec->power_on = 1; | ||
2228 | } | ||
2229 | |||
2230 | void snd_hda_power_up(struct hda_codec *codec) | ||
2231 | { | ||
2232 | codec->power_count++; | ||
2233 | if (codec->power_on || codec->power_transition) | ||
2234 | return; | ||
2235 | |||
2236 | codec->power_on = 1; | ||
2237 | if (codec->bus->ops.pm_notify) | ||
2238 | codec->bus->ops.pm_notify(codec); | ||
2239 | hda_call_codec_resume(codec); | ||
2240 | cancel_delayed_work(&codec->power_work); | ||
2241 | codec->power_transition = 0; | ||
2242 | } | ||
2243 | |||
2244 | void snd_hda_power_down(struct hda_codec *codec) | ||
2245 | { | ||
2246 | --codec->power_count; | ||
2247 | if (!codec->power_on || codec->power_count || codec->power_transition) | ||
2248 | return; | ||
2249 | if (power_save) { | ||
2250 | codec->power_transition = 1; /* avoid reentrance */ | ||
2251 | schedule_delayed_work(&codec->power_work, | ||
2252 | msecs_to_jiffies(power_save * 1000)); | ||
2253 | } | ||
2254 | } | ||
2255 | |||
2256 | int snd_hda_check_amp_list_power(struct hda_codec *codec, | ||
2257 | struct hda_loopback_check *check, | ||
2258 | hda_nid_t nid) | ||
2259 | { | ||
2260 | struct hda_amp_list *p; | ||
2261 | int ch, v; | ||
2262 | |||
2263 | if (!check->amplist) | ||
2264 | return 0; | ||
2265 | for (p = check->amplist; p->nid; p++) { | ||
2266 | if (p->nid == nid) | ||
2267 | break; | ||
2268 | } | ||
2269 | if (!p->nid) | ||
2270 | return 0; /* nothing changed */ | ||
2271 | |||
2272 | for (p = check->amplist; p->nid; p++) { | ||
2273 | for (ch = 0; ch < 2; ch++) { | ||
2274 | v = snd_hda_codec_amp_read(codec, p->nid, ch, p->dir, | ||
2275 | p->idx); | ||
2276 | if (!(v & HDA_AMP_MUTE) && v > 0) { | ||
2277 | if (!check->power_on) { | ||
2278 | check->power_on = 1; | ||
2279 | snd_hda_power_up(codec); | ||
2280 | } | ||
2281 | return 1; | ||
2282 | } | ||
2283 | } | ||
2284 | } | ||
2285 | if (check->power_on) { | ||
2286 | check->power_on = 0; | ||
2287 | snd_hda_power_down(codec); | ||
2288 | } | ||
2289 | return 0; | ||
2290 | } | ||
2291 | #endif | ||
1870 | 2292 | ||
1871 | /* | 2293 | /* |
1872 | * Channel mode helper | 2294 | * Channel mode helper |
@@ -1913,12 +2335,12 @@ int snd_hda_ch_mode_put(struct hda_codec *codec, | |||
1913 | 2335 | ||
1914 | mode = ucontrol->value.enumerated.item[0]; | 2336 | mode = ucontrol->value.enumerated.item[0]; |
1915 | snd_assert(mode < num_chmodes, return -EINVAL); | 2337 | snd_assert(mode < num_chmodes, return -EINVAL); |
1916 | if (*max_channelsp == chmode[mode].channels && !codec->in_resume) | 2338 | if (*max_channelsp == chmode[mode].channels) |
1917 | return 0; | 2339 | return 0; |
1918 | /* change the current channel setting */ | 2340 | /* change the current channel setting */ |
1919 | *max_channelsp = chmode[mode].channels; | 2341 | *max_channelsp = chmode[mode].channels; |
1920 | if (chmode[mode].sequence) | 2342 | if (chmode[mode].sequence) |
1921 | snd_hda_sequence_write(codec, chmode[mode].sequence); | 2343 | snd_hda_sequence_write_cache(codec, chmode[mode].sequence); |
1922 | return 1; | 2344 | return 1; |
1923 | } | 2345 | } |
1924 | 2346 | ||
@@ -1933,6 +2355,8 @@ int snd_hda_input_mux_info(const struct hda_input_mux *imux, | |||
1933 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 2355 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
1934 | uinfo->count = 1; | 2356 | uinfo->count = 1; |
1935 | uinfo->value.enumerated.items = imux->num_items; | 2357 | uinfo->value.enumerated.items = imux->num_items; |
2358 | if (!imux->num_items) | ||
2359 | return 0; | ||
1936 | index = uinfo->value.enumerated.item; | 2360 | index = uinfo->value.enumerated.item; |
1937 | if (index >= imux->num_items) | 2361 | if (index >= imux->num_items) |
1938 | index = imux->num_items - 1; | 2362 | index = imux->num_items - 1; |
@@ -1948,13 +2372,15 @@ int snd_hda_input_mux_put(struct hda_codec *codec, | |||
1948 | { | 2372 | { |
1949 | unsigned int idx; | 2373 | unsigned int idx; |
1950 | 2374 | ||
2375 | if (!imux->num_items) | ||
2376 | return 0; | ||
1951 | idx = ucontrol->value.enumerated.item[0]; | 2377 | idx = ucontrol->value.enumerated.item[0]; |
1952 | if (idx >= imux->num_items) | 2378 | if (idx >= imux->num_items) |
1953 | idx = imux->num_items - 1; | 2379 | idx = imux->num_items - 1; |
1954 | if (*cur_val == idx && !codec->in_resume) | 2380 | if (*cur_val == idx) |
1955 | return 0; | 2381 | return 0; |
1956 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, | 2382 | snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, |
1957 | imux->items[idx].index); | 2383 | imux->items[idx].index); |
1958 | *cur_val = idx; | 2384 | *cur_val = idx; |
1959 | return 1; | 2385 | return 1; |
1960 | } | 2386 | } |
@@ -2118,7 +2544,7 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, | |||
2118 | * Helper for automatic ping configuration | 2544 | * Helper for automatic ping configuration |
2119 | */ | 2545 | */ |
2120 | 2546 | ||
2121 | static int __devinit is_in_nid_list(hda_nid_t nid, hda_nid_t *list) | 2547 | static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list) |
2122 | { | 2548 | { |
2123 | for (; *list; list++) | 2549 | for (; *list; list++) |
2124 | if (*list == nid) | 2550 | if (*list == nid) |
@@ -2169,9 +2595,9 @@ static void sort_pins_by_sequence(hda_nid_t * pins, short * sequences, | |||
2169 | * The digital input/output pins are assigned to dig_in_pin and dig_out_pin, | 2595 | * The digital input/output pins are assigned to dig_in_pin and dig_out_pin, |
2170 | * respectively. | 2596 | * respectively. |
2171 | */ | 2597 | */ |
2172 | int __devinit snd_hda_parse_pin_def_config(struct hda_codec *codec, | 2598 | int snd_hda_parse_pin_def_config(struct hda_codec *codec, |
2173 | struct auto_pin_cfg *cfg, | 2599 | struct auto_pin_cfg *cfg, |
2174 | hda_nid_t *ignore_nids) | 2600 | hda_nid_t *ignore_nids) |
2175 | { | 2601 | { |
2176 | hda_nid_t nid, nid_start; | 2602 | hda_nid_t nid, nid_start; |
2177 | int nodes; | 2603 | int nodes; |
@@ -2371,13 +2797,12 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state) | |||
2371 | { | 2797 | { |
2372 | struct hda_codec *codec; | 2798 | struct hda_codec *codec; |
2373 | 2799 | ||
2374 | /* FIXME: should handle power widget capabilities */ | ||
2375 | list_for_each_entry(codec, &bus->codec_list, list) { | 2800 | list_for_each_entry(codec, &bus->codec_list, list) { |
2376 | if (codec->patch_ops.suspend) | 2801 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
2377 | codec->patch_ops.suspend(codec, state); | 2802 | if (!codec->power_on) |
2378 | hda_set_power_state(codec, | 2803 | continue; |
2379 | codec->afg ? codec->afg : codec->mfg, | 2804 | #endif |
2380 | AC_PWRST_D3); | 2805 | hda_call_codec_suspend(codec); |
2381 | } | 2806 | } |
2382 | return 0; | 2807 | return 0; |
2383 | } | 2808 | } |
@@ -2388,76 +2813,30 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state) | |||
2388 | * @state: resume state | 2813 | * @state: resume state |
2389 | * | 2814 | * |
2390 | * Returns 0 if successful. | 2815 | * Returns 0 if successful. |
2816 | * | ||
2817 | * This fucntion is defined only when POWER_SAVE isn't set. | ||
2818 | * In the power-save mode, the codec is resumed dynamically. | ||
2391 | */ | 2819 | */ |
2392 | int snd_hda_resume(struct hda_bus *bus) | 2820 | int snd_hda_resume(struct hda_bus *bus) |
2393 | { | 2821 | { |
2394 | struct hda_codec *codec; | 2822 | struct hda_codec *codec; |
2395 | 2823 | ||
2396 | list_for_each_entry(codec, &bus->codec_list, list) { | 2824 | list_for_each_entry(codec, &bus->codec_list, list) { |
2397 | hda_set_power_state(codec, | 2825 | if (snd_hda_codec_needs_resume(codec)) |
2398 | codec->afg ? codec->afg : codec->mfg, | 2826 | hda_call_codec_resume(codec); |
2399 | AC_PWRST_D0); | ||
2400 | if (codec->patch_ops.resume) | ||
2401 | codec->patch_ops.resume(codec); | ||
2402 | } | 2827 | } |
2403 | return 0; | 2828 | return 0; |
2404 | } | 2829 | } |
2405 | 2830 | #ifdef CONFIG_SND_HDA_POWER_SAVE | |
2406 | /** | 2831 | int snd_hda_codecs_inuse(struct hda_bus *bus) |
2407 | * snd_hda_resume_ctls - resume controls in the new control list | ||
2408 | * @codec: the HDA codec | ||
2409 | * @knew: the array of struct snd_kcontrol_new | ||
2410 | * | ||
2411 | * This function resumes the mixer controls in the struct snd_kcontrol_new array, | ||
2412 | * originally for snd_hda_add_new_ctls(). | ||
2413 | * The array must be terminated with an empty entry as terminator. | ||
2414 | */ | ||
2415 | int snd_hda_resume_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) | ||
2416 | { | 2832 | { |
2417 | struct snd_ctl_elem_value *val; | 2833 | struct hda_codec *codec; |
2418 | 2834 | ||
2419 | val = kmalloc(sizeof(*val), GFP_KERNEL); | 2835 | list_for_each_entry(codec, &bus->codec_list, list) { |
2420 | if (!val) | 2836 | if (snd_hda_codec_needs_resume(codec)) |
2421 | return -ENOMEM; | 2837 | return 1; |
2422 | codec->in_resume = 1; | ||
2423 | for (; knew->name; knew++) { | ||
2424 | int i, count; | ||
2425 | count = knew->count ? knew->count : 1; | ||
2426 | for (i = 0; i < count; i++) { | ||
2427 | memset(val, 0, sizeof(*val)); | ||
2428 | val->id.iface = knew->iface; | ||
2429 | val->id.device = knew->device; | ||
2430 | val->id.subdevice = knew->subdevice; | ||
2431 | strcpy(val->id.name, knew->name); | ||
2432 | val->id.index = knew->index ? knew->index : i; | ||
2433 | /* Assume that get callback reads only from cache, | ||
2434 | * not accessing to the real hardware | ||
2435 | */ | ||
2436 | if (snd_ctl_elem_read(codec->bus->card, val) < 0) | ||
2437 | continue; | ||
2438 | snd_ctl_elem_write(codec->bus->card, NULL, val); | ||
2439 | } | ||
2440 | } | 2838 | } |
2441 | codec->in_resume = 0; | ||
2442 | kfree(val); | ||
2443 | return 0; | 2839 | return 0; |
2444 | } | 2840 | } |
2445 | 2841 | #endif | |
2446 | /** | ||
2447 | * snd_hda_resume_spdif_out - resume the digital out | ||
2448 | * @codec: the HDA codec | ||
2449 | */ | ||
2450 | int snd_hda_resume_spdif_out(struct hda_codec *codec) | ||
2451 | { | ||
2452 | return snd_hda_resume_ctls(codec, dig_mixes); | ||
2453 | } | ||
2454 | |||
2455 | /** | ||
2456 | * snd_hda_resume_spdif_in - resume the digital in | ||
2457 | * @codec: the HDA codec | ||
2458 | */ | ||
2459 | int snd_hda_resume_spdif_in(struct hda_codec *codec) | ||
2460 | { | ||
2461 | return snd_hda_resume_ctls(codec, dig_in_ctls); | ||
2462 | } | ||
2463 | #endif | 2842 | #endif |
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 56c26e7ccdf1..2bce925d84ef 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h | |||
@@ -24,6 +24,11 @@ | |||
24 | #include <sound/info.h> | 24 | #include <sound/info.h> |
25 | #include <sound/control.h> | 25 | #include <sound/control.h> |
26 | #include <sound/pcm.h> | 26 | #include <sound/pcm.h> |
27 | #include <sound/hwdep.h> | ||
28 | |||
29 | #if defined(CONFIG_PM) || defined(CONFIG_SND_HDA_POWER_SAVE) | ||
30 | #define SND_HDA_NEEDS_RESUME /* resume control code is required */ | ||
31 | #endif | ||
27 | 32 | ||
28 | /* | 33 | /* |
29 | * nodes | 34 | * nodes |
@@ -199,7 +204,9 @@ enum { | |||
199 | #define AC_AMPCAP_OFFSET_SHIFT 0 | 204 | #define AC_AMPCAP_OFFSET_SHIFT 0 |
200 | #define AC_AMPCAP_NUM_STEPS (0x7f<<8) /* number of steps */ | 205 | #define AC_AMPCAP_NUM_STEPS (0x7f<<8) /* number of steps */ |
201 | #define AC_AMPCAP_NUM_STEPS_SHIFT 8 | 206 | #define AC_AMPCAP_NUM_STEPS_SHIFT 8 |
202 | #define AC_AMPCAP_STEP_SIZE (0x7f<<16) /* step size 0-32dB in 0.25dB */ | 207 | #define AC_AMPCAP_STEP_SIZE (0x7f<<16) /* step size 0-32dB |
208 | * in 0.25dB | ||
209 | */ | ||
203 | #define AC_AMPCAP_STEP_SIZE_SHIFT 16 | 210 | #define AC_AMPCAP_STEP_SIZE_SHIFT 16 |
204 | #define AC_AMPCAP_MUTE (1<<31) /* mute capable */ | 211 | #define AC_AMPCAP_MUTE (1<<31) /* mute capable */ |
205 | #define AC_AMPCAP_MUTE_SHIFT 31 | 212 | #define AC_AMPCAP_MUTE_SHIFT 31 |
@@ -409,6 +416,10 @@ struct hda_bus_ops { | |||
409 | unsigned int (*get_response)(struct hda_codec *codec); | 416 | unsigned int (*get_response)(struct hda_codec *codec); |
410 | /* free the private data */ | 417 | /* free the private data */ |
411 | void (*private_free)(struct hda_bus *); | 418 | void (*private_free)(struct hda_bus *); |
419 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
420 | /* notify power-up/down from codec to contoller */ | ||
421 | void (*pm_notify)(struct hda_codec *codec); | ||
422 | #endif | ||
412 | }; | 423 | }; |
413 | 424 | ||
414 | /* template to pass to the bus constructor */ | 425 | /* template to pass to the bus constructor */ |
@@ -436,7 +447,8 @@ struct hda_bus { | |||
436 | 447 | ||
437 | /* codec linked list */ | 448 | /* codec linked list */ |
438 | struct list_head codec_list; | 449 | struct list_head codec_list; |
439 | struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1]; /* caddr -> codec */ | 450 | /* link caddr -> codec */ |
451 | struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1]; | ||
440 | 452 | ||
441 | struct mutex cmd_mutex; | 453 | struct mutex cmd_mutex; |
442 | 454 | ||
@@ -469,19 +481,34 @@ struct hda_codec_ops { | |||
469 | int (*init)(struct hda_codec *codec); | 481 | int (*init)(struct hda_codec *codec); |
470 | void (*free)(struct hda_codec *codec); | 482 | void (*free)(struct hda_codec *codec); |
471 | void (*unsol_event)(struct hda_codec *codec, unsigned int res); | 483 | void (*unsol_event)(struct hda_codec *codec, unsigned int res); |
472 | #ifdef CONFIG_PM | 484 | #ifdef SND_HDA_NEEDS_RESUME |
473 | int (*suspend)(struct hda_codec *codec, pm_message_t state); | 485 | int (*suspend)(struct hda_codec *codec, pm_message_t state); |
474 | int (*resume)(struct hda_codec *codec); | 486 | int (*resume)(struct hda_codec *codec); |
475 | #endif | 487 | #endif |
488 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
489 | int (*check_power_status)(struct hda_codec *codec, hda_nid_t nid); | ||
490 | #endif | ||
476 | }; | 491 | }; |
477 | 492 | ||
478 | /* record for amp information cache */ | 493 | /* record for amp information cache */ |
479 | struct hda_amp_info { | 494 | struct hda_cache_head { |
480 | u32 key; /* hash key */ | 495 | u32 key; /* hash key */ |
496 | u16 val; /* assigned value */ | ||
497 | u16 next; /* next link; -1 = terminal */ | ||
498 | }; | ||
499 | |||
500 | struct hda_amp_info { | ||
501 | struct hda_cache_head head; | ||
481 | u32 amp_caps; /* amp capabilities */ | 502 | u32 amp_caps; /* amp capabilities */ |
482 | u16 vol[2]; /* current volume & mute */ | 503 | u16 vol[2]; /* current volume & mute */ |
483 | u16 status; /* update flag */ | 504 | }; |
484 | u16 next; /* next link */ | 505 | |
506 | struct hda_cache_rec { | ||
507 | u16 hash[64]; /* hash table for index */ | ||
508 | unsigned int num_entries; /* number of assigned entries */ | ||
509 | unsigned int size; /* allocated size */ | ||
510 | unsigned int record_size; /* record size (including header) */ | ||
511 | void *buffer; /* hash table entries */ | ||
485 | }; | 512 | }; |
486 | 513 | ||
487 | /* PCM callbacks */ | 514 | /* PCM callbacks */ |
@@ -499,7 +526,7 @@ struct hda_pcm_ops { | |||
499 | 526 | ||
500 | /* PCM information for each substream */ | 527 | /* PCM information for each substream */ |
501 | struct hda_pcm_stream { | 528 | struct hda_pcm_stream { |
502 | unsigned int substreams; /* number of substreams, 0 = not exist */ | 529 | unsigned int substreams; /* number of substreams, 0 = not exist*/ |
503 | unsigned int channels_min; /* min. number of channels */ | 530 | unsigned int channels_min; /* min. number of channels */ |
504 | unsigned int channels_max; /* max. number of channels */ | 531 | unsigned int channels_max; /* max. number of channels */ |
505 | hda_nid_t nid; /* default NID to query rates/formats/bps, or set up */ | 532 | hda_nid_t nid; /* default NID to query rates/formats/bps, or set up */ |
@@ -536,11 +563,6 @@ struct hda_codec { | |||
536 | /* set by patch */ | 563 | /* set by patch */ |
537 | struct hda_codec_ops patch_ops; | 564 | struct hda_codec_ops patch_ops; |
538 | 565 | ||
539 | /* resume phase - all controls should update even if | ||
540 | * the values are not changed | ||
541 | */ | ||
542 | unsigned int in_resume; | ||
543 | |||
544 | /* PCM to create, set by patch_ops.build_pcms callback */ | 566 | /* PCM to create, set by patch_ops.build_pcms callback */ |
545 | unsigned int num_pcms; | 567 | unsigned int num_pcms; |
546 | struct hda_pcm *pcm_info; | 568 | struct hda_pcm *pcm_info; |
@@ -553,16 +575,22 @@ struct hda_codec { | |||
553 | hda_nid_t start_nid; | 575 | hda_nid_t start_nid; |
554 | u32 *wcaps; | 576 | u32 *wcaps; |
555 | 577 | ||
556 | /* hash for amp access */ | 578 | struct hda_cache_rec amp_cache; /* cache for amp access */ |
557 | u16 amp_hash[32]; | 579 | struct hda_cache_rec cmd_cache; /* cache for other commands */ |
558 | int num_amp_entries; | ||
559 | int amp_info_size; | ||
560 | struct hda_amp_info *amp_info; | ||
561 | 580 | ||
562 | struct mutex spdif_mutex; | 581 | struct mutex spdif_mutex; |
563 | unsigned int spdif_status; /* IEC958 status bits */ | 582 | unsigned int spdif_status; /* IEC958 status bits */ |
564 | unsigned short spdif_ctls; /* SPDIF control bits */ | 583 | unsigned short spdif_ctls; /* SPDIF control bits */ |
565 | unsigned int spdif_in_enable; /* SPDIF input enable? */ | 584 | unsigned int spdif_in_enable; /* SPDIF input enable? */ |
585 | |||
586 | struct snd_hwdep *hwdep; /* assigned hwdep device */ | ||
587 | |||
588 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
589 | unsigned int power_on :1; /* current (global) power-state */ | ||
590 | unsigned int power_transition :1; /* power-state in transition */ | ||
591 | int power_count; /* current (global) power refcount */ | ||
592 | struct delayed_work power_work; /* delayed task for powerdown */ | ||
593 | #endif | ||
566 | }; | 594 | }; |
567 | 595 | ||
568 | /* direction */ | 596 | /* direction */ |
@@ -582,13 +610,17 @@ int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, | |||
582 | /* | 610 | /* |
583 | * low level functions | 611 | * low level functions |
584 | */ | 612 | */ |
585 | unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, int direct, | 613 | unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, |
614 | int direct, | ||
586 | unsigned int verb, unsigned int parm); | 615 | unsigned int verb, unsigned int parm); |
587 | int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, | 616 | int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, |
588 | unsigned int verb, unsigned int parm); | 617 | unsigned int verb, unsigned int parm); |
589 | #define snd_hda_param_read(codec, nid, param) snd_hda_codec_read(codec, nid, 0, AC_VERB_PARAMETERS, param) | 618 | #define snd_hda_param_read(codec, nid, param) \ |
590 | int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *start_id); | 619 | snd_hda_codec_read(codec, nid, 0, AC_VERB_PARAMETERS, param) |
591 | int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *conn_list, int max_conns); | 620 | int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, |
621 | hda_nid_t *start_id); | ||
622 | int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, | ||
623 | hda_nid_t *conn_list, int max_conns); | ||
592 | 624 | ||
593 | struct hda_verb { | 625 | struct hda_verb { |
594 | hda_nid_t nid; | 626 | hda_nid_t nid; |
@@ -596,11 +628,24 @@ struct hda_verb { | |||
596 | u32 param; | 628 | u32 param; |
597 | }; | 629 | }; |
598 | 630 | ||
599 | void snd_hda_sequence_write(struct hda_codec *codec, const struct hda_verb *seq); | 631 | void snd_hda_sequence_write(struct hda_codec *codec, |
632 | const struct hda_verb *seq); | ||
600 | 633 | ||
601 | /* unsolicited event */ | 634 | /* unsolicited event */ |
602 | int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex); | 635 | int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex); |
603 | 636 | ||
637 | /* cached write */ | ||
638 | #ifdef SND_HDA_NEEDS_RESUME | ||
639 | int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, | ||
640 | int direct, unsigned int verb, unsigned int parm); | ||
641 | void snd_hda_sequence_write_cache(struct hda_codec *codec, | ||
642 | const struct hda_verb *seq); | ||
643 | void snd_hda_codec_resume_cache(struct hda_codec *codec); | ||
644 | #else | ||
645 | #define snd_hda_codec_write_cache snd_hda_codec_write | ||
646 | #define snd_hda_sequence_write_cache snd_hda_sequence_write | ||
647 | #endif | ||
648 | |||
604 | /* | 649 | /* |
605 | * Mixer | 650 | * Mixer |
606 | */ | 651 | */ |
@@ -610,10 +655,13 @@ int snd_hda_build_controls(struct hda_bus *bus); | |||
610 | * PCM | 655 | * PCM |
611 | */ | 656 | */ |
612 | int snd_hda_build_pcms(struct hda_bus *bus); | 657 | int snd_hda_build_pcms(struct hda_bus *bus); |
613 | void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag, | 658 | void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, |
659 | u32 stream_tag, | ||
614 | int channel_id, int format); | 660 | int channel_id, int format); |
615 | unsigned int snd_hda_calc_stream_format(unsigned int rate, unsigned int channels, | 661 | unsigned int snd_hda_calc_stream_format(unsigned int rate, |
616 | unsigned int format, unsigned int maxbps); | 662 | unsigned int channels, |
663 | unsigned int format, | ||
664 | unsigned int maxbps); | ||
617 | int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, | 665 | int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, |
618 | u32 *ratesp, u64 *formatsp, unsigned int *bpsp); | 666 | u32 *ratesp, u64 *formatsp, unsigned int *bpsp); |
619 | int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, | 667 | int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, |
@@ -632,4 +680,19 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state); | |||
632 | int snd_hda_resume(struct hda_bus *bus); | 680 | int snd_hda_resume(struct hda_bus *bus); |
633 | #endif | 681 | #endif |
634 | 682 | ||
683 | /* | ||
684 | * power saving | ||
685 | */ | ||
686 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
687 | void snd_hda_power_up(struct hda_codec *codec); | ||
688 | void snd_hda_power_down(struct hda_codec *codec); | ||
689 | #define snd_hda_codec_needs_resume(codec) codec->power_count | ||
690 | int snd_hda_codecs_inuse(struct hda_bus *bus); | ||
691 | #else | ||
692 | static inline void snd_hda_power_up(struct hda_codec *codec) {} | ||
693 | static inline void snd_hda_power_down(struct hda_codec *codec) {} | ||
694 | #define snd_hda_codec_needs_resume(codec) 1 | ||
695 | #define snd_hda_codecs_inuse(bus) 1 | ||
696 | #endif | ||
697 | |||
635 | #endif /* __SOUND_HDA_CODEC_H */ | 698 | #endif /* __SOUND_HDA_CODEC_H */ |
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 000287f7da43..c957eb58de5c 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c | |||
@@ -70,6 +70,13 @@ struct hda_gspec { | |||
70 | struct hda_pcm pcm_rec; /* PCM information */ | 70 | struct hda_pcm pcm_rec; /* PCM information */ |
71 | 71 | ||
72 | struct list_head nid_list; /* list of widgets */ | 72 | struct list_head nid_list; /* list of widgets */ |
73 | |||
74 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
75 | #define MAX_LOOPBACK_AMPS 7 | ||
76 | struct hda_loopback_check loopback; | ||
77 | int num_loopbacks; | ||
78 | struct hda_amp_list loopback_list[MAX_LOOPBACK_AMPS + 1]; | ||
79 | #endif | ||
73 | }; | 80 | }; |
74 | 81 | ||
75 | /* | 82 | /* |
@@ -88,13 +95,12 @@ struct hda_gspec { | |||
88 | static void snd_hda_generic_free(struct hda_codec *codec) | 95 | static void snd_hda_generic_free(struct hda_codec *codec) |
89 | { | 96 | { |
90 | struct hda_gspec *spec = codec->spec; | 97 | struct hda_gspec *spec = codec->spec; |
91 | struct list_head *p, *n; | 98 | struct hda_gnode *node, *n; |
92 | 99 | ||
93 | if (! spec) | 100 | if (! spec) |
94 | return; | 101 | return; |
95 | /* free all widgets */ | 102 | /* free all widgets */ |
96 | list_for_each_safe(p, n, &spec->nid_list) { | 103 | list_for_each_entry_safe(node, n, &spec->nid_list, list) { |
97 | struct hda_gnode *node = list_entry(p, struct hda_gnode, list); | ||
98 | if (node->conn_list != node->slist) | 104 | if (node->conn_list != node->slist) |
99 | kfree(node->conn_list); | 105 | kfree(node->conn_list); |
100 | kfree(node); | 106 | kfree(node); |
@@ -196,11 +202,9 @@ static int build_afg_tree(struct hda_codec *codec) | |||
196 | /* FIXME: should avoid the braindead linear search */ | 202 | /* FIXME: should avoid the braindead linear search */ |
197 | static struct hda_gnode *hda_get_node(struct hda_gspec *spec, hda_nid_t nid) | 203 | static struct hda_gnode *hda_get_node(struct hda_gspec *spec, hda_nid_t nid) |
198 | { | 204 | { |
199 | struct list_head *p; | ||
200 | struct hda_gnode *node; | 205 | struct hda_gnode *node; |
201 | 206 | ||
202 | list_for_each(p, &spec->nid_list) { | 207 | list_for_each_entry(node, &spec->nid_list, list) { |
203 | node = list_entry(p, struct hda_gnode, list); | ||
204 | if (node->nid == nid) | 208 | if (node->nid == nid) |
205 | return node; | 209 | return node; |
206 | } | 210 | } |
@@ -218,9 +222,8 @@ static int unmute_output(struct hda_codec *codec, struct hda_gnode *node) | |||
218 | ofs = (node->amp_out_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; | 222 | ofs = (node->amp_out_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; |
219 | if (val >= ofs) | 223 | if (val >= ofs) |
220 | val -= ofs; | 224 | val -= ofs; |
221 | val |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT; | 225 | snd_hda_codec_amp_stereo(codec, node->nid, HDA_OUTPUT, 0, 0xff, val); |
222 | val |= AC_AMP_SET_OUTPUT; | 226 | return 0; |
223 | return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, val); | ||
224 | } | 227 | } |
225 | 228 | ||
226 | /* | 229 | /* |
@@ -234,11 +237,8 @@ static int unmute_input(struct hda_codec *codec, struct hda_gnode *node, unsigne | |||
234 | ofs = (node->amp_in_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; | 237 | ofs = (node->amp_in_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; |
235 | if (val >= ofs) | 238 | if (val >= ofs) |
236 | val -= ofs; | 239 | val -= ofs; |
237 | val |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT; | 240 | snd_hda_codec_amp_stereo(codec, node->nid, HDA_INPUT, index, 0xff, val); |
238 | val |= AC_AMP_SET_INPUT; | 241 | return 0; |
239 | // awk added - fixed to allow unmuting of indexed amps | ||
240 | val |= index << AC_AMP_SET_INDEX_SHIFT; | ||
241 | return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, val); | ||
242 | } | 242 | } |
243 | 243 | ||
244 | /* | 244 | /* |
@@ -248,7 +248,8 @@ static int select_input_connection(struct hda_codec *codec, struct hda_gnode *no | |||
248 | unsigned int index) | 248 | unsigned int index) |
249 | { | 249 | { |
250 | snd_printdd("CONNECT: NID=0x%x IDX=0x%x\n", node->nid, index); | 250 | snd_printdd("CONNECT: NID=0x%x IDX=0x%x\n", node->nid, index); |
251 | return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_CONNECT_SEL, index); | 251 | return snd_hda_codec_write_cache(codec, node->nid, 0, |
252 | AC_VERB_SET_CONNECT_SEL, index); | ||
252 | } | 253 | } |
253 | 254 | ||
254 | /* | 255 | /* |
@@ -256,11 +257,9 @@ static int select_input_connection(struct hda_codec *codec, struct hda_gnode *no | |||
256 | */ | 257 | */ |
257 | static void clear_check_flags(struct hda_gspec *spec) | 258 | static void clear_check_flags(struct hda_gspec *spec) |
258 | { | 259 | { |
259 | struct list_head *p; | ||
260 | struct hda_gnode *node; | 260 | struct hda_gnode *node; |
261 | 261 | ||
262 | list_for_each(p, &spec->nid_list) { | 262 | list_for_each_entry(node, &spec->nid_list, list) { |
263 | node = list_entry(p, struct hda_gnode, list); | ||
264 | node->checked = 0; | 263 | node->checked = 0; |
265 | } | 264 | } |
266 | } | 265 | } |
@@ -343,12 +342,10 @@ static struct hda_gnode *parse_output_jack(struct hda_codec *codec, | |||
343 | struct hda_gspec *spec, | 342 | struct hda_gspec *spec, |
344 | int jack_type) | 343 | int jack_type) |
345 | { | 344 | { |
346 | struct list_head *p; | ||
347 | struct hda_gnode *node; | 345 | struct hda_gnode *node; |
348 | int err; | 346 | int err; |
349 | 347 | ||
350 | list_for_each(p, &spec->nid_list) { | 348 | list_for_each_entry(node, &spec->nid_list, list) { |
351 | node = list_entry(p, struct hda_gnode, list); | ||
352 | if (node->type != AC_WID_PIN) | 349 | if (node->type != AC_WID_PIN) |
353 | continue; | 350 | continue; |
354 | /* output capable? */ | 351 | /* output capable? */ |
@@ -379,7 +376,7 @@ static struct hda_gnode *parse_output_jack(struct hda_codec *codec, | |||
379 | /* unmute the PIN output */ | 376 | /* unmute the PIN output */ |
380 | unmute_output(codec, node); | 377 | unmute_output(codec, node); |
381 | /* set PIN-Out enable */ | 378 | /* set PIN-Out enable */ |
382 | snd_hda_codec_write(codec, node->nid, 0, | 379 | snd_hda_codec_write_cache(codec, node->nid, 0, |
383 | AC_VERB_SET_PIN_WIDGET_CONTROL, | 380 | AC_VERB_SET_PIN_WIDGET_CONTROL, |
384 | AC_PINCTL_OUT_EN | | 381 | AC_PINCTL_OUT_EN | |
385 | ((node->pin_caps & AC_PINCAP_HP_DRV) ? | 382 | ((node->pin_caps & AC_PINCAP_HP_DRV) ? |
@@ -570,7 +567,8 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec, | |||
570 | /* unmute the PIN external input */ | 567 | /* unmute the PIN external input */ |
571 | unmute_input(codec, node, 0); /* index = 0? */ | 568 | unmute_input(codec, node, 0); /* index = 0? */ |
572 | /* set PIN-In enable */ | 569 | /* set PIN-In enable */ |
573 | snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); | 570 | snd_hda_codec_write_cache(codec, node->nid, 0, |
571 | AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); | ||
574 | 572 | ||
575 | return 1; /* found */ | 573 | return 1; /* found */ |
576 | } | 574 | } |
@@ -659,7 +657,6 @@ static int parse_input_path(struct hda_codec *codec, struct hda_gnode *adc_node) | |||
659 | static int parse_input(struct hda_codec *codec) | 657 | static int parse_input(struct hda_codec *codec) |
660 | { | 658 | { |
661 | struct hda_gspec *spec = codec->spec; | 659 | struct hda_gspec *spec = codec->spec; |
662 | struct list_head *p; | ||
663 | struct hda_gnode *node; | 660 | struct hda_gnode *node; |
664 | int err; | 661 | int err; |
665 | 662 | ||
@@ -668,8 +665,7 @@ static int parse_input(struct hda_codec *codec) | |||
668 | * If it reaches to certain input PINs, we take it as the | 665 | * If it reaches to certain input PINs, we take it as the |
669 | * input path. | 666 | * input path. |
670 | */ | 667 | */ |
671 | list_for_each(p, &spec->nid_list) { | 668 | list_for_each_entry(node, &spec->nid_list, list) { |
672 | node = list_entry(p, struct hda_gnode, list); | ||
673 | if (node->wid_caps & AC_WCAP_DIGITAL) | 669 | if (node->wid_caps & AC_WCAP_DIGITAL) |
674 | continue; /* skip SPDIF */ | 670 | continue; /* skip SPDIF */ |
675 | if (node->type == AC_WID_AUD_IN) { | 671 | if (node->type == AC_WID_AUD_IN) { |
@@ -684,11 +680,33 @@ static int parse_input(struct hda_codec *codec) | |||
684 | return 0; | 680 | return 0; |
685 | } | 681 | } |
686 | 682 | ||
683 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
684 | static void add_input_loopback(struct hda_codec *codec, hda_nid_t nid, | ||
685 | int dir, int idx) | ||
686 | { | ||
687 | struct hda_gspec *spec = codec->spec; | ||
688 | struct hda_amp_list *p; | ||
689 | |||
690 | if (spec->num_loopbacks >= MAX_LOOPBACK_AMPS) { | ||
691 | snd_printk(KERN_ERR "hda_generic: Too many loopback ctls\n"); | ||
692 | return; | ||
693 | } | ||
694 | p = &spec->loopback_list[spec->num_loopbacks++]; | ||
695 | p->nid = nid; | ||
696 | p->dir = dir; | ||
697 | p->idx = idx; | ||
698 | spec->loopback.amplist = spec->loopback_list; | ||
699 | } | ||
700 | #else | ||
701 | #define add_input_loopback(codec,nid,dir,idx) | ||
702 | #endif | ||
703 | |||
687 | /* | 704 | /* |
688 | * create mixer controls if possible | 705 | * create mixer controls if possible |
689 | */ | 706 | */ |
690 | static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, | 707 | static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, |
691 | unsigned int index, const char *type, const char *dir_sfx) | 708 | unsigned int index, const char *type, |
709 | const char *dir_sfx, int is_loopback) | ||
692 | { | 710 | { |
693 | char name[32]; | 711 | char name[32]; |
694 | int err; | 712 | int err; |
@@ -702,6 +720,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, | |||
702 | if ((node->wid_caps & AC_WCAP_IN_AMP) && | 720 | if ((node->wid_caps & AC_WCAP_IN_AMP) && |
703 | (node->amp_in_caps & AC_AMPCAP_MUTE)) { | 721 | (node->amp_in_caps & AC_AMPCAP_MUTE)) { |
704 | knew = (struct snd_kcontrol_new)HDA_CODEC_MUTE(name, node->nid, index, HDA_INPUT); | 722 | knew = (struct snd_kcontrol_new)HDA_CODEC_MUTE(name, node->nid, index, HDA_INPUT); |
723 | if (is_loopback) | ||
724 | add_input_loopback(codec, node->nid, HDA_INPUT, index); | ||
705 | snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index); | 725 | snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index); |
706 | if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) | 726 | if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) |
707 | return err; | 727 | return err; |
@@ -709,6 +729,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, | |||
709 | } else if ((node->wid_caps & AC_WCAP_OUT_AMP) && | 729 | } else if ((node->wid_caps & AC_WCAP_OUT_AMP) && |
710 | (node->amp_out_caps & AC_AMPCAP_MUTE)) { | 730 | (node->amp_out_caps & AC_AMPCAP_MUTE)) { |
711 | knew = (struct snd_kcontrol_new)HDA_CODEC_MUTE(name, node->nid, 0, HDA_OUTPUT); | 731 | knew = (struct snd_kcontrol_new)HDA_CODEC_MUTE(name, node->nid, 0, HDA_OUTPUT); |
732 | if (is_loopback) | ||
733 | add_input_loopback(codec, node->nid, HDA_OUTPUT, 0); | ||
712 | snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid); | 734 | snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid); |
713 | if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) | 735 | if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) |
714 | return err; | 736 | return err; |
@@ -767,7 +789,7 @@ static int create_output_mixers(struct hda_codec *codec, const char **names) | |||
767 | for (i = 0; i < spec->pcm_vol_nodes; i++) { | 789 | for (i = 0; i < spec->pcm_vol_nodes; i++) { |
768 | err = create_mixer(codec, spec->pcm_vol[i].node, | 790 | err = create_mixer(codec, spec->pcm_vol[i].node, |
769 | spec->pcm_vol[i].index, | 791 | spec->pcm_vol[i].index, |
770 | names[i], "Playback"); | 792 | names[i], "Playback", 0); |
771 | if (err < 0) | 793 | if (err < 0) |
772 | return err; | 794 | return err; |
773 | } | 795 | } |
@@ -784,7 +806,7 @@ static int build_output_controls(struct hda_codec *codec) | |||
784 | case 1: | 806 | case 1: |
785 | return create_mixer(codec, spec->pcm_vol[0].node, | 807 | return create_mixer(codec, spec->pcm_vol[0].node, |
786 | spec->pcm_vol[0].index, | 808 | spec->pcm_vol[0].index, |
787 | "Master", "Playback"); | 809 | "Master", "Playback", 0); |
788 | case 2: | 810 | case 2: |
789 | if (defcfg_type(spec->out_pin_node[0]) == AC_JACK_SPEAKER) | 811 | if (defcfg_type(spec->out_pin_node[0]) == AC_JACK_SPEAKER) |
790 | return create_output_mixers(codec, types_speaker); | 812 | return create_output_mixers(codec, types_speaker); |
@@ -820,7 +842,7 @@ static int build_input_controls(struct hda_codec *codec) | |||
820 | if (spec->input_mux.num_items == 1) { | 842 | if (spec->input_mux.num_items == 1) { |
821 | err = create_mixer(codec, adc_node, | 843 | err = create_mixer(codec, adc_node, |
822 | spec->input_mux.items[0].index, | 844 | spec->input_mux.items[0].index, |
823 | NULL, "Capture"); | 845 | NULL, "Capture", 0); |
824 | if (err < 0) | 846 | if (err < 0) |
825 | return err; | 847 | return err; |
826 | return 0; | 848 | return 0; |
@@ -886,7 +908,8 @@ static int parse_loopback_path(struct hda_codec *codec, struct hda_gspec *spec, | |||
886 | return err; | 908 | return err; |
887 | else if (err >= 1) { | 909 | else if (err >= 1) { |
888 | if (err == 1) { | 910 | if (err == 1) { |
889 | err = create_mixer(codec, node, i, type, "Playback"); | 911 | err = create_mixer(codec, node, i, type, |
912 | "Playback", 1); | ||
890 | if (err < 0) | 913 | if (err < 0) |
891 | return err; | 914 | return err; |
892 | if (err > 0) | 915 | if (err > 0) |
@@ -911,7 +934,6 @@ static int parse_loopback_path(struct hda_codec *codec, struct hda_gspec *spec, | |||
911 | static int build_loopback_controls(struct hda_codec *codec) | 934 | static int build_loopback_controls(struct hda_codec *codec) |
912 | { | 935 | { |
913 | struct hda_gspec *spec = codec->spec; | 936 | struct hda_gspec *spec = codec->spec; |
914 | struct list_head *p; | ||
915 | struct hda_gnode *node; | 937 | struct hda_gnode *node; |
916 | int err; | 938 | int err; |
917 | const char *type; | 939 | const char *type; |
@@ -919,8 +941,7 @@ static int build_loopback_controls(struct hda_codec *codec) | |||
919 | if (! spec->out_pin_node[0]) | 941 | if (! spec->out_pin_node[0]) |
920 | return 0; | 942 | return 0; |
921 | 943 | ||
922 | list_for_each(p, &spec->nid_list) { | 944 | list_for_each_entry(node, &spec->nid_list, list) { |
923 | node = list_entry(p, struct hda_gnode, list); | ||
924 | if (node->type != AC_WID_PIN) | 945 | if (node->type != AC_WID_PIN) |
925 | continue; | 946 | continue; |
926 | /* input capable? */ | 947 | /* input capable? */ |
@@ -1022,6 +1043,14 @@ static int build_generic_pcms(struct hda_codec *codec) | |||
1022 | return 0; | 1043 | return 0; |
1023 | } | 1044 | } |
1024 | 1045 | ||
1046 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1047 | static int generic_check_power_status(struct hda_codec *codec, hda_nid_t nid) | ||
1048 | { | ||
1049 | struct hda_gspec *spec = codec->spec; | ||
1050 | return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); | ||
1051 | } | ||
1052 | #endif | ||
1053 | |||
1025 | 1054 | ||
1026 | /* | 1055 | /* |
1027 | */ | 1056 | */ |
@@ -1029,6 +1058,9 @@ static struct hda_codec_ops generic_patch_ops = { | |||
1029 | .build_controls = build_generic_controls, | 1058 | .build_controls = build_generic_controls, |
1030 | .build_pcms = build_generic_pcms, | 1059 | .build_pcms = build_generic_pcms, |
1031 | .free = snd_hda_generic_free, | 1060 | .free = snd_hda_generic_free, |
1061 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1062 | .check_power_status = generic_check_power_status, | ||
1063 | #endif | ||
1032 | }; | 1064 | }; |
1033 | 1065 | ||
1034 | /* | 1066 | /* |
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c new file mode 100644 index 000000000000..bafb7b01f5a1 --- /dev/null +++ b/sound/pci/hda/hda_hwdep.c | |||
@@ -0,0 +1,122 @@ | |||
1 | /* | ||
2 | * HWDEP Interface for HD-audio codec | ||
3 | * | ||
4 | * Copyright (c) 2007 Takashi Iwai <tiwai@suse.de> | ||
5 | * | ||
6 | * This driver is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This driver is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include <sound/driver.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/pci.h> | ||
25 | #include <linux/compat.h> | ||
26 | #include <linux/mutex.h> | ||
27 | #include <sound/core.h> | ||
28 | #include "hda_codec.h" | ||
29 | #include "hda_local.h" | ||
30 | #include <sound/hda_hwdep.h> | ||
31 | |||
32 | /* | ||
33 | * write/read an out-of-bound verb | ||
34 | */ | ||
35 | static int verb_write_ioctl(struct hda_codec *codec, | ||
36 | struct hda_verb_ioctl __user *arg) | ||
37 | { | ||
38 | u32 verb, res; | ||
39 | |||
40 | if (get_user(verb, &arg->verb)) | ||
41 | return -EFAULT; | ||
42 | res = snd_hda_codec_read(codec, verb >> 24, 0, | ||
43 | (verb >> 8) & 0xffff, verb & 0xff); | ||
44 | if (put_user(res, &arg->res)) | ||
45 | return -EFAULT; | ||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | static int get_wcap_ioctl(struct hda_codec *codec, | ||
50 | struct hda_verb_ioctl __user *arg) | ||
51 | { | ||
52 | u32 verb, res; | ||
53 | |||
54 | if (get_user(verb, &arg->verb)) | ||
55 | return -EFAULT; | ||
56 | res = get_wcaps(codec, verb >> 24); | ||
57 | if (put_user(res, &arg->res)) | ||
58 | return -EFAULT; | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | |||
63 | /* | ||
64 | */ | ||
65 | static int hda_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, | ||
66 | unsigned int cmd, unsigned long arg) | ||
67 | { | ||
68 | struct hda_codec *codec = hw->private_data; | ||
69 | void __user *argp = (void __user *)arg; | ||
70 | |||
71 | switch (cmd) { | ||
72 | case HDA_IOCTL_PVERSION: | ||
73 | return put_user(HDA_HWDEP_VERSION, (int __user *)argp); | ||
74 | case HDA_IOCTL_VERB_WRITE: | ||
75 | return verb_write_ioctl(codec, argp); | ||
76 | case HDA_IOCTL_GET_WCAP: | ||
77 | return get_wcap_ioctl(codec, argp); | ||
78 | } | ||
79 | return -ENOIOCTLCMD; | ||
80 | } | ||
81 | |||
82 | #ifdef CONFIG_COMPAT | ||
83 | static int hda_hwdep_ioctl_compat(struct snd_hwdep *hw, struct file *file, | ||
84 | unsigned int cmd, unsigned long arg) | ||
85 | { | ||
86 | return hda_hwdep_ioctl(hw, file, cmd, (unsigned long)compat_ptr(arg)); | ||
87 | } | ||
88 | #endif | ||
89 | |||
90 | static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file) | ||
91 | { | ||
92 | #ifndef CONFIG_SND_DEBUG_DETECT | ||
93 | if (!capable(CAP_SYS_RAWIO)) | ||
94 | return -EACCES; | ||
95 | #endif | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | int __devinit snd_hda_create_hwdep(struct hda_codec *codec) | ||
100 | { | ||
101 | char hwname[16]; | ||
102 | struct snd_hwdep *hwdep; | ||
103 | int err; | ||
104 | |||
105 | sprintf(hwname, "HDA Codec %d", codec->addr); | ||
106 | err = snd_hwdep_new(codec->bus->card, hwname, codec->addr, &hwdep); | ||
107 | if (err < 0) | ||
108 | return err; | ||
109 | codec->hwdep = hwdep; | ||
110 | sprintf(hwdep->name, "HDA Codec %d", codec->addr); | ||
111 | hwdep->iface = SNDRV_HWDEP_IFACE_HDA; | ||
112 | hwdep->private_data = codec; | ||
113 | hwdep->exclusive = 1; | ||
114 | |||
115 | hwdep->ops.open = hda_hwdep_open; | ||
116 | hwdep->ops.ioctl = hda_hwdep_ioctl; | ||
117 | #ifdef CONFIG_COMPAT | ||
118 | hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat; | ||
119 | #endif | ||
120 | |||
121 | return 0; | ||
122 | } | ||
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 92bc8b3fa2a0..3fa0f9704909 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -1,6 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * | 2 | * |
3 | * hda_intel.c - Implementation of primary alsa driver code base for Intel HD Audio. | 3 | * hda_intel.c - Implementation of primary alsa driver code base |
4 | * for Intel HD Audio. | ||
4 | * | 5 | * |
5 | * Copyright(c) 2004 Intel Corporation. All rights reserved. | 6 | * Copyright(c) 2004 Intel Corporation. All rights reserved. |
6 | * | 7 | * |
@@ -64,14 +65,27 @@ MODULE_PARM_DESC(id, "ID string for Intel HD audio interface."); | |||
64 | module_param(model, charp, 0444); | 65 | module_param(model, charp, 0444); |
65 | MODULE_PARM_DESC(model, "Use the given board model."); | 66 | MODULE_PARM_DESC(model, "Use the given board model."); |
66 | module_param(position_fix, int, 0444); | 67 | module_param(position_fix, int, 0444); |
67 | MODULE_PARM_DESC(position_fix, "Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)."); | 68 | MODULE_PARM_DESC(position_fix, "Fix DMA pointer " |
69 | "(0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)."); | ||
68 | module_param(probe_mask, int, 0444); | 70 | module_param(probe_mask, int, 0444); |
69 | MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); | 71 | MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); |
70 | module_param(single_cmd, bool, 0444); | 72 | module_param(single_cmd, bool, 0444); |
71 | MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs (for debugging only)."); | 73 | MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs " |
74 | "(for debugging only)."); | ||
72 | module_param(enable_msi, int, 0); | 75 | module_param(enable_msi, int, 0); |
73 | MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)"); | 76 | MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)"); |
74 | 77 | ||
78 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
79 | /* power_save option is defined in hda_codec.c */ | ||
80 | |||
81 | /* reset the HD-audio controller in power save mode. | ||
82 | * this may give more power-saving, but will take longer time to | ||
83 | * wake up. | ||
84 | */ | ||
85 | static int power_save_controller = 1; | ||
86 | module_param(power_save_controller, bool, 0644); | ||
87 | MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode."); | ||
88 | #endif | ||
75 | 89 | ||
76 | /* just for backward compatibility */ | 90 | /* just for backward compatibility */ |
77 | static int enable; | 91 | static int enable; |
@@ -98,6 +112,7 @@ MODULE_DESCRIPTION("Intel HDA driver"); | |||
98 | 112 | ||
99 | #define SFX "hda-intel: " | 113 | #define SFX "hda-intel: " |
100 | 114 | ||
115 | |||
101 | /* | 116 | /* |
102 | * registers | 117 | * registers |
103 | */ | 118 | */ |
@@ -213,15 +228,16 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; | |||
213 | #define SD_INT_DESC_ERR 0x10 /* descriptor error interrupt */ | 228 | #define SD_INT_DESC_ERR 0x10 /* descriptor error interrupt */ |
214 | #define SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */ | 229 | #define SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */ |
215 | #define SD_INT_COMPLETE 0x04 /* completion interrupt */ | 230 | #define SD_INT_COMPLETE 0x04 /* completion interrupt */ |
216 | #define SD_INT_MASK (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|SD_INT_COMPLETE) | 231 | #define SD_INT_MASK (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\ |
232 | SD_INT_COMPLETE) | ||
217 | 233 | ||
218 | /* SD_STS */ | 234 | /* SD_STS */ |
219 | #define SD_STS_FIFO_READY 0x20 /* FIFO ready */ | 235 | #define SD_STS_FIFO_READY 0x20 /* FIFO ready */ |
220 | 236 | ||
221 | /* INTCTL and INTSTS */ | 237 | /* INTCTL and INTSTS */ |
222 | #define ICH6_INT_ALL_STREAM 0xff /* all stream interrupts */ | 238 | #define ICH6_INT_ALL_STREAM 0xff /* all stream interrupts */ |
223 | #define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ | 239 | #define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ |
224 | #define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ | 240 | #define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ |
225 | 241 | ||
226 | /* GCTL unsolicited response enable bit */ | 242 | /* GCTL unsolicited response enable bit */ |
227 | #define ICH6_GCTL_UREN (1<<8) | 243 | #define ICH6_GCTL_UREN (1<<8) |
@@ -257,22 +273,26 @@ enum { | |||
257 | */ | 273 | */ |
258 | 274 | ||
259 | struct azx_dev { | 275 | struct azx_dev { |
260 | u32 *bdl; /* virtual address of the BDL */ | 276 | u32 *bdl; /* virtual address of the BDL */ |
261 | dma_addr_t bdl_addr; /* physical address of the BDL */ | 277 | dma_addr_t bdl_addr; /* physical address of the BDL */ |
262 | u32 *posbuf; /* position buffer pointer */ | 278 | u32 *posbuf; /* position buffer pointer */ |
263 | 279 | ||
264 | unsigned int bufsize; /* size of the play buffer in bytes */ | 280 | unsigned int bufsize; /* size of the play buffer in bytes */ |
265 | unsigned int fragsize; /* size of each period in bytes */ | 281 | unsigned int fragsize; /* size of each period in bytes */ |
266 | unsigned int frags; /* number for period in the play buffer */ | 282 | unsigned int frags; /* number for period in the play buffer */ |
267 | unsigned int fifo_size; /* FIFO size */ | 283 | unsigned int fifo_size; /* FIFO size */ |
268 | 284 | ||
269 | void __iomem *sd_addr; /* stream descriptor pointer */ | 285 | void __iomem *sd_addr; /* stream descriptor pointer */ |
270 | 286 | ||
271 | u32 sd_int_sta_mask; /* stream int status mask */ | 287 | u32 sd_int_sta_mask; /* stream int status mask */ |
272 | 288 | ||
273 | /* pcm support */ | 289 | /* pcm support */ |
274 | struct snd_pcm_substream *substream; /* assigned substream, set in PCM open */ | 290 | struct snd_pcm_substream *substream; /* assigned substream, |
275 | unsigned int format_val; /* format value to be set in the controller and the codec */ | 291 | * set in PCM open |
292 | */ | ||
293 | unsigned int format_val; /* format value to be set in the | ||
294 | * controller and the codec | ||
295 | */ | ||
276 | unsigned char stream_tag; /* assigned stream */ | 296 | unsigned char stream_tag; /* assigned stream */ |
277 | unsigned char index; /* stream index */ | 297 | unsigned char index; /* stream index */ |
278 | /* for sanity check of position buffer */ | 298 | /* for sanity check of position buffer */ |
@@ -337,6 +357,7 @@ struct azx { | |||
337 | 357 | ||
338 | /* flags */ | 358 | /* flags */ |
339 | int position_fix; | 359 | int position_fix; |
360 | unsigned int running :1; | ||
340 | unsigned int initialized :1; | 361 | unsigned int initialized :1; |
341 | unsigned int single_cmd :1; | 362 | unsigned int single_cmd :1; |
342 | unsigned int polling_mode :1; | 363 | unsigned int polling_mode :1; |
@@ -418,7 +439,8 @@ static int azx_alloc_cmd_io(struct azx *chip) | |||
418 | int err; | 439 | int err; |
419 | 440 | ||
420 | /* single page (at least 4096 bytes) must suffice for both ringbuffes */ | 441 | /* single page (at least 4096 bytes) must suffice for both ringbuffes */ |
421 | err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), | 442 | err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, |
443 | snd_dma_pci_data(chip->pci), | ||
422 | PAGE_SIZE, &chip->rb); | 444 | PAGE_SIZE, &chip->rb); |
423 | if (err < 0) { | 445 | if (err < 0) { |
424 | snd_printk(KERN_ERR SFX "cannot allocate CORB/RIRB\n"); | 446 | snd_printk(KERN_ERR SFX "cannot allocate CORB/RIRB\n"); |
@@ -531,9 +553,9 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec) | |||
531 | azx_update_rirb(chip); | 553 | azx_update_rirb(chip); |
532 | spin_unlock_irq(&chip->reg_lock); | 554 | spin_unlock_irq(&chip->reg_lock); |
533 | } | 555 | } |
534 | if (! chip->rirb.cmds) | 556 | if (!chip->rirb.cmds) |
535 | return chip->rirb.res; /* the last value */ | 557 | return chip->rirb.res; /* the last value */ |
536 | schedule_timeout(1); | 558 | schedule_timeout_uninterruptible(1); |
537 | } while (time_after_eq(timeout, jiffies)); | 559 | } while (time_after_eq(timeout, jiffies)); |
538 | 560 | ||
539 | if (chip->msi) { | 561 | if (chip->msi) { |
@@ -585,16 +607,19 @@ static int azx_single_send_cmd(struct hda_codec *codec, u32 val) | |||
585 | 607 | ||
586 | while (timeout--) { | 608 | while (timeout--) { |
587 | /* check ICB busy bit */ | 609 | /* check ICB busy bit */ |
588 | if (! (azx_readw(chip, IRS) & ICH6_IRS_BUSY)) { | 610 | if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) { |
589 | /* Clear IRV valid bit */ | 611 | /* Clear IRV valid bit */ |
590 | azx_writew(chip, IRS, azx_readw(chip, IRS) | ICH6_IRS_VALID); | 612 | azx_writew(chip, IRS, azx_readw(chip, IRS) | |
613 | ICH6_IRS_VALID); | ||
591 | azx_writel(chip, IC, val); | 614 | azx_writel(chip, IC, val); |
592 | azx_writew(chip, IRS, azx_readw(chip, IRS) | ICH6_IRS_BUSY); | 615 | azx_writew(chip, IRS, azx_readw(chip, IRS) | |
616 | ICH6_IRS_BUSY); | ||
593 | return 0; | 617 | return 0; |
594 | } | 618 | } |
595 | udelay(1); | 619 | udelay(1); |
596 | } | 620 | } |
597 | snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n", azx_readw(chip, IRS), val); | 621 | snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n", |
622 | azx_readw(chip, IRS), val); | ||
598 | return -EIO; | 623 | return -EIO; |
599 | } | 624 | } |
600 | 625 | ||
@@ -610,7 +635,8 @@ static unsigned int azx_single_get_response(struct hda_codec *codec) | |||
610 | return azx_readl(chip, IR); | 635 | return azx_readl(chip, IR); |
611 | udelay(1); | 636 | udelay(1); |
612 | } | 637 | } |
613 | snd_printd(SFX "get_response timeout: IRS=0x%x\n", azx_readw(chip, IRS)); | 638 | snd_printd(SFX "get_response timeout: IRS=0x%x\n", |
639 | azx_readw(chip, IRS)); | ||
614 | return (unsigned int)-1; | 640 | return (unsigned int)-1; |
615 | } | 641 | } |
616 | 642 | ||
@@ -652,12 +678,18 @@ static unsigned int azx_get_response(struct hda_codec *codec) | |||
652 | return azx_rirb_get_response(codec); | 678 | return azx_rirb_get_response(codec); |
653 | } | 679 | } |
654 | 680 | ||
681 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
682 | static void azx_power_notify(struct hda_codec *codec); | ||
683 | #endif | ||
655 | 684 | ||
656 | /* reset codec link */ | 685 | /* reset codec link */ |
657 | static int azx_reset(struct azx *chip) | 686 | static int azx_reset(struct azx *chip) |
658 | { | 687 | { |
659 | int count; | 688 | int count; |
660 | 689 | ||
690 | /* clear STATESTS */ | ||
691 | azx_writeb(chip, STATESTS, STATESTS_INT_MASK); | ||
692 | |||
661 | /* reset controller */ | 693 | /* reset controller */ |
662 | azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_RESET); | 694 | azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_RESET); |
663 | 695 | ||
@@ -777,18 +809,12 @@ static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev) | |||
777 | 809 | ||
778 | 810 | ||
779 | /* | 811 | /* |
780 | * initialize the chip | 812 | * reset and start the controller registers |
781 | */ | 813 | */ |
782 | static void azx_init_chip(struct azx *chip) | 814 | static void azx_init_chip(struct azx *chip) |
783 | { | 815 | { |
784 | unsigned char reg; | 816 | if (chip->initialized) |
785 | 817 | return; | |
786 | /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44) | ||
787 | * TCSEL == Traffic Class Select Register, which sets PCI express QOS | ||
788 | * Ensuring these bits are 0 clears playback static on some HD Audio codecs | ||
789 | */ | ||
790 | pci_read_config_byte (chip->pci, ICH6_PCIREG_TCSEL, ®); | ||
791 | pci_write_config_byte(chip->pci, ICH6_PCIREG_TCSEL, reg & 0xf8); | ||
792 | 818 | ||
793 | /* reset controller */ | 819 | /* reset controller */ |
794 | azx_reset(chip); | 820 | azx_reset(chip); |
@@ -805,19 +831,45 @@ static void azx_init_chip(struct azx *chip) | |||
805 | azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); | 831 | azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); |
806 | azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr)); | 832 | azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr)); |
807 | 833 | ||
834 | chip->initialized = 1; | ||
835 | } | ||
836 | |||
837 | /* | ||
838 | * initialize the PCI registers | ||
839 | */ | ||
840 | /* update bits in a PCI register byte */ | ||
841 | static void update_pci_byte(struct pci_dev *pci, unsigned int reg, | ||
842 | unsigned char mask, unsigned char val) | ||
843 | { | ||
844 | unsigned char data; | ||
845 | |||
846 | pci_read_config_byte(pci, reg, &data); | ||
847 | data &= ~mask; | ||
848 | data |= (val & mask); | ||
849 | pci_write_config_byte(pci, reg, data); | ||
850 | } | ||
851 | |||
852 | static void azx_init_pci(struct azx *chip) | ||
853 | { | ||
854 | /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44) | ||
855 | * TCSEL == Traffic Class Select Register, which sets PCI express QOS | ||
856 | * Ensuring these bits are 0 clears playback static on some HD Audio | ||
857 | * codecs | ||
858 | */ | ||
859 | update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0); | ||
860 | |||
808 | switch (chip->driver_type) { | 861 | switch (chip->driver_type) { |
809 | case AZX_DRIVER_ATI: | 862 | case AZX_DRIVER_ATI: |
810 | /* For ATI SB450 azalia HD audio, we need to enable snoop */ | 863 | /* For ATI SB450 azalia HD audio, we need to enable snoop */ |
811 | pci_read_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, | 864 | update_pci_byte(chip->pci, |
812 | ®); | 865 | ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, |
813 | pci_write_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, | 866 | 0x07, ATI_SB450_HDAUDIO_ENABLE_SNOOP); |
814 | (reg & 0xf8) | ATI_SB450_HDAUDIO_ENABLE_SNOOP); | ||
815 | break; | 867 | break; |
816 | case AZX_DRIVER_NVIDIA: | 868 | case AZX_DRIVER_NVIDIA: |
817 | /* For NVIDIA HDA, enable snoop */ | 869 | /* For NVIDIA HDA, enable snoop */ |
818 | pci_read_config_byte(chip->pci,NVIDIA_HDA_TRANSREG_ADDR, ®); | 870 | update_pci_byte(chip->pci, |
819 | pci_write_config_byte(chip->pci,NVIDIA_HDA_TRANSREG_ADDR, | 871 | NVIDIA_HDA_TRANSREG_ADDR, |
820 | (reg & 0xf0) | NVIDIA_HDA_ENABLE_COHBITS); | 872 | 0x0f, NVIDIA_HDA_ENABLE_COHBITS); |
821 | break; | 873 | break; |
822 | } | 874 | } |
823 | } | 875 | } |
@@ -857,7 +909,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id) | |||
857 | /* clear rirb int */ | 909 | /* clear rirb int */ |
858 | status = azx_readb(chip, RIRBSTS); | 910 | status = azx_readb(chip, RIRBSTS); |
859 | if (status & RIRB_INT_MASK) { | 911 | if (status & RIRB_INT_MASK) { |
860 | if (! chip->single_cmd && (status & RIRB_INT_RESPONSE)) | 912 | if (!chip->single_cmd && (status & RIRB_INT_RESPONSE)) |
861 | azx_update_rirb(chip); | 913 | azx_update_rirb(chip); |
862 | azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); | 914 | azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); |
863 | } | 915 | } |
@@ -911,9 +963,11 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) | |||
911 | int timeout; | 963 | int timeout; |
912 | 964 | ||
913 | /* make sure the run bit is zero for SD */ | 965 | /* make sure the run bit is zero for SD */ |
914 | azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) & ~SD_CTL_DMA_START); | 966 | azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) & |
967 | ~SD_CTL_DMA_START); | ||
915 | /* reset stream */ | 968 | /* reset stream */ |
916 | azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) | SD_CTL_STREAM_RESET); | 969 | azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) | |
970 | SD_CTL_STREAM_RESET); | ||
917 | udelay(3); | 971 | udelay(3); |
918 | timeout = 300; | 972 | timeout = 300; |
919 | while (!((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) && | 973 | while (!((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) && |
@@ -931,7 +985,7 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) | |||
931 | 985 | ||
932 | /* program the stream_tag */ | 986 | /* program the stream_tag */ |
933 | azx_sd_writel(azx_dev, SD_CTL, | 987 | azx_sd_writel(azx_dev, SD_CTL, |
934 | (azx_sd_readl(azx_dev, SD_CTL) & ~SD_CTL_STREAM_TAG_MASK) | | 988 | (azx_sd_readl(azx_dev, SD_CTL) & ~SD_CTL_STREAM_TAG_MASK)| |
935 | (azx_dev->stream_tag << SD_CTL_STREAM_TAG_SHIFT)); | 989 | (azx_dev->stream_tag << SD_CTL_STREAM_TAG_SHIFT)); |
936 | 990 | ||
937 | /* program the length of samples in cyclic buffer */ | 991 | /* program the length of samples in cyclic buffer */ |
@@ -951,11 +1005,13 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) | |||
951 | azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl_addr)); | 1005 | azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl_addr)); |
952 | 1006 | ||
953 | /* enable the position buffer */ | 1007 | /* enable the position buffer */ |
954 | if (! (azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) | 1008 | if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) |
955 | azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE); | 1009 | azx_writel(chip, DPLBASE, |
1010 | (u32)chip->posbuf.addr |ICH6_DPLBASE_ENABLE); | ||
956 | 1011 | ||
957 | /* set the interrupt enable bits in the descriptor control register */ | 1012 | /* set the interrupt enable bits in the descriptor control register */ |
958 | azx_sd_writel(azx_dev, SD_CTL, azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK); | 1013 | azx_sd_writel(azx_dev, SD_CTL, |
1014 | azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK); | ||
959 | 1015 | ||
960 | return 0; | 1016 | return 0; |
961 | } | 1017 | } |
@@ -986,8 +1042,12 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model) | |||
986 | bus_temp.pci = chip->pci; | 1042 | bus_temp.pci = chip->pci; |
987 | bus_temp.ops.command = azx_send_cmd; | 1043 | bus_temp.ops.command = azx_send_cmd; |
988 | bus_temp.ops.get_response = azx_get_response; | 1044 | bus_temp.ops.get_response = azx_get_response; |
1045 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1046 | bus_temp.ops.pm_notify = azx_power_notify; | ||
1047 | #endif | ||
989 | 1048 | ||
990 | if ((err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus)) < 0) | 1049 | err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus); |
1050 | if (err < 0) | ||
991 | return err; | 1051 | return err; |
992 | 1052 | ||
993 | codecs = audio_codecs = 0; | 1053 | codecs = audio_codecs = 0; |
@@ -1038,7 +1098,7 @@ static inline struct azx_dev *azx_assign_device(struct azx *chip, int stream) | |||
1038 | nums = chip->capture_streams; | 1098 | nums = chip->capture_streams; |
1039 | } | 1099 | } |
1040 | for (i = 0; i < nums; i++, dev++) | 1100 | for (i = 0; i < nums; i++, dev++) |
1041 | if (! chip->azx_dev[dev].opened) { | 1101 | if (!chip->azx_dev[dev].opened) { |
1042 | chip->azx_dev[dev].opened = 1; | 1102 | chip->azx_dev[dev].opened = 1; |
1043 | return &chip->azx_dev[dev]; | 1103 | return &chip->azx_dev[dev]; |
1044 | } | 1104 | } |
@@ -1052,7 +1112,8 @@ static inline void azx_release_device(struct azx_dev *azx_dev) | |||
1052 | } | 1112 | } |
1053 | 1113 | ||
1054 | static struct snd_pcm_hardware azx_pcm_hw = { | 1114 | static struct snd_pcm_hardware azx_pcm_hw = { |
1055 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 1115 | .info = (SNDRV_PCM_INFO_MMAP | |
1116 | SNDRV_PCM_INFO_INTERLEAVED | | ||
1056 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 1117 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
1057 | SNDRV_PCM_INFO_MMAP_VALID | | 1118 | SNDRV_PCM_INFO_MMAP_VALID | |
1058 | /* No full-resume yet implemented */ | 1119 | /* No full-resume yet implemented */ |
@@ -1105,8 +1166,11 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) | |||
1105 | 128); | 1166 | 128); |
1106 | snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, | 1167 | snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, |
1107 | 128); | 1168 | 128); |
1108 | if ((err = hinfo->ops.open(hinfo, apcm->codec, substream)) < 0) { | 1169 | snd_hda_power_up(apcm->codec); |
1170 | err = hinfo->ops.open(hinfo, apcm->codec, substream); | ||
1171 | if (err < 0) { | ||
1109 | azx_release_device(azx_dev); | 1172 | azx_release_device(azx_dev); |
1173 | snd_hda_power_down(apcm->codec); | ||
1110 | mutex_unlock(&chip->open_mutex); | 1174 | mutex_unlock(&chip->open_mutex); |
1111 | return err; | 1175 | return err; |
1112 | } | 1176 | } |
@@ -1135,13 +1199,16 @@ static int azx_pcm_close(struct snd_pcm_substream *substream) | |||
1135 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 1199 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
1136 | azx_release_device(azx_dev); | 1200 | azx_release_device(azx_dev); |
1137 | hinfo->ops.close(hinfo, apcm->codec, substream); | 1201 | hinfo->ops.close(hinfo, apcm->codec, substream); |
1202 | snd_hda_power_down(apcm->codec); | ||
1138 | mutex_unlock(&chip->open_mutex); | 1203 | mutex_unlock(&chip->open_mutex); |
1139 | return 0; | 1204 | return 0; |
1140 | } | 1205 | } |
1141 | 1206 | ||
1142 | static int azx_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) | 1207 | static int azx_pcm_hw_params(struct snd_pcm_substream *substream, |
1208 | struct snd_pcm_hw_params *hw_params) | ||
1143 | { | 1209 | { |
1144 | return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); | 1210 | return snd_pcm_lib_malloc_pages(substream, |
1211 | params_buffer_bytes(hw_params)); | ||
1145 | } | 1212 | } |
1146 | 1213 | ||
1147 | static int azx_pcm_hw_free(struct snd_pcm_substream *substream) | 1214 | static int azx_pcm_hw_free(struct snd_pcm_substream *substream) |
@@ -1175,13 +1242,15 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) | |||
1175 | runtime->channels, | 1242 | runtime->channels, |
1176 | runtime->format, | 1243 | runtime->format, |
1177 | hinfo->maxbps); | 1244 | hinfo->maxbps); |
1178 | if (! azx_dev->format_val) { | 1245 | if (!azx_dev->format_val) { |
1179 | snd_printk(KERN_ERR SFX "invalid format_val, rate=%d, ch=%d, format=%d\n", | 1246 | snd_printk(KERN_ERR SFX |
1247 | "invalid format_val, rate=%d, ch=%d, format=%d\n", | ||
1180 | runtime->rate, runtime->channels, runtime->format); | 1248 | runtime->rate, runtime->channels, runtime->format); |
1181 | return -EINVAL; | 1249 | return -EINVAL; |
1182 | } | 1250 | } |
1183 | 1251 | ||
1184 | snd_printdd("azx_pcm_prepare: bufsize=0x%x, fragsize=0x%x, format=0x%x\n", | 1252 | snd_printdd("azx_pcm_prepare: bufsize=0x%x, fragsize=0x%x, " |
1253 | "format=0x%x\n", | ||
1185 | azx_dev->bufsize, azx_dev->fragsize, azx_dev->format_val); | 1254 | azx_dev->bufsize, azx_dev->fragsize, azx_dev->format_val); |
1186 | azx_setup_periods(azx_dev); | 1255 | azx_setup_periods(azx_dev); |
1187 | azx_setup_controller(chip, azx_dev); | 1256 | azx_setup_controller(chip, azx_dev); |
@@ -1223,7 +1292,8 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
1223 | cmd == SNDRV_PCM_TRIGGER_SUSPEND || | 1292 | cmd == SNDRV_PCM_TRIGGER_SUSPEND || |
1224 | cmd == SNDRV_PCM_TRIGGER_STOP) { | 1293 | cmd == SNDRV_PCM_TRIGGER_STOP) { |
1225 | int timeout = 5000; | 1294 | int timeout = 5000; |
1226 | while (azx_sd_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START && --timeout) | 1295 | while ((azx_sd_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START) && |
1296 | --timeout) | ||
1227 | ; | 1297 | ; |
1228 | } | 1298 | } |
1229 | return err; | 1299 | return err; |
@@ -1241,7 +1311,7 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) | |||
1241 | /* use the position buffer */ | 1311 | /* use the position buffer */ |
1242 | pos = le32_to_cpu(*azx_dev->posbuf); | 1312 | pos = le32_to_cpu(*azx_dev->posbuf); |
1243 | if (chip->position_fix == POS_FIX_AUTO && | 1313 | if (chip->position_fix == POS_FIX_AUTO && |
1244 | azx_dev->period_intr == 1 && ! pos) { | 1314 | azx_dev->period_intr == 1 && !pos) { |
1245 | printk(KERN_WARNING | 1315 | printk(KERN_WARNING |
1246 | "hda-intel: Invalid position buffer, " | 1316 | "hda-intel: Invalid position buffer, " |
1247 | "using LPIB read method instead.\n"); | 1317 | "using LPIB read method instead.\n"); |
@@ -1292,7 +1362,8 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec, | |||
1292 | snd_assert(cpcm->name, return -EINVAL); | 1362 | snd_assert(cpcm->name, return -EINVAL); |
1293 | 1363 | ||
1294 | err = snd_pcm_new(chip->card, cpcm->name, pcm_dev, | 1364 | err = snd_pcm_new(chip->card, cpcm->name, pcm_dev, |
1295 | cpcm->stream[0].substreams, cpcm->stream[1].substreams, | 1365 | cpcm->stream[0].substreams, |
1366 | cpcm->stream[1].substreams, | ||
1296 | &pcm); | 1367 | &pcm); |
1297 | if (err < 0) | 1368 | if (err < 0) |
1298 | return err; | 1369 | return err; |
@@ -1322,26 +1393,27 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec, | |||
1322 | 1393 | ||
1323 | static int __devinit azx_pcm_create(struct azx *chip) | 1394 | static int __devinit azx_pcm_create(struct azx *chip) |
1324 | { | 1395 | { |
1325 | struct list_head *p; | ||
1326 | struct hda_codec *codec; | 1396 | struct hda_codec *codec; |
1327 | int c, err; | 1397 | int c, err; |
1328 | int pcm_dev; | 1398 | int pcm_dev; |
1329 | 1399 | ||
1330 | if ((err = snd_hda_build_pcms(chip->bus)) < 0) | 1400 | err = snd_hda_build_pcms(chip->bus); |
1401 | if (err < 0) | ||
1331 | return err; | 1402 | return err; |
1332 | 1403 | ||
1333 | /* create audio PCMs */ | 1404 | /* create audio PCMs */ |
1334 | pcm_dev = 0; | 1405 | pcm_dev = 0; |
1335 | list_for_each(p, &chip->bus->codec_list) { | 1406 | list_for_each_entry(codec, &chip->bus->codec_list, list) { |
1336 | codec = list_entry(p, struct hda_codec, list); | ||
1337 | for (c = 0; c < codec->num_pcms; c++) { | 1407 | for (c = 0; c < codec->num_pcms; c++) { |
1338 | if (codec->pcm_info[c].is_modem) | 1408 | if (codec->pcm_info[c].is_modem) |
1339 | continue; /* create later */ | 1409 | continue; /* create later */ |
1340 | if (pcm_dev >= AZX_MAX_AUDIO_PCMS) { | 1410 | if (pcm_dev >= AZX_MAX_AUDIO_PCMS) { |
1341 | snd_printk(KERN_ERR SFX "Too many audio PCMs\n"); | 1411 | snd_printk(KERN_ERR SFX |
1412 | "Too many audio PCMs\n"); | ||
1342 | return -EINVAL; | 1413 | return -EINVAL; |
1343 | } | 1414 | } |
1344 | err = create_codec_pcm(chip, codec, &codec->pcm_info[c], pcm_dev); | 1415 | err = create_codec_pcm(chip, codec, |
1416 | &codec->pcm_info[c], pcm_dev); | ||
1345 | if (err < 0) | 1417 | if (err < 0) |
1346 | return err; | 1418 | return err; |
1347 | pcm_dev++; | 1419 | pcm_dev++; |
@@ -1350,16 +1422,17 @@ static int __devinit azx_pcm_create(struct azx *chip) | |||
1350 | 1422 | ||
1351 | /* create modem PCMs */ | 1423 | /* create modem PCMs */ |
1352 | pcm_dev = AZX_MAX_AUDIO_PCMS; | 1424 | pcm_dev = AZX_MAX_AUDIO_PCMS; |
1353 | list_for_each(p, &chip->bus->codec_list) { | 1425 | list_for_each_entry(codec, &chip->bus->codec_list, list) { |
1354 | codec = list_entry(p, struct hda_codec, list); | ||
1355 | for (c = 0; c < codec->num_pcms; c++) { | 1426 | for (c = 0; c < codec->num_pcms; c++) { |
1356 | if (! codec->pcm_info[c].is_modem) | 1427 | if (!codec->pcm_info[c].is_modem) |
1357 | continue; /* already created */ | 1428 | continue; /* already created */ |
1358 | if (pcm_dev >= AZX_MAX_PCMS) { | 1429 | if (pcm_dev >= AZX_MAX_PCMS) { |
1359 | snd_printk(KERN_ERR SFX "Too many modem PCMs\n"); | 1430 | snd_printk(KERN_ERR SFX |
1431 | "Too many modem PCMs\n"); | ||
1360 | return -EINVAL; | 1432 | return -EINVAL; |
1361 | } | 1433 | } |
1362 | err = create_codec_pcm(chip, codec, &codec->pcm_info[c], pcm_dev); | 1434 | err = create_codec_pcm(chip, codec, |
1435 | &codec->pcm_info[c], pcm_dev); | ||
1363 | if (err < 0) | 1436 | if (err < 0) |
1364 | return err; | 1437 | return err; |
1365 | chip->pcm[pcm_dev]->dev_class = SNDRV_PCM_CLASS_MODEM; | 1438 | chip->pcm[pcm_dev]->dev_class = SNDRV_PCM_CLASS_MODEM; |
@@ -1386,7 +1459,8 @@ static int __devinit azx_init_stream(struct azx *chip) | |||
1386 | int i; | 1459 | int i; |
1387 | 1460 | ||
1388 | /* initialize each stream (aka device) | 1461 | /* initialize each stream (aka device) |
1389 | * assign the starting bdl address to each stream (device) and initialize | 1462 | * assign the starting bdl address to each stream (device) |
1463 | * and initialize | ||
1390 | */ | 1464 | */ |
1391 | for (i = 0; i < chip->num_streams; i++) { | 1465 | for (i = 0; i < chip->num_streams; i++) { |
1392 | unsigned int off = sizeof(u32) * (i * AZX_MAX_FRAG * 4); | 1466 | unsigned int off = sizeof(u32) * (i * AZX_MAX_FRAG * 4); |
@@ -1423,6 +1497,46 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect) | |||
1423 | } | 1497 | } |
1424 | 1498 | ||
1425 | 1499 | ||
1500 | static void azx_stop_chip(struct azx *chip) | ||
1501 | { | ||
1502 | if (!chip->initialized) | ||
1503 | return; | ||
1504 | |||
1505 | /* disable interrupts */ | ||
1506 | azx_int_disable(chip); | ||
1507 | azx_int_clear(chip); | ||
1508 | |||
1509 | /* disable CORB/RIRB */ | ||
1510 | azx_free_cmd_io(chip); | ||
1511 | |||
1512 | /* disable position buffer */ | ||
1513 | azx_writel(chip, DPLBASE, 0); | ||
1514 | azx_writel(chip, DPUBASE, 0); | ||
1515 | |||
1516 | chip->initialized = 0; | ||
1517 | } | ||
1518 | |||
1519 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1520 | /* power-up/down the controller */ | ||
1521 | static void azx_power_notify(struct hda_codec *codec) | ||
1522 | { | ||
1523 | struct azx *chip = codec->bus->private_data; | ||
1524 | struct hda_codec *c; | ||
1525 | int power_on = 0; | ||
1526 | |||
1527 | list_for_each_entry(c, &codec->bus->codec_list, list) { | ||
1528 | if (c->power_on) { | ||
1529 | power_on = 1; | ||
1530 | break; | ||
1531 | } | ||
1532 | } | ||
1533 | if (power_on) | ||
1534 | azx_init_chip(chip); | ||
1535 | else if (chip->running && power_save_controller) | ||
1536 | azx_stop_chip(chip); | ||
1537 | } | ||
1538 | #endif /* CONFIG_SND_HDA_POWER_SAVE */ | ||
1539 | |||
1426 | #ifdef CONFIG_PM | 1540 | #ifdef CONFIG_PM |
1427 | /* | 1541 | /* |
1428 | * power management | 1542 | * power management |
@@ -1436,8 +1550,9 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state) | |||
1436 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | 1550 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); |
1437 | for (i = 0; i < chip->pcm_devs; i++) | 1551 | for (i = 0; i < chip->pcm_devs; i++) |
1438 | snd_pcm_suspend_all(chip->pcm[i]); | 1552 | snd_pcm_suspend_all(chip->pcm[i]); |
1439 | snd_hda_suspend(chip->bus, state); | 1553 | if (chip->initialized) |
1440 | azx_free_cmd_io(chip); | 1554 | snd_hda_suspend(chip->bus, state); |
1555 | azx_stop_chip(chip); | ||
1441 | if (chip->irq >= 0) { | 1556 | if (chip->irq >= 0) { |
1442 | synchronize_irq(chip->irq); | 1557 | synchronize_irq(chip->irq); |
1443 | free_irq(chip->irq, chip); | 1558 | free_irq(chip->irq, chip); |
@@ -1470,7 +1585,11 @@ static int azx_resume(struct pci_dev *pci) | |||
1470 | chip->msi = 0; | 1585 | chip->msi = 0; |
1471 | if (azx_acquire_irq(chip, 1) < 0) | 1586 | if (azx_acquire_irq(chip, 1) < 0) |
1472 | return -EIO; | 1587 | return -EIO; |
1473 | azx_init_chip(chip); | 1588 | azx_init_pci(chip); |
1589 | |||
1590 | if (snd_hda_codecs_inuse(chip->bus)) | ||
1591 | azx_init_chip(chip); | ||
1592 | |||
1474 | snd_hda_resume(chip->bus); | 1593 | snd_hda_resume(chip->bus); |
1475 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | 1594 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); |
1476 | return 0; | 1595 | return 0; |
@@ -1485,20 +1604,9 @@ static int azx_free(struct azx *chip) | |||
1485 | { | 1604 | { |
1486 | if (chip->initialized) { | 1605 | if (chip->initialized) { |
1487 | int i; | 1606 | int i; |
1488 | |||
1489 | for (i = 0; i < chip->num_streams; i++) | 1607 | for (i = 0; i < chip->num_streams; i++) |
1490 | azx_stream_stop(chip, &chip->azx_dev[i]); | 1608 | azx_stream_stop(chip, &chip->azx_dev[i]); |
1491 | 1609 | azx_stop_chip(chip); | |
1492 | /* disable interrupts */ | ||
1493 | azx_int_disable(chip); | ||
1494 | azx_int_clear(chip); | ||
1495 | |||
1496 | /* disable CORB/RIRB */ | ||
1497 | azx_free_cmd_io(chip); | ||
1498 | |||
1499 | /* disable position buffer */ | ||
1500 | azx_writel(chip, DPLBASE, 0); | ||
1501 | azx_writel(chip, DPUBASE, 0); | ||
1502 | } | 1610 | } |
1503 | 1611 | ||
1504 | if (chip->irq >= 0) { | 1612 | if (chip->irq >= 0) { |
@@ -1534,6 +1642,7 @@ static int azx_dev_free(struct snd_device *device) | |||
1534 | */ | 1642 | */ |
1535 | static struct snd_pci_quirk position_fix_list[] __devinitdata = { | 1643 | static struct snd_pci_quirk position_fix_list[] __devinitdata = { |
1536 | SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_NONE), | 1644 | SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_NONE), |
1645 | SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_NONE), | ||
1537 | {} | 1646 | {} |
1538 | }; | 1647 | }; |
1539 | 1648 | ||
@@ -1544,7 +1653,7 @@ static int __devinit check_position_fix(struct azx *chip, int fix) | |||
1544 | if (fix == POS_FIX_AUTO) { | 1653 | if (fix == POS_FIX_AUTO) { |
1545 | q = snd_pci_quirk_lookup(chip->pci, position_fix_list); | 1654 | q = snd_pci_quirk_lookup(chip->pci, position_fix_list); |
1546 | if (q) { | 1655 | if (q) { |
1547 | snd_printdd(KERN_INFO | 1656 | printk(KERN_INFO |
1548 | "hda_intel: position_fix set to %d " | 1657 | "hda_intel: position_fix set to %d " |
1549 | "for device %04x:%04x\n", | 1658 | "for device %04x:%04x\n", |
1550 | q->value, q->subvendor, q->subdevice); | 1659 | q->value, q->subvendor, q->subdevice); |
@@ -1555,6 +1664,36 @@ static int __devinit check_position_fix(struct azx *chip, int fix) | |||
1555 | } | 1664 | } |
1556 | 1665 | ||
1557 | /* | 1666 | /* |
1667 | * black-lists for probe_mask | ||
1668 | */ | ||
1669 | static struct snd_pci_quirk probe_mask_list[] __devinitdata = { | ||
1670 | /* Thinkpad often breaks the controller communication when accessing | ||
1671 | * to the non-working (or non-existing) modem codec slot. | ||
1672 | */ | ||
1673 | SND_PCI_QUIRK(0x1014, 0x05b7, "Thinkpad Z60", 0x01), | ||
1674 | SND_PCI_QUIRK(0x17aa, 0x2010, "Thinkpad X/T/R60", 0x01), | ||
1675 | SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X/T/R61", 0x01), | ||
1676 | {} | ||
1677 | }; | ||
1678 | |||
1679 | static void __devinit check_probe_mask(struct azx *chip) | ||
1680 | { | ||
1681 | const struct snd_pci_quirk *q; | ||
1682 | |||
1683 | if (probe_mask == -1) { | ||
1684 | q = snd_pci_quirk_lookup(chip->pci, probe_mask_list); | ||
1685 | if (q) { | ||
1686 | printk(KERN_INFO | ||
1687 | "hda_intel: probe_mask set to 0x%x " | ||
1688 | "for device %04x:%04x\n", | ||
1689 | q->value, q->subvendor, q->subdevice); | ||
1690 | probe_mask = q->value; | ||
1691 | } | ||
1692 | } | ||
1693 | } | ||
1694 | |||
1695 | |||
1696 | /* | ||
1558 | * constructor | 1697 | * constructor |
1559 | */ | 1698 | */ |
1560 | static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | 1699 | static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, |
@@ -1589,6 +1728,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
1589 | chip->msi = enable_msi; | 1728 | chip->msi = enable_msi; |
1590 | 1729 | ||
1591 | chip->position_fix = check_position_fix(chip, position_fix); | 1730 | chip->position_fix = check_position_fix(chip, position_fix); |
1731 | check_probe_mask(chip); | ||
1592 | 1732 | ||
1593 | chip->single_cmd = single_cmd; | 1733 | chip->single_cmd = single_cmd; |
1594 | 1734 | ||
@@ -1650,37 +1790,43 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
1650 | break; | 1790 | break; |
1651 | } | 1791 | } |
1652 | chip->num_streams = chip->playback_streams + chip->capture_streams; | 1792 | chip->num_streams = chip->playback_streams + chip->capture_streams; |
1653 | chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), GFP_KERNEL); | 1793 | chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), |
1794 | GFP_KERNEL); | ||
1654 | if (!chip->azx_dev) { | 1795 | if (!chip->azx_dev) { |
1655 | snd_printk(KERN_ERR "cannot malloc azx_dev\n"); | 1796 | snd_printk(KERN_ERR "cannot malloc azx_dev\n"); |
1656 | goto errout; | 1797 | goto errout; |
1657 | } | 1798 | } |
1658 | 1799 | ||
1659 | /* allocate memory for the BDL for each stream */ | 1800 | /* allocate memory for the BDL for each stream */ |
1660 | if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), | 1801 | err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, |
1661 | BDL_SIZE, &chip->bdl)) < 0) { | 1802 | snd_dma_pci_data(chip->pci), |
1803 | BDL_SIZE, &chip->bdl); | ||
1804 | if (err < 0) { | ||
1662 | snd_printk(KERN_ERR SFX "cannot allocate BDL\n"); | 1805 | snd_printk(KERN_ERR SFX "cannot allocate BDL\n"); |
1663 | goto errout; | 1806 | goto errout; |
1664 | } | 1807 | } |
1665 | /* allocate memory for the position buffer */ | 1808 | /* allocate memory for the position buffer */ |
1666 | if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), | 1809 | err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, |
1667 | chip->num_streams * 8, &chip->posbuf)) < 0) { | 1810 | snd_dma_pci_data(chip->pci), |
1811 | chip->num_streams * 8, &chip->posbuf); | ||
1812 | if (err < 0) { | ||
1668 | snd_printk(KERN_ERR SFX "cannot allocate posbuf\n"); | 1813 | snd_printk(KERN_ERR SFX "cannot allocate posbuf\n"); |
1669 | goto errout; | 1814 | goto errout; |
1670 | } | 1815 | } |
1671 | /* allocate CORB/RIRB */ | 1816 | /* allocate CORB/RIRB */ |
1672 | if (! chip->single_cmd) | 1817 | if (!chip->single_cmd) { |
1673 | if ((err = azx_alloc_cmd_io(chip)) < 0) | 1818 | err = azx_alloc_cmd_io(chip); |
1819 | if (err < 0) | ||
1674 | goto errout; | 1820 | goto errout; |
1821 | } | ||
1675 | 1822 | ||
1676 | /* initialize streams */ | 1823 | /* initialize streams */ |
1677 | azx_init_stream(chip); | 1824 | azx_init_stream(chip); |
1678 | 1825 | ||
1679 | /* initialize chip */ | 1826 | /* initialize chip */ |
1827 | azx_init_pci(chip); | ||
1680 | azx_init_chip(chip); | 1828 | azx_init_chip(chip); |
1681 | 1829 | ||
1682 | chip->initialized = 1; | ||
1683 | |||
1684 | /* codec detection */ | 1830 | /* codec detection */ |
1685 | if (!chip->codec_mask) { | 1831 | if (!chip->codec_mask) { |
1686 | snd_printk(KERN_ERR SFX "no codecs found!\n"); | 1832 | snd_printk(KERN_ERR SFX "no codecs found!\n"); |
@@ -1688,14 +1834,16 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
1688 | goto errout; | 1834 | goto errout; |
1689 | } | 1835 | } |
1690 | 1836 | ||
1691 | if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) <0) { | 1837 | err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); |
1838 | if (err <0) { | ||
1692 | snd_printk(KERN_ERR SFX "Error creating device [card]!\n"); | 1839 | snd_printk(KERN_ERR SFX "Error creating device [card]!\n"); |
1693 | goto errout; | 1840 | goto errout; |
1694 | } | 1841 | } |
1695 | 1842 | ||
1696 | strcpy(card->driver, "HDA-Intel"); | 1843 | strcpy(card->driver, "HDA-Intel"); |
1697 | strcpy(card->shortname, driver_short_names[chip->driver_type]); | 1844 | strcpy(card->shortname, driver_short_names[chip->driver_type]); |
1698 | sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->addr, chip->irq); | 1845 | sprintf(card->longname, "%s at 0x%lx irq %i", |
1846 | card->shortname, chip->addr, chip->irq); | ||
1699 | 1847 | ||
1700 | *rchip = chip; | 1848 | *rchip = chip; |
1701 | return 0; | 1849 | return 0; |
@@ -1705,7 +1853,21 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
1705 | return err; | 1853 | return err; |
1706 | } | 1854 | } |
1707 | 1855 | ||
1708 | static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | 1856 | static void power_down_all_codecs(struct azx *chip) |
1857 | { | ||
1858 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1859 | /* The codecs were powered up in snd_hda_codec_new(). | ||
1860 | * Now all initialization done, so turn them down if possible | ||
1861 | */ | ||
1862 | struct hda_codec *codec; | ||
1863 | list_for_each_entry(codec, &chip->bus->codec_list, list) { | ||
1864 | snd_hda_power_down(codec); | ||
1865 | } | ||
1866 | #endif | ||
1867 | } | ||
1868 | |||
1869 | static int __devinit azx_probe(struct pci_dev *pci, | ||
1870 | const struct pci_device_id *pci_id) | ||
1709 | { | 1871 | { |
1710 | struct snd_card *card; | 1872 | struct snd_card *card; |
1711 | struct azx *chip; | 1873 | struct azx *chip; |
@@ -1725,31 +1887,37 @@ static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id * | |||
1725 | card->private_data = chip; | 1887 | card->private_data = chip; |
1726 | 1888 | ||
1727 | /* create codec instances */ | 1889 | /* create codec instances */ |
1728 | if ((err = azx_codec_create(chip, model)) < 0) { | 1890 | err = azx_codec_create(chip, model); |
1891 | if (err < 0) { | ||
1729 | snd_card_free(card); | 1892 | snd_card_free(card); |
1730 | return err; | 1893 | return err; |
1731 | } | 1894 | } |
1732 | 1895 | ||
1733 | /* create PCM streams */ | 1896 | /* create PCM streams */ |
1734 | if ((err = azx_pcm_create(chip)) < 0) { | 1897 | err = azx_pcm_create(chip); |
1898 | if (err < 0) { | ||
1735 | snd_card_free(card); | 1899 | snd_card_free(card); |
1736 | return err; | 1900 | return err; |
1737 | } | 1901 | } |
1738 | 1902 | ||
1739 | /* create mixer controls */ | 1903 | /* create mixer controls */ |
1740 | if ((err = azx_mixer_create(chip)) < 0) { | 1904 | err = azx_mixer_create(chip); |
1905 | if (err < 0) { | ||
1741 | snd_card_free(card); | 1906 | snd_card_free(card); |
1742 | return err; | 1907 | return err; |
1743 | } | 1908 | } |
1744 | 1909 | ||
1745 | snd_card_set_dev(card, &pci->dev); | 1910 | snd_card_set_dev(card, &pci->dev); |
1746 | 1911 | ||
1747 | if ((err = snd_card_register(card)) < 0) { | 1912 | err = snd_card_register(card); |
1913 | if (err < 0) { | ||
1748 | snd_card_free(card); | 1914 | snd_card_free(card); |
1749 | return err; | 1915 | return err; |
1750 | } | 1916 | } |
1751 | 1917 | ||
1752 | pci_set_drvdata(pci, card); | 1918 | pci_set_drvdata(pci, card); |
1919 | chip->running = 1; | ||
1920 | power_down_all_codecs(chip); | ||
1753 | 1921 | ||
1754 | return err; | 1922 | return err; |
1755 | } | 1923 | } |
@@ -1791,6 +1959,10 @@ static struct pci_device_id azx_ids[] = { | |||
1791 | { 0x10de, 0x0775, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */ | 1959 | { 0x10de, 0x0775, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */ |
1792 | { 0x10de, 0x0776, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */ | 1960 | { 0x10de, 0x0776, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */ |
1793 | { 0x10de, 0x0777, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */ | 1961 | { 0x10de, 0x0777, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */ |
1962 | { 0x10de, 0x0ac0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP79 */ | ||
1963 | { 0x10de, 0x0ac1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP79 */ | ||
1964 | { 0x10de, 0x0ac2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP79 */ | ||
1965 | { 0x10de, 0x0ac3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP79 */ | ||
1794 | { 0, } | 1966 | { 0, } |
1795 | }; | 1967 | }; |
1796 | MODULE_DEVICE_TABLE(pci, azx_ids); | 1968 | MODULE_DEVICE_TABLE(pci, azx_ids); |
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index f91ea5ec9f6d..a79d0ed5469c 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h | |||
@@ -26,7 +26,8 @@ | |||
26 | /* | 26 | /* |
27 | * for mixer controls | 27 | * for mixer controls |
28 | */ | 28 | */ |
29 | #define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19)) | 29 | #define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) \ |
30 | ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19)) | ||
30 | /* mono volume with index (index=0,1,...) (channel=1,2) */ | 31 | /* mono volume with index (index=0,1,...) (channel=1,2) */ |
31 | #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ | 32 | #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ |
32 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ | 33 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ |
@@ -64,18 +65,35 @@ | |||
64 | #define HDA_CODEC_MUTE(xname, nid, xindex, direction) \ | 65 | #define HDA_CODEC_MUTE(xname, nid, xindex, direction) \ |
65 | HDA_CODEC_MUTE_MONO(xname, nid, 3, xindex, direction) | 66 | HDA_CODEC_MUTE_MONO(xname, nid, 3, xindex, direction) |
66 | 67 | ||
67 | int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); | 68 | int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, |
68 | int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); | 69 | struct snd_ctl_elem_info *uinfo); |
69 | int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); | 70 | int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, |
70 | int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *tlv); | 71 | struct snd_ctl_elem_value *ucontrol); |
71 | int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); | 72 | int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, |
72 | int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); | 73 | struct snd_ctl_elem_value *ucontrol); |
73 | int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); | 74 | int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, |
75 | unsigned int size, unsigned int __user *tlv); | ||
76 | int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, | ||
77 | struct snd_ctl_elem_info *uinfo); | ||
78 | int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, | ||
79 | struct snd_ctl_elem_value *ucontrol); | ||
80 | int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, | ||
81 | struct snd_ctl_elem_value *ucontrol); | ||
74 | /* lowlevel accessor with caching; use carefully */ | 82 | /* lowlevel accessor with caching; use carefully */ |
75 | int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, | 83 | int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, |
76 | int direction, int index); | 84 | int direction, int index); |
77 | int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, | 85 | int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, |
78 | int direction, int idx, int mask, int val); | 86 | int direction, int idx, int mask, int val); |
87 | int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, | ||
88 | int dir, int idx, int mask, int val); | ||
89 | #ifdef SND_HDA_NEEDS_RESUME | ||
90 | void snd_hda_codec_resume_amp(struct hda_codec *codec); | ||
91 | #endif | ||
92 | |||
93 | /* amp value bits */ | ||
94 | #define HDA_AMP_MUTE 0x80 | ||
95 | #define HDA_AMP_UNMUTE 0x00 | ||
96 | #define HDA_AMP_VOLMASK 0x7f | ||
79 | 97 | ||
80 | /* mono switch binding multiple inputs */ | 98 | /* mono switch binding multiple inputs */ |
81 | #define HDA_BIND_MUTE_MONO(xname, nid, channel, indices, direction) \ | 99 | #define HDA_BIND_MUTE_MONO(xname, nid, channel, indices, direction) \ |
@@ -86,11 +104,61 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, | |||
86 | .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, indices, direction) } | 104 | .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, indices, direction) } |
87 | 105 | ||
88 | /* stereo switch binding multiple inputs */ | 106 | /* stereo switch binding multiple inputs */ |
89 | #define HDA_BIND_MUTE(xname,nid,indices,dir) HDA_BIND_MUTE_MONO(xname,nid,3,indices,dir) | 107 | #define HDA_BIND_MUTE(xname,nid,indices,dir) \ |
108 | HDA_BIND_MUTE_MONO(xname,nid,3,indices,dir) | ||
109 | |||
110 | int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, | ||
111 | struct snd_ctl_elem_value *ucontrol); | ||
112 | int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, | ||
113 | struct snd_ctl_elem_value *ucontrol); | ||
114 | |||
115 | /* more generic bound controls */ | ||
116 | struct hda_ctl_ops { | ||
117 | snd_kcontrol_info_t *info; | ||
118 | snd_kcontrol_get_t *get; | ||
119 | snd_kcontrol_put_t *put; | ||
120 | snd_kcontrol_tlv_rw_t *tlv; | ||
121 | }; | ||
90 | 122 | ||
91 | int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); | 123 | extern struct hda_ctl_ops snd_hda_bind_vol; /* for bind-volume with TLV */ |
92 | int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); | 124 | extern struct hda_ctl_ops snd_hda_bind_sw; /* for bind-switch */ |
93 | 125 | ||
126 | struct hda_bind_ctls { | ||
127 | struct hda_ctl_ops *ops; | ||
128 | long values[]; | ||
129 | }; | ||
130 | |||
131 | int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol, | ||
132 | struct snd_ctl_elem_info *uinfo); | ||
133 | int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, | ||
134 | struct snd_ctl_elem_value *ucontrol); | ||
135 | int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, | ||
136 | struct snd_ctl_elem_value *ucontrol); | ||
137 | int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, | ||
138 | unsigned int size, unsigned int __user *tlv); | ||
139 | |||
140 | #define HDA_BIND_VOL(xname, bindrec) \ | ||
141 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
142 | .name = xname, \ | ||
143 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ | ||
144 | SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | ||
145 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,\ | ||
146 | .info = snd_hda_mixer_bind_ctls_info,\ | ||
147 | .get = snd_hda_mixer_bind_ctls_get,\ | ||
148 | .put = snd_hda_mixer_bind_ctls_put,\ | ||
149 | .tlv = { .c = snd_hda_mixer_bind_tlv },\ | ||
150 | .private_value = (long) (bindrec) } | ||
151 | #define HDA_BIND_SW(xname, bindrec) \ | ||
152 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,\ | ||
153 | .name = xname, \ | ||
154 | .info = snd_hda_mixer_bind_ctls_info,\ | ||
155 | .get = snd_hda_mixer_bind_ctls_get,\ | ||
156 | .put = snd_hda_mixer_bind_ctls_put,\ | ||
157 | .private_value = (long) (bindrec) } | ||
158 | |||
159 | /* | ||
160 | * SPDIF I/O | ||
161 | */ | ||
94 | int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid); | 162 | int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid); |
95 | int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid); | 163 | int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid); |
96 | 164 | ||
@@ -107,8 +175,10 @@ struct hda_input_mux { | |||
107 | struct hda_input_mux_item items[HDA_MAX_NUM_INPUTS]; | 175 | struct hda_input_mux_item items[HDA_MAX_NUM_INPUTS]; |
108 | }; | 176 | }; |
109 | 177 | ||
110 | int snd_hda_input_mux_info(const struct hda_input_mux *imux, struct snd_ctl_elem_info *uinfo); | 178 | int snd_hda_input_mux_info(const struct hda_input_mux *imux, |
111 | int snd_hda_input_mux_put(struct hda_codec *codec, const struct hda_input_mux *imux, | 179 | struct snd_ctl_elem_info *uinfo); |
180 | int snd_hda_input_mux_put(struct hda_codec *codec, | ||
181 | const struct hda_input_mux *imux, | ||
112 | struct snd_ctl_elem_value *ucontrol, hda_nid_t nid, | 182 | struct snd_ctl_elem_value *ucontrol, hda_nid_t nid, |
113 | unsigned int *cur_val); | 183 | unsigned int *cur_val); |
114 | 184 | ||
@@ -120,13 +190,19 @@ struct hda_channel_mode { | |||
120 | const struct hda_verb *sequence; | 190 | const struct hda_verb *sequence; |
121 | }; | 191 | }; |
122 | 192 | ||
123 | int snd_hda_ch_mode_info(struct hda_codec *codec, struct snd_ctl_elem_info *uinfo, | 193 | int snd_hda_ch_mode_info(struct hda_codec *codec, |
124 | const struct hda_channel_mode *chmode, int num_chmodes); | 194 | struct snd_ctl_elem_info *uinfo, |
125 | int snd_hda_ch_mode_get(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, | 195 | const struct hda_channel_mode *chmode, |
126 | const struct hda_channel_mode *chmode, int num_chmodes, | 196 | int num_chmodes); |
197 | int snd_hda_ch_mode_get(struct hda_codec *codec, | ||
198 | struct snd_ctl_elem_value *ucontrol, | ||
199 | const struct hda_channel_mode *chmode, | ||
200 | int num_chmodes, | ||
127 | int max_channels); | 201 | int max_channels); |
128 | int snd_hda_ch_mode_put(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, | 202 | int snd_hda_ch_mode_put(struct hda_codec *codec, |
129 | const struct hda_channel_mode *chmode, int num_chmodes, | 203 | struct snd_ctl_elem_value *ucontrol, |
204 | const struct hda_channel_mode *chmode, | ||
205 | int num_chmodes, | ||
130 | int *max_channelsp); | 206 | int *max_channelsp); |
131 | 207 | ||
132 | /* | 208 | /* |
@@ -146,20 +222,25 @@ struct hda_multi_out { | |||
146 | int dig_out_used; /* current usage of digital out (HDA_DIG_XXX) */ | 222 | int dig_out_used; /* current usage of digital out (HDA_DIG_XXX) */ |
147 | }; | 223 | }; |
148 | 224 | ||
149 | int snd_hda_multi_out_dig_open(struct hda_codec *codec, struct hda_multi_out *mout); | 225 | int snd_hda_multi_out_dig_open(struct hda_codec *codec, |
150 | int snd_hda_multi_out_dig_close(struct hda_codec *codec, struct hda_multi_out *mout); | 226 | struct hda_multi_out *mout); |
227 | int snd_hda_multi_out_dig_close(struct hda_codec *codec, | ||
228 | struct hda_multi_out *mout); | ||
151 | int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, | 229 | int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, |
152 | struct hda_multi_out *mout, | 230 | struct hda_multi_out *mout, |
153 | unsigned int stream_tag, | 231 | unsigned int stream_tag, |
154 | unsigned int format, | 232 | unsigned int format, |
155 | struct snd_pcm_substream *substream); | 233 | struct snd_pcm_substream *substream); |
156 | int snd_hda_multi_out_analog_open(struct hda_codec *codec, struct hda_multi_out *mout, | 234 | int snd_hda_multi_out_analog_open(struct hda_codec *codec, |
235 | struct hda_multi_out *mout, | ||
157 | struct snd_pcm_substream *substream); | 236 | struct snd_pcm_substream *substream); |
158 | int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_out *mout, | 237 | int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, |
238 | struct hda_multi_out *mout, | ||
159 | unsigned int stream_tag, | 239 | unsigned int stream_tag, |
160 | unsigned int format, | 240 | unsigned int format, |
161 | struct snd_pcm_substream *substream); | 241 | struct snd_pcm_substream *substream); |
162 | int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, struct hda_multi_out *mout); | 242 | int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, |
243 | struct hda_multi_out *mout); | ||
163 | 244 | ||
164 | /* | 245 | /* |
165 | * generic codec parser | 246 | * generic codec parser |
@@ -181,16 +262,8 @@ static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; } | |||
181 | int snd_hda_check_board_config(struct hda_codec *codec, int num_configs, | 262 | int snd_hda_check_board_config(struct hda_codec *codec, int num_configs, |
182 | const char **modelnames, | 263 | const char **modelnames, |
183 | const struct snd_pci_quirk *pci_list); | 264 | const struct snd_pci_quirk *pci_list); |
184 | int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew); | 265 | int snd_hda_add_new_ctls(struct hda_codec *codec, |
185 | 266 | struct snd_kcontrol_new *knew); | |
186 | /* | ||
187 | * power management | ||
188 | */ | ||
189 | #ifdef CONFIG_PM | ||
190 | int snd_hda_resume_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew); | ||
191 | int snd_hda_resume_spdif_out(struct hda_codec *codec); | ||
192 | int snd_hda_resume_spdif_in(struct hda_codec *codec); | ||
193 | #endif | ||
194 | 267 | ||
195 | /* | 268 | /* |
196 | * unsolicited event handler | 269 | * unsolicited event handler |
@@ -232,7 +305,9 @@ extern const char *auto_pin_cfg_labels[AUTO_PIN_LAST]; | |||
232 | 305 | ||
233 | struct auto_pin_cfg { | 306 | struct auto_pin_cfg { |
234 | int line_outs; | 307 | int line_outs; |
235 | hda_nid_t line_out_pins[5]; /* sorted in the order of Front/Surr/CLFE/Side */ | 308 | hda_nid_t line_out_pins[5]; /* sorted in the order of |
309 | * Front/Surr/CLFE/Side | ||
310 | */ | ||
236 | int speaker_outs; | 311 | int speaker_outs; |
237 | hda_nid_t speaker_pins[5]; | 312 | hda_nid_t speaker_pins[5]; |
238 | int hp_outs; | 313 | int hp_outs; |
@@ -243,13 +318,19 @@ struct auto_pin_cfg { | |||
243 | hda_nid_t dig_in_pin; | 318 | hda_nid_t dig_in_pin; |
244 | }; | 319 | }; |
245 | 320 | ||
246 | #define get_defcfg_connect(cfg) ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) | 321 | #define get_defcfg_connect(cfg) \ |
247 | #define get_defcfg_association(cfg) ((cfg & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT) | 322 | ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) |
248 | #define get_defcfg_location(cfg) ((cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) | 323 | #define get_defcfg_association(cfg) \ |
249 | #define get_defcfg_sequence(cfg) (cfg & AC_DEFCFG_SEQUENCE) | 324 | ((cfg & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT) |
250 | #define get_defcfg_device(cfg) ((cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) | 325 | #define get_defcfg_location(cfg) \ |
251 | 326 | ((cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) | |
252 | int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *cfg, | 327 | #define get_defcfg_sequence(cfg) \ |
328 | (cfg & AC_DEFCFG_SEQUENCE) | ||
329 | #define get_defcfg_device(cfg) \ | ||
330 | ((cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) | ||
331 | |||
332 | int snd_hda_parse_pin_def_config(struct hda_codec *codec, | ||
333 | struct auto_pin_cfg *cfg, | ||
253 | hda_nid_t *ignore_nids); | 334 | hda_nid_t *ignore_nids); |
254 | 335 | ||
255 | /* amp values */ | 336 | /* amp values */ |
@@ -280,4 +361,32 @@ static inline u32 get_wcaps(struct hda_codec *codec, hda_nid_t nid) | |||
280 | int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, | 361 | int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, |
281 | unsigned int caps); | 362 | unsigned int caps); |
282 | 363 | ||
364 | /* | ||
365 | * hwdep interface | ||
366 | */ | ||
367 | int snd_hda_create_hwdep(struct hda_codec *codec); | ||
368 | |||
369 | /* | ||
370 | * power-management | ||
371 | */ | ||
372 | |||
373 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
374 | void snd_hda_schedule_power_save(struct hda_codec *codec); | ||
375 | |||
376 | struct hda_amp_list { | ||
377 | hda_nid_t nid; | ||
378 | unsigned char dir; | ||
379 | unsigned char idx; | ||
380 | }; | ||
381 | |||
382 | struct hda_loopback_check { | ||
383 | struct hda_amp_list *amplist; | ||
384 | int power_on; | ||
385 | }; | ||
386 | |||
387 | int snd_hda_check_amp_list_power(struct hda_codec *codec, | ||
388 | struct hda_loopback_check *check, | ||
389 | hda_nid_t nid); | ||
390 | #endif /* CONFIG_SND_HDA_POWER_SAVE */ | ||
391 | |||
283 | #endif /* __SOUND_HDA_LOCAL_H */ | 392 | #endif /* __SOUND_HDA_LOCAL_H */ |
diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h index 9f9e9ae44a9d..f5c23bb16d7e 100644 --- a/sound/pci/hda/hda_patch.h +++ b/sound/pci/hda/hda_patch.h | |||
@@ -20,13 +20,29 @@ extern struct hda_codec_preset snd_hda_preset_conexant[]; | |||
20 | extern struct hda_codec_preset snd_hda_preset_via[]; | 20 | extern struct hda_codec_preset snd_hda_preset_via[]; |
21 | 21 | ||
22 | static const struct hda_codec_preset *hda_preset_tables[] = { | 22 | static const struct hda_codec_preset *hda_preset_tables[] = { |
23 | #ifdef CONFIG_SND_HDA_CODEC_REALTEK | ||
23 | snd_hda_preset_realtek, | 24 | snd_hda_preset_realtek, |
25 | #endif | ||
26 | #ifdef CONFIG_SND_HDA_CODEC_CMEDIA | ||
24 | snd_hda_preset_cmedia, | 27 | snd_hda_preset_cmedia, |
28 | #endif | ||
29 | #ifdef CONFIG_SND_HDA_CODEC_ANALOG | ||
25 | snd_hda_preset_analog, | 30 | snd_hda_preset_analog, |
31 | #endif | ||
32 | #ifdef CONFIG_SND_HDA_CODEC_SIGMATEL | ||
26 | snd_hda_preset_sigmatel, | 33 | snd_hda_preset_sigmatel, |
34 | #endif | ||
35 | #ifdef CONFIG_SND_HDA_CODEC_SI3054 | ||
27 | snd_hda_preset_si3054, | 36 | snd_hda_preset_si3054, |
37 | #endif | ||
38 | #ifdef CONFIG_SND_HDA_CODEC_ATIHDMI | ||
28 | snd_hda_preset_atihdmi, | 39 | snd_hda_preset_atihdmi, |
40 | #endif | ||
41 | #ifdef CONFIG_SND_HDA_CODEC_CONEXANT | ||
29 | snd_hda_preset_conexant, | 42 | snd_hda_preset_conexant, |
43 | #endif | ||
44 | #ifdef CONFIG_SND_HDA_CODEC_VIA | ||
30 | snd_hda_preset_via, | 45 | snd_hda_preset_via, |
46 | #endif | ||
31 | NULL | 47 | NULL |
32 | }; | 48 | }; |
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index ac15066fd300..e94944f34ffd 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c | |||
@@ -58,7 +58,8 @@ static void print_amp_caps(struct snd_info_buffer *buffer, | |||
58 | snd_iprintf(buffer, "N/A\n"); | 58 | snd_iprintf(buffer, "N/A\n"); |
59 | return; | 59 | return; |
60 | } | 60 | } |
61 | snd_iprintf(buffer, "ofs=0x%02x, nsteps=0x%02x, stepsize=0x%02x, mute=%x\n", | 61 | snd_iprintf(buffer, "ofs=0x%02x, nsteps=0x%02x, stepsize=0x%02x, " |
62 | "mute=%x\n", | ||
62 | caps & AC_AMPCAP_OFFSET, | 63 | caps & AC_AMPCAP_OFFSET, |
63 | (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT, | 64 | (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT, |
64 | (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT, | 65 | (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT, |
@@ -76,11 +77,13 @@ static void print_amp_vals(struct snd_info_buffer *buffer, | |||
76 | for (i = 0; i < indices; i++) { | 77 | for (i = 0; i < indices; i++) { |
77 | snd_iprintf(buffer, " ["); | 78 | snd_iprintf(buffer, " ["); |
78 | if (stereo) { | 79 | if (stereo) { |
79 | val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, | 80 | val = snd_hda_codec_read(codec, nid, 0, |
81 | AC_VERB_GET_AMP_GAIN_MUTE, | ||
80 | AC_AMP_GET_LEFT | dir | i); | 82 | AC_AMP_GET_LEFT | dir | i); |
81 | snd_iprintf(buffer, "0x%02x ", val); | 83 | snd_iprintf(buffer, "0x%02x ", val); |
82 | } | 84 | } |
83 | val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, | 85 | val = snd_hda_codec_read(codec, nid, 0, |
86 | AC_VERB_GET_AMP_GAIN_MUTE, | ||
84 | AC_AMP_GET_RIGHT | dir | i); | 87 | AC_AMP_GET_RIGHT | dir | i); |
85 | snd_iprintf(buffer, "0x%02x]", val); | 88 | snd_iprintf(buffer, "0x%02x]", val); |
86 | } | 89 | } |
@@ -237,7 +240,8 @@ static void print_pin_caps(struct snd_info_buffer *buffer, | |||
237 | } | 240 | } |
238 | 241 | ||
239 | 242 | ||
240 | static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | 243 | static void print_codec_info(struct snd_info_entry *entry, |
244 | struct snd_info_buffer *buffer) | ||
241 | { | 245 | { |
242 | struct hda_codec *codec = entry->private_data; | 246 | struct hda_codec *codec = entry->private_data; |
243 | char buf[32]; | 247 | char buf[32]; |
@@ -258,6 +262,7 @@ static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffe | |||
258 | 262 | ||
259 | if (! codec->afg) | 263 | if (! codec->afg) |
260 | return; | 264 | return; |
265 | snd_hda_power_up(codec); | ||
261 | snd_iprintf(buffer, "Default PCM:\n"); | 266 | snd_iprintf(buffer, "Default PCM:\n"); |
262 | print_pcm_caps(buffer, codec, codec->afg); | 267 | print_pcm_caps(buffer, codec, codec->afg); |
263 | snd_iprintf(buffer, "Default Amp-In caps: "); | 268 | snd_iprintf(buffer, "Default Amp-In caps: "); |
@@ -268,12 +273,15 @@ static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffe | |||
268 | nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid); | 273 | nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid); |
269 | if (! nid || nodes < 0) { | 274 | if (! nid || nodes < 0) { |
270 | snd_iprintf(buffer, "Invalid AFG subtree\n"); | 275 | snd_iprintf(buffer, "Invalid AFG subtree\n"); |
276 | snd_hda_power_down(codec); | ||
271 | return; | 277 | return; |
272 | } | 278 | } |
273 | for (i = 0; i < nodes; i++, nid++) { | 279 | for (i = 0; i < nodes; i++, nid++) { |
274 | unsigned int wid_caps = snd_hda_param_read(codec, nid, | 280 | unsigned int wid_caps = |
275 | AC_PAR_AUDIO_WIDGET_CAP); | 281 | snd_hda_param_read(codec, nid, |
276 | unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; | 282 | AC_PAR_AUDIO_WIDGET_CAP); |
283 | unsigned int wid_type = | ||
284 | (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; | ||
277 | int conn_len = 0; | 285 | int conn_len = 0; |
278 | hda_nid_t conn[HDA_MAX_CONNECTIONS]; | 286 | hda_nid_t conn[HDA_MAX_CONNECTIONS]; |
279 | 287 | ||
@@ -313,7 +321,9 @@ static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffe | |||
313 | if (wid_type == AC_WID_PIN) { | 321 | if (wid_type == AC_WID_PIN) { |
314 | unsigned int pinctls; | 322 | unsigned int pinctls; |
315 | print_pin_caps(buffer, codec, nid); | 323 | print_pin_caps(buffer, codec, nid); |
316 | pinctls = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | 324 | pinctls = snd_hda_codec_read(codec, nid, 0, |
325 | AC_VERB_GET_PIN_WIDGET_CONTROL, | ||
326 | 0); | ||
317 | snd_iprintf(buffer, " Pin-ctls: 0x%02x:", pinctls); | 327 | snd_iprintf(buffer, " Pin-ctls: 0x%02x:", pinctls); |
318 | if (pinctls & AC_PINCTL_IN_EN) | 328 | if (pinctls & AC_PINCTL_IN_EN) |
319 | snd_iprintf(buffer, " IN"); | 329 | snd_iprintf(buffer, " IN"); |
@@ -333,7 +343,8 @@ static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffe | |||
333 | if (wid_caps & AC_WCAP_POWER) | 343 | if (wid_caps & AC_WCAP_POWER) |
334 | snd_iprintf(buffer, " Power: 0x%x\n", | 344 | snd_iprintf(buffer, " Power: 0x%x\n", |
335 | snd_hda_codec_read(codec, nid, 0, | 345 | snd_hda_codec_read(codec, nid, 0, |
336 | AC_VERB_GET_POWER_STATE, 0)); | 346 | AC_VERB_GET_POWER_STATE, |
347 | 0)); | ||
337 | 348 | ||
338 | if (wid_caps & AC_WCAP_CONN_LIST) { | 349 | if (wid_caps & AC_WCAP_CONN_LIST) { |
339 | int c, curr = -1; | 350 | int c, curr = -1; |
@@ -350,6 +361,7 @@ static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffe | |||
350 | snd_iprintf(buffer, "\n"); | 361 | snd_iprintf(buffer, "\n"); |
351 | } | 362 | } |
352 | } | 363 | } |
364 | snd_hda_power_down(codec); | ||
353 | } | 365 | } |
354 | 366 | ||
355 | /* | 367 | /* |
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 4d7f8d11ad75..54cfd4526d20 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -73,6 +73,12 @@ struct ad198x_spec { | |||
73 | struct snd_kcontrol_new *kctl_alloc; | 73 | struct snd_kcontrol_new *kctl_alloc; |
74 | struct hda_input_mux private_imux; | 74 | struct hda_input_mux private_imux; |
75 | hda_nid_t private_dac_nids[4]; | 75 | hda_nid_t private_dac_nids[4]; |
76 | |||
77 | unsigned int jack_present :1; | ||
78 | |||
79 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
80 | struct hda_loopback_check loopback; | ||
81 | #endif | ||
76 | }; | 82 | }; |
77 | 83 | ||
78 | /* | 84 | /* |
@@ -144,6 +150,14 @@ static int ad198x_build_controls(struct hda_codec *codec) | |||
144 | return 0; | 150 | return 0; |
145 | } | 151 | } |
146 | 152 | ||
153 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
154 | static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid) | ||
155 | { | ||
156 | struct ad198x_spec *spec = codec->spec; | ||
157 | return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); | ||
158 | } | ||
159 | #endif | ||
160 | |||
147 | /* | 161 | /* |
148 | * Analog playback callbacks | 162 | * Analog playback callbacks |
149 | */ | 163 | */ |
@@ -318,30 +332,13 @@ static void ad198x_free(struct hda_codec *codec) | |||
318 | kfree(codec->spec); | 332 | kfree(codec->spec); |
319 | } | 333 | } |
320 | 334 | ||
321 | #ifdef CONFIG_PM | ||
322 | static int ad198x_resume(struct hda_codec *codec) | ||
323 | { | ||
324 | struct ad198x_spec *spec = codec->spec; | ||
325 | int i; | ||
326 | |||
327 | codec->patch_ops.init(codec); | ||
328 | for (i = 0; i < spec->num_mixers; i++) | ||
329 | snd_hda_resume_ctls(codec, spec->mixers[i]); | ||
330 | if (spec->multiout.dig_out_nid) | ||
331 | snd_hda_resume_spdif_out(codec); | ||
332 | if (spec->dig_in_nid) | ||
333 | snd_hda_resume_spdif_in(codec); | ||
334 | return 0; | ||
335 | } | ||
336 | #endif | ||
337 | |||
338 | static struct hda_codec_ops ad198x_patch_ops = { | 335 | static struct hda_codec_ops ad198x_patch_ops = { |
339 | .build_controls = ad198x_build_controls, | 336 | .build_controls = ad198x_build_controls, |
340 | .build_pcms = ad198x_build_pcms, | 337 | .build_pcms = ad198x_build_pcms, |
341 | .init = ad198x_init, | 338 | .init = ad198x_init, |
342 | .free = ad198x_free, | 339 | .free = ad198x_free, |
343 | #ifdef CONFIG_PM | 340 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
344 | .resume = ad198x_resume, | 341 | .check_power_status = ad198x_check_power_status, |
345 | #endif | 342 | #endif |
346 | }; | 343 | }; |
347 | 344 | ||
@@ -350,15 +347,7 @@ static struct hda_codec_ops ad198x_patch_ops = { | |||
350 | * EAPD control | 347 | * EAPD control |
351 | * the private value = nid | (invert << 8) | 348 | * the private value = nid | (invert << 8) |
352 | */ | 349 | */ |
353 | static int ad198x_eapd_info(struct snd_kcontrol *kcontrol, | 350 | #define ad198x_eapd_info snd_ctl_boolean_mono_info |
354 | struct snd_ctl_elem_info *uinfo) | ||
355 | { | ||
356 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
357 | uinfo->count = 1; | ||
358 | uinfo->value.integer.min = 0; | ||
359 | uinfo->value.integer.max = 1; | ||
360 | return 0; | ||
361 | } | ||
362 | 351 | ||
363 | static int ad198x_eapd_get(struct snd_kcontrol *kcontrol, | 352 | static int ad198x_eapd_get(struct snd_kcontrol *kcontrol, |
364 | struct snd_ctl_elem_value *ucontrol) | 353 | struct snd_ctl_elem_value *ucontrol) |
@@ -384,12 +373,12 @@ static int ad198x_eapd_put(struct snd_kcontrol *kcontrol, | |||
384 | eapd = ucontrol->value.integer.value[0]; | 373 | eapd = ucontrol->value.integer.value[0]; |
385 | if (invert) | 374 | if (invert) |
386 | eapd = !eapd; | 375 | eapd = !eapd; |
387 | if (eapd == spec->cur_eapd && ! codec->in_resume) | 376 | if (eapd == spec->cur_eapd) |
388 | return 0; | 377 | return 0; |
389 | spec->cur_eapd = eapd; | 378 | spec->cur_eapd = eapd; |
390 | snd_hda_codec_write(codec, nid, | 379 | snd_hda_codec_write_cache(codec, nid, |
391 | 0, AC_VERB_SET_EAPD_BTLENABLE, | 380 | 0, AC_VERB_SET_EAPD_BTLENABLE, |
392 | eapd ? 0x02 : 0x00); | 381 | eapd ? 0x02 : 0x00); |
393 | return 1; | 382 | return 1; |
394 | } | 383 | } |
395 | 384 | ||
@@ -430,94 +419,36 @@ static struct hda_input_mux ad1986a_capture_source = { | |||
430 | }, | 419 | }, |
431 | }; | 420 | }; |
432 | 421 | ||
433 | /* | ||
434 | * PCM control | ||
435 | * | ||
436 | * bind volumes/mutes of 3 DACs as a single PCM control for simplicity | ||
437 | */ | ||
438 | |||
439 | #define ad1986a_pcm_amp_vol_info snd_hda_mixer_amp_volume_info | ||
440 | |||
441 | static int ad1986a_pcm_amp_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
442 | { | ||
443 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
444 | struct ad198x_spec *ad = codec->spec; | ||
445 | |||
446 | mutex_lock(&ad->amp_mutex); | ||
447 | snd_hda_mixer_amp_volume_get(kcontrol, ucontrol); | ||
448 | mutex_unlock(&ad->amp_mutex); | ||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | static int ad1986a_pcm_amp_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
453 | { | ||
454 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
455 | struct ad198x_spec *ad = codec->spec; | ||
456 | int i, change = 0; | ||
457 | |||
458 | mutex_lock(&ad->amp_mutex); | ||
459 | for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) { | ||
460 | kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT); | ||
461 | change |= snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); | ||
462 | } | ||
463 | kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT); | ||
464 | mutex_unlock(&ad->amp_mutex); | ||
465 | return change; | ||
466 | } | ||
467 | |||
468 | #define ad1986a_pcm_amp_sw_info snd_hda_mixer_amp_switch_info | ||
469 | 422 | ||
470 | static int ad1986a_pcm_amp_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 423 | static struct hda_bind_ctls ad1986a_bind_pcm_vol = { |
471 | { | 424 | .ops = &snd_hda_bind_vol, |
472 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 425 | .values = { |
473 | struct ad198x_spec *ad = codec->spec; | 426 | HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT), |
474 | 427 | HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT), | |
475 | mutex_lock(&ad->amp_mutex); | 428 | HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT), |
476 | snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); | 429 | 0 |
477 | mutex_unlock(&ad->amp_mutex); | 430 | }, |
478 | return 0; | 431 | }; |
479 | } | ||
480 | |||
481 | static int ad1986a_pcm_amp_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
482 | { | ||
483 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
484 | struct ad198x_spec *ad = codec->spec; | ||
485 | int i, change = 0; | ||
486 | 432 | ||
487 | mutex_lock(&ad->amp_mutex); | 433 | static struct hda_bind_ctls ad1986a_bind_pcm_sw = { |
488 | for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) { | 434 | .ops = &snd_hda_bind_sw, |
489 | kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT); | 435 | .values = { |
490 | change |= snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); | 436 | HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT), |
491 | } | 437 | HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT), |
492 | kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT); | 438 | HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT), |
493 | mutex_unlock(&ad->amp_mutex); | 439 | 0 |
494 | return change; | 440 | }, |
495 | } | 441 | }; |
496 | 442 | ||
497 | /* | 443 | /* |
498 | * mixers | 444 | * mixers |
499 | */ | 445 | */ |
500 | static struct snd_kcontrol_new ad1986a_mixers[] = { | 446 | static struct snd_kcontrol_new ad1986a_mixers[] = { |
501 | { | 447 | /* |
502 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 448 | * bind volumes/mutes of 3 DACs as a single PCM control for simplicity |
503 | .name = "PCM Playback Volume", | 449 | */ |
504 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | 450 | HDA_BIND_VOL("PCM Playback Volume", &ad1986a_bind_pcm_vol), |
505 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | | 451 | HDA_BIND_SW("PCM Playback Switch", &ad1986a_bind_pcm_sw), |
506 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, | ||
507 | .info = ad1986a_pcm_amp_vol_info, | ||
508 | .get = ad1986a_pcm_amp_vol_get, | ||
509 | .put = ad1986a_pcm_amp_vol_put, | ||
510 | .tlv = { .c = snd_hda_mixer_amp_tlv }, | ||
511 | .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT) | ||
512 | }, | ||
513 | { | ||
514 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
515 | .name = "PCM Playback Switch", | ||
516 | .info = ad1986a_pcm_amp_sw_info, | ||
517 | .get = ad1986a_pcm_amp_sw_get, | ||
518 | .put = ad1986a_pcm_amp_sw_put, | ||
519 | .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT) | ||
520 | }, | ||
521 | HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | 452 | HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT), |
522 | HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | 453 | HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), |
523 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT), | 454 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT), |
@@ -569,13 +500,30 @@ static struct snd_kcontrol_new ad1986a_3st_mixers[] = { | |||
569 | /* laptop model - 2ch only */ | 500 | /* laptop model - 2ch only */ |
570 | static hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC }; | 501 | static hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC }; |
571 | 502 | ||
503 | /* master controls both pins 0x1a and 0x1b */ | ||
504 | static struct hda_bind_ctls ad1986a_laptop_master_vol = { | ||
505 | .ops = &snd_hda_bind_vol, | ||
506 | .values = { | ||
507 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), | ||
508 | HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), | ||
509 | 0, | ||
510 | }, | ||
511 | }; | ||
512 | |||
513 | static struct hda_bind_ctls ad1986a_laptop_master_sw = { | ||
514 | .ops = &snd_hda_bind_sw, | ||
515 | .values = { | ||
516 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), | ||
517 | HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), | ||
518 | 0, | ||
519 | }, | ||
520 | }; | ||
521 | |||
572 | static struct snd_kcontrol_new ad1986a_laptop_mixers[] = { | 522 | static struct snd_kcontrol_new ad1986a_laptop_mixers[] = { |
573 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), | 523 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), |
574 | HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), | 524 | HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), |
575 | HDA_CODEC_VOLUME("Master Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | 525 | HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), |
576 | HDA_CODEC_MUTE("Master Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | 526 | HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), |
577 | /* HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT), | ||
578 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT), */ | ||
579 | HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT), | 527 | HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT), |
580 | HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT), | 528 | HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT), |
581 | HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT), | 529 | HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT), |
@@ -603,68 +551,114 @@ static struct snd_kcontrol_new ad1986a_laptop_mixers[] = { | |||
603 | 551 | ||
604 | /* laptop-eapd model - 2ch only */ | 552 | /* laptop-eapd model - 2ch only */ |
605 | 553 | ||
606 | /* master controls both pins 0x1a and 0x1b */ | 554 | static struct hda_input_mux ad1986a_laptop_eapd_capture_source = { |
607 | static int ad1986a_laptop_master_vol_put(struct snd_kcontrol *kcontrol, | 555 | .num_items = 3, |
608 | struct snd_ctl_elem_value *ucontrol) | 556 | .items = { |
557 | { "Mic", 0x0 }, | ||
558 | { "Internal Mic", 0x4 }, | ||
559 | { "Mix", 0x5 }, | ||
560 | }, | ||
561 | }; | ||
562 | |||
563 | static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { | ||
564 | HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), | ||
565 | HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), | ||
566 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
567 | HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), | ||
568 | HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x0, HDA_OUTPUT), | ||
569 | HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x0, HDA_OUTPUT), | ||
570 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
571 | HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||
572 | HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), | ||
573 | HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), | ||
574 | HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), | ||
575 | { | ||
576 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
577 | .name = "Capture Source", | ||
578 | .info = ad198x_mux_enum_info, | ||
579 | .get = ad198x_mux_enum_get, | ||
580 | .put = ad198x_mux_enum_put, | ||
581 | }, | ||
582 | { | ||
583 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
584 | .name = "External Amplifier", | ||
585 | .info = ad198x_eapd_info, | ||
586 | .get = ad198x_eapd_get, | ||
587 | .put = ad198x_eapd_put, | ||
588 | .private_value = 0x1b | (1 << 8), /* port-D, inversed */ | ||
589 | }, | ||
590 | { } /* end */ | ||
591 | }; | ||
592 | |||
593 | /* laptop-automute - 2ch only */ | ||
594 | |||
595 | static void ad1986a_update_hp(struct hda_codec *codec) | ||
609 | { | 596 | { |
610 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 597 | struct ad198x_spec *spec = codec->spec; |
611 | long *valp = ucontrol->value.integer.value; | 598 | unsigned int mute; |
612 | int change; | ||
613 | 599 | ||
614 | change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0, | 600 | if (spec->jack_present) |
615 | 0x7f, valp[0] & 0x7f); | 601 | mute = HDA_AMP_MUTE; /* mute internal speaker */ |
616 | change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, | 602 | else |
617 | 0x7f, valp[1] & 0x7f); | 603 | /* unmute internal speaker if necessary */ |
618 | snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, | 604 | mute = snd_hda_codec_amp_read(codec, 0x1a, 0, HDA_OUTPUT, 0); |
619 | 0x7f, valp[0] & 0x7f); | 605 | snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, |
620 | snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, | 606 | HDA_AMP_MUTE, mute); |
621 | 0x7f, valp[1] & 0x7f); | ||
622 | return change; | ||
623 | } | 607 | } |
624 | 608 | ||
625 | static int ad1986a_laptop_master_sw_put(struct snd_kcontrol *kcontrol, | 609 | static void ad1986a_hp_automute(struct hda_codec *codec) |
626 | struct snd_ctl_elem_value *ucontrol) | 610 | { |
611 | struct ad198x_spec *spec = codec->spec; | ||
612 | unsigned int present; | ||
613 | |||
614 | present = snd_hda_codec_read(codec, 0x1a, 0, AC_VERB_GET_PIN_SENSE, 0); | ||
615 | spec->jack_present = (present & 0x80000000) != 0; | ||
616 | ad1986a_update_hp(codec); | ||
617 | } | ||
618 | |||
619 | #define AD1986A_HP_EVENT 0x37 | ||
620 | |||
621 | static void ad1986a_hp_unsol_event(struct hda_codec *codec, unsigned int res) | ||
622 | { | ||
623 | if ((res >> 26) != AD1986A_HP_EVENT) | ||
624 | return; | ||
625 | ad1986a_hp_automute(codec); | ||
626 | } | ||
627 | |||
628 | static int ad1986a_hp_init(struct hda_codec *codec) | ||
629 | { | ||
630 | ad198x_init(codec); | ||
631 | ad1986a_hp_automute(codec); | ||
632 | return 0; | ||
633 | } | ||
634 | |||
635 | /* bind hp and internal speaker mute (with plug check) */ | ||
636 | static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol, | ||
637 | struct snd_ctl_elem_value *ucontrol) | ||
627 | { | 638 | { |
628 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 639 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
629 | long *valp = ucontrol->value.integer.value; | 640 | long *valp = ucontrol->value.integer.value; |
630 | int change; | 641 | int change; |
631 | 642 | ||
632 | change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0, | 643 | change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0, |
633 | 0x80, valp[0] ? 0 : 0x80); | 644 | HDA_AMP_MUTE, |
645 | valp[0] ? 0 : HDA_AMP_MUTE); | ||
634 | change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, | 646 | change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, |
635 | 0x80, valp[1] ? 0 : 0x80); | 647 | HDA_AMP_MUTE, |
636 | snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, | 648 | valp[1] ? 0 : HDA_AMP_MUTE); |
637 | 0x80, valp[0] ? 0 : 0x80); | 649 | if (change) |
638 | snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, | 650 | ad1986a_update_hp(codec); |
639 | 0x80, valp[1] ? 0 : 0x80); | ||
640 | return change; | 651 | return change; |
641 | } | 652 | } |
642 | 653 | ||
643 | static struct hda_input_mux ad1986a_laptop_eapd_capture_source = { | 654 | static struct snd_kcontrol_new ad1986a_laptop_automute_mixers[] = { |
644 | .num_items = 3, | 655 | HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), |
645 | .items = { | ||
646 | { "Mic", 0x0 }, | ||
647 | { "Internal Mic", 0x4 }, | ||
648 | { "Mix", 0x5 }, | ||
649 | }, | ||
650 | }; | ||
651 | |||
652 | static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { | ||
653 | { | ||
654 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
655 | .name = "Master Playback Volume", | ||
656 | .info = snd_hda_mixer_amp_volume_info, | ||
657 | .get = snd_hda_mixer_amp_volume_get, | ||
658 | .put = ad1986a_laptop_master_vol_put, | ||
659 | .tlv = { .c = snd_hda_mixer_amp_tlv }, | ||
660 | .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), | ||
661 | }, | ||
662 | { | 656 | { |
663 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 657 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
664 | .name = "Master Playback Switch", | 658 | .name = "Master Playback Switch", |
665 | .info = snd_hda_mixer_amp_switch_info, | 659 | .info = snd_hda_mixer_amp_switch_info, |
666 | .get = snd_hda_mixer_amp_switch_get, | 660 | .get = snd_hda_mixer_amp_switch_get, |
667 | .put = ad1986a_laptop_master_sw_put, | 661 | .put = ad1986a_hp_master_sw_put, |
668 | .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), | 662 | .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), |
669 | }, | 663 | }, |
670 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), | 664 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), |
@@ -674,6 +668,8 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { | |||
674 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), | 668 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), |
675 | HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), | 669 | HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), |
676 | HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), | 670 | HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), |
671 | HDA_CODEC_VOLUME("Beep Playback Volume", 0x18, 0x0, HDA_OUTPUT), | ||
672 | HDA_CODEC_MUTE("Beep Playback Switch", 0x18, 0x0, HDA_OUTPUT), | ||
677 | HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), | 673 | HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), |
678 | HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), | 674 | HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), |
679 | { | 675 | { |
@@ -807,12 +803,20 @@ static struct hda_verb ad1986a_ultra_init[] = { | |||
807 | { } /* end */ | 803 | { } /* end */ |
808 | }; | 804 | }; |
809 | 805 | ||
806 | /* pin sensing on HP jack */ | ||
807 | static struct hda_verb ad1986a_hp_init_verbs[] = { | ||
808 | {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT}, | ||
809 | {} | ||
810 | }; | ||
811 | |||
812 | |||
810 | /* models */ | 813 | /* models */ |
811 | enum { | 814 | enum { |
812 | AD1986A_6STACK, | 815 | AD1986A_6STACK, |
813 | AD1986A_3STACK, | 816 | AD1986A_3STACK, |
814 | AD1986A_LAPTOP, | 817 | AD1986A_LAPTOP, |
815 | AD1986A_LAPTOP_EAPD, | 818 | AD1986A_LAPTOP_EAPD, |
819 | AD1986A_LAPTOP_AUTOMUTE, | ||
816 | AD1986A_ULTRA, | 820 | AD1986A_ULTRA, |
817 | AD1986A_MODELS | 821 | AD1986A_MODELS |
818 | }; | 822 | }; |
@@ -822,6 +826,7 @@ static const char *ad1986a_models[AD1986A_MODELS] = { | |||
822 | [AD1986A_3STACK] = "3stack", | 826 | [AD1986A_3STACK] = "3stack", |
823 | [AD1986A_LAPTOP] = "laptop", | 827 | [AD1986A_LAPTOP] = "laptop", |
824 | [AD1986A_LAPTOP_EAPD] = "laptop-eapd", | 828 | [AD1986A_LAPTOP_EAPD] = "laptop-eapd", |
829 | [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute", | ||
825 | [AD1986A_ULTRA] = "ultra", | 830 | [AD1986A_ULTRA] = "ultra", |
826 | }; | 831 | }; |
827 | 832 | ||
@@ -850,11 +855,22 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = { | |||
850 | SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA), | 855 | SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA), |
851 | SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), | 856 | SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), |
852 | SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK), | 857 | SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK), |
853 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_EAPD), | 858 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE), |
854 | SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP), | 859 | SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP), |
855 | {} | 860 | {} |
856 | }; | 861 | }; |
857 | 862 | ||
863 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
864 | static struct hda_amp_list ad1986a_loopbacks[] = { | ||
865 | { 0x13, HDA_OUTPUT, 0 }, /* Mic */ | ||
866 | { 0x14, HDA_OUTPUT, 0 }, /* Phone */ | ||
867 | { 0x15, HDA_OUTPUT, 0 }, /* CD */ | ||
868 | { 0x16, HDA_OUTPUT, 0 }, /* Aux */ | ||
869 | { 0x17, HDA_OUTPUT, 0 }, /* Line */ | ||
870 | { } /* end */ | ||
871 | }; | ||
872 | #endif | ||
873 | |||
858 | static int patch_ad1986a(struct hda_codec *codec) | 874 | static int patch_ad1986a(struct hda_codec *codec) |
859 | { | 875 | { |
860 | struct ad198x_spec *spec; | 876 | struct ad198x_spec *spec; |
@@ -864,7 +880,6 @@ static int patch_ad1986a(struct hda_codec *codec) | |||
864 | if (spec == NULL) | 880 | if (spec == NULL) |
865 | return -ENOMEM; | 881 | return -ENOMEM; |
866 | 882 | ||
867 | mutex_init(&spec->amp_mutex); | ||
868 | codec->spec = spec; | 883 | codec->spec = spec; |
869 | 884 | ||
870 | spec->multiout.max_channels = 6; | 885 | spec->multiout.max_channels = 6; |
@@ -879,6 +894,9 @@ static int patch_ad1986a(struct hda_codec *codec) | |||
879 | spec->mixers[0] = ad1986a_mixers; | 894 | spec->mixers[0] = ad1986a_mixers; |
880 | spec->num_init_verbs = 1; | 895 | spec->num_init_verbs = 1; |
881 | spec->init_verbs[0] = ad1986a_init_verbs; | 896 | spec->init_verbs[0] = ad1986a_init_verbs; |
897 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
898 | spec->loopback.amplist = ad1986a_loopbacks; | ||
899 | #endif | ||
882 | 900 | ||
883 | codec->patch_ops = ad198x_patch_ops; | 901 | codec->patch_ops = ad198x_patch_ops; |
884 | 902 | ||
@@ -914,6 +932,19 @@ static int patch_ad1986a(struct hda_codec *codec) | |||
914 | spec->multiout.dig_out_nid = 0; | 932 | spec->multiout.dig_out_nid = 0; |
915 | spec->input_mux = &ad1986a_laptop_eapd_capture_source; | 933 | spec->input_mux = &ad1986a_laptop_eapd_capture_source; |
916 | break; | 934 | break; |
935 | case AD1986A_LAPTOP_AUTOMUTE: | ||
936 | spec->mixers[0] = ad1986a_laptop_automute_mixers; | ||
937 | spec->num_init_verbs = 3; | ||
938 | spec->init_verbs[1] = ad1986a_eapd_init_verbs; | ||
939 | spec->init_verbs[2] = ad1986a_hp_init_verbs; | ||
940 | spec->multiout.max_channels = 2; | ||
941 | spec->multiout.num_dacs = 1; | ||
942 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | ||
943 | spec->multiout.dig_out_nid = 0; | ||
944 | spec->input_mux = &ad1986a_laptop_eapd_capture_source; | ||
945 | codec->patch_ops.unsol_event = ad1986a_hp_unsol_event; | ||
946 | codec->patch_ops.init = ad1986a_hp_init; | ||
947 | break; | ||
917 | case AD1986A_ULTRA: | 948 | case AD1986A_ULTRA: |
918 | spec->mixers[0] = ad1986a_laptop_eapd_mixers; | 949 | spec->mixers[0] = ad1986a_laptop_eapd_mixers; |
919 | spec->num_init_verbs = 2; | 950 | spec->num_init_verbs = 2; |
@@ -982,8 +1013,9 @@ static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
982 | 1013 | ||
983 | if (spec->spdif_route != ucontrol->value.enumerated.item[0]) { | 1014 | if (spec->spdif_route != ucontrol->value.enumerated.item[0]) { |
984 | spec->spdif_route = ucontrol->value.enumerated.item[0]; | 1015 | spec->spdif_route = ucontrol->value.enumerated.item[0]; |
985 | snd_hda_codec_write(codec, spec->multiout.dig_out_nid, 0, | 1016 | snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0, |
986 | AC_VERB_SET_CONNECT_SEL, spec->spdif_route); | 1017 | AC_VERB_SET_CONNECT_SEL, |
1018 | spec->spdif_route); | ||
987 | return 1; | 1019 | return 1; |
988 | } | 1020 | } |
989 | return 0; | 1021 | return 0; |
@@ -1063,6 +1095,13 @@ static struct hda_verb ad1983_init_verbs[] = { | |||
1063 | { } /* end */ | 1095 | { } /* end */ |
1064 | }; | 1096 | }; |
1065 | 1097 | ||
1098 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1099 | static struct hda_amp_list ad1983_loopbacks[] = { | ||
1100 | { 0x12, HDA_OUTPUT, 0 }, /* Mic */ | ||
1101 | { 0x13, HDA_OUTPUT, 0 }, /* Line */ | ||
1102 | { } /* end */ | ||
1103 | }; | ||
1104 | #endif | ||
1066 | 1105 | ||
1067 | static int patch_ad1983(struct hda_codec *codec) | 1106 | static int patch_ad1983(struct hda_codec *codec) |
1068 | { | 1107 | { |
@@ -1072,7 +1111,6 @@ static int patch_ad1983(struct hda_codec *codec) | |||
1072 | if (spec == NULL) | 1111 | if (spec == NULL) |
1073 | return -ENOMEM; | 1112 | return -ENOMEM; |
1074 | 1113 | ||
1075 | mutex_init(&spec->amp_mutex); | ||
1076 | codec->spec = spec; | 1114 | codec->spec = spec; |
1077 | 1115 | ||
1078 | spec->multiout.max_channels = 2; | 1116 | spec->multiout.max_channels = 2; |
@@ -1088,6 +1126,9 @@ static int patch_ad1983(struct hda_codec *codec) | |||
1088 | spec->num_init_verbs = 1; | 1126 | spec->num_init_verbs = 1; |
1089 | spec->init_verbs[0] = ad1983_init_verbs; | 1127 | spec->init_verbs[0] = ad1983_init_verbs; |
1090 | spec->spdif_route = 0; | 1128 | spec->spdif_route = 0; |
1129 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1130 | spec->loopback.amplist = ad1983_loopbacks; | ||
1131 | #endif | ||
1091 | 1132 | ||
1092 | codec->patch_ops = ad198x_patch_ops; | 1133 | codec->patch_ops = ad198x_patch_ops; |
1093 | 1134 | ||
@@ -1211,6 +1252,17 @@ static struct hda_verb ad1981_init_verbs[] = { | |||
1211 | { } /* end */ | 1252 | { } /* end */ |
1212 | }; | 1253 | }; |
1213 | 1254 | ||
1255 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1256 | static struct hda_amp_list ad1981_loopbacks[] = { | ||
1257 | { 0x12, HDA_OUTPUT, 0 }, /* Front Mic */ | ||
1258 | { 0x13, HDA_OUTPUT, 0 }, /* Line */ | ||
1259 | { 0x1b, HDA_OUTPUT, 0 }, /* Aux */ | ||
1260 | { 0x1c, HDA_OUTPUT, 0 }, /* Mic */ | ||
1261 | { 0x1d, HDA_OUTPUT, 0 }, /* CD */ | ||
1262 | { } /* end */ | ||
1263 | }; | ||
1264 | #endif | ||
1265 | |||
1214 | /* | 1266 | /* |
1215 | * Patch for HP nx6320 | 1267 | * Patch for HP nx6320 |
1216 | * | 1268 | * |
@@ -1240,31 +1292,21 @@ static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol, | |||
1240 | return 0; | 1292 | return 0; |
1241 | 1293 | ||
1242 | /* toggle HP mute appropriately */ | 1294 | /* toggle HP mute appropriately */ |
1243 | snd_hda_codec_amp_update(codec, 0x06, 0, HDA_OUTPUT, 0, | 1295 | snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0, |
1244 | 0x80, spec->cur_eapd ? 0 : 0x80); | 1296 | HDA_AMP_MUTE, |
1245 | snd_hda_codec_amp_update(codec, 0x06, 1, HDA_OUTPUT, 0, | 1297 | spec->cur_eapd ? 0 : HDA_AMP_MUTE); |
1246 | 0x80, spec->cur_eapd ? 0 : 0x80); | ||
1247 | return 1; | 1298 | return 1; |
1248 | } | 1299 | } |
1249 | 1300 | ||
1250 | /* bind volumes of both NID 0x05 and 0x06 */ | 1301 | /* bind volumes of both NID 0x05 and 0x06 */ |
1251 | static int ad1981_hp_master_vol_put(struct snd_kcontrol *kcontrol, | 1302 | static struct hda_bind_ctls ad1981_hp_bind_master_vol = { |
1252 | struct snd_ctl_elem_value *ucontrol) | 1303 | .ops = &snd_hda_bind_vol, |
1253 | { | 1304 | .values = { |
1254 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 1305 | HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), |
1255 | long *valp = ucontrol->value.integer.value; | 1306 | HDA_COMPOSE_AMP_VAL(0x06, 3, 0, HDA_OUTPUT), |
1256 | int change; | 1307 | 0 |
1257 | 1308 | }, | |
1258 | change = snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, | 1309 | }; |
1259 | 0x7f, valp[0] & 0x7f); | ||
1260 | change |= snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, | ||
1261 | 0x7f, valp[1] & 0x7f); | ||
1262 | snd_hda_codec_amp_update(codec, 0x06, 0, HDA_OUTPUT, 0, | ||
1263 | 0x7f, valp[0] & 0x7f); | ||
1264 | snd_hda_codec_amp_update(codec, 0x06, 1, HDA_OUTPUT, 0, | ||
1265 | 0x7f, valp[1] & 0x7f); | ||
1266 | return change; | ||
1267 | } | ||
1268 | 1310 | ||
1269 | /* mute internal speaker if HP is plugged */ | 1311 | /* mute internal speaker if HP is plugged */ |
1270 | static void ad1981_hp_automute(struct hda_codec *codec) | 1312 | static void ad1981_hp_automute(struct hda_codec *codec) |
@@ -1273,10 +1315,8 @@ static void ad1981_hp_automute(struct hda_codec *codec) | |||
1273 | 1315 | ||
1274 | present = snd_hda_codec_read(codec, 0x06, 0, | 1316 | present = snd_hda_codec_read(codec, 0x06, 0, |
1275 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 1317 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; |
1276 | snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, | 1318 | snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0, |
1277 | 0x80, present ? 0x80 : 0); | 1319 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); |
1278 | snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, | ||
1279 | 0x80, present ? 0x80 : 0); | ||
1280 | } | 1320 | } |
1281 | 1321 | ||
1282 | /* toggle input of built-in and mic jack appropriately */ | 1322 | /* toggle input of built-in and mic jack appropriately */ |
@@ -1327,14 +1367,7 @@ static struct hda_input_mux ad1981_hp_capture_source = { | |||
1327 | }; | 1367 | }; |
1328 | 1368 | ||
1329 | static struct snd_kcontrol_new ad1981_hp_mixers[] = { | 1369 | static struct snd_kcontrol_new ad1981_hp_mixers[] = { |
1330 | { | 1370 | HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol), |
1331 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1332 | .name = "Master Playback Volume", | ||
1333 | .info = snd_hda_mixer_amp_volume_info, | ||
1334 | .get = snd_hda_mixer_amp_volume_get, | ||
1335 | .put = ad1981_hp_master_vol_put, | ||
1336 | .private_value = HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), | ||
1337 | }, | ||
1338 | { | 1371 | { |
1339 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1372 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1340 | .name = "Master Playback Switch", | 1373 | .name = "Master Playback Switch", |
@@ -1474,7 +1507,6 @@ static int patch_ad1981(struct hda_codec *codec) | |||
1474 | if (spec == NULL) | 1507 | if (spec == NULL) |
1475 | return -ENOMEM; | 1508 | return -ENOMEM; |
1476 | 1509 | ||
1477 | mutex_init(&spec->amp_mutex); | ||
1478 | codec->spec = spec; | 1510 | codec->spec = spec; |
1479 | 1511 | ||
1480 | spec->multiout.max_channels = 2; | 1512 | spec->multiout.max_channels = 2; |
@@ -1490,6 +1522,9 @@ static int patch_ad1981(struct hda_codec *codec) | |||
1490 | spec->num_init_verbs = 1; | 1522 | spec->num_init_verbs = 1; |
1491 | spec->init_verbs[0] = ad1981_init_verbs; | 1523 | spec->init_verbs[0] = ad1981_init_verbs; |
1492 | spec->spdif_route = 0; | 1524 | spec->spdif_route = 0; |
1525 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1526 | spec->loopback.amplist = ad1981_loopbacks; | ||
1527 | #endif | ||
1493 | 1528 | ||
1494 | codec->patch_ops = ad198x_patch_ops; | 1529 | codec->patch_ops = ad198x_patch_ops; |
1495 | 1530 | ||
@@ -1897,16 +1932,19 @@ static int ad1988_spdif_playback_source_get(struct snd_kcontrol *kcontrol, | |||
1897 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 1932 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
1898 | unsigned int sel; | 1933 | unsigned int sel; |
1899 | 1934 | ||
1900 | sel = snd_hda_codec_read(codec, 0x02, 0, AC_VERB_GET_CONNECT_SEL, 0); | 1935 | sel = snd_hda_codec_read(codec, 0x1d, 0, AC_VERB_GET_AMP_GAIN_MUTE, |
1901 | if (sel > 0) { | 1936 | AC_AMP_GET_INPUT); |
1937 | if (!(sel & 0x80)) | ||
1938 | ucontrol->value.enumerated.item[0] = 0; | ||
1939 | else { | ||
1902 | sel = snd_hda_codec_read(codec, 0x0b, 0, | 1940 | sel = snd_hda_codec_read(codec, 0x0b, 0, |
1903 | AC_VERB_GET_CONNECT_SEL, 0); | 1941 | AC_VERB_GET_CONNECT_SEL, 0); |
1904 | if (sel < 3) | 1942 | if (sel < 3) |
1905 | sel++; | 1943 | sel++; |
1906 | else | 1944 | else |
1907 | sel = 0; | 1945 | sel = 0; |
1946 | ucontrol->value.enumerated.item[0] = sel; | ||
1908 | } | 1947 | } |
1909 | ucontrol->value.enumerated.item[0] = sel; | ||
1910 | return 0; | 1948 | return 0; |
1911 | } | 1949 | } |
1912 | 1950 | ||
@@ -1918,23 +1956,39 @@ static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol, | |||
1918 | int change; | 1956 | int change; |
1919 | 1957 | ||
1920 | val = ucontrol->value.enumerated.item[0]; | 1958 | val = ucontrol->value.enumerated.item[0]; |
1921 | sel = snd_hda_codec_read(codec, 0x02, 0, AC_VERB_GET_CONNECT_SEL, 0); | ||
1922 | if (!val) { | 1959 | if (!val) { |
1923 | change = sel != 0; | 1960 | sel = snd_hda_codec_read(codec, 0x1d, 0, |
1924 | if (change || codec->in_resume) | 1961 | AC_VERB_GET_AMP_GAIN_MUTE, |
1925 | snd_hda_codec_write(codec, 0x02, 0, | 1962 | AC_AMP_GET_INPUT); |
1926 | AC_VERB_SET_CONNECT_SEL, 0); | 1963 | change = sel & 0x80; |
1964 | if (change) { | ||
1965 | snd_hda_codec_write_cache(codec, 0x1d, 0, | ||
1966 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
1967 | AMP_IN_UNMUTE(0)); | ||
1968 | snd_hda_codec_write_cache(codec, 0x1d, 0, | ||
1969 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
1970 | AMP_IN_MUTE(1)); | ||
1971 | } | ||
1927 | } else { | 1972 | } else { |
1928 | change = sel == 0; | 1973 | sel = snd_hda_codec_read(codec, 0x1d, 0, |
1929 | if (change || codec->in_resume) | 1974 | AC_VERB_GET_AMP_GAIN_MUTE, |
1930 | snd_hda_codec_write(codec, 0x02, 0, | 1975 | AC_AMP_GET_INPUT | 0x01); |
1931 | AC_VERB_SET_CONNECT_SEL, 1); | 1976 | change = sel & 0x80; |
1977 | if (change) { | ||
1978 | snd_hda_codec_write_cache(codec, 0x1d, 0, | ||
1979 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
1980 | AMP_IN_MUTE(0)); | ||
1981 | snd_hda_codec_write_cache(codec, 0x1d, 0, | ||
1982 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
1983 | AMP_IN_UNMUTE(1)); | ||
1984 | } | ||
1932 | sel = snd_hda_codec_read(codec, 0x0b, 0, | 1985 | sel = snd_hda_codec_read(codec, 0x0b, 0, |
1933 | AC_VERB_GET_CONNECT_SEL, 0) + 1; | 1986 | AC_VERB_GET_CONNECT_SEL, 0) + 1; |
1934 | change |= sel != val; | 1987 | change |= sel != val; |
1935 | if (change || codec->in_resume) | 1988 | if (change) |
1936 | snd_hda_codec_write(codec, 0x0b, 0, | 1989 | snd_hda_codec_write_cache(codec, 0x0b, 0, |
1937 | AC_VERB_SET_CONNECT_SEL, val - 1); | 1990 | AC_VERB_SET_CONNECT_SEL, |
1991 | val - 1); | ||
1938 | } | 1992 | } |
1939 | return change; | 1993 | return change; |
1940 | } | 1994 | } |
@@ -2047,10 +2101,9 @@ static struct hda_verb ad1988_spdif_init_verbs[] = { | |||
2047 | {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */ | 2101 | {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */ |
2048 | {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */ | 2102 | {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */ |
2049 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 2103 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
2050 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 2104 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
2051 | /* SPDIF out pin */ | 2105 | /* SPDIF out pin */ |
2052 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | 2106 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ |
2053 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x17}, /* 0dB */ | ||
2054 | 2107 | ||
2055 | { } | 2108 | { } |
2056 | }; | 2109 | }; |
@@ -2225,6 +2278,15 @@ static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res) | |||
2225 | snd_hda_sequence_write(codec, ad1988_laptop_hp_off); | 2278 | snd_hda_sequence_write(codec, ad1988_laptop_hp_off); |
2226 | } | 2279 | } |
2227 | 2280 | ||
2281 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
2282 | static struct hda_amp_list ad1988_loopbacks[] = { | ||
2283 | { 0x20, HDA_INPUT, 0 }, /* Front Mic */ | ||
2284 | { 0x20, HDA_INPUT, 1 }, /* Line */ | ||
2285 | { 0x20, HDA_INPUT, 4 }, /* Mic */ | ||
2286 | { 0x20, HDA_INPUT, 6 }, /* CD */ | ||
2287 | { } /* end */ | ||
2288 | }; | ||
2289 | #endif | ||
2228 | 2290 | ||
2229 | /* | 2291 | /* |
2230 | * Automatic parse of I/O pins from the BIOS configuration | 2292 | * Automatic parse of I/O pins from the BIOS configuration |
@@ -2663,7 +2725,6 @@ static int patch_ad1988(struct hda_codec *codec) | |||
2663 | if (spec == NULL) | 2725 | if (spec == NULL) |
2664 | return -ENOMEM; | 2726 | return -ENOMEM; |
2665 | 2727 | ||
2666 | mutex_init(&spec->amp_mutex); | ||
2667 | codec->spec = spec; | 2728 | codec->spec = spec; |
2668 | 2729 | ||
2669 | if (is_rev2(codec)) | 2730 | if (is_rev2(codec)) |
@@ -2770,6 +2831,9 @@ static int patch_ad1988(struct hda_codec *codec) | |||
2770 | codec->patch_ops.unsol_event = ad1988_laptop_unsol_event; | 2831 | codec->patch_ops.unsol_event = ad1988_laptop_unsol_event; |
2771 | break; | 2832 | break; |
2772 | } | 2833 | } |
2834 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
2835 | spec->loopback.amplist = ad1988_loopbacks; | ||
2836 | #endif | ||
2773 | 2837 | ||
2774 | return 0; | 2838 | return 0; |
2775 | } | 2839 | } |
@@ -2926,6 +2990,16 @@ static struct hda_verb ad1884_init_verbs[] = { | |||
2926 | { } /* end */ | 2990 | { } /* end */ |
2927 | }; | 2991 | }; |
2928 | 2992 | ||
2993 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
2994 | static struct hda_amp_list ad1884_loopbacks[] = { | ||
2995 | { 0x20, HDA_INPUT, 0 }, /* Front Mic */ | ||
2996 | { 0x20, HDA_INPUT, 1 }, /* Mic */ | ||
2997 | { 0x20, HDA_INPUT, 2 }, /* CD */ | ||
2998 | { 0x20, HDA_INPUT, 4 }, /* Docking */ | ||
2999 | { } /* end */ | ||
3000 | }; | ||
3001 | #endif | ||
3002 | |||
2929 | static int patch_ad1884(struct hda_codec *codec) | 3003 | static int patch_ad1884(struct hda_codec *codec) |
2930 | { | 3004 | { |
2931 | struct ad198x_spec *spec; | 3005 | struct ad198x_spec *spec; |
@@ -2950,6 +3024,9 @@ static int patch_ad1884(struct hda_codec *codec) | |||
2950 | spec->num_init_verbs = 1; | 3024 | spec->num_init_verbs = 1; |
2951 | spec->init_verbs[0] = ad1884_init_verbs; | 3025 | spec->init_verbs[0] = ad1884_init_verbs; |
2952 | spec->spdif_route = 0; | 3026 | spec->spdif_route = 0; |
3027 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
3028 | spec->loopback.amplist = ad1884_loopbacks; | ||
3029 | #endif | ||
2953 | 3030 | ||
2954 | codec->patch_ops = ad198x_patch_ops; | 3031 | codec->patch_ops = ad198x_patch_ops; |
2955 | 3032 | ||
@@ -3331,6 +3408,16 @@ static struct hda_verb ad1882_init_verbs[] = { | |||
3331 | { } /* end */ | 3408 | { } /* end */ |
3332 | }; | 3409 | }; |
3333 | 3410 | ||
3411 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
3412 | static struct hda_amp_list ad1882_loopbacks[] = { | ||
3413 | { 0x20, HDA_INPUT, 0 }, /* Front Mic */ | ||
3414 | { 0x20, HDA_INPUT, 1 }, /* Mic */ | ||
3415 | { 0x20, HDA_INPUT, 4 }, /* Line */ | ||
3416 | { 0x20, HDA_INPUT, 6 }, /* CD */ | ||
3417 | { } /* end */ | ||
3418 | }; | ||
3419 | #endif | ||
3420 | |||
3334 | /* models */ | 3421 | /* models */ |
3335 | enum { | 3422 | enum { |
3336 | AD1882_3STACK, | 3423 | AD1882_3STACK, |
@@ -3369,6 +3456,9 @@ static int patch_ad1882(struct hda_codec *codec) | |||
3369 | spec->num_init_verbs = 1; | 3456 | spec->num_init_verbs = 1; |
3370 | spec->init_verbs[0] = ad1882_init_verbs; | 3457 | spec->init_verbs[0] = ad1882_init_verbs; |
3371 | spec->spdif_route = 0; | 3458 | spec->spdif_route = 0; |
3459 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
3460 | spec->loopback.amplist = ad1882_loopbacks; | ||
3461 | #endif | ||
3372 | 3462 | ||
3373 | codec->patch_ops = ad198x_patch_ops; | 3463 | codec->patch_ops = ad198x_patch_ops; |
3374 | 3464 | ||
diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c index 72d3ab9751ac..fbb8969dc559 100644 --- a/sound/pci/hda/patch_atihdmi.c +++ b/sound/pci/hda/patch_atihdmi.c | |||
@@ -62,19 +62,6 @@ static int atihdmi_init(struct hda_codec *codec) | |||
62 | return 0; | 62 | return 0; |
63 | } | 63 | } |
64 | 64 | ||
65 | #ifdef CONFIG_PM | ||
66 | /* | ||
67 | * resume | ||
68 | */ | ||
69 | static int atihdmi_resume(struct hda_codec *codec) | ||
70 | { | ||
71 | atihdmi_init(codec); | ||
72 | snd_hda_resume_spdif_out(codec); | ||
73 | |||
74 | return 0; | ||
75 | } | ||
76 | #endif | ||
77 | |||
78 | /* | 65 | /* |
79 | * Digital out | 66 | * Digital out |
80 | */ | 67 | */ |
@@ -141,9 +128,6 @@ static struct hda_codec_ops atihdmi_patch_ops = { | |||
141 | .build_pcms = atihdmi_build_pcms, | 128 | .build_pcms = atihdmi_build_pcms, |
142 | .init = atihdmi_init, | 129 | .init = atihdmi_init, |
143 | .free = atihdmi_free, | 130 | .free = atihdmi_free, |
144 | #ifdef CONFIG_PM | ||
145 | .resume = atihdmi_resume, | ||
146 | #endif | ||
147 | }; | 131 | }; |
148 | 132 | ||
149 | static int patch_atihdmi(struct hda_codec *codec) | 133 | static int patch_atihdmi(struct hda_codec *codec) |
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 3c722e667bc8..2468f3171222 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c | |||
@@ -427,27 +427,6 @@ static int cmi9880_init(struct hda_codec *codec) | |||
427 | return 0; | 427 | return 0; |
428 | } | 428 | } |
429 | 429 | ||
430 | #ifdef CONFIG_PM | ||
431 | /* | ||
432 | * resume | ||
433 | */ | ||
434 | static int cmi9880_resume(struct hda_codec *codec) | ||
435 | { | ||
436 | struct cmi_spec *spec = codec->spec; | ||
437 | |||
438 | cmi9880_init(codec); | ||
439 | snd_hda_resume_ctls(codec, cmi9880_basic_mixer); | ||
440 | if (spec->channel_modes) | ||
441 | snd_hda_resume_ctls(codec, cmi9880_ch_mode_mixer); | ||
442 | if (spec->multiout.dig_out_nid) | ||
443 | snd_hda_resume_spdif_out(codec); | ||
444 | if (spec->dig_in_nid) | ||
445 | snd_hda_resume_spdif_in(codec); | ||
446 | |||
447 | return 0; | ||
448 | } | ||
449 | #endif | ||
450 | |||
451 | /* | 430 | /* |
452 | * Analog playback callbacks | 431 | * Analog playback callbacks |
453 | */ | 432 | */ |
@@ -635,9 +614,6 @@ static struct hda_codec_ops cmi9880_patch_ops = { | |||
635 | .build_pcms = cmi9880_build_pcms, | 614 | .build_pcms = cmi9880_build_pcms, |
636 | .init = cmi9880_init, | 615 | .init = cmi9880_init, |
637 | .free = cmi9880_free, | 616 | .free = cmi9880_free, |
638 | #ifdef CONFIG_PM | ||
639 | .resume = cmi9880_resume, | ||
640 | #endif | ||
641 | }; | 617 | }; |
642 | 618 | ||
643 | static int patch_cmi9880(struct hda_codec *codec) | 619 | static int patch_cmi9880(struct hda_codec *codec) |
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 4d8e8af5c819..080e3001d9c5 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -311,23 +311,6 @@ static void conexant_free(struct hda_codec *codec) | |||
311 | kfree(codec->spec); | 311 | kfree(codec->spec); |
312 | } | 312 | } |
313 | 313 | ||
314 | #ifdef CONFIG_PM | ||
315 | static int conexant_resume(struct hda_codec *codec) | ||
316 | { | ||
317 | struct conexant_spec *spec = codec->spec; | ||
318 | int i; | ||
319 | |||
320 | codec->patch_ops.init(codec); | ||
321 | for (i = 0; i < spec->num_mixers; i++) | ||
322 | snd_hda_resume_ctls(codec, spec->mixers[i]); | ||
323 | if (spec->multiout.dig_out_nid) | ||
324 | snd_hda_resume_spdif_out(codec); | ||
325 | if (spec->dig_in_nid) | ||
326 | snd_hda_resume_spdif_in(codec); | ||
327 | return 0; | ||
328 | } | ||
329 | #endif | ||
330 | |||
331 | static int conexant_build_controls(struct hda_codec *codec) | 314 | static int conexant_build_controls(struct hda_codec *codec) |
332 | { | 315 | { |
333 | struct conexant_spec *spec = codec->spec; | 316 | struct conexant_spec *spec = codec->spec; |
@@ -358,9 +341,6 @@ static struct hda_codec_ops conexant_patch_ops = { | |||
358 | .build_pcms = conexant_build_pcms, | 341 | .build_pcms = conexant_build_pcms, |
359 | .init = conexant_init, | 342 | .init = conexant_init, |
360 | .free = conexant_free, | 343 | .free = conexant_free, |
361 | #ifdef CONFIG_PM | ||
362 | .resume = conexant_resume, | ||
363 | #endif | ||
364 | }; | 344 | }; |
365 | 345 | ||
366 | /* | 346 | /* |
@@ -368,15 +348,7 @@ static struct hda_codec_ops conexant_patch_ops = { | |||
368 | * the private value = nid | (invert << 8) | 348 | * the private value = nid | (invert << 8) |
369 | */ | 349 | */ |
370 | 350 | ||
371 | static int cxt_eapd_info(struct snd_kcontrol *kcontrol, | 351 | #define cxt_eapd_info snd_ctl_boolean_mono_info |
372 | struct snd_ctl_elem_info *uinfo) | ||
373 | { | ||
374 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
375 | uinfo->count = 1; | ||
376 | uinfo->value.integer.min = 0; | ||
377 | uinfo->value.integer.max = 1; | ||
378 | return 0; | ||
379 | } | ||
380 | 352 | ||
381 | static int cxt_eapd_get(struct snd_kcontrol *kcontrol, | 353 | static int cxt_eapd_get(struct snd_kcontrol *kcontrol, |
382 | struct snd_ctl_elem_value *ucontrol) | 354 | struct snd_ctl_elem_value *ucontrol) |
@@ -404,13 +376,13 @@ static int cxt_eapd_put(struct snd_kcontrol *kcontrol, | |||
404 | eapd = ucontrol->value.integer.value[0]; | 376 | eapd = ucontrol->value.integer.value[0]; |
405 | if (invert) | 377 | if (invert) |
406 | eapd = !eapd; | 378 | eapd = !eapd; |
407 | if (eapd == spec->cur_eapd && !codec->in_resume) | 379 | if (eapd == spec->cur_eapd) |
408 | return 0; | 380 | return 0; |
409 | 381 | ||
410 | spec->cur_eapd = eapd; | 382 | spec->cur_eapd = eapd; |
411 | snd_hda_codec_write(codec, nid, | 383 | snd_hda_codec_write_cache(codec, nid, |
412 | 0, AC_VERB_SET_EAPD_BTLENABLE, | 384 | 0, AC_VERB_SET_EAPD_BTLENABLE, |
413 | eapd ? 0x02 : 0x00); | 385 | eapd ? 0x02 : 0x00); |
414 | return 1; | 386 | return 1; |
415 | } | 387 | } |
416 | 388 | ||
@@ -500,34 +472,25 @@ static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol, | |||
500 | /* toggle internal speakers mute depending of presence of | 472 | /* toggle internal speakers mute depending of presence of |
501 | * the headphone jack | 473 | * the headphone jack |
502 | */ | 474 | */ |
503 | bits = (!spec->hp_present && spec->cur_eapd) ? 0 : 0x80; | 475 | bits = (!spec->hp_present && spec->cur_eapd) ? 0 : HDA_AMP_MUTE; |
504 | snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0, 0x80, bits); | 476 | snd_hda_codec_amp_stereo(codec, 0x10, HDA_OUTPUT, 0, |
505 | snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0, 0x80, bits); | 477 | HDA_AMP_MUTE, bits); |
506 | 478 | ||
507 | bits = spec->cur_eapd ? 0 : 0x80; | 479 | bits = spec->cur_eapd ? 0 : HDA_AMP_MUTE; |
508 | snd_hda_codec_amp_update(codec, 0x11, 0, HDA_OUTPUT, 0, 0x80, bits); | 480 | snd_hda_codec_amp_stereo(codec, 0x11, HDA_OUTPUT, 0, |
509 | snd_hda_codec_amp_update(codec, 0x11, 1, HDA_OUTPUT, 0, 0x80, bits); | 481 | HDA_AMP_MUTE, bits); |
510 | return 1; | 482 | return 1; |
511 | } | 483 | } |
512 | 484 | ||
513 | /* bind volumes of both NID 0x10 and 0x11 */ | 485 | /* bind volumes of both NID 0x10 and 0x11 */ |
514 | static int cxt5045_hp_master_vol_put(struct snd_kcontrol *kcontrol, | 486 | static struct hda_bind_ctls cxt5045_hp_bind_master_vol = { |
515 | struct snd_ctl_elem_value *ucontrol) | 487 | .ops = &snd_hda_bind_vol, |
516 | { | 488 | .values = { |
517 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 489 | HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT), |
518 | long *valp = ucontrol->value.integer.value; | 490 | HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT), |
519 | int change; | 491 | 0 |
520 | 492 | }, | |
521 | change = snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0, | 493 | }; |
522 | 0x7f, valp[0] & 0x7f); | ||
523 | change |= snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0, | ||
524 | 0x7f, valp[1] & 0x7f); | ||
525 | snd_hda_codec_amp_update(codec, 0x11, 0, HDA_OUTPUT, 0, | ||
526 | 0x7f, valp[0] & 0x7f); | ||
527 | snd_hda_codec_amp_update(codec, 0x11, 1, HDA_OUTPUT, 0, | ||
528 | 0x7f, valp[1] & 0x7f); | ||
529 | return change; | ||
530 | } | ||
531 | 494 | ||
532 | /* toggle input of built-in and mic jack appropriately */ | 495 | /* toggle input of built-in and mic jack appropriately */ |
533 | static void cxt5045_hp_automic(struct hda_codec *codec) | 496 | static void cxt5045_hp_automic(struct hda_codec *codec) |
@@ -562,9 +525,9 @@ static void cxt5045_hp_automute(struct hda_codec *codec) | |||
562 | spec->hp_present = snd_hda_codec_read(codec, 0x11, 0, | 525 | spec->hp_present = snd_hda_codec_read(codec, 0x11, 0, |
563 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 526 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; |
564 | 527 | ||
565 | bits = (spec->hp_present || !spec->cur_eapd) ? 0x80 : 0; | 528 | bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0; |
566 | snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0, 0x80, bits); | 529 | snd_hda_codec_amp_stereo(codec, 0x10, HDA_OUTPUT, 0, |
567 | snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0, 0x80, bits); | 530 | HDA_AMP_MUTE, bits); |
568 | } | 531 | } |
569 | 532 | ||
570 | /* unsolicited event for HP jack sensing */ | 533 | /* unsolicited event for HP jack sensing */ |
@@ -595,14 +558,7 @@ static struct snd_kcontrol_new cxt5045_mixers[] = { | |||
595 | HDA_CODEC_MUTE("Int Mic Switch", 0x1a, 0x01, HDA_INPUT), | 558 | HDA_CODEC_MUTE("Int Mic Switch", 0x1a, 0x01, HDA_INPUT), |
596 | HDA_CODEC_VOLUME("Ext Mic Volume", 0x1a, 0x02, HDA_INPUT), | 559 | HDA_CODEC_VOLUME("Ext Mic Volume", 0x1a, 0x02, HDA_INPUT), |
597 | HDA_CODEC_MUTE("Ext Mic Switch", 0x1a, 0x02, HDA_INPUT), | 560 | HDA_CODEC_MUTE("Ext Mic Switch", 0x1a, 0x02, HDA_INPUT), |
598 | { | 561 | HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol), |
599 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
600 | .name = "Master Playback Volume", | ||
601 | .info = snd_hda_mixer_amp_volume_info, | ||
602 | .get = snd_hda_mixer_amp_volume_get, | ||
603 | .put = cxt5045_hp_master_vol_put, | ||
604 | .private_value = HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT), | ||
605 | }, | ||
606 | { | 562 | { |
607 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 563 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
608 | .name = "Master Playback Switch", | 564 | .name = "Master Playback Switch", |
@@ -915,33 +871,24 @@ static int cxt5047_hp_master_sw_put(struct snd_kcontrol *kcontrol, | |||
915 | /* toggle internal speakers mute depending of presence of | 871 | /* toggle internal speakers mute depending of presence of |
916 | * the headphone jack | 872 | * the headphone jack |
917 | */ | 873 | */ |
918 | bits = (!spec->hp_present && spec->cur_eapd) ? 0 : 0x80; | 874 | bits = (!spec->hp_present && spec->cur_eapd) ? 0 : HDA_AMP_MUTE; |
919 | snd_hda_codec_amp_update(codec, 0x1d, 0, HDA_OUTPUT, 0, 0x80, bits); | 875 | snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0, |
920 | snd_hda_codec_amp_update(codec, 0x1d, 1, HDA_OUTPUT, 0, 0x80, bits); | 876 | HDA_AMP_MUTE, bits); |
921 | bits = spec->cur_eapd ? 0 : 0x80; | 877 | bits = spec->cur_eapd ? 0 : HDA_AMP_MUTE; |
922 | snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0, 0x80, bits); | 878 | snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0, |
923 | snd_hda_codec_amp_update(codec, 0x13, 1, HDA_OUTPUT, 0, 0x80, bits); | 879 | HDA_AMP_MUTE, bits); |
924 | return 1; | 880 | return 1; |
925 | } | 881 | } |
926 | 882 | ||
927 | /* bind volumes of both NID 0x13 (Headphones) and 0x1d (Speakers) */ | 883 | /* bind volumes of both NID 0x13 (Headphones) and 0x1d (Speakers) */ |
928 | static int cxt5047_hp_master_vol_put(struct snd_kcontrol *kcontrol, | 884 | static struct hda_bind_ctls cxt5047_bind_master_vol = { |
929 | struct snd_ctl_elem_value *ucontrol) | 885 | .ops = &snd_hda_bind_vol, |
930 | { | 886 | .values = { |
931 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 887 | HDA_COMPOSE_AMP_VAL(0x13, 3, 0, HDA_OUTPUT), |
932 | long *valp = ucontrol->value.integer.value; | 888 | HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT), |
933 | int change; | 889 | 0 |
934 | 890 | }, | |
935 | change = snd_hda_codec_amp_update(codec, 0x1d, 0, HDA_OUTPUT, 0, | 891 | }; |
936 | 0x7f, valp[0] & 0x7f); | ||
937 | change |= snd_hda_codec_amp_update(codec, 0x1d, 1, HDA_OUTPUT, 0, | ||
938 | 0x7f, valp[1] & 0x7f); | ||
939 | snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0, | ||
940 | 0x7f, valp[0] & 0x7f); | ||
941 | snd_hda_codec_amp_update(codec, 0x13, 1, HDA_OUTPUT, 0, | ||
942 | 0x7f, valp[1] & 0x7f); | ||
943 | return change; | ||
944 | } | ||
945 | 892 | ||
946 | /* mute internal speaker if HP is plugged */ | 893 | /* mute internal speaker if HP is plugged */ |
947 | static void cxt5047_hp_automute(struct hda_codec *codec) | 894 | static void cxt5047_hp_automute(struct hda_codec *codec) |
@@ -952,12 +899,12 @@ static void cxt5047_hp_automute(struct hda_codec *codec) | |||
952 | spec->hp_present = snd_hda_codec_read(codec, 0x13, 0, | 899 | spec->hp_present = snd_hda_codec_read(codec, 0x13, 0, |
953 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 900 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; |
954 | 901 | ||
955 | bits = (spec->hp_present || !spec->cur_eapd) ? 0x80 : 0; | 902 | bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0; |
956 | snd_hda_codec_amp_update(codec, 0x1d, 0, HDA_OUTPUT, 0, 0x80, bits); | 903 | snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0, |
957 | snd_hda_codec_amp_update(codec, 0x1d, 1, HDA_OUTPUT, 0, 0x80, bits); | 904 | HDA_AMP_MUTE, bits); |
958 | /* Mute/Unmute PCM 2 for good measure - some systems need this */ | 905 | /* Mute/Unmute PCM 2 for good measure - some systems need this */ |
959 | snd_hda_codec_amp_update(codec, 0x1c, 0, HDA_OUTPUT, 0, 0x80, bits); | 906 | snd_hda_codec_amp_stereo(codec, 0x1c, HDA_OUTPUT, 0, |
960 | snd_hda_codec_amp_update(codec, 0x1c, 1, HDA_OUTPUT, 0, 0x80, bits); | 907 | HDA_AMP_MUTE, bits); |
961 | } | 908 | } |
962 | 909 | ||
963 | /* mute internal speaker if HP is plugged */ | 910 | /* mute internal speaker if HP is plugged */ |
@@ -969,12 +916,12 @@ static void cxt5047_hp2_automute(struct hda_codec *codec) | |||
969 | spec->hp_present = snd_hda_codec_read(codec, 0x13, 0, | 916 | spec->hp_present = snd_hda_codec_read(codec, 0x13, 0, |
970 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 917 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; |
971 | 918 | ||
972 | bits = spec->hp_present ? 0x80 : 0; | 919 | bits = spec->hp_present ? HDA_AMP_MUTE : 0; |
973 | snd_hda_codec_amp_update(codec, 0x1d, 0, HDA_OUTPUT, 0, 0x80, bits); | 920 | snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0, |
974 | snd_hda_codec_amp_update(codec, 0x1d, 1, HDA_OUTPUT, 0, 0x80, bits); | 921 | HDA_AMP_MUTE, bits); |
975 | /* Mute/Unmute PCM 2 for good measure - some systems need this */ | 922 | /* Mute/Unmute PCM 2 for good measure - some systems need this */ |
976 | snd_hda_codec_amp_update(codec, 0x1c, 0, HDA_OUTPUT, 0, 0x80, bits); | 923 | snd_hda_codec_amp_stereo(codec, 0x1c, HDA_OUTPUT, 0, |
977 | snd_hda_codec_amp_update(codec, 0x1c, 1, HDA_OUTPUT, 0, 0x80, bits); | 924 | HDA_AMP_MUTE, bits); |
978 | } | 925 | } |
979 | 926 | ||
980 | /* toggle input of built-in and mic jack appropriately */ | 927 | /* toggle input of built-in and mic jack appropriately */ |
@@ -1063,14 +1010,7 @@ static struct snd_kcontrol_new cxt5047_toshiba_mixers[] = { | |||
1063 | HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), | 1010 | HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), |
1064 | HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), | 1011 | HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), |
1065 | HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT), | 1012 | HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT), |
1066 | { | 1013 | HDA_BIND_VOL("Master Playback Volume", &cxt5047_bind_master_vol), |
1067 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1068 | .name = "Master Playback Volume", | ||
1069 | .info = snd_hda_mixer_amp_volume_info, | ||
1070 | .get = snd_hda_mixer_amp_volume_get, | ||
1071 | .put = cxt5047_hp_master_vol_put, | ||
1072 | .private_value = HDA_COMPOSE_AMP_VAL(0x13, 3, 0, HDA_OUTPUT), | ||
1073 | }, | ||
1074 | { | 1014 | { |
1075 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1015 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1076 | .name = "Master Playback Switch", | 1016 | .name = "Master Playback Switch", |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9a47eec5a27b..53b0428abfc2 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -102,6 +102,8 @@ enum { | |||
102 | /* ALC268 models */ | 102 | /* ALC268 models */ |
103 | enum { | 103 | enum { |
104 | ALC268_3ST, | 104 | ALC268_3ST, |
105 | ALC268_TOSHIBA, | ||
106 | ALC268_ACER, | ||
105 | ALC268_AUTO, | 107 | ALC268_AUTO, |
106 | ALC268_MODEL_LAST /* last tag */ | 108 | ALC268_MODEL_LAST /* last tag */ |
107 | }; | 109 | }; |
@@ -129,6 +131,7 @@ enum { | |||
129 | ALC861VD_6ST_DIG, | 131 | ALC861VD_6ST_DIG, |
130 | ALC861VD_LENOVO, | 132 | ALC861VD_LENOVO, |
131 | ALC861VD_DALLAS, | 133 | ALC861VD_DALLAS, |
134 | ALC861VD_HP, | ||
132 | ALC861VD_AUTO, | 135 | ALC861VD_AUTO, |
133 | ALC861VD_MODEL_LAST, | 136 | ALC861VD_MODEL_LAST, |
134 | }; | 137 | }; |
@@ -140,6 +143,7 @@ enum { | |||
140 | ALC662_3ST_6ch, | 143 | ALC662_3ST_6ch, |
141 | ALC662_5ST_DIG, | 144 | ALC662_5ST_DIG, |
142 | ALC662_LENOVO_101E, | 145 | ALC662_LENOVO_101E, |
146 | ALC662_ASUS_EEEPC_P701, | ||
143 | ALC662_AUTO, | 147 | ALC662_AUTO, |
144 | ALC662_MODEL_LAST, | 148 | ALC662_MODEL_LAST, |
145 | }; | 149 | }; |
@@ -152,7 +156,9 @@ enum { | |||
152 | ALC882_W2JC, | 156 | ALC882_W2JC, |
153 | ALC882_TARGA, | 157 | ALC882_TARGA, |
154 | ALC882_ASUS_A7J, | 158 | ALC882_ASUS_A7J, |
159 | ALC882_ASUS_A7M, | ||
155 | ALC885_MACPRO, | 160 | ALC885_MACPRO, |
161 | ALC885_MBP3, | ||
156 | ALC885_IMAC24, | 162 | ALC885_IMAC24, |
157 | ALC882_AUTO, | 163 | ALC882_AUTO, |
158 | ALC882_MODEL_LAST, | 164 | ALC882_MODEL_LAST, |
@@ -167,12 +173,14 @@ enum { | |||
167 | ALC883_TARGA_DIG, | 173 | ALC883_TARGA_DIG, |
168 | ALC883_TARGA_2ch_DIG, | 174 | ALC883_TARGA_2ch_DIG, |
169 | ALC883_ACER, | 175 | ALC883_ACER, |
176 | ALC883_ACER_ASPIRE, | ||
170 | ALC883_MEDION, | 177 | ALC883_MEDION, |
171 | ALC883_MEDION_MD2, | 178 | ALC883_MEDION_MD2, |
172 | ALC883_LAPTOP_EAPD, | 179 | ALC883_LAPTOP_EAPD, |
173 | ALC883_LENOVO_101E_2ch, | 180 | ALC883_LENOVO_101E_2ch, |
174 | ALC883_LENOVO_NB0763, | 181 | ALC883_LENOVO_NB0763, |
175 | ALC888_LENOVO_MS7195_DIG, | 182 | ALC888_LENOVO_MS7195_DIG, |
183 | ALC883_HAIER_W66, | ||
176 | ALC888_6ST_HP, | 184 | ALC888_6ST_HP, |
177 | ALC888_3ST_HP, | 185 | ALC888_3ST_HP, |
178 | ALC883_AUTO, | 186 | ALC883_AUTO, |
@@ -239,6 +247,10 @@ struct alc_spec { | |||
239 | /* for pin sensing */ | 247 | /* for pin sensing */ |
240 | unsigned int sense_updated: 1; | 248 | unsigned int sense_updated: 1; |
241 | unsigned int jack_present: 1; | 249 | unsigned int jack_present: 1; |
250 | |||
251 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
252 | struct hda_loopback_check loopback; | ||
253 | #endif | ||
242 | }; | 254 | }; |
243 | 255 | ||
244 | /* | 256 | /* |
@@ -263,6 +275,9 @@ struct alc_config_preset { | |||
263 | const struct hda_input_mux *input_mux; | 275 | const struct hda_input_mux *input_mux; |
264 | void (*unsol_event)(struct hda_codec *, unsigned int); | 276 | void (*unsol_event)(struct hda_codec *, unsigned int); |
265 | void (*init_hook)(struct hda_codec *); | 277 | void (*init_hook)(struct hda_codec *); |
278 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
279 | struct hda_amp_list *loopbacks; | ||
280 | #endif | ||
266 | }; | 281 | }; |
267 | 282 | ||
268 | 283 | ||
@@ -441,8 +456,9 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, | |||
441 | change = pinctl != alc_pin_mode_values[val]; | 456 | change = pinctl != alc_pin_mode_values[val]; |
442 | if (change) { | 457 | if (change) { |
443 | /* Set pin mode to that requested */ | 458 | /* Set pin mode to that requested */ |
444 | snd_hda_codec_write(codec,nid,0,AC_VERB_SET_PIN_WIDGET_CONTROL, | 459 | snd_hda_codec_write_cache(codec, nid, 0, |
445 | alc_pin_mode_values[val]); | 460 | AC_VERB_SET_PIN_WIDGET_CONTROL, |
461 | alc_pin_mode_values[val]); | ||
446 | 462 | ||
447 | /* Also enable the retasking pin's input/output as required | 463 | /* Also enable the retasking pin's input/output as required |
448 | * for the requested pin mode. Enum values of 2 or less are | 464 | * for the requested pin mode. Enum values of 2 or less are |
@@ -455,19 +471,15 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, | |||
455 | * this turns out to be necessary in the future. | 471 | * this turns out to be necessary in the future. |
456 | */ | 472 | */ |
457 | if (val <= 2) { | 473 | if (val <= 2) { |
458 | snd_hda_codec_write(codec, nid, 0, | 474 | snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, |
459 | AC_VERB_SET_AMP_GAIN_MUTE, | 475 | HDA_AMP_MUTE, HDA_AMP_MUTE); |
460 | AMP_OUT_MUTE); | 476 | snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0, |
461 | snd_hda_codec_write(codec, nid, 0, | 477 | HDA_AMP_MUTE, 0); |
462 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
463 | AMP_IN_UNMUTE(0)); | ||
464 | } else { | 478 | } else { |
465 | snd_hda_codec_write(codec, nid, 0, | 479 | snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0, |
466 | AC_VERB_SET_AMP_GAIN_MUTE, | 480 | HDA_AMP_MUTE, HDA_AMP_MUTE); |
467 | AMP_IN_MUTE(0)); | 481 | snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, |
468 | snd_hda_codec_write(codec, nid, 0, | 482 | HDA_AMP_MUTE, 0); |
469 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
470 | AMP_OUT_UNMUTE); | ||
471 | } | 483 | } |
472 | } | 484 | } |
473 | return change; | 485 | return change; |
@@ -486,15 +498,7 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, | |||
486 | * needed for any "production" models. | 498 | * needed for any "production" models. |
487 | */ | 499 | */ |
488 | #ifdef CONFIG_SND_DEBUG | 500 | #ifdef CONFIG_SND_DEBUG |
489 | static int alc_gpio_data_info(struct snd_kcontrol *kcontrol, | 501 | #define alc_gpio_data_info snd_ctl_boolean_mono_info |
490 | struct snd_ctl_elem_info *uinfo) | ||
491 | { | ||
492 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
493 | uinfo->count = 1; | ||
494 | uinfo->value.integer.min = 0; | ||
495 | uinfo->value.integer.max = 1; | ||
496 | return 0; | ||
497 | } | ||
498 | 502 | ||
499 | static int alc_gpio_data_get(struct snd_kcontrol *kcontrol, | 503 | static int alc_gpio_data_get(struct snd_kcontrol *kcontrol, |
500 | struct snd_ctl_elem_value *ucontrol) | 504 | struct snd_ctl_elem_value *ucontrol) |
@@ -527,7 +531,8 @@ static int alc_gpio_data_put(struct snd_kcontrol *kcontrol, | |||
527 | gpio_data &= ~mask; | 531 | gpio_data &= ~mask; |
528 | else | 532 | else |
529 | gpio_data |= mask; | 533 | gpio_data |= mask; |
530 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_GPIO_DATA, gpio_data); | 534 | snd_hda_codec_write_cache(codec, nid, 0, |
535 | AC_VERB_SET_GPIO_DATA, gpio_data); | ||
531 | 536 | ||
532 | return change; | 537 | return change; |
533 | } | 538 | } |
@@ -547,15 +552,7 @@ static int alc_gpio_data_put(struct snd_kcontrol *kcontrol, | |||
547 | * necessary. | 552 | * necessary. |
548 | */ | 553 | */ |
549 | #ifdef CONFIG_SND_DEBUG | 554 | #ifdef CONFIG_SND_DEBUG |
550 | static int alc_spdif_ctrl_info(struct snd_kcontrol *kcontrol, | 555 | #define alc_spdif_ctrl_info snd_ctl_boolean_mono_info |
551 | struct snd_ctl_elem_info *uinfo) | ||
552 | { | ||
553 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
554 | uinfo->count = 1; | ||
555 | uinfo->value.integer.min = 0; | ||
556 | uinfo->value.integer.max = 1; | ||
557 | return 0; | ||
558 | } | ||
559 | 556 | ||
560 | static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol, | 557 | static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol, |
561 | struct snd_ctl_elem_value *ucontrol) | 558 | struct snd_ctl_elem_value *ucontrol) |
@@ -588,8 +585,8 @@ static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol, | |||
588 | ctrl_data &= ~mask; | 585 | ctrl_data &= ~mask; |
589 | else | 586 | else |
590 | ctrl_data |= mask; | 587 | ctrl_data |= mask; |
591 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, | 588 | snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, |
592 | ctrl_data); | 589 | ctrl_data); |
593 | 590 | ||
594 | return change; | 591 | return change; |
595 | } | 592 | } |
@@ -638,6 +635,9 @@ static void setup_preset(struct alc_spec *spec, | |||
638 | 635 | ||
639 | spec->unsol_event = preset->unsol_event; | 636 | spec->unsol_event = preset->unsol_event; |
640 | spec->init_hook = preset->init_hook; | 637 | spec->init_hook = preset->init_hook; |
638 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
639 | spec->loopback.amplist = preset->loopbacks; | ||
640 | #endif | ||
641 | } | 641 | } |
642 | 642 | ||
643 | /* Enable GPIO mask and set output */ | 643 | /* Enable GPIO mask and set output */ |
@@ -662,6 +662,44 @@ static struct hda_verb alc_gpio3_init_verbs[] = { | |||
662 | { } | 662 | { } |
663 | }; | 663 | }; |
664 | 664 | ||
665 | static void alc_sku_automute(struct hda_codec *codec) | ||
666 | { | ||
667 | struct alc_spec *spec = codec->spec; | ||
668 | unsigned int mute; | ||
669 | unsigned int present; | ||
670 | unsigned int hp_nid = spec->autocfg.hp_pins[0]; | ||
671 | unsigned int sp_nid = spec->autocfg.speaker_pins[0]; | ||
672 | |||
673 | /* need to execute and sync at first */ | ||
674 | snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0); | ||
675 | present = snd_hda_codec_read(codec, hp_nid, 0, | ||
676 | AC_VERB_GET_PIN_SENSE, 0); | ||
677 | spec->jack_present = (present & 0x80000000) != 0; | ||
678 | if (spec->jack_present) { | ||
679 | /* mute internal speaker */ | ||
680 | snd_hda_codec_amp_stereo(codec, sp_nid, HDA_OUTPUT, 0, | ||
681 | HDA_AMP_MUTE, HDA_AMP_MUTE); | ||
682 | } else { | ||
683 | /* unmute internal speaker if necessary */ | ||
684 | mute = snd_hda_codec_amp_read(codec, hp_nid, 0, HDA_OUTPUT, 0); | ||
685 | snd_hda_codec_amp_stereo(codec, sp_nid, HDA_OUTPUT, 0, | ||
686 | HDA_AMP_MUTE, mute); | ||
687 | } | ||
688 | } | ||
689 | |||
690 | /* unsolicited event for HP jack sensing */ | ||
691 | static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) | ||
692 | { | ||
693 | if (codec->vendor_id == 0x10ec0880) | ||
694 | res >>= 28; | ||
695 | else | ||
696 | res >>= 26; | ||
697 | if (res != ALC880_HP_EVENT) | ||
698 | return; | ||
699 | |||
700 | alc_sku_automute(codec); | ||
701 | } | ||
702 | |||
665 | /* 32-bit subsystem ID for BIOS loading in HD Audio codec. | 703 | /* 32-bit subsystem ID for BIOS loading in HD Audio codec. |
666 | * 31 ~ 16 : Manufacture ID | 704 | * 31 ~ 16 : Manufacture ID |
667 | * 15 ~ 8 : SKU ID | 705 | * 15 ~ 8 : SKU ID |
@@ -672,13 +710,48 @@ static void alc_subsystem_id(struct hda_codec *codec, | |||
672 | unsigned int porta, unsigned int porte, | 710 | unsigned int porta, unsigned int porte, |
673 | unsigned int portd) | 711 | unsigned int portd) |
674 | { | 712 | { |
675 | unsigned int ass, tmp; | 713 | unsigned int ass, tmp, i; |
714 | unsigned nid; | ||
715 | struct alc_spec *spec = codec->spec; | ||
676 | 716 | ||
677 | ass = codec->subsystem_id; | 717 | ass = codec->subsystem_id & 0xffff; |
678 | if (!(ass & 1)) | 718 | if ((ass != codec->bus->pci->subsystem_device) && (ass & 1)) |
719 | goto do_sku; | ||
720 | |||
721 | /* | ||
722 | * 31~30 : port conetcivity | ||
723 | * 29~21 : reserve | ||
724 | * 20 : PCBEEP input | ||
725 | * 19~16 : Check sum (15:1) | ||
726 | * 15~1 : Custom | ||
727 | * 0 : override | ||
728 | */ | ||
729 | nid = 0x1d; | ||
730 | if (codec->vendor_id == 0x10ec0260) | ||
731 | nid = 0x17; | ||
732 | ass = snd_hda_codec_read(codec, nid, 0, | ||
733 | AC_VERB_GET_CONFIG_DEFAULT, 0); | ||
734 | if (!(ass & 1) && !(ass & 0x100000)) | ||
735 | return; | ||
736 | if ((ass >> 30) != 1) /* no physical connection */ | ||
679 | return; | 737 | return; |
680 | 738 | ||
681 | /* Override */ | 739 | /* check sum */ |
740 | tmp = 0; | ||
741 | for (i = 1; i < 16; i++) { | ||
742 | if ((ass >> i) && 1) | ||
743 | tmp++; | ||
744 | } | ||
745 | if (((ass >> 16) & 0xf) != tmp) | ||
746 | return; | ||
747 | do_sku: | ||
748 | /* | ||
749 | * 0 : override | ||
750 | * 1 : Swap Jack | ||
751 | * 2 : 0 --> Desktop, 1 --> Laptop | ||
752 | * 3~5 : External Amplifier control | ||
753 | * 7~6 : Reserved | ||
754 | */ | ||
682 | tmp = (ass & 0x38) >> 3; /* external Amp control */ | 755 | tmp = (ass & 0x38) >> 3; /* external Amp control */ |
683 | switch (tmp) { | 756 | switch (tmp) { |
684 | case 1: | 757 | case 1: |
@@ -690,38 +763,108 @@ static void alc_subsystem_id(struct hda_codec *codec, | |||
690 | case 7: | 763 | case 7: |
691 | snd_hda_sequence_write(codec, alc_gpio3_init_verbs); | 764 | snd_hda_sequence_write(codec, alc_gpio3_init_verbs); |
692 | break; | 765 | break; |
693 | case 5: | 766 | case 5: /* set EAPD output high */ |
694 | switch (codec->vendor_id) { | 767 | switch (codec->vendor_id) { |
695 | case 0x10ec0862: | 768 | case 0x10ec0260: |
696 | case 0x10ec0660: | 769 | snd_hda_codec_write(codec, 0x0f, 0, |
697 | case 0x10ec0662: | 770 | AC_VERB_SET_EAPD_BTLENABLE, 2); |
771 | snd_hda_codec_write(codec, 0x10, 0, | ||
772 | AC_VERB_SET_EAPD_BTLENABLE, 2); | ||
773 | break; | ||
774 | case 0x10ec0262: | ||
698 | case 0x10ec0267: | 775 | case 0x10ec0267: |
699 | case 0x10ec0268: | 776 | case 0x10ec0268: |
777 | case 0x10ec0269: | ||
778 | case 0x10ec0862: | ||
779 | case 0x10ec0662: | ||
700 | snd_hda_codec_write(codec, 0x14, 0, | 780 | snd_hda_codec_write(codec, 0x14, 0, |
701 | AC_VERB_SET_EAPD_BTLENABLE, 2); | 781 | AC_VERB_SET_EAPD_BTLENABLE, 2); |
702 | snd_hda_codec_write(codec, 0x15, 0, | 782 | snd_hda_codec_write(codec, 0x15, 0, |
703 | AC_VERB_SET_EAPD_BTLENABLE, 2); | 783 | AC_VERB_SET_EAPD_BTLENABLE, 2); |
704 | return; | 784 | break; |
705 | } | 785 | } |
706 | case 6: | 786 | switch (codec->vendor_id) { |
707 | if (ass & 4) { /* bit 2 : 0 = Desktop, 1 = Laptop */ | 787 | case 0x10ec0260: |
708 | hda_nid_t port = 0; | 788 | snd_hda_codec_write(codec, 0x1a, 0, |
709 | tmp = (ass & 0x1800) >> 11; | 789 | AC_VERB_SET_COEF_INDEX, 7); |
710 | switch (tmp) { | 790 | tmp = snd_hda_codec_read(codec, 0x1a, 0, |
711 | case 0: port = porta; break; | 791 | AC_VERB_GET_PROC_COEF, 0); |
712 | case 1: port = porte; break; | 792 | snd_hda_codec_write(codec, 0x1a, 0, |
713 | case 2: port = portd; break; | 793 | AC_VERB_SET_COEF_INDEX, 7); |
714 | } | 794 | snd_hda_codec_write(codec, 0x1a, 0, |
715 | if (port) | 795 | AC_VERB_SET_PROC_COEF, |
716 | snd_hda_codec_write(codec, port, 0, | 796 | tmp | 0x2010); |
717 | AC_VERB_SET_EAPD_BTLENABLE, | 797 | break; |
718 | 2); | 798 | case 0x10ec0262: |
799 | case 0x10ec0880: | ||
800 | case 0x10ec0882: | ||
801 | case 0x10ec0883: | ||
802 | case 0x10ec0885: | ||
803 | case 0x10ec0888: | ||
804 | snd_hda_codec_write(codec, 0x20, 0, | ||
805 | AC_VERB_SET_COEF_INDEX, 7); | ||
806 | tmp = snd_hda_codec_read(codec, 0x20, 0, | ||
807 | AC_VERB_GET_PROC_COEF, 0); | ||
808 | snd_hda_codec_write(codec, 0x20, 0, | ||
809 | AC_VERB_SET_COEF_INDEX, 7); | ||
810 | snd_hda_codec_write(codec, 0x20, 0, | ||
811 | AC_VERB_SET_PROC_COEF, | ||
812 | tmp | 0x2010); | ||
813 | break; | ||
814 | case 0x10ec0267: | ||
815 | case 0x10ec0268: | ||
816 | snd_hda_codec_write(codec, 0x20, 0, | ||
817 | AC_VERB_SET_COEF_INDEX, 7); | ||
818 | tmp = snd_hda_codec_read(codec, 0x20, 0, | ||
819 | AC_VERB_GET_PROC_COEF, 0); | ||
820 | snd_hda_codec_write(codec, 0x20, 0, | ||
821 | AC_VERB_SET_COEF_INDEX, 7); | ||
822 | snd_hda_codec_write(codec, 0x20, 0, | ||
823 | AC_VERB_SET_PROC_COEF, | ||
824 | tmp | 0x3000); | ||
825 | break; | ||
719 | } | 826 | } |
720 | snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7); | 827 | default: |
721 | snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, | ||
722 | (tmp == 5 ? 0x3040 : 0x3050)); | ||
723 | break; | 828 | break; |
724 | } | 829 | } |
830 | |||
831 | /* is laptop and enable the function "Mute internal speaker | ||
832 | * when the external headphone out jack is plugged" | ||
833 | */ | ||
834 | if (!(ass & 0x4) || !(ass & 0x8000)) | ||
835 | return; | ||
836 | /* | ||
837 | * 10~8 : Jack location | ||
838 | * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered | ||
839 | * 14~13: Resvered | ||
840 | * 15 : 1 --> enable the function "Mute internal speaker | ||
841 | * when the external headphone out jack is plugged" | ||
842 | */ | ||
843 | if (!spec->autocfg.speaker_pins[0]) { | ||
844 | if (spec->multiout.dac_nids[0]) | ||
845 | spec->autocfg.speaker_pins[0] = | ||
846 | spec->multiout.dac_nids[0]; | ||
847 | else | ||
848 | return; | ||
849 | } | ||
850 | |||
851 | if (!spec->autocfg.hp_pins[0]) { | ||
852 | tmp = (ass >> 11) & 0x3; /* HP to chassis */ | ||
853 | if (tmp == 0) | ||
854 | spec->autocfg.hp_pins[0] = porta; | ||
855 | else if (tmp == 1) | ||
856 | spec->autocfg.hp_pins[0] = porte; | ||
857 | else if (tmp == 2) | ||
858 | spec->autocfg.hp_pins[0] = portd; | ||
859 | else | ||
860 | return; | ||
861 | } | ||
862 | |||
863 | snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0, | ||
864 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
865 | AC_USRSP_EN | ALC880_HP_EVENT); | ||
866 | spec->unsol_event = alc_sku_unsol_event; | ||
867 | spec->init_hook = alc_sku_automute; | ||
725 | } | 868 | } |
726 | 869 | ||
727 | /* | 870 | /* |
@@ -1304,11 +1447,13 @@ static struct hda_verb alc880_volume_init_verbs[] = { | |||
1304 | * panel mic (mic 2) | 1447 | * panel mic (mic 2) |
1305 | */ | 1448 | */ |
1306 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ | 1449 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ |
1307 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 1450 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
1308 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 1451 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
1309 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | 1452 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, |
1310 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | 1453 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, |
1311 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | 1454 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, |
1455 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, | ||
1456 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, | ||
1312 | 1457 | ||
1313 | /* | 1458 | /* |
1314 | * Set up output mixers (0x0c - 0x0f) | 1459 | * Set up output mixers (0x0c - 0x0f) |
@@ -1568,15 +1713,11 @@ static void alc880_uniwill_hp_automute(struct hda_codec *codec) | |||
1568 | 1713 | ||
1569 | present = snd_hda_codec_read(codec, 0x14, 0, | 1714 | present = snd_hda_codec_read(codec, 0x14, 0, |
1570 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 1715 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; |
1571 | bits = present ? 0x80 : 0; | 1716 | bits = present ? HDA_AMP_MUTE : 0; |
1572 | snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, | 1717 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, |
1573 | 0x80, bits); | 1718 | HDA_AMP_MUTE, bits); |
1574 | snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, | 1719 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, |
1575 | 0x80, bits); | 1720 | HDA_AMP_MUTE, bits); |
1576 | snd_hda_codec_amp_update(codec, 0x16, 0, HDA_OUTPUT, 0, | ||
1577 | 0x80, bits); | ||
1578 | snd_hda_codec_amp_update(codec, 0x16, 1, HDA_OUTPUT, 0, | ||
1579 | 0x80, bits); | ||
1580 | } | 1721 | } |
1581 | 1722 | ||
1582 | /* auto-toggle front mic */ | 1723 | /* auto-toggle front mic */ |
@@ -1587,11 +1728,8 @@ static void alc880_uniwill_mic_automute(struct hda_codec *codec) | |||
1587 | 1728 | ||
1588 | present = snd_hda_codec_read(codec, 0x18, 0, | 1729 | present = snd_hda_codec_read(codec, 0x18, 0, |
1589 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 1730 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; |
1590 | bits = present ? 0x80 : 0; | 1731 | bits = present ? HDA_AMP_MUTE : 0; |
1591 | snd_hda_codec_amp_update(codec, 0x0b, 0, HDA_INPUT, 1, | 1732 | snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits); |
1592 | 0x80, bits); | ||
1593 | snd_hda_codec_amp_update(codec, 0x0b, 1, HDA_INPUT, 1, | ||
1594 | 0x80, bits); | ||
1595 | } | 1733 | } |
1596 | 1734 | ||
1597 | static void alc880_uniwill_automute(struct hda_codec *codec) | 1735 | static void alc880_uniwill_automute(struct hda_codec *codec) |
@@ -1623,11 +1761,8 @@ static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec) | |||
1623 | 1761 | ||
1624 | present = snd_hda_codec_read(codec, 0x14, 0, | 1762 | present = snd_hda_codec_read(codec, 0x14, 0, |
1625 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 1763 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; |
1626 | bits = present ? 0x80 : 0; | 1764 | bits = present ? HDA_AMP_MUTE : 0; |
1627 | snd_hda_codec_amp_update(codec, 0x15, 0, HDA_INPUT, 0, | 1765 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_INPUT, 0, HDA_AMP_MUTE, bits); |
1628 | 0x80, bits); | ||
1629 | snd_hda_codec_amp_update(codec, 0x15, 1, HDA_INPUT, 0, | ||
1630 | 0x80, bits); | ||
1631 | } | 1766 | } |
1632 | 1767 | ||
1633 | static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) | 1768 | static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) |
@@ -1635,19 +1770,14 @@ static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) | |||
1635 | unsigned int present; | 1770 | unsigned int present; |
1636 | 1771 | ||
1637 | present = snd_hda_codec_read(codec, 0x21, 0, | 1772 | present = snd_hda_codec_read(codec, 0x21, 0, |
1638 | AC_VERB_GET_VOLUME_KNOB_CONTROL, 0) & 0x7f; | 1773 | AC_VERB_GET_VOLUME_KNOB_CONTROL, 0); |
1639 | 1774 | present &= HDA_AMP_VOLMASK; | |
1640 | snd_hda_codec_amp_update(codec, 0x0c, 0, HDA_OUTPUT, 0, | 1775 | snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, |
1641 | 0x7f, present); | 1776 | HDA_AMP_VOLMASK, present); |
1642 | snd_hda_codec_amp_update(codec, 0x0c, 1, HDA_OUTPUT, 0, | 1777 | snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0, |
1643 | 0x7f, present); | 1778 | HDA_AMP_VOLMASK, present); |
1644 | |||
1645 | snd_hda_codec_amp_update(codec, 0x0d, 0, HDA_OUTPUT, 0, | ||
1646 | 0x7f, present); | ||
1647 | snd_hda_codec_amp_update(codec, 0x0d, 1, HDA_OUTPUT, 0, | ||
1648 | 0x7f, present); | ||
1649 | |||
1650 | } | 1779 | } |
1780 | |||
1651 | static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec, | 1781 | static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec, |
1652 | unsigned int res) | 1782 | unsigned int res) |
1653 | { | 1783 | { |
@@ -1868,8 +1998,8 @@ static struct hda_verb alc880_lg_init_verbs[] = { | |||
1868 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 1998 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
1869 | /* mute all amp mixer inputs */ | 1999 | /* mute all amp mixer inputs */ |
1870 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, | 2000 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, |
1871 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)}, | 2001 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, |
1872 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(7)}, | 2002 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, |
1873 | /* line-in to input */ | 2003 | /* line-in to input */ |
1874 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | 2004 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, |
1875 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | 2005 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
@@ -1900,11 +2030,9 @@ static void alc880_lg_automute(struct hda_codec *codec) | |||
1900 | 2030 | ||
1901 | present = snd_hda_codec_read(codec, 0x1b, 0, | 2031 | present = snd_hda_codec_read(codec, 0x1b, 0, |
1902 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 2032 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; |
1903 | bits = present ? 0x80 : 0; | 2033 | bits = present ? HDA_AMP_MUTE : 0; |
1904 | snd_hda_codec_amp_update(codec, 0x17, 0, HDA_OUTPUT, 0, | 2034 | snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, |
1905 | 0x80, bits); | 2035 | HDA_AMP_MUTE, bits); |
1906 | snd_hda_codec_amp_update(codec, 0x17, 1, HDA_OUTPUT, 0, | ||
1907 | 0x80, bits); | ||
1908 | } | 2036 | } |
1909 | 2037 | ||
1910 | static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res) | 2038 | static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res) |
@@ -1973,7 +2101,7 @@ static struct hda_verb alc880_lg_lw_init_verbs[] = { | |||
1973 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 2101 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
1974 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 2102 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
1975 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 2103 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
1976 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(7)}, | 2104 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, |
1977 | /* speaker-out */ | 2105 | /* speaker-out */ |
1978 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | 2106 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, |
1979 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | 2107 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
@@ -1999,11 +2127,9 @@ static void alc880_lg_lw_automute(struct hda_codec *codec) | |||
1999 | 2127 | ||
2000 | present = snd_hda_codec_read(codec, 0x1b, 0, | 2128 | present = snd_hda_codec_read(codec, 0x1b, 0, |
2001 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 2129 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; |
2002 | bits = present ? 0x80 : 0; | 2130 | bits = present ? HDA_AMP_MUTE : 0; |
2003 | snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, | 2131 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, |
2004 | 0x80, bits); | 2132 | HDA_AMP_MUTE, bits); |
2005 | snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, | ||
2006 | 0x80, bits); | ||
2007 | } | 2133 | } |
2008 | 2134 | ||
2009 | static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res) | 2135 | static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res) |
@@ -2015,6 +2141,24 @@ static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res) | |||
2015 | alc880_lg_lw_automute(codec); | 2141 | alc880_lg_lw_automute(codec); |
2016 | } | 2142 | } |
2017 | 2143 | ||
2144 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
2145 | static struct hda_amp_list alc880_loopbacks[] = { | ||
2146 | { 0x0b, HDA_INPUT, 0 }, | ||
2147 | { 0x0b, HDA_INPUT, 1 }, | ||
2148 | { 0x0b, HDA_INPUT, 2 }, | ||
2149 | { 0x0b, HDA_INPUT, 3 }, | ||
2150 | { 0x0b, HDA_INPUT, 4 }, | ||
2151 | { } /* end */ | ||
2152 | }; | ||
2153 | |||
2154 | static struct hda_amp_list alc880_lg_loopbacks[] = { | ||
2155 | { 0x0b, HDA_INPUT, 1 }, | ||
2156 | { 0x0b, HDA_INPUT, 6 }, | ||
2157 | { 0x0b, HDA_INPUT, 7 }, | ||
2158 | { } /* end */ | ||
2159 | }; | ||
2160 | #endif | ||
2161 | |||
2018 | /* | 2162 | /* |
2019 | * Common callbacks | 2163 | * Common callbacks |
2020 | */ | 2164 | */ |
@@ -2041,24 +2185,11 @@ static void alc_unsol_event(struct hda_codec *codec, unsigned int res) | |||
2041 | spec->unsol_event(codec, res); | 2185 | spec->unsol_event(codec, res); |
2042 | } | 2186 | } |
2043 | 2187 | ||
2044 | #ifdef CONFIG_PM | 2188 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
2045 | /* | 2189 | static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid) |
2046 | * resume | ||
2047 | */ | ||
2048 | static int alc_resume(struct hda_codec *codec) | ||
2049 | { | 2190 | { |
2050 | struct alc_spec *spec = codec->spec; | 2191 | struct alc_spec *spec = codec->spec; |
2051 | int i; | 2192 | return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); |
2052 | |||
2053 | alc_init(codec); | ||
2054 | for (i = 0; i < spec->num_mixers; i++) | ||
2055 | snd_hda_resume_ctls(codec, spec->mixers[i]); | ||
2056 | if (spec->multiout.dig_out_nid) | ||
2057 | snd_hda_resume_spdif_out(codec); | ||
2058 | if (spec->dig_in_nid) | ||
2059 | snd_hda_resume_spdif_in(codec); | ||
2060 | |||
2061 | return 0; | ||
2062 | } | 2193 | } |
2063 | #endif | 2194 | #endif |
2064 | 2195 | ||
@@ -2293,8 +2424,8 @@ static struct hda_codec_ops alc_patch_ops = { | |||
2293 | .init = alc_init, | 2424 | .init = alc_init, |
2294 | .free = alc_free, | 2425 | .free = alc_free, |
2295 | .unsol_event = alc_unsol_event, | 2426 | .unsol_event = alc_unsol_event, |
2296 | #ifdef CONFIG_PM | 2427 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
2297 | .resume = alc_resume, | 2428 | .check_power_status = alc_check_power_status, |
2298 | #endif | 2429 | #endif |
2299 | }; | 2430 | }; |
2300 | 2431 | ||
@@ -2392,11 +2523,14 @@ static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol, | |||
2392 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | 2523 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); |
2393 | new_ctl = ctls[ucontrol->value.enumerated.item[0]]; | 2524 | new_ctl = ctls[ucontrol->value.enumerated.item[0]]; |
2394 | if (old_ctl != new_ctl) { | 2525 | if (old_ctl != new_ctl) { |
2395 | snd_hda_codec_write(codec, nid, 0, | 2526 | int val; |
2396 | AC_VERB_SET_PIN_WIDGET_CONTROL, new_ctl); | 2527 | snd_hda_codec_write_cache(codec, nid, 0, |
2397 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | 2528 | AC_VERB_SET_PIN_WIDGET_CONTROL, |
2398 | (ucontrol->value.enumerated.item[0] >= 3 ? | 2529 | new_ctl); |
2399 | 0xb080 : 0xb000)); | 2530 | val = ucontrol->value.enumerated.item[0] >= 3 ? |
2531 | HDA_AMP_MUTE : 0; | ||
2532 | snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, | ||
2533 | HDA_AMP_MUTE, val); | ||
2400 | return 1; | 2534 | return 1; |
2401 | } | 2535 | } |
2402 | return 0; | 2536 | return 0; |
@@ -2439,7 +2573,8 @@ static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol, | |||
2439 | sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3; | 2573 | sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3; |
2440 | if (ucontrol->value.enumerated.item[0] != sel) { | 2574 | if (ucontrol->value.enumerated.item[0] != sel) { |
2441 | sel = ucontrol->value.enumerated.item[0] & 3; | 2575 | sel = ucontrol->value.enumerated.item[0] & 3; |
2442 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, sel); | 2576 | snd_hda_codec_write_cache(codec, nid, 0, |
2577 | AC_VERB_SET_CONNECT_SEL, sel); | ||
2443 | return 1; | 2578 | return 1; |
2444 | } | 2579 | } |
2445 | return 0; | 2580 | return 0; |
@@ -2885,6 +3020,7 @@ static struct alc_config_preset alc880_presets[] = { | |||
2885 | alc880_beep_init_verbs }, | 3020 | alc880_beep_init_verbs }, |
2886 | .num_dacs = ARRAY_SIZE(alc880_dac_nids), | 3021 | .num_dacs = ARRAY_SIZE(alc880_dac_nids), |
2887 | .dac_nids = alc880_dac_nids, | 3022 | .dac_nids = alc880_dac_nids, |
3023 | .dig_out_nid = ALC880_DIGOUT_NID, | ||
2888 | .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), | 3024 | .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), |
2889 | .channel_mode = alc880_2_jack_modes, | 3025 | .channel_mode = alc880_2_jack_modes, |
2890 | .input_mux = &alc880_capture_source, | 3026 | .input_mux = &alc880_capture_source, |
@@ -2916,6 +3052,9 @@ static struct alc_config_preset alc880_presets[] = { | |||
2916 | .input_mux = &alc880_lg_capture_source, | 3052 | .input_mux = &alc880_lg_capture_source, |
2917 | .unsol_event = alc880_lg_unsol_event, | 3053 | .unsol_event = alc880_lg_unsol_event, |
2918 | .init_hook = alc880_lg_automute, | 3054 | .init_hook = alc880_lg_automute, |
3055 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
3056 | .loopbacks = alc880_lg_loopbacks, | ||
3057 | #endif | ||
2919 | }, | 3058 | }, |
2920 | [ALC880_LG_LW] = { | 3059 | [ALC880_LG_LW] = { |
2921 | .mixers = { alc880_lg_lw_mixer }, | 3060 | .mixers = { alc880_lg_lw_mixer }, |
@@ -3399,6 +3538,10 @@ static int patch_alc880(struct hda_codec *codec) | |||
3399 | codec->patch_ops = alc_patch_ops; | 3538 | codec->patch_ops = alc_patch_ops; |
3400 | if (board_config == ALC880_AUTO) | 3539 | if (board_config == ALC880_AUTO) |
3401 | spec->init_hook = alc880_auto_init; | 3540 | spec->init_hook = alc880_auto_init; |
3541 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
3542 | if (!spec->loopback.amplist) | ||
3543 | spec->loopback.amplist = alc880_loopbacks; | ||
3544 | #endif | ||
3402 | 3545 | ||
3403 | return 0; | 3546 | return 0; |
3404 | } | 3547 | } |
@@ -3747,12 +3890,12 @@ static struct hda_verb alc260_init_verbs[] = { | |||
3747 | /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & | 3890 | /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & |
3748 | * Line In 2 = 0x03 | 3891 | * Line In 2 = 0x03 |
3749 | */ | 3892 | */ |
3750 | /* mute CD */ | 3893 | /* mute analog inputs */ |
3751 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | 3894 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
3752 | /* mute Line In */ | 3895 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
3753 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | 3896 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, |
3754 | /* mute Mic */ | 3897 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, |
3755 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 3898 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, |
3756 | /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ | 3899 | /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ |
3757 | /* mute Front out path */ | 3900 | /* mute Front out path */ |
3758 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | 3901 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
@@ -3797,12 +3940,12 @@ static struct hda_verb alc260_hp_init_verbs[] = { | |||
3797 | /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & | 3940 | /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & |
3798 | * Line In 2 = 0x03 | 3941 | * Line In 2 = 0x03 |
3799 | */ | 3942 | */ |
3800 | /* unmute CD */ | 3943 | /* mute analog inputs */ |
3801 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, | 3944 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
3802 | /* unmute Line In */ | 3945 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
3803 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, | 3946 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, |
3804 | /* unmute Mic */ | 3947 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, |
3805 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 3948 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, |
3806 | /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ | 3949 | /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ |
3807 | /* Unmute Front out path */ | 3950 | /* Unmute Front out path */ |
3808 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 3951 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, |
@@ -3847,12 +3990,12 @@ static struct hda_verb alc260_hp_3013_init_verbs[] = { | |||
3847 | /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & | 3990 | /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & |
3848 | * Line In 2 = 0x03 | 3991 | * Line In 2 = 0x03 |
3849 | */ | 3992 | */ |
3850 | /* unmute CD */ | 3993 | /* mute analog inputs */ |
3851 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, | 3994 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
3852 | /* unmute Line In */ | 3995 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
3853 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, | 3996 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, |
3854 | /* unmute Mic */ | 3997 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, |
3855 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 3998 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, |
3856 | /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ | 3999 | /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ |
3857 | /* Unmute Front out path */ | 4000 | /* Unmute Front out path */ |
3858 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 4001 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, |
@@ -4069,13 +4212,17 @@ static void alc260_replacer_672v_automute(struct hda_codec *codec) | |||
4069 | present = snd_hda_codec_read(codec, 0x0f, 0, | 4212 | present = snd_hda_codec_read(codec, 0x0f, 0, |
4070 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 4213 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; |
4071 | if (present) { | 4214 | if (present) { |
4072 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 1); | 4215 | snd_hda_codec_write_cache(codec, 0x01, 0, |
4073 | snd_hda_codec_write(codec, 0x0f, 0, | 4216 | AC_VERB_SET_GPIO_DATA, 1); |
4074 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); | 4217 | snd_hda_codec_write_cache(codec, 0x0f, 0, |
4218 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
4219 | PIN_HP); | ||
4075 | } else { | 4220 | } else { |
4076 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0); | 4221 | snd_hda_codec_write_cache(codec, 0x01, 0, |
4077 | snd_hda_codec_write(codec, 0x0f, 0, | 4222 | AC_VERB_SET_GPIO_DATA, 0); |
4078 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); | 4223 | snd_hda_codec_write_cache(codec, 0x0f, 0, |
4224 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
4225 | PIN_OUT); | ||
4079 | } | 4226 | } |
4080 | } | 4227 | } |
4081 | 4228 | ||
@@ -4470,11 +4617,12 @@ static struct hda_verb alc260_volume_init_verbs[] = { | |||
4470 | * front panel mic (mic 2) | 4617 | * front panel mic (mic 2) |
4471 | */ | 4618 | */ |
4472 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ | 4619 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ |
4473 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 4620 | /* mute analog inputs */ |
4474 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 4621 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
4475 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | 4622 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
4476 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | 4623 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, |
4477 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | 4624 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, |
4625 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
4478 | 4626 | ||
4479 | /* | 4627 | /* |
4480 | * Set up output mixers (0x08 - 0x0a) | 4628 | * Set up output mixers (0x08 - 0x0a) |
@@ -4551,6 +4699,17 @@ static void alc260_auto_init(struct hda_codec *codec) | |||
4551 | alc260_auto_init_analog_input(codec); | 4699 | alc260_auto_init_analog_input(codec); |
4552 | } | 4700 | } |
4553 | 4701 | ||
4702 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
4703 | static struct hda_amp_list alc260_loopbacks[] = { | ||
4704 | { 0x07, HDA_INPUT, 0 }, | ||
4705 | { 0x07, HDA_INPUT, 1 }, | ||
4706 | { 0x07, HDA_INPUT, 2 }, | ||
4707 | { 0x07, HDA_INPUT, 3 }, | ||
4708 | { 0x07, HDA_INPUT, 4 }, | ||
4709 | { } /* end */ | ||
4710 | }; | ||
4711 | #endif | ||
4712 | |||
4554 | /* | 4713 | /* |
4555 | * ALC260 configurations | 4714 | * ALC260 configurations |
4556 | */ | 4715 | */ |
@@ -4750,6 +4909,10 @@ static int patch_alc260(struct hda_codec *codec) | |||
4750 | codec->patch_ops = alc_patch_ops; | 4909 | codec->patch_ops = alc_patch_ops; |
4751 | if (board_config == ALC260_AUTO) | 4910 | if (board_config == ALC260_AUTO) |
4752 | spec->init_hook = alc260_auto_init; | 4911 | spec->init_hook = alc260_auto_init; |
4912 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
4913 | if (!spec->loopback.amplist) | ||
4914 | spec->loopback.amplist = alc260_loopbacks; | ||
4915 | #endif | ||
4753 | 4916 | ||
4754 | return 0; | 4917 | return 0; |
4755 | } | 4918 | } |
@@ -4812,12 +4975,13 @@ static int alc882_mux_enum_put(struct snd_kcontrol *kcontrol, | |||
4812 | idx = ucontrol->value.enumerated.item[0]; | 4975 | idx = ucontrol->value.enumerated.item[0]; |
4813 | if (idx >= imux->num_items) | 4976 | if (idx >= imux->num_items) |
4814 | idx = imux->num_items - 1; | 4977 | idx = imux->num_items - 1; |
4815 | if (*cur_val == idx && !codec->in_resume) | 4978 | if (*cur_val == idx) |
4816 | return 0; | 4979 | return 0; |
4817 | for (i = 0; i < imux->num_items; i++) { | 4980 | for (i = 0; i < imux->num_items; i++) { |
4818 | unsigned int v = (i == idx) ? 0x7000 : 0x7080; | 4981 | unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; |
4819 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | 4982 | snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, |
4820 | v | (imux->items[i].index << 8)); | 4983 | imux->items[i].index, |
4984 | HDA_AMP_MUTE, v); | ||
4821 | } | 4985 | } |
4822 | *cur_val = idx; | 4986 | *cur_val = idx; |
4823 | return 1; | 4987 | return 1; |
@@ -4879,6 +5043,38 @@ static struct hda_channel_mode alc882_sixstack_modes[2] = { | |||
4879 | { 8, alc882_sixstack_ch8_init }, | 5043 | { 8, alc882_sixstack_ch8_init }, |
4880 | }; | 5044 | }; |
4881 | 5045 | ||
5046 | /* | ||
5047 | * macbook pro ALC885 can switch LineIn to LineOut without loosing Mic | ||
5048 | */ | ||
5049 | |||
5050 | /* | ||
5051 | * 2ch mode | ||
5052 | */ | ||
5053 | static struct hda_verb alc885_mbp_ch2_init[] = { | ||
5054 | { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, | ||
5055 | { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5056 | { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
5057 | { } /* end */ | ||
5058 | }; | ||
5059 | |||
5060 | /* | ||
5061 | * 6ch mode | ||
5062 | */ | ||
5063 | static struct hda_verb alc885_mbp_ch6_init[] = { | ||
5064 | { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
5065 | { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
5066 | { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, | ||
5067 | { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5068 | { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5069 | { } /* end */ | ||
5070 | }; | ||
5071 | |||
5072 | static struct hda_channel_mode alc885_mbp_6ch_modes[2] = { | ||
5073 | { 2, alc885_mbp_ch2_init }, | ||
5074 | { 6, alc885_mbp_ch6_init }, | ||
5075 | }; | ||
5076 | |||
5077 | |||
4882 | /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 | 5078 | /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 |
4883 | * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b | 5079 | * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b |
4884 | */ | 5080 | */ |
@@ -4909,6 +5105,19 @@ static struct snd_kcontrol_new alc882_base_mixer[] = { | |||
4909 | { } /* end */ | 5105 | { } /* end */ |
4910 | }; | 5106 | }; |
4911 | 5107 | ||
5108 | static struct snd_kcontrol_new alc885_mbp3_mixer[] = { | ||
5109 | HDA_CODEC_VOLUME("Master Volume", 0x0c, 0x00, HDA_OUTPUT), | ||
5110 | HDA_BIND_MUTE ("Master Switch", 0x0c, 0x02, HDA_INPUT), | ||
5111 | HDA_CODEC_MUTE ("Speaker Switch", 0x14, 0x00, HDA_OUTPUT), | ||
5112 | HDA_CODEC_VOLUME("Line Out Volume", 0x0d,0x00, HDA_OUTPUT), | ||
5113 | HDA_CODEC_VOLUME("Line In Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
5114 | HDA_CODEC_MUTE ("Line In Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
5115 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT), | ||
5116 | HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), | ||
5117 | HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0x00, HDA_INPUT), | ||
5118 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT), | ||
5119 | { } /* end */ | ||
5120 | }; | ||
4912 | static struct snd_kcontrol_new alc882_w2jc_mixer[] = { | 5121 | static struct snd_kcontrol_new alc882_w2jc_mixer[] = { |
4913 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 5122 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
4914 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), | 5123 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), |
@@ -4934,8 +5143,10 @@ static struct snd_kcontrol_new alc882_targa_mixer[] = { | |||
4934 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | 5143 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), |
4935 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | 5144 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), |
4936 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | 5145 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), |
5146 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
4937 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | 5147 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), |
4938 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | 5148 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), |
5149 | HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), | ||
4939 | { } /* end */ | 5150 | { } /* end */ |
4940 | }; | 5151 | }; |
4941 | 5152 | ||
@@ -4955,6 +5166,23 @@ static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = { | |||
4955 | HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT), | 5166 | HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT), |
4956 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | 5167 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), |
4957 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | 5168 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), |
5169 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
5170 | { } /* end */ | ||
5171 | }; | ||
5172 | |||
5173 | static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = { | ||
5174 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
5175 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), | ||
5176 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
5177 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | ||
5178 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | ||
5179 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
5180 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
5181 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
5182 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
5183 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
5184 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), | ||
5185 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), | ||
4958 | { } /* end */ | 5186 | { } /* end */ |
4959 | }; | 5187 | }; |
4960 | 5188 | ||
@@ -5119,6 +5347,66 @@ static struct hda_verb alc882_macpro_init_verbs[] = { | |||
5119 | { } | 5347 | { } |
5120 | }; | 5348 | }; |
5121 | 5349 | ||
5350 | /* Macbook Pro rev3 */ | ||
5351 | static struct hda_verb alc885_mbp3_init_verbs[] = { | ||
5352 | /* Front mixer: unmute input/output amp left and right (volume = 0) */ | ||
5353 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
5354 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5355 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
5356 | /* Rear mixer */ | ||
5357 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
5358 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5359 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
5360 | /* Front Pin: output 0 (0x0c) */ | ||
5361 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
5362 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
5363 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
5364 | /* HP Pin: output 0 (0x0d) */ | ||
5365 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, | ||
5366 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5367 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
5368 | {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, | ||
5369 | /* Mic (rear) pin: input vref at 80% */ | ||
5370 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
5371 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5372 | /* Front Mic pin: input vref at 80% */ | ||
5373 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
5374 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5375 | /* Line In pin: use output 1 when in LineOut mode */ | ||
5376 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
5377 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5378 | {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
5379 | |||
5380 | /* FIXME: use matrix-type input source selection */ | ||
5381 | /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ | ||
5382 | /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ | ||
5383 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5384 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
5385 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
5386 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
5387 | /* Input mixer2 */ | ||
5388 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5389 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
5390 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
5391 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
5392 | /* Input mixer3 */ | ||
5393 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5394 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
5395 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
5396 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
5397 | /* ADC1: mute amp left and right */ | ||
5398 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5399 | {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
5400 | /* ADC2: mute amp left and right */ | ||
5401 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5402 | {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
5403 | /* ADC3: mute amp left and right */ | ||
5404 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5405 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
5406 | |||
5407 | { } | ||
5408 | }; | ||
5409 | |||
5122 | /* iMac 24 mixer. */ | 5410 | /* iMac 24 mixer. */ |
5123 | static struct snd_kcontrol_new alc885_imac24_mixer[] = { | 5411 | static struct snd_kcontrol_new alc885_imac24_mixer[] = { |
5124 | HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT), | 5412 | HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT), |
@@ -5154,14 +5442,10 @@ static void alc885_imac24_automute(struct hda_codec *codec) | |||
5154 | 5442 | ||
5155 | present = snd_hda_codec_read(codec, 0x14, 0, | 5443 | present = snd_hda_codec_read(codec, 0x14, 0, |
5156 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 5444 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; |
5157 | snd_hda_codec_amp_update(codec, 0x18, 0, HDA_OUTPUT, 0, | 5445 | snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0, |
5158 | 0x80, present ? 0x80 : 0); | 5446 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); |
5159 | snd_hda_codec_amp_update(codec, 0x18, 1, HDA_OUTPUT, 0, | 5447 | snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0, |
5160 | 0x80, present ? 0x80 : 0); | 5448 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); |
5161 | snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0, | ||
5162 | 0x80, present ? 0x80 : 0); | ||
5163 | snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, | ||
5164 | 0x80, present ? 0x80 : 0); | ||
5165 | } | 5449 | } |
5166 | 5450 | ||
5167 | /* Processes unsolicited events. */ | 5451 | /* Processes unsolicited events. */ |
@@ -5173,6 +5457,27 @@ static void alc885_imac24_unsol_event(struct hda_codec *codec, | |||
5173 | alc885_imac24_automute(codec); | 5457 | alc885_imac24_automute(codec); |
5174 | } | 5458 | } |
5175 | 5459 | ||
5460 | static void alc885_mbp3_automute(struct hda_codec *codec) | ||
5461 | { | ||
5462 | unsigned int present; | ||
5463 | |||
5464 | present = snd_hda_codec_read(codec, 0x15, 0, | ||
5465 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
5466 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
5467 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
5468 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, | ||
5469 | HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE); | ||
5470 | |||
5471 | } | ||
5472 | static void alc885_mbp3_unsol_event(struct hda_codec *codec, | ||
5473 | unsigned int res) | ||
5474 | { | ||
5475 | /* Headphone insertion or removal. */ | ||
5476 | if ((res >> 26) == ALC880_HP_EVENT) | ||
5477 | alc885_mbp3_automute(codec); | ||
5478 | } | ||
5479 | |||
5480 | |||
5176 | static struct hda_verb alc882_targa_verbs[] = { | 5481 | static struct hda_verb alc882_targa_verbs[] = { |
5177 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 5482 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
5178 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 5483 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
@@ -5198,11 +5503,10 @@ static void alc882_targa_automute(struct hda_codec *codec) | |||
5198 | 5503 | ||
5199 | present = snd_hda_codec_read(codec, 0x14, 0, | 5504 | present = snd_hda_codec_read(codec, 0x14, 0, |
5200 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 5505 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; |
5201 | snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, | 5506 | snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, |
5202 | 0x80, present ? 0x80 : 0); | 5507 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); |
5203 | snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, | 5508 | snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, |
5204 | 0x80, present ? 0x80 : 0); | 5509 | present ? 1 : 3); |
5205 | snd_hda_codec_write(codec, 1, 0, AC_VERB_SET_GPIO_DATA, present ? 1 : 3); | ||
5206 | } | 5510 | } |
5207 | 5511 | ||
5208 | static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res) | 5512 | static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res) |
@@ -5233,6 +5537,24 @@ static struct hda_verb alc882_asus_a7j_verbs[] = { | |||
5233 | { } /* end */ | 5537 | { } /* end */ |
5234 | }; | 5538 | }; |
5235 | 5539 | ||
5540 | static struct hda_verb alc882_asus_a7m_verbs[] = { | ||
5541 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5542 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5543 | |||
5544 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
5545 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
5546 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
5547 | |||
5548 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */ | ||
5549 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ | ||
5550 | {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */ | ||
5551 | |||
5552 | {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ | ||
5553 | {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */ | ||
5554 | {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ | ||
5555 | { } /* end */ | ||
5556 | }; | ||
5557 | |||
5236 | static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted) | 5558 | static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted) |
5237 | { | 5559 | { |
5238 | unsigned int gpiostate, gpiomask, gpiodir; | 5560 | unsigned int gpiostate, gpiomask, gpiodir; |
@@ -5265,6 +5587,20 @@ static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted) | |||
5265 | AC_VERB_SET_GPIO_DATA, gpiostate); | 5587 | AC_VERB_SET_GPIO_DATA, gpiostate); |
5266 | } | 5588 | } |
5267 | 5589 | ||
5590 | /* set up GPIO at initialization */ | ||
5591 | static void alc885_macpro_init_hook(struct hda_codec *codec) | ||
5592 | { | ||
5593 | alc882_gpio_mute(codec, 0, 0); | ||
5594 | alc882_gpio_mute(codec, 1, 0); | ||
5595 | } | ||
5596 | |||
5597 | /* set up GPIO and update auto-muting at initialization */ | ||
5598 | static void alc885_imac24_init_hook(struct hda_codec *codec) | ||
5599 | { | ||
5600 | alc885_macpro_init_hook(codec); | ||
5601 | alc885_imac24_automute(codec); | ||
5602 | } | ||
5603 | |||
5268 | /* | 5604 | /* |
5269 | * generic initialization of ADC, input mixers and output mixers | 5605 | * generic initialization of ADC, input mixers and output mixers |
5270 | */ | 5606 | */ |
@@ -5279,17 +5615,17 @@ static struct hda_verb alc882_auto_init_verbs[] = { | |||
5279 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, | 5615 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, |
5280 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 5616 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
5281 | 5617 | ||
5282 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | 5618 | /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback |
5283 | * mixer widget | 5619 | * mixer widget |
5284 | * Note: PASD motherboards uses the Line In 2 as the input for | 5620 | * Note: PASD motherboards uses the Line In 2 as the input for |
5285 | * front panel mic (mic 2) | 5621 | * front panel mic (mic 2) |
5286 | */ | 5622 | */ |
5287 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ | 5623 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ |
5288 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 5624 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
5289 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 5625 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
5290 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | 5626 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, |
5291 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | 5627 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, |
5292 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | 5628 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, |
5293 | 5629 | ||
5294 | /* | 5630 | /* |
5295 | * Set up output mixers (0x0c - 0x0f) | 5631 | * Set up output mixers (0x0c - 0x0f) |
@@ -5378,6 +5714,10 @@ static struct snd_kcontrol_new alc882_capture_mixer[] = { | |||
5378 | { } /* end */ | 5714 | { } /* end */ |
5379 | }; | 5715 | }; |
5380 | 5716 | ||
5717 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
5718 | #define alc882_loopbacks alc880_loopbacks | ||
5719 | #endif | ||
5720 | |||
5381 | /* pcm configuration: identiacal with ALC880 */ | 5721 | /* pcm configuration: identiacal with ALC880 */ |
5382 | #define alc882_pcm_analog_playback alc880_pcm_analog_playback | 5722 | #define alc882_pcm_analog_playback alc880_pcm_analog_playback |
5383 | #define alc882_pcm_analog_capture alc880_pcm_analog_capture | 5723 | #define alc882_pcm_analog_capture alc880_pcm_analog_capture |
@@ -5392,7 +5732,11 @@ static const char *alc882_models[ALC882_MODEL_LAST] = { | |||
5392 | [ALC882_6ST_DIG] = "6stack-dig", | 5732 | [ALC882_6ST_DIG] = "6stack-dig", |
5393 | [ALC882_ARIMA] = "arima", | 5733 | [ALC882_ARIMA] = "arima", |
5394 | [ALC882_W2JC] = "w2jc", | 5734 | [ALC882_W2JC] = "w2jc", |
5735 | [ALC882_TARGA] = "targa", | ||
5736 | [ALC882_ASUS_A7J] = "asus-a7j", | ||
5737 | [ALC882_ASUS_A7M] = "asus-a7m", | ||
5395 | [ALC885_MACPRO] = "macpro", | 5738 | [ALC885_MACPRO] = "macpro", |
5739 | [ALC885_MBP3] = "mbp3", | ||
5396 | [ALC885_IMAC24] = "imac24", | 5740 | [ALC885_IMAC24] = "imac24", |
5397 | [ALC882_AUTO] = "auto", | 5741 | [ALC882_AUTO] = "auto", |
5398 | }; | 5742 | }; |
@@ -5404,6 +5748,8 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { | |||
5404 | SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */ | 5748 | SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */ |
5405 | SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), | 5749 | SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), |
5406 | SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J), | 5750 | SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J), |
5751 | SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J), | ||
5752 | SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M), | ||
5407 | SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG), | 5753 | SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG), |
5408 | SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG), | 5754 | SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG), |
5409 | SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC), | 5755 | SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC), |
@@ -5455,6 +5801,20 @@ static struct alc_config_preset alc882_presets[] = { | |||
5455 | .input_mux = &alc882_capture_source, | 5801 | .input_mux = &alc882_capture_source, |
5456 | .dig_out_nid = ALC882_DIGOUT_NID, | 5802 | .dig_out_nid = ALC882_DIGOUT_NID, |
5457 | }, | 5803 | }, |
5804 | [ALC885_MBP3] = { | ||
5805 | .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer }, | ||
5806 | .init_verbs = { alc885_mbp3_init_verbs, | ||
5807 | alc880_gpio1_init_verbs }, | ||
5808 | .num_dacs = ARRAY_SIZE(alc882_dac_nids), | ||
5809 | .dac_nids = alc882_dac_nids, | ||
5810 | .channel_mode = alc885_mbp_6ch_modes, | ||
5811 | .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes), | ||
5812 | .input_mux = &alc882_capture_source, | ||
5813 | .dig_out_nid = ALC882_DIGOUT_NID, | ||
5814 | .dig_in_nid = ALC882_DIGIN_NID, | ||
5815 | .unsol_event = alc885_mbp3_unsol_event, | ||
5816 | .init_hook = alc885_mbp3_automute, | ||
5817 | }, | ||
5458 | [ALC885_MACPRO] = { | 5818 | [ALC885_MACPRO] = { |
5459 | .mixers = { alc882_macpro_mixer }, | 5819 | .mixers = { alc882_macpro_mixer }, |
5460 | .init_verbs = { alc882_macpro_init_verbs }, | 5820 | .init_verbs = { alc882_macpro_init_verbs }, |
@@ -5465,6 +5825,7 @@ static struct alc_config_preset alc882_presets[] = { | |||
5465 | .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), | 5825 | .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), |
5466 | .channel_mode = alc882_ch_modes, | 5826 | .channel_mode = alc882_ch_modes, |
5467 | .input_mux = &alc882_capture_source, | 5827 | .input_mux = &alc882_capture_source, |
5828 | .init_hook = alc885_macpro_init_hook, | ||
5468 | }, | 5829 | }, |
5469 | [ALC885_IMAC24] = { | 5830 | [ALC885_IMAC24] = { |
5470 | .mixers = { alc885_imac24_mixer }, | 5831 | .mixers = { alc885_imac24_mixer }, |
@@ -5477,7 +5838,7 @@ static struct alc_config_preset alc882_presets[] = { | |||
5477 | .channel_mode = alc882_ch_modes, | 5838 | .channel_mode = alc882_ch_modes, |
5478 | .input_mux = &alc882_capture_source, | 5839 | .input_mux = &alc882_capture_source, |
5479 | .unsol_event = alc885_imac24_unsol_event, | 5840 | .unsol_event = alc885_imac24_unsol_event, |
5480 | .init_hook = alc885_imac24_automute, | 5841 | .init_hook = alc885_imac24_init_hook, |
5481 | }, | 5842 | }, |
5482 | [ALC882_TARGA] = { | 5843 | [ALC882_TARGA] = { |
5483 | .mixers = { alc882_targa_mixer, alc882_chmode_mixer, | 5844 | .mixers = { alc882_targa_mixer, alc882_chmode_mixer, |
@@ -5509,6 +5870,19 @@ static struct alc_config_preset alc882_presets[] = { | |||
5509 | .need_dac_fix = 1, | 5870 | .need_dac_fix = 1, |
5510 | .input_mux = &alc882_capture_source, | 5871 | .input_mux = &alc882_capture_source, |
5511 | }, | 5872 | }, |
5873 | [ALC882_ASUS_A7M] = { | ||
5874 | .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer }, | ||
5875 | .init_verbs = { alc882_init_verbs, alc882_eapd_verbs, | ||
5876 | alc880_gpio1_init_verbs, | ||
5877 | alc882_asus_a7m_verbs }, | ||
5878 | .num_dacs = ARRAY_SIZE(alc882_dac_nids), | ||
5879 | .dac_nids = alc882_dac_nids, | ||
5880 | .dig_out_nid = ALC882_DIGOUT_NID, | ||
5881 | .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), | ||
5882 | .channel_mode = alc880_threestack_modes, | ||
5883 | .need_dac_fix = 1, | ||
5884 | .input_mux = &alc882_capture_source, | ||
5885 | }, | ||
5512 | }; | 5886 | }; |
5513 | 5887 | ||
5514 | 5888 | ||
@@ -5608,6 +5982,32 @@ static void alc882_auto_init_analog_input(struct hda_codec *codec) | |||
5608 | } | 5982 | } |
5609 | } | 5983 | } |
5610 | 5984 | ||
5985 | /* add mic boosts if needed */ | ||
5986 | static int alc_auto_add_mic_boost(struct hda_codec *codec) | ||
5987 | { | ||
5988 | struct alc_spec *spec = codec->spec; | ||
5989 | int err; | ||
5990 | hda_nid_t nid; | ||
5991 | |||
5992 | nid = spec->autocfg.input_pins[AUTO_PIN_MIC]; | ||
5993 | if (nid) { | ||
5994 | err = add_control(spec, ALC_CTL_WIDGET_VOL, | ||
5995 | "Mic Boost", | ||
5996 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); | ||
5997 | if (err < 0) | ||
5998 | return err; | ||
5999 | } | ||
6000 | nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC]; | ||
6001 | if (nid) { | ||
6002 | err = add_control(spec, ALC_CTL_WIDGET_VOL, | ||
6003 | "Front Mic Boost", | ||
6004 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); | ||
6005 | if (err < 0) | ||
6006 | return err; | ||
6007 | } | ||
6008 | return 0; | ||
6009 | } | ||
6010 | |||
5611 | /* almost identical with ALC880 parser... */ | 6011 | /* almost identical with ALC880 parser... */ |
5612 | static int alc882_parse_auto_config(struct hda_codec *codec) | 6012 | static int alc882_parse_auto_config(struct hda_codec *codec) |
5613 | { | 6013 | { |
@@ -5616,10 +6016,17 @@ static int alc882_parse_auto_config(struct hda_codec *codec) | |||
5616 | 6016 | ||
5617 | if (err < 0) | 6017 | if (err < 0) |
5618 | return err; | 6018 | return err; |
5619 | else if (err > 0) | 6019 | else if (!err) |
5620 | /* hack - override the init verbs */ | 6020 | return 0; /* no config found */ |
5621 | spec->init_verbs[0] = alc882_auto_init_verbs; | 6021 | |
5622 | return err; | 6022 | err = alc_auto_add_mic_boost(codec); |
6023 | if (err < 0) | ||
6024 | return err; | ||
6025 | |||
6026 | /* hack - override the init verbs */ | ||
6027 | spec->init_verbs[0] = alc882_auto_init_verbs; | ||
6028 | |||
6029 | return 1; /* config found */ | ||
5623 | } | 6030 | } |
5624 | 6031 | ||
5625 | /* additional initialization for auto-configuration model */ | 6032 | /* additional initialization for auto-configuration model */ |
@@ -5654,6 +6061,9 @@ static int patch_alc882(struct hda_codec *codec) | |||
5654 | case 0x106b1000: /* iMac 24 */ | 6061 | case 0x106b1000: /* iMac 24 */ |
5655 | board_config = ALC885_IMAC24; | 6062 | board_config = ALC885_IMAC24; |
5656 | break; | 6063 | break; |
6064 | case 0x106b2c00: /* Macbook Pro rev3 */ | ||
6065 | board_config = ALC885_MBP3; | ||
6066 | break; | ||
5657 | default: | 6067 | default: |
5658 | printk(KERN_INFO "hda_codec: Unknown model for ALC882, " | 6068 | printk(KERN_INFO "hda_codec: Unknown model for ALC882, " |
5659 | "trying auto-probe from BIOS...\n"); | 6069 | "trying auto-probe from BIOS...\n"); |
@@ -5680,11 +6090,6 @@ static int patch_alc882(struct hda_codec *codec) | |||
5680 | if (board_config != ALC882_AUTO) | 6090 | if (board_config != ALC882_AUTO) |
5681 | setup_preset(spec, &alc882_presets[board_config]); | 6091 | setup_preset(spec, &alc882_presets[board_config]); |
5682 | 6092 | ||
5683 | if (board_config == ALC885_MACPRO || board_config == ALC885_IMAC24) { | ||
5684 | alc882_gpio_mute(codec, 0, 0); | ||
5685 | alc882_gpio_mute(codec, 1, 0); | ||
5686 | } | ||
5687 | |||
5688 | spec->stream_name_analog = "ALC882 Analog"; | 6093 | spec->stream_name_analog = "ALC882 Analog"; |
5689 | spec->stream_analog_playback = &alc882_pcm_analog_playback; | 6094 | spec->stream_analog_playback = &alc882_pcm_analog_playback; |
5690 | spec->stream_analog_capture = &alc882_pcm_analog_capture; | 6095 | spec->stream_analog_capture = &alc882_pcm_analog_capture; |
@@ -5715,6 +6120,10 @@ static int patch_alc882(struct hda_codec *codec) | |||
5715 | codec->patch_ops = alc_patch_ops; | 6120 | codec->patch_ops = alc_patch_ops; |
5716 | if (board_config == ALC882_AUTO) | 6121 | if (board_config == ALC882_AUTO) |
5717 | spec->init_hook = alc882_auto_init; | 6122 | spec->init_hook = alc882_auto_init; |
6123 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
6124 | if (!spec->loopback.amplist) | ||
6125 | spec->loopback.amplist = alc882_loopbacks; | ||
6126 | #endif | ||
5718 | 6127 | ||
5719 | return 0; | 6128 | return 0; |
5720 | } | 6129 | } |
@@ -5792,12 +6201,13 @@ static int alc883_mux_enum_put(struct snd_kcontrol *kcontrol, | |||
5792 | idx = ucontrol->value.enumerated.item[0]; | 6201 | idx = ucontrol->value.enumerated.item[0]; |
5793 | if (idx >= imux->num_items) | 6202 | if (idx >= imux->num_items) |
5794 | idx = imux->num_items - 1; | 6203 | idx = imux->num_items - 1; |
5795 | if (*cur_val == idx && !codec->in_resume) | 6204 | if (*cur_val == idx) |
5796 | return 0; | 6205 | return 0; |
5797 | for (i = 0; i < imux->num_items; i++) { | 6206 | for (i = 0; i < imux->num_items; i++) { |
5798 | unsigned int v = (i == idx) ? 0x7000 : 0x7080; | 6207 | unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; |
5799 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | 6208 | snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, |
5800 | v | (imux->items[i].index << 8)); | 6209 | imux->items[i].index, |
6210 | HDA_AMP_MUTE, v); | ||
5801 | } | 6211 | } |
5802 | *cur_val = idx; | 6212 | *cur_val = idx; |
5803 | return 1; | 6213 | return 1; |
@@ -5822,6 +6232,18 @@ static struct hda_verb alc883_3ST_ch2_init[] = { | |||
5822 | }; | 6232 | }; |
5823 | 6233 | ||
5824 | /* | 6234 | /* |
6235 | * 4ch mode | ||
6236 | */ | ||
6237 | static struct hda_verb alc883_3ST_ch4_init[] = { | ||
6238 | { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, | ||
6239 | { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
6240 | { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
6241 | { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
6242 | { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, | ||
6243 | { } /* end */ | ||
6244 | }; | ||
6245 | |||
6246 | /* | ||
5825 | * 6ch mode | 6247 | * 6ch mode |
5826 | */ | 6248 | */ |
5827 | static struct hda_verb alc883_3ST_ch6_init[] = { | 6249 | static struct hda_verb alc883_3ST_ch6_init[] = { |
@@ -5834,8 +6256,9 @@ static struct hda_verb alc883_3ST_ch6_init[] = { | |||
5834 | { } /* end */ | 6256 | { } /* end */ |
5835 | }; | 6257 | }; |
5836 | 6258 | ||
5837 | static struct hda_channel_mode alc883_3ST_6ch_modes[2] = { | 6259 | static struct hda_channel_mode alc883_3ST_6ch_modes[3] = { |
5838 | { 2, alc883_3ST_ch2_init }, | 6260 | { 2, alc883_3ST_ch2_init }, |
6261 | { 4, alc883_3ST_ch4_init }, | ||
5839 | { 6, alc883_3ST_ch6_init }, | 6262 | { 6, alc883_3ST_ch6_init }, |
5840 | }; | 6263 | }; |
5841 | 6264 | ||
@@ -6235,6 +6658,31 @@ static struct snd_kcontrol_new alc888_3st_hp_mixer[] = { | |||
6235 | { } /* end */ | 6658 | { } /* end */ |
6236 | }; | 6659 | }; |
6237 | 6660 | ||
6661 | static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { | ||
6662 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
6663 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), | ||
6664 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
6665 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
6666 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
6667 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
6668 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
6669 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
6670 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), | ||
6671 | HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), | ||
6672 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), | ||
6673 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), | ||
6674 | { | ||
6675 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
6676 | /* .name = "Capture Source", */ | ||
6677 | .name = "Input Source", | ||
6678 | .count = 2, | ||
6679 | .info = alc883_mux_enum_info, | ||
6680 | .get = alc883_mux_enum_get, | ||
6681 | .put = alc883_mux_enum_put, | ||
6682 | }, | ||
6683 | { } /* end */ | ||
6684 | }; | ||
6685 | |||
6238 | static struct snd_kcontrol_new alc883_chmode_mixer[] = { | 6686 | static struct snd_kcontrol_new alc883_chmode_mixer[] = { |
6239 | { | 6687 | { |
6240 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 6688 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -6270,11 +6718,12 @@ static struct hda_verb alc883_init_verbs[] = { | |||
6270 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | 6718 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
6271 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | 6719 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
6272 | 6720 | ||
6273 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 6721 | /* mute analog input loopbacks */ |
6274 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 6722 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
6275 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | 6723 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
6276 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | 6724 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, |
6277 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | 6725 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, |
6726 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
6278 | 6727 | ||
6279 | /* Front Pin: output 0 (0x0c) */ | 6728 | /* Front Pin: output 0 (0x0c) */ |
6280 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | 6729 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
@@ -6366,6 +6815,19 @@ static struct hda_verb alc888_lenovo_ms7195_verbs[] = { | |||
6366 | { } /* end */ | 6815 | { } /* end */ |
6367 | }; | 6816 | }; |
6368 | 6817 | ||
6818 | static struct hda_verb alc883_haier_w66_verbs[] = { | ||
6819 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
6820 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
6821 | |||
6822 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
6823 | |||
6824 | {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
6825 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
6826 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, | ||
6827 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
6828 | { } /* end */ | ||
6829 | }; | ||
6830 | |||
6369 | static struct hda_verb alc888_6st_hp_verbs[] = { | 6831 | static struct hda_verb alc888_6st_hp_verbs[] = { |
6370 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */ | 6832 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */ |
6371 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Rear : output 2 (0x0e) */ | 6833 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Rear : output 2 (0x0e) */ |
@@ -6409,15 +6871,10 @@ static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec) | |||
6409 | 6871 | ||
6410 | present = snd_hda_codec_read(codec, 0x1b, 0, | 6872 | present = snd_hda_codec_read(codec, 0x1b, 0, |
6411 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 6873 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; |
6412 | snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, | 6874 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, |
6413 | 0x80, present ? 0x80 : 0); | 6875 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); |
6414 | snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, | 6876 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, |
6415 | 0x80, present ? 0x80 : 0); | 6877 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); |
6416 | snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, | ||
6417 | 0x80, present ? 0x80 : 0); | ||
6418 | snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, | ||
6419 | 0x80, present ? 0x80 : 0); | ||
6420 | |||
6421 | } | 6878 | } |
6422 | 6879 | ||
6423 | /* toggle RCA according to the front-jack state */ | 6880 | /* toggle RCA according to the front-jack state */ |
@@ -6427,12 +6884,10 @@ static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec) | |||
6427 | 6884 | ||
6428 | present = snd_hda_codec_read(codec, 0x14, 0, | 6885 | present = snd_hda_codec_read(codec, 0x14, 0, |
6429 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 6886 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; |
6430 | snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, | 6887 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, |
6431 | 0x80, present ? 0x80 : 0); | 6888 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); |
6432 | snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, | ||
6433 | 0x80, present ? 0x80 : 0); | ||
6434 | |||
6435 | } | 6889 | } |
6890 | |||
6436 | static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec, | 6891 | static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec, |
6437 | unsigned int res) | 6892 | unsigned int res) |
6438 | { | 6893 | { |
@@ -6459,10 +6914,8 @@ static void alc883_medion_md2_automute(struct hda_codec *codec) | |||
6459 | 6914 | ||
6460 | present = snd_hda_codec_read(codec, 0x14, 0, | 6915 | present = snd_hda_codec_read(codec, 0x14, 0, |
6461 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 6916 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; |
6462 | snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, | 6917 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, |
6463 | 0x80, present ? 0x80 : 0); | 6918 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); |
6464 | snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, | ||
6465 | 0x80, present ? 0x80 : 0); | ||
6466 | } | 6919 | } |
6467 | 6920 | ||
6468 | static void alc883_medion_md2_unsol_event(struct hda_codec *codec, | 6921 | static void alc883_medion_md2_unsol_event(struct hda_codec *codec, |
@@ -6480,13 +6933,11 @@ static void alc883_tagra_automute(struct hda_codec *codec) | |||
6480 | 6933 | ||
6481 | present = snd_hda_codec_read(codec, 0x14, 0, | 6934 | present = snd_hda_codec_read(codec, 0x14, 0, |
6482 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 6935 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; |
6483 | bits = present ? 0x80 : 0; | 6936 | bits = present ? HDA_AMP_MUTE : 0; |
6484 | snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, | 6937 | snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, |
6485 | 0x80, bits); | 6938 | HDA_AMP_MUTE, bits); |
6486 | snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, | 6939 | snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, |
6487 | 0x80, bits); | 6940 | present ? 1 : 3); |
6488 | snd_hda_codec_write(codec, 1, 0, AC_VERB_SET_GPIO_DATA, | ||
6489 | present ? 1 : 3); | ||
6490 | } | 6941 | } |
6491 | 6942 | ||
6492 | static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res) | 6943 | static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res) |
@@ -6495,6 +6946,25 @@ static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res) | |||
6495 | alc883_tagra_automute(codec); | 6946 | alc883_tagra_automute(codec); |
6496 | } | 6947 | } |
6497 | 6948 | ||
6949 | static void alc883_haier_w66_automute(struct hda_codec *codec) | ||
6950 | { | ||
6951 | unsigned int present; | ||
6952 | unsigned char bits; | ||
6953 | |||
6954 | present = snd_hda_codec_read(codec, 0x1b, 0, | ||
6955 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
6956 | bits = present ? 0x80 : 0; | ||
6957 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
6958 | 0x80, bits); | ||
6959 | } | ||
6960 | |||
6961 | static void alc883_haier_w66_unsol_event(struct hda_codec *codec, | ||
6962 | unsigned int res) | ||
6963 | { | ||
6964 | if ((res >> 26) == ALC880_HP_EVENT) | ||
6965 | alc883_haier_w66_automute(codec); | ||
6966 | } | ||
6967 | |||
6498 | static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec) | 6968 | static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec) |
6499 | { | 6969 | { |
6500 | unsigned int present; | 6970 | unsigned int present; |
@@ -6502,11 +6972,9 @@ static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec) | |||
6502 | 6972 | ||
6503 | present = snd_hda_codec_read(codec, 0x14, 0, | 6973 | present = snd_hda_codec_read(codec, 0x14, 0, |
6504 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 6974 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; |
6505 | bits = present ? 0x80 : 0; | 6975 | bits = present ? HDA_AMP_MUTE : 0; |
6506 | snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, | 6976 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, |
6507 | 0x80, bits); | 6977 | HDA_AMP_MUTE, bits); |
6508 | snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, | ||
6509 | 0x80, bits); | ||
6510 | } | 6978 | } |
6511 | 6979 | ||
6512 | static void alc883_lenovo_101e_all_automute(struct hda_codec *codec) | 6980 | static void alc883_lenovo_101e_all_automute(struct hda_codec *codec) |
@@ -6516,15 +6984,11 @@ static void alc883_lenovo_101e_all_automute(struct hda_codec *codec) | |||
6516 | 6984 | ||
6517 | present = snd_hda_codec_read(codec, 0x1b, 0, | 6985 | present = snd_hda_codec_read(codec, 0x1b, 0, |
6518 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 6986 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; |
6519 | bits = present ? 0x80 : 0; | 6987 | bits = present ? HDA_AMP_MUTE : 0; |
6520 | snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, | 6988 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, |
6521 | 0x80, bits); | 6989 | HDA_AMP_MUTE, bits); |
6522 | snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, | 6990 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, |
6523 | 0x80, bits); | 6991 | HDA_AMP_MUTE, bits); |
6524 | snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, | ||
6525 | 0x80, bits); | ||
6526 | snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, | ||
6527 | 0x80, bits); | ||
6528 | } | 6992 | } |
6529 | 6993 | ||
6530 | static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec, | 6994 | static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec, |
@@ -6536,6 +7000,44 @@ static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec, | |||
6536 | alc883_lenovo_101e_ispeaker_automute(codec); | 7000 | alc883_lenovo_101e_ispeaker_automute(codec); |
6537 | } | 7001 | } |
6538 | 7002 | ||
7003 | /* toggle speaker-output according to the hp-jack state */ | ||
7004 | static void alc883_acer_aspire_automute(struct hda_codec *codec) | ||
7005 | { | ||
7006 | unsigned int present; | ||
7007 | |||
7008 | present = snd_hda_codec_read(codec, 0x14, 0, | ||
7009 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
7010 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, | ||
7011 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
7012 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, | ||
7013 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
7014 | } | ||
7015 | |||
7016 | static void alc883_acer_aspire_unsol_event(struct hda_codec *codec, | ||
7017 | unsigned int res) | ||
7018 | { | ||
7019 | if ((res >> 26) == ALC880_HP_EVENT) | ||
7020 | alc883_acer_aspire_automute(codec); | ||
7021 | } | ||
7022 | |||
7023 | static struct hda_verb alc883_acer_eapd_verbs[] = { | ||
7024 | /* HP Pin: output 0 (0x0c) */ | ||
7025 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
7026 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
7027 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
7028 | /* Front Pin: output 0 (0x0c) */ | ||
7029 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
7030 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
7031 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
7032 | {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
7033 | /* eanable EAPD on medion laptop */ | ||
7034 | {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, | ||
7035 | {0x20, AC_VERB_SET_PROC_COEF, 0x3050}, | ||
7036 | /* enable unsolicited event */ | ||
7037 | {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, | ||
7038 | { } | ||
7039 | }; | ||
7040 | |||
6539 | /* | 7041 | /* |
6540 | * generic initialization of ADC, input mixers and output mixers | 7042 | * generic initialization of ADC, input mixers and output mixers |
6541 | */ | 7043 | */ |
@@ -6548,17 +7050,17 @@ static struct hda_verb alc883_auto_init_verbs[] = { | |||
6548 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, | 7050 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, |
6549 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 7051 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
6550 | 7052 | ||
6551 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | 7053 | /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback |
6552 | * mixer widget | 7054 | * mixer widget |
6553 | * Note: PASD motherboards uses the Line In 2 as the input for | 7055 | * Note: PASD motherboards uses the Line In 2 as the input for |
6554 | * front panel mic (mic 2) | 7056 | * front panel mic (mic 2) |
6555 | */ | 7057 | */ |
6556 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ | 7058 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ |
6557 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 7059 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
6558 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 7060 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
6559 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | 7061 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, |
6560 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | 7062 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, |
6561 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | 7063 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, |
6562 | 7064 | ||
6563 | /* | 7065 | /* |
6564 | * Set up output mixers (0x0c - 0x0f) | 7066 | * Set up output mixers (0x0c - 0x0f) |
@@ -6621,6 +7123,10 @@ static struct snd_kcontrol_new alc883_capture_mixer[] = { | |||
6621 | { } /* end */ | 7123 | { } /* end */ |
6622 | }; | 7124 | }; |
6623 | 7125 | ||
7126 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
7127 | #define alc883_loopbacks alc880_loopbacks | ||
7128 | #endif | ||
7129 | |||
6624 | /* pcm configuration: identiacal with ALC880 */ | 7130 | /* pcm configuration: identiacal with ALC880 */ |
6625 | #define alc883_pcm_analog_playback alc880_pcm_analog_playback | 7131 | #define alc883_pcm_analog_playback alc880_pcm_analog_playback |
6626 | #define alc883_pcm_analog_capture alc880_pcm_analog_capture | 7132 | #define alc883_pcm_analog_capture alc880_pcm_analog_capture |
@@ -6638,12 +7144,14 @@ static const char *alc883_models[ALC883_MODEL_LAST] = { | |||
6638 | [ALC883_TARGA_DIG] = "targa-dig", | 7144 | [ALC883_TARGA_DIG] = "targa-dig", |
6639 | [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig", | 7145 | [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig", |
6640 | [ALC883_ACER] = "acer", | 7146 | [ALC883_ACER] = "acer", |
7147 | [ALC883_ACER_ASPIRE] = "acer-aspire", | ||
6641 | [ALC883_MEDION] = "medion", | 7148 | [ALC883_MEDION] = "medion", |
6642 | [ALC883_MEDION_MD2] = "medion-md2", | 7149 | [ALC883_MEDION_MD2] = "medion-md2", |
6643 | [ALC883_LAPTOP_EAPD] = "laptop-eapd", | 7150 | [ALC883_LAPTOP_EAPD] = "laptop-eapd", |
6644 | [ALC883_LENOVO_101E_2ch] = "lenovo-101e", | 7151 | [ALC883_LENOVO_101E_2ch] = "lenovo-101e", |
6645 | [ALC883_LENOVO_NB0763] = "lenovo-nb0763", | 7152 | [ALC883_LENOVO_NB0763] = "lenovo-nb0763", |
6646 | [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig", | 7153 | [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig", |
7154 | [ALC883_HAIER_W66] = "haier-w66", | ||
6647 | [ALC888_6ST_HP] = "6stack-hp", | 7155 | [ALC888_6ST_HP] = "6stack-hp", |
6648 | [ALC888_3ST_HP] = "3stack-hp", | 7156 | [ALC888_3ST_HP] = "3stack-hp", |
6649 | [ALC883_AUTO] = "auto", | 7157 | [ALC883_AUTO] = "auto", |
@@ -6669,10 +7177,14 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { | |||
6669 | SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG), | 7177 | SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG), |
6670 | SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG), | 7178 | SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG), |
6671 | SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG), | 7179 | SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG), |
7180 | SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG), | ||
6672 | SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG), | 7181 | SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG), |
6673 | SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG), | 7182 | SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG), |
6674 | SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG), | 7183 | SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG), |
6675 | SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG), | 7184 | SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG), |
7185 | SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE), | ||
7186 | SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE), | ||
7187 | SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE), | ||
6676 | SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), | 7188 | SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), |
6677 | SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch), | 7189 | SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch), |
6678 | SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION), | 7190 | SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION), |
@@ -6685,6 +7197,10 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { | |||
6685 | SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP), | 7197 | SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP), |
6686 | SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP), | 7198 | SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP), |
6687 | SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2), | 7199 | SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2), |
7200 | SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66), | ||
7201 | SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763), | ||
7202 | SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG), | ||
7203 | SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG), | ||
6688 | {} | 7204 | {} |
6689 | }; | 7205 | }; |
6690 | 7206 | ||
@@ -6771,8 +7287,7 @@ static struct alc_config_preset alc883_presets[] = { | |||
6771 | .init_hook = alc883_tagra_automute, | 7287 | .init_hook = alc883_tagra_automute, |
6772 | }, | 7288 | }, |
6773 | [ALC883_ACER] = { | 7289 | [ALC883_ACER] = { |
6774 | .mixers = { alc883_base_mixer, | 7290 | .mixers = { alc883_base_mixer }, |
6775 | alc883_chmode_mixer }, | ||
6776 | /* On TravelMate laptops, GPIO 0 enables the internal speaker | 7291 | /* On TravelMate laptops, GPIO 0 enables the internal speaker |
6777 | * and the headphone jack. Turn this on and rely on the | 7292 | * and the headphone jack. Turn this on and rely on the |
6778 | * standard mute methods whenever the user wants to turn | 7293 | * standard mute methods whenever the user wants to turn |
@@ -6787,6 +7302,20 @@ static struct alc_config_preset alc883_presets[] = { | |||
6787 | .channel_mode = alc883_3ST_2ch_modes, | 7302 | .channel_mode = alc883_3ST_2ch_modes, |
6788 | .input_mux = &alc883_capture_source, | 7303 | .input_mux = &alc883_capture_source, |
6789 | }, | 7304 | }, |
7305 | [ALC883_ACER_ASPIRE] = { | ||
7306 | .mixers = { alc883_acer_aspire_mixer }, | ||
7307 | .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs }, | ||
7308 | .num_dacs = ARRAY_SIZE(alc883_dac_nids), | ||
7309 | .dac_nids = alc883_dac_nids, | ||
7310 | .dig_out_nid = ALC883_DIGOUT_NID, | ||
7311 | .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), | ||
7312 | .adc_nids = alc883_adc_nids, | ||
7313 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), | ||
7314 | .channel_mode = alc883_3ST_2ch_modes, | ||
7315 | .input_mux = &alc883_capture_source, | ||
7316 | .unsol_event = alc883_acer_aspire_unsol_event, | ||
7317 | .init_hook = alc883_acer_aspire_automute, | ||
7318 | }, | ||
6790 | [ALC883_MEDION] = { | 7319 | [ALC883_MEDION] = { |
6791 | .mixers = { alc883_fivestack_mixer, | 7320 | .mixers = { alc883_fivestack_mixer, |
6792 | alc883_chmode_mixer }, | 7321 | alc883_chmode_mixer }, |
@@ -6815,8 +7344,7 @@ static struct alc_config_preset alc883_presets[] = { | |||
6815 | .init_hook = alc883_medion_md2_automute, | 7344 | .init_hook = alc883_medion_md2_automute, |
6816 | }, | 7345 | }, |
6817 | [ALC883_LAPTOP_EAPD] = { | 7346 | [ALC883_LAPTOP_EAPD] = { |
6818 | .mixers = { alc883_base_mixer, | 7347 | .mixers = { alc883_base_mixer }, |
6819 | alc883_chmode_mixer }, | ||
6820 | .init_verbs = { alc883_init_verbs, alc882_eapd_verbs }, | 7348 | .init_verbs = { alc883_init_verbs, alc882_eapd_verbs }, |
6821 | .num_dacs = ARRAY_SIZE(alc883_dac_nids), | 7349 | .num_dacs = ARRAY_SIZE(alc883_dac_nids), |
6822 | .dac_nids = alc883_dac_nids, | 7350 | .dac_nids = alc883_dac_nids, |
@@ -6867,6 +7395,20 @@ static struct alc_config_preset alc883_presets[] = { | |||
6867 | .input_mux = &alc883_capture_source, | 7395 | .input_mux = &alc883_capture_source, |
6868 | .unsol_event = alc883_lenovo_ms7195_unsol_event, | 7396 | .unsol_event = alc883_lenovo_ms7195_unsol_event, |
6869 | .init_hook = alc888_lenovo_ms7195_front_automute, | 7397 | .init_hook = alc888_lenovo_ms7195_front_automute, |
7398 | }, | ||
7399 | [ALC883_HAIER_W66] = { | ||
7400 | .mixers = { alc883_tagra_2ch_mixer}, | ||
7401 | .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs}, | ||
7402 | .num_dacs = ARRAY_SIZE(alc883_dac_nids), | ||
7403 | .dac_nids = alc883_dac_nids, | ||
7404 | .dig_out_nid = ALC883_DIGOUT_NID, | ||
7405 | .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), | ||
7406 | .adc_nids = alc883_adc_nids, | ||
7407 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), | ||
7408 | .channel_mode = alc883_3ST_2ch_modes, | ||
7409 | .input_mux = &alc883_capture_source, | ||
7410 | .unsol_event = alc883_haier_w66_unsol_event, | ||
7411 | .init_hook = alc883_haier_w66_automute, | ||
6870 | }, | 7412 | }, |
6871 | [ALC888_6ST_HP] = { | 7413 | [ALC888_6ST_HP] = { |
6872 | .mixers = { alc888_6st_hp_mixer, alc883_chmode_mixer }, | 7414 | .mixers = { alc888_6st_hp_mixer, alc883_chmode_mixer }, |
@@ -6977,12 +7519,19 @@ static int alc883_parse_auto_config(struct hda_codec *codec) | |||
6977 | 7519 | ||
6978 | if (err < 0) | 7520 | if (err < 0) |
6979 | return err; | 7521 | return err; |
6980 | else if (err > 0) | 7522 | else if (!err) |
6981 | /* hack - override the init verbs */ | 7523 | return 0; /* no config found */ |
6982 | spec->init_verbs[0] = alc883_auto_init_verbs; | 7524 | |
7525 | err = alc_auto_add_mic_boost(codec); | ||
7526 | if (err < 0) | ||
7527 | return err; | ||
7528 | |||
7529 | /* hack - override the init verbs */ | ||
7530 | spec->init_verbs[0] = alc883_auto_init_verbs; | ||
6983 | spec->mixers[spec->num_mixers] = alc883_capture_mixer; | 7531 | spec->mixers[spec->num_mixers] = alc883_capture_mixer; |
6984 | spec->num_mixers++; | 7532 | spec->num_mixers++; |
6985 | return err; | 7533 | |
7534 | return 1; /* config found */ | ||
6986 | } | 7535 | } |
6987 | 7536 | ||
6988 | /* additional initialization for auto-configuration model */ | 7537 | /* additional initialization for auto-configuration model */ |
@@ -7046,6 +7595,10 @@ static int patch_alc883(struct hda_codec *codec) | |||
7046 | codec->patch_ops = alc_patch_ops; | 7595 | codec->patch_ops = alc_patch_ops; |
7047 | if (board_config == ALC883_AUTO) | 7596 | if (board_config == ALC883_AUTO) |
7048 | spec->init_hook = alc883_auto_init; | 7597 | spec->init_hook = alc883_auto_init; |
7598 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
7599 | if (!spec->loopback.amplist) | ||
7600 | spec->loopback.amplist = alc883_loopbacks; | ||
7601 | #endif | ||
7049 | 7602 | ||
7050 | return 0; | 7603 | return 0; |
7051 | } | 7604 | } |
@@ -7156,9 +7709,46 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = { | |||
7156 | { } /* end */ | 7709 | { } /* end */ |
7157 | }; | 7710 | }; |
7158 | 7711 | ||
7712 | /* bind hp and internal speaker mute (with plug check) */ | ||
7713 | static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol, | ||
7714 | struct snd_ctl_elem_value *ucontrol) | ||
7715 | { | ||
7716 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
7717 | long *valp = ucontrol->value.integer.value; | ||
7718 | int change; | ||
7719 | |||
7720 | /* change hp mute */ | ||
7721 | change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, | ||
7722 | HDA_AMP_MUTE, | ||
7723 | valp[0] ? 0 : HDA_AMP_MUTE); | ||
7724 | change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, | ||
7725 | HDA_AMP_MUTE, | ||
7726 | valp[1] ? 0 : HDA_AMP_MUTE); | ||
7727 | if (change) { | ||
7728 | /* change speaker according to HP jack state */ | ||
7729 | struct alc_spec *spec = codec->spec; | ||
7730 | unsigned int mute; | ||
7731 | if (spec->jack_present) | ||
7732 | mute = HDA_AMP_MUTE; | ||
7733 | else | ||
7734 | mute = snd_hda_codec_amp_read(codec, 0x15, 0, | ||
7735 | HDA_OUTPUT, 0); | ||
7736 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
7737 | HDA_AMP_MUTE, mute); | ||
7738 | } | ||
7739 | return change; | ||
7740 | } | ||
7741 | |||
7159 | static struct snd_kcontrol_new alc262_sony_mixer[] = { | 7742 | static struct snd_kcontrol_new alc262_sony_mixer[] = { |
7160 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 7743 | HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
7161 | HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), | 7744 | { |
7745 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
7746 | .name = "Master Playback Switch", | ||
7747 | .info = snd_hda_mixer_amp_switch_info, | ||
7748 | .get = snd_hda_mixer_amp_switch_get, | ||
7749 | .put = alc262_sony_master_sw_put, | ||
7750 | .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), | ||
7751 | }, | ||
7162 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | 7752 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), |
7163 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | 7753 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), |
7164 | HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), | 7754 | HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), |
@@ -7194,17 +7784,17 @@ static struct hda_verb alc262_init_verbs[] = { | |||
7194 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, | 7784 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, |
7195 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 7785 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
7196 | 7786 | ||
7197 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | 7787 | /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback |
7198 | * mixer widget | 7788 | * mixer widget |
7199 | * Note: PASD motherboards uses the Line In 2 as the input for | 7789 | * Note: PASD motherboards uses the Line In 2 as the input for |
7200 | * front panel mic (mic 2) | 7790 | * front panel mic (mic 2) |
7201 | */ | 7791 | */ |
7202 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ | 7792 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ |
7203 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 7793 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
7204 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 7794 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
7205 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | 7795 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, |
7206 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | 7796 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, |
7207 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | 7797 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, |
7208 | 7798 | ||
7209 | /* | 7799 | /* |
7210 | * Set up output mixers (0x0c - 0x0e) | 7800 | * Set up output mixers (0x0c - 0x0e) |
@@ -7285,34 +7875,26 @@ static struct hda_verb alc262_sony_unsol_verbs[] = { | |||
7285 | }; | 7875 | }; |
7286 | 7876 | ||
7287 | /* mute/unmute internal speaker according to the hp jack and mute state */ | 7877 | /* mute/unmute internal speaker according to the hp jack and mute state */ |
7288 | static void alc262_hippo_automute(struct hda_codec *codec, int force) | 7878 | static void alc262_hippo_automute(struct hda_codec *codec) |
7289 | { | 7879 | { |
7290 | struct alc_spec *spec = codec->spec; | 7880 | struct alc_spec *spec = codec->spec; |
7291 | unsigned int mute; | 7881 | unsigned int mute; |
7882 | unsigned int present; | ||
7292 | 7883 | ||
7293 | if (force || !spec->sense_updated) { | 7884 | /* need to execute and sync at first */ |
7294 | unsigned int present; | 7885 | snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0); |
7295 | /* need to execute and sync at first */ | 7886 | present = snd_hda_codec_read(codec, 0x15, 0, |
7296 | snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0); | 7887 | AC_VERB_GET_PIN_SENSE, 0); |
7297 | present = snd_hda_codec_read(codec, 0x15, 0, | 7888 | spec->jack_present = (present & 0x80000000) != 0; |
7298 | AC_VERB_GET_PIN_SENSE, 0); | ||
7299 | spec->jack_present = (present & 0x80000000) != 0; | ||
7300 | spec->sense_updated = 1; | ||
7301 | } | ||
7302 | if (spec->jack_present) { | 7889 | if (spec->jack_present) { |
7303 | /* mute internal speaker */ | 7890 | /* mute internal speaker */ |
7304 | snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, | 7891 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, |
7305 | 0x80, 0x80); | 7892 | HDA_AMP_MUTE, HDA_AMP_MUTE); |
7306 | snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, | ||
7307 | 0x80, 0x80); | ||
7308 | } else { | 7893 | } else { |
7309 | /* unmute internal speaker if necessary */ | 7894 | /* unmute internal speaker if necessary */ |
7310 | mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0); | 7895 | mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0); |
7311 | snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, | 7896 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, |
7312 | 0x80, mute & 0x80); | 7897 | HDA_AMP_MUTE, mute); |
7313 | mute = snd_hda_codec_amp_read(codec, 0x15, 1, HDA_OUTPUT, 0); | ||
7314 | snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, | ||
7315 | 0x80, mute & 0x80); | ||
7316 | } | 7898 | } |
7317 | } | 7899 | } |
7318 | 7900 | ||
@@ -7322,37 +7904,27 @@ static void alc262_hippo_unsol_event(struct hda_codec *codec, | |||
7322 | { | 7904 | { |
7323 | if ((res >> 26) != ALC880_HP_EVENT) | 7905 | if ((res >> 26) != ALC880_HP_EVENT) |
7324 | return; | 7906 | return; |
7325 | alc262_hippo_automute(codec, 1); | 7907 | alc262_hippo_automute(codec); |
7326 | } | 7908 | } |
7327 | 7909 | ||
7328 | static void alc262_hippo1_automute(struct hda_codec *codec, int force) | 7910 | static void alc262_hippo1_automute(struct hda_codec *codec) |
7329 | { | 7911 | { |
7330 | struct alc_spec *spec = codec->spec; | ||
7331 | unsigned int mute; | 7912 | unsigned int mute; |
7913 | unsigned int present; | ||
7332 | 7914 | ||
7333 | if (force || !spec->sense_updated) { | 7915 | snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0); |
7334 | unsigned int present; | 7916 | present = snd_hda_codec_read(codec, 0x1b, 0, |
7335 | /* need to execute and sync at first */ | 7917 | AC_VERB_GET_PIN_SENSE, 0); |
7336 | snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0); | 7918 | present = (present & 0x80000000) != 0; |
7337 | present = snd_hda_codec_read(codec, 0x1b, 0, | 7919 | if (present) { |
7338 | AC_VERB_GET_PIN_SENSE, 0); | ||
7339 | spec->jack_present = (present & 0x80000000) != 0; | ||
7340 | spec->sense_updated = 1; | ||
7341 | } | ||
7342 | if (spec->jack_present) { | ||
7343 | /* mute internal speaker */ | 7920 | /* mute internal speaker */ |
7344 | snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, | 7921 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, |
7345 | 0x80, 0x80); | 7922 | HDA_AMP_MUTE, HDA_AMP_MUTE); |
7346 | snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, | ||
7347 | 0x80, 0x80); | ||
7348 | } else { | 7923 | } else { |
7349 | /* unmute internal speaker if necessary */ | 7924 | /* unmute internal speaker if necessary */ |
7350 | mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0); | 7925 | mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0); |
7351 | snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, | 7926 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, |
7352 | 0x80, mute & 0x80); | 7927 | HDA_AMP_MUTE, mute); |
7353 | mute = snd_hda_codec_amp_read(codec, 0x1b, 1, HDA_OUTPUT, 0); | ||
7354 | snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, | ||
7355 | 0x80, mute & 0x80); | ||
7356 | } | 7928 | } |
7357 | } | 7929 | } |
7358 | 7930 | ||
@@ -7362,7 +7934,7 @@ static void alc262_hippo1_unsol_event(struct hda_codec *codec, | |||
7362 | { | 7934 | { |
7363 | if ((res >> 26) != ALC880_HP_EVENT) | 7935 | if ((res >> 26) != ALC880_HP_EVENT) |
7364 | return; | 7936 | return; |
7365 | alc262_hippo1_automute(codec, 1); | 7937 | alc262_hippo1_automute(codec); |
7366 | } | 7938 | } |
7367 | 7939 | ||
7368 | /* | 7940 | /* |
@@ -7379,9 +7951,10 @@ static struct hda_verb alc262_fujitsu_unsol_verbs[] = { | |||
7379 | }; | 7951 | }; |
7380 | 7952 | ||
7381 | static struct hda_input_mux alc262_fujitsu_capture_source = { | 7953 | static struct hda_input_mux alc262_fujitsu_capture_source = { |
7382 | .num_items = 2, | 7954 | .num_items = 3, |
7383 | .items = { | 7955 | .items = { |
7384 | { "Mic", 0x0 }, | 7956 | { "Mic", 0x0 }, |
7957 | { "Int Mic", 0x1 }, | ||
7385 | { "CD", 0x4 }, | 7958 | { "CD", 0x4 }, |
7386 | }, | 7959 | }, |
7387 | }; | 7960 | }; |
@@ -7390,13 +7963,23 @@ static struct hda_input_mux alc262_HP_capture_source = { | |||
7390 | .num_items = 5, | 7963 | .num_items = 5, |
7391 | .items = { | 7964 | .items = { |
7392 | { "Mic", 0x0 }, | 7965 | { "Mic", 0x0 }, |
7393 | { "Front Mic", 0x3 }, | 7966 | { "Front Mic", 0x1 }, |
7394 | { "Line", 0x2 }, | 7967 | { "Line", 0x2 }, |
7395 | { "CD", 0x4 }, | 7968 | { "CD", 0x4 }, |
7396 | { "AUX IN", 0x6 }, | 7969 | { "AUX IN", 0x6 }, |
7397 | }, | 7970 | }, |
7398 | }; | 7971 | }; |
7399 | 7972 | ||
7973 | static struct hda_input_mux alc262_HP_D7000_capture_source = { | ||
7974 | .num_items = 4, | ||
7975 | .items = { | ||
7976 | { "Mic", 0x0 }, | ||
7977 | { "Front Mic", 0x2 }, | ||
7978 | { "Line", 0x1 }, | ||
7979 | { "CD", 0x4 }, | ||
7980 | }, | ||
7981 | }; | ||
7982 | |||
7400 | /* mute/unmute internal speaker according to the hp jack and mute state */ | 7983 | /* mute/unmute internal speaker according to the hp jack and mute state */ |
7401 | static void alc262_fujitsu_automute(struct hda_codec *codec, int force) | 7984 | static void alc262_fujitsu_automute(struct hda_codec *codec, int force) |
7402 | { | 7985 | { |
@@ -7414,18 +7997,13 @@ static void alc262_fujitsu_automute(struct hda_codec *codec, int force) | |||
7414 | } | 7997 | } |
7415 | if (spec->jack_present) { | 7998 | if (spec->jack_present) { |
7416 | /* mute internal speaker */ | 7999 | /* mute internal speaker */ |
7417 | snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, | 8000 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, |
7418 | 0x80, 0x80); | 8001 | HDA_AMP_MUTE, HDA_AMP_MUTE); |
7419 | snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, | ||
7420 | 0x80, 0x80); | ||
7421 | } else { | 8002 | } else { |
7422 | /* unmute internal speaker if necessary */ | 8003 | /* unmute internal speaker if necessary */ |
7423 | mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0); | 8004 | mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0); |
7424 | snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, | 8005 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, |
7425 | 0x80, mute & 0x80); | 8006 | HDA_AMP_MUTE, mute); |
7426 | mute = snd_hda_codec_amp_read(codec, 0x14, 1, HDA_OUTPUT, 0); | ||
7427 | snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, | ||
7428 | 0x80, mute & 0x80); | ||
7429 | } | 8007 | } |
7430 | } | 8008 | } |
7431 | 8009 | ||
@@ -7439,23 +8017,14 @@ static void alc262_fujitsu_unsol_event(struct hda_codec *codec, | |||
7439 | } | 8017 | } |
7440 | 8018 | ||
7441 | /* bind volumes of both NID 0x0c and 0x0d */ | 8019 | /* bind volumes of both NID 0x0c and 0x0d */ |
7442 | static int alc262_fujitsu_master_vol_put(struct snd_kcontrol *kcontrol, | 8020 | static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = { |
7443 | struct snd_ctl_elem_value *ucontrol) | 8021 | .ops = &snd_hda_bind_vol, |
7444 | { | 8022 | .values = { |
7445 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 8023 | HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT), |
7446 | long *valp = ucontrol->value.integer.value; | 8024 | HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT), |
7447 | int change; | 8025 | 0 |
7448 | 8026 | }, | |
7449 | change = snd_hda_codec_amp_update(codec, 0x0c, 0, HDA_OUTPUT, 0, | 8027 | }; |
7450 | 0x7f, valp[0] & 0x7f); | ||
7451 | change |= snd_hda_codec_amp_update(codec, 0x0c, 1, HDA_OUTPUT, 0, | ||
7452 | 0x7f, valp[1] & 0x7f); | ||
7453 | snd_hda_codec_amp_update(codec, 0x0d, 0, HDA_OUTPUT, 0, | ||
7454 | 0x7f, valp[0] & 0x7f); | ||
7455 | snd_hda_codec_amp_update(codec, 0x0d, 1, HDA_OUTPUT, 0, | ||
7456 | 0x7f, valp[1] & 0x7f); | ||
7457 | return change; | ||
7458 | } | ||
7459 | 8028 | ||
7460 | /* bind hp and internal speaker mute (with plug check) */ | 8029 | /* bind hp and internal speaker mute (with plug check) */ |
7461 | static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol, | 8030 | static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol, |
@@ -7466,24 +8035,18 @@ static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol, | |||
7466 | int change; | 8035 | int change; |
7467 | 8036 | ||
7468 | change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, | 8037 | change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, |
7469 | 0x80, valp[0] ? 0 : 0x80); | 8038 | HDA_AMP_MUTE, |
8039 | valp[0] ? 0 : HDA_AMP_MUTE); | ||
7470 | change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, | 8040 | change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, |
7471 | 0x80, valp[1] ? 0 : 0x80); | 8041 | HDA_AMP_MUTE, |
7472 | if (change || codec->in_resume) | 8042 | valp[1] ? 0 : HDA_AMP_MUTE); |
7473 | alc262_fujitsu_automute(codec, codec->in_resume); | 8043 | if (change) |
8044 | alc262_fujitsu_automute(codec, 0); | ||
7474 | return change; | 8045 | return change; |
7475 | } | 8046 | } |
7476 | 8047 | ||
7477 | static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { | 8048 | static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { |
7478 | { | 8049 | HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), |
7479 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
7480 | .name = "Master Playback Volume", | ||
7481 | .info = snd_hda_mixer_amp_volume_info, | ||
7482 | .get = snd_hda_mixer_amp_volume_get, | ||
7483 | .put = alc262_fujitsu_master_vol_put, | ||
7484 | .tlv = { .c = snd_hda_mixer_amp_tlv }, | ||
7485 | .private_value = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT), | ||
7486 | }, | ||
7487 | { | 8050 | { |
7488 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 8051 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
7489 | .name = "Master Playback Switch", | 8052 | .name = "Master Playback Switch", |
@@ -7497,6 +8060,9 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { | |||
7497 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | 8060 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), |
7498 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | 8061 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), |
7499 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | 8062 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), |
8063 | HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT), | ||
8064 | HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | ||
8065 | HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | ||
7500 | { } /* end */ | 8066 | { } /* end */ |
7501 | }; | 8067 | }; |
7502 | 8068 | ||
@@ -7611,17 +8177,17 @@ static struct hda_verb alc262_volume_init_verbs[] = { | |||
7611 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, | 8177 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, |
7612 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 8178 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
7613 | 8179 | ||
7614 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | 8180 | /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback |
7615 | * mixer widget | 8181 | * mixer widget |
7616 | * Note: PASD motherboards uses the Line In 2 as the input for | 8182 | * Note: PASD motherboards uses the Line In 2 as the input for |
7617 | * front panel mic (mic 2) | 8183 | * front panel mic (mic 2) |
7618 | */ | 8184 | */ |
7619 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ | 8185 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ |
7620 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 8186 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
7621 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 8187 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
7622 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | 8188 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, |
7623 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | 8189 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, |
7624 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | 8190 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, |
7625 | 8191 | ||
7626 | /* | 8192 | /* |
7627 | * Set up output mixers (0x0c - 0x0f) | 8193 | * Set up output mixers (0x0c - 0x0f) |
@@ -7672,19 +8238,19 @@ static struct hda_verb alc262_HP_BPC_init_verbs[] = { | |||
7672 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, | 8238 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, |
7673 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 8239 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
7674 | 8240 | ||
7675 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | 8241 | /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback |
7676 | * mixer widget | 8242 | * mixer widget |
7677 | * Note: PASD motherboards uses the Line In 2 as the input for | 8243 | * Note: PASD motherboards uses the Line In 2 as the input for |
7678 | * front panel mic (mic 2) | 8244 | * front panel mic (mic 2) |
7679 | */ | 8245 | */ |
7680 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ | 8246 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ |
7681 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 8247 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
7682 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 8248 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
7683 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | 8249 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, |
7684 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | 8250 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, |
7685 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | 8251 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, |
7686 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, | 8252 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, |
7687 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)}, | 8253 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, |
7688 | 8254 | ||
7689 | /* | 8255 | /* |
7690 | * Set up output mixers (0x0c - 0x0e) | 8256 | * Set up output mixers (0x0c - 0x0e) |
@@ -7759,20 +8325,20 @@ static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = { | |||
7759 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, | 8325 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, |
7760 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 8326 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
7761 | 8327 | ||
7762 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | 8328 | /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback |
7763 | * mixer widget | 8329 | * mixer widget |
7764 | * Note: PASD motherboards uses the Line In 2 as the input for front | 8330 | * Note: PASD motherboards uses the Line In 2 as the input for front |
7765 | * panel mic (mic 2) | 8331 | * panel mic (mic 2) |
7766 | */ | 8332 | */ |
7767 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ | 8333 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ |
7768 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 8334 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
7769 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 8335 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
7770 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | 8336 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, |
7771 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | 8337 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, |
7772 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | 8338 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, |
7773 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, | 8339 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, |
7774 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)}, | 8340 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, |
7775 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(7)}, | 8341 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, |
7776 | /* | 8342 | /* |
7777 | * Set up output mixers (0x0c - 0x0e) | 8343 | * Set up output mixers (0x0c - 0x0e) |
7778 | */ | 8344 | */ |
@@ -7842,6 +8408,10 @@ static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = { | |||
7842 | { } | 8408 | { } |
7843 | }; | 8409 | }; |
7844 | 8410 | ||
8411 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
8412 | #define alc262_loopbacks alc880_loopbacks | ||
8413 | #endif | ||
8414 | |||
7845 | /* pcm configuration: identiacal with ALC880 */ | 8415 | /* pcm configuration: identiacal with ALC880 */ |
7846 | #define alc262_pcm_analog_playback alc880_pcm_analog_playback | 8416 | #define alc262_pcm_analog_playback alc880_pcm_analog_playback |
7847 | #define alc262_pcm_analog_capture alc880_pcm_analog_capture | 8417 | #define alc262_pcm_analog_capture alc880_pcm_analog_capture |
@@ -7884,6 +8454,10 @@ static int alc262_parse_auto_config(struct hda_codec *codec) | |||
7884 | spec->num_mux_defs = 1; | 8454 | spec->num_mux_defs = 1; |
7885 | spec->input_mux = &spec->private_imux; | 8455 | spec->input_mux = &spec->private_imux; |
7886 | 8456 | ||
8457 | err = alc_auto_add_mic_boost(codec); | ||
8458 | if (err < 0) | ||
8459 | return err; | ||
8460 | |||
7887 | return 1; | 8461 | return 1; |
7888 | } | 8462 | } |
7889 | 8463 | ||
@@ -7939,6 +8513,7 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = { | |||
7939 | SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1), | 8513 | SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1), |
7940 | SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8), | 8514 | SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8), |
7941 | SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31), | 8515 | SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31), |
8516 | SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), | ||
7942 | SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD), | 8517 | SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD), |
7943 | SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD), | 8518 | SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD), |
7944 | SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD), | 8519 | SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD), |
@@ -7967,6 +8542,7 @@ static struct alc_config_preset alc262_presets[] = { | |||
7967 | .channel_mode = alc262_modes, | 8542 | .channel_mode = alc262_modes, |
7968 | .input_mux = &alc262_capture_source, | 8543 | .input_mux = &alc262_capture_source, |
7969 | .unsol_event = alc262_hippo_unsol_event, | 8544 | .unsol_event = alc262_hippo_unsol_event, |
8545 | .init_hook = alc262_hippo_automute, | ||
7970 | }, | 8546 | }, |
7971 | [ALC262_HIPPO_1] = { | 8547 | [ALC262_HIPPO_1] = { |
7972 | .mixers = { alc262_hippo1_mixer }, | 8548 | .mixers = { alc262_hippo1_mixer }, |
@@ -7979,10 +8555,12 @@ static struct alc_config_preset alc262_presets[] = { | |||
7979 | .channel_mode = alc262_modes, | 8555 | .channel_mode = alc262_modes, |
7980 | .input_mux = &alc262_capture_source, | 8556 | .input_mux = &alc262_capture_source, |
7981 | .unsol_event = alc262_hippo1_unsol_event, | 8557 | .unsol_event = alc262_hippo1_unsol_event, |
8558 | .init_hook = alc262_hippo1_automute, | ||
7982 | }, | 8559 | }, |
7983 | [ALC262_FUJITSU] = { | 8560 | [ALC262_FUJITSU] = { |
7984 | .mixers = { alc262_fujitsu_mixer }, | 8561 | .mixers = { alc262_fujitsu_mixer }, |
7985 | .init_verbs = { alc262_init_verbs, alc262_fujitsu_unsol_verbs }, | 8562 | .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs, |
8563 | alc262_fujitsu_unsol_verbs }, | ||
7986 | .num_dacs = ARRAY_SIZE(alc262_dac_nids), | 8564 | .num_dacs = ARRAY_SIZE(alc262_dac_nids), |
7987 | .dac_nids = alc262_dac_nids, | 8565 | .dac_nids = alc262_dac_nids, |
7988 | .hp_nid = 0x03, | 8566 | .hp_nid = 0x03, |
@@ -8010,7 +8588,7 @@ static struct alc_config_preset alc262_presets[] = { | |||
8010 | .hp_nid = 0x03, | 8588 | .hp_nid = 0x03, |
8011 | .num_channel_mode = ARRAY_SIZE(alc262_modes), | 8589 | .num_channel_mode = ARRAY_SIZE(alc262_modes), |
8012 | .channel_mode = alc262_modes, | 8590 | .channel_mode = alc262_modes, |
8013 | .input_mux = &alc262_HP_capture_source, | 8591 | .input_mux = &alc262_HP_D7000_capture_source, |
8014 | }, | 8592 | }, |
8015 | [ALC262_HP_BPC_D7000_WL] = { | 8593 | [ALC262_HP_BPC_D7000_WL] = { |
8016 | .mixers = { alc262_HP_BPC_WildWest_mixer, | 8594 | .mixers = { alc262_HP_BPC_WildWest_mixer, |
@@ -8021,7 +8599,7 @@ static struct alc_config_preset alc262_presets[] = { | |||
8021 | .hp_nid = 0x03, | 8599 | .hp_nid = 0x03, |
8022 | .num_channel_mode = ARRAY_SIZE(alc262_modes), | 8600 | .num_channel_mode = ARRAY_SIZE(alc262_modes), |
8023 | .channel_mode = alc262_modes, | 8601 | .channel_mode = alc262_modes, |
8024 | .input_mux = &alc262_HP_capture_source, | 8602 | .input_mux = &alc262_HP_D7000_capture_source, |
8025 | }, | 8603 | }, |
8026 | [ALC262_BENQ_ED8] = { | 8604 | [ALC262_BENQ_ED8] = { |
8027 | .mixers = { alc262_base_mixer }, | 8605 | .mixers = { alc262_base_mixer }, |
@@ -8043,6 +8621,7 @@ static struct alc_config_preset alc262_presets[] = { | |||
8043 | .channel_mode = alc262_modes, | 8621 | .channel_mode = alc262_modes, |
8044 | .input_mux = &alc262_capture_source, | 8622 | .input_mux = &alc262_capture_source, |
8045 | .unsol_event = alc262_hippo_unsol_event, | 8623 | .unsol_event = alc262_hippo_unsol_event, |
8624 | .init_hook = alc262_hippo_automute, | ||
8046 | }, | 8625 | }, |
8047 | [ALC262_BENQ_T31] = { | 8626 | [ALC262_BENQ_T31] = { |
8048 | .mixers = { alc262_benq_t31_mixer }, | 8627 | .mixers = { alc262_benq_t31_mixer }, |
@@ -8054,6 +8633,7 @@ static struct alc_config_preset alc262_presets[] = { | |||
8054 | .channel_mode = alc262_modes, | 8633 | .channel_mode = alc262_modes, |
8055 | .input_mux = &alc262_capture_source, | 8634 | .input_mux = &alc262_capture_source, |
8056 | .unsol_event = alc262_hippo_unsol_event, | 8635 | .unsol_event = alc262_hippo_unsol_event, |
8636 | .init_hook = alc262_hippo_automute, | ||
8057 | }, | 8637 | }, |
8058 | }; | 8638 | }; |
8059 | 8639 | ||
@@ -8139,6 +8719,10 @@ static int patch_alc262(struct hda_codec *codec) | |||
8139 | codec->patch_ops = alc_patch_ops; | 8719 | codec->patch_ops = alc_patch_ops; |
8140 | if (board_config == ALC262_AUTO) | 8720 | if (board_config == ALC262_AUTO) |
8141 | spec->init_hook = alc262_auto_init; | 8721 | spec->init_hook = alc262_auto_init; |
8722 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
8723 | if (!spec->loopback.amplist) | ||
8724 | spec->loopback.amplist = alc262_loopbacks; | ||
8725 | #endif | ||
8142 | 8726 | ||
8143 | return 0; | 8727 | return 0; |
8144 | } | 8728 | } |
@@ -8170,9 +8754,125 @@ static struct snd_kcontrol_new alc268_base_mixer[] = { | |||
8170 | HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), | 8754 | HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), |
8171 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), | 8755 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), |
8172 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), | 8756 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), |
8757 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
8758 | HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), | ||
8759 | HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT), | ||
8760 | { } | ||
8761 | }; | ||
8762 | |||
8763 | static struct hda_verb alc268_eapd_verbs[] = { | ||
8764 | {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, | ||
8765 | {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, | ||
8766 | { } | ||
8767 | }; | ||
8768 | |||
8769 | /* Toshiba specific */ | ||
8770 | #define alc268_toshiba_automute alc262_hippo_automute | ||
8771 | |||
8772 | static struct hda_verb alc268_toshiba_verbs[] = { | ||
8773 | {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, | ||
8774 | { } /* end */ | ||
8775 | }; | ||
8776 | |||
8777 | /* Acer specific */ | ||
8778 | /* bind volumes of both NID 0x02 and 0x03 */ | ||
8779 | static struct hda_bind_ctls alc268_acer_bind_master_vol = { | ||
8780 | .ops = &snd_hda_bind_vol, | ||
8781 | .values = { | ||
8782 | HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), | ||
8783 | HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT), | ||
8784 | 0 | ||
8785 | }, | ||
8786 | }; | ||
8787 | |||
8788 | /* mute/unmute internal speaker according to the hp jack and mute state */ | ||
8789 | static void alc268_acer_automute(struct hda_codec *codec, int force) | ||
8790 | { | ||
8791 | struct alc_spec *spec = codec->spec; | ||
8792 | unsigned int mute; | ||
8793 | |||
8794 | if (force || !spec->sense_updated) { | ||
8795 | unsigned int present; | ||
8796 | present = snd_hda_codec_read(codec, 0x14, 0, | ||
8797 | AC_VERB_GET_PIN_SENSE, 0); | ||
8798 | spec->jack_present = (present & 0x80000000) != 0; | ||
8799 | spec->sense_updated = 1; | ||
8800 | } | ||
8801 | if (spec->jack_present) | ||
8802 | mute = HDA_AMP_MUTE; /* mute internal speaker */ | ||
8803 | else /* unmute internal speaker if necessary */ | ||
8804 | mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0); | ||
8805 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, | ||
8806 | HDA_AMP_MUTE, mute); | ||
8807 | } | ||
8808 | |||
8809 | |||
8810 | /* bind hp and internal speaker mute (with plug check) */ | ||
8811 | static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol, | ||
8812 | struct snd_ctl_elem_value *ucontrol) | ||
8813 | { | ||
8814 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
8815 | long *valp = ucontrol->value.integer.value; | ||
8816 | int change; | ||
8817 | |||
8818 | change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, | ||
8819 | HDA_AMP_MUTE, | ||
8820 | valp[0] ? 0 : HDA_AMP_MUTE); | ||
8821 | change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, | ||
8822 | HDA_AMP_MUTE, | ||
8823 | valp[1] ? 0 : HDA_AMP_MUTE); | ||
8824 | if (change) | ||
8825 | alc268_acer_automute(codec, 0); | ||
8826 | return change; | ||
8827 | } | ||
8828 | |||
8829 | static struct snd_kcontrol_new alc268_acer_mixer[] = { | ||
8830 | /* output mixer control */ | ||
8831 | HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), | ||
8832 | { | ||
8833 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
8834 | .name = "Master Playback Switch", | ||
8835 | .info = snd_hda_mixer_amp_switch_info, | ||
8836 | .get = snd_hda_mixer_amp_switch_get, | ||
8837 | .put = alc268_acer_master_sw_put, | ||
8838 | .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), | ||
8839 | }, | ||
8840 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
8841 | HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT), | ||
8842 | HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT), | ||
8173 | { } | 8843 | { } |
8174 | }; | 8844 | }; |
8175 | 8845 | ||
8846 | static struct hda_verb alc268_acer_verbs[] = { | ||
8847 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
8848 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
8849 | |||
8850 | {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, | ||
8851 | { } | ||
8852 | }; | ||
8853 | |||
8854 | /* unsolicited event for HP jack sensing */ | ||
8855 | static void alc268_toshiba_unsol_event(struct hda_codec *codec, | ||
8856 | unsigned int res) | ||
8857 | { | ||
8858 | if ((res >> 26) != ALC880_HP_EVENT) | ||
8859 | return; | ||
8860 | alc268_toshiba_automute(codec); | ||
8861 | } | ||
8862 | |||
8863 | static void alc268_acer_unsol_event(struct hda_codec *codec, | ||
8864 | unsigned int res) | ||
8865 | { | ||
8866 | if ((res >> 26) != ALC880_HP_EVENT) | ||
8867 | return; | ||
8868 | alc268_acer_automute(codec, 1); | ||
8869 | } | ||
8870 | |||
8871 | static void alc268_acer_init_hook(struct hda_codec *codec) | ||
8872 | { | ||
8873 | alc268_acer_automute(codec, 1); | ||
8874 | } | ||
8875 | |||
8176 | /* | 8876 | /* |
8177 | * generic initialization of ADC, input mixers and output mixers | 8877 | * generic initialization of ADC, input mixers and output mixers |
8178 | */ | 8878 | */ |
@@ -8282,14 +8982,16 @@ static int alc268_mux_enum_put(struct snd_kcontrol *kcontrol, | |||
8282 | idx = ucontrol->value.enumerated.item[0]; | 8982 | idx = ucontrol->value.enumerated.item[0]; |
8283 | if (idx >= imux->num_items) | 8983 | if (idx >= imux->num_items) |
8284 | idx = imux->num_items - 1; | 8984 | idx = imux->num_items - 1; |
8285 | if (*cur_val == idx && !codec->in_resume) | 8985 | if (*cur_val == idx) |
8286 | return 0; | 8986 | return 0; |
8287 | for (i = 0; i < imux->num_items; i++) { | 8987 | for (i = 0; i < imux->num_items; i++) { |
8288 | unsigned int v = (i == idx) ? 0x7000 : 0x7080; | 8988 | unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; |
8289 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | 8989 | snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, |
8290 | v | (imux->items[i].index << 8)); | 8990 | imux->items[i].index, |
8291 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, | 8991 | HDA_AMP_MUTE, v); |
8292 | idx ); | 8992 | snd_hda_codec_write_cache(codec, nid, 0, |
8993 | AC_VERB_SET_CONNECT_SEL, | ||
8994 | idx ); | ||
8293 | } | 8995 | } |
8294 | *cur_val = idx; | 8996 | *cur_val = idx; |
8295 | return 1; | 8997 | return 1; |
@@ -8530,6 +9232,10 @@ static int alc268_parse_auto_config(struct hda_codec *codec) | |||
8530 | spec->num_mux_defs = 1; | 9232 | spec->num_mux_defs = 1; |
8531 | spec->input_mux = &spec->private_imux; | 9233 | spec->input_mux = &spec->private_imux; |
8532 | 9234 | ||
9235 | err = alc_auto_add_mic_boost(codec); | ||
9236 | if (err < 0) | ||
9237 | return err; | ||
9238 | |||
8533 | return 1; | 9239 | return 1; |
8534 | } | 9240 | } |
8535 | 9241 | ||
@@ -8551,11 +9257,19 @@ static void alc268_auto_init(struct hda_codec *codec) | |||
8551 | */ | 9257 | */ |
8552 | static const char *alc268_models[ALC268_MODEL_LAST] = { | 9258 | static const char *alc268_models[ALC268_MODEL_LAST] = { |
8553 | [ALC268_3ST] = "3stack", | 9259 | [ALC268_3ST] = "3stack", |
9260 | [ALC268_TOSHIBA] = "toshiba", | ||
9261 | [ALC268_ACER] = "acer", | ||
8554 | [ALC268_AUTO] = "auto", | 9262 | [ALC268_AUTO] = "auto", |
8555 | }; | 9263 | }; |
8556 | 9264 | ||
8557 | static struct snd_pci_quirk alc268_cfg_tbl[] = { | 9265 | static struct snd_pci_quirk alc268_cfg_tbl[] = { |
8558 | SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST), | 9266 | SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST), |
9267 | SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA), | ||
9268 | SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA), | ||
9269 | SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA), | ||
9270 | SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER), | ||
9271 | SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER), | ||
9272 | SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER), | ||
8559 | {} | 9273 | {} |
8560 | }; | 9274 | }; |
8561 | 9275 | ||
@@ -8573,6 +9287,37 @@ static struct alc_config_preset alc268_presets[] = { | |||
8573 | .channel_mode = alc268_modes, | 9287 | .channel_mode = alc268_modes, |
8574 | .input_mux = &alc268_capture_source, | 9288 | .input_mux = &alc268_capture_source, |
8575 | }, | 9289 | }, |
9290 | [ALC268_TOSHIBA] = { | ||
9291 | .mixers = { alc268_base_mixer, alc268_capture_alt_mixer }, | ||
9292 | .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, | ||
9293 | alc268_toshiba_verbs }, | ||
9294 | .num_dacs = ARRAY_SIZE(alc268_dac_nids), | ||
9295 | .dac_nids = alc268_dac_nids, | ||
9296 | .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), | ||
9297 | .adc_nids = alc268_adc_nids_alt, | ||
9298 | .hp_nid = 0x03, | ||
9299 | .num_channel_mode = ARRAY_SIZE(alc268_modes), | ||
9300 | .channel_mode = alc268_modes, | ||
9301 | .input_mux = &alc268_capture_source, | ||
9302 | .input_mux = &alc268_capture_source, | ||
9303 | .unsol_event = alc268_toshiba_unsol_event, | ||
9304 | .init_hook = alc268_toshiba_automute, | ||
9305 | }, | ||
9306 | [ALC268_ACER] = { | ||
9307 | .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer }, | ||
9308 | .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, | ||
9309 | alc268_acer_verbs }, | ||
9310 | .num_dacs = ARRAY_SIZE(alc268_dac_nids), | ||
9311 | .dac_nids = alc268_dac_nids, | ||
9312 | .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), | ||
9313 | .adc_nids = alc268_adc_nids_alt, | ||
9314 | .hp_nid = 0x02, | ||
9315 | .num_channel_mode = ARRAY_SIZE(alc268_modes), | ||
9316 | .channel_mode = alc268_modes, | ||
9317 | .input_mux = &alc268_capture_source, | ||
9318 | .unsol_event = alc268_acer_unsol_event, | ||
9319 | .init_hook = alc268_acer_init_hook, | ||
9320 | }, | ||
8576 | }; | 9321 | }; |
8577 | 9322 | ||
8578 | static int patch_alc268(struct hda_codec *codec) | 9323 | static int patch_alc268(struct hda_codec *codec) |
@@ -9279,14 +10024,10 @@ static void alc861_toshiba_automute(struct hda_codec *codec) | |||
9279 | 10024 | ||
9280 | present = snd_hda_codec_read(codec, 0x0f, 0, | 10025 | present = snd_hda_codec_read(codec, 0x0f, 0, |
9281 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 10026 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; |
9282 | snd_hda_codec_amp_update(codec, 0x16, 0, HDA_INPUT, 0, | 10027 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0, |
9283 | 0x80, present ? 0x80 : 0); | 10028 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); |
9284 | snd_hda_codec_amp_update(codec, 0x16, 1, HDA_INPUT, 0, | 10029 | snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3, |
9285 | 0x80, present ? 0x80 : 0); | 10030 | HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE); |
9286 | snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_INPUT, 3, | ||
9287 | 0x80, present ? 0 : 0x80); | ||
9288 | snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_INPUT, 3, | ||
9289 | 0x80, present ? 0 : 0x80); | ||
9290 | } | 10031 | } |
9291 | 10032 | ||
9292 | static void alc861_toshiba_unsol_event(struct hda_codec *codec, | 10033 | static void alc861_toshiba_unsol_event(struct hda_codec *codec, |
@@ -9599,6 +10340,16 @@ static void alc861_auto_init(struct hda_codec *codec) | |||
9599 | alc861_auto_init_analog_input(codec); | 10340 | alc861_auto_init_analog_input(codec); |
9600 | } | 10341 | } |
9601 | 10342 | ||
10343 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
10344 | static struct hda_amp_list alc861_loopbacks[] = { | ||
10345 | { 0x15, HDA_INPUT, 0 }, | ||
10346 | { 0x15, HDA_INPUT, 1 }, | ||
10347 | { 0x15, HDA_INPUT, 2 }, | ||
10348 | { 0x15, HDA_INPUT, 3 }, | ||
10349 | { } /* end */ | ||
10350 | }; | ||
10351 | #endif | ||
10352 | |||
9602 | 10353 | ||
9603 | /* | 10354 | /* |
9604 | * configuration and preset | 10355 | * configuration and preset |
@@ -9796,6 +10547,10 @@ static int patch_alc861(struct hda_codec *codec) | |||
9796 | codec->patch_ops = alc_patch_ops; | 10547 | codec->patch_ops = alc_patch_ops; |
9797 | if (board_config == ALC861_AUTO) | 10548 | if (board_config == ALC861_AUTO) |
9798 | spec->init_hook = alc861_auto_init; | 10549 | spec->init_hook = alc861_auto_init; |
10550 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
10551 | if (!spec->loopback.amplist) | ||
10552 | spec->loopback.amplist = alc861_loopbacks; | ||
10553 | #endif | ||
9799 | 10554 | ||
9800 | return 0; | 10555 | return 0; |
9801 | } | 10556 | } |
@@ -9852,6 +10607,14 @@ static struct hda_input_mux alc861vd_dallas_capture_source = { | |||
9852 | }, | 10607 | }, |
9853 | }; | 10608 | }; |
9854 | 10609 | ||
10610 | static struct hda_input_mux alc861vd_hp_capture_source = { | ||
10611 | .num_items = 2, | ||
10612 | .items = { | ||
10613 | { "Front Mic", 0x0 }, | ||
10614 | { "ATAPI Mic", 0x1 }, | ||
10615 | }, | ||
10616 | }; | ||
10617 | |||
9855 | #define alc861vd_mux_enum_info alc_mux_enum_info | 10618 | #define alc861vd_mux_enum_info alc_mux_enum_info |
9856 | #define alc861vd_mux_enum_get alc_mux_enum_get | 10619 | #define alc861vd_mux_enum_get alc_mux_enum_get |
9857 | 10620 | ||
@@ -9870,12 +10633,13 @@ static int alc861vd_mux_enum_put(struct snd_kcontrol *kcontrol, | |||
9870 | idx = ucontrol->value.enumerated.item[0]; | 10633 | idx = ucontrol->value.enumerated.item[0]; |
9871 | if (idx >= imux->num_items) | 10634 | if (idx >= imux->num_items) |
9872 | idx = imux->num_items - 1; | 10635 | idx = imux->num_items - 1; |
9873 | if (*cur_val == idx && !codec->in_resume) | 10636 | if (*cur_val == idx) |
9874 | return 0; | 10637 | return 0; |
9875 | for (i = 0; i < imux->num_items; i++) { | 10638 | for (i = 0; i < imux->num_items; i++) { |
9876 | unsigned int v = (i == idx) ? 0x7000 : 0x7080; | 10639 | unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; |
9877 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | 10640 | snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, |
9878 | v | (imux->items[i].index << 8)); | 10641 | imux->items[i].index, |
10642 | HDA_AMP_MUTE, v); | ||
9879 | } | 10643 | } |
9880 | *cur_val = idx; | 10644 | *cur_val = idx; |
9881 | return 1; | 10645 | return 1; |
@@ -10049,17 +10813,22 @@ static struct snd_kcontrol_new alc861vd_dallas_mixer[] = { | |||
10049 | HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | 10813 | HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), |
10050 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x05, HDA_INPUT), | 10814 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x05, HDA_INPUT), |
10051 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x05, HDA_INPUT), | 10815 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x05, HDA_INPUT), |
10052 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), | 10816 | { } /* end */ |
10053 | HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), | 10817 | }; |
10054 | { | 10818 | |
10055 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 10819 | /* Pin assignment: Speaker=0x14, Line-out = 0x15, |
10056 | /* .name = "Capture Source", */ | 10820 | * Front Mic=0x18, ATAPI Mic = 0x19, |
10057 | .name = "Input Source", | 10821 | */ |
10058 | .count = 1, | 10822 | static struct snd_kcontrol_new alc861vd_hp_mixer[] = { |
10059 | .info = alc882_mux_enum_info, | 10823 | HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), |
10060 | .get = alc882_mux_enum_get, | 10824 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), |
10061 | .put = alc882_mux_enum_put, | 10825 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), |
10062 | }, | 10826 | HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), |
10827 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
10828 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
10829 | HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | ||
10830 | HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | ||
10831 | |||
10063 | { } /* end */ | 10832 | { } /* end */ |
10064 | }; | 10833 | }; |
10065 | 10834 | ||
@@ -10077,11 +10846,11 @@ static struct hda_verb alc861vd_volume_init_verbs[] = { | |||
10077 | * the analog-loopback mixer widget | 10846 | * the analog-loopback mixer widget |
10078 | */ | 10847 | */ |
10079 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ | 10848 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ |
10080 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 10849 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
10081 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 10850 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
10082 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | 10851 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, |
10083 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | 10852 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, |
10084 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | 10853 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, |
10085 | 10854 | ||
10086 | /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */ | 10855 | /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */ |
10087 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 10856 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
@@ -10210,11 +10979,9 @@ static void alc861vd_lenovo_hp_automute(struct hda_codec *codec) | |||
10210 | 10979 | ||
10211 | present = snd_hda_codec_read(codec, 0x1b, 0, | 10980 | present = snd_hda_codec_read(codec, 0x1b, 0, |
10212 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 10981 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; |
10213 | bits = present ? 0x80 : 0; | 10982 | bits = present ? HDA_AMP_MUTE : 0; |
10214 | snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, | 10983 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, |
10215 | 0x80, bits); | 10984 | HDA_AMP_MUTE, bits); |
10216 | snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, | ||
10217 | 0x80, bits); | ||
10218 | } | 10985 | } |
10219 | 10986 | ||
10220 | static void alc861vd_lenovo_mic_automute(struct hda_codec *codec) | 10987 | static void alc861vd_lenovo_mic_automute(struct hda_codec *codec) |
@@ -10224,11 +10991,9 @@ static void alc861vd_lenovo_mic_automute(struct hda_codec *codec) | |||
10224 | 10991 | ||
10225 | present = snd_hda_codec_read(codec, 0x18, 0, | 10992 | present = snd_hda_codec_read(codec, 0x18, 0, |
10226 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 10993 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; |
10227 | bits = present ? 0x80 : 0; | 10994 | bits = present ? HDA_AMP_MUTE : 0; |
10228 | snd_hda_codec_amp_update(codec, 0x0b, 0, HDA_INPUT, 1, | 10995 | snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, |
10229 | 0x80, bits); | 10996 | HDA_AMP_MUTE, bits); |
10230 | snd_hda_codec_amp_update(codec, 0x0b, 1, HDA_INPUT, 1, | ||
10231 | 0x80, bits); | ||
10232 | } | 10997 | } |
10233 | 10998 | ||
10234 | static void alc861vd_lenovo_automute(struct hda_codec *codec) | 10999 | static void alc861vd_lenovo_automute(struct hda_codec *codec) |
@@ -10302,10 +11067,8 @@ static void alc861vd_dallas_automute(struct hda_codec *codec) | |||
10302 | 11067 | ||
10303 | present = snd_hda_codec_read(codec, 0x15, 0, | 11068 | present = snd_hda_codec_read(codec, 0x15, 0, |
10304 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 11069 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; |
10305 | snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, | 11070 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, |
10306 | 0x80, present ? 0x80 : 0); | 11071 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); |
10307 | snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, | ||
10308 | 0x80, present ? 0x80 : 0); | ||
10309 | } | 11072 | } |
10310 | 11073 | ||
10311 | static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int res) | 11074 | static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int res) |
@@ -10314,6 +11077,10 @@ static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int re | |||
10314 | alc861vd_dallas_automute(codec); | 11077 | alc861vd_dallas_automute(codec); |
10315 | } | 11078 | } |
10316 | 11079 | ||
11080 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
11081 | #define alc861vd_loopbacks alc880_loopbacks | ||
11082 | #endif | ||
11083 | |||
10317 | /* pcm configuration: identiacal with ALC880 */ | 11084 | /* pcm configuration: identiacal with ALC880 */ |
10318 | #define alc861vd_pcm_analog_playback alc880_pcm_analog_playback | 11085 | #define alc861vd_pcm_analog_playback alc880_pcm_analog_playback |
10319 | #define alc861vd_pcm_analog_capture alc880_pcm_analog_capture | 11086 | #define alc861vd_pcm_analog_capture alc880_pcm_analog_capture |
@@ -10325,12 +11092,13 @@ static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int re | |||
10325 | */ | 11092 | */ |
10326 | static const char *alc861vd_models[ALC861VD_MODEL_LAST] = { | 11093 | static const char *alc861vd_models[ALC861VD_MODEL_LAST] = { |
10327 | [ALC660VD_3ST] = "3stack-660", | 11094 | [ALC660VD_3ST] = "3stack-660", |
10328 | [ALC660VD_3ST_DIG]= "3stack-660-digout", | 11095 | [ALC660VD_3ST_DIG] = "3stack-660-digout", |
10329 | [ALC861VD_3ST] = "3stack", | 11096 | [ALC861VD_3ST] = "3stack", |
10330 | [ALC861VD_3ST_DIG] = "3stack-digout", | 11097 | [ALC861VD_3ST_DIG] = "3stack-digout", |
10331 | [ALC861VD_6ST_DIG] = "6stack-digout", | 11098 | [ALC861VD_6ST_DIG] = "6stack-digout", |
10332 | [ALC861VD_LENOVO] = "lenovo", | 11099 | [ALC861VD_LENOVO] = "lenovo", |
10333 | [ALC861VD_DALLAS] = "dallas", | 11100 | [ALC861VD_DALLAS] = "dallas", |
11101 | [ALC861VD_HP] = "hp", | ||
10334 | [ALC861VD_AUTO] = "auto", | 11102 | [ALC861VD_AUTO] = "auto", |
10335 | }; | 11103 | }; |
10336 | 11104 | ||
@@ -10341,11 +11109,15 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = { | |||
10341 | SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST), | 11109 | SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST), |
10342 | SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST), | 11110 | SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST), |
10343 | 11111 | ||
10344 | SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS), | 11112 | /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/ |
10345 | SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS), | 11113 | SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS), |
10346 | SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO), | 11114 | SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO), |
10347 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO), | 11115 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO), |
10348 | SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO), | 11116 | SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO), |
11117 | SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO), | ||
11118 | SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG), | ||
11119 | SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG), | ||
11120 | SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP), | ||
10349 | {} | 11121 | {} |
10350 | }; | 11122 | }; |
10351 | 11123 | ||
@@ -10435,7 +11207,21 @@ static struct alc_config_preset alc861vd_presets[] = { | |||
10435 | .input_mux = &alc861vd_dallas_capture_source, | 11207 | .input_mux = &alc861vd_dallas_capture_source, |
10436 | .unsol_event = alc861vd_dallas_unsol_event, | 11208 | .unsol_event = alc861vd_dallas_unsol_event, |
10437 | .init_hook = alc861vd_dallas_automute, | 11209 | .init_hook = alc861vd_dallas_automute, |
10438 | }, | 11210 | }, |
11211 | [ALC861VD_HP] = { | ||
11212 | .mixers = { alc861vd_hp_mixer }, | ||
11213 | .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs }, | ||
11214 | .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), | ||
11215 | .dac_nids = alc861vd_dac_nids, | ||
11216 | .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids), | ||
11217 | .dig_out_nid = ALC861VD_DIGOUT_NID, | ||
11218 | .adc_nids = alc861vd_adc_nids, | ||
11219 | .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), | ||
11220 | .channel_mode = alc861vd_3stack_2ch_modes, | ||
11221 | .input_mux = &alc861vd_hp_capture_source, | ||
11222 | .unsol_event = alc861vd_dallas_unsol_event, | ||
11223 | .init_hook = alc861vd_dallas_automute, | ||
11224 | }, | ||
10439 | }; | 11225 | }; |
10440 | 11226 | ||
10441 | /* | 11227 | /* |
@@ -10668,6 +11454,10 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec) | |||
10668 | spec->num_mux_defs = 1; | 11454 | spec->num_mux_defs = 1; |
10669 | spec->input_mux = &spec->private_imux; | 11455 | spec->input_mux = &spec->private_imux; |
10670 | 11456 | ||
11457 | err = alc_auto_add_mic_boost(codec); | ||
11458 | if (err < 0) | ||
11459 | return err; | ||
11460 | |||
10671 | return 1; | 11461 | return 1; |
10672 | } | 11462 | } |
10673 | 11463 | ||
@@ -10735,6 +11525,10 @@ static int patch_alc861vd(struct hda_codec *codec) | |||
10735 | 11525 | ||
10736 | if (board_config == ALC861VD_AUTO) | 11526 | if (board_config == ALC861VD_AUTO) |
10737 | spec->init_hook = alc861vd_auto_init; | 11527 | spec->init_hook = alc861vd_auto_init; |
11528 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
11529 | if (!spec->loopback.amplist) | ||
11530 | spec->loopback.amplist = alc861vd_loopbacks; | ||
11531 | #endif | ||
10738 | 11532 | ||
10739 | return 0; | 11533 | return 0; |
10740 | } | 11534 | } |
@@ -10782,6 +11576,15 @@ static struct hda_input_mux alc662_lenovo_101e_capture_source = { | |||
10782 | { "Line", 0x2 }, | 11576 | { "Line", 0x2 }, |
10783 | }, | 11577 | }, |
10784 | }; | 11578 | }; |
11579 | |||
11580 | static struct hda_input_mux alc662_eeepc_capture_source = { | ||
11581 | .num_items = 2, | ||
11582 | .items = { | ||
11583 | { "i-Mic", 0x1 }, | ||
11584 | { "e-Mic", 0x0 }, | ||
11585 | }, | ||
11586 | }; | ||
11587 | |||
10785 | #define alc662_mux_enum_info alc_mux_enum_info | 11588 | #define alc662_mux_enum_info alc_mux_enum_info |
10786 | #define alc662_mux_enum_get alc_mux_enum_get | 11589 | #define alc662_mux_enum_get alc_mux_enum_get |
10787 | 11590 | ||
@@ -10792,7 +11595,7 @@ static int alc662_mux_enum_put(struct snd_kcontrol *kcontrol, | |||
10792 | struct alc_spec *spec = codec->spec; | 11595 | struct alc_spec *spec = codec->spec; |
10793 | const struct hda_input_mux *imux = spec->input_mux; | 11596 | const struct hda_input_mux *imux = spec->input_mux; |
10794 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | 11597 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); |
10795 | static hda_nid_t capture_mixers[3] = { 0x24, 0x23, 0x22 }; | 11598 | static hda_nid_t capture_mixers[2] = { 0x23, 0x22 }; |
10796 | hda_nid_t nid = capture_mixers[adc_idx]; | 11599 | hda_nid_t nid = capture_mixers[adc_idx]; |
10797 | unsigned int *cur_val = &spec->cur_mux[adc_idx]; | 11600 | unsigned int *cur_val = &spec->cur_mux[adc_idx]; |
10798 | unsigned int i, idx; | 11601 | unsigned int i, idx; |
@@ -10800,12 +11603,13 @@ static int alc662_mux_enum_put(struct snd_kcontrol *kcontrol, | |||
10800 | idx = ucontrol->value.enumerated.item[0]; | 11603 | idx = ucontrol->value.enumerated.item[0]; |
10801 | if (idx >= imux->num_items) | 11604 | if (idx >= imux->num_items) |
10802 | idx = imux->num_items - 1; | 11605 | idx = imux->num_items - 1; |
10803 | if (*cur_val == idx && !codec->in_resume) | 11606 | if (*cur_val == idx) |
10804 | return 0; | 11607 | return 0; |
10805 | for (i = 0; i < imux->num_items; i++) { | 11608 | for (i = 0; i < imux->num_items; i++) { |
10806 | unsigned int v = (i == idx) ? 0x7000 : 0x7080; | 11609 | unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; |
10807 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | 11610 | snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, |
10808 | v | (imux->items[i].index << 8)); | 11611 | imux->items[i].index, |
11612 | HDA_AMP_MUTE, v); | ||
10809 | } | 11613 | } |
10810 | *cur_val = idx; | 11614 | *cur_val = idx; |
10811 | return 1; | 11615 | return 1; |
@@ -10997,6 +11801,22 @@ static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = { | |||
10997 | { } /* end */ | 11801 | { } /* end */ |
10998 | }; | 11802 | }; |
10999 | 11803 | ||
11804 | static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { | ||
11805 | HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
11806 | |||
11807 | HDA_CODEC_VOLUME("LineOut Playback Volume", 0x02, 0x0, HDA_OUTPUT), | ||
11808 | HDA_CODEC_MUTE("LineOut Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
11809 | |||
11810 | HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT), | ||
11811 | HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
11812 | HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
11813 | |||
11814 | HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT), | ||
11815 | HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | ||
11816 | HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | ||
11817 | { } /* end */ | ||
11818 | }; | ||
11819 | |||
11000 | static struct snd_kcontrol_new alc662_chmode_mixer[] = { | 11820 | static struct snd_kcontrol_new alc662_chmode_mixer[] = { |
11001 | { | 11821 | { |
11002 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 11822 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -11014,18 +11834,18 @@ static struct hda_verb alc662_init_verbs[] = { | |||
11014 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, | 11834 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, |
11015 | /* Front mixer: unmute input/output amp left and right (volume = 0) */ | 11835 | /* Front mixer: unmute input/output amp left and right (volume = 0) */ |
11016 | 11836 | ||
11017 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 11837 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
11018 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 11838 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
11019 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | 11839 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, |
11020 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | 11840 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, |
11021 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | 11841 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, |
11022 | 11842 | ||
11023 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 11843 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
11024 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 11844 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
11025 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 11845 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
11026 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 11846 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
11027 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 11847 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
11028 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 11848 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
11029 | 11849 | ||
11030 | /* Front Pin: output 0 (0x0c) */ | 11850 | /* Front Pin: output 0 (0x0c) */ |
11031 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | 11851 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
@@ -11062,13 +11882,24 @@ static struct hda_verb alc662_init_verbs[] = { | |||
11062 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 11882 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
11063 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | 11883 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, |
11064 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | 11884 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, |
11885 | |||
11886 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
11887 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
11888 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
11889 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | ||
11065 | { } | 11890 | { } |
11066 | }; | 11891 | }; |
11067 | 11892 | ||
11068 | static struct hda_verb alc662_sue_init_verbs[] = { | 11893 | static struct hda_verb alc662_sue_init_verbs[] = { |
11069 | {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT}, | 11894 | {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT}, |
11070 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT}, | 11895 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT}, |
11071 | {} | 11896 | {} |
11897 | }; | ||
11898 | |||
11899 | static struct hda_verb alc662_eeepc_sue_init_verbs[] = { | ||
11900 | {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, | ||
11901 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, | ||
11902 | {} | ||
11072 | }; | 11903 | }; |
11073 | 11904 | ||
11074 | /* | 11905 | /* |
@@ -11087,11 +11918,11 @@ static struct hda_verb alc662_auto_init_verbs[] = { | |||
11087 | * panel mic (mic 2) | 11918 | * panel mic (mic 2) |
11088 | */ | 11919 | */ |
11089 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ | 11920 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ |
11090 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 11921 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, |
11091 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 11922 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
11092 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | 11923 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, |
11093 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | 11924 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, |
11094 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | 11925 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, |
11095 | 11926 | ||
11096 | /* | 11927 | /* |
11097 | * Set up output mixers (0x0c - 0x0f) | 11928 | * Set up output mixers (0x0c - 0x0f) |
@@ -11103,23 +11934,19 @@ static struct hda_verb alc662_auto_init_verbs[] = { | |||
11103 | 11934 | ||
11104 | /* set up input amps for analog loopback */ | 11935 | /* set up input amps for analog loopback */ |
11105 | /* Amp Indices: DAC = 0, mixer = 1 */ | 11936 | /* Amp Indices: DAC = 0, mixer = 1 */ |
11106 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 11937 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
11107 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 11938 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
11108 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 11939 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
11109 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 11940 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
11110 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 11941 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
11111 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 11942 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
11112 | 11943 | ||
11113 | 11944 | ||
11114 | /* FIXME: use matrix-type input source selection */ | 11945 | /* FIXME: use matrix-type input source selection */ |
11115 | /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ | 11946 | /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ |
11116 | /* Input mixer */ | 11947 | /* Input mixer */ |
11117 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 11948 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
11118 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 11949 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
11119 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
11120 | /*{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},*/ | ||
11121 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | ||
11122 | |||
11123 | { } | 11950 | { } |
11124 | }; | 11951 | }; |
11125 | 11952 | ||
@@ -11150,11 +11977,9 @@ static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec) | |||
11150 | 11977 | ||
11151 | present = snd_hda_codec_read(codec, 0x14, 0, | 11978 | present = snd_hda_codec_read(codec, 0x14, 0, |
11152 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 11979 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; |
11153 | bits = present ? 0x80 : 0; | 11980 | bits = present ? HDA_AMP_MUTE : 0; |
11154 | snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, | 11981 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, |
11155 | 0x80, bits); | 11982 | HDA_AMP_MUTE, bits); |
11156 | snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, | ||
11157 | 0x80, bits); | ||
11158 | } | 11983 | } |
11159 | 11984 | ||
11160 | static void alc662_lenovo_101e_all_automute(struct hda_codec *codec) | 11985 | static void alc662_lenovo_101e_all_automute(struct hda_codec *codec) |
@@ -11164,15 +11989,11 @@ static void alc662_lenovo_101e_all_automute(struct hda_codec *codec) | |||
11164 | 11989 | ||
11165 | present = snd_hda_codec_read(codec, 0x1b, 0, | 11990 | present = snd_hda_codec_read(codec, 0x1b, 0, |
11166 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 11991 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; |
11167 | bits = present ? 0x80 : 0; | 11992 | bits = present ? HDA_AMP_MUTE : 0; |
11168 | snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, | 11993 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, |
11169 | 0x80, bits); | 11994 | HDA_AMP_MUTE, bits); |
11170 | snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, | 11995 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, |
11171 | 0x80, bits); | 11996 | HDA_AMP_MUTE, bits); |
11172 | snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, | ||
11173 | 0x80, bits); | ||
11174 | snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, | ||
11175 | 0x80, bits); | ||
11176 | } | 11997 | } |
11177 | 11998 | ||
11178 | static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec, | 11999 | static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec, |
@@ -11184,6 +12005,43 @@ static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec, | |||
11184 | alc662_lenovo_101e_ispeaker_automute(codec); | 12005 | alc662_lenovo_101e_ispeaker_automute(codec); |
11185 | } | 12006 | } |
11186 | 12007 | ||
12008 | static void alc662_eeepc_mic_automute(struct hda_codec *codec) | ||
12009 | { | ||
12010 | unsigned int present; | ||
12011 | |||
12012 | present = snd_hda_codec_read(codec, 0x18, 0, | ||
12013 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
12014 | snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
12015 | 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); | ||
12016 | snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
12017 | 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); | ||
12018 | snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
12019 | 0x7000 | (0x01 << 8) | (present ? 0x80 : 0)); | ||
12020 | snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
12021 | 0x7000 | (0x01 << 8) | (present ? 0x80 : 0)); | ||
12022 | } | ||
12023 | |||
12024 | /* unsolicited event for HP jack sensing */ | ||
12025 | static void alc662_eeepc_unsol_event(struct hda_codec *codec, | ||
12026 | unsigned int res) | ||
12027 | { | ||
12028 | if ((res >> 26) == ALC880_HP_EVENT) | ||
12029 | alc262_hippo1_automute( codec ); | ||
12030 | |||
12031 | if ((res >> 26) == ALC880_MIC_EVENT) | ||
12032 | alc662_eeepc_mic_automute(codec); | ||
12033 | } | ||
12034 | |||
12035 | static void alc662_eeepc_inithook(struct hda_codec *codec) | ||
12036 | { | ||
12037 | alc262_hippo1_automute( codec ); | ||
12038 | alc662_eeepc_mic_automute(codec); | ||
12039 | } | ||
12040 | |||
12041 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
12042 | #define alc662_loopbacks alc880_loopbacks | ||
12043 | #endif | ||
12044 | |||
11187 | 12045 | ||
11188 | /* pcm configuration: identiacal with ALC880 */ | 12046 | /* pcm configuration: identiacal with ALC880 */ |
11189 | #define alc662_pcm_analog_playback alc880_pcm_analog_playback | 12047 | #define alc662_pcm_analog_playback alc880_pcm_analog_playback |
@@ -11205,12 +12063,13 @@ static const char *alc662_models[ALC662_MODEL_LAST] = { | |||
11205 | 12063 | ||
11206 | static struct snd_pci_quirk alc662_cfg_tbl[] = { | 12064 | static struct snd_pci_quirk alc662_cfg_tbl[] = { |
11207 | SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), | 12065 | SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), |
12066 | SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701), | ||
11208 | {} | 12067 | {} |
11209 | }; | 12068 | }; |
11210 | 12069 | ||
11211 | static struct alc_config_preset alc662_presets[] = { | 12070 | static struct alc_config_preset alc662_presets[] = { |
11212 | [ALC662_3ST_2ch_DIG] = { | 12071 | [ALC662_3ST_2ch_DIG] = { |
11213 | .mixers = { alc662_3ST_2ch_mixer }, | 12072 | .mixers = { alc662_3ST_2ch_mixer, alc662_capture_mixer }, |
11214 | .init_verbs = { alc662_init_verbs }, | 12073 | .init_verbs = { alc662_init_verbs }, |
11215 | .num_dacs = ARRAY_SIZE(alc662_dac_nids), | 12074 | .num_dacs = ARRAY_SIZE(alc662_dac_nids), |
11216 | .dac_nids = alc662_dac_nids, | 12075 | .dac_nids = alc662_dac_nids, |
@@ -11223,7 +12082,8 @@ static struct alc_config_preset alc662_presets[] = { | |||
11223 | .input_mux = &alc662_capture_source, | 12082 | .input_mux = &alc662_capture_source, |
11224 | }, | 12083 | }, |
11225 | [ALC662_3ST_6ch_DIG] = { | 12084 | [ALC662_3ST_6ch_DIG] = { |
11226 | .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, | 12085 | .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer, |
12086 | alc662_capture_mixer }, | ||
11227 | .init_verbs = { alc662_init_verbs }, | 12087 | .init_verbs = { alc662_init_verbs }, |
11228 | .num_dacs = ARRAY_SIZE(alc662_dac_nids), | 12088 | .num_dacs = ARRAY_SIZE(alc662_dac_nids), |
11229 | .dac_nids = alc662_dac_nids, | 12089 | .dac_nids = alc662_dac_nids, |
@@ -11237,7 +12097,8 @@ static struct alc_config_preset alc662_presets[] = { | |||
11237 | .input_mux = &alc662_capture_source, | 12097 | .input_mux = &alc662_capture_source, |
11238 | }, | 12098 | }, |
11239 | [ALC662_3ST_6ch] = { | 12099 | [ALC662_3ST_6ch] = { |
11240 | .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, | 12100 | .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer, |
12101 | alc662_capture_mixer }, | ||
11241 | .init_verbs = { alc662_init_verbs }, | 12102 | .init_verbs = { alc662_init_verbs }, |
11242 | .num_dacs = ARRAY_SIZE(alc662_dac_nids), | 12103 | .num_dacs = ARRAY_SIZE(alc662_dac_nids), |
11243 | .dac_nids = alc662_dac_nids, | 12104 | .dac_nids = alc662_dac_nids, |
@@ -11249,7 +12110,8 @@ static struct alc_config_preset alc662_presets[] = { | |||
11249 | .input_mux = &alc662_capture_source, | 12110 | .input_mux = &alc662_capture_source, |
11250 | }, | 12111 | }, |
11251 | [ALC662_5ST_DIG] = { | 12112 | [ALC662_5ST_DIG] = { |
11252 | .mixers = { alc662_base_mixer, alc662_chmode_mixer }, | 12113 | .mixers = { alc662_base_mixer, alc662_chmode_mixer, |
12114 | alc662_capture_mixer }, | ||
11253 | .init_verbs = { alc662_init_verbs }, | 12115 | .init_verbs = { alc662_init_verbs }, |
11254 | .num_dacs = ARRAY_SIZE(alc662_dac_nids), | 12116 | .num_dacs = ARRAY_SIZE(alc662_dac_nids), |
11255 | .dac_nids = alc662_dac_nids, | 12117 | .dac_nids = alc662_dac_nids, |
@@ -11262,7 +12124,7 @@ static struct alc_config_preset alc662_presets[] = { | |||
11262 | .input_mux = &alc662_capture_source, | 12124 | .input_mux = &alc662_capture_source, |
11263 | }, | 12125 | }, |
11264 | [ALC662_LENOVO_101E] = { | 12126 | [ALC662_LENOVO_101E] = { |
11265 | .mixers = { alc662_lenovo_101e_mixer }, | 12127 | .mixers = { alc662_lenovo_101e_mixer, alc662_capture_mixer }, |
11266 | .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs }, | 12128 | .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs }, |
11267 | .num_dacs = ARRAY_SIZE(alc662_dac_nids), | 12129 | .num_dacs = ARRAY_SIZE(alc662_dac_nids), |
11268 | .dac_nids = alc662_dac_nids, | 12130 | .dac_nids = alc662_dac_nids, |
@@ -11274,6 +12136,20 @@ static struct alc_config_preset alc662_presets[] = { | |||
11274 | .unsol_event = alc662_lenovo_101e_unsol_event, | 12136 | .unsol_event = alc662_lenovo_101e_unsol_event, |
11275 | .init_hook = alc662_lenovo_101e_all_automute, | 12137 | .init_hook = alc662_lenovo_101e_all_automute, |
11276 | }, | 12138 | }, |
12139 | [ALC662_ASUS_EEEPC_P701] = { | ||
12140 | .mixers = { alc662_eeepc_p701_mixer, alc662_capture_mixer }, | ||
12141 | .init_verbs = { alc662_init_verbs, | ||
12142 | alc662_eeepc_sue_init_verbs }, | ||
12143 | .num_dacs = ARRAY_SIZE(alc662_dac_nids), | ||
12144 | .dac_nids = alc662_dac_nids, | ||
12145 | .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids), | ||
12146 | .adc_nids = alc662_adc_nids, | ||
12147 | .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), | ||
12148 | .channel_mode = alc662_3ST_2ch_modes, | ||
12149 | .input_mux = &alc662_eeepc_capture_source, | ||
12150 | .unsol_event = alc662_eeepc_unsol_event, | ||
12151 | .init_hook = alc662_eeepc_inithook, | ||
12152 | }, | ||
11277 | 12153 | ||
11278 | }; | 12154 | }; |
11279 | 12155 | ||
@@ -11296,7 +12172,7 @@ static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec, | |||
11296 | for (i = 0; i < cfg->line_outs; i++) { | 12172 | for (i = 0; i < cfg->line_outs; i++) { |
11297 | if (!spec->multiout.dac_nids[i]) | 12173 | if (!spec->multiout.dac_nids[i]) |
11298 | continue; | 12174 | continue; |
11299 | nid = alc880_idx_to_mixer(i); | 12175 | nid = alc880_idx_to_dac(i); |
11300 | if (i == 2) { | 12176 | if (i == 2) { |
11301 | /* Center/LFE */ | 12177 | /* Center/LFE */ |
11302 | err = add_control(spec, ALC_CTL_WIDGET_VOL, | 12178 | err = add_control(spec, ALC_CTL_WIDGET_VOL, |
@@ -11586,6 +12462,10 @@ static int patch_alc662(struct hda_codec *codec) | |||
11586 | codec->patch_ops = alc_patch_ops; | 12462 | codec->patch_ops = alc_patch_ops; |
11587 | if (board_config == ALC662_AUTO) | 12463 | if (board_config == ALC662_AUTO) |
11588 | spec->init_hook = alc662_auto_init; | 12464 | spec->init_hook = alc662_auto_init; |
12465 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
12466 | if (!spec->loopback.amplist) | ||
12467 | spec->loopback.amplist = alc662_loopbacks; | ||
12468 | #endif | ||
11589 | 12469 | ||
11590 | return 0; | 12470 | return 0; |
11591 | } | 12471 | } |
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index 6d2ecc38905c..2a4b9609aa5c 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c | |||
@@ -78,6 +78,8 @@ | |||
78 | /* si3054 codec registers (nodes) access macros */ | 78 | /* si3054 codec registers (nodes) access macros */ |
79 | #define GET_REG(codec,reg) (snd_hda_codec_read(codec,reg,0,SI3054_VERB_READ_NODE,0)) | 79 | #define GET_REG(codec,reg) (snd_hda_codec_read(codec,reg,0,SI3054_VERB_READ_NODE,0)) |
80 | #define SET_REG(codec,reg,val) (snd_hda_codec_write(codec,reg,0,SI3054_VERB_WRITE_NODE,val)) | 80 | #define SET_REG(codec,reg,val) (snd_hda_codec_write(codec,reg,0,SI3054_VERB_WRITE_NODE,val)) |
81 | #define SET_REG_CACHE(codec,reg,val) \ | ||
82 | snd_hda_codec_write_cache(codec,reg,0,SI3054_VERB_WRITE_NODE,val) | ||
81 | 83 | ||
82 | 84 | ||
83 | struct si3054_spec { | 85 | struct si3054_spec { |
@@ -94,15 +96,7 @@ struct si3054_spec { | |||
94 | #define PRIVATE_REG(val) ((val>>16)&0xffff) | 96 | #define PRIVATE_REG(val) ((val>>16)&0xffff) |
95 | #define PRIVATE_MASK(val) (val&0xffff) | 97 | #define PRIVATE_MASK(val) (val&0xffff) |
96 | 98 | ||
97 | static int si3054_switch_info(struct snd_kcontrol *kcontrol, | 99 | #define si3054_switch_info snd_ctl_boolean_mono_info |
98 | struct snd_ctl_elem_info *uinfo) | ||
99 | { | ||
100 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
101 | uinfo->count = 1; | ||
102 | uinfo->value.integer.min = 0; | ||
103 | uinfo->value.integer.max = 1; | ||
104 | return 0; | ||
105 | } | ||
106 | 100 | ||
107 | static int si3054_switch_get(struct snd_kcontrol *kcontrol, | 101 | static int si3054_switch_get(struct snd_kcontrol *kcontrol, |
108 | struct snd_ctl_elem_value *uvalue) | 102 | struct snd_ctl_elem_value *uvalue) |
@@ -121,9 +115,9 @@ static int si3054_switch_put(struct snd_kcontrol *kcontrol, | |||
121 | u16 reg = PRIVATE_REG(kcontrol->private_value); | 115 | u16 reg = PRIVATE_REG(kcontrol->private_value); |
122 | u16 mask = PRIVATE_MASK(kcontrol->private_value); | 116 | u16 mask = PRIVATE_MASK(kcontrol->private_value); |
123 | if (uvalue->value.integer.value[0]) | 117 | if (uvalue->value.integer.value[0]) |
124 | SET_REG(codec, reg, (GET_REG(codec, reg)) | mask); | 118 | SET_REG_CACHE(codec, reg, (GET_REG(codec, reg)) | mask); |
125 | else | 119 | else |
126 | SET_REG(codec, reg, (GET_REG(codec, reg)) & ~mask); | 120 | SET_REG_CACHE(codec, reg, (GET_REG(codec, reg)) & ~mask); |
127 | return 0; | 121 | return 0; |
128 | } | 122 | } |
129 | 123 | ||
@@ -275,10 +269,6 @@ static struct hda_codec_ops si3054_patch_ops = { | |||
275 | .build_pcms = si3054_build_pcms, | 269 | .build_pcms = si3054_build_pcms, |
276 | .init = si3054_init, | 270 | .init = si3054_init, |
277 | .free = si3054_free, | 271 | .free = si3054_free, |
278 | #ifdef CONFIG_PM | ||
279 | //.suspend = si3054_suspend, | ||
280 | .resume = si3054_init, | ||
281 | #endif | ||
282 | }; | 272 | }; |
283 | 273 | ||
284 | static int patch_si3054(struct hda_codec *codec) | 274 | static int patch_si3054(struct hda_codec *codec) |
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 3f25de72966b..bf950195107c 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -39,12 +39,25 @@ | |||
39 | 39 | ||
40 | enum { | 40 | enum { |
41 | STAC_REF, | 41 | STAC_REF, |
42 | STAC_9200_DELL_D21, | ||
43 | STAC_9200_DELL_D22, | ||
44 | STAC_9200_DELL_D23, | ||
45 | STAC_9200_DELL_M21, | ||
46 | STAC_9200_DELL_M22, | ||
47 | STAC_9200_DELL_M23, | ||
48 | STAC_9200_DELL_M24, | ||
49 | STAC_9200_DELL_M25, | ||
50 | STAC_9200_DELL_M26, | ||
51 | STAC_9200_DELL_M27, | ||
52 | STAC_9200_GATEWAY, | ||
42 | STAC_9200_MODELS | 53 | STAC_9200_MODELS |
43 | }; | 54 | }; |
44 | 55 | ||
45 | enum { | 56 | enum { |
46 | STAC_9205_REF, | 57 | STAC_9205_REF, |
47 | STAC_M43xx, | 58 | STAC_9205_DELL_M42, |
59 | STAC_9205_DELL_M43, | ||
60 | STAC_9205_DELL_M44, | ||
48 | STAC_9205_MODELS | 61 | STAC_9205_MODELS |
49 | }; | 62 | }; |
50 | 63 | ||
@@ -60,19 +73,22 @@ enum { | |||
60 | STAC_D945_REF, | 73 | STAC_D945_REF, |
61 | STAC_D945GTP3, | 74 | STAC_D945GTP3, |
62 | STAC_D945GTP5, | 75 | STAC_D945GTP5, |
63 | STAC_922X_DELL, | ||
64 | STAC_INTEL_MAC_V1, | 76 | STAC_INTEL_MAC_V1, |
65 | STAC_INTEL_MAC_V2, | 77 | STAC_INTEL_MAC_V2, |
66 | STAC_INTEL_MAC_V3, | 78 | STAC_INTEL_MAC_V3, |
67 | STAC_INTEL_MAC_V4, | 79 | STAC_INTEL_MAC_V4, |
68 | STAC_INTEL_MAC_V5, | 80 | STAC_INTEL_MAC_V5, |
69 | /* for backward compitability */ | 81 | /* for backward compatibility */ |
70 | STAC_MACMINI, | 82 | STAC_MACMINI, |
71 | STAC_MACBOOK, | 83 | STAC_MACBOOK, |
72 | STAC_MACBOOK_PRO_V1, | 84 | STAC_MACBOOK_PRO_V1, |
73 | STAC_MACBOOK_PRO_V2, | 85 | STAC_MACBOOK_PRO_V2, |
74 | STAC_IMAC_INTEL, | 86 | STAC_IMAC_INTEL, |
75 | STAC_IMAC_INTEL_20, | 87 | STAC_IMAC_INTEL_20, |
88 | STAC_922X_DELL_D81, | ||
89 | STAC_922X_DELL_D82, | ||
90 | STAC_922X_DELL_M81, | ||
91 | STAC_922X_DELL_M82, | ||
76 | STAC_922X_MODELS | 92 | STAC_922X_MODELS |
77 | }; | 93 | }; |
78 | 94 | ||
@@ -80,6 +96,7 @@ enum { | |||
80 | STAC_D965_REF, | 96 | STAC_D965_REF, |
81 | STAC_D965_3ST, | 97 | STAC_D965_3ST, |
82 | STAC_D965_5ST, | 98 | STAC_D965_5ST, |
99 | STAC_DELL_3ST, | ||
83 | STAC_927X_MODELS | 100 | STAC_927X_MODELS |
84 | }; | 101 | }; |
85 | 102 | ||
@@ -95,6 +112,8 @@ struct sigmatel_spec { | |||
95 | unsigned int hp_detect: 1; | 112 | unsigned int hp_detect: 1; |
96 | unsigned int gpio_mute: 1; | 113 | unsigned int gpio_mute: 1; |
97 | 114 | ||
115 | unsigned int gpio_mask, gpio_data; | ||
116 | |||
98 | /* playback */ | 117 | /* playback */ |
99 | struct hda_multi_out multiout; | 118 | struct hda_multi_out multiout; |
100 | hda_nid_t dac_nids[5]; | 119 | hda_nid_t dac_nids[5]; |
@@ -127,6 +146,8 @@ struct sigmatel_spec { | |||
127 | 146 | ||
128 | /* i/o switches */ | 147 | /* i/o switches */ |
129 | unsigned int io_switch[2]; | 148 | unsigned int io_switch[2]; |
149 | unsigned int clfe_swap; | ||
150 | unsigned int aloopback; | ||
130 | 151 | ||
131 | struct hda_pcm pcm_rec[2]; /* PCM information */ | 152 | struct hda_pcm pcm_rec[2]; /* PCM information */ |
132 | 153 | ||
@@ -162,8 +183,9 @@ static hda_nid_t stac925x_dac_nids[1] = { | |||
162 | 0x02, | 183 | 0x02, |
163 | }; | 184 | }; |
164 | 185 | ||
165 | static hda_nid_t stac925x_dmic_nids[1] = { | 186 | #define STAC925X_NUM_DMICS 1 |
166 | 0x15, | 187 | static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = { |
188 | 0x15, 0 | ||
167 | }; | 189 | }; |
168 | 190 | ||
169 | static hda_nid_t stac922x_adc_nids[2] = { | 191 | static hda_nid_t stac922x_adc_nids[2] = { |
@@ -190,8 +212,9 @@ static hda_nid_t stac9205_mux_nids[2] = { | |||
190 | 0x19, 0x1a | 212 | 0x19, 0x1a |
191 | }; | 213 | }; |
192 | 214 | ||
193 | static hda_nid_t stac9205_dmic_nids[2] = { | 215 | #define STAC9205_NUM_DMICS 2 |
194 | 0x17, 0x18, | 216 | static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = { |
217 | 0x17, 0x18, 0 | ||
195 | }; | 218 | }; |
196 | 219 | ||
197 | static hda_nid_t stac9200_pin_nids[8] = { | 220 | static hda_nid_t stac9200_pin_nids[8] = { |
@@ -276,12 +299,97 @@ static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
276 | spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]); | 299 | spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]); |
277 | } | 300 | } |
278 | 301 | ||
302 | #define stac92xx_aloopback_info snd_ctl_boolean_mono_info | ||
303 | |||
304 | static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol, | ||
305 | struct snd_ctl_elem_value *ucontrol) | ||
306 | { | ||
307 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
308 | struct sigmatel_spec *spec = codec->spec; | ||
309 | |||
310 | ucontrol->value.integer.value[0] = spec->aloopback; | ||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol, | ||
315 | struct snd_ctl_elem_value *ucontrol) | ||
316 | { | ||
317 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
318 | struct sigmatel_spec *spec = codec->spec; | ||
319 | unsigned int dac_mode; | ||
320 | |||
321 | if (spec->aloopback == ucontrol->value.integer.value[0]) | ||
322 | return 0; | ||
323 | |||
324 | spec->aloopback = ucontrol->value.integer.value[0]; | ||
325 | |||
326 | |||
327 | dac_mode = snd_hda_codec_read(codec, codec->afg, 0, | ||
328 | kcontrol->private_value & 0xFFFF, 0x0); | ||
329 | |||
330 | if (spec->aloopback) { | ||
331 | snd_hda_power_up(codec); | ||
332 | dac_mode |= 0x40; | ||
333 | } else { | ||
334 | snd_hda_power_down(codec); | ||
335 | dac_mode &= ~0x40; | ||
336 | } | ||
337 | |||
338 | snd_hda_codec_write_cache(codec, codec->afg, 0, | ||
339 | kcontrol->private_value >> 16, dac_mode); | ||
340 | |||
341 | return 1; | ||
342 | } | ||
343 | |||
344 | static int stac92xx_volknob_info(struct snd_kcontrol *kcontrol, | ||
345 | struct snd_ctl_elem_info *uinfo) | ||
346 | { | ||
347 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
348 | uinfo->count = 1; | ||
349 | uinfo->value.integer.min = 0; | ||
350 | uinfo->value.integer.max = 127; | ||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | static int stac92xx_volknob_get(struct snd_kcontrol *kcontrol, | ||
355 | struct snd_ctl_elem_value *ucontrol) | ||
356 | { | ||
357 | ucontrol->value.integer.value[0] = kcontrol->private_value & 0xff; | ||
358 | return 0; | ||
359 | } | ||
360 | |||
361 | static int stac92xx_volknob_put(struct snd_kcontrol *kcontrol, | ||
362 | struct snd_ctl_elem_value *ucontrol) | ||
363 | { | ||
364 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
365 | unsigned int val = kcontrol->private_value & 0xff; | ||
366 | |||
367 | if (val == ucontrol->value.integer.value[0]) | ||
368 | return 0; | ||
369 | |||
370 | val = ucontrol->value.integer.value[0]; | ||
371 | kcontrol->private_value &= ~0xff; | ||
372 | kcontrol->private_value |= val; | ||
373 | |||
374 | snd_hda_codec_write_cache(codec, kcontrol->private_value >> 16, 0, | ||
375 | AC_VERB_SET_VOLUME_KNOB_CONTROL, val | 0x80); | ||
376 | return 1; | ||
377 | } | ||
378 | |||
379 | |||
279 | static struct hda_verb stac9200_core_init[] = { | 380 | static struct hda_verb stac9200_core_init[] = { |
280 | /* set dac0mux for dac converter */ | 381 | /* set dac0mux for dac converter */ |
281 | { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, | 382 | { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, |
282 | {} | 383 | {} |
283 | }; | 384 | }; |
284 | 385 | ||
386 | static struct hda_verb stac9200_eapd_init[] = { | ||
387 | /* set dac0mux for dac converter */ | ||
388 | {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
389 | {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, | ||
390 | {} | ||
391 | }; | ||
392 | |||
285 | static struct hda_verb stac925x_core_init[] = { | 393 | static struct hda_verb stac925x_core_init[] = { |
286 | /* set dac0mux for dac converter */ | 394 | /* set dac0mux for dac converter */ |
287 | { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00}, | 395 | { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00}, |
@@ -316,17 +424,43 @@ static struct hda_verb stac9205_core_init[] = { | |||
316 | {} | 424 | {} |
317 | }; | 425 | }; |
318 | 426 | ||
427 | #define STAC_INPUT_SOURCE(cnt) \ | ||
428 | { \ | ||
429 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
430 | .name = "Input Source", \ | ||
431 | .count = cnt, \ | ||
432 | .info = stac92xx_mux_enum_info, \ | ||
433 | .get = stac92xx_mux_enum_get, \ | ||
434 | .put = stac92xx_mux_enum_put, \ | ||
435 | } | ||
436 | |||
437 | #define STAC_ANALOG_LOOPBACK(verb_read,verb_write) \ | ||
438 | { \ | ||
439 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
440 | .name = "Analog Loopback", \ | ||
441 | .count = 1, \ | ||
442 | .info = stac92xx_aloopback_info, \ | ||
443 | .get = stac92xx_aloopback_get, \ | ||
444 | .put = stac92xx_aloopback_put, \ | ||
445 | .private_value = verb_read | (verb_write << 16), \ | ||
446 | } | ||
447 | |||
448 | #define STAC_VOLKNOB(knob_nid) \ | ||
449 | { \ | ||
450 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
451 | .name = "Master Playback Volume", \ | ||
452 | .count = 1, \ | ||
453 | .info = stac92xx_volknob_info, \ | ||
454 | .get = stac92xx_volknob_get, \ | ||
455 | .put = stac92xx_volknob_put, \ | ||
456 | .private_value = 127 | (knob_nid << 16), \ | ||
457 | } | ||
458 | |||
459 | |||
319 | static struct snd_kcontrol_new stac9200_mixer[] = { | 460 | static struct snd_kcontrol_new stac9200_mixer[] = { |
320 | HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), | 461 | HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), |
321 | HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), | 462 | HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), |
322 | { | 463 | STAC_INPUT_SOURCE(1), |
323 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
324 | .name = "Input Source", | ||
325 | .count = 1, | ||
326 | .info = stac92xx_mux_enum_info, | ||
327 | .get = stac92xx_mux_enum_get, | ||
328 | .put = stac92xx_mux_enum_put, | ||
329 | }, | ||
330 | HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT), | 464 | HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT), |
331 | HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT), | 465 | HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT), |
332 | HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT), | 466 | HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT), |
@@ -334,86 +468,68 @@ static struct snd_kcontrol_new stac9200_mixer[] = { | |||
334 | }; | 468 | }; |
335 | 469 | ||
336 | static struct snd_kcontrol_new stac925x_mixer[] = { | 470 | static struct snd_kcontrol_new stac925x_mixer[] = { |
337 | { | 471 | STAC_INPUT_SOURCE(1), |
338 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
339 | .name = "Input Source", | ||
340 | .count = 1, | ||
341 | .info = stac92xx_mux_enum_info, | ||
342 | .get = stac92xx_mux_enum_get, | ||
343 | .put = stac92xx_mux_enum_put, | ||
344 | }, | ||
345 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), | 472 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), |
346 | HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT), | 473 | HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT), |
347 | HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT), | 474 | HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT), |
348 | { } /* end */ | 475 | { } /* end */ |
349 | }; | 476 | }; |
350 | 477 | ||
351 | /* This needs to be generated dynamically based on sequence */ | 478 | static struct snd_kcontrol_new stac9205_mixer[] = { |
352 | static struct snd_kcontrol_new stac922x_mixer[] = { | ||
353 | { | 479 | { |
354 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 480 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
355 | .name = "Input Source", | 481 | .name = "Digital Input Source", |
356 | .count = 1, | 482 | .count = 1, |
357 | .info = stac92xx_mux_enum_info, | 483 | .info = stac92xx_dmux_enum_info, |
358 | .get = stac92xx_mux_enum_get, | 484 | .get = stac92xx_dmux_enum_get, |
359 | .put = stac92xx_mux_enum_put, | 485 | .put = stac92xx_dmux_enum_put, |
360 | }, | 486 | }, |
361 | HDA_CODEC_VOLUME("Capture Volume", 0x17, 0x0, HDA_INPUT), | 487 | STAC_INPUT_SOURCE(2), |
362 | HDA_CODEC_MUTE("Capture Switch", 0x17, 0x0, HDA_INPUT), | 488 | STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0), |
363 | HDA_CODEC_VOLUME("Mux Capture Volume", 0x12, 0x0, HDA_OUTPUT), | 489 | STAC_VOLKNOB(0x24), |
490 | |||
491 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT), | ||
492 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT), | ||
493 | HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x19, 0x0, HDA_OUTPUT), | ||
494 | |||
495 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT), | ||
496 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT), | ||
497 | HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x1A, 0x0, HDA_OUTPUT), | ||
498 | |||
364 | { } /* end */ | 499 | { } /* end */ |
365 | }; | 500 | }; |
366 | 501 | ||
367 | /* This needs to be generated dynamically based on sequence */ | 502 | /* This needs to be generated dynamically based on sequence */ |
368 | static struct snd_kcontrol_new stac9227_mixer[] = { | 503 | static struct snd_kcontrol_new stac922x_mixer[] = { |
369 | { | 504 | STAC_INPUT_SOURCE(2), |
370 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 505 | STAC_VOLKNOB(0x16), |
371 | .name = "Input Source", | 506 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT), |
372 | .count = 1, | 507 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT), |
373 | .info = stac92xx_mux_enum_info, | 508 | HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x12, 0x0, HDA_OUTPUT), |
374 | .get = stac92xx_mux_enum_get, | 509 | |
375 | .put = stac92xx_mux_enum_put, | 510 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT), |
376 | }, | 511 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT), |
377 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), | 512 | HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x13, 0x0, HDA_OUTPUT), |
378 | HDA_CODEC_MUTE("Capture Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
379 | { } /* end */ | 513 | { } /* end */ |
380 | }; | 514 | }; |
381 | 515 | ||
516 | |||
382 | static struct snd_kcontrol_new stac927x_mixer[] = { | 517 | static struct snd_kcontrol_new stac927x_mixer[] = { |
383 | { | 518 | STAC_INPUT_SOURCE(3), |
384 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 519 | STAC_VOLKNOB(0x24), |
385 | .name = "Input Source", | 520 | STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB), |
386 | .count = 1, | ||
387 | .info = stac92xx_mux_enum_info, | ||
388 | .get = stac92xx_mux_enum_get, | ||
389 | .put = stac92xx_mux_enum_put, | ||
390 | }, | ||
391 | HDA_CODEC_VOLUME("InMux Capture Volume", 0x15, 0x0, HDA_OUTPUT), | ||
392 | HDA_CODEC_VOLUME("InVol Capture Volume", 0x18, 0x0, HDA_INPUT), | ||
393 | HDA_CODEC_MUTE("ADCMux Capture Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
394 | { } /* end */ | ||
395 | }; | ||
396 | 521 | ||
397 | static struct snd_kcontrol_new stac9205_mixer[] = { | 522 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT), |
398 | { | 523 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT), |
399 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 524 | HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x15, 0x0, HDA_OUTPUT), |
400 | .name = "Digital Input Source", | 525 | |
401 | .count = 1, | 526 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT), |
402 | .info = stac92xx_dmux_enum_info, | 527 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT), |
403 | .get = stac92xx_dmux_enum_get, | 528 | HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x16, 0x0, HDA_OUTPUT), |
404 | .put = stac92xx_dmux_enum_put, | 529 | |
405 | }, | 530 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT), |
406 | { | 531 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT), |
407 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 532 | HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x2, 0x17, 0x0, HDA_OUTPUT), |
408 | .name = "Input Source", | ||
409 | .count = 1, | ||
410 | .info = stac92xx_mux_enum_info, | ||
411 | .get = stac92xx_mux_enum_get, | ||
412 | .put = stac92xx_mux_enum_put, | ||
413 | }, | ||
414 | HDA_CODEC_VOLUME("InMux Capture Volume", 0x19, 0x0, HDA_OUTPUT), | ||
415 | HDA_CODEC_VOLUME("InVol Capture Volume", 0x1b, 0x0, HDA_INPUT), | ||
416 | HDA_CODEC_MUTE("ADCMux Capture Switch", 0x1d, 0x0, HDA_OUTPUT), | ||
417 | { } /* end */ | 533 | { } /* end */ |
418 | }; | 534 | }; |
419 | 535 | ||
@@ -451,12 +567,145 @@ static unsigned int ref9200_pin_configs[8] = { | |||
451 | 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, | 567 | 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, |
452 | }; | 568 | }; |
453 | 569 | ||
570 | /* | ||
571 | STAC 9200 pin configs for | ||
572 | 102801A8 | ||
573 | 102801DE | ||
574 | 102801E8 | ||
575 | */ | ||
576 | static unsigned int dell9200_d21_pin_configs[8] = { | ||
577 | 0x400001f0, 0x400001f1, 0x02214030, 0x01014010, | ||
578 | 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, | ||
579 | }; | ||
580 | |||
581 | /* | ||
582 | STAC 9200 pin configs for | ||
583 | 102801C0 | ||
584 | 102801C1 | ||
585 | */ | ||
586 | static unsigned int dell9200_d22_pin_configs[8] = { | ||
587 | 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010, | ||
588 | 0x01813020, 0x02a19021, 0x90100140, 0x400001f2, | ||
589 | }; | ||
590 | |||
591 | /* | ||
592 | STAC 9200 pin configs for | ||
593 | 102801C4 (Dell Dimension E310) | ||
594 | 102801C5 | ||
595 | 102801C7 | ||
596 | 102801D9 | ||
597 | 102801DA | ||
598 | 102801E3 | ||
599 | */ | ||
600 | static unsigned int dell9200_d23_pin_configs[8] = { | ||
601 | 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010, | ||
602 | 0x01813020, 0x01a19021, 0x90100140, 0x400001f2, | ||
603 | }; | ||
604 | |||
605 | |||
606 | /* | ||
607 | STAC 9200-32 pin configs for | ||
608 | 102801B5 (Dell Inspiron 630m) | ||
609 | 102801D8 (Dell Inspiron 640m) | ||
610 | */ | ||
611 | static unsigned int dell9200_m21_pin_configs[8] = { | ||
612 | 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310, | ||
613 | 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd, | ||
614 | }; | ||
615 | |||
616 | /* | ||
617 | STAC 9200-32 pin configs for | ||
618 | 102801C2 (Dell Latitude D620) | ||
619 | 102801C8 | ||
620 | 102801CC (Dell Latitude D820) | ||
621 | 102801D4 | ||
622 | 102801D6 | ||
623 | */ | ||
624 | static unsigned int dell9200_m22_pin_configs[8] = { | ||
625 | 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310, | ||
626 | 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc, | ||
627 | }; | ||
628 | |||
629 | /* | ||
630 | STAC 9200-32 pin configs for | ||
631 | 102801CE (Dell XPS M1710) | ||
632 | 102801CF (Dell Precision M90) | ||
633 | */ | ||
634 | static unsigned int dell9200_m23_pin_configs[8] = { | ||
635 | 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310, | ||
636 | 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc, | ||
637 | }; | ||
638 | |||
639 | /* | ||
640 | STAC 9200-32 pin configs for | ||
641 | 102801C9 | ||
642 | 102801CA | ||
643 | 102801CB (Dell Latitude 120L) | ||
644 | 102801D3 | ||
645 | */ | ||
646 | static unsigned int dell9200_m24_pin_configs[8] = { | ||
647 | 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310, | ||
648 | 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe, | ||
649 | }; | ||
650 | |||
651 | /* | ||
652 | STAC 9200-32 pin configs for | ||
653 | 102801BD (Dell Inspiron E1505n) | ||
654 | 102801EE | ||
655 | 102801EF | ||
656 | */ | ||
657 | static unsigned int dell9200_m25_pin_configs[8] = { | ||
658 | 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310, | ||
659 | 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd, | ||
660 | }; | ||
661 | |||
662 | /* | ||
663 | STAC 9200-32 pin configs for | ||
664 | 102801F5 (Dell Inspiron 1501) | ||
665 | 102801F6 | ||
666 | */ | ||
667 | static unsigned int dell9200_m26_pin_configs[8] = { | ||
668 | 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310, | ||
669 | 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe, | ||
670 | }; | ||
671 | |||
672 | /* | ||
673 | STAC 9200-32 | ||
674 | 102801CD (Dell Inspiron E1705/9400) | ||
675 | */ | ||
676 | static unsigned int dell9200_m27_pin_configs[8] = { | ||
677 | 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310, | ||
678 | 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc, | ||
679 | }; | ||
680 | |||
681 | |||
454 | static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = { | 682 | static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = { |
455 | [STAC_REF] = ref9200_pin_configs, | 683 | [STAC_REF] = ref9200_pin_configs, |
684 | [STAC_9200_DELL_D21] = dell9200_d21_pin_configs, | ||
685 | [STAC_9200_DELL_D22] = dell9200_d22_pin_configs, | ||
686 | [STAC_9200_DELL_D23] = dell9200_d23_pin_configs, | ||
687 | [STAC_9200_DELL_M21] = dell9200_m21_pin_configs, | ||
688 | [STAC_9200_DELL_M22] = dell9200_m22_pin_configs, | ||
689 | [STAC_9200_DELL_M23] = dell9200_m23_pin_configs, | ||
690 | [STAC_9200_DELL_M24] = dell9200_m24_pin_configs, | ||
691 | [STAC_9200_DELL_M25] = dell9200_m25_pin_configs, | ||
692 | [STAC_9200_DELL_M26] = dell9200_m26_pin_configs, | ||
693 | [STAC_9200_DELL_M27] = dell9200_m27_pin_configs, | ||
456 | }; | 694 | }; |
457 | 695 | ||
458 | static const char *stac9200_models[STAC_9200_MODELS] = { | 696 | static const char *stac9200_models[STAC_9200_MODELS] = { |
459 | [STAC_REF] = "ref", | 697 | [STAC_REF] = "ref", |
698 | [STAC_9200_DELL_D21] = "dell-d21", | ||
699 | [STAC_9200_DELL_D22] = "dell-d22", | ||
700 | [STAC_9200_DELL_D23] = "dell-d23", | ||
701 | [STAC_9200_DELL_M21] = "dell-m21", | ||
702 | [STAC_9200_DELL_M22] = "dell-m22", | ||
703 | [STAC_9200_DELL_M23] = "dell-m23", | ||
704 | [STAC_9200_DELL_M24] = "dell-m24", | ||
705 | [STAC_9200_DELL_M25] = "dell-m25", | ||
706 | [STAC_9200_DELL_M26] = "dell-m26", | ||
707 | [STAC_9200_DELL_M27] = "dell-m27", | ||
708 | [STAC_9200_GATEWAY] = "gateway", | ||
460 | }; | 709 | }; |
461 | 710 | ||
462 | static struct snd_pci_quirk stac9200_cfg_tbl[] = { | 711 | static struct snd_pci_quirk stac9200_cfg_tbl[] = { |
@@ -464,30 +713,72 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = { | |||
464 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, | 713 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, |
465 | "DFI LanParty", STAC_REF), | 714 | "DFI LanParty", STAC_REF), |
466 | /* Dell laptops have BIOS problem */ | 715 | /* Dell laptops have BIOS problem */ |
716 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8, | ||
717 | "unknown Dell", STAC_9200_DELL_D21), | ||
467 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5, | 718 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5, |
468 | "Dell Inspiron 630m", STAC_REF), | 719 | "Dell Inspiron 630m", STAC_9200_DELL_M21), |
720 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd, | ||
721 | "Dell Inspiron E1505n", STAC_9200_DELL_M25), | ||
722 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0, | ||
723 | "unknown Dell", STAC_9200_DELL_D22), | ||
724 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1, | ||
725 | "unknown Dell", STAC_9200_DELL_D22), | ||
469 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2, | 726 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2, |
470 | "Dell Latitude D620", STAC_REF), | 727 | "Dell Latitude D620", STAC_9200_DELL_M22), |
728 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5, | ||
729 | "unknown Dell", STAC_9200_DELL_D23), | ||
730 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7, | ||
731 | "unknown Dell", STAC_9200_DELL_D23), | ||
732 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8, | ||
733 | "unknown Dell", STAC_9200_DELL_M22), | ||
734 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9, | ||
735 | "unknown Dell", STAC_9200_DELL_M24), | ||
736 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca, | ||
737 | "unknown Dell", STAC_9200_DELL_M24), | ||
471 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb, | 738 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb, |
472 | "Dell Latitude 120L", STAC_REF), | 739 | "Dell Latitude 120L", STAC_9200_DELL_M24), |
473 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc, | 740 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc, |
474 | "Dell Latitude D820", STAC_REF), | 741 | "Dell Latitude D820", STAC_9200_DELL_M22), |
475 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd, | 742 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd, |
476 | "Dell Inspiron E1705/9400", STAC_REF), | 743 | "Dell Inspiron E1705/9400", STAC_9200_DELL_M27), |
477 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce, | 744 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce, |
478 | "Dell XPS M1710", STAC_REF), | 745 | "Dell XPS M1710", STAC_9200_DELL_M23), |
479 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf, | 746 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf, |
480 | "Dell Precision M90", STAC_REF), | 747 | "Dell Precision M90", STAC_9200_DELL_M23), |
748 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3, | ||
749 | "unknown Dell", STAC_9200_DELL_M22), | ||
750 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4, | ||
751 | "unknown Dell", STAC_9200_DELL_M22), | ||
481 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6, | 752 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6, |
482 | "unknown Dell", STAC_REF), | 753 | "unknown Dell", STAC_9200_DELL_M22), |
483 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8, | 754 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8, |
484 | "Dell Inspiron 640m", STAC_REF), | 755 | "Dell Inspiron 640m", STAC_9200_DELL_M21), |
756 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9, | ||
757 | "unknown Dell", STAC_9200_DELL_D23), | ||
758 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da, | ||
759 | "unknown Dell", STAC_9200_DELL_D23), | ||
760 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de, | ||
761 | "unknown Dell", STAC_9200_DELL_D21), | ||
762 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3, | ||
763 | "unknown Dell", STAC_9200_DELL_D23), | ||
764 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8, | ||
765 | "unknown Dell", STAC_9200_DELL_D21), | ||
766 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee, | ||
767 | "unknown Dell", STAC_9200_DELL_M25), | ||
768 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef, | ||
769 | "unknown Dell", STAC_9200_DELL_M25), | ||
485 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5, | 770 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5, |
486 | "Dell Inspiron 1501", STAC_REF), | 771 | "Dell Inspiron 1501", STAC_9200_DELL_M26), |
487 | 772 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6, | |
773 | "unknown Dell", STAC_9200_DELL_M26), | ||
488 | /* Panasonic */ | 774 | /* Panasonic */ |
489 | SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_REF), | 775 | SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_REF), |
490 | 776 | /* Gateway machines needs EAPD to be set on resume */ | |
777 | SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY), | ||
778 | SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*", | ||
779 | STAC_9200_GATEWAY), | ||
780 | SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707", | ||
781 | STAC_9200_GATEWAY), | ||
491 | {} /* terminator */ | 782 | {} /* terminator */ |
492 | }; | 783 | }; |
493 | 784 | ||
@@ -543,6 +834,51 @@ static unsigned int ref922x_pin_configs[10] = { | |||
543 | 0x40000100, 0x40000100, | 834 | 0x40000100, 0x40000100, |
544 | }; | 835 | }; |
545 | 836 | ||
837 | /* | ||
838 | STAC 922X pin configs for | ||
839 | 102801A7 | ||
840 | 102801AB | ||
841 | 102801A9 | ||
842 | 102801D1 | ||
843 | 102801D2 | ||
844 | */ | ||
845 | static unsigned int dell_922x_d81_pin_configs[10] = { | ||
846 | 0x02214030, 0x01a19021, 0x01111012, 0x01114010, | ||
847 | 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1, | ||
848 | 0x01813122, 0x400001f2, | ||
849 | }; | ||
850 | |||
851 | /* | ||
852 | STAC 922X pin configs for | ||
853 | 102801AC | ||
854 | 102801D0 | ||
855 | */ | ||
856 | static unsigned int dell_922x_d82_pin_configs[10] = { | ||
857 | 0x02214030, 0x01a19021, 0x01111012, 0x01114010, | ||
858 | 0x02a19020, 0x01117011, 0x01451140, 0x400001f0, | ||
859 | 0x01813122, 0x400001f1, | ||
860 | }; | ||
861 | |||
862 | /* | ||
863 | STAC 922X pin configs for | ||
864 | 102801BF | ||
865 | */ | ||
866 | static unsigned int dell_922x_m81_pin_configs[10] = { | ||
867 | 0x0321101f, 0x01112024, 0x01111222, 0x91174220, | ||
868 | 0x03a11050, 0x01116221, 0x90a70330, 0x01452340, | ||
869 | 0x40C003f1, 0x405003f0, | ||
870 | }; | ||
871 | |||
872 | /* | ||
873 | STAC 9221 A1 pin configs for | ||
874 | 102801D7 (Dell XPS M1210) | ||
875 | */ | ||
876 | static unsigned int dell_922x_m82_pin_configs[10] = { | ||
877 | 0x0221121f, 0x408103ff, 0x02111212, 0x90100310, | ||
878 | 0x408003f1, 0x02111211, 0x03451340, 0x40c003f2, | ||
879 | 0x508003f3, 0x405003f4, | ||
880 | }; | ||
881 | |||
546 | static unsigned int d945gtp3_pin_configs[10] = { | 882 | static unsigned int d945gtp3_pin_configs[10] = { |
547 | 0x0221401f, 0x01a19022, 0x01813021, 0x01014010, | 883 | 0x0221401f, 0x01a19022, 0x01813021, 0x01014010, |
548 | 0x40000100, 0x40000100, 0x40000100, 0x40000100, | 884 | 0x40000100, 0x40000100, 0x40000100, 0x40000100, |
@@ -585,48 +921,49 @@ static unsigned int intel_mac_v5_pin_configs[10] = { | |||
585 | 0x400000fc, 0x400000fb, | 921 | 0x400000fc, 0x400000fb, |
586 | }; | 922 | }; |
587 | 923 | ||
588 | static unsigned int stac922x_dell_pin_configs[10] = { | ||
589 | 0x0221121e, 0x408103ff, 0x02a1123e, 0x90100310, | ||
590 | 0x408003f1, 0x0221122f, 0x03451340, 0x40c003f2, | ||
591 | 0x50a003f3, 0x405003f4 | ||
592 | }; | ||
593 | 924 | ||
594 | static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = { | 925 | static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = { |
595 | [STAC_D945_REF] = ref922x_pin_configs, | 926 | [STAC_D945_REF] = ref922x_pin_configs, |
596 | [STAC_D945GTP3] = d945gtp3_pin_configs, | 927 | [STAC_D945GTP3] = d945gtp3_pin_configs, |
597 | [STAC_D945GTP5] = d945gtp5_pin_configs, | 928 | [STAC_D945GTP5] = d945gtp5_pin_configs, |
598 | [STAC_922X_DELL] = stac922x_dell_pin_configs, | ||
599 | [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs, | 929 | [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs, |
600 | [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs, | 930 | [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs, |
601 | [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs, | 931 | [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs, |
602 | [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs, | 932 | [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs, |
603 | [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs, | 933 | [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs, |
604 | /* for backward compitability */ | 934 | /* for backward compatibility */ |
605 | [STAC_MACMINI] = intel_mac_v3_pin_configs, | 935 | [STAC_MACMINI] = intel_mac_v3_pin_configs, |
606 | [STAC_MACBOOK] = intel_mac_v5_pin_configs, | 936 | [STAC_MACBOOK] = intel_mac_v5_pin_configs, |
607 | [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs, | 937 | [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs, |
608 | [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs, | 938 | [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs, |
609 | [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs, | 939 | [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs, |
610 | [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs, | 940 | [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs, |
941 | [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs, | ||
942 | [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs, | ||
943 | [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs, | ||
944 | [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs, | ||
611 | }; | 945 | }; |
612 | 946 | ||
613 | static const char *stac922x_models[STAC_922X_MODELS] = { | 947 | static const char *stac922x_models[STAC_922X_MODELS] = { |
614 | [STAC_D945_REF] = "ref", | 948 | [STAC_D945_REF] = "ref", |
615 | [STAC_D945GTP5] = "5stack", | 949 | [STAC_D945GTP5] = "5stack", |
616 | [STAC_D945GTP3] = "3stack", | 950 | [STAC_D945GTP3] = "3stack", |
617 | [STAC_922X_DELL] = "dell", | ||
618 | [STAC_INTEL_MAC_V1] = "intel-mac-v1", | 951 | [STAC_INTEL_MAC_V1] = "intel-mac-v1", |
619 | [STAC_INTEL_MAC_V2] = "intel-mac-v2", | 952 | [STAC_INTEL_MAC_V2] = "intel-mac-v2", |
620 | [STAC_INTEL_MAC_V3] = "intel-mac-v3", | 953 | [STAC_INTEL_MAC_V3] = "intel-mac-v3", |
621 | [STAC_INTEL_MAC_V4] = "intel-mac-v4", | 954 | [STAC_INTEL_MAC_V4] = "intel-mac-v4", |
622 | [STAC_INTEL_MAC_V5] = "intel-mac-v5", | 955 | [STAC_INTEL_MAC_V5] = "intel-mac-v5", |
623 | /* for backward compitability */ | 956 | /* for backward compatibility */ |
624 | [STAC_MACMINI] = "macmini", | 957 | [STAC_MACMINI] = "macmini", |
625 | [STAC_MACBOOK] = "macbook", | 958 | [STAC_MACBOOK] = "macbook", |
626 | [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1", | 959 | [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1", |
627 | [STAC_MACBOOK_PRO_V2] = "macbook-pro", | 960 | [STAC_MACBOOK_PRO_V2] = "macbook-pro", |
628 | [STAC_IMAC_INTEL] = "imac-intel", | 961 | [STAC_IMAC_INTEL] = "imac-intel", |
629 | [STAC_IMAC_INTEL_20] = "imac-intel-20", | 962 | [STAC_IMAC_INTEL_20] = "imac-intel-20", |
963 | [STAC_922X_DELL_D81] = "dell-d81", | ||
964 | [STAC_922X_DELL_D82] = "dell-d82", | ||
965 | [STAC_922X_DELL_M81] = "dell-m81", | ||
966 | [STAC_922X_DELL_M82] = "dell-m82", | ||
630 | }; | 967 | }; |
631 | 968 | ||
632 | static struct snd_pci_quirk stac922x_cfg_tbl[] = { | 969 | static struct snd_pci_quirk stac922x_cfg_tbl[] = { |
@@ -690,9 +1027,25 @@ static struct snd_pci_quirk stac922x_cfg_tbl[] = { | |||
690 | /* Apple Mac Mini (early 2006) */ | 1027 | /* Apple Mac Mini (early 2006) */ |
691 | SND_PCI_QUIRK(0x8384, 0x7680, | 1028 | SND_PCI_QUIRK(0x8384, 0x7680, |
692 | "Mac Mini", STAC_INTEL_MAC_V3), | 1029 | "Mac Mini", STAC_INTEL_MAC_V3), |
693 | /* Dell */ | 1030 | /* Dell systems */ |
694 | SND_PCI_QUIRK(0x1028, 0x01d7, "Dell XPS M1210", STAC_922X_DELL), | 1031 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7, |
695 | 1032 | "unknown Dell", STAC_922X_DELL_D81), | |
1033 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9, | ||
1034 | "unknown Dell", STAC_922X_DELL_D81), | ||
1035 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab, | ||
1036 | "unknown Dell", STAC_922X_DELL_D81), | ||
1037 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac, | ||
1038 | "unknown Dell", STAC_922X_DELL_D82), | ||
1039 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf, | ||
1040 | "unknown Dell", STAC_922X_DELL_M81), | ||
1041 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0, | ||
1042 | "unknown Dell", STAC_922X_DELL_D82), | ||
1043 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1, | ||
1044 | "unknown Dell", STAC_922X_DELL_D81), | ||
1045 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2, | ||
1046 | "unknown Dell", STAC_922X_DELL_D81), | ||
1047 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7, | ||
1048 | "Dell XPS M1210", STAC_922X_DELL_M82), | ||
696 | {} /* terminator */ | 1049 | {} /* terminator */ |
697 | }; | 1050 | }; |
698 | 1051 | ||
@@ -717,16 +1070,25 @@ static unsigned int d965_5st_pin_configs[14] = { | |||
717 | 0x40000100, 0x40000100 | 1070 | 0x40000100, 0x40000100 |
718 | }; | 1071 | }; |
719 | 1072 | ||
1073 | static unsigned int dell_3st_pin_configs[14] = { | ||
1074 | 0x02211230, 0x02a11220, 0x01a19040, 0x01114210, | ||
1075 | 0x01111212, 0x01116211, 0x01813050, 0x01112214, | ||
1076 | 0x403003fa, 0x40000100, 0x40000100, 0x404003fb, | ||
1077 | 0x40c003fc, 0x40000100 | ||
1078 | }; | ||
1079 | |||
720 | static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { | 1080 | static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { |
721 | [STAC_D965_REF] = ref927x_pin_configs, | 1081 | [STAC_D965_REF] = ref927x_pin_configs, |
722 | [STAC_D965_3ST] = d965_3st_pin_configs, | 1082 | [STAC_D965_3ST] = d965_3st_pin_configs, |
723 | [STAC_D965_5ST] = d965_5st_pin_configs, | 1083 | [STAC_D965_5ST] = d965_5st_pin_configs, |
1084 | [STAC_DELL_3ST] = dell_3st_pin_configs, | ||
724 | }; | 1085 | }; |
725 | 1086 | ||
726 | static const char *stac927x_models[STAC_927X_MODELS] = { | 1087 | static const char *stac927x_models[STAC_927X_MODELS] = { |
727 | [STAC_D965_REF] = "ref", | 1088 | [STAC_D965_REF] = "ref", |
728 | [STAC_D965_3ST] = "3stack", | 1089 | [STAC_D965_3ST] = "3stack", |
729 | [STAC_D965_5ST] = "5stack", | 1090 | [STAC_D965_5ST] = "5stack", |
1091 | [STAC_DELL_3ST] = "dell-3stack", | ||
730 | }; | 1092 | }; |
731 | 1093 | ||
732 | static struct snd_pci_quirk stac927x_cfg_tbl[] = { | 1094 | static struct snd_pci_quirk stac927x_cfg_tbl[] = { |
@@ -753,7 +1115,13 @@ static struct snd_pci_quirk stac927x_cfg_tbl[] = { | |||
753 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST), | 1115 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST), |
754 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST), | 1116 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST), |
755 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST), | 1117 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST), |
1118 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_D965_3ST), | ||
1119 | /* Dell 3 stack systems */ | ||
1120 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST), | ||
1121 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST), | ||
1122 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST), | ||
756 | /* 965 based 5 stack systems */ | 1123 | /* 965 based 5 stack systems */ |
1124 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_D965_5ST), | ||
757 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST), | 1125 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST), |
758 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST), | 1126 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST), |
759 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST), | 1127 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST), |
@@ -772,23 +1140,97 @@ static unsigned int ref9205_pin_configs[12] = { | |||
772 | 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030 | 1140 | 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030 |
773 | }; | 1141 | }; |
774 | 1142 | ||
1143 | /* | ||
1144 | STAC 9205 pin configs for | ||
1145 | 102801F1 | ||
1146 | 102801F2 | ||
1147 | 102801FC | ||
1148 | 102801FD | ||
1149 | 10280204 | ||
1150 | 1028021F | ||
1151 | */ | ||
1152 | static unsigned int dell_9205_m42_pin_configs[12] = { | ||
1153 | 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310, | ||
1154 | 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9, | ||
1155 | 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE, | ||
1156 | }; | ||
1157 | |||
1158 | /* | ||
1159 | STAC 9205 pin configs for | ||
1160 | 102801F9 | ||
1161 | 102801FA | ||
1162 | 102801FE | ||
1163 | 102801FF (Dell Precision M4300) | ||
1164 | 10280206 | ||
1165 | 10280200 | ||
1166 | 10280201 | ||
1167 | */ | ||
1168 | static unsigned int dell_9205_m43_pin_configs[12] = { | ||
1169 | 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310, | ||
1170 | 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9, | ||
1171 | 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8, | ||
1172 | }; | ||
1173 | |||
1174 | static unsigned int dell_9205_m44_pin_configs[12] = { | ||
1175 | 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310, | ||
1176 | 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9, | ||
1177 | 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe, | ||
1178 | }; | ||
1179 | |||
775 | static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = { | 1180 | static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = { |
776 | [STAC_REF] = ref9205_pin_configs, | 1181 | [STAC_9205_REF] = ref9205_pin_configs, |
777 | [STAC_M43xx] = NULL, | 1182 | [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs, |
1183 | [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs, | ||
1184 | [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs, | ||
778 | }; | 1185 | }; |
779 | 1186 | ||
780 | static const char *stac9205_models[STAC_9205_MODELS] = { | 1187 | static const char *stac9205_models[STAC_9205_MODELS] = { |
781 | [STAC_9205_REF] = "ref", | 1188 | [STAC_9205_REF] = "ref", |
1189 | [STAC_9205_DELL_M42] = "dell-m42", | ||
1190 | [STAC_9205_DELL_M43] = "dell-m43", | ||
1191 | [STAC_9205_DELL_M44] = "dell-m44", | ||
782 | }; | 1192 | }; |
783 | 1193 | ||
784 | static struct snd_pci_quirk stac9205_cfg_tbl[] = { | 1194 | static struct snd_pci_quirk stac9205_cfg_tbl[] = { |
785 | /* SigmaTel reference board */ | 1195 | /* SigmaTel reference board */ |
786 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, | 1196 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, |
787 | "DFI LanParty", STAC_9205_REF), | 1197 | "DFI LanParty", STAC_9205_REF), |
788 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x01f8, | 1198 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1, |
789 | "Dell Precision", STAC_M43xx), | 1199 | "unknown Dell", STAC_9205_DELL_M42), |
790 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x01ff, | 1200 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2, |
791 | "Dell Precision", STAC_M43xx), | 1201 | "unknown Dell", STAC_9205_DELL_M42), |
1202 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8, | ||
1203 | "Dell Precision", STAC_9205_DELL_M43), | ||
1204 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c, | ||
1205 | "Dell Precision", STAC_9205_DELL_M43), | ||
1206 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9, | ||
1207 | "Dell Precision", STAC_9205_DELL_M43), | ||
1208 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b, | ||
1209 | "Dell Precision", STAC_9205_DELL_M43), | ||
1210 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa, | ||
1211 | "Dell Precision", STAC_9205_DELL_M43), | ||
1212 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc, | ||
1213 | "unknown Dell", STAC_9205_DELL_M42), | ||
1214 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd, | ||
1215 | "unknown Dell", STAC_9205_DELL_M42), | ||
1216 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe, | ||
1217 | "Dell Precision", STAC_9205_DELL_M43), | ||
1218 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff, | ||
1219 | "Dell Precision M4300", STAC_9205_DELL_M43), | ||
1220 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206, | ||
1221 | "Dell Precision", STAC_9205_DELL_M43), | ||
1222 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1, | ||
1223 | "Dell Inspiron", STAC_9205_DELL_M44), | ||
1224 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2, | ||
1225 | "Dell Inspiron", STAC_9205_DELL_M44), | ||
1226 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc, | ||
1227 | "Dell Inspiron", STAC_9205_DELL_M44), | ||
1228 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd, | ||
1229 | "Dell Inspiron", STAC_9205_DELL_M44), | ||
1230 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204, | ||
1231 | "unknown Dell", STAC_9205_DELL_M42), | ||
1232 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f, | ||
1233 | "Dell Inspiron", STAC_9205_DELL_M44), | ||
792 | {} /* terminator */ | 1234 | {} /* terminator */ |
793 | }; | 1235 | }; |
794 | 1236 | ||
@@ -854,20 +1296,20 @@ static void stac92xx_set_config_regs(struct hda_codec *codec) | |||
854 | spec->pin_configs[i]); | 1296 | spec->pin_configs[i]); |
855 | } | 1297 | } |
856 | 1298 | ||
857 | static void stac92xx_enable_gpio_mask(struct hda_codec *codec, | 1299 | static void stac92xx_enable_gpio_mask(struct hda_codec *codec) |
858 | int gpio_mask, int gpio_data) | ||
859 | { | 1300 | { |
1301 | struct sigmatel_spec *spec = codec->spec; | ||
860 | /* Configure GPIOx as output */ | 1302 | /* Configure GPIOx as output */ |
861 | snd_hda_codec_write(codec, codec->afg, 0, | 1303 | snd_hda_codec_write_cache(codec, codec->afg, 0, |
862 | AC_VERB_SET_GPIO_DIRECTION, gpio_mask); | 1304 | AC_VERB_SET_GPIO_DIRECTION, spec->gpio_mask); |
863 | /* Configure GPIOx as CMOS */ | 1305 | /* Configure GPIOx as CMOS */ |
864 | snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0x00000000); | 1306 | snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7e7, 0x00000000); |
865 | /* Assert GPIOx */ | 1307 | /* Assert GPIOx */ |
866 | snd_hda_codec_write(codec, codec->afg, 0, | 1308 | snd_hda_codec_write_cache(codec, codec->afg, 0, |
867 | AC_VERB_SET_GPIO_DATA, gpio_data); | 1309 | AC_VERB_SET_GPIO_DATA, spec->gpio_data); |
868 | /* Enable GPIOx */ | 1310 | /* Enable GPIOx */ |
869 | snd_hda_codec_write(codec, codec->afg, 0, | 1311 | snd_hda_codec_write_cache(codec, codec->afg, 0, |
870 | AC_VERB_SET_GPIO_MASK, gpio_mask); | 1312 | AC_VERB_SET_GPIO_MASK, spec->gpio_mask); |
871 | } | 1313 | } |
872 | 1314 | ||
873 | /* | 1315 | /* |
@@ -1000,10 +1442,9 @@ static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = { | |||
1000 | }; | 1442 | }; |
1001 | 1443 | ||
1002 | static struct hda_pcm_stream stac92xx_pcm_analog_capture = { | 1444 | static struct hda_pcm_stream stac92xx_pcm_analog_capture = { |
1003 | .substreams = 2, | ||
1004 | .channels_min = 2, | 1445 | .channels_min = 2, |
1005 | .channels_max = 2, | 1446 | .channels_max = 2, |
1006 | /* NID is set in stac92xx_build_pcms */ | 1447 | /* NID + .substreams is set in stac92xx_build_pcms */ |
1007 | .ops = { | 1448 | .ops = { |
1008 | .prepare = stac92xx_capture_pcm_prepare, | 1449 | .prepare = stac92xx_capture_pcm_prepare, |
1009 | .cleanup = stac92xx_capture_pcm_cleanup | 1450 | .cleanup = stac92xx_capture_pcm_cleanup |
@@ -1022,6 +1463,7 @@ static int stac92xx_build_pcms(struct hda_codec *codec) | |||
1022 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback; | 1463 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback; |
1023 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture; | 1464 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture; |
1024 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; | 1465 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; |
1466 | info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs; | ||
1025 | 1467 | ||
1026 | if (spec->alt_switch) { | 1468 | if (spec->alt_switch) { |
1027 | codec->num_pcms++; | 1469 | codec->num_pcms++; |
@@ -1066,17 +1508,11 @@ static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid) | |||
1066 | static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type) | 1508 | static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type) |
1067 | 1509 | ||
1068 | { | 1510 | { |
1069 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); | 1511 | snd_hda_codec_write_cache(codec, nid, 0, |
1512 | AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); | ||
1070 | } | 1513 | } |
1071 | 1514 | ||
1072 | static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 1515 | #define stac92xx_io_switch_info snd_ctl_boolean_mono_info |
1073 | { | ||
1074 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
1075 | uinfo->count = 1; | ||
1076 | uinfo->value.integer.min = 0; | ||
1077 | uinfo->value.integer.max = 1; | ||
1078 | return 0; | ||
1079 | } | ||
1080 | 1516 | ||
1081 | static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 1517 | static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1082 | { | 1518 | { |
@@ -1109,6 +1545,36 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
1109 | return 1; | 1545 | return 1; |
1110 | } | 1546 | } |
1111 | 1547 | ||
1548 | #define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info | ||
1549 | |||
1550 | static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol, | ||
1551 | struct snd_ctl_elem_value *ucontrol) | ||
1552 | { | ||
1553 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1554 | struct sigmatel_spec *spec = codec->spec; | ||
1555 | |||
1556 | ucontrol->value.integer.value[0] = spec->clfe_swap; | ||
1557 | return 0; | ||
1558 | } | ||
1559 | |||
1560 | static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol, | ||
1561 | struct snd_ctl_elem_value *ucontrol) | ||
1562 | { | ||
1563 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1564 | struct sigmatel_spec *spec = codec->spec; | ||
1565 | hda_nid_t nid = kcontrol->private_value & 0xff; | ||
1566 | |||
1567 | if (spec->clfe_swap == ucontrol->value.integer.value[0]) | ||
1568 | return 0; | ||
1569 | |||
1570 | spec->clfe_swap = ucontrol->value.integer.value[0]; | ||
1571 | |||
1572 | snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
1573 | spec->clfe_swap ? 0x4 : 0x0); | ||
1574 | |||
1575 | return 1; | ||
1576 | } | ||
1577 | |||
1112 | #define STAC_CODEC_IO_SWITCH(xname, xpval) \ | 1578 | #define STAC_CODEC_IO_SWITCH(xname, xpval) \ |
1113 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | 1579 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
1114 | .name = xname, \ | 1580 | .name = xname, \ |
@@ -1119,17 +1585,28 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
1119 | .private_value = xpval, \ | 1585 | .private_value = xpval, \ |
1120 | } | 1586 | } |
1121 | 1587 | ||
1588 | #define STAC_CODEC_CLFE_SWITCH(xname, xpval) \ | ||
1589 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
1590 | .name = xname, \ | ||
1591 | .index = 0, \ | ||
1592 | .info = stac92xx_clfe_switch_info, \ | ||
1593 | .get = stac92xx_clfe_switch_get, \ | ||
1594 | .put = stac92xx_clfe_switch_put, \ | ||
1595 | .private_value = xpval, \ | ||
1596 | } | ||
1122 | 1597 | ||
1123 | enum { | 1598 | enum { |
1124 | STAC_CTL_WIDGET_VOL, | 1599 | STAC_CTL_WIDGET_VOL, |
1125 | STAC_CTL_WIDGET_MUTE, | 1600 | STAC_CTL_WIDGET_MUTE, |
1126 | STAC_CTL_WIDGET_IO_SWITCH, | 1601 | STAC_CTL_WIDGET_IO_SWITCH, |
1602 | STAC_CTL_WIDGET_CLFE_SWITCH | ||
1127 | }; | 1603 | }; |
1128 | 1604 | ||
1129 | static struct snd_kcontrol_new stac92xx_control_templates[] = { | 1605 | static struct snd_kcontrol_new stac92xx_control_templates[] = { |
1130 | HDA_CODEC_VOLUME(NULL, 0, 0, 0), | 1606 | HDA_CODEC_VOLUME(NULL, 0, 0, 0), |
1131 | HDA_CODEC_MUTE(NULL, 0, 0, 0), | 1607 | HDA_CODEC_MUTE(NULL, 0, 0, 0), |
1132 | STAC_CODEC_IO_SWITCH(NULL, 0), | 1608 | STAC_CODEC_IO_SWITCH(NULL, 0), |
1609 | STAC_CODEC_CLFE_SWITCH(NULL, 0), | ||
1133 | }; | 1610 | }; |
1134 | 1611 | ||
1135 | /* add dynamic controls */ | 1612 | /* add dynamic controls */ |
@@ -1182,7 +1659,8 @@ static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cf | |||
1182 | case 3: | 1659 | case 3: |
1183 | /* add line-in as side */ | 1660 | /* add line-in as side */ |
1184 | if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) { | 1661 | if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) { |
1185 | cfg->line_out_pins[3] = cfg->input_pins[AUTO_PIN_LINE]; | 1662 | cfg->line_out_pins[cfg->line_outs] = |
1663 | cfg->input_pins[AUTO_PIN_LINE]; | ||
1186 | spec->line_switch = 1; | 1664 | spec->line_switch = 1; |
1187 | cfg->line_outs++; | 1665 | cfg->line_outs++; |
1188 | } | 1666 | } |
@@ -1190,12 +1668,14 @@ static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cf | |||
1190 | case 2: | 1668 | case 2: |
1191 | /* add line-in as clfe and mic as side */ | 1669 | /* add line-in as clfe and mic as side */ |
1192 | if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) { | 1670 | if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) { |
1193 | cfg->line_out_pins[2] = cfg->input_pins[AUTO_PIN_LINE]; | 1671 | cfg->line_out_pins[cfg->line_outs] = |
1672 | cfg->input_pins[AUTO_PIN_LINE]; | ||
1194 | spec->line_switch = 1; | 1673 | spec->line_switch = 1; |
1195 | cfg->line_outs++; | 1674 | cfg->line_outs++; |
1196 | } | 1675 | } |
1197 | if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) { | 1676 | if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) { |
1198 | cfg->line_out_pins[3] = cfg->input_pins[AUTO_PIN_MIC]; | 1677 | cfg->line_out_pins[cfg->line_outs] = |
1678 | cfg->input_pins[AUTO_PIN_MIC]; | ||
1199 | spec->mic_switch = 1; | 1679 | spec->mic_switch = 1; |
1200 | cfg->line_outs++; | 1680 | cfg->line_outs++; |
1201 | } | 1681 | } |
@@ -1203,12 +1683,14 @@ static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cf | |||
1203 | case 1: | 1683 | case 1: |
1204 | /* add line-in as surr and mic as clfe */ | 1684 | /* add line-in as surr and mic as clfe */ |
1205 | if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) { | 1685 | if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) { |
1206 | cfg->line_out_pins[1] = cfg->input_pins[AUTO_PIN_LINE]; | 1686 | cfg->line_out_pins[cfg->line_outs] = |
1687 | cfg->input_pins[AUTO_PIN_LINE]; | ||
1207 | spec->line_switch = 1; | 1688 | spec->line_switch = 1; |
1208 | cfg->line_outs++; | 1689 | cfg->line_outs++; |
1209 | } | 1690 | } |
1210 | if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) { | 1691 | if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) { |
1211 | cfg->line_out_pins[2] = cfg->input_pins[AUTO_PIN_MIC]; | 1692 | cfg->line_out_pins[cfg->line_outs] = |
1693 | cfg->input_pins[AUTO_PIN_MIC]; | ||
1212 | spec->mic_switch = 1; | 1694 | spec->mic_switch = 1; |
1213 | cfg->line_outs++; | 1695 | cfg->line_outs++; |
1214 | } | 1696 | } |
@@ -1282,8 +1764,8 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, | |||
1282 | spec->multiout.num_dacs++; | 1764 | spec->multiout.num_dacs++; |
1283 | if (conn_len > 1) { | 1765 | if (conn_len > 1) { |
1284 | /* select this DAC in the pin's input mux */ | 1766 | /* select this DAC in the pin's input mux */ |
1285 | snd_hda_codec_write(codec, nid, 0, | 1767 | snd_hda_codec_write_cache(codec, nid, 0, |
1286 | AC_VERB_SET_CONNECT_SEL, j); | 1768 | AC_VERB_SET_CONNECT_SEL, j); |
1287 | 1769 | ||
1288 | } | 1770 | } |
1289 | } | 1771 | } |
@@ -1318,7 +1800,7 @@ static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_ | |||
1318 | } | 1800 | } |
1319 | 1801 | ||
1320 | /* add playback controls from the parsed DAC table */ | 1802 | /* add playback controls from the parsed DAC table */ |
1321 | static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, | 1803 | static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, |
1322 | const struct auto_pin_cfg *cfg) | 1804 | const struct auto_pin_cfg *cfg) |
1323 | { | 1805 | { |
1324 | static const char *chname[4] = { | 1806 | static const char *chname[4] = { |
@@ -1327,6 +1809,10 @@ static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, | |||
1327 | hda_nid_t nid; | 1809 | hda_nid_t nid; |
1328 | int i, err; | 1810 | int i, err; |
1329 | 1811 | ||
1812 | struct sigmatel_spec *spec = codec->spec; | ||
1813 | unsigned int wid_caps; | ||
1814 | |||
1815 | |||
1330 | for (i = 0; i < cfg->line_outs; i++) { | 1816 | for (i = 0; i < cfg->line_outs; i++) { |
1331 | if (!spec->multiout.dac_nids[i]) | 1817 | if (!spec->multiout.dac_nids[i]) |
1332 | continue; | 1818 | continue; |
@@ -1341,6 +1827,18 @@ static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, | |||
1341 | err = create_controls(spec, "LFE", nid, 2); | 1827 | err = create_controls(spec, "LFE", nid, 2); |
1342 | if (err < 0) | 1828 | if (err < 0) |
1343 | return err; | 1829 | return err; |
1830 | |||
1831 | wid_caps = get_wcaps(codec, nid); | ||
1832 | |||
1833 | if (wid_caps & AC_WCAP_LR_SWAP) { | ||
1834 | err = stac92xx_add_control(spec, | ||
1835 | STAC_CTL_WIDGET_CLFE_SWITCH, | ||
1836 | "Swap Center/LFE Playback Switch", nid); | ||
1837 | |||
1838 | if (err < 0) | ||
1839 | return err; | ||
1840 | } | ||
1841 | |||
1344 | } else { | 1842 | } else { |
1345 | err = create_controls(spec, chname[i], nid, 3); | 1843 | err = create_controls(spec, chname[i], nid, 3); |
1346 | if (err < 0) | 1844 | if (err < 0) |
@@ -1536,9 +2034,9 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const | |||
1536 | * NID lists. Hopefully this won't get confused. | 2034 | * NID lists. Hopefully this won't get confused. |
1537 | */ | 2035 | */ |
1538 | for (i = 0; i < spec->num_muxes; i++) { | 2036 | for (i = 0; i < spec->num_muxes; i++) { |
1539 | snd_hda_codec_write(codec, spec->mux_nids[i], 0, | 2037 | snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0, |
1540 | AC_VERB_SET_CONNECT_SEL, | 2038 | AC_VERB_SET_CONNECT_SEL, |
1541 | imux->items[0].index); | 2039 | imux->items[0].index); |
1542 | } | 2040 | } |
1543 | } | 2041 | } |
1544 | 2042 | ||
@@ -1593,9 +2091,19 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out | |||
1593 | if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0) | 2091 | if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0) |
1594 | return err; | 2092 | return err; |
1595 | 2093 | ||
1596 | if ((err = stac92xx_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || | 2094 | err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg); |
1597 | (err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg)) < 0 || | 2095 | |
1598 | (err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0) | 2096 | if (err < 0) |
2097 | return err; | ||
2098 | |||
2099 | err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg); | ||
2100 | |||
2101 | if (err < 0) | ||
2102 | return err; | ||
2103 | |||
2104 | err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg); | ||
2105 | |||
2106 | if (err < 0) | ||
1599 | return err; | 2107 | return err; |
1600 | 2108 | ||
1601 | if (spec->num_dmics > 0) | 2109 | if (spec->num_dmics > 0) |
@@ -1764,9 +2272,9 @@ static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, | |||
1764 | unsigned int event) | 2272 | unsigned int event) |
1765 | { | 2273 | { |
1766 | if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) | 2274 | if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) |
1767 | snd_hda_codec_write(codec, nid, 0, | 2275 | snd_hda_codec_write_cache(codec, nid, 0, |
1768 | AC_VERB_SET_UNSOLICITED_ENABLE, | 2276 | AC_VERB_SET_UNSOLICITED_ENABLE, |
1769 | (AC_USRSP_EN | event)); | 2277 | (AC_USRSP_EN | event)); |
1770 | } | 2278 | } |
1771 | 2279 | ||
1772 | static int stac92xx_init(struct hda_codec *codec) | 2280 | static int stac92xx_init(struct hda_codec *codec) |
@@ -1870,7 +2378,7 @@ static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid, | |||
1870 | if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN)) | 2378 | if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN)) |
1871 | pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN); | 2379 | pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN); |
1872 | 2380 | ||
1873 | snd_hda_codec_write(codec, nid, 0, | 2381 | snd_hda_codec_write_cache(codec, nid, 0, |
1874 | AC_VERB_SET_PIN_WIDGET_CONTROL, | 2382 | AC_VERB_SET_PIN_WIDGET_CONTROL, |
1875 | pin_ctl | flag); | 2383 | pin_ctl | flag); |
1876 | } | 2384 | } |
@@ -1880,7 +2388,7 @@ static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid, | |||
1880 | { | 2388 | { |
1881 | unsigned int pin_ctl = snd_hda_codec_read(codec, nid, | 2389 | unsigned int pin_ctl = snd_hda_codec_read(codec, nid, |
1882 | 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00); | 2390 | 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00); |
1883 | snd_hda_codec_write(codec, nid, 0, | 2391 | snd_hda_codec_write_cache(codec, nid, 0, |
1884 | AC_VERB_SET_PIN_WIDGET_CONTROL, | 2392 | AC_VERB_SET_PIN_WIDGET_CONTROL, |
1885 | pin_ctl & ~flag); | 2393 | pin_ctl & ~flag); |
1886 | } | 2394 | } |
@@ -1936,22 +2444,22 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) | |||
1936 | } | 2444 | } |
1937 | } | 2445 | } |
1938 | 2446 | ||
1939 | #ifdef CONFIG_PM | 2447 | #ifdef SND_HDA_NEEDS_RESUME |
1940 | static int stac92xx_resume(struct hda_codec *codec) | 2448 | static int stac92xx_resume(struct hda_codec *codec) |
1941 | { | 2449 | { |
1942 | struct sigmatel_spec *spec = codec->spec; | 2450 | struct sigmatel_spec *spec = codec->spec; |
1943 | int i; | ||
1944 | 2451 | ||
1945 | stac92xx_init(codec); | ||
1946 | stac92xx_set_config_regs(codec); | 2452 | stac92xx_set_config_regs(codec); |
1947 | snd_hda_resume_ctls(codec, spec->mixer); | 2453 | snd_hda_sequence_write(codec, spec->init); |
1948 | for (i = 0; i < spec->num_mixers; i++) | 2454 | if (spec->gpio_mute) { |
1949 | snd_hda_resume_ctls(codec, spec->mixers[i]); | 2455 | stac922x_gpio_mute(codec, 0, 0); |
1950 | if (spec->multiout.dig_out_nid) | 2456 | stac922x_gpio_mute(codec, 1, 0); |
1951 | snd_hda_resume_spdif_out(codec); | 2457 | } |
1952 | if (spec->dig_in_nid) | 2458 | snd_hda_codec_resume_amp(codec); |
1953 | snd_hda_resume_spdif_in(codec); | 2459 | snd_hda_codec_resume_cache(codec); |
1954 | 2460 | /* invoke unsolicited event to reset the HP state */ | |
2461 | if (spec->hp_detect) | ||
2462 | codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); | ||
1955 | return 0; | 2463 | return 0; |
1956 | } | 2464 | } |
1957 | #endif | 2465 | #endif |
@@ -1962,7 +2470,7 @@ static struct hda_codec_ops stac92xx_patch_ops = { | |||
1962 | .init = stac92xx_init, | 2470 | .init = stac92xx_init, |
1963 | .free = stac92xx_free, | 2471 | .free = stac92xx_free, |
1964 | .unsol_event = stac92xx_unsol_event, | 2472 | .unsol_event = stac92xx_unsol_event, |
1965 | #ifdef CONFIG_PM | 2473 | #ifdef SND_HDA_NEEDS_RESUME |
1966 | .resume = stac92xx_resume, | 2474 | .resume = stac92xx_resume, |
1967 | #endif | 2475 | #endif |
1968 | }; | 2476 | }; |
@@ -2002,8 +2510,12 @@ static int patch_stac9200(struct hda_codec *codec) | |||
2002 | spec->mux_nids = stac9200_mux_nids; | 2510 | spec->mux_nids = stac9200_mux_nids; |
2003 | spec->num_muxes = 1; | 2511 | spec->num_muxes = 1; |
2004 | spec->num_dmics = 0; | 2512 | spec->num_dmics = 0; |
2513 | spec->num_adcs = 1; | ||
2005 | 2514 | ||
2006 | spec->init = stac9200_core_init; | 2515 | if (spec->board_config == STAC_9200_GATEWAY) |
2516 | spec->init = stac9200_eapd_init; | ||
2517 | else | ||
2518 | spec->init = stac9200_core_init; | ||
2007 | spec->mixer = stac9200_mixer; | 2519 | spec->mixer = stac9200_mixer; |
2008 | 2520 | ||
2009 | err = stac9200_parse_auto_config(codec); | 2521 | err = stac9200_parse_auto_config(codec); |
@@ -2053,12 +2565,13 @@ static int patch_stac925x(struct hda_codec *codec) | |||
2053 | spec->adc_nids = stac925x_adc_nids; | 2565 | spec->adc_nids = stac925x_adc_nids; |
2054 | spec->mux_nids = stac925x_mux_nids; | 2566 | spec->mux_nids = stac925x_mux_nids; |
2055 | spec->num_muxes = 1; | 2567 | spec->num_muxes = 1; |
2568 | spec->num_adcs = 1; | ||
2056 | switch (codec->vendor_id) { | 2569 | switch (codec->vendor_id) { |
2057 | case 0x83847632: /* STAC9202 */ | 2570 | case 0x83847632: /* STAC9202 */ |
2058 | case 0x83847633: /* STAC9202D */ | 2571 | case 0x83847633: /* STAC9202D */ |
2059 | case 0x83847636: /* STAC9251 */ | 2572 | case 0x83847636: /* STAC9251 */ |
2060 | case 0x83847637: /* STAC9251D */ | 2573 | case 0x83847637: /* STAC9251D */ |
2061 | spec->num_dmics = 1; | 2574 | spec->num_dmics = STAC925X_NUM_DMICS; |
2062 | spec->dmic_nids = stac925x_dmic_nids; | 2575 | spec->dmic_nids = stac925x_dmic_nids; |
2063 | break; | 2576 | break; |
2064 | default: | 2577 | default: |
@@ -2156,6 +2669,7 @@ static int patch_stac922x(struct hda_codec *codec) | |||
2156 | spec->adc_nids = stac922x_adc_nids; | 2669 | spec->adc_nids = stac922x_adc_nids; |
2157 | spec->mux_nids = stac922x_mux_nids; | 2670 | spec->mux_nids = stac922x_mux_nids; |
2158 | spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids); | 2671 | spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids); |
2672 | spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids); | ||
2159 | spec->num_dmics = 0; | 2673 | spec->num_dmics = 0; |
2160 | 2674 | ||
2161 | spec->init = stac922x_core_init; | 2675 | spec->init = stac922x_core_init; |
@@ -2224,22 +2738,25 @@ static int patch_stac927x(struct hda_codec *codec) | |||
2224 | spec->adc_nids = stac927x_adc_nids; | 2738 | spec->adc_nids = stac927x_adc_nids; |
2225 | spec->mux_nids = stac927x_mux_nids; | 2739 | spec->mux_nids = stac927x_mux_nids; |
2226 | spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); | 2740 | spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); |
2741 | spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); | ||
2227 | spec->num_dmics = 0; | 2742 | spec->num_dmics = 0; |
2228 | spec->init = d965_core_init; | 2743 | spec->init = d965_core_init; |
2229 | spec->mixer = stac9227_mixer; | 2744 | spec->mixer = stac927x_mixer; |
2230 | break; | 2745 | break; |
2231 | case STAC_D965_5ST: | 2746 | case STAC_D965_5ST: |
2232 | spec->adc_nids = stac927x_adc_nids; | 2747 | spec->adc_nids = stac927x_adc_nids; |
2233 | spec->mux_nids = stac927x_mux_nids; | 2748 | spec->mux_nids = stac927x_mux_nids; |
2234 | spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); | 2749 | spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); |
2750 | spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); | ||
2235 | spec->num_dmics = 0; | 2751 | spec->num_dmics = 0; |
2236 | spec->init = d965_core_init; | 2752 | spec->init = d965_core_init; |
2237 | spec->mixer = stac9227_mixer; | 2753 | spec->mixer = stac927x_mixer; |
2238 | break; | 2754 | break; |
2239 | default: | 2755 | default: |
2240 | spec->adc_nids = stac927x_adc_nids; | 2756 | spec->adc_nids = stac927x_adc_nids; |
2241 | spec->mux_nids = stac927x_mux_nids; | 2757 | spec->mux_nids = stac927x_mux_nids; |
2242 | spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); | 2758 | spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); |
2759 | spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); | ||
2243 | spec->num_dmics = 0; | 2760 | spec->num_dmics = 0; |
2244 | spec->init = stac927x_core_init; | 2761 | spec->init = stac927x_core_init; |
2245 | spec->mixer = stac927x_mixer; | 2762 | spec->mixer = stac927x_mixer; |
@@ -2247,7 +2764,8 @@ static int patch_stac927x(struct hda_codec *codec) | |||
2247 | 2764 | ||
2248 | spec->multiout.dac_nids = spec->dac_nids; | 2765 | spec->multiout.dac_nids = spec->dac_nids; |
2249 | /* GPIO0 High = Enable EAPD */ | 2766 | /* GPIO0 High = Enable EAPD */ |
2250 | stac92xx_enable_gpio_mask(codec, 0x00000001, 0x00000001); | 2767 | spec->gpio_mask = spec->gpio_data = 0x00000001; |
2768 | stac92xx_enable_gpio_mask(codec); | ||
2251 | 2769 | ||
2252 | err = stac92xx_parse_auto_config(codec, 0x1e, 0x20); | 2770 | err = stac92xx_parse_auto_config(codec, 0x1e, 0x20); |
2253 | if (!err) { | 2771 | if (!err) { |
@@ -2272,7 +2790,7 @@ static int patch_stac927x(struct hda_codec *codec) | |||
2272 | static int patch_stac9205(struct hda_codec *codec) | 2790 | static int patch_stac9205(struct hda_codec *codec) |
2273 | { | 2791 | { |
2274 | struct sigmatel_spec *spec; | 2792 | struct sigmatel_spec *spec; |
2275 | int err, gpio_mask, gpio_data; | 2793 | int err; |
2276 | 2794 | ||
2277 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 2795 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
2278 | if (spec == NULL) | 2796 | if (spec == NULL) |
@@ -2299,10 +2817,11 @@ static int patch_stac9205(struct hda_codec *codec) | |||
2299 | } | 2817 | } |
2300 | 2818 | ||
2301 | spec->adc_nids = stac9205_adc_nids; | 2819 | spec->adc_nids = stac9205_adc_nids; |
2820 | spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids); | ||
2302 | spec->mux_nids = stac9205_mux_nids; | 2821 | spec->mux_nids = stac9205_mux_nids; |
2303 | spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids); | 2822 | spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids); |
2304 | spec->dmic_nids = stac9205_dmic_nids; | 2823 | spec->dmic_nids = stac9205_dmic_nids; |
2305 | spec->num_dmics = ARRAY_SIZE(stac9205_dmic_nids); | 2824 | spec->num_dmics = STAC9205_NUM_DMICS; |
2306 | spec->dmux_nid = 0x1d; | 2825 | spec->dmux_nid = 0x1d; |
2307 | 2826 | ||
2308 | spec->init = stac9205_core_init; | 2827 | spec->init = stac9205_core_init; |
@@ -2310,20 +2829,25 @@ static int patch_stac9205(struct hda_codec *codec) | |||
2310 | 2829 | ||
2311 | spec->multiout.dac_nids = spec->dac_nids; | 2830 | spec->multiout.dac_nids = spec->dac_nids; |
2312 | 2831 | ||
2313 | if (spec->board_config == STAC_M43xx) { | 2832 | switch (spec->board_config){ |
2833 | case STAC_9205_DELL_M43: | ||
2314 | /* Enable SPDIF in/out */ | 2834 | /* Enable SPDIF in/out */ |
2315 | stac92xx_set_config_reg(codec, 0x1f, 0x01441030); | 2835 | stac92xx_set_config_reg(codec, 0x1f, 0x01441030); |
2316 | stac92xx_set_config_reg(codec, 0x20, 0x1c410030); | 2836 | stac92xx_set_config_reg(codec, 0x20, 0x1c410030); |
2317 | 2837 | ||
2318 | gpio_mask = 0x00000007; /* GPIO0-2 */ | 2838 | spec->gpio_mask = 0x00000007; /* GPIO0-2 */ |
2319 | /* GPIO0 High = EAPD, GPIO1 Low = DRM, | 2839 | /* GPIO0 High = EAPD, GPIO1 Low = DRM, |
2320 | * GPIO2 High = Headphone Mute | 2840 | * GPIO2 High = Headphone Mute |
2321 | */ | 2841 | */ |
2322 | gpio_data = 0x00000005; | 2842 | spec->gpio_data = 0x00000005; |
2323 | } else | 2843 | break; |
2324 | gpio_mask = gpio_data = 0x00000001; /* GPIO0 High = EAPD */ | 2844 | default: |
2845 | /* GPIO0 High = EAPD */ | ||
2846 | spec->gpio_mask = spec->gpio_data = 0x00000001; | ||
2847 | break; | ||
2848 | } | ||
2325 | 2849 | ||
2326 | stac92xx_enable_gpio_mask(codec, gpio_mask, gpio_data); | 2850 | stac92xx_enable_gpio_mask(codec); |
2327 | err = stac92xx_parse_auto_config(codec, 0x1f, 0x20); | 2851 | err = stac92xx_parse_auto_config(codec, 0x1f, 0x20); |
2328 | if (!err) { | 2852 | if (!err) { |
2329 | if (spec->board_config < 0) { | 2853 | if (spec->board_config < 0) { |
@@ -2355,7 +2879,7 @@ static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ }; | |||
2355 | static hda_nid_t vaio_mux_nids[] = { 0x15 }; | 2879 | static hda_nid_t vaio_mux_nids[] = { 0x15 }; |
2356 | 2880 | ||
2357 | static struct hda_input_mux vaio_mux = { | 2881 | static struct hda_input_mux vaio_mux = { |
2358 | .num_items = 2, | 2882 | .num_items = 3, |
2359 | .items = { | 2883 | .items = { |
2360 | /* { "HP", 0x0 }, */ | 2884 | /* { "HP", 0x0 }, */ |
2361 | { "Mic Jack", 0x1 }, | 2885 | { "Mic Jack", 0x1 }, |
@@ -2366,6 +2890,7 @@ static struct hda_input_mux vaio_mux = { | |||
2366 | 2890 | ||
2367 | static struct hda_verb vaio_init[] = { | 2891 | static struct hda_verb vaio_init[] = { |
2368 | {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */ | 2892 | {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */ |
2893 | {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT}, | ||
2369 | {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */ | 2894 | {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */ |
2370 | {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */ | 2895 | {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */ |
2371 | {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */ | 2896 | {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */ |
@@ -2397,61 +2922,28 @@ static struct hda_verb vaio_ar_init[] = { | |||
2397 | }; | 2922 | }; |
2398 | 2923 | ||
2399 | /* bind volumes of both NID 0x02 and 0x05 */ | 2924 | /* bind volumes of both NID 0x02 and 0x05 */ |
2400 | static int vaio_master_vol_put(struct snd_kcontrol *kcontrol, | 2925 | static struct hda_bind_ctls vaio_bind_master_vol = { |
2401 | struct snd_ctl_elem_value *ucontrol) | 2926 | .ops = &snd_hda_bind_vol, |
2402 | { | 2927 | .values = { |
2403 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 2928 | HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), |
2404 | long *valp = ucontrol->value.integer.value; | 2929 | HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), |
2405 | int change; | 2930 | 0 |
2406 | 2931 | }, | |
2407 | change = snd_hda_codec_amp_update(codec, 0x02, 0, HDA_OUTPUT, 0, | 2932 | }; |
2408 | 0x7f, valp[0] & 0x7f); | ||
2409 | change |= snd_hda_codec_amp_update(codec, 0x02, 1, HDA_OUTPUT, 0, | ||
2410 | 0x7f, valp[1] & 0x7f); | ||
2411 | snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, | ||
2412 | 0x7f, valp[0] & 0x7f); | ||
2413 | snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, | ||
2414 | 0x7f, valp[1] & 0x7f); | ||
2415 | return change; | ||
2416 | } | ||
2417 | 2933 | ||
2418 | /* bind volumes of both NID 0x02 and 0x05 */ | 2934 | /* bind volumes of both NID 0x02 and 0x05 */ |
2419 | static int vaio_master_sw_put(struct snd_kcontrol *kcontrol, | 2935 | static struct hda_bind_ctls vaio_bind_master_sw = { |
2420 | struct snd_ctl_elem_value *ucontrol) | 2936 | .ops = &snd_hda_bind_sw, |
2421 | { | 2937 | .values = { |
2422 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 2938 | HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), |
2423 | long *valp = ucontrol->value.integer.value; | 2939 | HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), |
2424 | int change; | 2940 | 0, |
2425 | 2941 | }, | |
2426 | change = snd_hda_codec_amp_update(codec, 0x02, 0, HDA_OUTPUT, 0, | 2942 | }; |
2427 | 0x80, (valp[0] ? 0 : 0x80)); | ||
2428 | change |= snd_hda_codec_amp_update(codec, 0x02, 1, HDA_OUTPUT, 0, | ||
2429 | 0x80, (valp[1] ? 0 : 0x80)); | ||
2430 | snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, | ||
2431 | 0x80, (valp[0] ? 0 : 0x80)); | ||
2432 | snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, | ||
2433 | 0x80, (valp[1] ? 0 : 0x80)); | ||
2434 | return change; | ||
2435 | } | ||
2436 | 2943 | ||
2437 | static struct snd_kcontrol_new vaio_mixer[] = { | 2944 | static struct snd_kcontrol_new vaio_mixer[] = { |
2438 | { | 2945 | HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol), |
2439 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2946 | HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw), |
2440 | .name = "Master Playback Volume", | ||
2441 | .info = snd_hda_mixer_amp_volume_info, | ||
2442 | .get = snd_hda_mixer_amp_volume_get, | ||
2443 | .put = vaio_master_vol_put, | ||
2444 | .tlv = { .c = snd_hda_mixer_amp_tlv }, | ||
2445 | .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), | ||
2446 | }, | ||
2447 | { | ||
2448 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2449 | .name = "Master Playback Switch", | ||
2450 | .info = snd_hda_mixer_amp_switch_info, | ||
2451 | .get = snd_hda_mixer_amp_switch_get, | ||
2452 | .put = vaio_master_sw_put, | ||
2453 | .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), | ||
2454 | }, | ||
2455 | /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */ | 2947 | /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */ |
2456 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT), | 2948 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT), |
2457 | HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT), | 2949 | HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT), |
@@ -2467,22 +2959,8 @@ static struct snd_kcontrol_new vaio_mixer[] = { | |||
2467 | }; | 2959 | }; |
2468 | 2960 | ||
2469 | static struct snd_kcontrol_new vaio_ar_mixer[] = { | 2961 | static struct snd_kcontrol_new vaio_ar_mixer[] = { |
2470 | { | 2962 | HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol), |
2471 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2963 | HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw), |
2472 | .name = "Master Playback Volume", | ||
2473 | .info = snd_hda_mixer_amp_volume_info, | ||
2474 | .get = snd_hda_mixer_amp_volume_get, | ||
2475 | .put = vaio_master_vol_put, | ||
2476 | .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), | ||
2477 | }, | ||
2478 | { | ||
2479 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2480 | .name = "Master Playback Switch", | ||
2481 | .info = snd_hda_mixer_amp_switch_info, | ||
2482 | .get = snd_hda_mixer_amp_switch_get, | ||
2483 | .put = vaio_master_sw_put, | ||
2484 | .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), | ||
2485 | }, | ||
2486 | /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */ | 2964 | /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */ |
2487 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT), | 2965 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT), |
2488 | HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT), | 2966 | HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT), |
@@ -2504,6 +2982,49 @@ static struct hda_codec_ops stac9872_patch_ops = { | |||
2504 | .build_pcms = stac92xx_build_pcms, | 2982 | .build_pcms = stac92xx_build_pcms, |
2505 | .init = stac92xx_init, | 2983 | .init = stac92xx_init, |
2506 | .free = stac92xx_free, | 2984 | .free = stac92xx_free, |
2985 | #ifdef SND_HDA_NEEDS_RESUME | ||
2986 | .resume = stac92xx_resume, | ||
2987 | #endif | ||
2988 | }; | ||
2989 | |||
2990 | static int stac9872_vaio_init(struct hda_codec *codec) | ||
2991 | { | ||
2992 | int err; | ||
2993 | |||
2994 | err = stac92xx_init(codec); | ||
2995 | if (err < 0) | ||
2996 | return err; | ||
2997 | if (codec->patch_ops.unsol_event) | ||
2998 | codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); | ||
2999 | return 0; | ||
3000 | } | ||
3001 | |||
3002 | static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res) | ||
3003 | { | ||
3004 | if (get_pin_presence(codec, 0x0a)) { | ||
3005 | stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN); | ||
3006 | stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN); | ||
3007 | } else { | ||
3008 | stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN); | ||
3009 | stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN); | ||
3010 | } | ||
3011 | } | ||
3012 | |||
3013 | static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res) | ||
3014 | { | ||
3015 | switch (res >> 26) { | ||
3016 | case STAC_HP_EVENT: | ||
3017 | stac9872_vaio_hp_detect(codec, res); | ||
3018 | break; | ||
3019 | } | ||
3020 | } | ||
3021 | |||
3022 | static struct hda_codec_ops stac9872_vaio_patch_ops = { | ||
3023 | .build_controls = stac92xx_build_controls, | ||
3024 | .build_pcms = stac92xx_build_pcms, | ||
3025 | .init = stac9872_vaio_init, | ||
3026 | .free = stac92xx_free, | ||
3027 | .unsol_event = stac9872_vaio_unsol_event, | ||
2507 | #ifdef CONFIG_PM | 3028 | #ifdef CONFIG_PM |
2508 | .resume = stac92xx_resume, | 3029 | .resume = stac92xx_resume, |
2509 | #endif | 3030 | #endif |
@@ -2564,6 +3085,7 @@ static int patch_stac9872(struct hda_codec *codec) | |||
2564 | spec->adc_nids = vaio_adcs; | 3085 | spec->adc_nids = vaio_adcs; |
2565 | spec->input_mux = &vaio_mux; | 3086 | spec->input_mux = &vaio_mux; |
2566 | spec->mux_nids = vaio_mux_nids; | 3087 | spec->mux_nids = vaio_mux_nids; |
3088 | codec->patch_ops = stac9872_vaio_patch_ops; | ||
2567 | break; | 3089 | break; |
2568 | 3090 | ||
2569 | case CXD9872AKD_VAIO: | 3091 | case CXD9872AKD_VAIO: |
@@ -2577,10 +3099,10 @@ static int patch_stac9872(struct hda_codec *codec) | |||
2577 | spec->adc_nids = vaio_adcs; | 3099 | spec->adc_nids = vaio_adcs; |
2578 | spec->input_mux = &vaio_mux; | 3100 | spec->input_mux = &vaio_mux; |
2579 | spec->mux_nids = vaio_mux_nids; | 3101 | spec->mux_nids = vaio_mux_nids; |
3102 | codec->patch_ops = stac9872_patch_ops; | ||
2580 | break; | 3103 | break; |
2581 | } | 3104 | } |
2582 | 3105 | ||
2583 | codec->patch_ops = stac9872_patch_ops; | ||
2584 | return 0; | 3106 | return 0; |
2585 | } | 3107 | } |
2586 | 3108 | ||
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index ba32d1e52cb8..33b5e1ffa817 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c | |||
@@ -115,6 +115,10 @@ struct via_spec { | |||
115 | struct snd_kcontrol_new *kctl_alloc; | 115 | struct snd_kcontrol_new *kctl_alloc; |
116 | struct hda_input_mux private_imux; | 116 | struct hda_input_mux private_imux; |
117 | hda_nid_t private_dac_nids[4]; | 117 | hda_nid_t private_dac_nids[4]; |
118 | |||
119 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
120 | struct hda_loopback_check loopback; | ||
121 | #endif | ||
118 | }; | 122 | }; |
119 | 123 | ||
120 | static hda_nid_t vt1708_adc_nids[2] = { | 124 | static hda_nid_t vt1708_adc_nids[2] = { |
@@ -305,15 +309,15 @@ static struct hda_verb vt1708_volume_init_verbs[] = { | |||
305 | {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 309 | {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
306 | 310 | ||
307 | 311 | ||
308 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | 312 | /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback |
309 | * mixer widget | 313 | * mixer widget |
310 | */ | 314 | */ |
311 | /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ | 315 | /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ |
312 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 316 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* master */ |
313 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 317 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
314 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | 318 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, |
315 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | 319 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, |
316 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | 320 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, |
317 | 321 | ||
318 | /* | 322 | /* |
319 | * Set up output mixers (0x19 - 0x1b) | 323 | * Set up output mixers (0x19 - 0x1b) |
@@ -543,24 +547,11 @@ static int via_init(struct hda_codec *codec) | |||
543 | return 0; | 547 | return 0; |
544 | } | 548 | } |
545 | 549 | ||
546 | #ifdef CONFIG_PM | 550 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
547 | /* | 551 | static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid) |
548 | * resume | ||
549 | */ | ||
550 | static int via_resume(struct hda_codec *codec) | ||
551 | { | 552 | { |
552 | struct via_spec *spec = codec->spec; | 553 | struct via_spec *spec = codec->spec; |
553 | int i; | 554 | return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); |
554 | |||
555 | via_init(codec); | ||
556 | for (i = 0; i < spec->num_mixers; i++) | ||
557 | snd_hda_resume_ctls(codec, spec->mixers[i]); | ||
558 | if (spec->multiout.dig_out_nid) | ||
559 | snd_hda_resume_spdif_out(codec); | ||
560 | if (spec->dig_in_nid) | ||
561 | snd_hda_resume_spdif_in(codec); | ||
562 | |||
563 | return 0; | ||
564 | } | 555 | } |
565 | #endif | 556 | #endif |
566 | 557 | ||
@@ -571,8 +562,8 @@ static struct hda_codec_ops via_patch_ops = { | |||
571 | .build_pcms = via_build_pcms, | 562 | .build_pcms = via_build_pcms, |
572 | .init = via_init, | 563 | .init = via_init, |
573 | .free = via_free, | 564 | .free = via_free, |
574 | #ifdef CONFIG_PM | 565 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
575 | .resume = via_resume, | 566 | .check_power_status = via_check_power_status, |
576 | #endif | 567 | #endif |
577 | }; | 568 | }; |
578 | 569 | ||
@@ -762,6 +753,16 @@ static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec, | |||
762 | return 0; | 753 | return 0; |
763 | } | 754 | } |
764 | 755 | ||
756 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
757 | static struct hda_amp_list vt1708_loopbacks[] = { | ||
758 | { 0x17, HDA_INPUT, 1 }, | ||
759 | { 0x17, HDA_INPUT, 2 }, | ||
760 | { 0x17, HDA_INPUT, 3 }, | ||
761 | { 0x17, HDA_INPUT, 4 }, | ||
762 | { } /* end */ | ||
763 | }; | ||
764 | #endif | ||
765 | |||
765 | static int vt1708_parse_auto_config(struct hda_codec *codec) | 766 | static int vt1708_parse_auto_config(struct hda_codec *codec) |
766 | { | 767 | { |
767 | struct via_spec *spec = codec->spec; | 768 | struct via_spec *spec = codec->spec; |
@@ -855,6 +856,9 @@ static int patch_vt1708(struct hda_codec *codec) | |||
855 | codec->patch_ops = via_patch_ops; | 856 | codec->patch_ops = via_patch_ops; |
856 | 857 | ||
857 | codec->patch_ops.init = via_auto_init; | 858 | codec->patch_ops.init = via_auto_init; |
859 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
860 | spec->loopback.amplist = vt1708_loopbacks; | ||
861 | #endif | ||
858 | 862 | ||
859 | return 0; | 863 | return 0; |
860 | } | 864 | } |
@@ -895,15 +899,15 @@ static struct hda_verb vt1709_10ch_volume_init_verbs[] = { | |||
895 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 899 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
896 | 900 | ||
897 | 901 | ||
898 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | 902 | /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback |
899 | * mixer widget | 903 | * mixer widget |
900 | */ | 904 | */ |
901 | /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ | 905 | /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ |
902 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 906 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* unmute master */ |
903 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 907 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, |
904 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | 908 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, |
905 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | 909 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, |
906 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | 910 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, |
907 | 911 | ||
908 | /* | 912 | /* |
909 | * Set up output selector (0x1a, 0x1b, 0x29) | 913 | * Set up output selector (0x1a, 0x1b, 0x29) |
@@ -1251,6 +1255,16 @@ static int vt1709_parse_auto_config(struct hda_codec *codec) | |||
1251 | return 1; | 1255 | return 1; |
1252 | } | 1256 | } |
1253 | 1257 | ||
1258 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1259 | static struct hda_amp_list vt1709_loopbacks[] = { | ||
1260 | { 0x18, HDA_INPUT, 1 }, | ||
1261 | { 0x18, HDA_INPUT, 2 }, | ||
1262 | { 0x18, HDA_INPUT, 3 }, | ||
1263 | { 0x18, HDA_INPUT, 4 }, | ||
1264 | { } /* end */ | ||
1265 | }; | ||
1266 | #endif | ||
1267 | |||
1254 | static int patch_vt1709_10ch(struct hda_codec *codec) | 1268 | static int patch_vt1709_10ch(struct hda_codec *codec) |
1255 | { | 1269 | { |
1256 | struct via_spec *spec; | 1270 | struct via_spec *spec; |
@@ -1293,6 +1307,9 @@ static int patch_vt1709_10ch(struct hda_codec *codec) | |||
1293 | codec->patch_ops = via_patch_ops; | 1307 | codec->patch_ops = via_patch_ops; |
1294 | 1308 | ||
1295 | codec->patch_ops.init = via_auto_init; | 1309 | codec->patch_ops.init = via_auto_init; |
1310 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1311 | spec->loopback.amplist = vt1709_loopbacks; | ||
1312 | #endif | ||
1296 | 1313 | ||
1297 | return 0; | 1314 | return 0; |
1298 | } | 1315 | } |
@@ -1383,6 +1400,9 @@ static int patch_vt1709_6ch(struct hda_codec *codec) | |||
1383 | codec->patch_ops = via_patch_ops; | 1400 | codec->patch_ops = via_patch_ops; |
1384 | 1401 | ||
1385 | codec->patch_ops.init = via_auto_init; | 1402 | codec->patch_ops.init = via_auto_init; |
1403 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1404 | spec->loopback.amplist = vt1709_loopbacks; | ||
1405 | #endif | ||
1386 | 1406 | ||
1387 | return 0; | 1407 | return 0; |
1388 | } | 1408 | } |