diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 90 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 7 | ||||
-rw-r--r-- | sound/pci/hda/hda_eld.c | 5 | ||||
-rw-r--r-- | sound/pci/hda/hda_hwdep.c | 38 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel.c | 46 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 15 | ||||
-rw-r--r-- | sound/pci/hda/hda_proc.c | 16 | ||||
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 16 | ||||
-rw-r--r-- | sound/pci/hda/patch_intelhdmi.c | 411 | ||||
-rw-r--r-- | sound/pci/hda/patch_nvhdmi.c | 2 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 160 | ||||
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 113 | ||||
-rw-r--r-- | sound/pci/hda/patch_via.c | 3519 |
13 files changed, 3860 insertions, 578 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index af989f660cca..444d9039c1ac 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -515,6 +515,7 @@ static int snd_hda_bus_dev_register(struct snd_device *device) | |||
515 | struct hda_codec *codec; | 515 | struct hda_codec *codec; |
516 | list_for_each_entry(codec, &bus->codec_list, list) { | 516 | list_for_each_entry(codec, &bus->codec_list, list) { |
517 | snd_hda_hwdep_add_sysfs(codec); | 517 | snd_hda_hwdep_add_sysfs(codec); |
518 | snd_hda_hwdep_add_power_sysfs(codec); | ||
518 | } | 519 | } |
519 | return 0; | 520 | return 0; |
520 | } | 521 | } |
@@ -2452,9 +2453,11 @@ static void hda_call_codec_suspend(struct hda_codec *codec) | |||
2452 | codec->afg ? codec->afg : codec->mfg, | 2453 | codec->afg ? codec->afg : codec->mfg, |
2453 | AC_PWRST_D3); | 2454 | AC_PWRST_D3); |
2454 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 2455 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
2456 | snd_hda_update_power_acct(codec); | ||
2455 | cancel_delayed_work(&codec->power_work); | 2457 | cancel_delayed_work(&codec->power_work); |
2456 | codec->power_on = 0; | 2458 | codec->power_on = 0; |
2457 | codec->power_transition = 0; | 2459 | codec->power_transition = 0; |
2460 | codec->power_jiffies = jiffies; | ||
2458 | #endif | 2461 | #endif |
2459 | } | 2462 | } |
2460 | 2463 | ||
@@ -2877,51 +2880,35 @@ static int set_pcm_default_values(struct hda_codec *codec, | |||
2877 | return 0; | 2880 | return 0; |
2878 | } | 2881 | } |
2879 | 2882 | ||
2883 | const char *snd_hda_pcm_type_name[HDA_PCM_NTYPES] = { | ||
2884 | "Audio", "SPDIF", "HDMI", "Modem" | ||
2885 | }; | ||
2886 | |||
2880 | /* | 2887 | /* |
2881 | * get the empty PCM device number to assign | 2888 | * get the empty PCM device number to assign |
2882 | */ | 2889 | */ |
2883 | static int get_empty_pcm_device(struct hda_bus *bus, int type) | 2890 | static int get_empty_pcm_device(struct hda_bus *bus, int type) |
2884 | { | 2891 | { |
2885 | static const char *dev_name[HDA_PCM_NTYPES] = { | 2892 | /* audio device indices; not linear to keep compatibility */ |
2886 | "Audio", "SPDIF", "HDMI", "Modem" | 2893 | static int audio_idx[HDA_PCM_NTYPES][5] = { |
2894 | [HDA_PCM_TYPE_AUDIO] = { 0, 2, 4, 5, -1 }, | ||
2895 | [HDA_PCM_TYPE_SPDIF] = { 1, -1 }, | ||
2896 | [HDA_PCM_TYPE_HDMI] = { 3, 7, 8, 9, -1 }, | ||
2897 | [HDA_PCM_TYPE_MODEM] = { 6, -1 }, | ||
2887 | }; | 2898 | }; |
2888 | /* starting device index for each PCM type */ | 2899 | int i; |
2889 | static int dev_idx[HDA_PCM_NTYPES] = { | 2900 | |
2890 | [HDA_PCM_TYPE_AUDIO] = 0, | 2901 | if (type >= HDA_PCM_NTYPES) { |
2891 | [HDA_PCM_TYPE_SPDIF] = 1, | ||
2892 | [HDA_PCM_TYPE_HDMI] = 3, | ||
2893 | [HDA_PCM_TYPE_MODEM] = 6 | ||
2894 | }; | ||
2895 | /* normal audio device indices; not linear to keep compatibility */ | ||
2896 | static int audio_idx[4] = { 0, 2, 4, 5 }; | ||
2897 | int i, dev; | ||
2898 | |||
2899 | switch (type) { | ||
2900 | case HDA_PCM_TYPE_AUDIO: | ||
2901 | for (i = 0; i < ARRAY_SIZE(audio_idx); i++) { | ||
2902 | dev = audio_idx[i]; | ||
2903 | if (!test_bit(dev, bus->pcm_dev_bits)) | ||
2904 | goto ok; | ||
2905 | } | ||
2906 | snd_printk(KERN_WARNING "Too many audio devices\n"); | ||
2907 | return -EAGAIN; | ||
2908 | case HDA_PCM_TYPE_SPDIF: | ||
2909 | case HDA_PCM_TYPE_HDMI: | ||
2910 | case HDA_PCM_TYPE_MODEM: | ||
2911 | dev = dev_idx[type]; | ||
2912 | if (test_bit(dev, bus->pcm_dev_bits)) { | ||
2913 | snd_printk(KERN_WARNING "%s already defined\n", | ||
2914 | dev_name[type]); | ||
2915 | return -EAGAIN; | ||
2916 | } | ||
2917 | break; | ||
2918 | default: | ||
2919 | snd_printk(KERN_WARNING "Invalid PCM type %d\n", type); | 2902 | snd_printk(KERN_WARNING "Invalid PCM type %d\n", type); |
2920 | return -EINVAL; | 2903 | return -EINVAL; |
2921 | } | 2904 | } |
2922 | ok: | 2905 | |
2923 | set_bit(dev, bus->pcm_dev_bits); | 2906 | for (i = 0; audio_idx[type][i] >= 0 ; i++) |
2924 | return dev; | 2907 | if (!test_and_set_bit(audio_idx[type][i], bus->pcm_dev_bits)) |
2908 | return audio_idx[type][i]; | ||
2909 | |||
2910 | snd_printk(KERN_WARNING "Too many %s devices\n", snd_hda_pcm_type_name[type]); | ||
2911 | return -EAGAIN; | ||
2925 | } | 2912 | } |
2926 | 2913 | ||
2927 | /* | 2914 | /* |
@@ -3207,6 +3194,17 @@ static void hda_keep_power_on(struct hda_codec *codec) | |||
3207 | { | 3194 | { |
3208 | codec->power_count++; | 3195 | codec->power_count++; |
3209 | codec->power_on = 1; | 3196 | codec->power_on = 1; |
3197 | codec->power_jiffies = jiffies; | ||
3198 | } | ||
3199 | |||
3200 | void snd_hda_update_power_acct(struct hda_codec *codec) | ||
3201 | { | ||
3202 | unsigned long delta = jiffies - codec->power_jiffies; | ||
3203 | if (codec->power_on) | ||
3204 | codec->power_on_acct += delta; | ||
3205 | else | ||
3206 | codec->power_off_acct += delta; | ||
3207 | codec->power_jiffies += delta; | ||
3210 | } | 3208 | } |
3211 | 3209 | ||
3212 | void snd_hda_power_up(struct hda_codec *codec) | 3210 | void snd_hda_power_up(struct hda_codec *codec) |
@@ -3217,7 +3215,9 @@ void snd_hda_power_up(struct hda_codec *codec) | |||
3217 | if (codec->power_on || codec->power_transition) | 3215 | if (codec->power_on || codec->power_transition) |
3218 | return; | 3216 | return; |
3219 | 3217 | ||
3218 | snd_hda_update_power_acct(codec); | ||
3220 | codec->power_on = 1; | 3219 | codec->power_on = 1; |
3220 | codec->power_jiffies = jiffies; | ||
3221 | if (bus->ops.pm_notify) | 3221 | if (bus->ops.pm_notify) |
3222 | bus->ops.pm_notify(bus); | 3222 | bus->ops.pm_notify(bus); |
3223 | hda_call_codec_resume(codec); | 3223 | hda_call_codec_resume(codec); |
@@ -3421,6 +3421,24 @@ static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid) | |||
3421 | } | 3421 | } |
3422 | } | 3422 | } |
3423 | 3423 | ||
3424 | /* call each reboot notifier */ | ||
3425 | void snd_hda_bus_reboot_notify(struct hda_bus *bus) | ||
3426 | { | ||
3427 | struct hda_codec *codec; | ||
3428 | |||
3429 | if (!bus) | ||
3430 | return; | ||
3431 | list_for_each_entry(codec, &bus->codec_list, list) { | ||
3432 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
3433 | if (!codec->power_on) | ||
3434 | continue; | ||
3435 | #endif | ||
3436 | if (codec->patch_ops.reboot_notify) | ||
3437 | codec->patch_ops.reboot_notify(codec); | ||
3438 | } | ||
3439 | } | ||
3440 | EXPORT_SYMBOL_HDA(snd_hda_bus_reboot_notify); | ||
3441 | |||
3424 | /* | 3442 | /* |
3425 | * open the digital out in the exclusive mode | 3443 | * open the digital out in the exclusive mode |
3426 | */ | 3444 | */ |
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 99552fb5f756..b16678cade18 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h | |||
@@ -674,6 +674,7 @@ struct hda_codec_ops { | |||
674 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 674 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
675 | int (*check_power_status)(struct hda_codec *codec, hda_nid_t nid); | 675 | int (*check_power_status)(struct hda_codec *codec, hda_nid_t nid); |
676 | #endif | 676 | #endif |
677 | void (*reboot_notify)(struct hda_codec *codec); | ||
677 | }; | 678 | }; |
678 | 679 | ||
679 | /* record for amp information cache */ | 680 | /* record for amp information cache */ |
@@ -811,6 +812,9 @@ struct hda_codec { | |||
811 | unsigned int power_transition :1; /* power-state in transition */ | 812 | unsigned int power_transition :1; /* power-state in transition */ |
812 | int power_count; /* current (global) power refcount */ | 813 | int power_count; /* current (global) power refcount */ |
813 | struct delayed_work power_work; /* delayed task for powerdown */ | 814 | struct delayed_work power_work; /* delayed task for powerdown */ |
815 | unsigned long power_on_acct; | ||
816 | unsigned long power_off_acct; | ||
817 | unsigned long power_jiffies; | ||
814 | #endif | 818 | #endif |
815 | 819 | ||
816 | /* codec-specific additional proc output */ | 820 | /* codec-specific additional proc output */ |
@@ -893,6 +897,7 @@ int snd_hda_codec_build_controls(struct hda_codec *codec); | |||
893 | /* | 897 | /* |
894 | * PCM | 898 | * PCM |
895 | */ | 899 | */ |
900 | extern const char *snd_hda_pcm_type_name[]; | ||
896 | int snd_hda_build_pcms(struct hda_bus *bus); | 901 | int snd_hda_build_pcms(struct hda_bus *bus); |
897 | int snd_hda_codec_build_pcms(struct hda_codec *codec); | 902 | int snd_hda_codec_build_pcms(struct hda_codec *codec); |
898 | void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, | 903 | void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, |
@@ -910,6 +915,7 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, | |||
910 | * Misc | 915 | * Misc |
911 | */ | 916 | */ |
912 | void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen); | 917 | void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen); |
918 | void snd_hda_bus_reboot_notify(struct hda_bus *bus); | ||
913 | 919 | ||
914 | /* | 920 | /* |
915 | * power management | 921 | * power management |
@@ -933,6 +939,7 @@ const char *snd_hda_get_jack_location(u32 cfg); | |||
933 | void snd_hda_power_up(struct hda_codec *codec); | 939 | void snd_hda_power_up(struct hda_codec *codec); |
934 | void snd_hda_power_down(struct hda_codec *codec); | 940 | void snd_hda_power_down(struct hda_codec *codec); |
935 | #define snd_hda_codec_needs_resume(codec) codec->power_count | 941 | #define snd_hda_codec_needs_resume(codec) codec->power_count |
942 | void snd_hda_update_power_acct(struct hda_codec *codec); | ||
936 | #else | 943 | #else |
937 | static inline void snd_hda_power_up(struct hda_codec *codec) {} | 944 | static inline void snd_hda_power_up(struct hda_codec *codec) {} |
938 | static inline void snd_hda_power_down(struct hda_codec *codec) {} | 945 | static inline void snd_hda_power_down(struct hda_codec *codec) {} |
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 9446a5abea13..20fa6aee29c0 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c | |||
@@ -560,13 +560,14 @@ static void hdmi_write_eld_info(struct snd_info_entry *entry, | |||
560 | } | 560 | } |
561 | 561 | ||
562 | 562 | ||
563 | int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld) | 563 | int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld, |
564 | int index) | ||
564 | { | 565 | { |
565 | char name[32]; | 566 | char name[32]; |
566 | struct snd_info_entry *entry; | 567 | struct snd_info_entry *entry; |
567 | int err; | 568 | int err; |
568 | 569 | ||
569 | snprintf(name, sizeof(name), "eld#%d", codec->addr); | 570 | snprintf(name, sizeof(name), "eld#%d.%d", codec->addr, index); |
570 | err = snd_card_proc_new(codec->bus->card, name, &entry); | 571 | err = snd_card_proc_new(codec->bus->card, name, &entry); |
571 | if (err < 0) | 572 | if (err < 0) |
572 | return err; | 573 | return err; |
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index cc24e6721d74..d24328661c6a 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c | |||
@@ -154,6 +154,44 @@ int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec) | |||
154 | return 0; | 154 | return 0; |
155 | } | 155 | } |
156 | 156 | ||
157 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
158 | static ssize_t power_on_acct_show(struct device *dev, | ||
159 | struct device_attribute *attr, | ||
160 | char *buf) | ||
161 | { | ||
162 | struct snd_hwdep *hwdep = dev_get_drvdata(dev); | ||
163 | struct hda_codec *codec = hwdep->private_data; | ||
164 | snd_hda_update_power_acct(codec); | ||
165 | return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_on_acct)); | ||
166 | } | ||
167 | |||
168 | static ssize_t power_off_acct_show(struct device *dev, | ||
169 | struct device_attribute *attr, | ||
170 | char *buf) | ||
171 | { | ||
172 | struct snd_hwdep *hwdep = dev_get_drvdata(dev); | ||
173 | struct hda_codec *codec = hwdep->private_data; | ||
174 | snd_hda_update_power_acct(codec); | ||
175 | return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_off_acct)); | ||
176 | } | ||
177 | |||
178 | static struct device_attribute power_attrs[] = { | ||
179 | __ATTR_RO(power_on_acct), | ||
180 | __ATTR_RO(power_off_acct), | ||
181 | }; | ||
182 | |||
183 | int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec) | ||
184 | { | ||
185 | struct snd_hwdep *hwdep = codec->hwdep; | ||
186 | int i; | ||
187 | |||
188 | for (i = 0; i < ARRAY_SIZE(power_attrs); i++) | ||
189 | snd_add_device_sysfs_file(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, | ||
190 | hwdep->device, &power_attrs[i]); | ||
191 | return 0; | ||
192 | } | ||
193 | #endif /* CONFIG_SND_HDA_POWER_SAVE */ | ||
194 | |||
157 | #ifdef CONFIG_SND_HDA_RECONFIG | 195 | #ifdef CONFIG_SND_HDA_RECONFIG |
158 | 196 | ||
159 | /* | 197 | /* |
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index c9ad182e1b4b..e73e395e7601 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -60,7 +60,7 @@ static int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; | |||
60 | static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; | 60 | static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; |
61 | static int probe_only[SNDRV_CARDS]; | 61 | static int probe_only[SNDRV_CARDS]; |
62 | static int single_cmd; | 62 | static int single_cmd; |
63 | static int enable_msi; | 63 | static int enable_msi = -1; |
64 | #ifdef CONFIG_SND_HDA_PATCH_LOADER | 64 | #ifdef CONFIG_SND_HDA_PATCH_LOADER |
65 | static char *patch[SNDRV_CARDS]; | 65 | static char *patch[SNDRV_CARDS]; |
66 | #endif | 66 | #endif |
@@ -677,6 +677,14 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, | |||
677 | } | 677 | } |
678 | } | 678 | } |
679 | 679 | ||
680 | if (!chip->polling_mode) { | ||
681 | snd_printk(KERN_WARNING SFX "azx_get_response timeout, " | ||
682 | "switching to polling mode: last cmd=0x%08x\n", | ||
683 | chip->last_cmd[addr]); | ||
684 | chip->polling_mode = 1; | ||
685 | goto again; | ||
686 | } | ||
687 | |||
680 | if (chip->msi) { | 688 | if (chip->msi) { |
681 | snd_printk(KERN_WARNING SFX "No response from codec, " | 689 | snd_printk(KERN_WARNING SFX "No response from codec, " |
682 | "disabling MSI: last cmd=0x%08x\n", | 690 | "disabling MSI: last cmd=0x%08x\n", |
@@ -692,14 +700,6 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, | |||
692 | goto again; | 700 | goto again; |
693 | } | 701 | } |
694 | 702 | ||
695 | if (!chip->polling_mode) { | ||
696 | snd_printk(KERN_WARNING SFX "azx_get_response timeout, " | ||
697 | "switching to polling mode: last cmd=0x%08x\n", | ||
698 | chip->last_cmd[addr]); | ||
699 | chip->polling_mode = 1; | ||
700 | goto again; | ||
701 | } | ||
702 | |||
703 | if (chip->probing) { | 703 | if (chip->probing) { |
704 | /* If this critical timeout happens during the codec probing | 704 | /* If this critical timeout happens during the codec probing |
705 | * phase, this is likely an access to a non-existing codec | 705 | * phase, this is likely an access to a non-existing codec |
@@ -722,9 +722,10 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, | |||
722 | chip->last_cmd[addr]); | 722 | chip->last_cmd[addr]); |
723 | chip->single_cmd = 1; | 723 | chip->single_cmd = 1; |
724 | bus->response_reset = 0; | 724 | bus->response_reset = 0; |
725 | /* re-initialize CORB/RIRB */ | 725 | /* release CORB/RIRB */ |
726 | azx_free_cmd_io(chip); | 726 | azx_free_cmd_io(chip); |
727 | azx_init_cmd_io(chip); | 727 | /* disable unsolicited responses */ |
728 | azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_UNSOL); | ||
728 | return -1; | 729 | return -1; |
729 | } | 730 | } |
730 | 731 | ||
@@ -865,7 +866,9 @@ static int azx_reset(struct azx *chip) | |||
865 | } | 866 | } |
866 | 867 | ||
867 | /* Accept unsolicited responses */ | 868 | /* Accept unsolicited responses */ |
868 | azx_writel(chip, GCTL, azx_readl(chip, GCTL) | ICH6_GCTL_UNSOL); | 869 | if (!chip->single_cmd) |
870 | azx_writel(chip, GCTL, azx_readl(chip, GCTL) | | ||
871 | ICH6_GCTL_UNSOL); | ||
869 | 872 | ||
870 | /* detect codecs */ | 873 | /* detect codecs */ |
871 | if (!chip->codec_mask) { | 874 | if (!chip->codec_mask) { |
@@ -980,7 +983,8 @@ static void azx_init_chip(struct azx *chip) | |||
980 | azx_int_enable(chip); | 983 | azx_int_enable(chip); |
981 | 984 | ||
982 | /* initialize the codec command I/O */ | 985 | /* initialize the codec command I/O */ |
983 | azx_init_cmd_io(chip); | 986 | if (!chip->single_cmd) |
987 | azx_init_cmd_io(chip); | ||
984 | 988 | ||
985 | /* program the position buffer */ | 989 | /* program the position buffer */ |
986 | azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); | 990 | azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); |
@@ -2150,6 +2154,7 @@ static int azx_resume(struct pci_dev *pci) | |||
2150 | static int azx_halt(struct notifier_block *nb, unsigned long event, void *buf) | 2154 | static int azx_halt(struct notifier_block *nb, unsigned long event, void *buf) |
2151 | { | 2155 | { |
2152 | struct azx *chip = container_of(nb, struct azx, reboot_notifier); | 2156 | struct azx *chip = container_of(nb, struct azx, reboot_notifier); |
2157 | snd_hda_bus_reboot_notify(chip->bus); | ||
2153 | azx_stop_chip(chip); | 2158 | azx_stop_chip(chip); |
2154 | return NOTIFY_OK; | 2159 | return NOTIFY_OK; |
2155 | } | 2160 | } |
@@ -2300,11 +2305,9 @@ static void __devinit check_probe_mask(struct azx *chip, int dev) | |||
2300 | } | 2305 | } |
2301 | 2306 | ||
2302 | /* | 2307 | /* |
2303 | * white-list for enable_msi | 2308 | * white/black-list for enable_msi |
2304 | */ | 2309 | */ |
2305 | static struct snd_pci_quirk msi_white_list[] __devinitdata = { | 2310 | static struct snd_pci_quirk msi_black_list[] __devinitdata = { |
2306 | SND_PCI_QUIRK(0x103c, 0x30f7, "HP Pavilion dv4t-1300", 1), | ||
2307 | SND_PCI_QUIRK(0x103c, 0x3607, "HP Compa CQ40", 1), | ||
2308 | {} | 2311 | {} |
2309 | }; | 2312 | }; |
2310 | 2313 | ||
@@ -2312,10 +2315,12 @@ static void __devinit check_msi(struct azx *chip) | |||
2312 | { | 2315 | { |
2313 | const struct snd_pci_quirk *q; | 2316 | const struct snd_pci_quirk *q; |
2314 | 2317 | ||
2315 | chip->msi = enable_msi; | 2318 | if (enable_msi >= 0) { |
2316 | if (chip->msi) | 2319 | chip->msi = !!enable_msi; |
2317 | return; | 2320 | return; |
2318 | q = snd_pci_quirk_lookup(chip->pci, msi_white_list); | 2321 | } |
2322 | chip->msi = 1; /* enable MSI as default */ | ||
2323 | q = snd_pci_quirk_lookup(chip->pci, msi_black_list); | ||
2319 | if (q) { | 2324 | if (q) { |
2320 | printk(KERN_INFO | 2325 | printk(KERN_INFO |
2321 | "hda_intel: msi for device %04x:%04x set to %d\n", | 2326 | "hda_intel: msi for device %04x:%04x set to %d\n", |
@@ -2674,6 +2679,7 @@ static struct pci_device_id azx_ids[] = { | |||
2674 | { PCI_DEVICE(0x10de, 0x044b), .driver_data = AZX_DRIVER_NVIDIA }, | 2679 | { PCI_DEVICE(0x10de, 0x044b), .driver_data = AZX_DRIVER_NVIDIA }, |
2675 | { PCI_DEVICE(0x10de, 0x055c), .driver_data = AZX_DRIVER_NVIDIA }, | 2680 | { PCI_DEVICE(0x10de, 0x055c), .driver_data = AZX_DRIVER_NVIDIA }, |
2676 | { PCI_DEVICE(0x10de, 0x055d), .driver_data = AZX_DRIVER_NVIDIA }, | 2681 | { PCI_DEVICE(0x10de, 0x055d), .driver_data = AZX_DRIVER_NVIDIA }, |
2682 | { PCI_DEVICE(0x10de, 0x0590), .driver_data = AZX_DRIVER_NVIDIA }, | ||
2677 | { PCI_DEVICE(0x10de, 0x0774), .driver_data = AZX_DRIVER_NVIDIA }, | 2683 | { PCI_DEVICE(0x10de, 0x0774), .driver_data = AZX_DRIVER_NVIDIA }, |
2678 | { PCI_DEVICE(0x10de, 0x0775), .driver_data = AZX_DRIVER_NVIDIA }, | 2684 | { PCI_DEVICE(0x10de, 0x0775), .driver_data = AZX_DRIVER_NVIDIA }, |
2679 | { PCI_DEVICE(0x10de, 0x0776), .driver_data = AZX_DRIVER_NVIDIA }, | 2685 | { PCI_DEVICE(0x10de, 0x0776), .driver_data = AZX_DRIVER_NVIDIA }, |
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 5f1dcc59002b..c1ca3182e6a4 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h | |||
@@ -437,6 +437,15 @@ int snd_hda_create_hwdep(struct hda_codec *codec); | |||
437 | static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; } | 437 | static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; } |
438 | #endif | 438 | #endif |
439 | 439 | ||
440 | #if defined(CONFIG_SND_HDA_POWER_SAVE) && defined(CONFIG_SND_HDA_HWDEP) | ||
441 | int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec); | ||
442 | #else | ||
443 | static inline int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec) | ||
444 | { | ||
445 | return 0; | ||
446 | } | ||
447 | #endif | ||
448 | |||
440 | #ifdef CONFIG_SND_HDA_RECONFIG | 449 | #ifdef CONFIG_SND_HDA_RECONFIG |
441 | int snd_hda_hwdep_add_sysfs(struct hda_codec *codec); | 450 | int snd_hda_hwdep_add_sysfs(struct hda_codec *codec); |
442 | #else | 451 | #else |
@@ -541,11 +550,13 @@ int snd_hdmi_get_eld(struct hdmi_eld *, struct hda_codec *, hda_nid_t); | |||
541 | void snd_hdmi_show_eld(struct hdmi_eld *eld); | 550 | void snd_hdmi_show_eld(struct hdmi_eld *eld); |
542 | 551 | ||
543 | #ifdef CONFIG_PROC_FS | 552 | #ifdef CONFIG_PROC_FS |
544 | int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld); | 553 | int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld, |
554 | int index); | ||
545 | void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld); | 555 | void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld); |
546 | #else | 556 | #else |
547 | static inline int snd_hda_eld_proc_new(struct hda_codec *codec, | 557 | static inline int snd_hda_eld_proc_new(struct hda_codec *codec, |
548 | struct hdmi_eld *eld) | 558 | struct hdmi_eld *eld, |
559 | int index) | ||
549 | { | 560 | { |
550 | return 0; | 561 | return 0; |
551 | } | 562 | } |
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 95f24e4729f8..f5b783ce450d 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c | |||
@@ -309,7 +309,21 @@ static void print_audio_io(struct snd_info_buffer *buffer, | |||
309 | struct hda_codec *codec, hda_nid_t nid, | 309 | struct hda_codec *codec, hda_nid_t nid, |
310 | unsigned int wid_type) | 310 | unsigned int wid_type) |
311 | { | 311 | { |
312 | int conv = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); | 312 | int pcm, conv; |
313 | for (pcm = 0; pcm < codec->num_pcms; pcm++) { | ||
314 | int type; | ||
315 | struct hda_pcm *cpcm = &codec->pcm_info[pcm]; | ||
316 | for (type = 0; type < 2; type++) { | ||
317 | if (cpcm->stream[type].nid != nid || cpcm->pcm == NULL) | ||
318 | continue; | ||
319 | snd_iprintf(buffer, " Device: name=\"%s\", " | ||
320 | "type=\"%s\", device=%i\n", | ||
321 | cpcm->name, | ||
322 | snd_hda_pcm_type_name[cpcm->pcm_type], | ||
323 | cpcm->pcm->device); | ||
324 | } | ||
325 | } | ||
326 | conv = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); | ||
313 | snd_iprintf(buffer, | 327 | snd_iprintf(buffer, |
314 | " Converter: stream=%d, channel=%d\n", | 328 | " Converter: stream=%d, channel=%d\n", |
315 | (conv & AC_CONV_STREAM) >> AC_CONV_STREAM_SHIFT, | 329 | (conv & AC_CONV_STREAM) >> AC_CONV_STREAM_SHIFT, |
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 3fbbc8c01e70..905859d4f4df 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -110,6 +110,7 @@ struct conexant_spec { | |||
110 | 110 | ||
111 | unsigned int dell_automute; | 111 | unsigned int dell_automute; |
112 | unsigned int port_d_mode; | 112 | unsigned int port_d_mode; |
113 | unsigned char ext_mic_bias; | ||
113 | }; | 114 | }; |
114 | 115 | ||
115 | static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, | 116 | static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, |
@@ -1927,6 +1928,11 @@ static hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 }; | |||
1927 | static hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 }; | 1928 | static hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 }; |
1928 | #define CXT5066_SPDIF_OUT 0x21 | 1929 | #define CXT5066_SPDIF_OUT 0x21 |
1929 | 1930 | ||
1931 | /* OLPC's microphone port is DC coupled for use with external sensors, | ||
1932 | * therefore we use a 50% mic bias in order to center the input signal with | ||
1933 | * the DC input range of the codec. */ | ||
1934 | #define CXT5066_OLPC_EXT_MIC_BIAS PIN_VREF50 | ||
1935 | |||
1930 | static struct hda_channel_mode cxt5066_modes[1] = { | 1936 | static struct hda_channel_mode cxt5066_modes[1] = { |
1931 | { 2, NULL }, | 1937 | { 2, NULL }, |
1932 | }; | 1938 | }; |
@@ -1980,9 +1986,10 @@ static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol, | |||
1980 | /* toggle input of built-in and mic jack appropriately */ | 1986 | /* toggle input of built-in and mic jack appropriately */ |
1981 | static void cxt5066_automic(struct hda_codec *codec) | 1987 | static void cxt5066_automic(struct hda_codec *codec) |
1982 | { | 1988 | { |
1983 | static struct hda_verb ext_mic_present[] = { | 1989 | struct conexant_spec *spec = codec->spec; |
1990 | struct hda_verb ext_mic_present[] = { | ||
1984 | /* enable external mic, port B */ | 1991 | /* enable external mic, port B */ |
1985 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 1992 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias}, |
1986 | 1993 | ||
1987 | /* switch to external mic input */ | 1994 | /* switch to external mic input */ |
1988 | {0x17, AC_VERB_SET_CONNECT_SEL, 0}, | 1995 | {0x17, AC_VERB_SET_CONNECT_SEL, 0}, |
@@ -2235,7 +2242,7 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = { | |||
2235 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ | 2242 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ |
2236 | 2243 | ||
2237 | /* Port B: external microphone */ | 2244 | /* Port B: external microphone */ |
2238 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 2245 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, CXT5066_OLPC_EXT_MIC_BIAS}, |
2239 | 2246 | ||
2240 | /* Port C: internal microphone */ | 2247 | /* Port C: internal microphone */ |
2241 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 2248 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
@@ -2325,6 +2332,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { | |||
2325 | CXT5066_LAPTOP), | 2332 | CXT5066_LAPTOP), |
2326 | SND_PCI_QUIRK(0x1028, 0x02f5, "Dell", | 2333 | SND_PCI_QUIRK(0x1028, 0x02f5, "Dell", |
2327 | CXT5066_DELL_LAPTOP), | 2334 | CXT5066_DELL_LAPTOP), |
2335 | SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), | ||
2328 | {} | 2336 | {} |
2329 | }; | 2337 | }; |
2330 | 2338 | ||
@@ -2352,6 +2360,7 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
2352 | spec->input_mux = &cxt5066_capture_source; | 2360 | spec->input_mux = &cxt5066_capture_source; |
2353 | 2361 | ||
2354 | spec->port_d_mode = PIN_HP; | 2362 | spec->port_d_mode = PIN_HP; |
2363 | spec->ext_mic_bias = PIN_VREF80; | ||
2355 | 2364 | ||
2356 | spec->num_init_verbs = 1; | 2365 | spec->num_init_verbs = 1; |
2357 | spec->init_verbs[0] = cxt5066_init_verbs; | 2366 | spec->init_verbs[0] = cxt5066_init_verbs; |
@@ -2383,6 +2392,7 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
2383 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; | 2392 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; |
2384 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; | 2393 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; |
2385 | spec->port_d_mode = 0; | 2394 | spec->port_d_mode = 0; |
2395 | spec->ext_mic_bias = CXT5066_OLPC_EXT_MIC_BIAS; | ||
2386 | 2396 | ||
2387 | /* no S/PDIF out */ | 2397 | /* no S/PDIF out */ |
2388 | spec->multiout.dig_out_nid = 0; | 2398 | spec->multiout.dig_out_nid = 0; |
diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 01a18ed475ac..4f25f08d332b 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c | |||
@@ -33,15 +33,43 @@ | |||
33 | #include "hda_codec.h" | 33 | #include "hda_codec.h" |
34 | #include "hda_local.h" | 34 | #include "hda_local.h" |
35 | 35 | ||
36 | static hda_nid_t cvt_nid; /* audio converter */ | 36 | /* |
37 | static hda_nid_t pin_nid; /* HDMI output pin */ | 37 | * The HDMI/DisplayPort configuration can be highly dynamic. A graphics device |
38 | * could support two independent pipes, each of them can be connected to one or | ||
39 | * more ports (DVI, HDMI or DisplayPort). | ||
40 | * | ||
41 | * The HDA correspondence of pipes/ports are converter/pin nodes. | ||
42 | */ | ||
43 | #define INTEL_HDMI_CVTS 2 | ||
44 | #define INTEL_HDMI_PINS 3 | ||
38 | 45 | ||
39 | #define INTEL_HDMI_EVENT_TAG 0x08 | 46 | static char *intel_hdmi_pcm_names[INTEL_HDMI_CVTS] = { |
47 | "INTEL HDMI 0", | ||
48 | "INTEL HDMI 1", | ||
49 | }; | ||
40 | 50 | ||
41 | struct intel_hdmi_spec { | 51 | struct intel_hdmi_spec { |
42 | struct hda_multi_out multiout; | 52 | int num_cvts; |
43 | struct hda_pcm pcm_rec; | 53 | int num_pins; |
44 | struct hdmi_eld sink_eld; | 54 | hda_nid_t cvt[INTEL_HDMI_CVTS+1]; /* audio sources */ |
55 | hda_nid_t pin[INTEL_HDMI_PINS+1]; /* audio sinks */ | ||
56 | |||
57 | /* | ||
58 | * source connection for each pin | ||
59 | */ | ||
60 | hda_nid_t pin_cvt[INTEL_HDMI_PINS+1]; | ||
61 | |||
62 | /* | ||
63 | * HDMI sink attached to each pin | ||
64 | */ | ||
65 | bool sink_present[INTEL_HDMI_PINS]; | ||
66 | bool sink_eldv[INTEL_HDMI_PINS]; | ||
67 | struct hdmi_eld sink_eld[INTEL_HDMI_PINS]; | ||
68 | |||
69 | /* | ||
70 | * export one pcm per pipe | ||
71 | */ | ||
72 | struct hda_pcm pcm_rec[INTEL_HDMI_CVTS]; | ||
45 | }; | 73 | }; |
46 | 74 | ||
47 | struct hdmi_audio_infoframe { | 75 | struct hdmi_audio_infoframe { |
@@ -184,40 +212,165 @@ static struct cea_channel_speaker_allocation channel_allocations[] = { | |||
184 | { .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } }, | 212 | { .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } }, |
185 | }; | 213 | }; |
186 | 214 | ||
215 | |||
216 | /* | ||
217 | * HDA/HDMI auto parsing | ||
218 | */ | ||
219 | |||
220 | static int hda_node_index(hda_nid_t *nids, hda_nid_t nid) | ||
221 | { | ||
222 | int i; | ||
223 | |||
224 | for (i = 0; nids[i]; i++) | ||
225 | if (nids[i] == nid) | ||
226 | return i; | ||
227 | |||
228 | snd_printk(KERN_WARNING "HDMI: nid %d not registered\n", nid); | ||
229 | return -EINVAL; | ||
230 | } | ||
231 | |||
232 | static int intel_hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid) | ||
233 | { | ||
234 | struct intel_hdmi_spec *spec = codec->spec; | ||
235 | hda_nid_t conn_list[HDA_MAX_CONNECTIONS]; | ||
236 | int conn_len, curr; | ||
237 | int index; | ||
238 | |||
239 | if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) { | ||
240 | snd_printk(KERN_WARNING | ||
241 | "HDMI: pin %d wcaps %#x " | ||
242 | "does not support connection list\n", | ||
243 | pin_nid, get_wcaps(codec, pin_nid)); | ||
244 | return -EINVAL; | ||
245 | } | ||
246 | |||
247 | conn_len = snd_hda_get_connections(codec, pin_nid, conn_list, | ||
248 | HDA_MAX_CONNECTIONS); | ||
249 | if (conn_len > 1) | ||
250 | curr = snd_hda_codec_read(codec, pin_nid, 0, | ||
251 | AC_VERB_GET_CONNECT_SEL, 0); | ||
252 | else | ||
253 | curr = 0; | ||
254 | |||
255 | index = hda_node_index(spec->pin, pin_nid); | ||
256 | if (index < 0) | ||
257 | return -EINVAL; | ||
258 | |||
259 | spec->pin_cvt[index] = conn_list[curr]; | ||
260 | |||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | static int intel_hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) | ||
265 | { | ||
266 | struct intel_hdmi_spec *spec = codec->spec; | ||
267 | |||
268 | if (spec->num_pins >= INTEL_HDMI_PINS) { | ||
269 | snd_printk(KERN_WARNING | ||
270 | "HDMI: no space for pin %d \n", pin_nid); | ||
271 | return -EINVAL; | ||
272 | } | ||
273 | |||
274 | spec->pin[spec->num_pins] = pin_nid; | ||
275 | spec->num_pins++; | ||
276 | |||
277 | /* | ||
278 | * It is assumed that converter nodes come first in the node list and | ||
279 | * hence have been registered and usable now. | ||
280 | */ | ||
281 | return intel_hdmi_read_pin_conn(codec, pin_nid); | ||
282 | } | ||
283 | |||
284 | static int intel_hdmi_add_cvt(struct hda_codec *codec, hda_nid_t nid) | ||
285 | { | ||
286 | struct intel_hdmi_spec *spec = codec->spec; | ||
287 | |||
288 | if (spec->num_cvts >= INTEL_HDMI_CVTS) { | ||
289 | snd_printk(KERN_WARNING | ||
290 | "HDMI: no space for converter %d \n", nid); | ||
291 | return -EINVAL; | ||
292 | } | ||
293 | |||
294 | spec->cvt[spec->num_cvts] = nid; | ||
295 | spec->num_cvts++; | ||
296 | |||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | static int intel_hdmi_parse_codec(struct hda_codec *codec) | ||
301 | { | ||
302 | hda_nid_t nid; | ||
303 | int i, nodes; | ||
304 | |||
305 | nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid); | ||
306 | if (!nid || nodes < 0) { | ||
307 | snd_printk(KERN_WARNING "HDMI: failed to get afg sub nodes\n"); | ||
308 | return -EINVAL; | ||
309 | } | ||
310 | |||
311 | for (i = 0; i < nodes; i++, nid++) { | ||
312 | unsigned int caps; | ||
313 | unsigned int type; | ||
314 | |||
315 | caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP); | ||
316 | type = get_wcaps_type(caps); | ||
317 | |||
318 | if (!(caps & AC_WCAP_DIGITAL)) | ||
319 | continue; | ||
320 | |||
321 | switch (type) { | ||
322 | case AC_WID_AUD_OUT: | ||
323 | if (intel_hdmi_add_cvt(codec, nid) < 0) | ||
324 | return -EINVAL; | ||
325 | break; | ||
326 | case AC_WID_PIN: | ||
327 | caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); | ||
328 | if (!(caps & AC_PINCAP_HDMI)) | ||
329 | continue; | ||
330 | if (intel_hdmi_add_pin(codec, nid) < 0) | ||
331 | return -EINVAL; | ||
332 | break; | ||
333 | } | ||
334 | } | ||
335 | |||
336 | return 0; | ||
337 | } | ||
338 | |||
187 | /* | 339 | /* |
188 | * HDMI routines | 340 | * HDMI routines |
189 | */ | 341 | */ |
190 | 342 | ||
191 | #ifdef BE_PARANOID | 343 | #ifdef BE_PARANOID |
192 | static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t nid, | 344 | static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t pin_nid, |
193 | int *packet_index, int *byte_index) | 345 | int *packet_index, int *byte_index) |
194 | { | 346 | { |
195 | int val; | 347 | int val; |
196 | 348 | ||
197 | val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_INDEX, 0); | 349 | val = snd_hda_codec_read(codec, pin_nid, 0, |
350 | AC_VERB_GET_HDMI_DIP_INDEX, 0); | ||
198 | 351 | ||
199 | *packet_index = val >> 5; | 352 | *packet_index = val >> 5; |
200 | *byte_index = val & 0x1f; | 353 | *byte_index = val & 0x1f; |
201 | } | 354 | } |
202 | #endif | 355 | #endif |
203 | 356 | ||
204 | static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t nid, | 357 | static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t pin_nid, |
205 | int packet_index, int byte_index) | 358 | int packet_index, int byte_index) |
206 | { | 359 | { |
207 | int val; | 360 | int val; |
208 | 361 | ||
209 | val = (packet_index << 5) | (byte_index & 0x1f); | 362 | val = (packet_index << 5) | (byte_index & 0x1f); |
210 | 363 | ||
211 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val); | 364 | snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val); |
212 | } | 365 | } |
213 | 366 | ||
214 | static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t nid, | 367 | static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t pin_nid, |
215 | unsigned char val) | 368 | unsigned char val) |
216 | { | 369 | { |
217 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val); | 370 | snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val); |
218 | } | 371 | } |
219 | 372 | ||
220 | static void hdmi_enable_output(struct hda_codec *codec) | 373 | static void hdmi_enable_output(struct hda_codec *codec, hda_nid_t pin_nid) |
221 | { | 374 | { |
222 | /* Unmute */ | 375 | /* Unmute */ |
223 | if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP) | 376 | if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP) |
@@ -231,7 +384,8 @@ static void hdmi_enable_output(struct hda_codec *codec) | |||
231 | /* | 384 | /* |
232 | * Enable Audio InfoFrame Transmission | 385 | * Enable Audio InfoFrame Transmission |
233 | */ | 386 | */ |
234 | static void hdmi_start_infoframe_trans(struct hda_codec *codec) | 387 | static void hdmi_start_infoframe_trans(struct hda_codec *codec, |
388 | hda_nid_t pin_nid) | ||
235 | { | 389 | { |
236 | hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); | 390 | hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); |
237 | snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, | 391 | snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, |
@@ -241,37 +395,42 @@ static void hdmi_start_infoframe_trans(struct hda_codec *codec) | |||
241 | /* | 395 | /* |
242 | * Disable Audio InfoFrame Transmission | 396 | * Disable Audio InfoFrame Transmission |
243 | */ | 397 | */ |
244 | static void hdmi_stop_infoframe_trans(struct hda_codec *codec) | 398 | static void hdmi_stop_infoframe_trans(struct hda_codec *codec, |
399 | hda_nid_t pin_nid) | ||
245 | { | 400 | { |
246 | hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); | 401 | hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); |
247 | snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, | 402 | snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, |
248 | AC_DIPXMIT_DISABLE); | 403 | AC_DIPXMIT_DISABLE); |
249 | } | 404 | } |
250 | 405 | ||
251 | static int hdmi_get_channel_count(struct hda_codec *codec) | 406 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
407 | static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t nid) | ||
252 | { | 408 | { |
253 | return 1 + snd_hda_codec_read(codec, cvt_nid, 0, | 409 | return 1 + snd_hda_codec_read(codec, nid, 0, |
254 | AC_VERB_GET_CVT_CHAN_COUNT, 0); | 410 | AC_VERB_GET_CVT_CHAN_COUNT, 0); |
255 | } | 411 | } |
412 | #endif | ||
256 | 413 | ||
257 | static void hdmi_set_channel_count(struct hda_codec *codec, int chs) | 414 | static void hdmi_set_channel_count(struct hda_codec *codec, |
415 | hda_nid_t nid, int chs) | ||
258 | { | 416 | { |
259 | snd_hda_codec_write(codec, cvt_nid, 0, | 417 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); |
260 | AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); | ||
261 | 418 | ||
262 | if (chs != hdmi_get_channel_count(codec)) | 419 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
420 | if (chs != hdmi_get_channel_count(codec, nid)) | ||
263 | snd_printd(KERN_INFO "HDMI channel count: expect %d, get %d\n", | 421 | snd_printd(KERN_INFO "HDMI channel count: expect %d, get %d\n", |
264 | chs, hdmi_get_channel_count(codec)); | 422 | chs, hdmi_get_channel_count(codec, nid)); |
423 | #endif | ||
265 | } | 424 | } |
266 | 425 | ||
267 | static void hdmi_debug_channel_mapping(struct hda_codec *codec) | 426 | static void hdmi_debug_channel_mapping(struct hda_codec *codec, hda_nid_t nid) |
268 | { | 427 | { |
269 | #ifdef CONFIG_SND_DEBUG_VERBOSE | 428 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
270 | int i; | 429 | int i; |
271 | int slot; | 430 | int slot; |
272 | 431 | ||
273 | for (i = 0; i < 8; i++) { | 432 | for (i = 0; i < 8; i++) { |
274 | slot = snd_hda_codec_read(codec, cvt_nid, 0, | 433 | slot = snd_hda_codec_read(codec, nid, 0, |
275 | AC_VERB_GET_HDMI_CHAN_SLOT, i); | 434 | AC_VERB_GET_HDMI_CHAN_SLOT, i); |
276 | printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n", | 435 | printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n", |
277 | slot >> 4, slot & 0x7); | 436 | slot >> 4, slot & 0x7); |
@@ -279,12 +438,12 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec) | |||
279 | #endif | 438 | #endif |
280 | } | 439 | } |
281 | 440 | ||
282 | static void hdmi_parse_eld(struct hda_codec *codec) | 441 | static void hdmi_parse_eld(struct hda_codec *codec, int index) |
283 | { | 442 | { |
284 | struct intel_hdmi_spec *spec = codec->spec; | 443 | struct intel_hdmi_spec *spec = codec->spec; |
285 | struct hdmi_eld *eld = &spec->sink_eld; | 444 | struct hdmi_eld *eld = &spec->sink_eld[index]; |
286 | 445 | ||
287 | if (!snd_hdmi_get_eld(eld, codec, pin_nid)) | 446 | if (!snd_hdmi_get_eld(eld, codec, spec->pin[index])) |
288 | snd_hdmi_show_eld(eld); | 447 | snd_hdmi_show_eld(eld); |
289 | } | 448 | } |
290 | 449 | ||
@@ -293,7 +452,7 @@ static void hdmi_parse_eld(struct hda_codec *codec) | |||
293 | * Audio InfoFrame routines | 452 | * Audio InfoFrame routines |
294 | */ | 453 | */ |
295 | 454 | ||
296 | static void hdmi_debug_dip_size(struct hda_codec *codec) | 455 | static void hdmi_debug_dip_size(struct hda_codec *codec, hda_nid_t pin_nid) |
297 | { | 456 | { |
298 | #ifdef CONFIG_SND_DEBUG_VERBOSE | 457 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
299 | int i; | 458 | int i; |
@@ -310,7 +469,7 @@ static void hdmi_debug_dip_size(struct hda_codec *codec) | |||
310 | #endif | 469 | #endif |
311 | } | 470 | } |
312 | 471 | ||
313 | static void hdmi_clear_dip_buffers(struct hda_codec *codec) | 472 | static void hdmi_clear_dip_buffers(struct hda_codec *codec, hda_nid_t pin_nid) |
314 | { | 473 | { |
315 | #ifdef BE_PARANOID | 474 | #ifdef BE_PARANOID |
316 | int i, j; | 475 | int i, j; |
@@ -340,14 +499,15 @@ static void hdmi_clear_dip_buffers(struct hda_codec *codec) | |||
340 | } | 499 | } |
341 | 500 | ||
342 | static void hdmi_fill_audio_infoframe(struct hda_codec *codec, | 501 | static void hdmi_fill_audio_infoframe(struct hda_codec *codec, |
343 | struct hdmi_audio_infoframe *ai) | 502 | hda_nid_t pin_nid, |
503 | struct hdmi_audio_infoframe *ai) | ||
344 | { | 504 | { |
345 | u8 *params = (u8 *)ai; | 505 | u8 *params = (u8 *)ai; |
346 | u8 sum = 0; | 506 | u8 sum = 0; |
347 | int i; | 507 | int i; |
348 | 508 | ||
349 | hdmi_debug_dip_size(codec); | 509 | hdmi_debug_dip_size(codec, pin_nid); |
350 | hdmi_clear_dip_buffers(codec); /* be paranoid */ | 510 | hdmi_clear_dip_buffers(codec, pin_nid); /* be paranoid */ |
351 | 511 | ||
352 | for (i = 0; i < sizeof(ai); i++) | 512 | for (i = 0; i < sizeof(ai); i++) |
353 | sum += params[i]; | 513 | sum += params[i]; |
@@ -386,11 +546,11 @@ static void init_channel_allocations(void) | |||
386 | * | 546 | * |
387 | * TODO: it could select the wrong CA from multiple candidates. | 547 | * TODO: it could select the wrong CA from multiple candidates. |
388 | */ | 548 | */ |
389 | static int hdmi_setup_channel_allocation(struct hda_codec *codec, | 549 | static int hdmi_setup_channel_allocation(struct hda_codec *codec, hda_nid_t nid, |
390 | struct hdmi_audio_infoframe *ai) | 550 | struct hdmi_audio_infoframe *ai) |
391 | { | 551 | { |
392 | struct intel_hdmi_spec *spec = codec->spec; | 552 | struct intel_hdmi_spec *spec = codec->spec; |
393 | struct hdmi_eld *eld = &spec->sink_eld; | 553 | struct hdmi_eld *eld; |
394 | int i; | 554 | int i; |
395 | int spk_mask = 0; | 555 | int spk_mask = 0; |
396 | int channels = 1 + (ai->CC02_CT47 & 0x7); | 556 | int channels = 1 + (ai->CC02_CT47 & 0x7); |
@@ -402,6 +562,11 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, | |||
402 | if (channels <= 2) | 562 | if (channels <= 2) |
403 | return 0; | 563 | return 0; |
404 | 564 | ||
565 | i = hda_node_index(spec->pin_cvt, nid); | ||
566 | if (i < 0) | ||
567 | return 0; | ||
568 | eld = &spec->sink_eld[i]; | ||
569 | |||
405 | /* | 570 | /* |
406 | * HDMI sink's ELD info cannot always be retrieved for now, e.g. | 571 | * HDMI sink's ELD info cannot always be retrieved for now, e.g. |
407 | * in console or for audio devices. Assume the highest speakers | 572 | * in console or for audio devices. Assume the highest speakers |
@@ -439,8 +604,8 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, | |||
439 | return ai->CA; | 604 | return ai->CA; |
440 | } | 605 | } |
441 | 606 | ||
442 | static void hdmi_setup_channel_mapping(struct hda_codec *codec, | 607 | static void hdmi_setup_channel_mapping(struct hda_codec *codec, hda_nid_t nid, |
443 | struct hdmi_audio_infoframe *ai) | 608 | struct hdmi_audio_infoframe *ai) |
444 | { | 609 | { |
445 | int i; | 610 | int i; |
446 | 611 | ||
@@ -453,17 +618,20 @@ static void hdmi_setup_channel_mapping(struct hda_codec *codec, | |||
453 | */ | 618 | */ |
454 | 619 | ||
455 | for (i = 0; i < 8; i++) | 620 | for (i = 0; i < 8; i++) |
456 | snd_hda_codec_write(codec, cvt_nid, 0, | 621 | snd_hda_codec_write(codec, nid, 0, |
457 | AC_VERB_SET_HDMI_CHAN_SLOT, | 622 | AC_VERB_SET_HDMI_CHAN_SLOT, |
458 | (i << 4) | i); | 623 | (i << 4) | i); |
459 | 624 | ||
460 | hdmi_debug_channel_mapping(codec); | 625 | hdmi_debug_channel_mapping(codec, nid); |
461 | } | 626 | } |
462 | 627 | ||
463 | 628 | ||
464 | static void hdmi_setup_audio_infoframe(struct hda_codec *codec, | 629 | static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, |
465 | struct snd_pcm_substream *substream) | 630 | struct snd_pcm_substream *substream) |
466 | { | 631 | { |
632 | struct intel_hdmi_spec *spec = codec->spec; | ||
633 | hda_nid_t pin_nid; | ||
634 | int i; | ||
467 | struct hdmi_audio_infoframe ai = { | 635 | struct hdmi_audio_infoframe ai = { |
468 | .type = 0x84, | 636 | .type = 0x84, |
469 | .ver = 0x01, | 637 | .ver = 0x01, |
@@ -471,11 +639,19 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, | |||
471 | .CC02_CT47 = substream->runtime->channels - 1, | 639 | .CC02_CT47 = substream->runtime->channels - 1, |
472 | }; | 640 | }; |
473 | 641 | ||
474 | hdmi_setup_channel_allocation(codec, &ai); | 642 | hdmi_setup_channel_allocation(codec, nid, &ai); |
475 | hdmi_setup_channel_mapping(codec, &ai); | 643 | hdmi_setup_channel_mapping(codec, nid, &ai); |
644 | |||
645 | for (i = 0; i < spec->num_pins; i++) { | ||
646 | if (spec->pin_cvt[i] != nid) | ||
647 | continue; | ||
648 | if (spec->sink_present[i] != true) | ||
649 | continue; | ||
476 | 650 | ||
477 | hdmi_fill_audio_infoframe(codec, &ai); | 651 | pin_nid = spec->pin[i]; |
478 | hdmi_start_infoframe_trans(codec); | 652 | hdmi_fill_audio_infoframe(codec, pin_nid, &ai); |
653 | hdmi_start_infoframe_trans(codec, pin_nid); | ||
654 | } | ||
479 | } | 655 | } |
480 | 656 | ||
481 | 657 | ||
@@ -485,27 +661,39 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, | |||
485 | 661 | ||
486 | static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) | 662 | static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) |
487 | { | 663 | { |
664 | struct intel_hdmi_spec *spec = codec->spec; | ||
665 | int tag = res >> AC_UNSOL_RES_TAG_SHIFT; | ||
488 | int pind = !!(res & AC_UNSOL_RES_PD); | 666 | int pind = !!(res & AC_UNSOL_RES_PD); |
489 | int eldv = !!(res & AC_UNSOL_RES_ELDV); | 667 | int eldv = !!(res & AC_UNSOL_RES_ELDV); |
668 | int index; | ||
490 | 669 | ||
491 | printk(KERN_INFO | 670 | printk(KERN_INFO |
492 | "HDMI hot plug event: Presence_Detect=%d ELD_Valid=%d\n", | 671 | "HDMI hot plug event: Pin=%d Presence_Detect=%d ELD_Valid=%d\n", |
493 | pind, eldv); | 672 | tag, pind, eldv); |
673 | |||
674 | index = hda_node_index(spec->pin, tag); | ||
675 | if (index < 0) | ||
676 | return; | ||
677 | |||
678 | spec->sink_present[index] = pind; | ||
679 | spec->sink_eldv[index] = eldv; | ||
494 | 680 | ||
495 | if (pind && eldv) { | 681 | if (pind && eldv) { |
496 | hdmi_parse_eld(codec); | 682 | hdmi_parse_eld(codec, index); |
497 | /* TODO: do real things about ELD */ | 683 | /* TODO: do real things about ELD */ |
498 | } | 684 | } |
499 | } | 685 | } |
500 | 686 | ||
501 | static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) | 687 | static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) |
502 | { | 688 | { |
689 | int tag = res >> AC_UNSOL_RES_TAG_SHIFT; | ||
503 | int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; | 690 | int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; |
504 | int cp_state = !!(res & AC_UNSOL_RES_CP_STATE); | 691 | int cp_state = !!(res & AC_UNSOL_RES_CP_STATE); |
505 | int cp_ready = !!(res & AC_UNSOL_RES_CP_READY); | 692 | int cp_ready = !!(res & AC_UNSOL_RES_CP_READY); |
506 | 693 | ||
507 | printk(KERN_INFO | 694 | printk(KERN_INFO |
508 | "HDMI content protection event: SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", | 695 | "HDMI CP event: PIN=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", |
696 | tag, | ||
509 | subtag, | 697 | subtag, |
510 | cp_state, | 698 | cp_state, |
511 | cp_ready); | 699 | cp_ready); |
@@ -520,10 +708,11 @@ static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) | |||
520 | 708 | ||
521 | static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res) | 709 | static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res) |
522 | { | 710 | { |
711 | struct intel_hdmi_spec *spec = codec->spec; | ||
523 | int tag = res >> AC_UNSOL_RES_TAG_SHIFT; | 712 | int tag = res >> AC_UNSOL_RES_TAG_SHIFT; |
524 | int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; | 713 | int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; |
525 | 714 | ||
526 | if (tag != INTEL_HDMI_EVENT_TAG) { | 715 | if (hda_node_index(spec->pin, tag) < 0) { |
527 | snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag); | 716 | snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag); |
528 | return; | 717 | return; |
529 | } | 718 | } |
@@ -538,69 +727,70 @@ static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res) | |||
538 | * Callbacks | 727 | * Callbacks |
539 | */ | 728 | */ |
540 | 729 | ||
541 | static int intel_hdmi_playback_pcm_open(struct hda_pcm_stream *hinfo, | 730 | static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, |
542 | struct hda_codec *codec, | 731 | struct hda_codec *codec, |
543 | struct snd_pcm_substream *substream) | 732 | unsigned int stream_tag, |
544 | { | 733 | unsigned int format, |
545 | struct intel_hdmi_spec *spec = codec->spec; | 734 | struct snd_pcm_substream *substream) |
546 | |||
547 | return snd_hda_multi_out_dig_open(codec, &spec->multiout); | ||
548 | } | ||
549 | |||
550 | static int intel_hdmi_playback_pcm_close(struct hda_pcm_stream *hinfo, | ||
551 | struct hda_codec *codec, | ||
552 | struct snd_pcm_substream *substream) | ||
553 | { | 735 | { |
554 | struct intel_hdmi_spec *spec = codec->spec; | 736 | hdmi_set_channel_count(codec, hinfo->nid, |
737 | substream->runtime->channels); | ||
555 | 738 | ||
556 | hdmi_stop_infoframe_trans(codec); | 739 | hdmi_setup_audio_infoframe(codec, hinfo->nid, substream); |
557 | 740 | ||
558 | return snd_hda_multi_out_dig_close(codec, &spec->multiout); | 741 | snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); |
742 | return 0; | ||
559 | } | 743 | } |
560 | 744 | ||
561 | static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | 745 | static int intel_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, |
562 | struct hda_codec *codec, | 746 | struct hda_codec *codec, |
563 | unsigned int stream_tag, | ||
564 | unsigned int format, | ||
565 | struct snd_pcm_substream *substream) | 747 | struct snd_pcm_substream *substream) |
566 | { | 748 | { |
567 | struct intel_hdmi_spec *spec = codec->spec; | 749 | struct intel_hdmi_spec *spec = codec->spec; |
750 | int i; | ||
568 | 751 | ||
569 | snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, | 752 | for (i = 0; i < spec->num_pins; i++) { |
570 | format, substream); | 753 | if (spec->pin_cvt[i] != hinfo->nid) |
571 | 754 | continue; | |
572 | hdmi_set_channel_count(codec, substream->runtime->channels); | ||
573 | 755 | ||
574 | hdmi_setup_audio_infoframe(codec, substream); | 756 | hdmi_stop_infoframe_trans(codec, spec->pin[i]); |
757 | } | ||
575 | 758 | ||
759 | snd_hda_codec_cleanup_stream(codec, hinfo->nid); | ||
576 | return 0; | 760 | return 0; |
577 | } | 761 | } |
578 | 762 | ||
579 | static struct hda_pcm_stream intel_hdmi_pcm_playback = { | 763 | static struct hda_pcm_stream intel_hdmi_pcm_playback = { |
580 | .substreams = 1, | 764 | .substreams = 1, |
581 | .channels_min = 2, | 765 | .channels_min = 2, |
582 | .channels_max = 8, | ||
583 | .ops = { | 766 | .ops = { |
584 | .open = intel_hdmi_playback_pcm_open, | 767 | .prepare = intel_hdmi_playback_pcm_prepare, |
585 | .close = intel_hdmi_playback_pcm_close, | 768 | .cleanup = intel_hdmi_playback_pcm_cleanup, |
586 | .prepare = intel_hdmi_playback_pcm_prepare | ||
587 | }, | 769 | }, |
588 | }; | 770 | }; |
589 | 771 | ||
590 | static int intel_hdmi_build_pcms(struct hda_codec *codec) | 772 | static int intel_hdmi_build_pcms(struct hda_codec *codec) |
591 | { | 773 | { |
592 | struct intel_hdmi_spec *spec = codec->spec; | 774 | struct intel_hdmi_spec *spec = codec->spec; |
593 | struct hda_pcm *info = &spec->pcm_rec; | 775 | struct hda_pcm *info = spec->pcm_rec; |
776 | int i; | ||
594 | 777 | ||
595 | codec->num_pcms = 1; | 778 | codec->num_pcms = spec->num_cvts; |
596 | codec->pcm_info = info; | 779 | codec->pcm_info = info; |
597 | 780 | ||
598 | /* NID to query formats and rates and setup streams */ | 781 | for (i = 0; i < codec->num_pcms; i++, info++) { |
599 | intel_hdmi_pcm_playback.nid = cvt_nid; | 782 | unsigned int chans; |
783 | |||
784 | chans = get_wcaps(codec, spec->cvt[i]); | ||
785 | chans = get_wcaps_channels(chans); | ||
600 | 786 | ||
601 | info->name = "INTEL HDMI"; | 787 | info->name = intel_hdmi_pcm_names[i]; |
602 | info->pcm_type = HDA_PCM_TYPE_HDMI; | 788 | info->pcm_type = HDA_PCM_TYPE_HDMI; |
603 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = intel_hdmi_pcm_playback; | 789 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = |
790 | intel_hdmi_pcm_playback; | ||
791 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->cvt[i]; | ||
792 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans; | ||
793 | } | ||
604 | 794 | ||
605 | return 0; | 795 | return 0; |
606 | } | 796 | } |
@@ -609,29 +799,39 @@ static int intel_hdmi_build_controls(struct hda_codec *codec) | |||
609 | { | 799 | { |
610 | struct intel_hdmi_spec *spec = codec->spec; | 800 | struct intel_hdmi_spec *spec = codec->spec; |
611 | int err; | 801 | int err; |
802 | int i; | ||
612 | 803 | ||
613 | err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); | 804 | for (i = 0; i < codec->num_pcms; i++) { |
614 | if (err < 0) | 805 | err = snd_hda_create_spdif_out_ctls(codec, spec->cvt[i]); |
615 | return err; | 806 | if (err < 0) |
807 | return err; | ||
808 | } | ||
616 | 809 | ||
617 | return 0; | 810 | return 0; |
618 | } | 811 | } |
619 | 812 | ||
620 | static int intel_hdmi_init(struct hda_codec *codec) | 813 | static int intel_hdmi_init(struct hda_codec *codec) |
621 | { | 814 | { |
622 | hdmi_enable_output(codec); | 815 | struct intel_hdmi_spec *spec = codec->spec; |
816 | int i; | ||
623 | 817 | ||
624 | snd_hda_codec_write(codec, pin_nid, 0, | 818 | for (i = 0; spec->pin[i]; i++) { |
625 | AC_VERB_SET_UNSOLICITED_ENABLE, | 819 | hdmi_enable_output(codec, spec->pin[i]); |
626 | AC_USRSP_EN | INTEL_HDMI_EVENT_TAG); | 820 | snd_hda_codec_write(codec, spec->pin[i], 0, |
821 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
822 | AC_USRSP_EN | spec->pin[i]); | ||
823 | } | ||
627 | return 0; | 824 | return 0; |
628 | } | 825 | } |
629 | 826 | ||
630 | static void intel_hdmi_free(struct hda_codec *codec) | 827 | static void intel_hdmi_free(struct hda_codec *codec) |
631 | { | 828 | { |
632 | struct intel_hdmi_spec *spec = codec->spec; | 829 | struct intel_hdmi_spec *spec = codec->spec; |
830 | int i; | ||
831 | |||
832 | for (i = 0; i < spec->num_pins; i++) | ||
833 | snd_hda_eld_proc_free(codec, &spec->sink_eld[i]); | ||
633 | 834 | ||
634 | snd_hda_eld_proc_free(codec, &spec->sink_eld); | ||
635 | kfree(spec); | 835 | kfree(spec); |
636 | } | 836 | } |
637 | 837 | ||
@@ -643,49 +843,38 @@ static struct hda_codec_ops intel_hdmi_patch_ops = { | |||
643 | .unsol_event = intel_hdmi_unsol_event, | 843 | .unsol_event = intel_hdmi_unsol_event, |
644 | }; | 844 | }; |
645 | 845 | ||
646 | static int do_patch_intel_hdmi(struct hda_codec *codec) | 846 | static int patch_intel_hdmi(struct hda_codec *codec) |
647 | { | 847 | { |
648 | struct intel_hdmi_spec *spec; | 848 | struct intel_hdmi_spec *spec; |
849 | int i; | ||
649 | 850 | ||
650 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 851 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
651 | if (spec == NULL) | 852 | if (spec == NULL) |
652 | return -ENOMEM; | 853 | return -ENOMEM; |
653 | 854 | ||
654 | spec->multiout.num_dacs = 0; /* no analog */ | ||
655 | spec->multiout.max_channels = 8; | ||
656 | spec->multiout.dig_out_nid = cvt_nid; | ||
657 | |||
658 | codec->spec = spec; | 855 | codec->spec = spec; |
856 | if (intel_hdmi_parse_codec(codec) < 0) { | ||
857 | codec->spec = NULL; | ||
858 | kfree(spec); | ||
859 | return -EINVAL; | ||
860 | } | ||
659 | codec->patch_ops = intel_hdmi_patch_ops; | 861 | codec->patch_ops = intel_hdmi_patch_ops; |
660 | 862 | ||
661 | snd_hda_eld_proc_new(codec, &spec->sink_eld); | 863 | for (i = 0; i < spec->num_pins; i++) |
864 | snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i); | ||
662 | 865 | ||
663 | init_channel_allocations(); | 866 | init_channel_allocations(); |
664 | 867 | ||
665 | return 0; | 868 | return 0; |
666 | } | 869 | } |
667 | 870 | ||
668 | static int patch_intel_hdmi(struct hda_codec *codec) | ||
669 | { | ||
670 | cvt_nid = 0x02; | ||
671 | pin_nid = 0x03; | ||
672 | return do_patch_intel_hdmi(codec); | ||
673 | } | ||
674 | |||
675 | static int patch_intel_hdmi_ibexpeak(struct hda_codec *codec) | ||
676 | { | ||
677 | cvt_nid = 0x02; | ||
678 | pin_nid = 0x04; | ||
679 | return do_patch_intel_hdmi(codec); | ||
680 | } | ||
681 | |||
682 | static struct hda_codec_preset snd_hda_preset_intelhdmi[] = { | 871 | static struct hda_codec_preset snd_hda_preset_intelhdmi[] = { |
683 | { .id = 0x808629fb, .name = "G45 DEVCL", .patch = patch_intel_hdmi }, | 872 | { .id = 0x808629fb, .name = "G45 DEVCL", .patch = patch_intel_hdmi }, |
684 | { .id = 0x80862801, .name = "G45 DEVBLC", .patch = patch_intel_hdmi }, | 873 | { .id = 0x80862801, .name = "G45 DEVBLC", .patch = patch_intel_hdmi }, |
685 | { .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi }, | 874 | { .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi }, |
686 | { .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi }, | 875 | { .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi }, |
687 | { .id = 0x80862804, .name = "G45 DEVIBX", .patch = patch_intel_hdmi }, | 876 | { .id = 0x80862804, .name = "G45 DEVIBX", .patch = patch_intel_hdmi }, |
688 | { .id = 0x80860054, .name = "Q57 DEVIBX", .patch = patch_intel_hdmi_ibexpeak }, | 877 | { .id = 0x80860054, .name = "Q57 DEVIBX", .patch = patch_intel_hdmi }, |
689 | { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi }, | 878 | { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi }, |
690 | {} /* terminator */ | 879 | {} /* terminator */ |
691 | }; | 880 | }; |
diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index 9fb60276f5c9..6afdab09bab7 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c | |||
@@ -397,6 +397,7 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec) | |||
397 | static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { | 397 | static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { |
398 | { .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, | 398 | { .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, |
399 | { .id = 0x10de0003, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, | 399 | { .id = 0x10de0003, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, |
400 | { .id = 0x10de0005, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, | ||
400 | { .id = 0x10de0006, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, | 401 | { .id = 0x10de0006, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, |
401 | { .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi_8ch }, | 402 | { .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi_8ch }, |
402 | { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, | 403 | { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, |
@@ -406,6 +407,7 @@ static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { | |||
406 | 407 | ||
407 | MODULE_ALIAS("snd-hda-codec-id:10de0002"); | 408 | MODULE_ALIAS("snd-hda-codec-id:10de0002"); |
408 | MODULE_ALIAS("snd-hda-codec-id:10de0003"); | 409 | MODULE_ALIAS("snd-hda-codec-id:10de0003"); |
410 | MODULE_ALIAS("snd-hda-codec-id:10de0005"); | ||
409 | MODULE_ALIAS("snd-hda-codec-id:10de0006"); | 411 | MODULE_ALIAS("snd-hda-codec-id:10de0006"); |
410 | MODULE_ALIAS("snd-hda-codec-id:10de0007"); | 412 | MODULE_ALIAS("snd-hda-codec-id:10de0007"); |
411 | MODULE_ALIAS("snd-hda-codec-id:10de0067"); | 413 | MODULE_ALIAS("snd-hda-codec-id:10de0067"); |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 08a5b8a55408..49de107db16b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -965,6 +965,8 @@ static void alc_automute_pin(struct hda_codec *codec) | |||
965 | unsigned int nid = spec->autocfg.hp_pins[0]; | 965 | unsigned int nid = spec->autocfg.hp_pins[0]; |
966 | int i; | 966 | int i; |
967 | 967 | ||
968 | if (!nid) | ||
969 | return; | ||
968 | pincap = snd_hda_query_pin_caps(codec, nid); | 970 | pincap = snd_hda_query_pin_caps(codec, nid); |
969 | if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */ | 971 | if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */ |
970 | snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0); | 972 | snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0); |
@@ -4324,6 +4326,20 @@ static int add_control(struct alc_spec *spec, int type, const char *name, | |||
4324 | return 0; | 4326 | return 0; |
4325 | } | 4327 | } |
4326 | 4328 | ||
4329 | static int add_control_with_pfx(struct alc_spec *spec, int type, | ||
4330 | const char *pfx, const char *dir, | ||
4331 | const char *sfx, unsigned long val) | ||
4332 | { | ||
4333 | char name[32]; | ||
4334 | snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx); | ||
4335 | return add_control(spec, type, name, val); | ||
4336 | } | ||
4337 | |||
4338 | #define add_pb_vol_ctrl(spec, type, pfx, val) \ | ||
4339 | add_control_with_pfx(spec, type, pfx, "Playback", "Volume", val) | ||
4340 | #define add_pb_sw_ctrl(spec, type, pfx, val) \ | ||
4341 | add_control_with_pfx(spec, type, pfx, "Playback", "Switch", val) | ||
4342 | |||
4327 | #define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17) | 4343 | #define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17) |
4328 | #define alc880_fixed_pin_idx(nid) ((nid) - 0x14) | 4344 | #define alc880_fixed_pin_idx(nid) ((nid) - 0x14) |
4329 | #define alc880_is_multi_pin(nid) ((nid) >= 0x18) | 4345 | #define alc880_is_multi_pin(nid) ((nid) >= 0x18) |
@@ -4377,7 +4393,6 @@ static int alc880_auto_fill_dac_nids(struct alc_spec *spec, | |||
4377 | static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, | 4393 | static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, |
4378 | const struct auto_pin_cfg *cfg) | 4394 | const struct auto_pin_cfg *cfg) |
4379 | { | 4395 | { |
4380 | char name[32]; | ||
4381 | static const char *chname[4] = { | 4396 | static const char *chname[4] = { |
4382 | "Front", "Surround", NULL /*CLFE*/, "Side" | 4397 | "Front", "Surround", NULL /*CLFE*/, "Side" |
4383 | }; | 4398 | }; |
@@ -4390,26 +4405,26 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, | |||
4390 | nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i])); | 4405 | nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i])); |
4391 | if (i == 2) { | 4406 | if (i == 2) { |
4392 | /* Center/LFE */ | 4407 | /* Center/LFE */ |
4393 | err = add_control(spec, ALC_CTL_WIDGET_VOL, | 4408 | err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, |
4394 | "Center Playback Volume", | 4409 | "Center", |
4395 | HDA_COMPOSE_AMP_VAL(nid, 1, 0, | 4410 | HDA_COMPOSE_AMP_VAL(nid, 1, 0, |
4396 | HDA_OUTPUT)); | 4411 | HDA_OUTPUT)); |
4397 | if (err < 0) | 4412 | if (err < 0) |
4398 | return err; | 4413 | return err; |
4399 | err = add_control(spec, ALC_CTL_WIDGET_VOL, | 4414 | err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, |
4400 | "LFE Playback Volume", | 4415 | "LFE", |
4401 | HDA_COMPOSE_AMP_VAL(nid, 2, 0, | 4416 | HDA_COMPOSE_AMP_VAL(nid, 2, 0, |
4402 | HDA_OUTPUT)); | 4417 | HDA_OUTPUT)); |
4403 | if (err < 0) | 4418 | if (err < 0) |
4404 | return err; | 4419 | return err; |
4405 | err = add_control(spec, ALC_CTL_BIND_MUTE, | 4420 | err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, |
4406 | "Center Playback Switch", | 4421 | "Center", |
4407 | HDA_COMPOSE_AMP_VAL(nid, 1, 2, | 4422 | HDA_COMPOSE_AMP_VAL(nid, 1, 2, |
4408 | HDA_INPUT)); | 4423 | HDA_INPUT)); |
4409 | if (err < 0) | 4424 | if (err < 0) |
4410 | return err; | 4425 | return err; |
4411 | err = add_control(spec, ALC_CTL_BIND_MUTE, | 4426 | err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, |
4412 | "LFE Playback Switch", | 4427 | "LFE", |
4413 | HDA_COMPOSE_AMP_VAL(nid, 2, 2, | 4428 | HDA_COMPOSE_AMP_VAL(nid, 2, 2, |
4414 | HDA_INPUT)); | 4429 | HDA_INPUT)); |
4415 | if (err < 0) | 4430 | if (err < 0) |
@@ -4421,14 +4436,12 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, | |||
4421 | pfx = "Speaker"; | 4436 | pfx = "Speaker"; |
4422 | else | 4437 | else |
4423 | pfx = chname[i]; | 4438 | pfx = chname[i]; |
4424 | sprintf(name, "%s Playback Volume", pfx); | 4439 | err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, |
4425 | err = add_control(spec, ALC_CTL_WIDGET_VOL, name, | ||
4426 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, | 4440 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, |
4427 | HDA_OUTPUT)); | 4441 | HDA_OUTPUT)); |
4428 | if (err < 0) | 4442 | if (err < 0) |
4429 | return err; | 4443 | return err; |
4430 | sprintf(name, "%s Playback Switch", pfx); | 4444 | err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx, |
4431 | err = add_control(spec, ALC_CTL_BIND_MUTE, name, | ||
4432 | HDA_COMPOSE_AMP_VAL(nid, 3, 2, | 4445 | HDA_COMPOSE_AMP_VAL(nid, 3, 2, |
4433 | HDA_INPUT)); | 4446 | HDA_INPUT)); |
4434 | if (err < 0) | 4447 | if (err < 0) |
@@ -4444,7 +4457,6 @@ static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, | |||
4444 | { | 4457 | { |
4445 | hda_nid_t nid; | 4458 | hda_nid_t nid; |
4446 | int err; | 4459 | int err; |
4447 | char name[32]; | ||
4448 | 4460 | ||
4449 | if (!pin) | 4461 | if (!pin) |
4450 | return 0; | 4462 | return 0; |
@@ -4458,21 +4470,18 @@ static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, | |||
4458 | spec->multiout.extra_out_nid[0] = nid; | 4470 | spec->multiout.extra_out_nid[0] = nid; |
4459 | /* control HP volume/switch on the output mixer amp */ | 4471 | /* control HP volume/switch on the output mixer amp */ |
4460 | nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin)); | 4472 | nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin)); |
4461 | sprintf(name, "%s Playback Volume", pfx); | 4473 | err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, |
4462 | err = add_control(spec, ALC_CTL_WIDGET_VOL, name, | ||
4463 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); | 4474 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); |
4464 | if (err < 0) | 4475 | if (err < 0) |
4465 | return err; | 4476 | return err; |
4466 | sprintf(name, "%s Playback Switch", pfx); | 4477 | err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx, |
4467 | err = add_control(spec, ALC_CTL_BIND_MUTE, name, | ||
4468 | HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT)); | 4478 | HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT)); |
4469 | if (err < 0) | 4479 | if (err < 0) |
4470 | return err; | 4480 | return err; |
4471 | } else if (alc880_is_multi_pin(pin)) { | 4481 | } else if (alc880_is_multi_pin(pin)) { |
4472 | /* set manual connection */ | 4482 | /* set manual connection */ |
4473 | /* we have only a switch on HP-out PIN */ | 4483 | /* we have only a switch on HP-out PIN */ |
4474 | sprintf(name, "%s Playback Switch", pfx); | 4484 | err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, |
4475 | err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, | ||
4476 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); | 4485 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); |
4477 | if (err < 0) | 4486 | if (err < 0) |
4478 | return err; | 4487 | return err; |
@@ -4485,16 +4494,13 @@ static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, | |||
4485 | const char *ctlname, | 4494 | const char *ctlname, |
4486 | int idx, hda_nid_t mix_nid) | 4495 | int idx, hda_nid_t mix_nid) |
4487 | { | 4496 | { |
4488 | char name[32]; | ||
4489 | int err; | 4497 | int err; |
4490 | 4498 | ||
4491 | sprintf(name, "%s Playback Volume", ctlname); | 4499 | err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, |
4492 | err = add_control(spec, ALC_CTL_WIDGET_VOL, name, | ||
4493 | HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); | 4500 | HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); |
4494 | if (err < 0) | 4501 | if (err < 0) |
4495 | return err; | 4502 | return err; |
4496 | sprintf(name, "%s Playback Switch", ctlname); | 4503 | err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, |
4497 | err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, | ||
4498 | HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); | 4504 | HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); |
4499 | if (err < 0) | 4505 | if (err < 0) |
4500 | return err; | 4506 | return err; |
@@ -4682,9 +4688,9 @@ static int alc880_parse_auto_config(struct hda_codec *codec) | |||
4682 | spec->multiout.dig_out_nid = dig_nid; | 4688 | spec->multiout.dig_out_nid = dig_nid; |
4683 | else { | 4689 | else { |
4684 | spec->multiout.slave_dig_outs = spec->slave_dig_outs; | 4690 | spec->multiout.slave_dig_outs = spec->slave_dig_outs; |
4685 | spec->slave_dig_outs[i - 1] = dig_nid; | 4691 | if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1) |
4686 | if (i == ARRAY_SIZE(spec->slave_dig_outs) - 1) | ||
4687 | break; | 4692 | break; |
4693 | spec->slave_dig_outs[i - 1] = dig_nid; | ||
4688 | } | 4694 | } |
4689 | } | 4695 | } |
4690 | if (spec->autocfg.dig_in_pin) | 4696 | if (spec->autocfg.dig_in_pin) |
@@ -5987,7 +5993,6 @@ static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid, | |||
5987 | { | 5993 | { |
5988 | hda_nid_t nid_vol; | 5994 | hda_nid_t nid_vol; |
5989 | unsigned long vol_val, sw_val; | 5995 | unsigned long vol_val, sw_val; |
5990 | char name[32]; | ||
5991 | int err; | 5996 | int err; |
5992 | 5997 | ||
5993 | if (nid >= 0x0f && nid < 0x11) { | 5998 | if (nid >= 0x0f && nid < 0x11) { |
@@ -6007,14 +6012,12 @@ static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid, | |||
6007 | 6012 | ||
6008 | if (!(*vol_bits & (1 << nid_vol))) { | 6013 | if (!(*vol_bits & (1 << nid_vol))) { |
6009 | /* first control for the volume widget */ | 6014 | /* first control for the volume widget */ |
6010 | snprintf(name, sizeof(name), "%s Playback Volume", pfx); | 6015 | err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, vol_val); |
6011 | err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val); | ||
6012 | if (err < 0) | 6016 | if (err < 0) |
6013 | return err; | 6017 | return err; |
6014 | *vol_bits |= (1 << nid_vol); | 6018 | *vol_bits |= (1 << nid_vol); |
6015 | } | 6019 | } |
6016 | snprintf(name, sizeof(name), "%s Playback Switch", pfx); | 6020 | err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, sw_val); |
6017 | err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val); | ||
6018 | if (err < 0) | 6021 | if (err < 0) |
6019 | return err; | 6022 | return err; |
6020 | return 1; | 6023 | return 1; |
@@ -6247,7 +6250,7 @@ static struct snd_pci_quirk alc260_cfg_tbl[] = { | |||
6247 | SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER), | 6250 | SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER), |
6248 | SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100), | 6251 | SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100), |
6249 | SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013), | 6252 | SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013), |
6250 | SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013), | 6253 | SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */ |
6251 | SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013), | 6254 | SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013), |
6252 | SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013), | 6255 | SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013), |
6253 | SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600), | 6256 | SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600), |
@@ -8909,10 +8912,11 @@ static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = { | |||
8909 | SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3), | 8912 | SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3), |
8910 | SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24), | 8913 | SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24), |
8911 | SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5), | 8914 | SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5), |
8912 | /* FIXME: HP jack sense seems not working for MBP 5,1, so apparently | 8915 | /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2, |
8913 | * no perfect solution yet | 8916 | * so apparently no perfect solution yet |
8914 | */ | 8917 | */ |
8915 | SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5), | 8918 | SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5), |
8919 | SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5), | ||
8916 | {} /* terminator */ | 8920 | {} /* terminator */ |
8917 | }; | 8921 | }; |
8918 | 8922 | ||
@@ -9811,9 +9815,9 @@ static int alc882_parse_auto_config(struct hda_codec *codec) | |||
9811 | spec->multiout.dig_out_nid = dig_nid; | 9815 | spec->multiout.dig_out_nid = dig_nid; |
9812 | else { | 9816 | else { |
9813 | spec->multiout.slave_dig_outs = spec->slave_dig_outs; | 9817 | spec->multiout.slave_dig_outs = spec->slave_dig_outs; |
9814 | spec->slave_dig_outs[i - 1] = dig_nid; | 9818 | if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1) |
9815 | if (i == ARRAY_SIZE(spec->slave_dig_outs) - 1) | ||
9816 | break; | 9819 | break; |
9820 | spec->slave_dig_outs[i - 1] = dig_nid; | ||
9817 | } | 9821 | } |
9818 | } | 9822 | } |
9819 | if (spec->autocfg.dig_in_pin) | 9823 | if (spec->autocfg.dig_in_pin) |
@@ -10953,7 +10957,6 @@ static int alc262_check_volbit(hda_nid_t nid) | |||
10953 | static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid, | 10957 | static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid, |
10954 | const char *pfx, int *vbits) | 10958 | const char *pfx, int *vbits) |
10955 | { | 10959 | { |
10956 | char name[32]; | ||
10957 | unsigned long val; | 10960 | unsigned long val; |
10958 | int vbit; | 10961 | int vbit; |
10959 | 10962 | ||
@@ -10963,28 +10966,25 @@ static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid, | |||
10963 | if (*vbits & vbit) /* a volume control for this mixer already there */ | 10966 | if (*vbits & vbit) /* a volume control for this mixer already there */ |
10964 | return 0; | 10967 | return 0; |
10965 | *vbits |= vbit; | 10968 | *vbits |= vbit; |
10966 | snprintf(name, sizeof(name), "%s Playback Volume", pfx); | ||
10967 | if (vbit == 2) | 10969 | if (vbit == 2) |
10968 | val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT); | 10970 | val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT); |
10969 | else | 10971 | else |
10970 | val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT); | 10972 | val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT); |
10971 | return add_control(spec, ALC_CTL_WIDGET_VOL, name, val); | 10973 | return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, val); |
10972 | } | 10974 | } |
10973 | 10975 | ||
10974 | static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid, | 10976 | static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid, |
10975 | const char *pfx) | 10977 | const char *pfx) |
10976 | { | 10978 | { |
10977 | char name[32]; | ||
10978 | unsigned long val; | 10979 | unsigned long val; |
10979 | 10980 | ||
10980 | if (!nid) | 10981 | if (!nid) |
10981 | return 0; | 10982 | return 0; |
10982 | snprintf(name, sizeof(name), "%s Playback Switch", pfx); | ||
10983 | if (nid == 0x16) | 10983 | if (nid == 0x16) |
10984 | val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT); | 10984 | val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT); |
10985 | else | 10985 | else |
10986 | val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); | 10986 | val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); |
10987 | return add_control(spec, ALC_CTL_WIDGET_MUTE, name, val); | 10987 | return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, val); |
10988 | } | 10988 | } |
10989 | 10989 | ||
10990 | /* add playback controls from the parsed DAC table */ | 10990 | /* add playback controls from the parsed DAC table */ |
@@ -11458,6 +11458,7 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = { | |||
11458 | SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), | 11458 | SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), |
11459 | SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */ | 11459 | SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */ |
11460 | SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06), | 11460 | SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06), |
11461 | SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO), | ||
11461 | SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO", | 11462 | SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO", |
11462 | ALC262_SONY_ASSAMD), | 11463 | ALC262_SONY_ASSAMD), |
11463 | SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1", | 11464 | SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1", |
@@ -12322,11 +12323,9 @@ static struct snd_kcontrol_new alc268_test_mixer[] = { | |||
12322 | static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid, | 12323 | static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid, |
12323 | const char *ctlname, int idx) | 12324 | const char *ctlname, int idx) |
12324 | { | 12325 | { |
12325 | char name[32]; | ||
12326 | hda_nid_t dac; | 12326 | hda_nid_t dac; |
12327 | int err; | 12327 | int err; |
12328 | 12328 | ||
12329 | sprintf(name, "%s Playback Volume", ctlname); | ||
12330 | switch (nid) { | 12329 | switch (nid) { |
12331 | case 0x14: | 12330 | case 0x14: |
12332 | case 0x16: | 12331 | case 0x16: |
@@ -12340,7 +12339,7 @@ static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid, | |||
12340 | } | 12339 | } |
12341 | if (spec->multiout.dac_nids[0] != dac && | 12340 | if (spec->multiout.dac_nids[0] != dac && |
12342 | spec->multiout.dac_nids[1] != dac) { | 12341 | spec->multiout.dac_nids[1] != dac) { |
12343 | err = add_control(spec, ALC_CTL_WIDGET_VOL, name, | 12342 | err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, |
12344 | HDA_COMPOSE_AMP_VAL(dac, 3, idx, | 12343 | HDA_COMPOSE_AMP_VAL(dac, 3, idx, |
12345 | HDA_OUTPUT)); | 12344 | HDA_OUTPUT)); |
12346 | if (err < 0) | 12345 | if (err < 0) |
@@ -12348,12 +12347,11 @@ static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid, | |||
12348 | spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac; | 12347 | spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac; |
12349 | } | 12348 | } |
12350 | 12349 | ||
12351 | sprintf(name, "%s Playback Switch", ctlname); | ||
12352 | if (nid != 0x16) | 12350 | if (nid != 0x16) |
12353 | err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, | 12351 | err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, |
12354 | HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT)); | 12352 | HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT)); |
12355 | else /* mono */ | 12353 | else /* mono */ |
12356 | err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, | 12354 | err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, |
12357 | HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT)); | 12355 | HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT)); |
12358 | if (err < 0) | 12356 | if (err < 0) |
12359 | return err; | 12357 | return err; |
@@ -12383,8 +12381,7 @@ static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec, | |||
12383 | 12381 | ||
12384 | nid = cfg->speaker_pins[0]; | 12382 | nid = cfg->speaker_pins[0]; |
12385 | if (nid == 0x1d) { | 12383 | if (nid == 0x1d) { |
12386 | err = add_control(spec, ALC_CTL_WIDGET_VOL, | 12384 | err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker", |
12387 | "Speaker Playback Volume", | ||
12388 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); | 12385 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); |
12389 | if (err < 0) | 12386 | if (err < 0) |
12390 | return err; | 12387 | return err; |
@@ -12402,8 +12399,7 @@ static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec, | |||
12402 | 12399 | ||
12403 | nid = cfg->line_out_pins[1] | cfg->line_out_pins[2]; | 12400 | nid = cfg->line_out_pins[1] | cfg->line_out_pins[2]; |
12404 | if (nid == 0x16) { | 12401 | if (nid == 0x16) { |
12405 | err = add_control(spec, ALC_CTL_WIDGET_MUTE, | 12402 | err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono", |
12406 | "Mono Playback Switch", | ||
12407 | HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT)); | 12403 | HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT)); |
12408 | if (err < 0) | 12404 | if (err < 0) |
12409 | return err; | 12405 | return err; |
@@ -12602,7 +12598,8 @@ static struct snd_pci_quirk alc268_cfg_tbl[] = { | |||
12602 | SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One", | 12598 | SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One", |
12603 | ALC268_ACER_ASPIRE_ONE), | 12599 | ALC268_ACER_ASPIRE_ONE), |
12604 | SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL), | 12600 | SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL), |
12605 | SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron Mini9", ALC268_DELL), | 12601 | SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0, |
12602 | "Dell Inspiron Mini9/Vostro A90", ALC268_DELL), | ||
12606 | /* almost compatible with toshiba but with optional digital outs; | 12603 | /* almost compatible with toshiba but with optional digital outs; |
12607 | * auto-probing seems working fine | 12604 | * auto-probing seems working fine |
12608 | */ | 12605 | */ |
@@ -14254,9 +14251,7 @@ static int alc861_auto_fill_dac_nids(struct hda_codec *codec, | |||
14254 | static int alc861_create_out_sw(struct hda_codec *codec, const char *pfx, | 14251 | static int alc861_create_out_sw(struct hda_codec *codec, const char *pfx, |
14255 | hda_nid_t nid, unsigned int chs) | 14252 | hda_nid_t nid, unsigned int chs) |
14256 | { | 14253 | { |
14257 | char name[32]; | 14254 | return add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx, |
14258 | snprintf(name, sizeof(name), "%s Playback Switch", pfx); | ||
14259 | return add_control(codec->spec, ALC_CTL_WIDGET_MUTE, name, | ||
14260 | HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); | 14255 | HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); |
14261 | } | 14256 | } |
14262 | 14257 | ||
@@ -15380,7 +15375,6 @@ static void alc861vd_auto_init_analog_input(struct hda_codec *codec) | |||
15380 | static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec, | 15375 | static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec, |
15381 | const struct auto_pin_cfg *cfg) | 15376 | const struct auto_pin_cfg *cfg) |
15382 | { | 15377 | { |
15383 | char name[32]; | ||
15384 | static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"}; | 15378 | static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"}; |
15385 | hda_nid_t nid_v, nid_s; | 15379 | hda_nid_t nid_v, nid_s; |
15386 | int i, err; | 15380 | int i, err; |
@@ -15397,26 +15391,26 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec, | |||
15397 | 15391 | ||
15398 | if (i == 2) { | 15392 | if (i == 2) { |
15399 | /* Center/LFE */ | 15393 | /* Center/LFE */ |
15400 | err = add_control(spec, ALC_CTL_WIDGET_VOL, | 15394 | err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, |
15401 | "Center Playback Volume", | 15395 | "Center", |
15402 | HDA_COMPOSE_AMP_VAL(nid_v, 1, 0, | 15396 | HDA_COMPOSE_AMP_VAL(nid_v, 1, 0, |
15403 | HDA_OUTPUT)); | 15397 | HDA_OUTPUT)); |
15404 | if (err < 0) | 15398 | if (err < 0) |
15405 | return err; | 15399 | return err; |
15406 | err = add_control(spec, ALC_CTL_WIDGET_VOL, | 15400 | err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, |
15407 | "LFE Playback Volume", | 15401 | "LFE", |
15408 | HDA_COMPOSE_AMP_VAL(nid_v, 2, 0, | 15402 | HDA_COMPOSE_AMP_VAL(nid_v, 2, 0, |
15409 | HDA_OUTPUT)); | 15403 | HDA_OUTPUT)); |
15410 | if (err < 0) | 15404 | if (err < 0) |
15411 | return err; | 15405 | return err; |
15412 | err = add_control(spec, ALC_CTL_BIND_MUTE, | 15406 | err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, |
15413 | "Center Playback Switch", | 15407 | "Center", |
15414 | HDA_COMPOSE_AMP_VAL(nid_s, 1, 2, | 15408 | HDA_COMPOSE_AMP_VAL(nid_s, 1, 2, |
15415 | HDA_INPUT)); | 15409 | HDA_INPUT)); |
15416 | if (err < 0) | 15410 | if (err < 0) |
15417 | return err; | 15411 | return err; |
15418 | err = add_control(spec, ALC_CTL_BIND_MUTE, | 15412 | err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, |
15419 | "LFE Playback Switch", | 15413 | "LFE", |
15420 | HDA_COMPOSE_AMP_VAL(nid_s, 2, 2, | 15414 | HDA_COMPOSE_AMP_VAL(nid_s, 2, 2, |
15421 | HDA_INPUT)); | 15415 | HDA_INPUT)); |
15422 | if (err < 0) | 15416 | if (err < 0) |
@@ -15431,8 +15425,7 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec, | |||
15431 | pfx = "PCM"; | 15425 | pfx = "PCM"; |
15432 | } else | 15426 | } else |
15433 | pfx = chname[i]; | 15427 | pfx = chname[i]; |
15434 | sprintf(name, "%s Playback Volume", pfx); | 15428 | err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, |
15435 | err = add_control(spec, ALC_CTL_WIDGET_VOL, name, | ||
15436 | HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, | 15429 | HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, |
15437 | HDA_OUTPUT)); | 15430 | HDA_OUTPUT)); |
15438 | if (err < 0) | 15431 | if (err < 0) |
@@ -15440,8 +15433,7 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec, | |||
15440 | if (cfg->line_outs == 1 && | 15433 | if (cfg->line_outs == 1 && |
15441 | cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) | 15434 | cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) |
15442 | pfx = "Speaker"; | 15435 | pfx = "Speaker"; |
15443 | sprintf(name, "%s Playback Switch", pfx); | 15436 | err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx, |
15444 | err = add_control(spec, ALC_CTL_BIND_MUTE, name, | ||
15445 | HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, | 15437 | HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, |
15446 | HDA_INPUT)); | 15438 | HDA_INPUT)); |
15447 | if (err < 0) | 15439 | if (err < 0) |
@@ -15459,7 +15451,6 @@ static int alc861vd_auto_create_extra_out(struct alc_spec *spec, | |||
15459 | { | 15451 | { |
15460 | hda_nid_t nid_v, nid_s; | 15452 | hda_nid_t nid_v, nid_s; |
15461 | int err; | 15453 | int err; |
15462 | char name[32]; | ||
15463 | 15454 | ||
15464 | if (!pin) | 15455 | if (!pin) |
15465 | return 0; | 15456 | return 0; |
@@ -15477,21 +15468,18 @@ static int alc861vd_auto_create_extra_out(struct alc_spec *spec, | |||
15477 | nid_s = alc861vd_idx_to_mixer_switch( | 15468 | nid_s = alc861vd_idx_to_mixer_switch( |
15478 | alc880_fixed_pin_idx(pin)); | 15469 | alc880_fixed_pin_idx(pin)); |
15479 | 15470 | ||
15480 | sprintf(name, "%s Playback Volume", pfx); | 15471 | err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, |
15481 | err = add_control(spec, ALC_CTL_WIDGET_VOL, name, | ||
15482 | HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT)); | 15472 | HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT)); |
15483 | if (err < 0) | 15473 | if (err < 0) |
15484 | return err; | 15474 | return err; |
15485 | sprintf(name, "%s Playback Switch", pfx); | 15475 | err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx, |
15486 | err = add_control(spec, ALC_CTL_BIND_MUTE, name, | ||
15487 | HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT)); | 15476 | HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT)); |
15488 | if (err < 0) | 15477 | if (err < 0) |
15489 | return err; | 15478 | return err; |
15490 | } else if (alc880_is_multi_pin(pin)) { | 15479 | } else if (alc880_is_multi_pin(pin)) { |
15491 | /* set manual connection */ | 15480 | /* set manual connection */ |
15492 | /* we have only a switch on HP-out PIN */ | 15481 | /* we have only a switch on HP-out PIN */ |
15493 | sprintf(name, "%s Playback Switch", pfx); | 15482 | err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, |
15494 | err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, | ||
15495 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); | 15483 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); |
15496 | if (err < 0) | 15484 | if (err < 0) |
15497 | return err; | 15485 | return err; |
@@ -17258,21 +17246,17 @@ static int alc662_auto_fill_dac_nids(struct hda_codec *codec, | |||
17258 | return 0; | 17246 | return 0; |
17259 | } | 17247 | } |
17260 | 17248 | ||
17261 | static int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx, | 17249 | static inline int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx, |
17262 | hda_nid_t nid, unsigned int chs) | 17250 | hda_nid_t nid, unsigned int chs) |
17263 | { | 17251 | { |
17264 | char name[32]; | 17252 | return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, |
17265 | sprintf(name, "%s Playback Volume", pfx); | ||
17266 | return add_control(spec, ALC_CTL_WIDGET_VOL, name, | ||
17267 | HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); | 17253 | HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); |
17268 | } | 17254 | } |
17269 | 17255 | ||
17270 | static int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx, | 17256 | static inline int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx, |
17271 | hda_nid_t nid, unsigned int chs) | 17257 | hda_nid_t nid, unsigned int chs) |
17272 | { | 17258 | { |
17273 | char name[32]; | 17259 | return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, |
17274 | sprintf(name, "%s Playback Switch", pfx); | ||
17275 | return add_control(spec, ALC_CTL_WIDGET_MUTE, name, | ||
17276 | HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT)); | 17260 | HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT)); |
17277 | } | 17261 | } |
17278 | 17262 | ||
@@ -17350,13 +17334,11 @@ static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, | |||
17350 | return 0; | 17334 | return 0; |
17351 | nid = alc662_look_for_dac(codec, pin); | 17335 | nid = alc662_look_for_dac(codec, pin); |
17352 | if (!nid) { | 17336 | if (!nid) { |
17353 | char name[32]; | ||
17354 | /* the corresponding DAC is already occupied */ | 17337 | /* the corresponding DAC is already occupied */ |
17355 | if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)) | 17338 | if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)) |
17356 | return 0; /* no way */ | 17339 | return 0; /* no way */ |
17357 | /* create a switch only */ | 17340 | /* create a switch only */ |
17358 | sprintf(name, "%s Playback Switch", pfx); | 17341 | return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, |
17359 | return add_control(spec, ALC_CTL_WIDGET_MUTE, name, | ||
17360 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); | 17342 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); |
17361 | } | 17343 | } |
17362 | 17344 | ||
@@ -17374,7 +17356,7 @@ static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, | |||
17374 | 17356 | ||
17375 | /* create playback/capture controls for input pins */ | 17357 | /* create playback/capture controls for input pins */ |
17376 | #define alc662_auto_create_input_ctls \ | 17358 | #define alc662_auto_create_input_ctls \ |
17377 | alc880_auto_create_input_ctls | 17359 | alc882_auto_create_input_ctls |
17378 | 17360 | ||
17379 | static void alc662_auto_set_output_and_unmute(struct hda_codec *codec, | 17361 | static void alc662_auto_set_output_and_unmute(struct hda_codec *codec, |
17380 | hda_nid_t nid, int pin_type, | 17362 | hda_nid_t nid, int pin_type, |
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 426edfa476a2..8d65d2b25234 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/pci.h> | 30 | #include <linux/pci.h> |
31 | #include <linux/dmi.h> | ||
31 | #include <sound/core.h> | 32 | #include <sound/core.h> |
32 | #include <sound/asoundef.h> | 33 | #include <sound/asoundef.h> |
33 | #include <sound/jack.h> | 34 | #include <sound/jack.h> |
@@ -1589,6 +1590,8 @@ static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { | |||
1589 | "Dell Studio 17", STAC_DELL_M6_DMIC), | 1590 | "Dell Studio 17", STAC_DELL_M6_DMIC), |
1590 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02be, | 1591 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02be, |
1591 | "Dell Studio 1555", STAC_DELL_M6_DMIC), | 1592 | "Dell Studio 1555", STAC_DELL_M6_DMIC), |
1593 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02bd, | ||
1594 | "Dell Studio 1557", STAC_DELL_M6_DMIC), | ||
1592 | {} /* terminator */ | 1595 | {} /* terminator */ |
1593 | }; | 1596 | }; |
1594 | 1597 | ||
@@ -1693,6 +1696,8 @@ static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { | |||
1693 | "DFI LanParty", STAC_92HD71BXX_REF), | 1696 | "DFI LanParty", STAC_92HD71BXX_REF), |
1694 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fb, | 1697 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fb, |
1695 | "HP dv4-1222nr", STAC_HP_DV4_1222NR), | 1698 | "HP dv4-1222nr", STAC_HP_DV4_1222NR), |
1699 | SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x1720, | ||
1700 | "HP", STAC_HP_DV5), | ||
1696 | SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3080, | 1701 | SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3080, |
1697 | "HP", STAC_HP_DV5), | 1702 | "HP", STAC_HP_DV5), |
1698 | SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x30f0, | 1703 | SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x30f0, |
@@ -4324,6 +4329,28 @@ static void stac92xx_free_kctls(struct hda_codec *codec) | |||
4324 | snd_array_free(&spec->kctls); | 4329 | snd_array_free(&spec->kctls); |
4325 | } | 4330 | } |
4326 | 4331 | ||
4332 | static void stac92xx_shutup(struct hda_codec *codec) | ||
4333 | { | ||
4334 | struct sigmatel_spec *spec = codec->spec; | ||
4335 | int i; | ||
4336 | hda_nid_t nid; | ||
4337 | |||
4338 | /* reset each pin before powering down DAC/ADC to avoid click noise */ | ||
4339 | nid = codec->start_nid; | ||
4340 | for (i = 0; i < codec->num_nodes; i++, nid++) { | ||
4341 | unsigned int wcaps = get_wcaps(codec, nid); | ||
4342 | unsigned int wid_type = get_wcaps_type(wcaps); | ||
4343 | if (wid_type == AC_WID_PIN) | ||
4344 | snd_hda_codec_read(codec, nid, 0, | ||
4345 | AC_VERB_SET_PIN_WIDGET_CONTROL, 0); | ||
4346 | } | ||
4347 | |||
4348 | if (spec->eapd_mask) | ||
4349 | stac_gpio_set(codec, spec->gpio_mask, | ||
4350 | spec->gpio_dir, spec->gpio_data & | ||
4351 | ~spec->eapd_mask); | ||
4352 | } | ||
4353 | |||
4327 | static void stac92xx_free(struct hda_codec *codec) | 4354 | static void stac92xx_free(struct hda_codec *codec) |
4328 | { | 4355 | { |
4329 | struct sigmatel_spec *spec = codec->spec; | 4356 | struct sigmatel_spec *spec = codec->spec; |
@@ -4331,6 +4358,7 @@ static void stac92xx_free(struct hda_codec *codec) | |||
4331 | if (! spec) | 4358 | if (! spec) |
4332 | return; | 4359 | return; |
4333 | 4360 | ||
4361 | stac92xx_shutup(codec); | ||
4334 | stac92xx_free_jacks(codec); | 4362 | stac92xx_free_jacks(codec); |
4335 | snd_array_free(&spec->events); | 4363 | snd_array_free(&spec->events); |
4336 | 4364 | ||
@@ -4665,6 +4693,26 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) | |||
4665 | } | 4693 | } |
4666 | } | 4694 | } |
4667 | 4695 | ||
4696 | static int hp_bseries_system(u32 subsystem_id) | ||
4697 | { | ||
4698 | switch (subsystem_id) { | ||
4699 | case 0x103c307e: | ||
4700 | case 0x103c307f: | ||
4701 | case 0x103c3080: | ||
4702 | case 0x103c3081: | ||
4703 | case 0x103c1722: | ||
4704 | case 0x103c1723: | ||
4705 | case 0x103c1724: | ||
4706 | case 0x103c1725: | ||
4707 | case 0x103c1726: | ||
4708 | case 0x103c1727: | ||
4709 | case 0x103c1728: | ||
4710 | case 0x103c1729: | ||
4711 | return 1; | ||
4712 | } | ||
4713 | return 0; | ||
4714 | } | ||
4715 | |||
4668 | #ifdef CONFIG_PROC_FS | 4716 | #ifdef CONFIG_PROC_FS |
4669 | static void stac92hd_proc_hook(struct snd_info_buffer *buffer, | 4717 | static void stac92hd_proc_hook(struct snd_info_buffer *buffer, |
4670 | struct hda_codec *codec, hda_nid_t nid) | 4718 | struct hda_codec *codec, hda_nid_t nid) |
@@ -4754,6 +4802,11 @@ static int stac92xx_hp_check_power_status(struct hda_codec *codec, | |||
4754 | else | 4802 | else |
4755 | spec->gpio_data |= spec->gpio_led; /* white */ | 4803 | spec->gpio_data |= spec->gpio_led; /* white */ |
4756 | 4804 | ||
4805 | if (hp_bseries_system(codec->subsystem_id)) { | ||
4806 | /* LED state is inverted on these systems */ | ||
4807 | spec->gpio_data ^= spec->gpio_led; | ||
4808 | } | ||
4809 | |||
4757 | stac_gpio_set(codec, spec->gpio_mask, | 4810 | stac_gpio_set(codec, spec->gpio_mask, |
4758 | spec->gpio_dir, | 4811 | spec->gpio_dir, |
4759 | spec->gpio_data); | 4812 | spec->gpio_data); |
@@ -4765,24 +4818,7 @@ static int stac92xx_hp_check_power_status(struct hda_codec *codec, | |||
4765 | 4818 | ||
4766 | static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) | 4819 | static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) |
4767 | { | 4820 | { |
4768 | struct sigmatel_spec *spec = codec->spec; | 4821 | stac92xx_shutup(codec); |
4769 | int i; | ||
4770 | hda_nid_t nid; | ||
4771 | |||
4772 | /* reset each pin before powering down DAC/ADC to avoid click noise */ | ||
4773 | nid = codec->start_nid; | ||
4774 | for (i = 0; i < codec->num_nodes; i++, nid++) { | ||
4775 | unsigned int wcaps = get_wcaps(codec, nid); | ||
4776 | unsigned int wid_type = get_wcaps_type(wcaps); | ||
4777 | if (wid_type == AC_WID_PIN) | ||
4778 | snd_hda_codec_read(codec, nid, 0, | ||
4779 | AC_VERB_SET_PIN_WIDGET_CONTROL, 0); | ||
4780 | } | ||
4781 | |||
4782 | if (spec->eapd_mask) | ||
4783 | stac_gpio_set(codec, spec->gpio_mask, | ||
4784 | spec->gpio_dir, spec->gpio_data & | ||
4785 | ~spec->eapd_mask); | ||
4786 | return 0; | 4822 | return 0; |
4787 | } | 4823 | } |
4788 | #endif | 4824 | #endif |
@@ -4797,6 +4833,7 @@ static struct hda_codec_ops stac92xx_patch_ops = { | |||
4797 | .suspend = stac92xx_suspend, | 4833 | .suspend = stac92xx_suspend, |
4798 | .resume = stac92xx_resume, | 4834 | .resume = stac92xx_resume, |
4799 | #endif | 4835 | #endif |
4836 | .reboot_notify = stac92xx_shutup, | ||
4800 | }; | 4837 | }; |
4801 | 4838 | ||
4802 | static int patch_stac9200(struct hda_codec *codec) | 4839 | static int patch_stac9200(struct hda_codec *codec) |
@@ -5243,6 +5280,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) | |||
5243 | { | 5280 | { |
5244 | struct sigmatel_spec *spec; | 5281 | struct sigmatel_spec *spec; |
5245 | struct hda_verb *unmute_init = stac92hd71bxx_unmute_core_init; | 5282 | struct hda_verb *unmute_init = stac92hd71bxx_unmute_core_init; |
5283 | unsigned int pin_cfg; | ||
5246 | int err = 0; | 5284 | int err = 0; |
5247 | 5285 | ||
5248 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 5286 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
@@ -5426,6 +5464,45 @@ again: | |||
5426 | break; | 5464 | break; |
5427 | } | 5465 | } |
5428 | 5466 | ||
5467 | if (hp_bseries_system(codec->subsystem_id)) { | ||
5468 | pin_cfg = snd_hda_codec_get_pincfg(codec, 0x0f); | ||
5469 | if (get_defcfg_device(pin_cfg) == AC_JACK_LINE_OUT || | ||
5470 | get_defcfg_device(pin_cfg) == AC_JACK_SPEAKER || | ||
5471 | get_defcfg_device(pin_cfg) == AC_JACK_HP_OUT) { | ||
5472 | /* It was changed in the BIOS to just satisfy MS DTM. | ||
5473 | * Lets turn it back into slaved HP | ||
5474 | */ | ||
5475 | pin_cfg = (pin_cfg & (~AC_DEFCFG_DEVICE)) | ||
5476 | | (AC_JACK_HP_OUT << | ||
5477 | AC_DEFCFG_DEVICE_SHIFT); | ||
5478 | pin_cfg = (pin_cfg & (~(AC_DEFCFG_DEF_ASSOC | ||
5479 | | AC_DEFCFG_SEQUENCE))) | ||
5480 | | 0x1f; | ||
5481 | snd_hda_codec_set_pincfg(codec, 0x0f, pin_cfg); | ||
5482 | } | ||
5483 | } | ||
5484 | |||
5485 | if ((codec->subsystem_id >> 16) == PCI_VENDOR_ID_HP) { | ||
5486 | const struct dmi_device *dev = NULL; | ||
5487 | while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, | ||
5488 | NULL, dev))) { | ||
5489 | if (strcmp(dev->name, "HP_Mute_LED_1")) { | ||
5490 | switch (codec->vendor_id) { | ||
5491 | case 0x111d7608: | ||
5492 | spec->gpio_led = 0x01; | ||
5493 | break; | ||
5494 | case 0x111d7600: | ||
5495 | case 0x111d7601: | ||
5496 | case 0x111d7602: | ||
5497 | case 0x111d7603: | ||
5498 | spec->gpio_led = 0x08; | ||
5499 | break; | ||
5500 | } | ||
5501 | break; | ||
5502 | } | ||
5503 | } | ||
5504 | } | ||
5505 | |||
5429 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 5506 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
5430 | if (spec->gpio_led) { | 5507 | if (spec->gpio_led) { |
5431 | spec->gpio_mask |= spec->gpio_led; | 5508 | spec->gpio_mask |= spec->gpio_led; |
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index ee89db90c9b6..5a856009c916 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c | |||
@@ -1,10 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * Universal Interface for Intel High Definition Audio Codec | 2 | * Universal Interface for Intel High Definition Audio Codec |
3 | * | 3 | * |
4 | * HD audio interface patch for VIA VT1702/VT1708/VT1709 codec | 4 | * HD audio interface patch for VIA VT17xx/VT18xx/VT20xx codec |
5 | * | 5 | * |
6 | * Copyright (c) 2006-2008 Lydia Wang <lydiawang@viatech.com> | 6 | * (C) 2006-2009 VIA Technology, Inc. |
7 | * Takashi Iwai <tiwai@suse.de> | 7 | * (C) 2006-2008 Takashi Iwai <tiwai@suse.de> |
8 | * | 8 | * |
9 | * This driver is free software; you can redistribute it and/or modify | 9 | * This driver is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License as published by | 10 | * it under the terms of the GNU General Public License as published by |
@@ -22,21 +22,27 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | /* * * * * * * * * * * * * * Release History * * * * * * * * * * * * * * * * */ | 24 | /* * * * * * * * * * * * * * Release History * * * * * * * * * * * * * * * * */ |
25 | /* */ | 25 | /* */ |
26 | /* 2006-03-03 Lydia Wang Create the basic patch to support VT1708 codec */ | 26 | /* 2006-03-03 Lydia Wang Create the basic patch to support VT1708 codec */ |
27 | /* 2006-03-14 Lydia Wang Modify hard code for some pin widget nid */ | 27 | /* 2006-03-14 Lydia Wang Modify hard code for some pin widget nid */ |
28 | /* 2006-08-02 Lydia Wang Add support to VT1709 codec */ | 28 | /* 2006-08-02 Lydia Wang Add support to VT1709 codec */ |
29 | /* 2006-09-08 Lydia Wang Fix internal loopback recording source select bug */ | 29 | /* 2006-09-08 Lydia Wang Fix internal loopback recording source select bug */ |
30 | /* 2007-09-12 Lydia Wang Add EAPD enable during driver initialization */ | 30 | /* 2007-09-12 Lydia Wang Add EAPD enable during driver initialization */ |
31 | /* 2007-09-17 Lydia Wang Add VT1708B codec support */ | 31 | /* 2007-09-17 Lydia Wang Add VT1708B codec support */ |
32 | /* 2007-11-14 Lydia Wang Add VT1708A codec HP and CD pin connect config */ | 32 | /* 2007-11-14 Lydia Wang Add VT1708A codec HP and CD pin connect config */ |
33 | /* 2008-02-03 Lydia Wang Fix Rear channels and Back channels inverse issue */ | 33 | /* 2008-02-03 Lydia Wang Fix Rear channels and Back channels inverse issue */ |
34 | /* 2008-03-06 Lydia Wang Add VT1702 codec and VT1708S codec support */ | 34 | /* 2008-03-06 Lydia Wang Add VT1702 codec and VT1708S codec support */ |
35 | /* 2008-04-09 Lydia Wang Add mute front speaker when HP plugin */ | 35 | /* 2008-04-09 Lydia Wang Add mute front speaker when HP plugin */ |
36 | /* 2008-04-09 Lydia Wang Add Independent HP feature */ | 36 | /* 2008-04-09 Lydia Wang Add Independent HP feature */ |
37 | /* 2008-05-28 Lydia Wang Add second S/PDIF Out support for VT1702 */ | 37 | /* 2008-05-28 Lydia Wang Add second S/PDIF Out support for VT1702 */ |
38 | /* 2008-09-15 Logan Li Add VT1708S Mic Boost workaround/backdoor */ | 38 | /* 2008-09-15 Logan Li Add VT1708S Mic Boost workaround/backdoor */ |
39 | /* */ | 39 | /* 2009-02-16 Logan Li Add support for VT1718S */ |
40 | /* 2009-03-13 Logan Li Add support for VT1716S */ | ||
41 | /* 2009-04-14 Lydai Wang Add support for VT1828S and VT2020 */ | ||
42 | /* 2009-07-08 Lydia Wang Add support for VT2002P */ | ||
43 | /* 2009-07-21 Lydia Wang Add support for VT1812 */ | ||
44 | /* 2009-09-19 Lydia Wang Add support for VT1818S */ | ||
45 | /* */ | ||
40 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | 46 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
41 | 47 | ||
42 | 48 | ||
@@ -76,14 +82,6 @@ | |||
76 | #define VT1702_HP_NID 0x17 | 82 | #define VT1702_HP_NID 0x17 |
77 | #define VT1702_DIGOUT_NID 0x11 | 83 | #define VT1702_DIGOUT_NID 0x11 |
78 | 84 | ||
79 | #define IS_VT1708_VENDORID(x) ((x) >= 0x11061708 && (x) <= 0x1106170b) | ||
80 | #define IS_VT1709_10CH_VENDORID(x) ((x) >= 0x1106e710 && (x) <= 0x1106e713) | ||
81 | #define IS_VT1709_6CH_VENDORID(x) ((x) >= 0x1106e714 && (x) <= 0x1106e717) | ||
82 | #define IS_VT1708B_8CH_VENDORID(x) ((x) >= 0x1106e720 && (x) <= 0x1106e723) | ||
83 | #define IS_VT1708B_4CH_VENDORID(x) ((x) >= 0x1106e724 && (x) <= 0x1106e727) | ||
84 | #define IS_VT1708S_VENDORID(x) ((x) >= 0x11060397 && (x) <= 0x11067397) | ||
85 | #define IS_VT1702_VENDORID(x) ((x) >= 0x11060398 && (x) <= 0x11067398) | ||
86 | |||
87 | enum VIA_HDA_CODEC { | 85 | enum VIA_HDA_CODEC { |
88 | UNKNOWN = -1, | 86 | UNKNOWN = -1, |
89 | VT1708, | 87 | VT1708, |
@@ -92,12 +90,76 @@ enum VIA_HDA_CODEC { | |||
92 | VT1708B_8CH, | 90 | VT1708B_8CH, |
93 | VT1708B_4CH, | 91 | VT1708B_4CH, |
94 | VT1708S, | 92 | VT1708S, |
93 | VT1708BCE, | ||
95 | VT1702, | 94 | VT1702, |
95 | VT1718S, | ||
96 | VT1716S, | ||
97 | VT2002P, | ||
98 | VT1812, | ||
96 | CODEC_TYPES, | 99 | CODEC_TYPES, |
97 | }; | 100 | }; |
98 | 101 | ||
99 | static enum VIA_HDA_CODEC get_codec_type(u32 vendor_id) | 102 | struct via_spec { |
103 | /* codec parameterization */ | ||
104 | struct snd_kcontrol_new *mixers[6]; | ||
105 | unsigned int num_mixers; | ||
106 | |||
107 | struct hda_verb *init_verbs[5]; | ||
108 | unsigned int num_iverbs; | ||
109 | |||
110 | char *stream_name_analog; | ||
111 | struct hda_pcm_stream *stream_analog_playback; | ||
112 | struct hda_pcm_stream *stream_analog_capture; | ||
113 | |||
114 | char *stream_name_digital; | ||
115 | struct hda_pcm_stream *stream_digital_playback; | ||
116 | struct hda_pcm_stream *stream_digital_capture; | ||
117 | |||
118 | /* playback */ | ||
119 | struct hda_multi_out multiout; | ||
120 | hda_nid_t slave_dig_outs[2]; | ||
121 | |||
122 | /* capture */ | ||
123 | unsigned int num_adc_nids; | ||
124 | hda_nid_t *adc_nids; | ||
125 | hda_nid_t mux_nids[3]; | ||
126 | hda_nid_t dig_in_nid; | ||
127 | hda_nid_t dig_in_pin; | ||
128 | |||
129 | /* capture source */ | ||
130 | const struct hda_input_mux *input_mux; | ||
131 | unsigned int cur_mux[3]; | ||
132 | |||
133 | /* PCM information */ | ||
134 | struct hda_pcm pcm_rec[3]; | ||
135 | |||
136 | /* dynamic controls, init_verbs and input_mux */ | ||
137 | struct auto_pin_cfg autocfg; | ||
138 | struct snd_array kctls; | ||
139 | struct hda_input_mux private_imux[2]; | ||
140 | hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; | ||
141 | |||
142 | /* HP mode source */ | ||
143 | const struct hda_input_mux *hp_mux; | ||
144 | unsigned int hp_independent_mode; | ||
145 | unsigned int hp_independent_mode_index; | ||
146 | unsigned int smart51_enabled; | ||
147 | unsigned int dmic_enabled; | ||
148 | enum VIA_HDA_CODEC codec_type; | ||
149 | |||
150 | /* work to check hp jack state */ | ||
151 | struct hda_codec *codec; | ||
152 | struct delayed_work vt1708_hp_work; | ||
153 | int vt1708_jack_detectect; | ||
154 | int vt1708_hp_present; | ||
155 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
156 | struct hda_loopback_check loopback; | ||
157 | #endif | ||
158 | }; | ||
159 | |||
160 | static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) | ||
100 | { | 161 | { |
162 | u32 vendor_id = codec->vendor_id; | ||
101 | u16 ven_id = vendor_id >> 16; | 163 | u16 ven_id = vendor_id >> 16; |
102 | u16 dev_id = vendor_id & 0xffff; | 164 | u16 dev_id = vendor_id & 0xffff; |
103 | enum VIA_HDA_CODEC codec_type; | 165 | enum VIA_HDA_CODEC codec_type; |
@@ -111,9 +173,11 @@ static enum VIA_HDA_CODEC get_codec_type(u32 vendor_id) | |||
111 | codec_type = VT1709_10CH; | 173 | codec_type = VT1709_10CH; |
112 | else if (dev_id >= 0xe714 && dev_id <= 0xe717) | 174 | else if (dev_id >= 0xe714 && dev_id <= 0xe717) |
113 | codec_type = VT1709_6CH; | 175 | codec_type = VT1709_6CH; |
114 | else if (dev_id >= 0xe720 && dev_id <= 0xe723) | 176 | else if (dev_id >= 0xe720 && dev_id <= 0xe723) { |
115 | codec_type = VT1708B_8CH; | 177 | codec_type = VT1708B_8CH; |
116 | else if (dev_id >= 0xe724 && dev_id <= 0xe727) | 178 | if (snd_hda_param_read(codec, 0x16, AC_PAR_CONNLIST_LEN) == 0x7) |
179 | codec_type = VT1708BCE; | ||
180 | } else if (dev_id >= 0xe724 && dev_id <= 0xe727) | ||
117 | codec_type = VT1708B_4CH; | 181 | codec_type = VT1708B_4CH; |
118 | else if ((dev_id & 0xfff) == 0x397 | 182 | else if ((dev_id & 0xfff) == 0x397 |
119 | && (dev_id >> 12) < 8) | 183 | && (dev_id >> 12) < 8) |
@@ -121,6 +185,19 @@ static enum VIA_HDA_CODEC get_codec_type(u32 vendor_id) | |||
121 | else if ((dev_id & 0xfff) == 0x398 | 185 | else if ((dev_id & 0xfff) == 0x398 |
122 | && (dev_id >> 12) < 8) | 186 | && (dev_id >> 12) < 8) |
123 | codec_type = VT1702; | 187 | codec_type = VT1702; |
188 | else if ((dev_id & 0xfff) == 0x428 | ||
189 | && (dev_id >> 12) < 8) | ||
190 | codec_type = VT1718S; | ||
191 | else if (dev_id == 0x0433 || dev_id == 0xa721) | ||
192 | codec_type = VT1716S; | ||
193 | else if (dev_id == 0x0441 || dev_id == 0x4441) | ||
194 | codec_type = VT1718S; | ||
195 | else if (dev_id == 0x0438 || dev_id == 0x4438) | ||
196 | codec_type = VT2002P; | ||
197 | else if (dev_id == 0x0448) | ||
198 | codec_type = VT1812; | ||
199 | else if (dev_id == 0x0440) | ||
200 | codec_type = VT1708S; | ||
124 | else | 201 | else |
125 | codec_type = UNKNOWN; | 202 | codec_type = UNKNOWN; |
126 | return codec_type; | 203 | return codec_type; |
@@ -128,10 +205,16 @@ static enum VIA_HDA_CODEC get_codec_type(u32 vendor_id) | |||
128 | 205 | ||
129 | #define VIA_HP_EVENT 0x01 | 206 | #define VIA_HP_EVENT 0x01 |
130 | #define VIA_GPIO_EVENT 0x02 | 207 | #define VIA_GPIO_EVENT 0x02 |
208 | #define VIA_JACK_EVENT 0x04 | ||
209 | #define VIA_MONO_EVENT 0x08 | ||
210 | #define VIA_SPEAKER_EVENT 0x10 | ||
211 | #define VIA_BIND_HP_EVENT 0x20 | ||
131 | 212 | ||
132 | enum { | 213 | enum { |
133 | VIA_CTL_WIDGET_VOL, | 214 | VIA_CTL_WIDGET_VOL, |
134 | VIA_CTL_WIDGET_MUTE, | 215 | VIA_CTL_WIDGET_MUTE, |
216 | VIA_CTL_WIDGET_ANALOG_MUTE, | ||
217 | VIA_CTL_WIDGET_BIND_PIN_MUTE, | ||
135 | }; | 218 | }; |
136 | 219 | ||
137 | enum { | 220 | enum { |
@@ -141,99 +224,162 @@ enum { | |||
141 | AUTO_SEQ_SIDE | 224 | AUTO_SEQ_SIDE |
142 | }; | 225 | }; |
143 | 226 | ||
144 | /* Some VT1708S based boards gets the micboost setting wrong, so we have | 227 | static void analog_low_current_mode(struct hda_codec *codec, int stream_idle); |
145 | * to apply some brute-force and re-write the TLV's by software. */ | 228 | static void set_jack_power_state(struct hda_codec *codec); |
146 | static int mic_boost_tlv(struct snd_kcontrol *kcontrol, int op_flag, | 229 | static int is_aa_path_mute(struct hda_codec *codec); |
147 | unsigned int size, unsigned int __user *_tlv) | 230 | |
231 | static void vt1708_start_hp_work(struct via_spec *spec) | ||
148 | { | 232 | { |
149 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 233 | if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0) |
150 | hda_nid_t nid = get_amp_nid(kcontrol); | 234 | return; |
235 | snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81, | ||
236 | !spec->vt1708_jack_detectect); | ||
237 | if (!delayed_work_pending(&spec->vt1708_hp_work)) | ||
238 | schedule_delayed_work(&spec->vt1708_hp_work, | ||
239 | msecs_to_jiffies(100)); | ||
240 | } | ||
151 | 241 | ||
152 | if (get_codec_type(codec->vendor_id) == VT1708S | 242 | static void vt1708_stop_hp_work(struct via_spec *spec) |
153 | && (nid == 0x1a || nid == 0x1e)) { | 243 | { |
154 | if (size < 4 * sizeof(unsigned int)) | 244 | if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0) |
155 | return -ENOMEM; | 245 | return; |
156 | if (put_user(1, _tlv)) /* SNDRV_CTL_TLVT_DB_SCALE */ | 246 | if (snd_hda_get_bool_hint(spec->codec, "analog_loopback_hp_detect") == 1 |
157 | return -EFAULT; | 247 | && !is_aa_path_mute(spec->codec)) |
158 | if (put_user(2 * sizeof(unsigned int), _tlv + 1)) | 248 | return; |
159 | return -EFAULT; | 249 | snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81, |
160 | if (put_user(0, _tlv + 2)) /* offset = 0 */ | 250 | !spec->vt1708_jack_detectect); |
161 | return -EFAULT; | 251 | cancel_delayed_work(&spec->vt1708_hp_work); |
162 | if (put_user(1000, _tlv + 3)) /* step size = 10 dB */ | 252 | flush_scheduled_work(); |
163 | return -EFAULT; | ||
164 | } | ||
165 | return 0; | ||
166 | } | 253 | } |
167 | 254 | ||
168 | static int mic_boost_volume_info(struct snd_kcontrol *kcontrol, | 255 | |
169 | struct snd_ctl_elem_info *uinfo) | 256 | static int analog_input_switch_put(struct snd_kcontrol *kcontrol, |
257 | struct snd_ctl_elem_value *ucontrol) | ||
170 | { | 258 | { |
259 | int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); | ||
171 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 260 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
172 | hda_nid_t nid = get_amp_nid(kcontrol); | ||
173 | 261 | ||
174 | if (get_codec_type(codec->vendor_id) == VT1708S | 262 | set_jack_power_state(codec); |
175 | && (nid == 0x1a || nid == 0x1e)) { | 263 | analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1); |
176 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 264 | if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) { |
177 | uinfo->count = 2; | 265 | if (is_aa_path_mute(codec)) |
178 | uinfo->value.integer.min = 0; | 266 | vt1708_start_hp_work(codec->spec); |
179 | uinfo->value.integer.max = 3; | 267 | else |
268 | vt1708_stop_hp_work(codec->spec); | ||
180 | } | 269 | } |
181 | return 0; | 270 | return change; |
182 | } | 271 | } |
183 | 272 | ||
184 | static struct snd_kcontrol_new vt1708_control_templates[] = { | 273 | /* modify .put = snd_hda_mixer_amp_switch_put */ |
185 | HDA_CODEC_VOLUME(NULL, 0, 0, 0), | 274 | #define ANALOG_INPUT_MUTE \ |
186 | HDA_CODEC_MUTE(NULL, 0, 0, 0), | 275 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
187 | }; | 276 | .name = NULL, \ |
188 | 277 | .index = 0, \ | |
189 | 278 | .info = snd_hda_mixer_amp_switch_info, \ | |
190 | struct via_spec { | 279 | .get = snd_hda_mixer_amp_switch_get, \ |
191 | /* codec parameterization */ | 280 | .put = analog_input_switch_put, \ |
192 | struct snd_kcontrol_new *mixers[3]; | 281 | .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) } |
193 | unsigned int num_mixers; | ||
194 | 282 | ||
195 | struct hda_verb *init_verbs[5]; | 283 | static void via_hp_bind_automute(struct hda_codec *codec); |
196 | unsigned int num_iverbs; | ||
197 | 284 | ||
198 | char *stream_name_analog; | 285 | static int bind_pin_switch_put(struct snd_kcontrol *kcontrol, |
199 | struct hda_pcm_stream *stream_analog_playback; | 286 | struct snd_ctl_elem_value *ucontrol) |
200 | struct hda_pcm_stream *stream_analog_capture; | 287 | { |
201 | 288 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | |
202 | char *stream_name_digital; | 289 | struct via_spec *spec = codec->spec; |
203 | struct hda_pcm_stream *stream_digital_playback; | 290 | int i; |
204 | struct hda_pcm_stream *stream_digital_capture; | 291 | int change = 0; |
205 | |||
206 | /* playback */ | ||
207 | struct hda_multi_out multiout; | ||
208 | hda_nid_t slave_dig_outs[2]; | ||
209 | |||
210 | /* capture */ | ||
211 | unsigned int num_adc_nids; | ||
212 | hda_nid_t *adc_nids; | ||
213 | hda_nid_t mux_nids[3]; | ||
214 | hda_nid_t dig_in_nid; | ||
215 | hda_nid_t dig_in_pin; | ||
216 | 292 | ||
217 | /* capture source */ | 293 | long *valp = ucontrol->value.integer.value; |
218 | const struct hda_input_mux *input_mux; | 294 | int lmute, rmute; |
219 | unsigned int cur_mux[3]; | 295 | if (strstr(kcontrol->id.name, "Switch") == NULL) { |
296 | snd_printd("Invalid control!\n"); | ||
297 | return change; | ||
298 | } | ||
299 | change = snd_hda_mixer_amp_switch_put(kcontrol, | ||
300 | ucontrol); | ||
301 | /* Get mute value */ | ||
302 | lmute = *valp ? 0 : HDA_AMP_MUTE; | ||
303 | valp++; | ||
304 | rmute = *valp ? 0 : HDA_AMP_MUTE; | ||
305 | |||
306 | /* Set hp pins */ | ||
307 | if (!spec->hp_independent_mode) { | ||
308 | for (i = 0; i < spec->autocfg.hp_outs; i++) { | ||
309 | snd_hda_codec_amp_update( | ||
310 | codec, spec->autocfg.hp_pins[i], | ||
311 | 0, HDA_OUTPUT, 0, HDA_AMP_MUTE, | ||
312 | lmute); | ||
313 | snd_hda_codec_amp_update( | ||
314 | codec, spec->autocfg.hp_pins[i], | ||
315 | 1, HDA_OUTPUT, 0, HDA_AMP_MUTE, | ||
316 | rmute); | ||
317 | } | ||
318 | } | ||
220 | 319 | ||
221 | /* PCM information */ | 320 | if (!lmute && !rmute) { |
222 | struct hda_pcm pcm_rec[3]; | 321 | /* Line Outs */ |
322 | for (i = 0; i < spec->autocfg.line_outs; i++) | ||
323 | snd_hda_codec_amp_stereo( | ||
324 | codec, spec->autocfg.line_out_pins[i], | ||
325 | HDA_OUTPUT, 0, HDA_AMP_MUTE, 0); | ||
326 | /* Speakers */ | ||
327 | for (i = 0; i < spec->autocfg.speaker_outs; i++) | ||
328 | snd_hda_codec_amp_stereo( | ||
329 | codec, spec->autocfg.speaker_pins[i], | ||
330 | HDA_OUTPUT, 0, HDA_AMP_MUTE, 0); | ||
331 | /* unmute */ | ||
332 | via_hp_bind_automute(codec); | ||
223 | 333 | ||
224 | /* dynamic controls, init_verbs and input_mux */ | 334 | } else { |
225 | struct auto_pin_cfg autocfg; | 335 | if (lmute) { |
226 | struct snd_array kctls; | 336 | /* Mute all left channels */ |
227 | struct hda_input_mux private_imux[2]; | 337 | for (i = 1; i < spec->autocfg.line_outs; i++) |
228 | hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; | 338 | snd_hda_codec_amp_update( |
339 | codec, | ||
340 | spec->autocfg.line_out_pins[i], | ||
341 | 0, HDA_OUTPUT, 0, HDA_AMP_MUTE, | ||
342 | lmute); | ||
343 | for (i = 0; i < spec->autocfg.speaker_outs; i++) | ||
344 | snd_hda_codec_amp_update( | ||
345 | codec, | ||
346 | spec->autocfg.speaker_pins[i], | ||
347 | 0, HDA_OUTPUT, 0, HDA_AMP_MUTE, | ||
348 | lmute); | ||
349 | } | ||
350 | if (rmute) { | ||
351 | /* mute all right channels */ | ||
352 | for (i = 1; i < spec->autocfg.line_outs; i++) | ||
353 | snd_hda_codec_amp_update( | ||
354 | codec, | ||
355 | spec->autocfg.line_out_pins[i], | ||
356 | 1, HDA_OUTPUT, 0, HDA_AMP_MUTE, | ||
357 | rmute); | ||
358 | for (i = 0; i < spec->autocfg.speaker_outs; i++) | ||
359 | snd_hda_codec_amp_update( | ||
360 | codec, | ||
361 | spec->autocfg.speaker_pins[i], | ||
362 | 1, HDA_OUTPUT, 0, HDA_AMP_MUTE, | ||
363 | rmute); | ||
364 | } | ||
365 | } | ||
366 | return change; | ||
367 | } | ||
229 | 368 | ||
230 | /* HP mode source */ | 369 | #define BIND_PIN_MUTE \ |
231 | const struct hda_input_mux *hp_mux; | 370 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
232 | unsigned int hp_independent_mode; | 371 | .name = NULL, \ |
372 | .index = 0, \ | ||
373 | .info = snd_hda_mixer_amp_switch_info, \ | ||
374 | .get = snd_hda_mixer_amp_switch_get, \ | ||
375 | .put = bind_pin_switch_put, \ | ||
376 | .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) } | ||
233 | 377 | ||
234 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 378 | static struct snd_kcontrol_new via_control_templates[] = { |
235 | struct hda_loopback_check loopback; | 379 | HDA_CODEC_VOLUME(NULL, 0, 0, 0), |
236 | #endif | 380 | HDA_CODEC_MUTE(NULL, 0, 0, 0), |
381 | ANALOG_INPUT_MUTE, | ||
382 | BIND_PIN_MUTE, | ||
237 | }; | 383 | }; |
238 | 384 | ||
239 | static hda_nid_t vt1708_adc_nids[2] = { | 385 | static hda_nid_t vt1708_adc_nids[2] = { |
@@ -261,6 +407,27 @@ static hda_nid_t vt1702_adc_nids[3] = { | |||
261 | 0x12, 0x20, 0x1F | 407 | 0x12, 0x20, 0x1F |
262 | }; | 408 | }; |
263 | 409 | ||
410 | static hda_nid_t vt1718S_adc_nids[2] = { | ||
411 | /* ADC1-2 */ | ||
412 | 0x10, 0x11 | ||
413 | }; | ||
414 | |||
415 | static hda_nid_t vt1716S_adc_nids[2] = { | ||
416 | /* ADC1-2 */ | ||
417 | 0x13, 0x14 | ||
418 | }; | ||
419 | |||
420 | static hda_nid_t vt2002P_adc_nids[2] = { | ||
421 | /* ADC1-2 */ | ||
422 | 0x10, 0x11 | ||
423 | }; | ||
424 | |||
425 | static hda_nid_t vt1812_adc_nids[2] = { | ||
426 | /* ADC1-2 */ | ||
427 | 0x10, 0x11 | ||
428 | }; | ||
429 | |||
430 | |||
264 | /* add dynamic controls */ | 431 | /* add dynamic controls */ |
265 | static int via_add_control(struct via_spec *spec, int type, const char *name, | 432 | static int via_add_control(struct via_spec *spec, int type, const char *name, |
266 | unsigned long val) | 433 | unsigned long val) |
@@ -271,7 +438,7 @@ static int via_add_control(struct via_spec *spec, int type, const char *name, | |||
271 | knew = snd_array_new(&spec->kctls); | 438 | knew = snd_array_new(&spec->kctls); |
272 | if (!knew) | 439 | if (!knew) |
273 | return -ENOMEM; | 440 | return -ENOMEM; |
274 | *knew = vt1708_control_templates[type]; | 441 | *knew = via_control_templates[type]; |
275 | knew->name = kstrdup(name, GFP_KERNEL); | 442 | knew->name = kstrdup(name, GFP_KERNEL); |
276 | if (!knew->name) | 443 | if (!knew->name) |
277 | return -ENOMEM; | 444 | return -ENOMEM; |
@@ -293,8 +460,8 @@ static void via_free_kctls(struct hda_codec *codec) | |||
293 | } | 460 | } |
294 | 461 | ||
295 | /* create input playback/capture controls for the given pin */ | 462 | /* create input playback/capture controls for the given pin */ |
296 | static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin, | 463 | static int via_new_analog_input(struct via_spec *spec, const char *ctlname, |
297 | const char *ctlname, int idx, int mix_nid) | 464 | int idx, int mix_nid) |
298 | { | 465 | { |
299 | char name[32]; | 466 | char name[32]; |
300 | int err; | 467 | int err; |
@@ -305,7 +472,7 @@ static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin, | |||
305 | if (err < 0) | 472 | if (err < 0) |
306 | return err; | 473 | return err; |
307 | sprintf(name, "%s Playback Switch", ctlname); | 474 | sprintf(name, "%s Playback Switch", ctlname); |
308 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | 475 | err = via_add_control(spec, VIA_CTL_WIDGET_ANALOG_MUTE, name, |
309 | HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); | 476 | HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); |
310 | if (err < 0) | 477 | if (err < 0) |
311 | return err; | 478 | return err; |
@@ -322,7 +489,7 @@ static void via_auto_set_output_and_unmute(struct hda_codec *codec, | |||
322 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | 489 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, |
323 | AMP_OUT_UNMUTE); | 490 | AMP_OUT_UNMUTE); |
324 | if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD) | 491 | if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD) |
325 | snd_hda_codec_write(codec, nid, 0, | 492 | snd_hda_codec_write(codec, nid, 0, |
326 | AC_VERB_SET_EAPD_BTLENABLE, 0x02); | 493 | AC_VERB_SET_EAPD_BTLENABLE, 0x02); |
327 | } | 494 | } |
328 | 495 | ||
@@ -343,10 +510,13 @@ static void via_auto_init_hp_out(struct hda_codec *codec) | |||
343 | { | 510 | { |
344 | struct via_spec *spec = codec->spec; | 511 | struct via_spec *spec = codec->spec; |
345 | hda_nid_t pin; | 512 | hda_nid_t pin; |
513 | int i; | ||
346 | 514 | ||
347 | pin = spec->autocfg.hp_pins[0]; | 515 | for (i = 0; i < spec->autocfg.hp_outs; i++) { |
348 | if (pin) /* connect to front */ | 516 | pin = spec->autocfg.hp_pins[i]; |
349 | via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); | 517 | if (pin) /* connect to front */ |
518 | via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); | ||
519 | } | ||
350 | } | 520 | } |
351 | 521 | ||
352 | static void via_auto_init_analog_input(struct hda_codec *codec) | 522 | static void via_auto_init_analog_input(struct hda_codec *codec) |
@@ -364,6 +534,510 @@ static void via_auto_init_analog_input(struct hda_codec *codec) | |||
364 | 534 | ||
365 | } | 535 | } |
366 | } | 536 | } |
537 | |||
538 | static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin); | ||
539 | |||
540 | static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, | ||
541 | unsigned int *affected_parm) | ||
542 | { | ||
543 | unsigned parm; | ||
544 | unsigned def_conf = snd_hda_codec_get_pincfg(codec, nid); | ||
545 | unsigned no_presence = (def_conf & AC_DEFCFG_MISC) | ||
546 | >> AC_DEFCFG_MISC_SHIFT | ||
547 | & AC_DEFCFG_MISC_NO_PRESENCE; /* do not support pin sense */ | ||
548 | unsigned present = snd_hda_codec_read(codec, nid, 0, | ||
549 | AC_VERB_GET_PIN_SENSE, 0) >> 31; | ||
550 | struct via_spec *spec = codec->spec; | ||
551 | if ((spec->smart51_enabled && is_smart51_pins(spec, nid)) | ||
552 | || ((no_presence || present) | ||
553 | && get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)) { | ||
554 | *affected_parm = AC_PWRST_D0; /* if it's connected */ | ||
555 | parm = AC_PWRST_D0; | ||
556 | } else | ||
557 | parm = AC_PWRST_D3; | ||
558 | |||
559 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm); | ||
560 | } | ||
561 | |||
562 | static void set_jack_power_state(struct hda_codec *codec) | ||
563 | { | ||
564 | struct via_spec *spec = codec->spec; | ||
565 | int imux_is_smixer; | ||
566 | unsigned int parm; | ||
567 | |||
568 | if (spec->codec_type == VT1702) { | ||
569 | imux_is_smixer = snd_hda_codec_read( | ||
570 | codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3; | ||
571 | /* inputs */ | ||
572 | /* PW 1/2/5 (14h/15h/18h) */ | ||
573 | parm = AC_PWRST_D3; | ||
574 | set_pin_power_state(codec, 0x14, &parm); | ||
575 | set_pin_power_state(codec, 0x15, &parm); | ||
576 | set_pin_power_state(codec, 0x18, &parm); | ||
577 | if (imux_is_smixer) | ||
578 | parm = AC_PWRST_D0; /* SW0 = stereo mixer (idx 3) */ | ||
579 | /* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */ | ||
580 | snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, | ||
581 | parm); | ||
582 | snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE, | ||
583 | parm); | ||
584 | snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, | ||
585 | parm); | ||
586 | snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE, | ||
587 | parm); | ||
588 | |||
589 | /* outputs */ | ||
590 | /* PW 3/4 (16h/17h) */ | ||
591 | parm = AC_PWRST_D3; | ||
592 | set_pin_power_state(codec, 0x16, &parm); | ||
593 | set_pin_power_state(codec, 0x17, &parm); | ||
594 | /* MW0 (1ah), AOW 0/1 (10h/1dh) */ | ||
595 | snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, | ||
596 | imux_is_smixer ? AC_PWRST_D0 : parm); | ||
597 | snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, | ||
598 | parm); | ||
599 | snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, | ||
600 | parm); | ||
601 | } else if (spec->codec_type == VT1708B_8CH | ||
602 | || spec->codec_type == VT1708B_4CH | ||
603 | || spec->codec_type == VT1708S) { | ||
604 | /* SW0 (17h) = stereo mixer */ | ||
605 | int is_8ch = spec->codec_type != VT1708B_4CH; | ||
606 | imux_is_smixer = snd_hda_codec_read( | ||
607 | codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00) | ||
608 | == ((spec->codec_type == VT1708S) ? 5 : 0); | ||
609 | /* inputs */ | ||
610 | /* PW 1/2/5 (1ah/1bh/1eh) */ | ||
611 | parm = AC_PWRST_D3; | ||
612 | set_pin_power_state(codec, 0x1a, &parm); | ||
613 | set_pin_power_state(codec, 0x1b, &parm); | ||
614 | set_pin_power_state(codec, 0x1e, &parm); | ||
615 | if (imux_is_smixer) | ||
616 | parm = AC_PWRST_D0; | ||
617 | /* SW0 (17h), AIW 0/1 (13h/14h) */ | ||
618 | snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, | ||
619 | parm); | ||
620 | snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, | ||
621 | parm); | ||
622 | snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, | ||
623 | parm); | ||
624 | |||
625 | /* outputs */ | ||
626 | /* PW0 (19h), SW1 (18h), AOW1 (11h) */ | ||
627 | parm = AC_PWRST_D3; | ||
628 | set_pin_power_state(codec, 0x19, &parm); | ||
629 | snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, | ||
630 | parm); | ||
631 | snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, | ||
632 | parm); | ||
633 | |||
634 | /* PW6 (22h), SW2 (26h), AOW2 (24h) */ | ||
635 | if (is_8ch) { | ||
636 | parm = AC_PWRST_D3; | ||
637 | set_pin_power_state(codec, 0x22, &parm); | ||
638 | snd_hda_codec_write(codec, 0x26, 0, | ||
639 | AC_VERB_SET_POWER_STATE, parm); | ||
640 | snd_hda_codec_write(codec, 0x24, 0, | ||
641 | AC_VERB_SET_POWER_STATE, parm); | ||
642 | } | ||
643 | |||
644 | /* PW 3/4/7 (1ch/1dh/23h) */ | ||
645 | parm = AC_PWRST_D3; | ||
646 | /* force to D0 for internal Speaker */ | ||
647 | set_pin_power_state(codec, 0x1c, &parm); | ||
648 | set_pin_power_state(codec, 0x1d, &parm); | ||
649 | if (is_8ch) | ||
650 | set_pin_power_state(codec, 0x23, &parm); | ||
651 | /* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */ | ||
652 | snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE, | ||
653 | imux_is_smixer ? AC_PWRST_D0 : parm); | ||
654 | snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, | ||
655 | parm); | ||
656 | if (is_8ch) { | ||
657 | snd_hda_codec_write(codec, 0x25, 0, | ||
658 | AC_VERB_SET_POWER_STATE, parm); | ||
659 | snd_hda_codec_write(codec, 0x27, 0, | ||
660 | AC_VERB_SET_POWER_STATE, parm); | ||
661 | } | ||
662 | } else if (spec->codec_type == VT1718S) { | ||
663 | /* MUX6 (1eh) = stereo mixer */ | ||
664 | imux_is_smixer = snd_hda_codec_read( | ||
665 | codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; | ||
666 | /* inputs */ | ||
667 | /* PW 5/6/7 (29h/2ah/2bh) */ | ||
668 | parm = AC_PWRST_D3; | ||
669 | set_pin_power_state(codec, 0x29, &parm); | ||
670 | set_pin_power_state(codec, 0x2a, &parm); | ||
671 | set_pin_power_state(codec, 0x2b, &parm); | ||
672 | if (imux_is_smixer) | ||
673 | parm = AC_PWRST_D0; | ||
674 | /* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */ | ||
675 | snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, | ||
676 | parm); | ||
677 | snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, | ||
678 | parm); | ||
679 | snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, | ||
680 | parm); | ||
681 | snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, | ||
682 | parm); | ||
683 | |||
684 | /* outputs */ | ||
685 | /* PW3 (27h), MW2 (1ah), AOW3 (bh) */ | ||
686 | parm = AC_PWRST_D3; | ||
687 | set_pin_power_state(codec, 0x27, &parm); | ||
688 | snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, | ||
689 | parm); | ||
690 | snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE, | ||
691 | parm); | ||
692 | |||
693 | /* PW2 (26h), AOW2 (ah) */ | ||
694 | parm = AC_PWRST_D3; | ||
695 | set_pin_power_state(codec, 0x26, &parm); | ||
696 | snd_hda_codec_write(codec, 0xa, 0, AC_VERB_SET_POWER_STATE, | ||
697 | parm); | ||
698 | |||
699 | /* PW0/1 (24h/25h) */ | ||
700 | parm = AC_PWRST_D3; | ||
701 | set_pin_power_state(codec, 0x24, &parm); | ||
702 | set_pin_power_state(codec, 0x25, &parm); | ||
703 | if (!spec->hp_independent_mode) /* check for redirected HP */ | ||
704 | set_pin_power_state(codec, 0x28, &parm); | ||
705 | snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, | ||
706 | parm); | ||
707 | snd_hda_codec_write(codec, 0x9, 0, AC_VERB_SET_POWER_STATE, | ||
708 | parm); | ||
709 | /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */ | ||
710 | snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE, | ||
711 | imux_is_smixer ? AC_PWRST_D0 : parm); | ||
712 | if (spec->hp_independent_mode) { | ||
713 | /* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */ | ||
714 | parm = AC_PWRST_D3; | ||
715 | set_pin_power_state(codec, 0x28, &parm); | ||
716 | snd_hda_codec_write(codec, 0x1b, 0, | ||
717 | AC_VERB_SET_POWER_STATE, parm); | ||
718 | snd_hda_codec_write(codec, 0x34, 0, | ||
719 | AC_VERB_SET_POWER_STATE, parm); | ||
720 | snd_hda_codec_write(codec, 0xc, 0, | ||
721 | AC_VERB_SET_POWER_STATE, parm); | ||
722 | } | ||
723 | } else if (spec->codec_type == VT1716S) { | ||
724 | unsigned int mono_out, present; | ||
725 | /* SW0 (17h) = stereo mixer */ | ||
726 | imux_is_smixer = snd_hda_codec_read( | ||
727 | codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; | ||
728 | /* inputs */ | ||
729 | /* PW 1/2/5 (1ah/1bh/1eh) */ | ||
730 | parm = AC_PWRST_D3; | ||
731 | set_pin_power_state(codec, 0x1a, &parm); | ||
732 | set_pin_power_state(codec, 0x1b, &parm); | ||
733 | set_pin_power_state(codec, 0x1e, &parm); | ||
734 | if (imux_is_smixer) | ||
735 | parm = AC_PWRST_D0; | ||
736 | /* SW0 (17h), AIW0(13h) */ | ||
737 | snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, | ||
738 | parm); | ||
739 | snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, | ||
740 | parm); | ||
741 | |||
742 | parm = AC_PWRST_D3; | ||
743 | set_pin_power_state(codec, 0x1e, &parm); | ||
744 | /* PW11 (22h) */ | ||
745 | if (spec->dmic_enabled) | ||
746 | set_pin_power_state(codec, 0x22, &parm); | ||
747 | else | ||
748 | snd_hda_codec_write( | ||
749 | codec, 0x22, 0, | ||
750 | AC_VERB_SET_POWER_STATE, AC_PWRST_D3); | ||
751 | |||
752 | /* SW2(26h), AIW1(14h) */ | ||
753 | snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_POWER_STATE, | ||
754 | parm); | ||
755 | snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, | ||
756 | parm); | ||
757 | |||
758 | /* outputs */ | ||
759 | /* PW0 (19h), SW1 (18h), AOW1 (11h) */ | ||
760 | parm = AC_PWRST_D3; | ||
761 | set_pin_power_state(codec, 0x19, &parm); | ||
762 | /* Smart 5.1 PW2(1bh) */ | ||
763 | if (spec->smart51_enabled) | ||
764 | set_pin_power_state(codec, 0x1b, &parm); | ||
765 | snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, | ||
766 | parm); | ||
767 | snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, | ||
768 | parm); | ||
769 | |||
770 | /* PW7 (23h), SW3 (27h), AOW3 (25h) */ | ||
771 | parm = AC_PWRST_D3; | ||
772 | set_pin_power_state(codec, 0x23, &parm); | ||
773 | /* Smart 5.1 PW1(1ah) */ | ||
774 | if (spec->smart51_enabled) | ||
775 | set_pin_power_state(codec, 0x1a, &parm); | ||
776 | snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE, | ||
777 | parm); | ||
778 | |||
779 | /* Smart 5.1 PW5(1eh) */ | ||
780 | if (spec->smart51_enabled) | ||
781 | set_pin_power_state(codec, 0x1e, &parm); | ||
782 | snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE, | ||
783 | parm); | ||
784 | |||
785 | /* Mono out */ | ||
786 | /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/ | ||
787 | present = snd_hda_codec_read( | ||
788 | codec, 0x1c, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
789 | if (present) | ||
790 | mono_out = 0; | ||
791 | else { | ||
792 | present = snd_hda_codec_read( | ||
793 | codec, 0x1d, 0, AC_VERB_GET_PIN_SENSE, 0) | ||
794 | & 0x80000000; | ||
795 | if (!spec->hp_independent_mode && present) | ||
796 | mono_out = 0; | ||
797 | else | ||
798 | mono_out = 1; | ||
799 | } | ||
800 | parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3; | ||
801 | snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE, | ||
802 | parm); | ||
803 | snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE, | ||
804 | parm); | ||
805 | snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE, | ||
806 | parm); | ||
807 | |||
808 | /* PW 3/4 (1ch/1dh) */ | ||
809 | parm = AC_PWRST_D3; | ||
810 | set_pin_power_state(codec, 0x1c, &parm); | ||
811 | set_pin_power_state(codec, 0x1d, &parm); | ||
812 | /* HP Independent Mode, power on AOW3 */ | ||
813 | if (spec->hp_independent_mode) | ||
814 | snd_hda_codec_write(codec, 0x25, 0, | ||
815 | AC_VERB_SET_POWER_STATE, parm); | ||
816 | |||
817 | /* force to D0 for internal Speaker */ | ||
818 | /* MW0 (16h), AOW0 (10h) */ | ||
819 | snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE, | ||
820 | imux_is_smixer ? AC_PWRST_D0 : parm); | ||
821 | snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, | ||
822 | mono_out ? AC_PWRST_D0 : parm); | ||
823 | } else if (spec->codec_type == VT2002P) { | ||
824 | unsigned int present; | ||
825 | /* MUX9 (1eh) = stereo mixer */ | ||
826 | imux_is_smixer = snd_hda_codec_read( | ||
827 | codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3; | ||
828 | /* inputs */ | ||
829 | /* PW 5/6/7 (29h/2ah/2bh) */ | ||
830 | parm = AC_PWRST_D3; | ||
831 | set_pin_power_state(codec, 0x29, &parm); | ||
832 | set_pin_power_state(codec, 0x2a, &parm); | ||
833 | set_pin_power_state(codec, 0x2b, &parm); | ||
834 | if (imux_is_smixer) | ||
835 | parm = AC_PWRST_D0; | ||
836 | /* MUX9/10 (1eh/1fh), AIW 0/1 (10h/11h) */ | ||
837 | snd_hda_codec_write(codec, 0x1e, 0, | ||
838 | AC_VERB_SET_POWER_STATE, parm); | ||
839 | snd_hda_codec_write(codec, 0x1f, 0, | ||
840 | AC_VERB_SET_POWER_STATE, parm); | ||
841 | snd_hda_codec_write(codec, 0x10, 0, | ||
842 | AC_VERB_SET_POWER_STATE, parm); | ||
843 | snd_hda_codec_write(codec, 0x11, 0, | ||
844 | AC_VERB_SET_POWER_STATE, parm); | ||
845 | |||
846 | /* outputs */ | ||
847 | /* AOW0 (8h)*/ | ||
848 | snd_hda_codec_write(codec, 0x8, 0, | ||
849 | AC_VERB_SET_POWER_STATE, AC_PWRST_D0); | ||
850 | |||
851 | /* PW4 (26h), MW4 (1ch), MUX4(37h) */ | ||
852 | parm = AC_PWRST_D3; | ||
853 | set_pin_power_state(codec, 0x26, &parm); | ||
854 | snd_hda_codec_write(codec, 0x1c, 0, | ||
855 | AC_VERB_SET_POWER_STATE, parm); | ||
856 | snd_hda_codec_write(codec, 0x37, | ||
857 | 0, AC_VERB_SET_POWER_STATE, parm); | ||
858 | |||
859 | /* PW1 (25h), MW1 (19h), MUX1(35h), AOW1 (9h) */ | ||
860 | parm = AC_PWRST_D3; | ||
861 | set_pin_power_state(codec, 0x25, &parm); | ||
862 | snd_hda_codec_write(codec, 0x19, 0, | ||
863 | AC_VERB_SET_POWER_STATE, parm); | ||
864 | snd_hda_codec_write(codec, 0x35, 0, | ||
865 | AC_VERB_SET_POWER_STATE, parm); | ||
866 | if (spec->hp_independent_mode) { | ||
867 | snd_hda_codec_write(codec, 0x9, 0, | ||
868 | AC_VERB_SET_POWER_STATE, parm); | ||
869 | } | ||
870 | |||
871 | /* Class-D */ | ||
872 | /* PW0 (24h), MW0(18h), MUX0(34h) */ | ||
873 | present = snd_hda_codec_read( | ||
874 | codec, 0x25, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
875 | parm = AC_PWRST_D3; | ||
876 | set_pin_power_state(codec, 0x24, &parm); | ||
877 | if (present) { | ||
878 | snd_hda_codec_write( | ||
879 | codec, 0x18, 0, | ||
880 | AC_VERB_SET_POWER_STATE, AC_PWRST_D3); | ||
881 | snd_hda_codec_write( | ||
882 | codec, 0x34, 0, | ||
883 | AC_VERB_SET_POWER_STATE, AC_PWRST_D3); | ||
884 | } else { | ||
885 | snd_hda_codec_write( | ||
886 | codec, 0x18, 0, | ||
887 | AC_VERB_SET_POWER_STATE, AC_PWRST_D0); | ||
888 | snd_hda_codec_write( | ||
889 | codec, 0x34, 0, | ||
890 | AC_VERB_SET_POWER_STATE, AC_PWRST_D0); | ||
891 | } | ||
892 | |||
893 | /* Mono Out */ | ||
894 | /* PW15 (31h), MW8(17h), MUX8(3bh) */ | ||
895 | present = snd_hda_codec_read( | ||
896 | codec, 0x26, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
897 | parm = AC_PWRST_D3; | ||
898 | set_pin_power_state(codec, 0x31, &parm); | ||
899 | if (present) { | ||
900 | snd_hda_codec_write( | ||
901 | codec, 0x17, 0, | ||
902 | AC_VERB_SET_POWER_STATE, AC_PWRST_D3); | ||
903 | snd_hda_codec_write( | ||
904 | codec, 0x3b, 0, | ||
905 | AC_VERB_SET_POWER_STATE, AC_PWRST_D3); | ||
906 | } else { | ||
907 | snd_hda_codec_write( | ||
908 | codec, 0x17, 0, | ||
909 | AC_VERB_SET_POWER_STATE, AC_PWRST_D0); | ||
910 | snd_hda_codec_write( | ||
911 | codec, 0x3b, 0, | ||
912 | AC_VERB_SET_POWER_STATE, AC_PWRST_D0); | ||
913 | } | ||
914 | |||
915 | /* MW9 (21h) */ | ||
916 | if (imux_is_smixer || !is_aa_path_mute(codec)) | ||
917 | snd_hda_codec_write( | ||
918 | codec, 0x21, 0, | ||
919 | AC_VERB_SET_POWER_STATE, AC_PWRST_D0); | ||
920 | else | ||
921 | snd_hda_codec_write( | ||
922 | codec, 0x21, 0, | ||
923 | AC_VERB_SET_POWER_STATE, AC_PWRST_D3); | ||
924 | } else if (spec->codec_type == VT1812) { | ||
925 | unsigned int present; | ||
926 | /* MUX10 (1eh) = stereo mixer */ | ||
927 | imux_is_smixer = snd_hda_codec_read( | ||
928 | codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; | ||
929 | /* inputs */ | ||
930 | /* PW 5/6/7 (29h/2ah/2bh) */ | ||
931 | parm = AC_PWRST_D3; | ||
932 | set_pin_power_state(codec, 0x29, &parm); | ||
933 | set_pin_power_state(codec, 0x2a, &parm); | ||
934 | set_pin_power_state(codec, 0x2b, &parm); | ||
935 | if (imux_is_smixer) | ||
936 | parm = AC_PWRST_D0; | ||
937 | /* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */ | ||
938 | snd_hda_codec_write(codec, 0x1e, 0, | ||
939 | AC_VERB_SET_POWER_STATE, parm); | ||
940 | snd_hda_codec_write(codec, 0x1f, 0, | ||
941 | AC_VERB_SET_POWER_STATE, parm); | ||
942 | snd_hda_codec_write(codec, 0x10, 0, | ||
943 | AC_VERB_SET_POWER_STATE, parm); | ||
944 | snd_hda_codec_write(codec, 0x11, 0, | ||
945 | AC_VERB_SET_POWER_STATE, parm); | ||
946 | |||
947 | /* outputs */ | ||
948 | /* AOW0 (8h)*/ | ||
949 | snd_hda_codec_write(codec, 0x8, 0, | ||
950 | AC_VERB_SET_POWER_STATE, AC_PWRST_D0); | ||
951 | |||
952 | /* PW4 (28h), MW4 (18h), MUX4(38h) */ | ||
953 | parm = AC_PWRST_D3; | ||
954 | set_pin_power_state(codec, 0x28, &parm); | ||
955 | snd_hda_codec_write(codec, 0x18, 0, | ||
956 | AC_VERB_SET_POWER_STATE, parm); | ||
957 | snd_hda_codec_write(codec, 0x38, 0, | ||
958 | AC_VERB_SET_POWER_STATE, parm); | ||
959 | |||
960 | /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */ | ||
961 | parm = AC_PWRST_D3; | ||
962 | set_pin_power_state(codec, 0x25, &parm); | ||
963 | snd_hda_codec_write(codec, 0x15, 0, | ||
964 | AC_VERB_SET_POWER_STATE, parm); | ||
965 | snd_hda_codec_write(codec, 0x35, 0, | ||
966 | AC_VERB_SET_POWER_STATE, parm); | ||
967 | if (spec->hp_independent_mode) { | ||
968 | snd_hda_codec_write(codec, 0x9, 0, | ||
969 | AC_VERB_SET_POWER_STATE, parm); | ||
970 | } | ||
971 | |||
972 | /* Internal Speaker */ | ||
973 | /* PW0 (24h), MW0(14h), MUX0(34h) */ | ||
974 | present = snd_hda_codec_read( | ||
975 | codec, 0x25, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
976 | parm = AC_PWRST_D3; | ||
977 | set_pin_power_state(codec, 0x24, &parm); | ||
978 | if (present) { | ||
979 | snd_hda_codec_write(codec, 0x14, 0, | ||
980 | AC_VERB_SET_POWER_STATE, | ||
981 | AC_PWRST_D3); | ||
982 | snd_hda_codec_write(codec, 0x34, 0, | ||
983 | AC_VERB_SET_POWER_STATE, | ||
984 | AC_PWRST_D3); | ||
985 | } else { | ||
986 | snd_hda_codec_write(codec, 0x14, 0, | ||
987 | AC_VERB_SET_POWER_STATE, | ||
988 | AC_PWRST_D0); | ||
989 | snd_hda_codec_write(codec, 0x34, 0, | ||
990 | AC_VERB_SET_POWER_STATE, | ||
991 | AC_PWRST_D0); | ||
992 | } | ||
993 | /* Mono Out */ | ||
994 | /* PW13 (31h), MW13(1ch), MUX13(3ch), MW14(3eh) */ | ||
995 | present = snd_hda_codec_read( | ||
996 | codec, 0x28, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
997 | parm = AC_PWRST_D3; | ||
998 | set_pin_power_state(codec, 0x31, &parm); | ||
999 | if (present) { | ||
1000 | snd_hda_codec_write(codec, 0x1c, 0, | ||
1001 | AC_VERB_SET_POWER_STATE, | ||
1002 | AC_PWRST_D3); | ||
1003 | snd_hda_codec_write(codec, 0x3c, 0, | ||
1004 | AC_VERB_SET_POWER_STATE, | ||
1005 | AC_PWRST_D3); | ||
1006 | snd_hda_codec_write(codec, 0x3e, 0, | ||
1007 | AC_VERB_SET_POWER_STATE, | ||
1008 | AC_PWRST_D3); | ||
1009 | } else { | ||
1010 | snd_hda_codec_write(codec, 0x1c, 0, | ||
1011 | AC_VERB_SET_POWER_STATE, | ||
1012 | AC_PWRST_D0); | ||
1013 | snd_hda_codec_write(codec, 0x3c, 0, | ||
1014 | AC_VERB_SET_POWER_STATE, | ||
1015 | AC_PWRST_D0); | ||
1016 | snd_hda_codec_write(codec, 0x3e, 0, | ||
1017 | AC_VERB_SET_POWER_STATE, | ||
1018 | AC_PWRST_D0); | ||
1019 | } | ||
1020 | |||
1021 | /* PW15 (33h), MW15 (1dh), MUX15(3dh) */ | ||
1022 | parm = AC_PWRST_D3; | ||
1023 | set_pin_power_state(codec, 0x33, &parm); | ||
1024 | snd_hda_codec_write(codec, 0x1d, 0, | ||
1025 | AC_VERB_SET_POWER_STATE, parm); | ||
1026 | snd_hda_codec_write(codec, 0x3d, 0, | ||
1027 | AC_VERB_SET_POWER_STATE, parm); | ||
1028 | |||
1029 | /* MW9 (21h) */ | ||
1030 | if (imux_is_smixer || !is_aa_path_mute(codec)) | ||
1031 | snd_hda_codec_write( | ||
1032 | codec, 0x21, 0, | ||
1033 | AC_VERB_SET_POWER_STATE, AC_PWRST_D0); | ||
1034 | else | ||
1035 | snd_hda_codec_write( | ||
1036 | codec, 0x21, 0, | ||
1037 | AC_VERB_SET_POWER_STATE, AC_PWRST_D3); | ||
1038 | } | ||
1039 | } | ||
1040 | |||
367 | /* | 1041 | /* |
368 | * input MUX handling | 1042 | * input MUX handling |
369 | */ | 1043 | */ |
@@ -395,6 +1069,14 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol, | |||
395 | 1069 | ||
396 | if (!spec->mux_nids[adc_idx]) | 1070 | if (!spec->mux_nids[adc_idx]) |
397 | return -EINVAL; | 1071 | return -EINVAL; |
1072 | /* switch to D0 beofre change index */ | ||
1073 | if (snd_hda_codec_read(codec, spec->mux_nids[adc_idx], 0, | ||
1074 | AC_VERB_GET_POWER_STATE, 0x00) != AC_PWRST_D0) | ||
1075 | snd_hda_codec_write(codec, spec->mux_nids[adc_idx], 0, | ||
1076 | AC_VERB_SET_POWER_STATE, AC_PWRST_D0); | ||
1077 | /* update jack power state */ | ||
1078 | set_jack_power_state(codec); | ||
1079 | |||
398 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, | 1080 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, |
399 | spec->mux_nids[adc_idx], | 1081 | spec->mux_nids[adc_idx], |
400 | &spec->cur_mux[adc_idx]); | 1082 | &spec->cur_mux[adc_idx]); |
@@ -413,16 +1095,74 @@ static int via_independent_hp_get(struct snd_kcontrol *kcontrol, | |||
413 | { | 1095 | { |
414 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 1096 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
415 | struct via_spec *spec = codec->spec; | 1097 | struct via_spec *spec = codec->spec; |
416 | hda_nid_t nid = spec->autocfg.hp_pins[0]; | 1098 | hda_nid_t nid; |
417 | unsigned int pinsel = snd_hda_codec_read(codec, nid, 0, | 1099 | unsigned int pinsel; |
418 | AC_VERB_GET_CONNECT_SEL, | 1100 | |
419 | 0x00); | 1101 | switch (spec->codec_type) { |
420 | 1102 | case VT1718S: | |
1103 | nid = 0x34; | ||
1104 | break; | ||
1105 | case VT2002P: | ||
1106 | nid = 0x35; | ||
1107 | break; | ||
1108 | case VT1812: | ||
1109 | nid = 0x3d; | ||
1110 | break; | ||
1111 | default: | ||
1112 | nid = spec->autocfg.hp_pins[0]; | ||
1113 | break; | ||
1114 | } | ||
1115 | /* use !! to translate conn sel 2 for VT1718S */ | ||
1116 | pinsel = !!snd_hda_codec_read(codec, nid, 0, | ||
1117 | AC_VERB_GET_CONNECT_SEL, | ||
1118 | 0x00); | ||
421 | ucontrol->value.enumerated.item[0] = pinsel; | 1119 | ucontrol->value.enumerated.item[0] = pinsel; |
422 | 1120 | ||
423 | return 0; | 1121 | return 0; |
424 | } | 1122 | } |
425 | 1123 | ||
1124 | static void activate_ctl(struct hda_codec *codec, const char *name, int active) | ||
1125 | { | ||
1126 | struct snd_kcontrol *ctl = snd_hda_find_mixer_ctl(codec, name); | ||
1127 | if (ctl) { | ||
1128 | ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; | ||
1129 | ctl->vd[0].access |= active | ||
1130 | ? 0 : SNDRV_CTL_ELEM_ACCESS_INACTIVE; | ||
1131 | snd_ctl_notify(codec->bus->card, | ||
1132 | SNDRV_CTL_EVENT_MASK_VALUE, &ctl->id); | ||
1133 | } | ||
1134 | } | ||
1135 | |||
1136 | static int update_side_mute_status(struct hda_codec *codec) | ||
1137 | { | ||
1138 | /* mute side channel */ | ||
1139 | struct via_spec *spec = codec->spec; | ||
1140 | unsigned int parm = spec->hp_independent_mode | ||
1141 | ? AMP_OUT_MUTE : AMP_OUT_UNMUTE; | ||
1142 | hda_nid_t sw3; | ||
1143 | |||
1144 | switch (spec->codec_type) { | ||
1145 | case VT1708: | ||
1146 | sw3 = 0x1b; | ||
1147 | break; | ||
1148 | case VT1709_10CH: | ||
1149 | sw3 = 0x29; | ||
1150 | break; | ||
1151 | case VT1708B_8CH: | ||
1152 | case VT1708S: | ||
1153 | sw3 = 0x27; | ||
1154 | break; | ||
1155 | default: | ||
1156 | sw3 = 0; | ||
1157 | break; | ||
1158 | } | ||
1159 | |||
1160 | if (sw3) | ||
1161 | snd_hda_codec_write(codec, sw3, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
1162 | parm); | ||
1163 | return 0; | ||
1164 | } | ||
1165 | |||
426 | static int via_independent_hp_put(struct snd_kcontrol *kcontrol, | 1166 | static int via_independent_hp_put(struct snd_kcontrol *kcontrol, |
427 | struct snd_ctl_elem_value *ucontrol) | 1167 | struct snd_ctl_elem_value *ucontrol) |
428 | { | 1168 | { |
@@ -430,47 +1170,46 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, | |||
430 | struct via_spec *spec = codec->spec; | 1170 | struct via_spec *spec = codec->spec; |
431 | hda_nid_t nid = spec->autocfg.hp_pins[0]; | 1171 | hda_nid_t nid = spec->autocfg.hp_pins[0]; |
432 | unsigned int pinsel = ucontrol->value.enumerated.item[0]; | 1172 | unsigned int pinsel = ucontrol->value.enumerated.item[0]; |
433 | unsigned int con_nid = snd_hda_codec_read(codec, nid, 0, | 1173 | /* Get Independent Mode index of headphone pin widget */ |
434 | AC_VERB_GET_CONNECT_LIST, 0) & 0xff; | 1174 | spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel |
435 | 1175 | ? 1 : 0; | |
436 | if (con_nid == spec->multiout.hp_nid) { | 1176 | |
437 | if (pinsel == 0) { | 1177 | switch (spec->codec_type) { |
438 | if (!spec->hp_independent_mode) { | 1178 | case VT1718S: |
439 | if (spec->multiout.num_dacs > 1) | 1179 | nid = 0x34; |
440 | spec->multiout.num_dacs -= 1; | 1180 | pinsel = pinsel ? 2 : 0; /* indep HP use AOW4 (index 2) */ |
441 | spec->hp_independent_mode = 1; | 1181 | spec->multiout.num_dacs = 4; |
442 | } | 1182 | break; |
443 | } else if (pinsel == 1) { | 1183 | case VT2002P: |
444 | if (spec->hp_independent_mode) { | 1184 | nid = 0x35; |
445 | if (spec->multiout.num_dacs > 1) | 1185 | break; |
446 | spec->multiout.num_dacs += 1; | 1186 | case VT1812: |
447 | spec->hp_independent_mode = 0; | 1187 | nid = 0x3d; |
448 | } | 1188 | break; |
449 | } | 1189 | default: |
450 | } else { | 1190 | nid = spec->autocfg.hp_pins[0]; |
451 | if (pinsel == 0) { | 1191 | break; |
452 | if (spec->hp_independent_mode) { | 1192 | } |
453 | if (spec->multiout.num_dacs > 1) | 1193 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, pinsel); |
454 | spec->multiout.num_dacs += 1; | 1194 | |
455 | spec->hp_independent_mode = 0; | 1195 | if (spec->multiout.hp_nid && spec->multiout.hp_nid |
456 | } | 1196 | != spec->multiout.dac_nids[HDA_FRONT]) |
457 | } else if (pinsel == 1) { | 1197 | snd_hda_codec_setup_stream(codec, spec->multiout.hp_nid, |
458 | if (!spec->hp_independent_mode) { | 1198 | 0, 0, 0); |
459 | if (spec->multiout.num_dacs > 1) | 1199 | |
460 | spec->multiout.num_dacs -= 1; | 1200 | update_side_mute_status(codec); |
461 | spec->hp_independent_mode = 1; | 1201 | /* update HP volume/swtich active state */ |
462 | } | 1202 | if (spec->codec_type == VT1708S |
463 | } | 1203 | || spec->codec_type == VT1702 |
1204 | || spec->codec_type == VT1718S | ||
1205 | || spec->codec_type == VT1716S | ||
1206 | || spec->codec_type == VT2002P | ||
1207 | || spec->codec_type == VT1812) { | ||
1208 | activate_ctl(codec, "Headphone Playback Volume", | ||
1209 | spec->hp_independent_mode); | ||
1210 | activate_ctl(codec, "Headphone Playback Switch", | ||
1211 | spec->hp_independent_mode); | ||
464 | } | 1212 | } |
465 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, | ||
466 | pinsel); | ||
467 | |||
468 | if (spec->multiout.hp_nid && | ||
469 | spec->multiout.hp_nid != spec->multiout.dac_nids[HDA_FRONT]) | ||
470 | snd_hda_codec_setup_stream(codec, | ||
471 | spec->multiout.hp_nid, | ||
472 | 0, 0, 0); | ||
473 | |||
474 | return 0; | 1213 | return 0; |
475 | } | 1214 | } |
476 | 1215 | ||
@@ -486,6 +1225,175 @@ static struct snd_kcontrol_new via_hp_mixer[] = { | |||
486 | { } /* end */ | 1225 | { } /* end */ |
487 | }; | 1226 | }; |
488 | 1227 | ||
1228 | static void notify_aa_path_ctls(struct hda_codec *codec) | ||
1229 | { | ||
1230 | int i; | ||
1231 | struct snd_ctl_elem_id id; | ||
1232 | const char *labels[] = {"Mic", "Front Mic", "Line"}; | ||
1233 | |||
1234 | memset(&id, 0, sizeof(id)); | ||
1235 | id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
1236 | for (i = 0; i < ARRAY_SIZE(labels); i++) { | ||
1237 | sprintf(id.name, "%s Playback Volume", labels[i]); | ||
1238 | snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
1239 | &id); | ||
1240 | } | ||
1241 | } | ||
1242 | |||
1243 | static void mute_aa_path(struct hda_codec *codec, int mute) | ||
1244 | { | ||
1245 | struct via_spec *spec = codec->spec; | ||
1246 | hda_nid_t nid_mixer; | ||
1247 | int start_idx; | ||
1248 | int end_idx; | ||
1249 | int i; | ||
1250 | /* get nid of MW0 and start & end index */ | ||
1251 | switch (spec->codec_type) { | ||
1252 | case VT1708: | ||
1253 | nid_mixer = 0x17; | ||
1254 | start_idx = 2; | ||
1255 | end_idx = 4; | ||
1256 | break; | ||
1257 | case VT1709_10CH: | ||
1258 | case VT1709_6CH: | ||
1259 | nid_mixer = 0x18; | ||
1260 | start_idx = 2; | ||
1261 | end_idx = 4; | ||
1262 | break; | ||
1263 | case VT1708B_8CH: | ||
1264 | case VT1708B_4CH: | ||
1265 | case VT1708S: | ||
1266 | case VT1716S: | ||
1267 | nid_mixer = 0x16; | ||
1268 | start_idx = 2; | ||
1269 | end_idx = 4; | ||
1270 | break; | ||
1271 | default: | ||
1272 | return; | ||
1273 | } | ||
1274 | /* check AA path's mute status */ | ||
1275 | for (i = start_idx; i <= end_idx; i++) { | ||
1276 | int val = mute ? HDA_AMP_MUTE : HDA_AMP_UNMUTE; | ||
1277 | snd_hda_codec_amp_stereo(codec, nid_mixer, HDA_INPUT, i, | ||
1278 | HDA_AMP_MUTE, val); | ||
1279 | } | ||
1280 | } | ||
1281 | static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin) | ||
1282 | { | ||
1283 | int res = 0; | ||
1284 | int index; | ||
1285 | for (index = AUTO_PIN_MIC; index < AUTO_PIN_FRONT_LINE; index++) { | ||
1286 | if (pin == spec->autocfg.input_pins[index]) { | ||
1287 | res = 1; | ||
1288 | break; | ||
1289 | } | ||
1290 | } | ||
1291 | return res; | ||
1292 | } | ||
1293 | |||
1294 | static int via_smart51_info(struct snd_kcontrol *kcontrol, | ||
1295 | struct snd_ctl_elem_info *uinfo) | ||
1296 | { | ||
1297 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
1298 | uinfo->count = 1; | ||
1299 | uinfo->value.integer.min = 0; | ||
1300 | uinfo->value.integer.max = 1; | ||
1301 | return 0; | ||
1302 | } | ||
1303 | |||
1304 | static int via_smart51_get(struct snd_kcontrol *kcontrol, | ||
1305 | struct snd_ctl_elem_value *ucontrol) | ||
1306 | { | ||
1307 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1308 | struct via_spec *spec = codec->spec; | ||
1309 | int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE }; | ||
1310 | int on = 1; | ||
1311 | int i; | ||
1312 | |||
1313 | for (i = 0; i < ARRAY_SIZE(index); i++) { | ||
1314 | hda_nid_t nid = spec->autocfg.input_pins[index[i]]; | ||
1315 | if (nid) { | ||
1316 | int ctl = | ||
1317 | snd_hda_codec_read(codec, nid, 0, | ||
1318 | AC_VERB_GET_PIN_WIDGET_CONTROL, | ||
1319 | 0); | ||
1320 | if (i == AUTO_PIN_FRONT_MIC | ||
1321 | && spec->hp_independent_mode | ||
1322 | && spec->codec_type != VT1718S) | ||
1323 | continue; /* ignore FMic for independent HP */ | ||
1324 | if (ctl & AC_PINCTL_IN_EN | ||
1325 | && !(ctl & AC_PINCTL_OUT_EN)) | ||
1326 | on = 0; | ||
1327 | } | ||
1328 | } | ||
1329 | *ucontrol->value.integer.value = on; | ||
1330 | return 0; | ||
1331 | } | ||
1332 | |||
1333 | static int via_smart51_put(struct snd_kcontrol *kcontrol, | ||
1334 | struct snd_ctl_elem_value *ucontrol) | ||
1335 | { | ||
1336 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1337 | struct via_spec *spec = codec->spec; | ||
1338 | int out_in = *ucontrol->value.integer.value | ||
1339 | ? AC_PINCTL_OUT_EN : AC_PINCTL_IN_EN; | ||
1340 | int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE }; | ||
1341 | int i; | ||
1342 | |||
1343 | for (i = 0; i < ARRAY_SIZE(index); i++) { | ||
1344 | hda_nid_t nid = spec->autocfg.input_pins[index[i]]; | ||
1345 | if (i == AUTO_PIN_FRONT_MIC | ||
1346 | && spec->hp_independent_mode | ||
1347 | && spec->codec_type != VT1718S) | ||
1348 | continue; /* don't retask FMic for independent HP */ | ||
1349 | if (nid) { | ||
1350 | unsigned int parm = snd_hda_codec_read( | ||
1351 | codec, nid, 0, | ||
1352 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
1353 | parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN); | ||
1354 | parm |= out_in; | ||
1355 | snd_hda_codec_write(codec, nid, 0, | ||
1356 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
1357 | parm); | ||
1358 | if (out_in == AC_PINCTL_OUT_EN) { | ||
1359 | mute_aa_path(codec, 1); | ||
1360 | notify_aa_path_ctls(codec); | ||
1361 | } | ||
1362 | if (spec->codec_type == VT1718S) | ||
1363 | snd_hda_codec_amp_stereo( | ||
1364 | codec, nid, HDA_OUTPUT, 0, HDA_AMP_MUTE, | ||
1365 | HDA_AMP_UNMUTE); | ||
1366 | } | ||
1367 | if (i == AUTO_PIN_FRONT_MIC) { | ||
1368 | if (spec->codec_type == VT1708S | ||
1369 | || spec->codec_type == VT1716S) { | ||
1370 | /* input = index 1 (AOW3) */ | ||
1371 | snd_hda_codec_write( | ||
1372 | codec, nid, 0, | ||
1373 | AC_VERB_SET_CONNECT_SEL, 1); | ||
1374 | snd_hda_codec_amp_stereo( | ||
1375 | codec, nid, HDA_OUTPUT, | ||
1376 | 0, HDA_AMP_MUTE, HDA_AMP_UNMUTE); | ||
1377 | } | ||
1378 | } | ||
1379 | } | ||
1380 | spec->smart51_enabled = *ucontrol->value.integer.value; | ||
1381 | set_jack_power_state(codec); | ||
1382 | return 1; | ||
1383 | } | ||
1384 | |||
1385 | static struct snd_kcontrol_new via_smart51_mixer[] = { | ||
1386 | { | ||
1387 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1388 | .name = "Smart 5.1", | ||
1389 | .count = 1, | ||
1390 | .info = via_smart51_info, | ||
1391 | .get = via_smart51_get, | ||
1392 | .put = via_smart51_put, | ||
1393 | }, | ||
1394 | {} /* end */ | ||
1395 | }; | ||
1396 | |||
489 | /* capture mixer elements */ | 1397 | /* capture mixer elements */ |
490 | static struct snd_kcontrol_new vt1708_capture_mixer[] = { | 1398 | static struct snd_kcontrol_new vt1708_capture_mixer[] = { |
491 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT), | 1399 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT), |
@@ -506,6 +1414,112 @@ static struct snd_kcontrol_new vt1708_capture_mixer[] = { | |||
506 | }, | 1414 | }, |
507 | { } /* end */ | 1415 | { } /* end */ |
508 | }; | 1416 | }; |
1417 | |||
1418 | /* check AA path's mute statue */ | ||
1419 | static int is_aa_path_mute(struct hda_codec *codec) | ||
1420 | { | ||
1421 | int mute = 1; | ||
1422 | hda_nid_t nid_mixer; | ||
1423 | int start_idx; | ||
1424 | int end_idx; | ||
1425 | int i; | ||
1426 | struct via_spec *spec = codec->spec; | ||
1427 | /* get nid of MW0 and start & end index */ | ||
1428 | switch (spec->codec_type) { | ||
1429 | case VT1708B_8CH: | ||
1430 | case VT1708B_4CH: | ||
1431 | case VT1708S: | ||
1432 | case VT1716S: | ||
1433 | nid_mixer = 0x16; | ||
1434 | start_idx = 2; | ||
1435 | end_idx = 4; | ||
1436 | break; | ||
1437 | case VT1702: | ||
1438 | nid_mixer = 0x1a; | ||
1439 | start_idx = 1; | ||
1440 | end_idx = 3; | ||
1441 | break; | ||
1442 | case VT1718S: | ||
1443 | nid_mixer = 0x21; | ||
1444 | start_idx = 1; | ||
1445 | end_idx = 3; | ||
1446 | break; | ||
1447 | case VT2002P: | ||
1448 | case VT1812: | ||
1449 | nid_mixer = 0x21; | ||
1450 | start_idx = 0; | ||
1451 | end_idx = 2; | ||
1452 | break; | ||
1453 | default: | ||
1454 | return 0; | ||
1455 | } | ||
1456 | /* check AA path's mute status */ | ||
1457 | for (i = start_idx; i <= end_idx; i++) { | ||
1458 | unsigned int con_list = snd_hda_codec_read( | ||
1459 | codec, nid_mixer, 0, AC_VERB_GET_CONNECT_LIST, i/4*4); | ||
1460 | int shift = 8 * (i % 4); | ||
1461 | hda_nid_t nid_pin = (con_list & (0xff << shift)) >> shift; | ||
1462 | unsigned int defconf = snd_hda_codec_get_pincfg(codec, nid_pin); | ||
1463 | if (get_defcfg_connect(defconf) == AC_JACK_PORT_COMPLEX) { | ||
1464 | /* check mute status while the pin is connected */ | ||
1465 | int mute_l = snd_hda_codec_amp_read(codec, nid_mixer, 0, | ||
1466 | HDA_INPUT, i) >> 7; | ||
1467 | int mute_r = snd_hda_codec_amp_read(codec, nid_mixer, 1, | ||
1468 | HDA_INPUT, i) >> 7; | ||
1469 | if (!mute_l || !mute_r) { | ||
1470 | mute = 0; | ||
1471 | break; | ||
1472 | } | ||
1473 | } | ||
1474 | } | ||
1475 | return mute; | ||
1476 | } | ||
1477 | |||
1478 | /* enter/exit analog low-current mode */ | ||
1479 | static void analog_low_current_mode(struct hda_codec *codec, int stream_idle) | ||
1480 | { | ||
1481 | struct via_spec *spec = codec->spec; | ||
1482 | static int saved_stream_idle = 1; /* saved stream idle status */ | ||
1483 | int enable = is_aa_path_mute(codec); | ||
1484 | unsigned int verb = 0; | ||
1485 | unsigned int parm = 0; | ||
1486 | |||
1487 | if (stream_idle == -1) /* stream status did not change */ | ||
1488 | enable = enable && saved_stream_idle; | ||
1489 | else { | ||
1490 | enable = enable && stream_idle; | ||
1491 | saved_stream_idle = stream_idle; | ||
1492 | } | ||
1493 | |||
1494 | /* decide low current mode's verb & parameter */ | ||
1495 | switch (spec->codec_type) { | ||
1496 | case VT1708B_8CH: | ||
1497 | case VT1708B_4CH: | ||
1498 | verb = 0xf70; | ||
1499 | parm = enable ? 0x02 : 0x00; /* 0x02: 2/3x, 0x00: 1x */ | ||
1500 | break; | ||
1501 | case VT1708S: | ||
1502 | case VT1718S: | ||
1503 | case VT1716S: | ||
1504 | verb = 0xf73; | ||
1505 | parm = enable ? 0x51 : 0xe1; /* 0x51: 4/28x, 0xe1: 1x */ | ||
1506 | break; | ||
1507 | case VT1702: | ||
1508 | verb = 0xf73; | ||
1509 | parm = enable ? 0x01 : 0x1d; /* 0x01: 4/40x, 0x1d: 1x */ | ||
1510 | break; | ||
1511 | case VT2002P: | ||
1512 | case VT1812: | ||
1513 | verb = 0xf93; | ||
1514 | parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */ | ||
1515 | break; | ||
1516 | default: | ||
1517 | return; /* other codecs are not supported */ | ||
1518 | } | ||
1519 | /* send verb */ | ||
1520 | snd_hda_codec_write(codec, codec->afg, 0, verb, parm); | ||
1521 | } | ||
1522 | |||
509 | /* | 1523 | /* |
510 | * generic initialization of ADC, input mixers and output mixers | 1524 | * generic initialization of ADC, input mixers and output mixers |
511 | */ | 1525 | */ |
@@ -534,9 +1548,9 @@ static struct hda_verb vt1708_volume_init_verbs[] = { | |||
534 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | 1548 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, |
535 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | 1549 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, |
536 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | 1550 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, |
537 | 1551 | ||
538 | /* Setup default input to PW4 */ | 1552 | /* Setup default input MW0 to PW4 */ |
539 | {0x20, AC_VERB_SET_CONNECT_SEL, 0x1}, | 1553 | {0x20, AC_VERB_SET_CONNECT_SEL, 0}, |
540 | /* PW9 Output enable */ | 1554 | /* PW9 Output enable */ |
541 | {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | 1555 | {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, |
542 | { } | 1556 | { } |
@@ -547,30 +1561,13 @@ static int via_playback_pcm_open(struct hda_pcm_stream *hinfo, | |||
547 | struct snd_pcm_substream *substream) | 1561 | struct snd_pcm_substream *substream) |
548 | { | 1562 | { |
549 | struct via_spec *spec = codec->spec; | 1563 | struct via_spec *spec = codec->spec; |
1564 | int idle = substream->pstr->substream_opened == 1 | ||
1565 | && substream->ref_count == 0; | ||
1566 | analog_low_current_mode(codec, idle); | ||
550 | return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, | 1567 | return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, |
551 | hinfo); | 1568 | hinfo); |
552 | } | 1569 | } |
553 | 1570 | ||
554 | static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
555 | struct hda_codec *codec, | ||
556 | unsigned int stream_tag, | ||
557 | unsigned int format, | ||
558 | struct snd_pcm_substream *substream) | ||
559 | { | ||
560 | struct via_spec *spec = codec->spec; | ||
561 | return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, | ||
562 | stream_tag, format, substream); | ||
563 | } | ||
564 | |||
565 | static int via_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
566 | struct hda_codec *codec, | ||
567 | struct snd_pcm_substream *substream) | ||
568 | { | ||
569 | struct via_spec *spec = codec->spec; | ||
570 | return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); | ||
571 | } | ||
572 | |||
573 | |||
574 | static void playback_multi_pcm_prep_0(struct hda_codec *codec, | 1571 | static void playback_multi_pcm_prep_0(struct hda_codec *codec, |
575 | unsigned int stream_tag, | 1572 | unsigned int stream_tag, |
576 | unsigned int format, | 1573 | unsigned int format, |
@@ -615,8 +1612,8 @@ static void playback_multi_pcm_prep_0(struct hda_codec *codec, | |||
615 | snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, | 1612 | snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, |
616 | 0, format); | 1613 | 0, format); |
617 | 1614 | ||
618 | if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] && | 1615 | if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] |
619 | !spec->hp_independent_mode) | 1616 | && !spec->hp_independent_mode) |
620 | /* headphone out will just decode front left/right (stereo) */ | 1617 | /* headphone out will just decode front left/right (stereo) */ |
621 | snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, | 1618 | snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, |
622 | 0, format); | 1619 | 0, format); |
@@ -658,7 +1655,7 @@ static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo, | |||
658 | snd_hda_codec_setup_stream(codec, mout->hp_nid, | 1655 | snd_hda_codec_setup_stream(codec, mout->hp_nid, |
659 | stream_tag, 0, format); | 1656 | stream_tag, 0, format); |
660 | } | 1657 | } |
661 | 1658 | vt1708_start_hp_work(spec); | |
662 | return 0; | 1659 | return 0; |
663 | } | 1660 | } |
664 | 1661 | ||
@@ -698,7 +1695,7 @@ static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
698 | snd_hda_codec_setup_stream(codec, mout->hp_nid, | 1695 | snd_hda_codec_setup_stream(codec, mout->hp_nid, |
699 | 0, 0, 0); | 1696 | 0, 0, 0); |
700 | } | 1697 | } |
701 | 1698 | vt1708_stop_hp_work(spec); | |
702 | return 0; | 1699 | return 0; |
703 | } | 1700 | } |
704 | 1701 | ||
@@ -779,7 +1776,7 @@ static struct hda_pcm_stream vt1708_pcm_analog_playback = { | |||
779 | }; | 1776 | }; |
780 | 1777 | ||
781 | static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = { | 1778 | static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = { |
782 | .substreams = 1, | 1779 | .substreams = 2, |
783 | .channels_min = 2, | 1780 | .channels_min = 2, |
784 | .channels_max = 8, | 1781 | .channels_max = 8, |
785 | .nid = 0x10, /* NID to query formats and rates */ | 1782 | .nid = 0x10, /* NID to query formats and rates */ |
@@ -790,8 +1787,8 @@ static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = { | |||
790 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 1787 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
791 | .ops = { | 1788 | .ops = { |
792 | .open = via_playback_pcm_open, | 1789 | .open = via_playback_pcm_open, |
793 | .prepare = via_playback_pcm_prepare, | 1790 | .prepare = via_playback_multi_pcm_prepare, |
794 | .cleanup = via_playback_pcm_cleanup | 1791 | .cleanup = via_playback_multi_pcm_cleanup |
795 | }, | 1792 | }, |
796 | }; | 1793 | }; |
797 | 1794 | ||
@@ -853,6 +1850,11 @@ static int via_build_controls(struct hda_codec *codec) | |||
853 | if (err < 0) | 1850 | if (err < 0) |
854 | return err; | 1851 | return err; |
855 | } | 1852 | } |
1853 | |||
1854 | /* init power states */ | ||
1855 | set_jack_power_state(codec); | ||
1856 | analog_low_current_mode(codec, 1); | ||
1857 | |||
856 | via_free_kctls(codec); /* no longer needed */ | 1858 | via_free_kctls(codec); /* no longer needed */ |
857 | return 0; | 1859 | return 0; |
858 | } | 1860 | } |
@@ -866,8 +1868,10 @@ static int via_build_pcms(struct hda_codec *codec) | |||
866 | codec->pcm_info = info; | 1868 | codec->pcm_info = info; |
867 | 1869 | ||
868 | info->name = spec->stream_name_analog; | 1870 | info->name = spec->stream_name_analog; |
869 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback); | 1871 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = |
870 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; | 1872 | *(spec->stream_analog_playback); |
1873 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = | ||
1874 | spec->multiout.dac_nids[0]; | ||
871 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); | 1875 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); |
872 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; | 1876 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; |
873 | 1877 | ||
@@ -904,20 +1908,62 @@ static void via_free(struct hda_codec *codec) | |||
904 | return; | 1908 | return; |
905 | 1909 | ||
906 | via_free_kctls(codec); | 1910 | via_free_kctls(codec); |
1911 | vt1708_stop_hp_work(spec); | ||
907 | kfree(codec->spec); | 1912 | kfree(codec->spec); |
908 | } | 1913 | } |
909 | 1914 | ||
910 | /* mute internal speaker if HP is plugged */ | 1915 | /* mute internal speaker if HP is plugged */ |
911 | static void via_hp_automute(struct hda_codec *codec) | 1916 | static void via_hp_automute(struct hda_codec *codec) |
912 | { | 1917 | { |
913 | unsigned int present; | 1918 | unsigned int present = 0; |
914 | struct via_spec *spec = codec->spec; | 1919 | struct via_spec *spec = codec->spec; |
915 | 1920 | ||
916 | present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0, | 1921 | present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0, |
917 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 1922 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; |
918 | snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0], | 1923 | |
919 | HDA_OUTPUT, 0, HDA_AMP_MUTE, | 1924 | if (!spec->hp_independent_mode) { |
920 | present ? HDA_AMP_MUTE : 0); | 1925 | struct snd_ctl_elem_id id; |
1926 | /* auto mute */ | ||
1927 | snd_hda_codec_amp_stereo( | ||
1928 | codec, spec->autocfg.line_out_pins[0], HDA_OUTPUT, 0, | ||
1929 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
1930 | /* notify change */ | ||
1931 | memset(&id, 0, sizeof(id)); | ||
1932 | id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
1933 | strcpy(id.name, "Front Playback Switch"); | ||
1934 | snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
1935 | &id); | ||
1936 | } | ||
1937 | } | ||
1938 | |||
1939 | /* mute mono out if HP or Line out is plugged */ | ||
1940 | static void via_mono_automute(struct hda_codec *codec) | ||
1941 | { | ||
1942 | unsigned int hp_present, lineout_present; | ||
1943 | struct via_spec *spec = codec->spec; | ||
1944 | |||
1945 | if (spec->codec_type != VT1716S) | ||
1946 | return; | ||
1947 | |||
1948 | lineout_present = snd_hda_codec_read( | ||
1949 | codec, spec->autocfg.line_out_pins[0], 0, | ||
1950 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
1951 | |||
1952 | /* Mute Mono Out if Line Out is plugged */ | ||
1953 | if (lineout_present) { | ||
1954 | snd_hda_codec_amp_stereo( | ||
1955 | codec, 0x2A, HDA_OUTPUT, 0, HDA_AMP_MUTE, HDA_AMP_MUTE); | ||
1956 | return; | ||
1957 | } | ||
1958 | |||
1959 | hp_present = snd_hda_codec_read( | ||
1960 | codec, spec->autocfg.hp_pins[0], 0, | ||
1961 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
1962 | |||
1963 | if (!spec->hp_independent_mode) | ||
1964 | snd_hda_codec_amp_stereo( | ||
1965 | codec, 0x2A, HDA_OUTPUT, 0, HDA_AMP_MUTE, | ||
1966 | hp_present ? HDA_AMP_MUTE : 0); | ||
921 | } | 1967 | } |
922 | 1968 | ||
923 | static void via_gpio_control(struct hda_codec *codec) | 1969 | static void via_gpio_control(struct hda_codec *codec) |
@@ -968,15 +2014,86 @@ static void via_gpio_control(struct hda_codec *codec) | |||
968 | } | 2014 | } |
969 | } | 2015 | } |
970 | 2016 | ||
2017 | /* mute Internal-Speaker if HP is plugged */ | ||
2018 | static void via_speaker_automute(struct hda_codec *codec) | ||
2019 | { | ||
2020 | unsigned int hp_present; | ||
2021 | struct via_spec *spec = codec->spec; | ||
2022 | |||
2023 | if (spec->codec_type != VT2002P && spec->codec_type != VT1812) | ||
2024 | return; | ||
2025 | |||
2026 | hp_present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0, | ||
2027 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
2028 | |||
2029 | if (!spec->hp_independent_mode) { | ||
2030 | struct snd_ctl_elem_id id; | ||
2031 | snd_hda_codec_amp_stereo( | ||
2032 | codec, spec->autocfg.speaker_pins[0], HDA_OUTPUT, 0, | ||
2033 | HDA_AMP_MUTE, hp_present ? HDA_AMP_MUTE : 0); | ||
2034 | /* notify change */ | ||
2035 | memset(&id, 0, sizeof(id)); | ||
2036 | id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
2037 | strcpy(id.name, "Speaker Playback Switch"); | ||
2038 | snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
2039 | &id); | ||
2040 | } | ||
2041 | } | ||
2042 | |||
2043 | /* mute line-out and internal speaker if HP is plugged */ | ||
2044 | static void via_hp_bind_automute(struct hda_codec *codec) | ||
2045 | { | ||
2046 | /* use long instead of int below just to avoid an internal compiler | ||
2047 | * error with gcc 4.0.x | ||
2048 | */ | ||
2049 | unsigned long hp_present, present = 0; | ||
2050 | struct via_spec *spec = codec->spec; | ||
2051 | int i; | ||
2052 | |||
2053 | if (!spec->autocfg.hp_pins[0] || !spec->autocfg.line_out_pins[0]) | ||
2054 | return; | ||
2055 | |||
2056 | hp_present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0, | ||
2057 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
2058 | |||
2059 | present = snd_hda_codec_read(codec, spec->autocfg.line_out_pins[0], 0, | ||
2060 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
2061 | |||
2062 | if (!spec->hp_independent_mode) { | ||
2063 | /* Mute Line-Outs */ | ||
2064 | for (i = 0; i < spec->autocfg.line_outs; i++) | ||
2065 | snd_hda_codec_amp_stereo( | ||
2066 | codec, spec->autocfg.line_out_pins[i], | ||
2067 | HDA_OUTPUT, 0, | ||
2068 | HDA_AMP_MUTE, hp_present ? HDA_AMP_MUTE : 0); | ||
2069 | if (hp_present) | ||
2070 | present = hp_present; | ||
2071 | } | ||
2072 | /* Speakers */ | ||
2073 | for (i = 0; i < spec->autocfg.speaker_outs; i++) | ||
2074 | snd_hda_codec_amp_stereo( | ||
2075 | codec, spec->autocfg.speaker_pins[i], HDA_OUTPUT, 0, | ||
2076 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
2077 | } | ||
2078 | |||
2079 | |||
971 | /* unsolicited event for jack sensing */ | 2080 | /* unsolicited event for jack sensing */ |
972 | static void via_unsol_event(struct hda_codec *codec, | 2081 | static void via_unsol_event(struct hda_codec *codec, |
973 | unsigned int res) | 2082 | unsigned int res) |
974 | { | 2083 | { |
975 | res >>= 26; | 2084 | res >>= 26; |
976 | if (res == VIA_HP_EVENT) | 2085 | if (res & VIA_HP_EVENT) |
977 | via_hp_automute(codec); | 2086 | via_hp_automute(codec); |
978 | else if (res == VIA_GPIO_EVENT) | 2087 | if (res & VIA_GPIO_EVENT) |
979 | via_gpio_control(codec); | 2088 | via_gpio_control(codec); |
2089 | if (res & VIA_JACK_EVENT) | ||
2090 | set_jack_power_state(codec); | ||
2091 | if (res & VIA_MONO_EVENT) | ||
2092 | via_mono_automute(codec); | ||
2093 | if (res & VIA_SPEAKER_EVENT) | ||
2094 | via_speaker_automute(codec); | ||
2095 | if (res & VIA_BIND_HP_EVENT) | ||
2096 | via_hp_bind_automute(codec); | ||
980 | } | 2097 | } |
981 | 2098 | ||
982 | static int via_init(struct hda_codec *codec) | 2099 | static int via_init(struct hda_codec *codec) |
@@ -986,6 +2103,10 @@ static int via_init(struct hda_codec *codec) | |||
986 | for (i = 0; i < spec->num_iverbs; i++) | 2103 | for (i = 0; i < spec->num_iverbs; i++) |
987 | snd_hda_sequence_write(codec, spec->init_verbs[i]); | 2104 | snd_hda_sequence_write(codec, spec->init_verbs[i]); |
988 | 2105 | ||
2106 | spec->codec_type = get_codec_type(codec); | ||
2107 | if (spec->codec_type == VT1708BCE) | ||
2108 | spec->codec_type = VT1708S; /* VT1708BCE & VT1708S are almost | ||
2109 | same */ | ||
989 | /* Lydia Add for EAPD enable */ | 2110 | /* Lydia Add for EAPD enable */ |
990 | if (!spec->dig_in_nid) { /* No Digital In connection */ | 2111 | if (!spec->dig_in_nid) { /* No Digital In connection */ |
991 | if (spec->dig_in_pin) { | 2112 | if (spec->dig_in_pin) { |
@@ -1003,8 +2124,17 @@ static int via_init(struct hda_codec *codec) | |||
1003 | if (spec->slave_dig_outs[0]) | 2124 | if (spec->slave_dig_outs[0]) |
1004 | codec->slave_dig_outs = spec->slave_dig_outs; | 2125 | codec->slave_dig_outs = spec->slave_dig_outs; |
1005 | 2126 | ||
1006 | return 0; | 2127 | return 0; |
2128 | } | ||
2129 | |||
2130 | #ifdef SND_HDA_NEEDS_RESUME | ||
2131 | static int via_suspend(struct hda_codec *codec, pm_message_t state) | ||
2132 | { | ||
2133 | struct via_spec *spec = codec->spec; | ||
2134 | vt1708_stop_hp_work(spec); | ||
2135 | return 0; | ||
1007 | } | 2136 | } |
2137 | #endif | ||
1008 | 2138 | ||
1009 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 2139 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
1010 | static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid) | 2140 | static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid) |
@@ -1021,6 +2151,9 @@ static struct hda_codec_ops via_patch_ops = { | |||
1021 | .build_pcms = via_build_pcms, | 2151 | .build_pcms = via_build_pcms, |
1022 | .init = via_init, | 2152 | .init = via_init, |
1023 | .free = via_free, | 2153 | .free = via_free, |
2154 | #ifdef SND_HDA_NEEDS_RESUME | ||
2155 | .suspend = via_suspend, | ||
2156 | #endif | ||
1024 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 2157 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
1025 | .check_power_status = via_check_power_status, | 2158 | .check_power_status = via_check_power_status, |
1026 | #endif | 2159 | #endif |
@@ -1036,8 +2169,8 @@ static int vt1708_auto_fill_dac_nids(struct via_spec *spec, | |||
1036 | spec->multiout.num_dacs = cfg->line_outs; | 2169 | spec->multiout.num_dacs = cfg->line_outs; |
1037 | 2170 | ||
1038 | spec->multiout.dac_nids = spec->private_dac_nids; | 2171 | spec->multiout.dac_nids = spec->private_dac_nids; |
1039 | 2172 | ||
1040 | for(i = 0; i < 4; i++) { | 2173 | for (i = 0; i < 4; i++) { |
1041 | nid = cfg->line_out_pins[i]; | 2174 | nid = cfg->line_out_pins[i]; |
1042 | if (nid) { | 2175 | if (nid) { |
1043 | /* config dac list */ | 2176 | /* config dac list */ |
@@ -1067,7 +2200,7 @@ static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec, | |||
1067 | { | 2200 | { |
1068 | char name[32]; | 2201 | char name[32]; |
1069 | static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; | 2202 | static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; |
1070 | hda_nid_t nid, nid_vol = 0; | 2203 | hda_nid_t nid, nid_vol, nid_vols[] = {0x17, 0x19, 0x1a, 0x1b}; |
1071 | int i, err; | 2204 | int i, err; |
1072 | 2205 | ||
1073 | for (i = 0; i <= AUTO_SEQ_SIDE; i++) { | 2206 | for (i = 0; i <= AUTO_SEQ_SIDE; i++) { |
@@ -1075,9 +2208,8 @@ static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec, | |||
1075 | 2208 | ||
1076 | if (!nid) | 2209 | if (!nid) |
1077 | continue; | 2210 | continue; |
1078 | 2211 | ||
1079 | if (i != AUTO_SEQ_FRONT) | 2212 | nid_vol = nid_vols[i]; |
1080 | nid_vol = 0x18 + i; | ||
1081 | 2213 | ||
1082 | if (i == AUTO_SEQ_CENLFE) { | 2214 | if (i == AUTO_SEQ_CENLFE) { |
1083 | /* Center/LFE */ | 2215 | /* Center/LFE */ |
@@ -1105,21 +2237,21 @@ static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec, | |||
1105 | HDA_OUTPUT)); | 2237 | HDA_OUTPUT)); |
1106 | if (err < 0) | 2238 | if (err < 0) |
1107 | return err; | 2239 | return err; |
1108 | } else if (i == AUTO_SEQ_FRONT){ | 2240 | } else if (i == AUTO_SEQ_FRONT) { |
1109 | /* add control to mixer index 0 */ | 2241 | /* add control to mixer index 0 */ |
1110 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | 2242 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, |
1111 | "Master Front Playback Volume", | 2243 | "Master Front Playback Volume", |
1112 | HDA_COMPOSE_AMP_VAL(0x17, 3, 0, | 2244 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, |
1113 | HDA_INPUT)); | 2245 | HDA_INPUT)); |
1114 | if (err < 0) | 2246 | if (err < 0) |
1115 | return err; | 2247 | return err; |
1116 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | 2248 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, |
1117 | "Master Front Playback Switch", | 2249 | "Master Front Playback Switch", |
1118 | HDA_COMPOSE_AMP_VAL(0x17, 3, 0, | 2250 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, |
1119 | HDA_INPUT)); | 2251 | HDA_INPUT)); |
1120 | if (err < 0) | 2252 | if (err < 0) |
1121 | return err; | 2253 | return err; |
1122 | 2254 | ||
1123 | /* add control to PW3 */ | 2255 | /* add control to PW3 */ |
1124 | sprintf(name, "%s Playback Volume", chname[i]); | 2256 | sprintf(name, "%s Playback Volume", chname[i]); |
1125 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | 2257 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, |
@@ -1178,6 +2310,7 @@ static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) | |||
1178 | return 0; | 2310 | return 0; |
1179 | 2311 | ||
1180 | spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */ | 2312 | spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */ |
2313 | spec->hp_independent_mode_index = 1; | ||
1181 | 2314 | ||
1182 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | 2315 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, |
1183 | "Headphone Playback Volume", | 2316 | "Headphone Playback Volume", |
@@ -1218,7 +2351,7 @@ static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec, | |||
1218 | case 0x1d: /* Mic */ | 2351 | case 0x1d: /* Mic */ |
1219 | idx = 2; | 2352 | idx = 2; |
1220 | break; | 2353 | break; |
1221 | 2354 | ||
1222 | case 0x1e: /* Line In */ | 2355 | case 0x1e: /* Line In */ |
1223 | idx = 3; | 2356 | idx = 3; |
1224 | break; | 2357 | break; |
@@ -1231,8 +2364,7 @@ static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec, | |||
1231 | idx = 1; | 2364 | idx = 1; |
1232 | break; | 2365 | break; |
1233 | } | 2366 | } |
1234 | err = via_new_analog_input(spec, cfg->input_pins[i], labels[i], | 2367 | err = via_new_analog_input(spec, labels[i], idx, 0x17); |
1235 | idx, 0x17); | ||
1236 | if (err < 0) | 2368 | if (err < 0) |
1237 | return err; | 2369 | return err; |
1238 | imux->items[imux->num_items].label = labels[i]; | 2370 | imux->items[imux->num_items].label = labels[i]; |
@@ -1260,16 +2392,60 @@ static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid) | |||
1260 | def_conf = snd_hda_codec_get_pincfg(codec, nid); | 2392 | def_conf = snd_hda_codec_get_pincfg(codec, nid); |
1261 | seqassoc = (unsigned char) get_defcfg_association(def_conf); | 2393 | seqassoc = (unsigned char) get_defcfg_association(def_conf); |
1262 | seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf); | 2394 | seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf); |
1263 | if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) { | 2395 | if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE |
1264 | if (seqassoc == 0xff) { | 2396 | && (seqassoc == 0xf0 || seqassoc == 0xff)) { |
1265 | def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30)); | 2397 | def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30)); |
1266 | snd_hda_codec_set_pincfg(codec, nid, def_conf); | 2398 | snd_hda_codec_set_pincfg(codec, nid, def_conf); |
1267 | } | ||
1268 | } | 2399 | } |
1269 | 2400 | ||
1270 | return; | 2401 | return; |
1271 | } | 2402 | } |
1272 | 2403 | ||
2404 | static int vt1708_jack_detectect_get(struct snd_kcontrol *kcontrol, | ||
2405 | struct snd_ctl_elem_value *ucontrol) | ||
2406 | { | ||
2407 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2408 | struct via_spec *spec = codec->spec; | ||
2409 | |||
2410 | if (spec->codec_type != VT1708) | ||
2411 | return 0; | ||
2412 | spec->vt1708_jack_detectect = | ||
2413 | !((snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8) & 0x1); | ||
2414 | ucontrol->value.integer.value[0] = spec->vt1708_jack_detectect; | ||
2415 | return 0; | ||
2416 | } | ||
2417 | |||
2418 | static int vt1708_jack_detectect_put(struct snd_kcontrol *kcontrol, | ||
2419 | struct snd_ctl_elem_value *ucontrol) | ||
2420 | { | ||
2421 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2422 | struct via_spec *spec = codec->spec; | ||
2423 | int change; | ||
2424 | |||
2425 | if (spec->codec_type != VT1708) | ||
2426 | return 0; | ||
2427 | spec->vt1708_jack_detectect = ucontrol->value.integer.value[0]; | ||
2428 | change = (0x1 & (snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8)) | ||
2429 | == !spec->vt1708_jack_detectect; | ||
2430 | if (spec->vt1708_jack_detectect) { | ||
2431 | mute_aa_path(codec, 1); | ||
2432 | notify_aa_path_ctls(codec); | ||
2433 | } | ||
2434 | return change; | ||
2435 | } | ||
2436 | |||
2437 | static struct snd_kcontrol_new vt1708_jack_detectect[] = { | ||
2438 | { | ||
2439 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2440 | .name = "Jack Detect", | ||
2441 | .count = 1, | ||
2442 | .info = snd_ctl_boolean_mono_info, | ||
2443 | .get = vt1708_jack_detectect_get, | ||
2444 | .put = vt1708_jack_detectect_put, | ||
2445 | }, | ||
2446 | {} /* end */ | ||
2447 | }; | ||
2448 | |||
1273 | static int vt1708_parse_auto_config(struct hda_codec *codec) | 2449 | static int vt1708_parse_auto_config(struct hda_codec *codec) |
1274 | { | 2450 | { |
1275 | struct via_spec *spec = codec->spec; | 2451 | struct via_spec *spec = codec->spec; |
@@ -1297,6 +2473,10 @@ static int vt1708_parse_auto_config(struct hda_codec *codec) | |||
1297 | err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg); | 2473 | err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg); |
1298 | if (err < 0) | 2474 | if (err < 0) |
1299 | return err; | 2475 | return err; |
2476 | /* add jack detect on/off control */ | ||
2477 | err = snd_hda_add_new_ctls(codec, vt1708_jack_detectect); | ||
2478 | if (err < 0) | ||
2479 | return err; | ||
1300 | 2480 | ||
1301 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | 2481 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; |
1302 | 2482 | ||
@@ -1316,19 +2496,45 @@ static int vt1708_parse_auto_config(struct hda_codec *codec) | |||
1316 | if (spec->hp_mux) | 2496 | if (spec->hp_mux) |
1317 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 2497 | spec->mixers[spec->num_mixers++] = via_hp_mixer; |
1318 | 2498 | ||
2499 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | ||
1319 | return 1; | 2500 | return 1; |
1320 | } | 2501 | } |
1321 | 2502 | ||
1322 | /* init callback for auto-configuration model -- overriding the default init */ | 2503 | /* init callback for auto-configuration model -- overriding the default init */ |
1323 | static int via_auto_init(struct hda_codec *codec) | 2504 | static int via_auto_init(struct hda_codec *codec) |
1324 | { | 2505 | { |
2506 | struct via_spec *spec = codec->spec; | ||
2507 | |||
1325 | via_init(codec); | 2508 | via_init(codec); |
1326 | via_auto_init_multi_out(codec); | 2509 | via_auto_init_multi_out(codec); |
1327 | via_auto_init_hp_out(codec); | 2510 | via_auto_init_hp_out(codec); |
1328 | via_auto_init_analog_input(codec); | 2511 | via_auto_init_analog_input(codec); |
2512 | if (spec->codec_type == VT2002P || spec->codec_type == VT1812) { | ||
2513 | via_hp_bind_automute(codec); | ||
2514 | } else { | ||
2515 | via_hp_automute(codec); | ||
2516 | via_speaker_automute(codec); | ||
2517 | } | ||
2518 | |||
1329 | return 0; | 2519 | return 0; |
1330 | } | 2520 | } |
1331 | 2521 | ||
2522 | static void vt1708_update_hp_jack_state(struct work_struct *work) | ||
2523 | { | ||
2524 | struct via_spec *spec = container_of(work, struct via_spec, | ||
2525 | vt1708_hp_work.work); | ||
2526 | if (spec->codec_type != VT1708) | ||
2527 | return; | ||
2528 | /* if jack state toggled */ | ||
2529 | if (spec->vt1708_hp_present | ||
2530 | != (snd_hda_codec_read(spec->codec, spec->autocfg.hp_pins[0], 0, | ||
2531 | AC_VERB_GET_PIN_SENSE, 0) >> 31)) { | ||
2532 | spec->vt1708_hp_present ^= 1; | ||
2533 | via_hp_automute(spec->codec); | ||
2534 | } | ||
2535 | vt1708_start_hp_work(spec); | ||
2536 | } | ||
2537 | |||
1332 | static int get_mux_nids(struct hda_codec *codec) | 2538 | static int get_mux_nids(struct hda_codec *codec) |
1333 | { | 2539 | { |
1334 | struct via_spec *spec = codec->spec; | 2540 | struct via_spec *spec = codec->spec; |
@@ -1378,7 +2584,7 @@ static int patch_vt1708(struct hda_codec *codec) | |||
1378 | "from BIOS. Using genenic mode...\n"); | 2584 | "from BIOS. Using genenic mode...\n"); |
1379 | } | 2585 | } |
1380 | 2586 | ||
1381 | 2587 | ||
1382 | spec->stream_name_analog = "VT1708 Analog"; | 2588 | spec->stream_name_analog = "VT1708 Analog"; |
1383 | spec->stream_analog_playback = &vt1708_pcm_analog_playback; | 2589 | spec->stream_analog_playback = &vt1708_pcm_analog_playback; |
1384 | /* disable 32bit format on VT1708 */ | 2590 | /* disable 32bit format on VT1708 */ |
@@ -1390,7 +2596,7 @@ static int patch_vt1708(struct hda_codec *codec) | |||
1390 | spec->stream_digital_playback = &vt1708_pcm_digital_playback; | 2596 | spec->stream_digital_playback = &vt1708_pcm_digital_playback; |
1391 | spec->stream_digital_capture = &vt1708_pcm_digital_capture; | 2597 | spec->stream_digital_capture = &vt1708_pcm_digital_capture; |
1392 | 2598 | ||
1393 | 2599 | ||
1394 | if (!spec->adc_nids && spec->input_mux) { | 2600 | if (!spec->adc_nids && spec->input_mux) { |
1395 | spec->adc_nids = vt1708_adc_nids; | 2601 | spec->adc_nids = vt1708_adc_nids; |
1396 | spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids); | 2602 | spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids); |
@@ -1405,7 +2611,8 @@ static int patch_vt1708(struct hda_codec *codec) | |||
1405 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 2611 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
1406 | spec->loopback.amplist = vt1708_loopbacks; | 2612 | spec->loopback.amplist = vt1708_loopbacks; |
1407 | #endif | 2613 | #endif |
1408 | 2614 | spec->codec = codec; | |
2615 | INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state); | ||
1409 | return 0; | 2616 | return 0; |
1410 | } | 2617 | } |
1411 | 2618 | ||
@@ -1433,7 +2640,8 @@ static struct snd_kcontrol_new vt1709_capture_mixer[] = { | |||
1433 | }; | 2640 | }; |
1434 | 2641 | ||
1435 | static struct hda_verb vt1709_uniwill_init_verbs[] = { | 2642 | static struct hda_verb vt1709_uniwill_init_verbs[] = { |
1436 | {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT}, | 2643 | {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, |
2644 | AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, | ||
1437 | { } | 2645 | { } |
1438 | }; | 2646 | }; |
1439 | 2647 | ||
@@ -1473,8 +2681,8 @@ static struct hda_verb vt1709_10ch_volume_init_verbs[] = { | |||
1473 | {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | 2681 | {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, |
1474 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | 2682 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, |
1475 | 2683 | ||
1476 | /* Set input of PW4 as AOW4 */ | 2684 | /* Set input of PW4 as MW0 */ |
1477 | {0x20, AC_VERB_SET_CONNECT_SEL, 0x1}, | 2685 | {0x20, AC_VERB_SET_CONNECT_SEL, 0}, |
1478 | /* PW9 Output enable */ | 2686 | /* PW9 Output enable */ |
1479 | {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | 2687 | {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, |
1480 | { } | 2688 | { } |
@@ -1487,8 +2695,8 @@ static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = { | |||
1487 | .nid = 0x10, /* NID to query formats and rates */ | 2695 | .nid = 0x10, /* NID to query formats and rates */ |
1488 | .ops = { | 2696 | .ops = { |
1489 | .open = via_playback_pcm_open, | 2697 | .open = via_playback_pcm_open, |
1490 | .prepare = via_playback_pcm_prepare, | 2698 | .prepare = via_playback_multi_pcm_prepare, |
1491 | .cleanup = via_playback_pcm_cleanup | 2699 | .cleanup = via_playback_multi_pcm_cleanup, |
1492 | }, | 2700 | }, |
1493 | }; | 2701 | }; |
1494 | 2702 | ||
@@ -1499,8 +2707,8 @@ static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = { | |||
1499 | .nid = 0x10, /* NID to query formats and rates */ | 2707 | .nid = 0x10, /* NID to query formats and rates */ |
1500 | .ops = { | 2708 | .ops = { |
1501 | .open = via_playback_pcm_open, | 2709 | .open = via_playback_pcm_open, |
1502 | .prepare = via_playback_pcm_prepare, | 2710 | .prepare = via_playback_multi_pcm_prepare, |
1503 | .cleanup = via_playback_pcm_cleanup | 2711 | .cleanup = via_playback_multi_pcm_cleanup, |
1504 | }, | 2712 | }, |
1505 | }; | 2713 | }; |
1506 | 2714 | ||
@@ -1575,11 +2783,11 @@ static int vt1709_auto_fill_dac_nids(struct via_spec *spec, | |||
1575 | spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */ | 2783 | spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */ |
1576 | 2784 | ||
1577 | } else if (cfg->line_outs == 3) { /* 6 channels */ | 2785 | } else if (cfg->line_outs == 3) { /* 6 channels */ |
1578 | for(i = 0; i < cfg->line_outs; i++) { | 2786 | for (i = 0; i < cfg->line_outs; i++) { |
1579 | nid = cfg->line_out_pins[i]; | 2787 | nid = cfg->line_out_pins[i]; |
1580 | if (nid) { | 2788 | if (nid) { |
1581 | /* config dac list */ | 2789 | /* config dac list */ |
1582 | switch(i) { | 2790 | switch (i) { |
1583 | case AUTO_SEQ_FRONT: | 2791 | case AUTO_SEQ_FRONT: |
1584 | /* AOW0 */ | 2792 | /* AOW0 */ |
1585 | spec->multiout.dac_nids[i] = 0x10; | 2793 | spec->multiout.dac_nids[i] = 0x10; |
@@ -1608,56 +2816,58 @@ static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec, | |||
1608 | { | 2816 | { |
1609 | char name[32]; | 2817 | char name[32]; |
1610 | static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; | 2818 | static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; |
1611 | hda_nid_t nid = 0; | 2819 | hda_nid_t nid, nid_vol, nid_vols[] = {0x18, 0x1a, 0x1b, 0x29}; |
1612 | int i, err; | 2820 | int i, err; |
1613 | 2821 | ||
1614 | for (i = 0; i <= AUTO_SEQ_SIDE; i++) { | 2822 | for (i = 0; i <= AUTO_SEQ_SIDE; i++) { |
1615 | nid = cfg->line_out_pins[i]; | 2823 | nid = cfg->line_out_pins[i]; |
1616 | 2824 | ||
1617 | if (!nid) | 2825 | if (!nid) |
1618 | continue; | 2826 | continue; |
1619 | 2827 | ||
2828 | nid_vol = nid_vols[i]; | ||
2829 | |||
1620 | if (i == AUTO_SEQ_CENLFE) { | 2830 | if (i == AUTO_SEQ_CENLFE) { |
1621 | /* Center/LFE */ | 2831 | /* Center/LFE */ |
1622 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | 2832 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, |
1623 | "Center Playback Volume", | 2833 | "Center Playback Volume", |
1624 | HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, | 2834 | HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, |
1625 | HDA_OUTPUT)); | 2835 | HDA_OUTPUT)); |
1626 | if (err < 0) | 2836 | if (err < 0) |
1627 | return err; | 2837 | return err; |
1628 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | 2838 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, |
1629 | "LFE Playback Volume", | 2839 | "LFE Playback Volume", |
1630 | HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, | 2840 | HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, |
1631 | HDA_OUTPUT)); | 2841 | HDA_OUTPUT)); |
1632 | if (err < 0) | 2842 | if (err < 0) |
1633 | return err; | 2843 | return err; |
1634 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | 2844 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, |
1635 | "Center Playback Switch", | 2845 | "Center Playback Switch", |
1636 | HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, | 2846 | HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, |
1637 | HDA_OUTPUT)); | 2847 | HDA_OUTPUT)); |
1638 | if (err < 0) | 2848 | if (err < 0) |
1639 | return err; | 2849 | return err; |
1640 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | 2850 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, |
1641 | "LFE Playback Switch", | 2851 | "LFE Playback Switch", |
1642 | HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, | 2852 | HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, |
1643 | HDA_OUTPUT)); | 2853 | HDA_OUTPUT)); |
1644 | if (err < 0) | 2854 | if (err < 0) |
1645 | return err; | 2855 | return err; |
1646 | } else if (i == AUTO_SEQ_FRONT){ | 2856 | } else if (i == AUTO_SEQ_FRONT) { |
1647 | /* add control to mixer index 0 */ | 2857 | /* ADD control to mixer index 0 */ |
1648 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | 2858 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, |
1649 | "Master Front Playback Volume", | 2859 | "Master Front Playback Volume", |
1650 | HDA_COMPOSE_AMP_VAL(0x18, 3, 0, | 2860 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, |
1651 | HDA_INPUT)); | 2861 | HDA_INPUT)); |
1652 | if (err < 0) | 2862 | if (err < 0) |
1653 | return err; | 2863 | return err; |
1654 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | 2864 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, |
1655 | "Master Front Playback Switch", | 2865 | "Master Front Playback Switch", |
1656 | HDA_COMPOSE_AMP_VAL(0x18, 3, 0, | 2866 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, |
1657 | HDA_INPUT)); | 2867 | HDA_INPUT)); |
1658 | if (err < 0) | 2868 | if (err < 0) |
1659 | return err; | 2869 | return err; |
1660 | 2870 | ||
1661 | /* add control to PW3 */ | 2871 | /* add control to PW3 */ |
1662 | sprintf(name, "%s Playback Volume", chname[i]); | 2872 | sprintf(name, "%s Playback Volume", chname[i]); |
1663 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | 2873 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, |
@@ -1674,26 +2884,26 @@ static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec, | |||
1674 | } else if (i == AUTO_SEQ_SURROUND) { | 2884 | } else if (i == AUTO_SEQ_SURROUND) { |
1675 | sprintf(name, "%s Playback Volume", chname[i]); | 2885 | sprintf(name, "%s Playback Volume", chname[i]); |
1676 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | 2886 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, |
1677 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, | 2887 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, |
1678 | HDA_OUTPUT)); | 2888 | HDA_OUTPUT)); |
1679 | if (err < 0) | 2889 | if (err < 0) |
1680 | return err; | 2890 | return err; |
1681 | sprintf(name, "%s Playback Switch", chname[i]); | 2891 | sprintf(name, "%s Playback Switch", chname[i]); |
1682 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | 2892 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, |
1683 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, | 2893 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, |
1684 | HDA_OUTPUT)); | 2894 | HDA_OUTPUT)); |
1685 | if (err < 0) | 2895 | if (err < 0) |
1686 | return err; | 2896 | return err; |
1687 | } else if (i == AUTO_SEQ_SIDE) { | 2897 | } else if (i == AUTO_SEQ_SIDE) { |
1688 | sprintf(name, "%s Playback Volume", chname[i]); | 2898 | sprintf(name, "%s Playback Volume", chname[i]); |
1689 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | 2899 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, |
1690 | HDA_COMPOSE_AMP_VAL(0x29, 3, 0, | 2900 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, |
1691 | HDA_OUTPUT)); | 2901 | HDA_OUTPUT)); |
1692 | if (err < 0) | 2902 | if (err < 0) |
1693 | return err; | 2903 | return err; |
1694 | sprintf(name, "%s Playback Switch", chname[i]); | 2904 | sprintf(name, "%s Playback Switch", chname[i]); |
1695 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | 2905 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, |
1696 | HDA_COMPOSE_AMP_VAL(0x29, 3, 0, | 2906 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, |
1697 | HDA_OUTPUT)); | 2907 | HDA_OUTPUT)); |
1698 | if (err < 0) | 2908 | if (err < 0) |
1699 | return err; | 2909 | return err; |
@@ -1714,6 +2924,7 @@ static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) | |||
1714 | spec->multiout.hp_nid = VT1709_HP_DAC_NID; | 2924 | spec->multiout.hp_nid = VT1709_HP_DAC_NID; |
1715 | else if (spec->multiout.num_dacs == 3) /* 6 channels */ | 2925 | else if (spec->multiout.num_dacs == 3) /* 6 channels */ |
1716 | spec->multiout.hp_nid = 0; | 2926 | spec->multiout.hp_nid = 0; |
2927 | spec->hp_independent_mode_index = 1; | ||
1717 | 2928 | ||
1718 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | 2929 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, |
1719 | "Headphone Playback Volume", | 2930 | "Headphone Playback Volume", |
@@ -1752,7 +2963,7 @@ static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec, | |||
1752 | case 0x1d: /* Mic */ | 2963 | case 0x1d: /* Mic */ |
1753 | idx = 2; | 2964 | idx = 2; |
1754 | break; | 2965 | break; |
1755 | 2966 | ||
1756 | case 0x1e: /* Line In */ | 2967 | case 0x1e: /* Line In */ |
1757 | idx = 3; | 2968 | idx = 3; |
1758 | break; | 2969 | break; |
@@ -1765,8 +2976,7 @@ static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec, | |||
1765 | idx = 1; | 2976 | idx = 1; |
1766 | break; | 2977 | break; |
1767 | } | 2978 | } |
1768 | err = via_new_analog_input(spec, cfg->input_pins[i], labels[i], | 2979 | err = via_new_analog_input(spec, labels[i], idx, 0x18); |
1769 | idx, 0x18); | ||
1770 | if (err < 0) | 2980 | if (err < 0) |
1771 | return err; | 2981 | return err; |
1772 | imux->items[imux->num_items].label = labels[i]; | 2982 | imux->items[imux->num_items].label = labels[i]; |
@@ -1816,6 +3026,7 @@ static int vt1709_parse_auto_config(struct hda_codec *codec) | |||
1816 | if (spec->hp_mux) | 3026 | if (spec->hp_mux) |
1817 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 3027 | spec->mixers[spec->num_mixers++] = via_hp_mixer; |
1818 | 3028 | ||
3029 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | ||
1819 | return 1; | 3030 | return 1; |
1820 | } | 3031 | } |
1821 | 3032 | ||
@@ -1861,7 +3072,7 @@ static int patch_vt1709_10ch(struct hda_codec *codec) | |||
1861 | spec->stream_digital_playback = &vt1709_pcm_digital_playback; | 3072 | spec->stream_digital_playback = &vt1709_pcm_digital_playback; |
1862 | spec->stream_digital_capture = &vt1709_pcm_digital_capture; | 3073 | spec->stream_digital_capture = &vt1709_pcm_digital_capture; |
1863 | 3074 | ||
1864 | 3075 | ||
1865 | if (!spec->adc_nids && spec->input_mux) { | 3076 | if (!spec->adc_nids && spec->input_mux) { |
1866 | spec->adc_nids = vt1709_adc_nids; | 3077 | spec->adc_nids = vt1709_adc_nids; |
1867 | spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids); | 3078 | spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids); |
@@ -1955,7 +3166,7 @@ static int patch_vt1709_6ch(struct hda_codec *codec) | |||
1955 | spec->stream_digital_playback = &vt1709_pcm_digital_playback; | 3166 | spec->stream_digital_playback = &vt1709_pcm_digital_playback; |
1956 | spec->stream_digital_capture = &vt1709_pcm_digital_capture; | 3167 | spec->stream_digital_capture = &vt1709_pcm_digital_capture; |
1957 | 3168 | ||
1958 | 3169 | ||
1959 | if (!spec->adc_nids && spec->input_mux) { | 3170 | if (!spec->adc_nids && spec->input_mux) { |
1960 | spec->adc_nids = vt1709_adc_nids; | 3171 | spec->adc_nids = vt1709_adc_nids; |
1961 | spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids); | 3172 | spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids); |
@@ -2024,7 +3235,7 @@ static struct hda_verb vt1708B_8ch_volume_init_verbs[] = { | |||
2024 | {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | 3235 | {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, |
2025 | 3236 | ||
2026 | /* Setup default input to PW4 */ | 3237 | /* Setup default input to PW4 */ |
2027 | {0x1d, AC_VERB_SET_CONNECT_SEL, 0x1}, | 3238 | {0x1d, AC_VERB_SET_CONNECT_SEL, 0}, |
2028 | /* PW9 Output enable */ | 3239 | /* PW9 Output enable */ |
2029 | {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | 3240 | {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, |
2030 | /* PW10 Input enable */ | 3241 | /* PW10 Input enable */ |
@@ -2068,10 +3279,29 @@ static struct hda_verb vt1708B_4ch_volume_init_verbs[] = { | |||
2068 | }; | 3279 | }; |
2069 | 3280 | ||
2070 | static struct hda_verb vt1708B_uniwill_init_verbs[] = { | 3281 | static struct hda_verb vt1708B_uniwill_init_verbs[] = { |
2071 | {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT}, | 3282 | {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, |
3283 | AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, | ||
3284 | {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
3285 | {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
3286 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
3287 | {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
3288 | {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
3289 | {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
3290 | {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
2072 | { } | 3291 | { } |
2073 | }; | 3292 | }; |
2074 | 3293 | ||
3294 | static int via_pcm_open_close(struct hda_pcm_stream *hinfo, | ||
3295 | struct hda_codec *codec, | ||
3296 | struct snd_pcm_substream *substream) | ||
3297 | { | ||
3298 | int idle = substream->pstr->substream_opened == 1 | ||
3299 | && substream->ref_count == 0; | ||
3300 | |||
3301 | analog_low_current_mode(codec, idle); | ||
3302 | return 0; | ||
3303 | } | ||
3304 | |||
2075 | static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = { | 3305 | static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = { |
2076 | .substreams = 2, | 3306 | .substreams = 2, |
2077 | .channels_min = 2, | 3307 | .channels_min = 2, |
@@ -2080,7 +3310,8 @@ static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = { | |||
2080 | .ops = { | 3310 | .ops = { |
2081 | .open = via_playback_pcm_open, | 3311 | .open = via_playback_pcm_open, |
2082 | .prepare = via_playback_multi_pcm_prepare, | 3312 | .prepare = via_playback_multi_pcm_prepare, |
2083 | .cleanup = via_playback_multi_pcm_cleanup | 3313 | .cleanup = via_playback_multi_pcm_cleanup, |
3314 | .close = via_pcm_open_close | ||
2084 | }, | 3315 | }, |
2085 | }; | 3316 | }; |
2086 | 3317 | ||
@@ -2102,8 +3333,10 @@ static struct hda_pcm_stream vt1708B_pcm_analog_capture = { | |||
2102 | .channels_max = 2, | 3333 | .channels_max = 2, |
2103 | .nid = 0x13, /* NID to query formats and rates */ | 3334 | .nid = 0x13, /* NID to query formats and rates */ |
2104 | .ops = { | 3335 | .ops = { |
3336 | .open = via_pcm_open_close, | ||
2105 | .prepare = via_capture_pcm_prepare, | 3337 | .prepare = via_capture_pcm_prepare, |
2106 | .cleanup = via_capture_pcm_cleanup | 3338 | .cleanup = via_capture_pcm_cleanup, |
3339 | .close = via_pcm_open_close | ||
2107 | }, | 3340 | }, |
2108 | }; | 3341 | }; |
2109 | 3342 | ||
@@ -2260,6 +3493,7 @@ static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) | |||
2260 | return 0; | 3493 | return 0; |
2261 | 3494 | ||
2262 | spec->multiout.hp_nid = VT1708B_HP_NID; /* AOW3 */ | 3495 | spec->multiout.hp_nid = VT1708B_HP_NID; /* AOW3 */ |
3496 | spec->hp_independent_mode_index = 1; | ||
2263 | 3497 | ||
2264 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | 3498 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, |
2265 | "Headphone Playback Volume", | 3499 | "Headphone Playback Volume", |
@@ -2313,8 +3547,7 @@ static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec, | |||
2313 | idx = 1; | 3547 | idx = 1; |
2314 | break; | 3548 | break; |
2315 | } | 3549 | } |
2316 | err = via_new_analog_input(spec, cfg->input_pins[i], labels[i], | 3550 | err = via_new_analog_input(spec, labels[i], idx, 0x16); |
2317 | idx, 0x16); | ||
2318 | if (err < 0) | 3551 | if (err < 0) |
2319 | return err; | 3552 | return err; |
2320 | imux->items[imux->num_items].label = labels[i]; | 3553 | imux->items[imux->num_items].label = labels[i]; |
@@ -2364,6 +3597,7 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec) | |||
2364 | if (spec->hp_mux) | 3597 | if (spec->hp_mux) |
2365 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 3598 | spec->mixers[spec->num_mixers++] = via_hp_mixer; |
2366 | 3599 | ||
3600 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | ||
2367 | return 1; | 3601 | return 1; |
2368 | } | 3602 | } |
2369 | 3603 | ||
@@ -2376,12 +3610,14 @@ static struct hda_amp_list vt1708B_loopbacks[] = { | |||
2376 | { } /* end */ | 3610 | { } /* end */ |
2377 | }; | 3611 | }; |
2378 | #endif | 3612 | #endif |
2379 | 3613 | static int patch_vt1708S(struct hda_codec *codec); | |
2380 | static int patch_vt1708B_8ch(struct hda_codec *codec) | 3614 | static int patch_vt1708B_8ch(struct hda_codec *codec) |
2381 | { | 3615 | { |
2382 | struct via_spec *spec; | 3616 | struct via_spec *spec; |
2383 | int err; | 3617 | int err; |
2384 | 3618 | ||
3619 | if (get_codec_type(codec) == VT1708BCE) | ||
3620 | return patch_vt1708S(codec); | ||
2385 | /* create a codec specific record */ | 3621 | /* create a codec specific record */ |
2386 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 3622 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
2387 | if (spec == NULL) | 3623 | if (spec == NULL) |
@@ -2483,29 +3719,15 @@ static int patch_vt1708B_4ch(struct hda_codec *codec) | |||
2483 | 3719 | ||
2484 | /* Patch for VT1708S */ | 3720 | /* Patch for VT1708S */ |
2485 | 3721 | ||
2486 | /* VT1708S software backdoor based override for buggy hardware micboost | ||
2487 | * setting */ | ||
2488 | #define MIC_BOOST_VOLUME(xname, nid) { \ | ||
2489 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
2490 | .name = xname, \ | ||
2491 | .index = 0, \ | ||
2492 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
2493 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | ||
2494 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \ | ||
2495 | .info = mic_boost_volume_info, \ | ||
2496 | .get = snd_hda_mixer_amp_volume_get, \ | ||
2497 | .put = snd_hda_mixer_amp_volume_put, \ | ||
2498 | .tlv = { .c = mic_boost_tlv }, \ | ||
2499 | .private_value = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT) } | ||
2500 | |||
2501 | /* capture mixer elements */ | 3722 | /* capture mixer elements */ |
2502 | static struct snd_kcontrol_new vt1708S_capture_mixer[] = { | 3723 | static struct snd_kcontrol_new vt1708S_capture_mixer[] = { |
2503 | HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT), | 3724 | HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT), |
2504 | HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT), | 3725 | HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT), |
2505 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT), | 3726 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT), |
2506 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT), | 3727 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT), |
2507 | MIC_BOOST_VOLUME("Mic Boost Capture Volume", 0x1A), | 3728 | HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x1A, 0x0, HDA_INPUT), |
2508 | MIC_BOOST_VOLUME("Front Mic Boost Capture Volume", 0x1E), | 3729 | HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x1E, 0x0, |
3730 | HDA_INPUT), | ||
2509 | { | 3731 | { |
2510 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 3732 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2511 | /* The multiple "Capture Source" controls confuse alsamixer | 3733 | /* The multiple "Capture Source" controls confuse alsamixer |
@@ -2542,11 +3764,21 @@ static struct hda_verb vt1708S_volume_init_verbs[] = { | |||
2542 | {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | 3764 | {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, |
2543 | /* Enable Mic Boost Volume backdoor */ | 3765 | /* Enable Mic Boost Volume backdoor */ |
2544 | {0x1, 0xf98, 0x1}, | 3766 | {0x1, 0xf98, 0x1}, |
3767 | /* don't bybass mixer */ | ||
3768 | {0x1, 0xf88, 0xc0}, | ||
2545 | { } | 3769 | { } |
2546 | }; | 3770 | }; |
2547 | 3771 | ||
2548 | static struct hda_verb vt1708S_uniwill_init_verbs[] = { | 3772 | static struct hda_verb vt1708S_uniwill_init_verbs[] = { |
2549 | {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT}, | 3773 | {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, |
3774 | AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, | ||
3775 | {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
3776 | {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
3777 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
3778 | {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
3779 | {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
3780 | {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
3781 | {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
2550 | { } | 3782 | { } |
2551 | }; | 3783 | }; |
2552 | 3784 | ||
@@ -2557,8 +3789,9 @@ static struct hda_pcm_stream vt1708S_pcm_analog_playback = { | |||
2557 | .nid = 0x10, /* NID to query formats and rates */ | 3789 | .nid = 0x10, /* NID to query formats and rates */ |
2558 | .ops = { | 3790 | .ops = { |
2559 | .open = via_playback_pcm_open, | 3791 | .open = via_playback_pcm_open, |
2560 | .prepare = via_playback_pcm_prepare, | 3792 | .prepare = via_playback_multi_pcm_prepare, |
2561 | .cleanup = via_playback_pcm_cleanup | 3793 | .cleanup = via_playback_multi_pcm_cleanup, |
3794 | .close = via_pcm_open_close | ||
2562 | }, | 3795 | }, |
2563 | }; | 3796 | }; |
2564 | 3797 | ||
@@ -2568,8 +3801,10 @@ static struct hda_pcm_stream vt1708S_pcm_analog_capture = { | |||
2568 | .channels_max = 2, | 3801 | .channels_max = 2, |
2569 | .nid = 0x13, /* NID to query formats and rates */ | 3802 | .nid = 0x13, /* NID to query formats and rates */ |
2570 | .ops = { | 3803 | .ops = { |
3804 | .open = via_pcm_open_close, | ||
2571 | .prepare = via_capture_pcm_prepare, | 3805 | .prepare = via_capture_pcm_prepare, |
2572 | .cleanup = via_capture_pcm_cleanup | 3806 | .cleanup = via_capture_pcm_cleanup, |
3807 | .close = via_pcm_open_close | ||
2573 | }, | 3808 | }, |
2574 | }; | 3809 | }; |
2575 | 3810 | ||
@@ -2726,6 +3961,7 @@ static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) | |||
2726 | return 0; | 3961 | return 0; |
2727 | 3962 | ||
2728 | spec->multiout.hp_nid = VT1708S_HP_NID; /* AOW3 */ | 3963 | spec->multiout.hp_nid = VT1708S_HP_NID; /* AOW3 */ |
3964 | spec->hp_independent_mode_index = 1; | ||
2729 | 3965 | ||
2730 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | 3966 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, |
2731 | "Headphone Playback Volume", | 3967 | "Headphone Playback Volume", |
@@ -2780,8 +4016,7 @@ static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec, | |||
2780 | idx = 1; | 4016 | idx = 1; |
2781 | break; | 4017 | break; |
2782 | } | 4018 | } |
2783 | err = via_new_analog_input(spec, cfg->input_pins[i], labels[i], | 4019 | err = via_new_analog_input(spec, labels[i], idx, 0x16); |
2784 | idx, 0x16); | ||
2785 | if (err < 0) | 4020 | if (err < 0) |
2786 | return err; | 4021 | return err; |
2787 | imux->items[imux->num_items].label = labels[i]; | 4022 | imux->items[imux->num_items].label = labels[i]; |
@@ -2852,6 +4087,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec) | |||
2852 | if (spec->hp_mux) | 4087 | if (spec->hp_mux) |
2853 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 4088 | spec->mixers[spec->num_mixers++] = via_hp_mixer; |
2854 | 4089 | ||
4090 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | ||
2855 | return 1; | 4091 | return 1; |
2856 | } | 4092 | } |
2857 | 4093 | ||
@@ -2865,6 +4101,16 @@ static struct hda_amp_list vt1708S_loopbacks[] = { | |||
2865 | }; | 4101 | }; |
2866 | #endif | 4102 | #endif |
2867 | 4103 | ||
4104 | static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin, | ||
4105 | int offset, int num_steps, int step_size) | ||
4106 | { | ||
4107 | snd_hda_override_amp_caps(codec, pin, HDA_INPUT, | ||
4108 | (offset << AC_AMPCAP_OFFSET_SHIFT) | | ||
4109 | (num_steps << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||
4110 | (step_size << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
4111 | (0 << AC_AMPCAP_MUTE_SHIFT)); | ||
4112 | } | ||
4113 | |||
2868 | static int patch_vt1708S(struct hda_codec *codec) | 4114 | static int patch_vt1708S(struct hda_codec *codec) |
2869 | { | 4115 | { |
2870 | struct via_spec *spec; | 4116 | struct via_spec *spec; |
@@ -2890,17 +4136,25 @@ static int patch_vt1708S(struct hda_codec *codec) | |||
2890 | spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs; | 4136 | spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs; |
2891 | spec->init_verbs[spec->num_iverbs++] = vt1708S_uniwill_init_verbs; | 4137 | spec->init_verbs[spec->num_iverbs++] = vt1708S_uniwill_init_verbs; |
2892 | 4138 | ||
2893 | spec->stream_name_analog = "VT1708S Analog"; | 4139 | if (codec->vendor_id == 0x11060440) |
4140 | spec->stream_name_analog = "VT1818S Analog"; | ||
4141 | else | ||
4142 | spec->stream_name_analog = "VT1708S Analog"; | ||
2894 | spec->stream_analog_playback = &vt1708S_pcm_analog_playback; | 4143 | spec->stream_analog_playback = &vt1708S_pcm_analog_playback; |
2895 | spec->stream_analog_capture = &vt1708S_pcm_analog_capture; | 4144 | spec->stream_analog_capture = &vt1708S_pcm_analog_capture; |
2896 | 4145 | ||
2897 | spec->stream_name_digital = "VT1708S Digital"; | 4146 | if (codec->vendor_id == 0x11060440) |
4147 | spec->stream_name_digital = "VT1818S Digital"; | ||
4148 | else | ||
4149 | spec->stream_name_digital = "VT1708S Digital"; | ||
2898 | spec->stream_digital_playback = &vt1708S_pcm_digital_playback; | 4150 | spec->stream_digital_playback = &vt1708S_pcm_digital_playback; |
2899 | 4151 | ||
2900 | if (!spec->adc_nids && spec->input_mux) { | 4152 | if (!spec->adc_nids && spec->input_mux) { |
2901 | spec->adc_nids = vt1708S_adc_nids; | 4153 | spec->adc_nids = vt1708S_adc_nids; |
2902 | spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids); | 4154 | spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids); |
2903 | get_mux_nids(codec); | 4155 | get_mux_nids(codec); |
4156 | override_mic_boost(codec, 0x1a, 0, 3, 40); | ||
4157 | override_mic_boost(codec, 0x1e, 0, 3, 40); | ||
2904 | spec->mixers[spec->num_mixers] = vt1708S_capture_mixer; | 4158 | spec->mixers[spec->num_mixers] = vt1708S_capture_mixer; |
2905 | spec->num_mixers++; | 4159 | spec->num_mixers++; |
2906 | } | 4160 | } |
@@ -2913,6 +4167,16 @@ static int patch_vt1708S(struct hda_codec *codec) | |||
2913 | spec->loopback.amplist = vt1708S_loopbacks; | 4167 | spec->loopback.amplist = vt1708S_loopbacks; |
2914 | #endif | 4168 | #endif |
2915 | 4169 | ||
4170 | /* correct names for VT1708BCE */ | ||
4171 | if (get_codec_type(codec) == VT1708BCE) { | ||
4172 | kfree(codec->chip_name); | ||
4173 | codec->chip_name = kstrdup("VT1708BCE", GFP_KERNEL); | ||
4174 | snprintf(codec->bus->card->mixername, | ||
4175 | sizeof(codec->bus->card->mixername), | ||
4176 | "%s %s", codec->vendor_name, codec->chip_name); | ||
4177 | spec->stream_name_analog = "VT1708BCE Analog"; | ||
4178 | spec->stream_name_digital = "VT1708BCE Digital"; | ||
4179 | } | ||
2916 | return 0; | 4180 | return 0; |
2917 | } | 4181 | } |
2918 | 4182 | ||
@@ -2967,12 +4231,20 @@ static struct hda_verb vt1702_volume_init_verbs[] = { | |||
2967 | /* PW6 PW7 Output enable */ | 4231 | /* PW6 PW7 Output enable */ |
2968 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | 4232 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, |
2969 | {0x1C, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | 4233 | {0x1C, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, |
4234 | /* mixer enable */ | ||
4235 | {0x1, 0xF88, 0x3}, | ||
4236 | /* GPIO 0~2 */ | ||
4237 | {0x1, 0xF82, 0x3F}, | ||
2970 | { } | 4238 | { } |
2971 | }; | 4239 | }; |
2972 | 4240 | ||
2973 | static struct hda_verb vt1702_uniwill_init_verbs[] = { | 4241 | static struct hda_verb vt1702_uniwill_init_verbs[] = { |
2974 | {0x01, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_GPIO_EVENT}, | 4242 | {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, |
2975 | {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT}, | 4243 | AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, |
4244 | {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
4245 | {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
4246 | {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
4247 | {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
2976 | { } | 4248 | { } |
2977 | }; | 4249 | }; |
2978 | 4250 | ||
@@ -2984,7 +4256,8 @@ static struct hda_pcm_stream vt1702_pcm_analog_playback = { | |||
2984 | .ops = { | 4256 | .ops = { |
2985 | .open = via_playback_pcm_open, | 4257 | .open = via_playback_pcm_open, |
2986 | .prepare = via_playback_multi_pcm_prepare, | 4258 | .prepare = via_playback_multi_pcm_prepare, |
2987 | .cleanup = via_playback_multi_pcm_cleanup | 4259 | .cleanup = via_playback_multi_pcm_cleanup, |
4260 | .close = via_pcm_open_close | ||
2988 | }, | 4261 | }, |
2989 | }; | 4262 | }; |
2990 | 4263 | ||
@@ -2994,8 +4267,10 @@ static struct hda_pcm_stream vt1702_pcm_analog_capture = { | |||
2994 | .channels_max = 2, | 4267 | .channels_max = 2, |
2995 | .nid = 0x12, /* NID to query formats and rates */ | 4268 | .nid = 0x12, /* NID to query formats and rates */ |
2996 | .ops = { | 4269 | .ops = { |
4270 | .open = via_pcm_open_close, | ||
2997 | .prepare = via_capture_pcm_prepare, | 4271 | .prepare = via_capture_pcm_prepare, |
2998 | .cleanup = via_capture_pcm_cleanup | 4272 | .cleanup = via_capture_pcm_cleanup, |
4273 | .close = via_pcm_open_close | ||
2999 | }, | 4274 | }, |
3000 | }; | 4275 | }; |
3001 | 4276 | ||
@@ -3065,12 +4340,13 @@ static int vt1702_auto_create_line_out_ctls(struct via_spec *spec, | |||
3065 | 4340 | ||
3066 | static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) | 4341 | static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) |
3067 | { | 4342 | { |
3068 | int err; | 4343 | int err, i; |
3069 | 4344 | struct hda_input_mux *imux; | |
4345 | static const char *texts[] = { "ON", "OFF", NULL}; | ||
3070 | if (!pin) | 4346 | if (!pin) |
3071 | return 0; | 4347 | return 0; |
3072 | |||
3073 | spec->multiout.hp_nid = 0x1D; | 4348 | spec->multiout.hp_nid = 0x1D; |
4349 | spec->hp_independent_mode_index = 0; | ||
3074 | 4350 | ||
3075 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | 4351 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, |
3076 | "Headphone Playback Volume", | 4352 | "Headphone Playback Volume", |
@@ -3084,8 +4360,18 @@ static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) | |||
3084 | if (err < 0) | 4360 | if (err < 0) |
3085 | return err; | 4361 | return err; |
3086 | 4362 | ||
3087 | create_hp_imux(spec); | 4363 | imux = &spec->private_imux[1]; |
4364 | |||
4365 | /* for hp mode select */ | ||
4366 | i = 0; | ||
4367 | while (texts[i] != NULL) { | ||
4368 | imux->items[imux->num_items].label = texts[i]; | ||
4369 | imux->items[imux->num_items].index = i; | ||
4370 | imux->num_items++; | ||
4371 | i++; | ||
4372 | } | ||
3088 | 4373 | ||
4374 | spec->hp_mux = &spec->private_imux[1]; | ||
3089 | return 0; | 4375 | return 0; |
3090 | } | 4376 | } |
3091 | 4377 | ||
@@ -3121,8 +4407,7 @@ static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec, | |||
3121 | idx = 3; | 4407 | idx = 3; |
3122 | break; | 4408 | break; |
3123 | } | 4409 | } |
3124 | err = via_new_analog_input(spec, cfg->input_pins[i], | 4410 | err = via_new_analog_input(spec, labels[i], idx, 0x1A); |
3125 | labels[i], idx, 0x1A); | ||
3126 | if (err < 0) | 4411 | if (err < 0) |
3127 | return err; | 4412 | return err; |
3128 | imux->items[imux->num_items].label = labels[i]; | 4413 | imux->items[imux->num_items].label = labels[i]; |
@@ -3152,6 +4437,12 @@ static int vt1702_parse_auto_config(struct hda_codec *codec) | |||
3152 | err = vt1702_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); | 4437 | err = vt1702_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); |
3153 | if (err < 0) | 4438 | if (err < 0) |
3154 | return err; | 4439 | return err; |
4440 | /* limit AA path volume to 0 dB */ | ||
4441 | snd_hda_override_amp_caps(codec, 0x1A, HDA_INPUT, | ||
4442 | (0x17 << AC_AMPCAP_OFFSET_SHIFT) | | ||
4443 | (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||
4444 | (0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
4445 | (1 << AC_AMPCAP_MUTE_SHIFT)); | ||
3155 | err = vt1702_auto_create_analog_input_ctls(spec, &spec->autocfg); | 4446 | err = vt1702_auto_create_analog_input_ctls(spec, &spec->autocfg); |
3156 | if (err < 0) | 4447 | if (err < 0) |
3157 | return err; | 4448 | return err; |
@@ -3185,8 +4476,6 @@ static int patch_vt1702(struct hda_codec *codec) | |||
3185 | { | 4476 | { |
3186 | struct via_spec *spec; | 4477 | struct via_spec *spec; |
3187 | int err; | 4478 | int err; |
3188 | unsigned int response; | ||
3189 | unsigned char control; | ||
3190 | 4479 | ||
3191 | /* create a codec specific record */ | 4480 | /* create a codec specific record */ |
3192 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 4481 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
@@ -3231,17 +4520,1638 @@ static int patch_vt1702(struct hda_codec *codec) | |||
3231 | spec->loopback.amplist = vt1702_loopbacks; | 4520 | spec->loopback.amplist = vt1702_loopbacks; |
3232 | #endif | 4521 | #endif |
3233 | 4522 | ||
3234 | /* Open backdoor */ | 4523 | return 0; |
3235 | response = snd_hda_codec_read(codec, codec->afg, 0, 0xF8C, 0); | 4524 | } |
3236 | control = (unsigned char)(response & 0xff); | 4525 | |
3237 | control |= 0x3; | 4526 | /* Patch for VT1718S */ |
3238 | snd_hda_codec_write(codec, codec->afg, 0, 0xF88, control); | ||
3239 | 4527 | ||
3240 | /* Enable GPIO 0&1 for volume&mute control */ | 4528 | /* capture mixer elements */ |
3241 | /* Enable GPIO 2 for DMIC-DATA */ | 4529 | static struct snd_kcontrol_new vt1718S_capture_mixer[] = { |
3242 | response = snd_hda_codec_read(codec, codec->afg, 0, 0xF84, 0); | 4530 | HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT), |
3243 | control = (unsigned char)((response >> 16) & 0x3f); | 4531 | HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT), |
3244 | snd_hda_codec_write(codec, codec->afg, 0, 0xF82, control); | 4532 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT), |
4533 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT), | ||
4534 | HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT), | ||
4535 | HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x29, 0x0, | ||
4536 | HDA_INPUT), | ||
4537 | { | ||
4538 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4539 | /* The multiple "Capture Source" controls confuse alsamixer | ||
4540 | * So call somewhat different.. | ||
4541 | */ | ||
4542 | .name = "Input Source", | ||
4543 | .count = 2, | ||
4544 | .info = via_mux_enum_info, | ||
4545 | .get = via_mux_enum_get, | ||
4546 | .put = via_mux_enum_put, | ||
4547 | }, | ||
4548 | { } /* end */ | ||
4549 | }; | ||
4550 | |||
4551 | static struct hda_verb vt1718S_volume_init_verbs[] = { | ||
4552 | /* | ||
4553 | * Unmute ADC0-1 and set the default input to mic-in | ||
4554 | */ | ||
4555 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4556 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4557 | |||
4558 | |||
4559 | /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | ||
4560 | * mixer widget | ||
4561 | */ | ||
4562 | /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ | ||
4563 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4564 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
4565 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
4566 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
4567 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
4568 | |||
4569 | /* Setup default input of Front HP to MW9 */ | ||
4570 | {0x28, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
4571 | /* PW9 PW10 Output enable */ | ||
4572 | {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN}, | ||
4573 | {0x2e, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN}, | ||
4574 | /* PW11 Input enable */ | ||
4575 | {0x2f, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_IN_EN}, | ||
4576 | /* Enable Boost Volume backdoor */ | ||
4577 | {0x1, 0xf88, 0x8}, | ||
4578 | /* MW0/1/2/3/4: un-mute index 0 (AOWx), mute index 1 (MW9) */ | ||
4579 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4580 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4581 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4582 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4583 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4584 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4585 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
4586 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
4587 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4588 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
4589 | /* set MUX1 = 2 (AOW4), MUX2 = 1 (AOW3) */ | ||
4590 | {0x34, AC_VERB_SET_CONNECT_SEL, 0x2}, | ||
4591 | {0x35, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
4592 | /* Unmute MW4's index 0 */ | ||
4593 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4594 | { } | ||
4595 | }; | ||
4596 | |||
4597 | |||
4598 | static struct hda_verb vt1718S_uniwill_init_verbs[] = { | ||
4599 | {0x28, AC_VERB_SET_UNSOLICITED_ENABLE, | ||
4600 | AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, | ||
4601 | {0x24, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
4602 | {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
4603 | {0x26, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
4604 | {0x27, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
4605 | {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
4606 | {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
4607 | {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
4608 | { } | ||
4609 | }; | ||
4610 | |||
4611 | static struct hda_pcm_stream vt1718S_pcm_analog_playback = { | ||
4612 | .substreams = 2, | ||
4613 | .channels_min = 2, | ||
4614 | .channels_max = 10, | ||
4615 | .nid = 0x8, /* NID to query formats and rates */ | ||
4616 | .ops = { | ||
4617 | .open = via_playback_pcm_open, | ||
4618 | .prepare = via_playback_multi_pcm_prepare, | ||
4619 | .cleanup = via_playback_multi_pcm_cleanup, | ||
4620 | .close = via_pcm_open_close, | ||
4621 | }, | ||
4622 | }; | ||
4623 | |||
4624 | static struct hda_pcm_stream vt1718S_pcm_analog_capture = { | ||
4625 | .substreams = 2, | ||
4626 | .channels_min = 2, | ||
4627 | .channels_max = 2, | ||
4628 | .nid = 0x10, /* NID to query formats and rates */ | ||
4629 | .ops = { | ||
4630 | .open = via_pcm_open_close, | ||
4631 | .prepare = via_capture_pcm_prepare, | ||
4632 | .cleanup = via_capture_pcm_cleanup, | ||
4633 | .close = via_pcm_open_close, | ||
4634 | }, | ||
4635 | }; | ||
4636 | |||
4637 | static struct hda_pcm_stream vt1718S_pcm_digital_playback = { | ||
4638 | .substreams = 2, | ||
4639 | .channels_min = 2, | ||
4640 | .channels_max = 2, | ||
4641 | /* NID is set in via_build_pcms */ | ||
4642 | .ops = { | ||
4643 | .open = via_dig_playback_pcm_open, | ||
4644 | .close = via_dig_playback_pcm_close, | ||
4645 | .prepare = via_dig_playback_pcm_prepare, | ||
4646 | .cleanup = via_dig_playback_pcm_cleanup | ||
4647 | }, | ||
4648 | }; | ||
4649 | |||
4650 | static struct hda_pcm_stream vt1718S_pcm_digital_capture = { | ||
4651 | .substreams = 1, | ||
4652 | .channels_min = 2, | ||
4653 | .channels_max = 2, | ||
4654 | }; | ||
4655 | |||
4656 | /* fill in the dac_nids table from the parsed pin configuration */ | ||
4657 | static int vt1718S_auto_fill_dac_nids(struct via_spec *spec, | ||
4658 | const struct auto_pin_cfg *cfg) | ||
4659 | { | ||
4660 | int i; | ||
4661 | hda_nid_t nid; | ||
4662 | |||
4663 | spec->multiout.num_dacs = cfg->line_outs; | ||
4664 | |||
4665 | spec->multiout.dac_nids = spec->private_dac_nids; | ||
4666 | |||
4667 | for (i = 0; i < 4; i++) { | ||
4668 | nid = cfg->line_out_pins[i]; | ||
4669 | if (nid) { | ||
4670 | /* config dac list */ | ||
4671 | switch (i) { | ||
4672 | case AUTO_SEQ_FRONT: | ||
4673 | spec->multiout.dac_nids[i] = 0x8; | ||
4674 | break; | ||
4675 | case AUTO_SEQ_CENLFE: | ||
4676 | spec->multiout.dac_nids[i] = 0xa; | ||
4677 | break; | ||
4678 | case AUTO_SEQ_SURROUND: | ||
4679 | spec->multiout.dac_nids[i] = 0x9; | ||
4680 | break; | ||
4681 | case AUTO_SEQ_SIDE: | ||
4682 | spec->multiout.dac_nids[i] = 0xb; | ||
4683 | break; | ||
4684 | } | ||
4685 | } | ||
4686 | } | ||
4687 | |||
4688 | return 0; | ||
4689 | } | ||
4690 | |||
4691 | /* add playback controls from the parsed DAC table */ | ||
4692 | static int vt1718S_auto_create_multi_out_ctls(struct via_spec *spec, | ||
4693 | const struct auto_pin_cfg *cfg) | ||
4694 | { | ||
4695 | char name[32]; | ||
4696 | static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; | ||
4697 | hda_nid_t nid_vols[] = {0x8, 0x9, 0xa, 0xb}; | ||
4698 | hda_nid_t nid_mutes[] = {0x24, 0x25, 0x26, 0x27}; | ||
4699 | hda_nid_t nid, nid_vol, nid_mute = 0; | ||
4700 | int i, err; | ||
4701 | |||
4702 | for (i = 0; i <= AUTO_SEQ_SIDE; i++) { | ||
4703 | nid = cfg->line_out_pins[i]; | ||
4704 | |||
4705 | if (!nid) | ||
4706 | continue; | ||
4707 | nid_vol = nid_vols[i]; | ||
4708 | nid_mute = nid_mutes[i]; | ||
4709 | |||
4710 | if (i == AUTO_SEQ_CENLFE) { | ||
4711 | /* Center/LFE */ | ||
4712 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
4713 | "Center Playback Volume", | ||
4714 | HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, | ||
4715 | HDA_OUTPUT)); | ||
4716 | if (err < 0) | ||
4717 | return err; | ||
4718 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
4719 | "LFE Playback Volume", | ||
4720 | HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, | ||
4721 | HDA_OUTPUT)); | ||
4722 | if (err < 0) | ||
4723 | return err; | ||
4724 | err = via_add_control( | ||
4725 | spec, VIA_CTL_WIDGET_MUTE, | ||
4726 | "Center Playback Switch", | ||
4727 | HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0, | ||
4728 | HDA_OUTPUT)); | ||
4729 | if (err < 0) | ||
4730 | return err; | ||
4731 | err = via_add_control( | ||
4732 | spec, VIA_CTL_WIDGET_MUTE, | ||
4733 | "LFE Playback Switch", | ||
4734 | HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0, | ||
4735 | HDA_OUTPUT)); | ||
4736 | if (err < 0) | ||
4737 | return err; | ||
4738 | } else if (i == AUTO_SEQ_FRONT) { | ||
4739 | /* Front */ | ||
4740 | sprintf(name, "%s Playback Volume", chname[i]); | ||
4741 | err = via_add_control( | ||
4742 | spec, VIA_CTL_WIDGET_VOL, name, | ||
4743 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); | ||
4744 | if (err < 0) | ||
4745 | return err; | ||
4746 | sprintf(name, "%s Playback Switch", chname[i]); | ||
4747 | err = via_add_control( | ||
4748 | spec, VIA_CTL_WIDGET_MUTE, name, | ||
4749 | HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0, | ||
4750 | HDA_OUTPUT)); | ||
4751 | if (err < 0) | ||
4752 | return err; | ||
4753 | } else { | ||
4754 | sprintf(name, "%s Playback Volume", chname[i]); | ||
4755 | err = via_add_control( | ||
4756 | spec, VIA_CTL_WIDGET_VOL, name, | ||
4757 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); | ||
4758 | if (err < 0) | ||
4759 | return err; | ||
4760 | sprintf(name, "%s Playback Switch", chname[i]); | ||
4761 | err = via_add_control( | ||
4762 | spec, VIA_CTL_WIDGET_MUTE, name, | ||
4763 | HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0, | ||
4764 | HDA_OUTPUT)); | ||
4765 | if (err < 0) | ||
4766 | return err; | ||
4767 | } | ||
4768 | } | ||
4769 | return 0; | ||
4770 | } | ||
4771 | |||
4772 | static int vt1718S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) | ||
4773 | { | ||
4774 | int err; | ||
4775 | |||
4776 | if (!pin) | ||
4777 | return 0; | ||
4778 | |||
4779 | spec->multiout.hp_nid = 0xc; /* AOW4 */ | ||
4780 | spec->hp_independent_mode_index = 1; | ||
4781 | |||
4782 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
4783 | "Headphone Playback Volume", | ||
4784 | HDA_COMPOSE_AMP_VAL(0xc, 3, 0, HDA_OUTPUT)); | ||
4785 | if (err < 0) | ||
4786 | return err; | ||
4787 | |||
4788 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
4789 | "Headphone Playback Switch", | ||
4790 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); | ||
4791 | if (err < 0) | ||
4792 | return err; | ||
4793 | |||
4794 | create_hp_imux(spec); | ||
4795 | return 0; | ||
4796 | } | ||
4797 | |||
4798 | /* create playback/capture controls for input pins */ | ||
4799 | static int vt1718S_auto_create_analog_input_ctls(struct via_spec *spec, | ||
4800 | const struct auto_pin_cfg *cfg) | ||
4801 | { | ||
4802 | static char *labels[] = { | ||
4803 | "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL | ||
4804 | }; | ||
4805 | struct hda_input_mux *imux = &spec->private_imux[0]; | ||
4806 | int i, err, idx = 0; | ||
4807 | |||
4808 | /* for internal loopback recording select */ | ||
4809 | imux->items[imux->num_items].label = "Stereo Mixer"; | ||
4810 | imux->items[imux->num_items].index = 5; | ||
4811 | imux->num_items++; | ||
4812 | |||
4813 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
4814 | if (!cfg->input_pins[i]) | ||
4815 | continue; | ||
4816 | |||
4817 | switch (cfg->input_pins[i]) { | ||
4818 | case 0x2b: /* Mic */ | ||
4819 | idx = 1; | ||
4820 | break; | ||
4821 | |||
4822 | case 0x2a: /* Line In */ | ||
4823 | idx = 2; | ||
4824 | break; | ||
4825 | |||
4826 | case 0x29: /* Front Mic */ | ||
4827 | idx = 3; | ||
4828 | break; | ||
4829 | |||
4830 | case 0x2c: /* CD */ | ||
4831 | idx = 0; | ||
4832 | break; | ||
4833 | } | ||
4834 | err = via_new_analog_input(spec, labels[i], idx, 0x21); | ||
4835 | if (err < 0) | ||
4836 | return err; | ||
4837 | imux->items[imux->num_items].label = labels[i]; | ||
4838 | imux->items[imux->num_items].index = idx; | ||
4839 | imux->num_items++; | ||
4840 | } | ||
4841 | return 0; | ||
4842 | } | ||
4843 | |||
4844 | static int vt1718S_parse_auto_config(struct hda_codec *codec) | ||
4845 | { | ||
4846 | struct via_spec *spec = codec->spec; | ||
4847 | int err; | ||
4848 | |||
4849 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); | ||
4850 | |||
4851 | if (err < 0) | ||
4852 | return err; | ||
4853 | err = vt1718S_auto_fill_dac_nids(spec, &spec->autocfg); | ||
4854 | if (err < 0) | ||
4855 | return err; | ||
4856 | if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) | ||
4857 | return 0; /* can't find valid BIOS pin config */ | ||
4858 | |||
4859 | err = vt1718S_auto_create_multi_out_ctls(spec, &spec->autocfg); | ||
4860 | if (err < 0) | ||
4861 | return err; | ||
4862 | err = vt1718S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); | ||
4863 | if (err < 0) | ||
4864 | return err; | ||
4865 | err = vt1718S_auto_create_analog_input_ctls(spec, &spec->autocfg); | ||
4866 | if (err < 0) | ||
4867 | return err; | ||
4868 | |||
4869 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | ||
4870 | |||
4871 | fill_dig_outs(codec); | ||
4872 | |||
4873 | if (spec->autocfg.dig_in_pin && codec->vendor_id == 0x11060428) | ||
4874 | spec->dig_in_nid = 0x13; | ||
4875 | |||
4876 | if (spec->kctls.list) | ||
4877 | spec->mixers[spec->num_mixers++] = spec->kctls.list; | ||
4878 | |||
4879 | spec->input_mux = &spec->private_imux[0]; | ||
4880 | |||
4881 | if (spec->hp_mux) | ||
4882 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | ||
4883 | |||
4884 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | ||
4885 | |||
4886 | return 1; | ||
4887 | } | ||
4888 | |||
4889 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
4890 | static struct hda_amp_list vt1718S_loopbacks[] = { | ||
4891 | { 0x21, HDA_INPUT, 1 }, | ||
4892 | { 0x21, HDA_INPUT, 2 }, | ||
4893 | { 0x21, HDA_INPUT, 3 }, | ||
4894 | { 0x21, HDA_INPUT, 4 }, | ||
4895 | { } /* end */ | ||
4896 | }; | ||
4897 | #endif | ||
4898 | |||
4899 | static int patch_vt1718S(struct hda_codec *codec) | ||
4900 | { | ||
4901 | struct via_spec *spec; | ||
4902 | int err; | ||
4903 | |||
4904 | /* create a codec specific record */ | ||
4905 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
4906 | if (spec == NULL) | ||
4907 | return -ENOMEM; | ||
4908 | |||
4909 | codec->spec = spec; | ||
4910 | |||
4911 | /* automatic parse from the BIOS config */ | ||
4912 | err = vt1718S_parse_auto_config(codec); | ||
4913 | if (err < 0) { | ||
4914 | via_free(codec); | ||
4915 | return err; | ||
4916 | } else if (!err) { | ||
4917 | printk(KERN_INFO "hda_codec: Cannot set up configuration " | ||
4918 | "from BIOS. Using genenic mode...\n"); | ||
4919 | } | ||
4920 | |||
4921 | spec->init_verbs[spec->num_iverbs++] = vt1718S_volume_init_verbs; | ||
4922 | spec->init_verbs[spec->num_iverbs++] = vt1718S_uniwill_init_verbs; | ||
4923 | |||
4924 | if (codec->vendor_id == 0x11060441) | ||
4925 | spec->stream_name_analog = "VT2020 Analog"; | ||
4926 | else if (codec->vendor_id == 0x11064441) | ||
4927 | spec->stream_name_analog = "VT1828S Analog"; | ||
4928 | else | ||
4929 | spec->stream_name_analog = "VT1718S Analog"; | ||
4930 | spec->stream_analog_playback = &vt1718S_pcm_analog_playback; | ||
4931 | spec->stream_analog_capture = &vt1718S_pcm_analog_capture; | ||
4932 | |||
4933 | if (codec->vendor_id == 0x11060441) | ||
4934 | spec->stream_name_digital = "VT2020 Digital"; | ||
4935 | else if (codec->vendor_id == 0x11064441) | ||
4936 | spec->stream_name_digital = "VT1828S Digital"; | ||
4937 | else | ||
4938 | spec->stream_name_digital = "VT1718S Digital"; | ||
4939 | spec->stream_digital_playback = &vt1718S_pcm_digital_playback; | ||
4940 | if (codec->vendor_id == 0x11060428 || codec->vendor_id == 0x11060441) | ||
4941 | spec->stream_digital_capture = &vt1718S_pcm_digital_capture; | ||
4942 | |||
4943 | if (!spec->adc_nids && spec->input_mux) { | ||
4944 | spec->adc_nids = vt1718S_adc_nids; | ||
4945 | spec->num_adc_nids = ARRAY_SIZE(vt1718S_adc_nids); | ||
4946 | get_mux_nids(codec); | ||
4947 | override_mic_boost(codec, 0x2b, 0, 3, 40); | ||
4948 | override_mic_boost(codec, 0x29, 0, 3, 40); | ||
4949 | spec->mixers[spec->num_mixers] = vt1718S_capture_mixer; | ||
4950 | spec->num_mixers++; | ||
4951 | } | ||
4952 | |||
4953 | codec->patch_ops = via_patch_ops; | ||
4954 | |||
4955 | codec->patch_ops.init = via_auto_init; | ||
4956 | codec->patch_ops.unsol_event = via_unsol_event; | ||
4957 | |||
4958 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
4959 | spec->loopback.amplist = vt1718S_loopbacks; | ||
4960 | #endif | ||
4961 | |||
4962 | return 0; | ||
4963 | } | ||
4964 | |||
4965 | /* Patch for VT1716S */ | ||
4966 | |||
4967 | static int vt1716s_dmic_info(struct snd_kcontrol *kcontrol, | ||
4968 | struct snd_ctl_elem_info *uinfo) | ||
4969 | { | ||
4970 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
4971 | uinfo->count = 1; | ||
4972 | uinfo->value.integer.min = 0; | ||
4973 | uinfo->value.integer.max = 1; | ||
4974 | return 0; | ||
4975 | } | ||
4976 | |||
4977 | static int vt1716s_dmic_get(struct snd_kcontrol *kcontrol, | ||
4978 | struct snd_ctl_elem_value *ucontrol) | ||
4979 | { | ||
4980 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
4981 | int index = 0; | ||
4982 | |||
4983 | index = snd_hda_codec_read(codec, 0x26, 0, | ||
4984 | AC_VERB_GET_CONNECT_SEL, 0); | ||
4985 | if (index != -1) | ||
4986 | *ucontrol->value.integer.value = index; | ||
4987 | |||
4988 | return 0; | ||
4989 | } | ||
4990 | |||
4991 | static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol, | ||
4992 | struct snd_ctl_elem_value *ucontrol) | ||
4993 | { | ||
4994 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
4995 | struct via_spec *spec = codec->spec; | ||
4996 | int index = *ucontrol->value.integer.value; | ||
4997 | |||
4998 | snd_hda_codec_write(codec, 0x26, 0, | ||
4999 | AC_VERB_SET_CONNECT_SEL, index); | ||
5000 | spec->dmic_enabled = index; | ||
5001 | set_jack_power_state(codec); | ||
5002 | |||
5003 | return 1; | ||
5004 | } | ||
5005 | |||
5006 | /* capture mixer elements */ | ||
5007 | static struct snd_kcontrol_new vt1716S_capture_mixer[] = { | ||
5008 | HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT), | ||
5009 | HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT), | ||
5010 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT), | ||
5011 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT), | ||
5012 | HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x1A, 0x0, HDA_INPUT), | ||
5013 | HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x1E, 0x0, | ||
5014 | HDA_INPUT), | ||
5015 | { | ||
5016 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
5017 | .name = "Input Source", | ||
5018 | .count = 1, | ||
5019 | .info = via_mux_enum_info, | ||
5020 | .get = via_mux_enum_get, | ||
5021 | .put = via_mux_enum_put, | ||
5022 | }, | ||
5023 | { } /* end */ | ||
5024 | }; | ||
5025 | |||
5026 | static struct snd_kcontrol_new vt1716s_dmic_mixer[] = { | ||
5027 | HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT), | ||
5028 | { | ||
5029 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
5030 | .name = "Digital Mic Capture Switch", | ||
5031 | .count = 1, | ||
5032 | .info = vt1716s_dmic_info, | ||
5033 | .get = vt1716s_dmic_get, | ||
5034 | .put = vt1716s_dmic_put, | ||
5035 | }, | ||
5036 | {} /* end */ | ||
5037 | }; | ||
5038 | |||
5039 | |||
5040 | /* mono-out mixer elements */ | ||
5041 | static struct snd_kcontrol_new vt1716S_mono_out_mixer[] = { | ||
5042 | HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT), | ||
5043 | { } /* end */ | ||
5044 | }; | ||
5045 | |||
5046 | static struct hda_verb vt1716S_volume_init_verbs[] = { | ||
5047 | /* | ||
5048 | * Unmute ADC0-1 and set the default input to mic-in | ||
5049 | */ | ||
5050 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5051 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5052 | |||
5053 | |||
5054 | /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | ||
5055 | * mixer widget | ||
5056 | */ | ||
5057 | /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ | ||
5058 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5059 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
5060 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
5061 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
5062 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
5063 | |||
5064 | /* MUX Indices: Stereo Mixer = 5 */ | ||
5065 | {0x17, AC_VERB_SET_CONNECT_SEL, 0x5}, | ||
5066 | |||
5067 | /* Setup default input of PW4 to MW0 */ | ||
5068 | {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
5069 | |||
5070 | /* Setup default input of SW1 as MW0 */ | ||
5071 | {0x18, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
5072 | |||
5073 | /* Setup default input of SW4 as AOW0 */ | ||
5074 | {0x28, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
5075 | |||
5076 | /* PW9 PW10 Output enable */ | ||
5077 | {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
5078 | {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
5079 | |||
5080 | /* Unmute SW1, PW12 */ | ||
5081 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5082 | {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
5083 | /* PW12 Output enable */ | ||
5084 | {0x2a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
5085 | /* Enable Boost Volume backdoor */ | ||
5086 | {0x1, 0xf8a, 0x80}, | ||
5087 | /* don't bybass mixer */ | ||
5088 | {0x1, 0xf88, 0xc0}, | ||
5089 | /* Enable mono output */ | ||
5090 | {0x1, 0xf90, 0x08}, | ||
5091 | { } | ||
5092 | }; | ||
5093 | |||
5094 | |||
5095 | static struct hda_verb vt1716S_uniwill_init_verbs[] = { | ||
5096 | {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, | ||
5097 | AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, | ||
5098 | {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
5099 | {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
5100 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
5101 | {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, | ||
5102 | AC_USRSP_EN | VIA_MONO_EVENT | VIA_JACK_EVENT}, | ||
5103 | {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
5104 | {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
5105 | { } | ||
5106 | }; | ||
5107 | |||
5108 | static struct hda_pcm_stream vt1716S_pcm_analog_playback = { | ||
5109 | .substreams = 2, | ||
5110 | .channels_min = 2, | ||
5111 | .channels_max = 6, | ||
5112 | .nid = 0x10, /* NID to query formats and rates */ | ||
5113 | .ops = { | ||
5114 | .open = via_playback_pcm_open, | ||
5115 | .prepare = via_playback_multi_pcm_prepare, | ||
5116 | .cleanup = via_playback_multi_pcm_cleanup, | ||
5117 | .close = via_pcm_open_close, | ||
5118 | }, | ||
5119 | }; | ||
5120 | |||
5121 | static struct hda_pcm_stream vt1716S_pcm_analog_capture = { | ||
5122 | .substreams = 2, | ||
5123 | .channels_min = 2, | ||
5124 | .channels_max = 2, | ||
5125 | .nid = 0x13, /* NID to query formats and rates */ | ||
5126 | .ops = { | ||
5127 | .open = via_pcm_open_close, | ||
5128 | .prepare = via_capture_pcm_prepare, | ||
5129 | .cleanup = via_capture_pcm_cleanup, | ||
5130 | .close = via_pcm_open_close, | ||
5131 | }, | ||
5132 | }; | ||
5133 | |||
5134 | static struct hda_pcm_stream vt1716S_pcm_digital_playback = { | ||
5135 | .substreams = 2, | ||
5136 | .channels_min = 2, | ||
5137 | .channels_max = 2, | ||
5138 | /* NID is set in via_build_pcms */ | ||
5139 | .ops = { | ||
5140 | .open = via_dig_playback_pcm_open, | ||
5141 | .close = via_dig_playback_pcm_close, | ||
5142 | .prepare = via_dig_playback_pcm_prepare, | ||
5143 | .cleanup = via_dig_playback_pcm_cleanup | ||
5144 | }, | ||
5145 | }; | ||
5146 | |||
5147 | /* fill in the dac_nids table from the parsed pin configuration */ | ||
5148 | static int vt1716S_auto_fill_dac_nids(struct via_spec *spec, | ||
5149 | const struct auto_pin_cfg *cfg) | ||
5150 | { int i; | ||
5151 | hda_nid_t nid; | ||
5152 | |||
5153 | spec->multiout.num_dacs = cfg->line_outs; | ||
5154 | |||
5155 | spec->multiout.dac_nids = spec->private_dac_nids; | ||
5156 | |||
5157 | for (i = 0; i < 3; i++) { | ||
5158 | nid = cfg->line_out_pins[i]; | ||
5159 | if (nid) { | ||
5160 | /* config dac list */ | ||
5161 | switch (i) { | ||
5162 | case AUTO_SEQ_FRONT: | ||
5163 | spec->multiout.dac_nids[i] = 0x10; | ||
5164 | break; | ||
5165 | case AUTO_SEQ_CENLFE: | ||
5166 | spec->multiout.dac_nids[i] = 0x25; | ||
5167 | break; | ||
5168 | case AUTO_SEQ_SURROUND: | ||
5169 | spec->multiout.dac_nids[i] = 0x11; | ||
5170 | break; | ||
5171 | } | ||
5172 | } | ||
5173 | } | ||
5174 | |||
5175 | return 0; | ||
5176 | } | ||
5177 | |||
5178 | /* add playback controls from the parsed DAC table */ | ||
5179 | static int vt1716S_auto_create_multi_out_ctls(struct via_spec *spec, | ||
5180 | const struct auto_pin_cfg *cfg) | ||
5181 | { | ||
5182 | char name[32]; | ||
5183 | static const char *chname[3] = { "Front", "Surround", "C/LFE" }; | ||
5184 | hda_nid_t nid_vols[] = {0x10, 0x11, 0x25}; | ||
5185 | hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x27}; | ||
5186 | hda_nid_t nid, nid_vol, nid_mute; | ||
5187 | int i, err; | ||
5188 | |||
5189 | for (i = 0; i <= AUTO_SEQ_CENLFE; i++) { | ||
5190 | nid = cfg->line_out_pins[i]; | ||
5191 | |||
5192 | if (!nid) | ||
5193 | continue; | ||
5194 | |||
5195 | nid_vol = nid_vols[i]; | ||
5196 | nid_mute = nid_mutes[i]; | ||
5197 | |||
5198 | if (i == AUTO_SEQ_CENLFE) { | ||
5199 | err = via_add_control( | ||
5200 | spec, VIA_CTL_WIDGET_VOL, | ||
5201 | "Center Playback Volume", | ||
5202 | HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT)); | ||
5203 | if (err < 0) | ||
5204 | return err; | ||
5205 | err = via_add_control( | ||
5206 | spec, VIA_CTL_WIDGET_VOL, | ||
5207 | "LFE Playback Volume", | ||
5208 | HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT)); | ||
5209 | if (err < 0) | ||
5210 | return err; | ||
5211 | err = via_add_control( | ||
5212 | spec, VIA_CTL_WIDGET_MUTE, | ||
5213 | "Center Playback Switch", | ||
5214 | HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0, | ||
5215 | HDA_OUTPUT)); | ||
5216 | if (err < 0) | ||
5217 | return err; | ||
5218 | err = via_add_control( | ||
5219 | spec, VIA_CTL_WIDGET_MUTE, | ||
5220 | "LFE Playback Switch", | ||
5221 | HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0, | ||
5222 | HDA_OUTPUT)); | ||
5223 | if (err < 0) | ||
5224 | return err; | ||
5225 | } else if (i == AUTO_SEQ_FRONT) { | ||
5226 | |||
5227 | err = via_add_control( | ||
5228 | spec, VIA_CTL_WIDGET_VOL, | ||
5229 | "Master Front Playback Volume", | ||
5230 | HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT)); | ||
5231 | if (err < 0) | ||
5232 | return err; | ||
5233 | err = via_add_control( | ||
5234 | spec, VIA_CTL_WIDGET_MUTE, | ||
5235 | "Master Front Playback Switch", | ||
5236 | HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT)); | ||
5237 | if (err < 0) | ||
5238 | return err; | ||
5239 | |||
5240 | sprintf(name, "%s Playback Volume", chname[i]); | ||
5241 | err = via_add_control( | ||
5242 | spec, VIA_CTL_WIDGET_VOL, name, | ||
5243 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); | ||
5244 | if (err < 0) | ||
5245 | return err; | ||
5246 | sprintf(name, "%s Playback Switch", chname[i]); | ||
5247 | err = via_add_control( | ||
5248 | spec, VIA_CTL_WIDGET_MUTE, name, | ||
5249 | HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0, | ||
5250 | HDA_OUTPUT)); | ||
5251 | if (err < 0) | ||
5252 | return err; | ||
5253 | } else { | ||
5254 | sprintf(name, "%s Playback Volume", chname[i]); | ||
5255 | err = via_add_control( | ||
5256 | spec, VIA_CTL_WIDGET_VOL, name, | ||
5257 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); | ||
5258 | if (err < 0) | ||
5259 | return err; | ||
5260 | sprintf(name, "%s Playback Switch", chname[i]); | ||
5261 | err = via_add_control( | ||
5262 | spec, VIA_CTL_WIDGET_MUTE, name, | ||
5263 | HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0, | ||
5264 | HDA_OUTPUT)); | ||
5265 | if (err < 0) | ||
5266 | return err; | ||
5267 | } | ||
5268 | } | ||
5269 | return 0; | ||
5270 | } | ||
5271 | |||
5272 | static int vt1716S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) | ||
5273 | { | ||
5274 | int err; | ||
5275 | |||
5276 | if (!pin) | ||
5277 | return 0; | ||
5278 | |||
5279 | spec->multiout.hp_nid = 0x25; /* AOW3 */ | ||
5280 | spec->hp_independent_mode_index = 1; | ||
5281 | |||
5282 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
5283 | "Headphone Playback Volume", | ||
5284 | HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT)); | ||
5285 | if (err < 0) | ||
5286 | return err; | ||
5287 | |||
5288 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
5289 | "Headphone Playback Switch", | ||
5290 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); | ||
5291 | if (err < 0) | ||
5292 | return err; | ||
5293 | |||
5294 | create_hp_imux(spec); | ||
5295 | return 0; | ||
5296 | } | ||
5297 | |||
5298 | /* create playback/capture controls for input pins */ | ||
5299 | static int vt1716S_auto_create_analog_input_ctls(struct via_spec *spec, | ||
5300 | const struct auto_pin_cfg *cfg) | ||
5301 | { | ||
5302 | static char *labels[] = { | ||
5303 | "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL | ||
5304 | }; | ||
5305 | struct hda_input_mux *imux = &spec->private_imux[0]; | ||
5306 | int i, err, idx = 0; | ||
5307 | |||
5308 | /* for internal loopback recording select */ | ||
5309 | imux->items[imux->num_items].label = "Stereo Mixer"; | ||
5310 | imux->items[imux->num_items].index = 5; | ||
5311 | imux->num_items++; | ||
5312 | |||
5313 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
5314 | if (!cfg->input_pins[i]) | ||
5315 | continue; | ||
5316 | |||
5317 | switch (cfg->input_pins[i]) { | ||
5318 | case 0x1a: /* Mic */ | ||
5319 | idx = 2; | ||
5320 | break; | ||
5321 | |||
5322 | case 0x1b: /* Line In */ | ||
5323 | idx = 3; | ||
5324 | break; | ||
5325 | |||
5326 | case 0x1e: /* Front Mic */ | ||
5327 | idx = 4; | ||
5328 | break; | ||
5329 | |||
5330 | case 0x1f: /* CD */ | ||
5331 | idx = 1; | ||
5332 | break; | ||
5333 | } | ||
5334 | err = via_new_analog_input(spec, labels[i], idx, 0x16); | ||
5335 | if (err < 0) | ||
5336 | return err; | ||
5337 | imux->items[imux->num_items].label = labels[i]; | ||
5338 | imux->items[imux->num_items].index = idx-1; | ||
5339 | imux->num_items++; | ||
5340 | } | ||
5341 | return 0; | ||
5342 | } | ||
5343 | |||
5344 | static int vt1716S_parse_auto_config(struct hda_codec *codec) | ||
5345 | { | ||
5346 | struct via_spec *spec = codec->spec; | ||
5347 | int err; | ||
5348 | |||
5349 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); | ||
5350 | if (err < 0) | ||
5351 | return err; | ||
5352 | err = vt1716S_auto_fill_dac_nids(spec, &spec->autocfg); | ||
5353 | if (err < 0) | ||
5354 | return err; | ||
5355 | if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) | ||
5356 | return 0; /* can't find valid BIOS pin config */ | ||
5357 | |||
5358 | err = vt1716S_auto_create_multi_out_ctls(spec, &spec->autocfg); | ||
5359 | if (err < 0) | ||
5360 | return err; | ||
5361 | err = vt1716S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); | ||
5362 | if (err < 0) | ||
5363 | return err; | ||
5364 | err = vt1716S_auto_create_analog_input_ctls(spec, &spec->autocfg); | ||
5365 | if (err < 0) | ||
5366 | return err; | ||
5367 | |||
5368 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | ||
5369 | |||
5370 | fill_dig_outs(codec); | ||
5371 | |||
5372 | if (spec->kctls.list) | ||
5373 | spec->mixers[spec->num_mixers++] = spec->kctls.list; | ||
5374 | |||
5375 | spec->input_mux = &spec->private_imux[0]; | ||
5376 | |||
5377 | if (spec->hp_mux) | ||
5378 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | ||
5379 | |||
5380 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | ||
5381 | |||
5382 | return 1; | ||
5383 | } | ||
5384 | |||
5385 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
5386 | static struct hda_amp_list vt1716S_loopbacks[] = { | ||
5387 | { 0x16, HDA_INPUT, 1 }, | ||
5388 | { 0x16, HDA_INPUT, 2 }, | ||
5389 | { 0x16, HDA_INPUT, 3 }, | ||
5390 | { 0x16, HDA_INPUT, 4 }, | ||
5391 | { } /* end */ | ||
5392 | }; | ||
5393 | #endif | ||
5394 | |||
5395 | static int patch_vt1716S(struct hda_codec *codec) | ||
5396 | { | ||
5397 | struct via_spec *spec; | ||
5398 | int err; | ||
5399 | |||
5400 | /* create a codec specific record */ | ||
5401 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
5402 | if (spec == NULL) | ||
5403 | return -ENOMEM; | ||
5404 | |||
5405 | codec->spec = spec; | ||
5406 | |||
5407 | /* automatic parse from the BIOS config */ | ||
5408 | err = vt1716S_parse_auto_config(codec); | ||
5409 | if (err < 0) { | ||
5410 | via_free(codec); | ||
5411 | return err; | ||
5412 | } else if (!err) { | ||
5413 | printk(KERN_INFO "hda_codec: Cannot set up configuration " | ||
5414 | "from BIOS. Using genenic mode...\n"); | ||
5415 | } | ||
5416 | |||
5417 | spec->init_verbs[spec->num_iverbs++] = vt1716S_volume_init_verbs; | ||
5418 | spec->init_verbs[spec->num_iverbs++] = vt1716S_uniwill_init_verbs; | ||
5419 | |||
5420 | spec->stream_name_analog = "VT1716S Analog"; | ||
5421 | spec->stream_analog_playback = &vt1716S_pcm_analog_playback; | ||
5422 | spec->stream_analog_capture = &vt1716S_pcm_analog_capture; | ||
5423 | |||
5424 | spec->stream_name_digital = "VT1716S Digital"; | ||
5425 | spec->stream_digital_playback = &vt1716S_pcm_digital_playback; | ||
5426 | |||
5427 | if (!spec->adc_nids && spec->input_mux) { | ||
5428 | spec->adc_nids = vt1716S_adc_nids; | ||
5429 | spec->num_adc_nids = ARRAY_SIZE(vt1716S_adc_nids); | ||
5430 | get_mux_nids(codec); | ||
5431 | override_mic_boost(codec, 0x1a, 0, 3, 40); | ||
5432 | override_mic_boost(codec, 0x1e, 0, 3, 40); | ||
5433 | spec->mixers[spec->num_mixers] = vt1716S_capture_mixer; | ||
5434 | spec->num_mixers++; | ||
5435 | } | ||
5436 | |||
5437 | spec->mixers[spec->num_mixers] = vt1716s_dmic_mixer; | ||
5438 | spec->num_mixers++; | ||
5439 | |||
5440 | spec->mixers[spec->num_mixers++] = vt1716S_mono_out_mixer; | ||
5441 | |||
5442 | codec->patch_ops = via_patch_ops; | ||
5443 | |||
5444 | codec->patch_ops.init = via_auto_init; | ||
5445 | codec->patch_ops.unsol_event = via_unsol_event; | ||
5446 | |||
5447 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
5448 | spec->loopback.amplist = vt1716S_loopbacks; | ||
5449 | #endif | ||
5450 | |||
5451 | return 0; | ||
5452 | } | ||
5453 | |||
5454 | /* for vt2002P */ | ||
5455 | |||
5456 | /* capture mixer elements */ | ||
5457 | static struct snd_kcontrol_new vt2002P_capture_mixer[] = { | ||
5458 | HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT), | ||
5459 | HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT), | ||
5460 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT), | ||
5461 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT), | ||
5462 | HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT), | ||
5463 | HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x29, 0x0, | ||
5464 | HDA_INPUT), | ||
5465 | { | ||
5466 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
5467 | /* The multiple "Capture Source" controls confuse alsamixer | ||
5468 | * So call somewhat different.. | ||
5469 | */ | ||
5470 | /* .name = "Capture Source", */ | ||
5471 | .name = "Input Source", | ||
5472 | .count = 2, | ||
5473 | .info = via_mux_enum_info, | ||
5474 | .get = via_mux_enum_get, | ||
5475 | .put = via_mux_enum_put, | ||
5476 | }, | ||
5477 | { } /* end */ | ||
5478 | }; | ||
5479 | |||
5480 | static struct hda_verb vt2002P_volume_init_verbs[] = { | ||
5481 | /* | ||
5482 | * Unmute ADC0-1 and set the default input to mic-in | ||
5483 | */ | ||
5484 | {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5485 | {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5486 | |||
5487 | |||
5488 | /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | ||
5489 | * mixer widget | ||
5490 | */ | ||
5491 | /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ | ||
5492 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5493 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
5494 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
5495 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
5496 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
5497 | |||
5498 | /* MUX Indices: Mic = 0 */ | ||
5499 | {0x1e, AC_VERB_SET_CONNECT_SEL, 0}, | ||
5500 | {0x1f, AC_VERB_SET_CONNECT_SEL, 0}, | ||
5501 | |||
5502 | /* PW9 Output enable */ | ||
5503 | {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN}, | ||
5504 | |||
5505 | /* Enable Boost Volume backdoor */ | ||
5506 | {0x1, 0xfb9, 0x24}, | ||
5507 | |||
5508 | /* MW0/1/4/8: un-mute index 0 (MUXx), un-mute index 1 (MW9) */ | ||
5509 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5510 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5511 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5512 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5513 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5514 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5515 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5516 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5517 | |||
5518 | /* set MUX0/1/4/8 = 0 (AOW0) */ | ||
5519 | {0x34, AC_VERB_SET_CONNECT_SEL, 0}, | ||
5520 | {0x35, AC_VERB_SET_CONNECT_SEL, 0}, | ||
5521 | {0x37, AC_VERB_SET_CONNECT_SEL, 0}, | ||
5522 | {0x3b, AC_VERB_SET_CONNECT_SEL, 0}, | ||
5523 | |||
5524 | /* set PW0 index=0 (MW0) */ | ||
5525 | {0x24, AC_VERB_SET_CONNECT_SEL, 0}, | ||
5526 | |||
5527 | /* Enable AOW0 to MW9 */ | ||
5528 | {0x1, 0xfb8, 0x88}, | ||
5529 | { } | ||
5530 | }; | ||
5531 | |||
5532 | |||
5533 | static struct hda_verb vt2002P_uniwill_init_verbs[] = { | ||
5534 | {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, | ||
5535 | AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, | ||
5536 | {0x26, AC_VERB_SET_UNSOLICITED_ENABLE, | ||
5537 | AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, | ||
5538 | {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
5539 | {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
5540 | {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
5541 | { } | ||
5542 | }; | ||
5543 | |||
5544 | static struct hda_pcm_stream vt2002P_pcm_analog_playback = { | ||
5545 | .substreams = 2, | ||
5546 | .channels_min = 2, | ||
5547 | .channels_max = 2, | ||
5548 | .nid = 0x8, /* NID to query formats and rates */ | ||
5549 | .ops = { | ||
5550 | .open = via_playback_pcm_open, | ||
5551 | .prepare = via_playback_multi_pcm_prepare, | ||
5552 | .cleanup = via_playback_multi_pcm_cleanup, | ||
5553 | .close = via_pcm_open_close, | ||
5554 | }, | ||
5555 | }; | ||
5556 | |||
5557 | static struct hda_pcm_stream vt2002P_pcm_analog_capture = { | ||
5558 | .substreams = 2, | ||
5559 | .channels_min = 2, | ||
5560 | .channels_max = 2, | ||
5561 | .nid = 0x10, /* NID to query formats and rates */ | ||
5562 | .ops = { | ||
5563 | .open = via_pcm_open_close, | ||
5564 | .prepare = via_capture_pcm_prepare, | ||
5565 | .cleanup = via_capture_pcm_cleanup, | ||
5566 | .close = via_pcm_open_close, | ||
5567 | }, | ||
5568 | }; | ||
5569 | |||
5570 | static struct hda_pcm_stream vt2002P_pcm_digital_playback = { | ||
5571 | .substreams = 1, | ||
5572 | .channels_min = 2, | ||
5573 | .channels_max = 2, | ||
5574 | /* NID is set in via_build_pcms */ | ||
5575 | .ops = { | ||
5576 | .open = via_dig_playback_pcm_open, | ||
5577 | .close = via_dig_playback_pcm_close, | ||
5578 | .prepare = via_dig_playback_pcm_prepare, | ||
5579 | .cleanup = via_dig_playback_pcm_cleanup | ||
5580 | }, | ||
5581 | }; | ||
5582 | |||
5583 | /* fill in the dac_nids table from the parsed pin configuration */ | ||
5584 | static int vt2002P_auto_fill_dac_nids(struct via_spec *spec, | ||
5585 | const struct auto_pin_cfg *cfg) | ||
5586 | { | ||
5587 | spec->multiout.num_dacs = 1; | ||
5588 | spec->multiout.dac_nids = spec->private_dac_nids; | ||
5589 | if (cfg->line_out_pins[0]) | ||
5590 | spec->multiout.dac_nids[0] = 0x8; | ||
5591 | return 0; | ||
5592 | } | ||
5593 | |||
5594 | /* add playback controls from the parsed DAC table */ | ||
5595 | static int vt2002P_auto_create_multi_out_ctls(struct via_spec *spec, | ||
5596 | const struct auto_pin_cfg *cfg) | ||
5597 | { | ||
5598 | int err; | ||
5599 | |||
5600 | if (!cfg->line_out_pins[0]) | ||
5601 | return -1; | ||
5602 | |||
5603 | |||
5604 | /* Line-Out: PortE */ | ||
5605 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
5606 | "Master Front Playback Volume", | ||
5607 | HDA_COMPOSE_AMP_VAL(0x8, 3, 0, HDA_OUTPUT)); | ||
5608 | if (err < 0) | ||
5609 | return err; | ||
5610 | err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE, | ||
5611 | "Master Front Playback Switch", | ||
5612 | HDA_COMPOSE_AMP_VAL(0x26, 3, 0, HDA_OUTPUT)); | ||
5613 | if (err < 0) | ||
5614 | return err; | ||
5615 | |||
5616 | return 0; | ||
5617 | } | ||
5618 | |||
5619 | static int vt2002P_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) | ||
5620 | { | ||
5621 | int err; | ||
5622 | |||
5623 | if (!pin) | ||
5624 | return 0; | ||
5625 | |||
5626 | spec->multiout.hp_nid = 0x9; | ||
5627 | spec->hp_independent_mode_index = 1; | ||
5628 | |||
5629 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
5630 | "Headphone Playback Volume", | ||
5631 | HDA_COMPOSE_AMP_VAL( | ||
5632 | spec->multiout.hp_nid, 3, 0, HDA_OUTPUT)); | ||
5633 | if (err < 0) | ||
5634 | return err; | ||
5635 | |||
5636 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
5637 | "Headphone Playback Switch", | ||
5638 | HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT)); | ||
5639 | if (err < 0) | ||
5640 | return err; | ||
5641 | |||
5642 | create_hp_imux(spec); | ||
5643 | return 0; | ||
5644 | } | ||
5645 | |||
5646 | /* create playback/capture controls for input pins */ | ||
5647 | static int vt2002P_auto_create_analog_input_ctls(struct via_spec *spec, | ||
5648 | const struct auto_pin_cfg *cfg) | ||
5649 | { | ||
5650 | static char *labels[] = { | ||
5651 | "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL | ||
5652 | }; | ||
5653 | struct hda_input_mux *imux = &spec->private_imux[0]; | ||
5654 | int i, err, idx = 0; | ||
5655 | |||
5656 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
5657 | if (!cfg->input_pins[i]) | ||
5658 | continue; | ||
5659 | |||
5660 | switch (cfg->input_pins[i]) { | ||
5661 | case 0x2b: /* Mic */ | ||
5662 | idx = 0; | ||
5663 | break; | ||
5664 | |||
5665 | case 0x2a: /* Line In */ | ||
5666 | idx = 1; | ||
5667 | break; | ||
5668 | |||
5669 | case 0x29: /* Front Mic */ | ||
5670 | idx = 2; | ||
5671 | break; | ||
5672 | } | ||
5673 | err = via_new_analog_input(spec, labels[i], idx, 0x21); | ||
5674 | if (err < 0) | ||
5675 | return err; | ||
5676 | imux->items[imux->num_items].label = labels[i]; | ||
5677 | imux->items[imux->num_items].index = idx; | ||
5678 | imux->num_items++; | ||
5679 | } | ||
5680 | |||
5681 | /* build volume/mute control of loopback */ | ||
5682 | err = via_new_analog_input(spec, "Stereo Mixer", 3, 0x21); | ||
5683 | if (err < 0) | ||
5684 | return err; | ||
5685 | |||
5686 | /* for internal loopback recording select */ | ||
5687 | imux->items[imux->num_items].label = "Stereo Mixer"; | ||
5688 | imux->items[imux->num_items].index = 3; | ||
5689 | imux->num_items++; | ||
5690 | |||
5691 | /* for digital mic select */ | ||
5692 | imux->items[imux->num_items].label = "Digital Mic"; | ||
5693 | imux->items[imux->num_items].index = 4; | ||
5694 | imux->num_items++; | ||
5695 | |||
5696 | return 0; | ||
5697 | } | ||
5698 | |||
5699 | static int vt2002P_parse_auto_config(struct hda_codec *codec) | ||
5700 | { | ||
5701 | struct via_spec *spec = codec->spec; | ||
5702 | int err; | ||
5703 | |||
5704 | |||
5705 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); | ||
5706 | if (err < 0) | ||
5707 | return err; | ||
5708 | |||
5709 | err = vt2002P_auto_fill_dac_nids(spec, &spec->autocfg); | ||
5710 | if (err < 0) | ||
5711 | return err; | ||
5712 | |||
5713 | if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) | ||
5714 | return 0; /* can't find valid BIOS pin config */ | ||
5715 | |||
5716 | err = vt2002P_auto_create_multi_out_ctls(spec, &spec->autocfg); | ||
5717 | if (err < 0) | ||
5718 | return err; | ||
5719 | err = vt2002P_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); | ||
5720 | if (err < 0) | ||
5721 | return err; | ||
5722 | err = vt2002P_auto_create_analog_input_ctls(spec, &spec->autocfg); | ||
5723 | if (err < 0) | ||
5724 | return err; | ||
5725 | |||
5726 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | ||
5727 | |||
5728 | fill_dig_outs(codec); | ||
5729 | |||
5730 | if (spec->kctls.list) | ||
5731 | spec->mixers[spec->num_mixers++] = spec->kctls.list; | ||
5732 | |||
5733 | spec->input_mux = &spec->private_imux[0]; | ||
5734 | |||
5735 | if (spec->hp_mux) | ||
5736 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | ||
5737 | |||
5738 | return 1; | ||
5739 | } | ||
5740 | |||
5741 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
5742 | static struct hda_amp_list vt2002P_loopbacks[] = { | ||
5743 | { 0x21, HDA_INPUT, 0 }, | ||
5744 | { 0x21, HDA_INPUT, 1 }, | ||
5745 | { 0x21, HDA_INPUT, 2 }, | ||
5746 | { } /* end */ | ||
5747 | }; | ||
5748 | #endif | ||
5749 | |||
5750 | |||
5751 | /* patch for vt2002P */ | ||
5752 | static int patch_vt2002P(struct hda_codec *codec) | ||
5753 | { | ||
5754 | struct via_spec *spec; | ||
5755 | int err; | ||
5756 | |||
5757 | /* create a codec specific record */ | ||
5758 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
5759 | if (spec == NULL) | ||
5760 | return -ENOMEM; | ||
5761 | |||
5762 | codec->spec = spec; | ||
5763 | |||
5764 | /* automatic parse from the BIOS config */ | ||
5765 | err = vt2002P_parse_auto_config(codec); | ||
5766 | if (err < 0) { | ||
5767 | via_free(codec); | ||
5768 | return err; | ||
5769 | } else if (!err) { | ||
5770 | printk(KERN_INFO "hda_codec: Cannot set up configuration " | ||
5771 | "from BIOS. Using genenic mode...\n"); | ||
5772 | } | ||
5773 | |||
5774 | spec->init_verbs[spec->num_iverbs++] = vt2002P_volume_init_verbs; | ||
5775 | spec->init_verbs[spec->num_iverbs++] = vt2002P_uniwill_init_verbs; | ||
5776 | |||
5777 | spec->stream_name_analog = "VT2002P Analog"; | ||
5778 | spec->stream_analog_playback = &vt2002P_pcm_analog_playback; | ||
5779 | spec->stream_analog_capture = &vt2002P_pcm_analog_capture; | ||
5780 | |||
5781 | spec->stream_name_digital = "VT2002P Digital"; | ||
5782 | spec->stream_digital_playback = &vt2002P_pcm_digital_playback; | ||
5783 | |||
5784 | if (!spec->adc_nids && spec->input_mux) { | ||
5785 | spec->adc_nids = vt2002P_adc_nids; | ||
5786 | spec->num_adc_nids = ARRAY_SIZE(vt2002P_adc_nids); | ||
5787 | get_mux_nids(codec); | ||
5788 | override_mic_boost(codec, 0x2b, 0, 3, 40); | ||
5789 | override_mic_boost(codec, 0x29, 0, 3, 40); | ||
5790 | spec->mixers[spec->num_mixers] = vt2002P_capture_mixer; | ||
5791 | spec->num_mixers++; | ||
5792 | } | ||
5793 | |||
5794 | codec->patch_ops = via_patch_ops; | ||
5795 | |||
5796 | codec->patch_ops.init = via_auto_init; | ||
5797 | codec->patch_ops.unsol_event = via_unsol_event; | ||
5798 | |||
5799 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
5800 | spec->loopback.amplist = vt2002P_loopbacks; | ||
5801 | #endif | ||
5802 | |||
5803 | return 0; | ||
5804 | } | ||
5805 | |||
5806 | /* for vt1812 */ | ||
5807 | |||
5808 | /* capture mixer elements */ | ||
5809 | static struct snd_kcontrol_new vt1812_capture_mixer[] = { | ||
5810 | HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT), | ||
5811 | HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT), | ||
5812 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT), | ||
5813 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT), | ||
5814 | HDA_CODEC_MUTE("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT), | ||
5815 | HDA_CODEC_MUTE("Front Mic Boost Capture Volume", 0x29, 0x0, | ||
5816 | HDA_INPUT), | ||
5817 | { | ||
5818 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
5819 | /* The multiple "Capture Source" controls confuse alsamixer | ||
5820 | * So call somewhat different.. | ||
5821 | */ | ||
5822 | .name = "Input Source", | ||
5823 | .count = 2, | ||
5824 | .info = via_mux_enum_info, | ||
5825 | .get = via_mux_enum_get, | ||
5826 | .put = via_mux_enum_put, | ||
5827 | }, | ||
5828 | { } /* end */ | ||
5829 | }; | ||
5830 | |||
5831 | static struct hda_verb vt1812_volume_init_verbs[] = { | ||
5832 | /* | ||
5833 | * Unmute ADC0-1 and set the default input to mic-in | ||
5834 | */ | ||
5835 | {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5836 | {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5837 | |||
5838 | |||
5839 | /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | ||
5840 | * mixer widget | ||
5841 | */ | ||
5842 | /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ | ||
5843 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5844 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
5845 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
5846 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
5847 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
5848 | |||
5849 | /* MUX Indices: Mic = 0 */ | ||
5850 | {0x1e, AC_VERB_SET_CONNECT_SEL, 0}, | ||
5851 | {0x1f, AC_VERB_SET_CONNECT_SEL, 0}, | ||
5852 | |||
5853 | /* PW9 Output enable */ | ||
5854 | {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN}, | ||
5855 | |||
5856 | /* Enable Boost Volume backdoor */ | ||
5857 | {0x1, 0xfb9, 0x24}, | ||
5858 | |||
5859 | /* MW0/1/4/13/15: un-mute index 0 (MUXx), un-mute index 1 (MW9) */ | ||
5860 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5861 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5862 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5863 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5864 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5865 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5866 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5867 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5868 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5869 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5870 | |||
5871 | /* set MUX0/1/4/13/15 = 0 (AOW0) */ | ||
5872 | {0x34, AC_VERB_SET_CONNECT_SEL, 0}, | ||
5873 | {0x35, AC_VERB_SET_CONNECT_SEL, 0}, | ||
5874 | {0x38, AC_VERB_SET_CONNECT_SEL, 0}, | ||
5875 | {0x3c, AC_VERB_SET_CONNECT_SEL, 0}, | ||
5876 | {0x3d, AC_VERB_SET_CONNECT_SEL, 0}, | ||
5877 | |||
5878 | /* Enable AOW0 to MW9 */ | ||
5879 | {0x1, 0xfb8, 0xa8}, | ||
5880 | { } | ||
5881 | }; | ||
5882 | |||
5883 | |||
5884 | static struct hda_verb vt1812_uniwill_init_verbs[] = { | ||
5885 | {0x33, AC_VERB_SET_UNSOLICITED_ENABLE, | ||
5886 | AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, | ||
5887 | {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT }, | ||
5888 | {0x28, AC_VERB_SET_UNSOLICITED_ENABLE, | ||
5889 | AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, | ||
5890 | {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
5891 | {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
5892 | {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, | ||
5893 | { } | ||
5894 | }; | ||
5895 | |||
5896 | static struct hda_pcm_stream vt1812_pcm_analog_playback = { | ||
5897 | .substreams = 2, | ||
5898 | .channels_min = 2, | ||
5899 | .channels_max = 2, | ||
5900 | .nid = 0x8, /* NID to query formats and rates */ | ||
5901 | .ops = { | ||
5902 | .open = via_playback_pcm_open, | ||
5903 | .prepare = via_playback_multi_pcm_prepare, | ||
5904 | .cleanup = via_playback_multi_pcm_cleanup, | ||
5905 | .close = via_pcm_open_close, | ||
5906 | }, | ||
5907 | }; | ||
5908 | |||
5909 | static struct hda_pcm_stream vt1812_pcm_analog_capture = { | ||
5910 | .substreams = 2, | ||
5911 | .channels_min = 2, | ||
5912 | .channels_max = 2, | ||
5913 | .nid = 0x10, /* NID to query formats and rates */ | ||
5914 | .ops = { | ||
5915 | .open = via_pcm_open_close, | ||
5916 | .prepare = via_capture_pcm_prepare, | ||
5917 | .cleanup = via_capture_pcm_cleanup, | ||
5918 | .close = via_pcm_open_close, | ||
5919 | }, | ||
5920 | }; | ||
5921 | |||
5922 | static struct hda_pcm_stream vt1812_pcm_digital_playback = { | ||
5923 | .substreams = 1, | ||
5924 | .channels_min = 2, | ||
5925 | .channels_max = 2, | ||
5926 | /* NID is set in via_build_pcms */ | ||
5927 | .ops = { | ||
5928 | .open = via_dig_playback_pcm_open, | ||
5929 | .close = via_dig_playback_pcm_close, | ||
5930 | .prepare = via_dig_playback_pcm_prepare, | ||
5931 | .cleanup = via_dig_playback_pcm_cleanup | ||
5932 | }, | ||
5933 | }; | ||
5934 | /* fill in the dac_nids table from the parsed pin configuration */ | ||
5935 | static int vt1812_auto_fill_dac_nids(struct via_spec *spec, | ||
5936 | const struct auto_pin_cfg *cfg) | ||
5937 | { | ||
5938 | spec->multiout.num_dacs = 1; | ||
5939 | spec->multiout.dac_nids = spec->private_dac_nids; | ||
5940 | if (cfg->line_out_pins[0]) | ||
5941 | spec->multiout.dac_nids[0] = 0x8; | ||
5942 | return 0; | ||
5943 | } | ||
5944 | |||
5945 | |||
5946 | /* add playback controls from the parsed DAC table */ | ||
5947 | static int vt1812_auto_create_multi_out_ctls(struct via_spec *spec, | ||
5948 | const struct auto_pin_cfg *cfg) | ||
5949 | { | ||
5950 | int err; | ||
5951 | |||
5952 | if (!cfg->line_out_pins[0]) | ||
5953 | return -1; | ||
5954 | |||
5955 | /* Line-Out: PortE */ | ||
5956 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
5957 | "Master Front Playback Volume", | ||
5958 | HDA_COMPOSE_AMP_VAL(0x8, 3, 0, HDA_OUTPUT)); | ||
5959 | if (err < 0) | ||
5960 | return err; | ||
5961 | err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE, | ||
5962 | "Master Front Playback Switch", | ||
5963 | HDA_COMPOSE_AMP_VAL(0x28, 3, 0, HDA_OUTPUT)); | ||
5964 | if (err < 0) | ||
5965 | return err; | ||
5966 | |||
5967 | return 0; | ||
5968 | } | ||
5969 | |||
5970 | static int vt1812_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) | ||
5971 | { | ||
5972 | int err; | ||
5973 | |||
5974 | if (!pin) | ||
5975 | return 0; | ||
5976 | |||
5977 | spec->multiout.hp_nid = 0x9; | ||
5978 | spec->hp_independent_mode_index = 1; | ||
5979 | |||
5980 | |||
5981 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
5982 | "Headphone Playback Volume", | ||
5983 | HDA_COMPOSE_AMP_VAL( | ||
5984 | spec->multiout.hp_nid, 3, 0, HDA_OUTPUT)); | ||
5985 | if (err < 0) | ||
5986 | return err; | ||
5987 | |||
5988 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
5989 | "Headphone Playback Switch", | ||
5990 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); | ||
5991 | if (err < 0) | ||
5992 | return err; | ||
5993 | |||
5994 | create_hp_imux(spec); | ||
5995 | return 0; | ||
5996 | } | ||
5997 | |||
5998 | /* create playback/capture controls for input pins */ | ||
5999 | static int vt1812_auto_create_analog_input_ctls(struct via_spec *spec, | ||
6000 | const struct auto_pin_cfg *cfg) | ||
6001 | { | ||
6002 | static char *labels[] = { | ||
6003 | "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL | ||
6004 | }; | ||
6005 | struct hda_input_mux *imux = &spec->private_imux[0]; | ||
6006 | int i, err, idx = 0; | ||
6007 | |||
6008 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
6009 | if (!cfg->input_pins[i]) | ||
6010 | continue; | ||
6011 | |||
6012 | switch (cfg->input_pins[i]) { | ||
6013 | case 0x2b: /* Mic */ | ||
6014 | idx = 0; | ||
6015 | break; | ||
6016 | |||
6017 | case 0x2a: /* Line In */ | ||
6018 | idx = 1; | ||
6019 | break; | ||
6020 | |||
6021 | case 0x29: /* Front Mic */ | ||
6022 | idx = 2; | ||
6023 | break; | ||
6024 | } | ||
6025 | err = via_new_analog_input(spec, labels[i], idx, 0x21); | ||
6026 | if (err < 0) | ||
6027 | return err; | ||
6028 | imux->items[imux->num_items].label = labels[i]; | ||
6029 | imux->items[imux->num_items].index = idx; | ||
6030 | imux->num_items++; | ||
6031 | } | ||
6032 | /* build volume/mute control of loopback */ | ||
6033 | err = via_new_analog_input(spec, "Stereo Mixer", 5, 0x21); | ||
6034 | if (err < 0) | ||
6035 | return err; | ||
6036 | |||
6037 | /* for internal loopback recording select */ | ||
6038 | imux->items[imux->num_items].label = "Stereo Mixer"; | ||
6039 | imux->items[imux->num_items].index = 5; | ||
6040 | imux->num_items++; | ||
6041 | |||
6042 | /* for digital mic select */ | ||
6043 | imux->items[imux->num_items].label = "Digital Mic"; | ||
6044 | imux->items[imux->num_items].index = 6; | ||
6045 | imux->num_items++; | ||
6046 | |||
6047 | return 0; | ||
6048 | } | ||
6049 | |||
6050 | static int vt1812_parse_auto_config(struct hda_codec *codec) | ||
6051 | { | ||
6052 | struct via_spec *spec = codec->spec; | ||
6053 | int err; | ||
6054 | |||
6055 | |||
6056 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); | ||
6057 | if (err < 0) | ||
6058 | return err; | ||
6059 | fill_dig_outs(codec); | ||
6060 | err = vt1812_auto_fill_dac_nids(spec, &spec->autocfg); | ||
6061 | if (err < 0) | ||
6062 | return err; | ||
6063 | |||
6064 | if (!spec->autocfg.line_outs && !spec->autocfg.hp_outs) | ||
6065 | return 0; /* can't find valid BIOS pin config */ | ||
6066 | |||
6067 | err = vt1812_auto_create_multi_out_ctls(spec, &spec->autocfg); | ||
6068 | if (err < 0) | ||
6069 | return err; | ||
6070 | err = vt1812_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); | ||
6071 | if (err < 0) | ||
6072 | return err; | ||
6073 | err = vt1812_auto_create_analog_input_ctls(spec, &spec->autocfg); | ||
6074 | if (err < 0) | ||
6075 | return err; | ||
6076 | |||
6077 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | ||
6078 | |||
6079 | fill_dig_outs(codec); | ||
6080 | |||
6081 | if (spec->kctls.list) | ||
6082 | spec->mixers[spec->num_mixers++] = spec->kctls.list; | ||
6083 | |||
6084 | spec->input_mux = &spec->private_imux[0]; | ||
6085 | |||
6086 | if (spec->hp_mux) | ||
6087 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | ||
6088 | |||
6089 | return 1; | ||
6090 | } | ||
6091 | |||
6092 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
6093 | static struct hda_amp_list vt1812_loopbacks[] = { | ||
6094 | { 0x21, HDA_INPUT, 0 }, | ||
6095 | { 0x21, HDA_INPUT, 1 }, | ||
6096 | { 0x21, HDA_INPUT, 2 }, | ||
6097 | { } /* end */ | ||
6098 | }; | ||
6099 | #endif | ||
6100 | |||
6101 | |||
6102 | /* patch for vt1812 */ | ||
6103 | static int patch_vt1812(struct hda_codec *codec) | ||
6104 | { | ||
6105 | struct via_spec *spec; | ||
6106 | int err; | ||
6107 | |||
6108 | /* create a codec specific record */ | ||
6109 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
6110 | if (spec == NULL) | ||
6111 | return -ENOMEM; | ||
6112 | |||
6113 | codec->spec = spec; | ||
6114 | |||
6115 | /* automatic parse from the BIOS config */ | ||
6116 | err = vt1812_parse_auto_config(codec); | ||
6117 | if (err < 0) { | ||
6118 | via_free(codec); | ||
6119 | return err; | ||
6120 | } else if (!err) { | ||
6121 | printk(KERN_INFO "hda_codec: Cannot set up configuration " | ||
6122 | "from BIOS. Using genenic mode...\n"); | ||
6123 | } | ||
6124 | |||
6125 | |||
6126 | spec->init_verbs[spec->num_iverbs++] = vt1812_volume_init_verbs; | ||
6127 | spec->init_verbs[spec->num_iverbs++] = vt1812_uniwill_init_verbs; | ||
6128 | |||
6129 | spec->stream_name_analog = "VT1812 Analog"; | ||
6130 | spec->stream_analog_playback = &vt1812_pcm_analog_playback; | ||
6131 | spec->stream_analog_capture = &vt1812_pcm_analog_capture; | ||
6132 | |||
6133 | spec->stream_name_digital = "VT1812 Digital"; | ||
6134 | spec->stream_digital_playback = &vt1812_pcm_digital_playback; | ||
6135 | |||
6136 | |||
6137 | if (!spec->adc_nids && spec->input_mux) { | ||
6138 | spec->adc_nids = vt1812_adc_nids; | ||
6139 | spec->num_adc_nids = ARRAY_SIZE(vt1812_adc_nids); | ||
6140 | get_mux_nids(codec); | ||
6141 | override_mic_boost(codec, 0x2b, 0, 3, 40); | ||
6142 | override_mic_boost(codec, 0x29, 0, 3, 40); | ||
6143 | spec->mixers[spec->num_mixers] = vt1812_capture_mixer; | ||
6144 | spec->num_mixers++; | ||
6145 | } | ||
6146 | |||
6147 | codec->patch_ops = via_patch_ops; | ||
6148 | |||
6149 | codec->patch_ops.init = via_auto_init; | ||
6150 | codec->patch_ops.unsol_event = via_unsol_event; | ||
6151 | |||
6152 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
6153 | spec->loopback.amplist = vt1812_loopbacks; | ||
6154 | #endif | ||
3245 | 6155 | ||
3246 | return 0; | 6156 | return 0; |
3247 | } | 6157 | } |
@@ -3318,6 +6228,23 @@ static struct hda_codec_preset snd_hda_preset_via[] = { | |||
3318 | .patch = patch_vt1702}, | 6228 | .patch = patch_vt1702}, |
3319 | { .id = 0x11067398, .name = "VT1702", | 6229 | { .id = 0x11067398, .name = "VT1702", |
3320 | .patch = patch_vt1702}, | 6230 | .patch = patch_vt1702}, |
6231 | { .id = 0x11060428, .name = "VT1718S", | ||
6232 | .patch = patch_vt1718S}, | ||
6233 | { .id = 0x11064428, .name = "VT1718S", | ||
6234 | .patch = patch_vt1718S}, | ||
6235 | { .id = 0x11060441, .name = "VT2020", | ||
6236 | .patch = patch_vt1718S}, | ||
6237 | { .id = 0x11064441, .name = "VT1828S", | ||
6238 | .patch = patch_vt1718S}, | ||
6239 | { .id = 0x11060433, .name = "VT1716S", | ||
6240 | .patch = patch_vt1716S}, | ||
6241 | { .id = 0x1106a721, .name = "VT1716S", | ||
6242 | .patch = patch_vt1716S}, | ||
6243 | { .id = 0x11060438, .name = "VT2002P", .patch = patch_vt2002P}, | ||
6244 | { .id = 0x11064438, .name = "VT2002P", .patch = patch_vt2002P}, | ||
6245 | { .id = 0x11060448, .name = "VT1812", .patch = patch_vt1812}, | ||
6246 | { .id = 0x11060440, .name = "VT1818S", | ||
6247 | .patch = patch_vt1708S}, | ||
3321 | {} /* terminator */ | 6248 | {} /* terminator */ |
3322 | }; | 6249 | }; |
3323 | 6250 | ||