diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-04 19:26:56 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-04 19:26:56 -0400 |
commit | 977dbfcf8e9ff1783355b260d93101af315de18a (patch) | |
tree | b586ca678499d1ccc2d199a97d65996c630b25d8 /sound/pci | |
parent | aa7054f5a5a9ff728ce291cb103afa19f4f849eb (diff) | |
parent | b054087dbacee30a9dddaef2c9a96312146be04e (diff) |
Merge tag 'sound-3.12' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai:
"Changes are seen in a wide range of codes, mainly due to ASoC DAPM
requirements; HD-audio shows a high peak in diffstat, it's just a
removal of bunch of old static quirks.
Some highlights:
- HDPM: Updates for AIO/RayDAT support, TCO/sync support
- RME96: Add PCM sync support
- HD-audio:
* A few HDMI/DP audio updates (CA assignment fix, stream switching
fix, Intel DP device list support)
* Device specific fixes (ASUS/CXT HP mic support, Thinkpad mic
improvements, Chromebook fixes, STAC9228 Dell fixes)
* Replace the all static quirks for AD codecs with the generic
parser
* WAKEEN support for handling irqs in the power saving mode
- USB-audio: Clean up implicit fb handling and related codes
- DAPM is now mandatory for ASoC CODEC drivers; all existing drivers
have had some level of DAPM support added. In addition, a lot of
cleanups and improvements in DAPM.
- Support for ASoC cross-platform compile test
- New drivers and support for Analog Devices ADAU1702 and
ADAU1401(a), Asahi Kasei Microdevices AK4554, Atmel AT91ASM9x5 and
WM8904 based machines, Freescale S/PDIF and SSI AC'97, Renesas
R-Car SoCs, Samsung Exynos5420 SoCs, Texas Instruments PCM1681 and
PCM1792A and Wolfson Microelectronics WM8997
- DT bindings for kirkwood and i.MX S/PDIF
- Clean up and bug fixes: ssm2602, rt5640 and sgtl5000.
- Core helpers for bitbanged AC'97 reset"
* tag 'sound-3.12' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (375 commits)
ALSA: hda - Re-setup HDMI pin and audio infoframe on stream switches
ALSA: hda - hdmi: Fallback to ALSA allocation when selecting CA
ASoC: mxs-sgtl5000: Configure the dai_links as unidirectional
ASoC: soc-pcm: Allow to specify unidirectional dai_link
ASoC: fsl_spdif: Staticse non-exported symbols
ASoC: ssm2602: Fix cache sync
ASoC: Remove unused sysfs_registered field from snd_soc_codec struct
ASoC: Remove unused debugfs_dapm field from snd_soc_{platform,codec} struct
ASoC: Remove unused control_type field from snd_soc_codec struct
ASoC: fsl: Add one blank space after ':=' in Makefile
ASoC: fsl: Add wrapping for dev_dbg() in fsl_spdif.c
ASoC: rt5640: change widget sequence for depop
ASoC: dapm: Fix auto-disable for inverted controls
ASoC: fsl: Drop SND_SOC_FSL_UTILS from SND_SOC_IMX_SPDIF
ASoC: Samsung: Do not queue cyclic buffers multiple times
ASoC: ep93xx-i2s: Remove unnecessary dev_set_drvdata()
ASoC: designware_i2s: Remove unnecessary dev_set_drvdata()
ASoC: fsl_spdif: remove redundant dev_err call in fsl_spdif_probe()
ASoC: fsl: Add S/PDIF machine driver
ASoc: kirkwood: Use the Kirkwood audio driver in Dove boards
...
Diffstat (limited to 'sound/pci')
-rw-r--r-- | sound/pci/hda/Kconfig | 9 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.c | 64 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 21 | ||||
-rw-r--r-- | sound/pci/hda/hda_generic.c | 79 | ||||
-rw-r--r-- | sound/pci/hda/hda_generic.h | 1 | ||||
-rw-r--r-- | sound/pci/hda/hda_hwdep.c | 6 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel.c | 34 | ||||
-rw-r--r-- | sound/pci/hda/hda_jack.c | 22 | ||||
-rw-r--r-- | sound/pci/hda/hda_jack.h | 13 | ||||
-rw-r--r-- | sound/pci/hda/hda_proc.c | 33 | ||||
-rw-r--r-- | sound/pci/hda/patch_analog.c | 4528 | ||||
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 79 | ||||
-rw-r--r-- | sound/pci/hda/patch_hdmi.c | 61 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 190 | ||||
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 14 | ||||
-rw-r--r-- | sound/pci/hda/patch_via.c | 2 | ||||
-rw-r--r-- | sound/pci/rme96.c | 307 | ||||
-rw-r--r-- | sound/pci/rme9652/hdspm.c | 779 |
18 files changed, 1506 insertions, 4736 deletions
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 59c5e9c03d53..8de66ccd7279 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig | |||
@@ -152,14 +152,9 @@ config SND_HDA_CODEC_HDMI | |||
152 | This module is automatically loaded at probing. | 152 | This module is automatically loaded at probing. |
153 | 153 | ||
154 | config SND_HDA_I915 | 154 | config SND_HDA_I915 |
155 | bool "Build Display HD-audio controller/codec power well support for i915 cards" | 155 | bool |
156 | default y | ||
156 | depends on DRM_I915 | 157 | depends on DRM_I915 |
157 | help | ||
158 | Say Y here to include full HDMI and DisplayPort HD-audio controller/codec | ||
159 | power-well support for Intel Haswell graphics cards based on the i915 driver. | ||
160 | |||
161 | Note that this option must be enabled for Intel Haswell C+ stepping machines, otherwise | ||
162 | the GPU audio controller/codecs will not be initialized or damaged when exit from S3 mode. | ||
163 | 158 | ||
164 | config SND_HDA_CODEC_CIRRUS | 159 | config SND_HDA_CODEC_CIRRUS |
165 | bool "Build Cirrus Logic codec support" | 160 | bool "Build Cirrus Logic codec support" |
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 8a005f0e5ca4..5b6c4e3c92ca 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -666,6 +666,64 @@ int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux, | |||
666 | } | 666 | } |
667 | EXPORT_SYMBOL_HDA(snd_hda_get_conn_index); | 667 | EXPORT_SYMBOL_HDA(snd_hda_get_conn_index); |
668 | 668 | ||
669 | |||
670 | /* return DEVLIST_LEN parameter of the given widget */ | ||
671 | static unsigned int get_num_devices(struct hda_codec *codec, hda_nid_t nid) | ||
672 | { | ||
673 | unsigned int wcaps = get_wcaps(codec, nid); | ||
674 | unsigned int parm; | ||
675 | |||
676 | if (!codec->dp_mst || !(wcaps & AC_WCAP_DIGITAL) || | ||
677 | get_wcaps_type(wcaps) != AC_WID_PIN) | ||
678 | return 0; | ||
679 | |||
680 | parm = snd_hda_param_read(codec, nid, AC_PAR_DEVLIST_LEN); | ||
681 | if (parm == -1 && codec->bus->rirb_error) | ||
682 | parm = 0; | ||
683 | return parm & AC_DEV_LIST_LEN_MASK; | ||
684 | } | ||
685 | |||
686 | /** | ||
687 | * snd_hda_get_devices - copy device list without cache | ||
688 | * @codec: the HDA codec | ||
689 | * @nid: NID of the pin to parse | ||
690 | * @dev_list: device list array | ||
691 | * @max_devices: max. number of devices to store | ||
692 | * | ||
693 | * Copy the device list. This info is dynamic and so not cached. | ||
694 | * Currently called only from hda_proc.c, so not exported. | ||
695 | */ | ||
696 | int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid, | ||
697 | u8 *dev_list, int max_devices) | ||
698 | { | ||
699 | unsigned int parm; | ||
700 | int i, dev_len, devices; | ||
701 | |||
702 | parm = get_num_devices(codec, nid); | ||
703 | if (!parm) /* not multi-stream capable */ | ||
704 | return 0; | ||
705 | |||
706 | dev_len = parm + 1; | ||
707 | dev_len = dev_len < max_devices ? dev_len : max_devices; | ||
708 | |||
709 | devices = 0; | ||
710 | while (devices < dev_len) { | ||
711 | parm = snd_hda_codec_read(codec, nid, 0, | ||
712 | AC_VERB_GET_DEVICE_LIST, devices); | ||
713 | if (parm == -1 && codec->bus->rirb_error) | ||
714 | break; | ||
715 | |||
716 | for (i = 0; i < 8; i++) { | ||
717 | dev_list[devices] = (u8)parm; | ||
718 | parm >>= 4; | ||
719 | devices++; | ||
720 | if (devices >= dev_len) | ||
721 | break; | ||
722 | } | ||
723 | } | ||
724 | return devices; | ||
725 | } | ||
726 | |||
669 | /** | 727 | /** |
670 | * snd_hda_queue_unsol_event - add an unsolicited event to queue | 728 | * snd_hda_queue_unsol_event - add an unsolicited event to queue |
671 | * @bus: the BUS | 729 | * @bus: the BUS |
@@ -1216,11 +1274,13 @@ static void hda_jackpoll_work(struct work_struct *work) | |||
1216 | { | 1274 | { |
1217 | struct hda_codec *codec = | 1275 | struct hda_codec *codec = |
1218 | container_of(work, struct hda_codec, jackpoll_work.work); | 1276 | container_of(work, struct hda_codec, jackpoll_work.work); |
1219 | if (!codec->jackpoll_interval) | ||
1220 | return; | ||
1221 | 1277 | ||
1222 | snd_hda_jack_set_dirty_all(codec); | 1278 | snd_hda_jack_set_dirty_all(codec); |
1223 | snd_hda_jack_poll_all(codec); | 1279 | snd_hda_jack_poll_all(codec); |
1280 | |||
1281 | if (!codec->jackpoll_interval) | ||
1282 | return; | ||
1283 | |||
1224 | queue_delayed_work(codec->bus->workq, &codec->jackpoll_work, | 1284 | queue_delayed_work(codec->bus->workq, &codec->jackpoll_work, |
1225 | codec->jackpoll_interval); | 1285 | codec->jackpoll_interval); |
1226 | } | 1286 | } |
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 701c2e069b10..7aa9870040c1 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h | |||
@@ -94,6 +94,8 @@ enum { | |||
94 | #define AC_VERB_GET_HDMI_DIP_XMIT 0x0f32 | 94 | #define AC_VERB_GET_HDMI_DIP_XMIT 0x0f32 |
95 | #define AC_VERB_GET_HDMI_CP_CTRL 0x0f33 | 95 | #define AC_VERB_GET_HDMI_CP_CTRL 0x0f33 |
96 | #define AC_VERB_GET_HDMI_CHAN_SLOT 0x0f34 | 96 | #define AC_VERB_GET_HDMI_CHAN_SLOT 0x0f34 |
97 | #define AC_VERB_GET_DEVICE_SEL 0xf35 | ||
98 | #define AC_VERB_GET_DEVICE_LIST 0xf36 | ||
97 | 99 | ||
98 | /* | 100 | /* |
99 | * SET verbs | 101 | * SET verbs |
@@ -133,6 +135,7 @@ enum { | |||
133 | #define AC_VERB_SET_HDMI_DIP_XMIT 0x732 | 135 | #define AC_VERB_SET_HDMI_DIP_XMIT 0x732 |
134 | #define AC_VERB_SET_HDMI_CP_CTRL 0x733 | 136 | #define AC_VERB_SET_HDMI_CP_CTRL 0x733 |
135 | #define AC_VERB_SET_HDMI_CHAN_SLOT 0x734 | 137 | #define AC_VERB_SET_HDMI_CHAN_SLOT 0x734 |
138 | #define AC_VERB_SET_DEVICE_SEL 0x735 | ||
136 | 139 | ||
137 | /* | 140 | /* |
138 | * Parameter IDs | 141 | * Parameter IDs |
@@ -154,6 +157,7 @@ enum { | |||
154 | #define AC_PAR_GPIO_CAP 0x11 | 157 | #define AC_PAR_GPIO_CAP 0x11 |
155 | #define AC_PAR_AMP_OUT_CAP 0x12 | 158 | #define AC_PAR_AMP_OUT_CAP 0x12 |
156 | #define AC_PAR_VOL_KNB_CAP 0x13 | 159 | #define AC_PAR_VOL_KNB_CAP 0x13 |
160 | #define AC_PAR_DEVLIST_LEN 0x15 | ||
157 | #define AC_PAR_HDMI_LPCM_CAP 0x20 | 161 | #define AC_PAR_HDMI_LPCM_CAP 0x20 |
158 | 162 | ||
159 | /* | 163 | /* |
@@ -251,6 +255,11 @@ enum { | |||
251 | #define AC_UNSOL_RES_TAG_SHIFT 26 | 255 | #define AC_UNSOL_RES_TAG_SHIFT 26 |
252 | #define AC_UNSOL_RES_SUBTAG (0x1f<<21) | 256 | #define AC_UNSOL_RES_SUBTAG (0x1f<<21) |
253 | #define AC_UNSOL_RES_SUBTAG_SHIFT 21 | 257 | #define AC_UNSOL_RES_SUBTAG_SHIFT 21 |
258 | #define AC_UNSOL_RES_DE (0x3f<<15) /* Device Entry | ||
259 | * (for DP1.2 MST) | ||
260 | */ | ||
261 | #define AC_UNSOL_RES_DE_SHIFT 15 | ||
262 | #define AC_UNSOL_RES_IA (1<<2) /* Inactive (for DP1.2 MST) */ | ||
254 | #define AC_UNSOL_RES_ELDV (1<<1) /* ELD Data valid (for HDMI) */ | 263 | #define AC_UNSOL_RES_ELDV (1<<1) /* ELD Data valid (for HDMI) */ |
255 | #define AC_UNSOL_RES_PD (1<<0) /* pinsense detect */ | 264 | #define AC_UNSOL_RES_PD (1<<0) /* pinsense detect */ |
256 | #define AC_UNSOL_RES_CP_STATE (1<<1) /* content protection */ | 265 | #define AC_UNSOL_RES_CP_STATE (1<<1) /* content protection */ |
@@ -352,6 +361,10 @@ enum { | |||
352 | #define AC_LPCMCAP_44K (1<<30) /* 44.1kHz support */ | 361 | #define AC_LPCMCAP_44K (1<<30) /* 44.1kHz support */ |
353 | #define AC_LPCMCAP_44K_MS (1<<31) /* 44.1kHz-multiplies support */ | 362 | #define AC_LPCMCAP_44K_MS (1<<31) /* 44.1kHz-multiplies support */ |
354 | 363 | ||
364 | /* Display pin's device list length */ | ||
365 | #define AC_DEV_LIST_LEN_MASK 0x3f | ||
366 | #define AC_MAX_DEV_LIST_LEN 64 | ||
367 | |||
355 | /* | 368 | /* |
356 | * Control Parameters | 369 | * Control Parameters |
357 | */ | 370 | */ |
@@ -460,6 +473,11 @@ enum { | |||
460 | #define AC_DEFCFG_PORT_CONN (0x3<<30) | 473 | #define AC_DEFCFG_PORT_CONN (0x3<<30) |
461 | #define AC_DEFCFG_PORT_CONN_SHIFT 30 | 474 | #define AC_DEFCFG_PORT_CONN_SHIFT 30 |
462 | 475 | ||
476 | /* Display pin's device list entry */ | ||
477 | #define AC_DE_PD (1<<0) | ||
478 | #define AC_DE_ELDV (1<<1) | ||
479 | #define AC_DE_IA (1<<2) | ||
480 | |||
463 | /* device device types (0x0-0xf) */ | 481 | /* device device types (0x0-0xf) */ |
464 | enum { | 482 | enum { |
465 | AC_JACK_LINE_OUT, | 483 | AC_JACK_LINE_OUT, |
@@ -885,6 +903,7 @@ struct hda_codec { | |||
885 | unsigned int pcm_format_first:1; /* PCM format must be set first */ | 903 | unsigned int pcm_format_first:1; /* PCM format must be set first */ |
886 | unsigned int epss:1; /* supporting EPSS? */ | 904 | unsigned int epss:1; /* supporting EPSS? */ |
887 | unsigned int cached_write:1; /* write only to caches */ | 905 | unsigned int cached_write:1; /* write only to caches */ |
906 | unsigned int dp_mst:1; /* support DP1.2 Multi-stream transport */ | ||
888 | #ifdef CONFIG_PM | 907 | #ifdef CONFIG_PM |
889 | unsigned int power_on :1; /* current (global) power-state */ | 908 | unsigned int power_on :1; /* current (global) power-state */ |
890 | unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */ | 909 | unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */ |
@@ -972,6 +991,8 @@ int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums, | |||
972 | const hda_nid_t *list); | 991 | const hda_nid_t *list); |
973 | int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux, | 992 | int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux, |
974 | hda_nid_t nid, int recursive); | 993 | hda_nid_t nid, int recursive); |
994 | int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid, | ||
995 | u8 *dev_list, int max_devices); | ||
975 | int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, | 996 | int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, |
976 | u32 *ratesp, u64 *formatsp, unsigned int *bpsp); | 997 | u32 *ratesp, u64 *formatsp, unsigned int *bpsp); |
977 | 998 | ||
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index e3c7ba8d7582..ac41e9cdc976 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c | |||
@@ -142,6 +142,9 @@ static void parse_user_hints(struct hda_codec *codec) | |||
142 | val = snd_hda_get_bool_hint(codec, "primary_hp"); | 142 | val = snd_hda_get_bool_hint(codec, "primary_hp"); |
143 | if (val >= 0) | 143 | if (val >= 0) |
144 | spec->no_primary_hp = !val; | 144 | spec->no_primary_hp = !val; |
145 | val = snd_hda_get_bool_hint(codec, "multi_io"); | ||
146 | if (val >= 0) | ||
147 | spec->no_multi_io = !val; | ||
145 | val = snd_hda_get_bool_hint(codec, "multi_cap_vol"); | 148 | val = snd_hda_get_bool_hint(codec, "multi_cap_vol"); |
146 | if (val >= 0) | 149 | if (val >= 0) |
147 | spec->multi_cap_vol = !!val; | 150 | spec->multi_cap_vol = !!val; |
@@ -813,6 +816,8 @@ static void resume_path_from_idx(struct hda_codec *codec, int path_idx) | |||
813 | 816 | ||
814 | static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol, | 817 | static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol, |
815 | struct snd_ctl_elem_value *ucontrol); | 818 | struct snd_ctl_elem_value *ucontrol); |
819 | static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol, | ||
820 | struct snd_ctl_elem_value *ucontrol); | ||
816 | 821 | ||
817 | enum { | 822 | enum { |
818 | HDA_CTL_WIDGET_VOL, | 823 | HDA_CTL_WIDGET_VOL, |
@@ -830,7 +835,13 @@ static const struct snd_kcontrol_new control_templates[] = { | |||
830 | .put = hda_gen_mixer_mute_put, /* replaced */ | 835 | .put = hda_gen_mixer_mute_put, /* replaced */ |
831 | .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0), | 836 | .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0), |
832 | }, | 837 | }, |
833 | HDA_BIND_MUTE(NULL, 0, 0, 0), | 838 | { |
839 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
840 | .info = snd_hda_mixer_amp_switch_info, | ||
841 | .get = snd_hda_mixer_bind_switch_get, | ||
842 | .put = hda_gen_bind_mute_put, /* replaced */ | ||
843 | .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0), | ||
844 | }, | ||
834 | }; | 845 | }; |
835 | 846 | ||
836 | /* add dynamic controls from template */ | 847 | /* add dynamic controls from template */ |
@@ -937,8 +948,8 @@ static int add_stereo_sw(struct hda_codec *codec, const char *pfx, | |||
937 | } | 948 | } |
938 | 949 | ||
939 | /* playback mute control with the software mute bit check */ | 950 | /* playback mute control with the software mute bit check */ |
940 | static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol, | 951 | static void sync_auto_mute_bits(struct snd_kcontrol *kcontrol, |
941 | struct snd_ctl_elem_value *ucontrol) | 952 | struct snd_ctl_elem_value *ucontrol) |
942 | { | 953 | { |
943 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 954 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
944 | struct hda_gen_spec *spec = codec->spec; | 955 | struct hda_gen_spec *spec = codec->spec; |
@@ -949,10 +960,22 @@ static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol, | |||
949 | ucontrol->value.integer.value[0] &= enabled; | 960 | ucontrol->value.integer.value[0] &= enabled; |
950 | ucontrol->value.integer.value[1] &= enabled; | 961 | ucontrol->value.integer.value[1] &= enabled; |
951 | } | 962 | } |
963 | } | ||
952 | 964 | ||
965 | static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol, | ||
966 | struct snd_ctl_elem_value *ucontrol) | ||
967 | { | ||
968 | sync_auto_mute_bits(kcontrol, ucontrol); | ||
953 | return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); | 969 | return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); |
954 | } | 970 | } |
955 | 971 | ||
972 | static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol, | ||
973 | struct snd_ctl_elem_value *ucontrol) | ||
974 | { | ||
975 | sync_auto_mute_bits(kcontrol, ucontrol); | ||
976 | return snd_hda_mixer_bind_switch_put(kcontrol, ucontrol); | ||
977 | } | ||
978 | |||
956 | /* any ctl assigned to the path with the given index? */ | 979 | /* any ctl assigned to the path with the given index? */ |
957 | static bool path_has_mixer(struct hda_codec *codec, int path_idx, int ctl_type) | 980 | static bool path_has_mixer(struct hda_codec *codec, int path_idx, int ctl_type) |
958 | { | 981 | { |
@@ -1541,7 +1564,8 @@ static int fill_and_eval_dacs(struct hda_codec *codec, | |||
1541 | cfg->speaker_pins, | 1564 | cfg->speaker_pins, |
1542 | spec->multiout.extra_out_nid, | 1565 | spec->multiout.extra_out_nid, |
1543 | spec->speaker_paths); | 1566 | spec->speaker_paths); |
1544 | if (fill_mio_first && cfg->line_outs == 1 && | 1567 | if (!spec->no_multi_io && |
1568 | fill_mio_first && cfg->line_outs == 1 && | ||
1545 | cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { | 1569 | cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { |
1546 | err = fill_multi_ios(codec, cfg->line_out_pins[0], true); | 1570 | err = fill_multi_ios(codec, cfg->line_out_pins[0], true); |
1547 | if (!err) | 1571 | if (!err) |
@@ -1554,7 +1578,7 @@ static int fill_and_eval_dacs(struct hda_codec *codec, | |||
1554 | spec->private_dac_nids, spec->out_paths, | 1578 | spec->private_dac_nids, spec->out_paths, |
1555 | spec->main_out_badness); | 1579 | spec->main_out_badness); |
1556 | 1580 | ||
1557 | if (fill_mio_first && | 1581 | if (!spec->no_multi_io && fill_mio_first && |
1558 | cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { | 1582 | cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { |
1559 | /* try to fill multi-io first */ | 1583 | /* try to fill multi-io first */ |
1560 | err = fill_multi_ios(codec, cfg->line_out_pins[0], false); | 1584 | err = fill_multi_ios(codec, cfg->line_out_pins[0], false); |
@@ -1582,7 +1606,8 @@ static int fill_and_eval_dacs(struct hda_codec *codec, | |||
1582 | return err; | 1606 | return err; |
1583 | badness += err; | 1607 | badness += err; |
1584 | } | 1608 | } |
1585 | if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { | 1609 | if (!spec->no_multi_io && |
1610 | cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { | ||
1586 | err = fill_multi_ios(codec, cfg->line_out_pins[0], false); | 1611 | err = fill_multi_ios(codec, cfg->line_out_pins[0], false); |
1587 | if (err < 0) | 1612 | if (err < 0) |
1588 | return err; | 1613 | return err; |
@@ -1600,7 +1625,8 @@ static int fill_and_eval_dacs(struct hda_codec *codec, | |||
1600 | check_aamix_out_path(codec, spec->speaker_paths[0]); | 1625 | check_aamix_out_path(codec, spec->speaker_paths[0]); |
1601 | } | 1626 | } |
1602 | 1627 | ||
1603 | if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) | 1628 | if (!spec->no_multi_io && |
1629 | cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) | ||
1604 | if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2) | 1630 | if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2) |
1605 | spec->multi_ios = 1; /* give badness */ | 1631 | spec->multi_ios = 1; /* give badness */ |
1606 | 1632 | ||
@@ -3724,7 +3750,8 @@ static int mux_select(struct hda_codec *codec, unsigned int adc_idx, | |||
3724 | /* check each pin in the given array; returns true if any of them is plugged */ | 3750 | /* check each pin in the given array; returns true if any of them is plugged */ |
3725 | static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) | 3751 | static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) |
3726 | { | 3752 | { |
3727 | int i, present = 0; | 3753 | int i; |
3754 | bool present = false; | ||
3728 | 3755 | ||
3729 | for (i = 0; i < num_pins; i++) { | 3756 | for (i = 0; i < num_pins; i++) { |
3730 | hda_nid_t nid = pins[i]; | 3757 | hda_nid_t nid = pins[i]; |
@@ -3733,14 +3760,15 @@ static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) | |||
3733 | /* don't detect pins retasked as inputs */ | 3760 | /* don't detect pins retasked as inputs */ |
3734 | if (snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_IN_EN) | 3761 | if (snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_IN_EN) |
3735 | continue; | 3762 | continue; |
3736 | present |= snd_hda_jack_detect(codec, nid); | 3763 | if (snd_hda_jack_detect_state(codec, nid) == HDA_JACK_PRESENT) |
3764 | present = true; | ||
3737 | } | 3765 | } |
3738 | return present; | 3766 | return present; |
3739 | } | 3767 | } |
3740 | 3768 | ||
3741 | /* standard HP/line-out auto-mute helper */ | 3769 | /* standard HP/line-out auto-mute helper */ |
3742 | static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, | 3770 | static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, |
3743 | bool mute) | 3771 | int *paths, bool mute) |
3744 | { | 3772 | { |
3745 | struct hda_gen_spec *spec = codec->spec; | 3773 | struct hda_gen_spec *spec = codec->spec; |
3746 | int i; | 3774 | int i; |
@@ -3752,10 +3780,19 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, | |||
3752 | break; | 3780 | break; |
3753 | 3781 | ||
3754 | if (spec->auto_mute_via_amp) { | 3782 | if (spec->auto_mute_via_amp) { |
3783 | struct nid_path *path; | ||
3784 | hda_nid_t mute_nid; | ||
3785 | |||
3786 | path = snd_hda_get_path_from_idx(codec, paths[i]); | ||
3787 | if (!path) | ||
3788 | continue; | ||
3789 | mute_nid = get_amp_nid_(path->ctls[NID_PATH_MUTE_CTL]); | ||
3790 | if (!mute_nid) | ||
3791 | continue; | ||
3755 | if (mute) | 3792 | if (mute) |
3756 | spec->mute_bits |= (1ULL << nid); | 3793 | spec->mute_bits |= (1ULL << mute_nid); |
3757 | else | 3794 | else |
3758 | spec->mute_bits &= ~(1ULL << nid); | 3795 | spec->mute_bits &= ~(1ULL << mute_nid); |
3759 | set_pin_eapd(codec, nid, !mute); | 3796 | set_pin_eapd(codec, nid, !mute); |
3760 | continue; | 3797 | continue; |
3761 | } | 3798 | } |
@@ -3786,14 +3823,19 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, | |||
3786 | void snd_hda_gen_update_outputs(struct hda_codec *codec) | 3823 | void snd_hda_gen_update_outputs(struct hda_codec *codec) |
3787 | { | 3824 | { |
3788 | struct hda_gen_spec *spec = codec->spec; | 3825 | struct hda_gen_spec *spec = codec->spec; |
3826 | int *paths; | ||
3789 | int on; | 3827 | int on; |
3790 | 3828 | ||
3791 | /* Control HP pins/amps depending on master_mute state; | 3829 | /* Control HP pins/amps depending on master_mute state; |
3792 | * in general, HP pins/amps control should be enabled in all cases, | 3830 | * in general, HP pins/amps control should be enabled in all cases, |
3793 | * but currently set only for master_mute, just to be safe | 3831 | * but currently set only for master_mute, just to be safe |
3794 | */ | 3832 | */ |
3833 | if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT) | ||
3834 | paths = spec->out_paths; | ||
3835 | else | ||
3836 | paths = spec->hp_paths; | ||
3795 | do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), | 3837 | do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), |
3796 | spec->autocfg.hp_pins, spec->master_mute); | 3838 | spec->autocfg.hp_pins, paths, spec->master_mute); |
3797 | 3839 | ||
3798 | if (!spec->automute_speaker) | 3840 | if (!spec->automute_speaker) |
3799 | on = 0; | 3841 | on = 0; |
@@ -3801,8 +3843,12 @@ void snd_hda_gen_update_outputs(struct hda_codec *codec) | |||
3801 | on = spec->hp_jack_present | spec->line_jack_present; | 3843 | on = spec->hp_jack_present | spec->line_jack_present; |
3802 | on |= spec->master_mute; | 3844 | on |= spec->master_mute; |
3803 | spec->speaker_muted = on; | 3845 | spec->speaker_muted = on; |
3846 | if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) | ||
3847 | paths = spec->out_paths; | ||
3848 | else | ||
3849 | paths = spec->speaker_paths; | ||
3804 | do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins), | 3850 | do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins), |
3805 | spec->autocfg.speaker_pins, on); | 3851 | spec->autocfg.speaker_pins, paths, on); |
3806 | 3852 | ||
3807 | /* toggle line-out mutes if needed, too */ | 3853 | /* toggle line-out mutes if needed, too */ |
3808 | /* if LO is a copy of either HP or Speaker, don't need to handle it */ | 3854 | /* if LO is a copy of either HP or Speaker, don't need to handle it */ |
@@ -3815,8 +3861,9 @@ void snd_hda_gen_update_outputs(struct hda_codec *codec) | |||
3815 | on = spec->hp_jack_present; | 3861 | on = spec->hp_jack_present; |
3816 | on |= spec->master_mute; | 3862 | on |= spec->master_mute; |
3817 | spec->line_out_muted = on; | 3863 | spec->line_out_muted = on; |
3864 | paths = spec->out_paths; | ||
3818 | do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), | 3865 | do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), |
3819 | spec->autocfg.line_out_pins, on); | 3866 | spec->autocfg.line_out_pins, paths, on); |
3820 | } | 3867 | } |
3821 | EXPORT_SYMBOL_HDA(snd_hda_gen_update_outputs); | 3868 | EXPORT_SYMBOL_HDA(snd_hda_gen_update_outputs); |
3822 | 3869 | ||
@@ -3887,7 +3934,7 @@ void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *ja | |||
3887 | /* don't detect pins retasked as outputs */ | 3934 | /* don't detect pins retasked as outputs */ |
3888 | if (snd_hda_codec_get_pin_target(codec, pin) & AC_PINCTL_OUT_EN) | 3935 | if (snd_hda_codec_get_pin_target(codec, pin) & AC_PINCTL_OUT_EN) |
3889 | continue; | 3936 | continue; |
3890 | if (snd_hda_jack_detect(codec, pin)) { | 3937 | if (snd_hda_jack_detect_state(codec, pin) == HDA_JACK_PRESENT) { |
3891 | mux_select(codec, 0, spec->am_entry[i].idx); | 3938 | mux_select(codec, 0, spec->am_entry[i].idx); |
3892 | return; | 3939 | return; |
3893 | } | 3940 | } |
diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index e199a852388b..48d44026705b 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h | |||
@@ -220,6 +220,7 @@ struct hda_gen_spec { | |||
220 | unsigned int hp_mic:1; /* Allow HP as a mic-in */ | 220 | unsigned int hp_mic:1; /* Allow HP as a mic-in */ |
221 | unsigned int suppress_hp_mic_detect:1; /* Don't detect HP/mic */ | 221 | unsigned int suppress_hp_mic_detect:1; /* Don't detect HP/mic */ |
222 | unsigned int no_primary_hp:1; /* Don't prefer HP pins to speaker pins */ | 222 | unsigned int no_primary_hp:1; /* Don't prefer HP pins to speaker pins */ |
223 | unsigned int no_multi_io:1; /* Don't try multi I/O config */ | ||
223 | unsigned int multi_cap_vol:1; /* allow multiple capture xxx volumes */ | 224 | unsigned int multi_cap_vol:1; /* allow multiple capture xxx volumes */ |
224 | unsigned int inv_dmic_split:1; /* inverted dmic w/a for conexant */ | 225 | unsigned int inv_dmic_split:1; /* inverted dmic w/a for conexant */ |
225 | unsigned int own_eapd_ctl:1; /* set EAPD by own function */ | 226 | unsigned int own_eapd_ctl:1; /* set EAPD by own function */ |
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index ce67608734b5..fe0bda19de15 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c | |||
@@ -295,7 +295,7 @@ static ssize_t type##_store(struct device *dev, \ | |||
295 | struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ | 295 | struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ |
296 | struct hda_codec *codec = hwdep->private_data; \ | 296 | struct hda_codec *codec = hwdep->private_data; \ |
297 | unsigned long val; \ | 297 | unsigned long val; \ |
298 | int err = strict_strtoul(buf, 0, &val); \ | 298 | int err = kstrtoul(buf, 0, &val); \ |
299 | if (err < 0) \ | 299 | if (err < 0) \ |
300 | return err; \ | 300 | return err; \ |
301 | codec->type = val; \ | 301 | codec->type = val; \ |
@@ -654,7 +654,7 @@ int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp) | |||
654 | p = snd_hda_get_hint(codec, key); | 654 | p = snd_hda_get_hint(codec, key); |
655 | if (!p) | 655 | if (!p) |
656 | ret = -ENOENT; | 656 | ret = -ENOENT; |
657 | else if (strict_strtoul(p, 0, &val)) | 657 | else if (kstrtoul(p, 0, &val)) |
658 | ret = -EINVAL; | 658 | ret = -EINVAL; |
659 | else { | 659 | else { |
660 | *valp = val; | 660 | *valp = val; |
@@ -751,7 +751,7 @@ static void parse_##name##_mode(char *buf, struct hda_bus *bus, \ | |||
751 | struct hda_codec **codecp) \ | 751 | struct hda_codec **codecp) \ |
752 | { \ | 752 | { \ |
753 | unsigned long val; \ | 753 | unsigned long val; \ |
754 | if (!strict_strtoul(buf, 0, &val)) \ | 754 | if (!kstrtoul(buf, 0, &val)) \ |
755 | (*codecp)->name = val; \ | 755 | (*codecp)->name = val; \ |
756 | } | 756 | } |
757 | 757 | ||
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 8860dd529520..c6c98298ac39 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -1160,7 +1160,7 @@ static int azx_reset(struct azx *chip, int full_reset) | |||
1160 | goto __skip; | 1160 | goto __skip; |
1161 | 1161 | ||
1162 | /* clear STATESTS */ | 1162 | /* clear STATESTS */ |
1163 | azx_writeb(chip, STATESTS, STATESTS_INT_MASK); | 1163 | azx_writew(chip, STATESTS, STATESTS_INT_MASK); |
1164 | 1164 | ||
1165 | /* reset controller */ | 1165 | /* reset controller */ |
1166 | azx_enter_link_reset(chip); | 1166 | azx_enter_link_reset(chip); |
@@ -1242,7 +1242,7 @@ static void azx_int_clear(struct azx *chip) | |||
1242 | } | 1242 | } |
1243 | 1243 | ||
1244 | /* clear STATESTS */ | 1244 | /* clear STATESTS */ |
1245 | azx_writeb(chip, STATESTS, STATESTS_INT_MASK); | 1245 | azx_writew(chip, STATESTS, STATESTS_INT_MASK); |
1246 | 1246 | ||
1247 | /* clear rirb status */ | 1247 | /* clear rirb status */ |
1248 | azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); | 1248 | azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); |
@@ -1451,8 +1451,8 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id) | |||
1451 | 1451 | ||
1452 | #if 0 | 1452 | #if 0 |
1453 | /* clear state status int */ | 1453 | /* clear state status int */ |
1454 | if (azx_readb(chip, STATESTS) & 0x04) | 1454 | if (azx_readw(chip, STATESTS) & 0x04) |
1455 | azx_writeb(chip, STATESTS, 0x04); | 1455 | azx_writew(chip, STATESTS, 0x04); |
1456 | #endif | 1456 | #endif |
1457 | spin_unlock(&chip->reg_lock); | 1457 | spin_unlock(&chip->reg_lock); |
1458 | 1458 | ||
@@ -2971,6 +2971,10 @@ static int azx_runtime_suspend(struct device *dev) | |||
2971 | struct snd_card *card = dev_get_drvdata(dev); | 2971 | struct snd_card *card = dev_get_drvdata(dev); |
2972 | struct azx *chip = card->private_data; | 2972 | struct azx *chip = card->private_data; |
2973 | 2973 | ||
2974 | /* enable controller wake up event */ | ||
2975 | azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) | | ||
2976 | STATESTS_INT_MASK); | ||
2977 | |||
2974 | azx_stop_chip(chip); | 2978 | azx_stop_chip(chip); |
2975 | azx_enter_link_reset(chip); | 2979 | azx_enter_link_reset(chip); |
2976 | azx_clear_irq_pending(chip); | 2980 | azx_clear_irq_pending(chip); |
@@ -2983,11 +2987,31 @@ static int azx_runtime_resume(struct device *dev) | |||
2983 | { | 2987 | { |
2984 | struct snd_card *card = dev_get_drvdata(dev); | 2988 | struct snd_card *card = dev_get_drvdata(dev); |
2985 | struct azx *chip = card->private_data; | 2989 | struct azx *chip = card->private_data; |
2990 | struct hda_bus *bus; | ||
2991 | struct hda_codec *codec; | ||
2992 | int status; | ||
2986 | 2993 | ||
2987 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) | 2994 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) |
2988 | hda_display_power(true); | 2995 | hda_display_power(true); |
2996 | |||
2997 | /* Read STATESTS before controller reset */ | ||
2998 | status = azx_readw(chip, STATESTS); | ||
2999 | |||
2989 | azx_init_pci(chip); | 3000 | azx_init_pci(chip); |
2990 | azx_init_chip(chip, 1); | 3001 | azx_init_chip(chip, 1); |
3002 | |||
3003 | bus = chip->bus; | ||
3004 | if (status && bus) { | ||
3005 | list_for_each_entry(codec, &bus->codec_list, list) | ||
3006 | if (status & (1 << codec->addr)) | ||
3007 | queue_delayed_work(codec->bus->workq, | ||
3008 | &codec->jackpoll_work, codec->jackpoll_interval); | ||
3009 | } | ||
3010 | |||
3011 | /* disable controller Wake Up event*/ | ||
3012 | azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) & | ||
3013 | ~STATESTS_INT_MASK); | ||
3014 | |||
2991 | return 0; | 3015 | return 0; |
2992 | } | 3016 | } |
2993 | 3017 | ||
@@ -3831,11 +3855,13 @@ static int azx_probe_continue(struct azx *chip) | |||
3831 | 3855 | ||
3832 | /* Request power well for Haswell HDA controller and codec */ | 3856 | /* Request power well for Haswell HDA controller and codec */ |
3833 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { | 3857 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { |
3858 | #ifdef CONFIG_SND_HDA_I915 | ||
3834 | err = hda_i915_init(); | 3859 | err = hda_i915_init(); |
3835 | if (err < 0) { | 3860 | if (err < 0) { |
3836 | snd_printk(KERN_ERR SFX "Error request power-well from i915\n"); | 3861 | snd_printk(KERN_ERR SFX "Error request power-well from i915\n"); |
3837 | goto out_free; | 3862 | goto out_free; |
3838 | } | 3863 | } |
3864 | #endif | ||
3839 | hda_display_power(true); | 3865 | hda_display_power(true); |
3840 | } | 3866 | } |
3841 | 3867 | ||
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index 3fd2973183e2..05b3e3e9108f 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c | |||
@@ -194,18 +194,24 @@ u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid) | |||
194 | EXPORT_SYMBOL_HDA(snd_hda_pin_sense); | 194 | EXPORT_SYMBOL_HDA(snd_hda_pin_sense); |
195 | 195 | ||
196 | /** | 196 | /** |
197 | * snd_hda_jack_detect - query pin Presence Detect status | 197 | * snd_hda_jack_detect_state - query pin Presence Detect status |
198 | * @codec: the CODEC to sense | 198 | * @codec: the CODEC to sense |
199 | * @nid: the pin NID to sense | 199 | * @nid: the pin NID to sense |
200 | * | 200 | * |
201 | * Query and return the pin's Presence Detect status. | 201 | * Query and return the pin's Presence Detect status, as either |
202 | * HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT or HDA_JACK_PHANTOM. | ||
202 | */ | 203 | */ |
203 | int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid) | 204 | int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid) |
204 | { | 205 | { |
205 | u32 sense = snd_hda_pin_sense(codec, nid); | 206 | struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid); |
206 | return get_jack_plug_state(sense); | 207 | if (jack && jack->phantom_jack) |
208 | return HDA_JACK_PHANTOM; | ||
209 | else if (snd_hda_pin_sense(codec, nid) & AC_PINSENSE_PRESENCE) | ||
210 | return HDA_JACK_PRESENT; | ||
211 | else | ||
212 | return HDA_JACK_NOT_PRESENT; | ||
207 | } | 213 | } |
208 | EXPORT_SYMBOL_HDA(snd_hda_jack_detect); | 214 | EXPORT_SYMBOL_HDA(snd_hda_jack_detect_state); |
209 | 215 | ||
210 | /** | 216 | /** |
211 | * snd_hda_jack_detect_enable - enable the jack-detection | 217 | * snd_hda_jack_detect_enable - enable the jack-detection |
@@ -247,8 +253,8 @@ EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable); | |||
247 | int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, | 253 | int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, |
248 | hda_nid_t gating_nid) | 254 | hda_nid_t gating_nid) |
249 | { | 255 | { |
250 | struct hda_jack_tbl *gated = snd_hda_jack_tbl_get(codec, gated_nid); | 256 | struct hda_jack_tbl *gated = snd_hda_jack_tbl_new(codec, gated_nid); |
251 | struct hda_jack_tbl *gating = snd_hda_jack_tbl_get(codec, gating_nid); | 257 | struct hda_jack_tbl *gating = snd_hda_jack_tbl_new(codec, gating_nid); |
252 | 258 | ||
253 | if (!gated || !gating) | 259 | if (!gated || !gating) |
254 | return -EINVAL; | 260 | return -EINVAL; |
diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h index ec12abd45263..379420c44eef 100644 --- a/sound/pci/hda/hda_jack.h +++ b/sound/pci/hda/hda_jack.h | |||
@@ -75,7 +75,18 @@ int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, | |||
75 | hda_nid_t gating_nid); | 75 | hda_nid_t gating_nid); |
76 | 76 | ||
77 | u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid); | 77 | u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid); |
78 | int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid); | 78 | |
79 | /* the jack state returned from snd_hda_jack_detect_state() */ | ||
80 | enum { | ||
81 | HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT, HDA_JACK_PHANTOM, | ||
82 | }; | ||
83 | |||
84 | int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid); | ||
85 | |||
86 | static inline bool snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid) | ||
87 | { | ||
88 | return snd_hda_jack_detect_state(codec, nid) != HDA_JACK_NOT_PRESENT; | ||
89 | } | ||
79 | 90 | ||
80 | bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid); | 91 | bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid); |
81 | 92 | ||
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 9760f001916d..a8cb22eec89e 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c | |||
@@ -582,6 +582,36 @@ static void print_gpio(struct snd_info_buffer *buffer, | |||
582 | print_nid_array(buffer, codec, nid, &codec->nids); | 582 | print_nid_array(buffer, codec, nid, &codec->nids); |
583 | } | 583 | } |
584 | 584 | ||
585 | static void print_device_list(struct snd_info_buffer *buffer, | ||
586 | struct hda_codec *codec, hda_nid_t nid) | ||
587 | { | ||
588 | int i, curr = -1; | ||
589 | u8 dev_list[AC_MAX_DEV_LIST_LEN]; | ||
590 | int devlist_len; | ||
591 | |||
592 | devlist_len = snd_hda_get_devices(codec, nid, dev_list, | ||
593 | AC_MAX_DEV_LIST_LEN); | ||
594 | snd_iprintf(buffer, " Devices: %d\n", devlist_len); | ||
595 | if (devlist_len <= 0) | ||
596 | return; | ||
597 | |||
598 | curr = snd_hda_codec_read(codec, nid, 0, | ||
599 | AC_VERB_GET_DEVICE_SEL, 0); | ||
600 | |||
601 | for (i = 0; i < devlist_len; i++) { | ||
602 | if (i == curr) | ||
603 | snd_iprintf(buffer, " *"); | ||
604 | else | ||
605 | snd_iprintf(buffer, " "); | ||
606 | |||
607 | snd_iprintf(buffer, | ||
608 | "Dev %02d: PD = %d, ELDV = %d, IA = %d\n", i, | ||
609 | !!(dev_list[i] & AC_DE_PD), | ||
610 | !!(dev_list[i] & AC_DE_ELDV), | ||
611 | !!(dev_list[i] & AC_DE_IA)); | ||
612 | } | ||
613 | } | ||
614 | |||
585 | static void print_codec_info(struct snd_info_entry *entry, | 615 | static void print_codec_info(struct snd_info_entry *entry, |
586 | struct snd_info_buffer *buffer) | 616 | struct snd_info_buffer *buffer) |
587 | { | 617 | { |
@@ -751,6 +781,9 @@ static void print_codec_info(struct snd_info_entry *entry, | |||
751 | (wid_caps & AC_WCAP_DELAY) >> | 781 | (wid_caps & AC_WCAP_DELAY) >> |
752 | AC_WCAP_DELAY_SHIFT); | 782 | AC_WCAP_DELAY_SHIFT); |
753 | 783 | ||
784 | if (wid_type == AC_WID_PIN && codec->dp_mst) | ||
785 | print_device_list(buffer, codec, nid); | ||
786 | |||
754 | if (wid_caps & AC_WCAP_CONN_LIST) | 787 | if (wid_caps & AC_WCAP_CONN_LIST) |
755 | print_conn_list(buffer, codec, nid, wid_type, | 788 | print_conn_list(buffer, codec, nid, wid_type, |
756 | conn, conn_len); | 789 | conn, conn_len); |
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index d97f0d61a15b..0cbdd87dde6d 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -32,7 +32,6 @@ | |||
32 | #include "hda_jack.h" | 32 | #include "hda_jack.h" |
33 | #include "hda_generic.h" | 33 | #include "hda_generic.h" |
34 | 34 | ||
35 | #define ENABLE_AD_STATIC_QUIRKS | ||
36 | 35 | ||
37 | struct ad198x_spec { | 36 | struct ad198x_spec { |
38 | struct hda_gen_spec gen; | 37 | struct hda_gen_spec gen; |
@@ -43,114 +42,8 @@ struct ad198x_spec { | |||
43 | hda_nid_t eapd_nid; | 42 | hda_nid_t eapd_nid; |
44 | 43 | ||
45 | unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */ | 44 | unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */ |
46 | |||
47 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
48 | const struct snd_kcontrol_new *mixers[6]; | ||
49 | int num_mixers; | ||
50 | const struct hda_verb *init_verbs[6]; /* initialization verbs | ||
51 | * don't forget NULL termination! | ||
52 | */ | ||
53 | unsigned int num_init_verbs; | ||
54 | |||
55 | /* playback */ | ||
56 | struct hda_multi_out multiout; /* playback set-up | ||
57 | * max_channels, dacs must be set | ||
58 | * dig_out_nid and hp_nid are optional | ||
59 | */ | ||
60 | unsigned int cur_eapd; | ||
61 | unsigned int need_dac_fix; | ||
62 | |||
63 | /* capture */ | ||
64 | unsigned int num_adc_nids; | ||
65 | const hda_nid_t *adc_nids; | ||
66 | hda_nid_t dig_in_nid; /* digital-in NID; optional */ | ||
67 | |||
68 | /* capture source */ | ||
69 | const struct hda_input_mux *input_mux; | ||
70 | const hda_nid_t *capsrc_nids; | ||
71 | unsigned int cur_mux[3]; | ||
72 | |||
73 | /* channel model */ | ||
74 | const struct hda_channel_mode *channel_mode; | ||
75 | int num_channel_mode; | ||
76 | |||
77 | /* PCM information */ | ||
78 | struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */ | ||
79 | |||
80 | unsigned int spdif_route; | ||
81 | |||
82 | unsigned int jack_present: 1; | ||
83 | unsigned int inv_jack_detect: 1;/* inverted jack-detection */ | ||
84 | unsigned int analog_beep: 1; /* analog beep input present */ | ||
85 | unsigned int avoid_init_slave_vol:1; | ||
86 | |||
87 | #ifdef CONFIG_PM | ||
88 | struct hda_loopback_check loopback; | ||
89 | #endif | ||
90 | /* for virtual master */ | ||
91 | hda_nid_t vmaster_nid; | ||
92 | const char * const *slave_vols; | ||
93 | const char * const *slave_sws; | ||
94 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
95 | }; | ||
96 | |||
97 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
98 | /* | ||
99 | * input MUX handling (common part) | ||
100 | */ | ||
101 | static int ad198x_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | ||
102 | { | ||
103 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
104 | struct ad198x_spec *spec = codec->spec; | ||
105 | |||
106 | return snd_hda_input_mux_info(spec->input_mux, uinfo); | ||
107 | } | ||
108 | |||
109 | static int ad198x_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
110 | { | ||
111 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
112 | struct ad198x_spec *spec = codec->spec; | ||
113 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
114 | |||
115 | ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static int ad198x_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
120 | { | ||
121 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
122 | struct ad198x_spec *spec = codec->spec; | ||
123 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
124 | |||
125 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, | ||
126 | spec->capsrc_nids[adc_idx], | ||
127 | &spec->cur_mux[adc_idx]); | ||
128 | } | ||
129 | |||
130 | /* | ||
131 | * initialization (common callbacks) | ||
132 | */ | ||
133 | static int ad198x_init(struct hda_codec *codec) | ||
134 | { | ||
135 | struct ad198x_spec *spec = codec->spec; | ||
136 | int i; | ||
137 | |||
138 | for (i = 0; i < spec->num_init_verbs; i++) | ||
139 | snd_hda_sequence_write(codec, spec->init_verbs[i]); | ||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static const char * const ad_slave_pfxs[] = { | ||
144 | "Front", "Surround", "Center", "LFE", "Side", | ||
145 | "Headphone", "Mono", "Speaker", "IEC958", | ||
146 | NULL | ||
147 | }; | 45 | }; |
148 | 46 | ||
149 | static const char * const ad1988_6stack_fp_slave_pfxs[] = { | ||
150 | "Front", "Surround", "Center", "LFE", "Side", "IEC958", | ||
151 | NULL | ||
152 | }; | ||
153 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
154 | 47 | ||
155 | #ifdef CONFIG_SND_HDA_INPUT_BEEP | 48 | #ifdef CONFIG_SND_HDA_INPUT_BEEP |
156 | /* additional beep mixers; the actual parameters are overwritten at build */ | 49 | /* additional beep mixers; the actual parameters are overwritten at build */ |
@@ -160,12 +53,6 @@ static const struct snd_kcontrol_new ad_beep_mixer[] = { | |||
160 | { } /* end */ | 53 | { } /* end */ |
161 | }; | 54 | }; |
162 | 55 | ||
163 | static const struct snd_kcontrol_new ad_beep2_mixer[] = { | ||
164 | HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0, 0, HDA_OUTPUT), | ||
165 | HDA_CODEC_MUTE_BEEP("Digital Beep Playback Switch", 0, 0, HDA_OUTPUT), | ||
166 | { } /* end */ | ||
167 | }; | ||
168 | |||
169 | #define set_beep_amp(spec, nid, idx, dir) \ | 56 | #define set_beep_amp(spec, nid, idx, dir) \ |
170 | ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */ | 57 | ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */ |
171 | #else | 58 | #else |
@@ -181,8 +68,7 @@ static int create_beep_ctls(struct hda_codec *codec) | |||
181 | if (!spec->beep_amp) | 68 | if (!spec->beep_amp) |
182 | return 0; | 69 | return 0; |
183 | 70 | ||
184 | knew = spec->analog_beep ? ad_beep2_mixer : ad_beep_mixer; | 71 | for (knew = ad_beep_mixer ; knew->name; knew++) { |
185 | for ( ; knew->name; knew++) { | ||
186 | int err; | 72 | int err; |
187 | struct snd_kcontrol *kctl; | 73 | struct snd_kcontrol *kctl; |
188 | kctl = snd_ctl_new1(knew, codec); | 74 | kctl = snd_ctl_new1(knew, codec); |
@@ -199,268 +85,6 @@ static int create_beep_ctls(struct hda_codec *codec) | |||
199 | #define create_beep_ctls(codec) 0 | 85 | #define create_beep_ctls(codec) 0 |
200 | #endif | 86 | #endif |
201 | 87 | ||
202 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
203 | static int ad198x_build_controls(struct hda_codec *codec) | ||
204 | { | ||
205 | struct ad198x_spec *spec = codec->spec; | ||
206 | struct snd_kcontrol *kctl; | ||
207 | unsigned int i; | ||
208 | int err; | ||
209 | |||
210 | for (i = 0; i < spec->num_mixers; i++) { | ||
211 | err = snd_hda_add_new_ctls(codec, spec->mixers[i]); | ||
212 | if (err < 0) | ||
213 | return err; | ||
214 | } | ||
215 | if (spec->multiout.dig_out_nid) { | ||
216 | err = snd_hda_create_spdif_out_ctls(codec, | ||
217 | spec->multiout.dig_out_nid, | ||
218 | spec->multiout.dig_out_nid); | ||
219 | if (err < 0) | ||
220 | return err; | ||
221 | err = snd_hda_create_spdif_share_sw(codec, | ||
222 | &spec->multiout); | ||
223 | if (err < 0) | ||
224 | return err; | ||
225 | spec->multiout.share_spdif = 1; | ||
226 | } | ||
227 | if (spec->dig_in_nid) { | ||
228 | err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); | ||
229 | if (err < 0) | ||
230 | return err; | ||
231 | } | ||
232 | |||
233 | /* create beep controls if needed */ | ||
234 | err = create_beep_ctls(codec); | ||
235 | if (err < 0) | ||
236 | return err; | ||
237 | |||
238 | /* if we have no master control, let's create it */ | ||
239 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { | ||
240 | unsigned int vmaster_tlv[4]; | ||
241 | snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, | ||
242 | HDA_OUTPUT, vmaster_tlv); | ||
243 | err = __snd_hda_add_vmaster(codec, "Master Playback Volume", | ||
244 | vmaster_tlv, | ||
245 | (spec->slave_vols ? | ||
246 | spec->slave_vols : ad_slave_pfxs), | ||
247 | "Playback Volume", | ||
248 | !spec->avoid_init_slave_vol, NULL); | ||
249 | if (err < 0) | ||
250 | return err; | ||
251 | } | ||
252 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { | ||
253 | err = snd_hda_add_vmaster(codec, "Master Playback Switch", | ||
254 | NULL, | ||
255 | (spec->slave_sws ? | ||
256 | spec->slave_sws : ad_slave_pfxs), | ||
257 | "Playback Switch"); | ||
258 | if (err < 0) | ||
259 | return err; | ||
260 | } | ||
261 | |||
262 | /* assign Capture Source enums to NID */ | ||
263 | kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); | ||
264 | if (!kctl) | ||
265 | kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); | ||
266 | for (i = 0; kctl && i < kctl->count; i++) { | ||
267 | err = snd_hda_add_nid(codec, kctl, i, spec->capsrc_nids[i]); | ||
268 | if (err < 0) | ||
269 | return err; | ||
270 | } | ||
271 | |||
272 | /* assign IEC958 enums to NID */ | ||
273 | kctl = snd_hda_find_mixer_ctl(codec, | ||
274 | SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source"); | ||
275 | if (kctl) { | ||
276 | err = snd_hda_add_nid(codec, kctl, 0, | ||
277 | spec->multiout.dig_out_nid); | ||
278 | if (err < 0) | ||
279 | return err; | ||
280 | } | ||
281 | |||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | #ifdef CONFIG_PM | ||
286 | static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid) | ||
287 | { | ||
288 | struct ad198x_spec *spec = codec->spec; | ||
289 | return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); | ||
290 | } | ||
291 | #endif | ||
292 | |||
293 | /* | ||
294 | * Analog playback callbacks | ||
295 | */ | ||
296 | static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
297 | struct hda_codec *codec, | ||
298 | struct snd_pcm_substream *substream) | ||
299 | { | ||
300 | struct ad198x_spec *spec = codec->spec; | ||
301 | return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, | ||
302 | hinfo); | ||
303 | } | ||
304 | |||
305 | static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
306 | struct hda_codec *codec, | ||
307 | unsigned int stream_tag, | ||
308 | unsigned int format, | ||
309 | struct snd_pcm_substream *substream) | ||
310 | { | ||
311 | struct ad198x_spec *spec = codec->spec; | ||
312 | return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, | ||
313 | format, substream); | ||
314 | } | ||
315 | |||
316 | static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
317 | struct hda_codec *codec, | ||
318 | struct snd_pcm_substream *substream) | ||
319 | { | ||
320 | struct ad198x_spec *spec = codec->spec; | ||
321 | return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); | ||
322 | } | ||
323 | |||
324 | /* | ||
325 | * Digital out | ||
326 | */ | ||
327 | static int ad198x_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
328 | struct hda_codec *codec, | ||
329 | struct snd_pcm_substream *substream) | ||
330 | { | ||
331 | struct ad198x_spec *spec = codec->spec; | ||
332 | return snd_hda_multi_out_dig_open(codec, &spec->multiout); | ||
333 | } | ||
334 | |||
335 | static int ad198x_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, | ||
336 | struct hda_codec *codec, | ||
337 | struct snd_pcm_substream *substream) | ||
338 | { | ||
339 | struct ad198x_spec *spec = codec->spec; | ||
340 | return snd_hda_multi_out_dig_close(codec, &spec->multiout); | ||
341 | } | ||
342 | |||
343 | static int ad198x_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
344 | struct hda_codec *codec, | ||
345 | unsigned int stream_tag, | ||
346 | unsigned int format, | ||
347 | struct snd_pcm_substream *substream) | ||
348 | { | ||
349 | struct ad198x_spec *spec = codec->spec; | ||
350 | return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, | ||
351 | format, substream); | ||
352 | } | ||
353 | |||
354 | static int ad198x_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
355 | struct hda_codec *codec, | ||
356 | struct snd_pcm_substream *substream) | ||
357 | { | ||
358 | struct ad198x_spec *spec = codec->spec; | ||
359 | return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); | ||
360 | } | ||
361 | |||
362 | /* | ||
363 | * Analog capture | ||
364 | */ | ||
365 | static int ad198x_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
366 | struct hda_codec *codec, | ||
367 | unsigned int stream_tag, | ||
368 | unsigned int format, | ||
369 | struct snd_pcm_substream *substream) | ||
370 | { | ||
371 | struct ad198x_spec *spec = codec->spec; | ||
372 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], | ||
373 | stream_tag, 0, format); | ||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
378 | struct hda_codec *codec, | ||
379 | struct snd_pcm_substream *substream) | ||
380 | { | ||
381 | struct ad198x_spec *spec = codec->spec; | ||
382 | snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); | ||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | /* | ||
387 | */ | ||
388 | static const struct hda_pcm_stream ad198x_pcm_analog_playback = { | ||
389 | .substreams = 1, | ||
390 | .channels_min = 2, | ||
391 | .channels_max = 6, /* changed later */ | ||
392 | .nid = 0, /* fill later */ | ||
393 | .ops = { | ||
394 | .open = ad198x_playback_pcm_open, | ||
395 | .prepare = ad198x_playback_pcm_prepare, | ||
396 | .cleanup = ad198x_playback_pcm_cleanup, | ||
397 | }, | ||
398 | }; | ||
399 | |||
400 | static const struct hda_pcm_stream ad198x_pcm_analog_capture = { | ||
401 | .substreams = 1, | ||
402 | .channels_min = 2, | ||
403 | .channels_max = 2, | ||
404 | .nid = 0, /* fill later */ | ||
405 | .ops = { | ||
406 | .prepare = ad198x_capture_pcm_prepare, | ||
407 | .cleanup = ad198x_capture_pcm_cleanup | ||
408 | }, | ||
409 | }; | ||
410 | |||
411 | static const struct hda_pcm_stream ad198x_pcm_digital_playback = { | ||
412 | .substreams = 1, | ||
413 | .channels_min = 2, | ||
414 | .channels_max = 2, | ||
415 | .nid = 0, /* fill later */ | ||
416 | .ops = { | ||
417 | .open = ad198x_dig_playback_pcm_open, | ||
418 | .close = ad198x_dig_playback_pcm_close, | ||
419 | .prepare = ad198x_dig_playback_pcm_prepare, | ||
420 | .cleanup = ad198x_dig_playback_pcm_cleanup | ||
421 | }, | ||
422 | }; | ||
423 | |||
424 | static const struct hda_pcm_stream ad198x_pcm_digital_capture = { | ||
425 | .substreams = 1, | ||
426 | .channels_min = 2, | ||
427 | .channels_max = 2, | ||
428 | /* NID is set in alc_build_pcms */ | ||
429 | }; | ||
430 | |||
431 | static int ad198x_build_pcms(struct hda_codec *codec) | ||
432 | { | ||
433 | struct ad198x_spec *spec = codec->spec; | ||
434 | struct hda_pcm *info = spec->pcm_rec; | ||
435 | |||
436 | codec->num_pcms = 1; | ||
437 | codec->pcm_info = info; | ||
438 | |||
439 | info->name = "AD198x Analog"; | ||
440 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_analog_playback; | ||
441 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels; | ||
442 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; | ||
443 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_analog_capture; | ||
444 | info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids; | ||
445 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; | ||
446 | |||
447 | if (spec->multiout.dig_out_nid) { | ||
448 | info++; | ||
449 | codec->num_pcms++; | ||
450 | codec->spdif_status_reset = 1; | ||
451 | info->name = "AD198x Digital"; | ||
452 | info->pcm_type = HDA_PCM_TYPE_SPDIF; | ||
453 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback; | ||
454 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; | ||
455 | if (spec->dig_in_nid) { | ||
456 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_digital_capture; | ||
457 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; | ||
458 | } | ||
459 | } | ||
460 | |||
461 | return 0; | ||
462 | } | ||
463 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
464 | 88 | ||
465 | static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front, | 89 | static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front, |
466 | hda_nid_t hp) | 90 | hda_nid_t hp) |
@@ -507,18 +131,6 @@ static void ad198x_shutup(struct hda_codec *codec) | |||
507 | ad198x_power_eapd(codec); | 131 | ad198x_power_eapd(codec); |
508 | } | 132 | } |
509 | 133 | ||
510 | static void ad198x_free(struct hda_codec *codec) | ||
511 | { | ||
512 | struct ad198x_spec *spec = codec->spec; | ||
513 | |||
514 | if (!spec) | ||
515 | return; | ||
516 | |||
517 | snd_hda_gen_spec_free(&spec->gen); | ||
518 | kfree(spec); | ||
519 | snd_hda_detach_beep_device(codec); | ||
520 | } | ||
521 | |||
522 | #ifdef CONFIG_PM | 134 | #ifdef CONFIG_PM |
523 | static int ad198x_suspend(struct hda_codec *codec) | 135 | static int ad198x_suspend(struct hda_codec *codec) |
524 | { | 136 | { |
@@ -527,65 +139,6 @@ static int ad198x_suspend(struct hda_codec *codec) | |||
527 | } | 139 | } |
528 | #endif | 140 | #endif |
529 | 141 | ||
530 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
531 | static const struct hda_codec_ops ad198x_patch_ops = { | ||
532 | .build_controls = ad198x_build_controls, | ||
533 | .build_pcms = ad198x_build_pcms, | ||
534 | .init = ad198x_init, | ||
535 | .free = ad198x_free, | ||
536 | #ifdef CONFIG_PM | ||
537 | .check_power_status = ad198x_check_power_status, | ||
538 | .suspend = ad198x_suspend, | ||
539 | #endif | ||
540 | .reboot_notify = ad198x_shutup, | ||
541 | }; | ||
542 | |||
543 | |||
544 | /* | ||
545 | * EAPD control | ||
546 | * the private value = nid | ||
547 | */ | ||
548 | #define ad198x_eapd_info snd_ctl_boolean_mono_info | ||
549 | |||
550 | static int ad198x_eapd_get(struct snd_kcontrol *kcontrol, | ||
551 | struct snd_ctl_elem_value *ucontrol) | ||
552 | { | ||
553 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
554 | struct ad198x_spec *spec = codec->spec; | ||
555 | if (codec->inv_eapd) | ||
556 | ucontrol->value.integer.value[0] = ! spec->cur_eapd; | ||
557 | else | ||
558 | ucontrol->value.integer.value[0] = spec->cur_eapd; | ||
559 | return 0; | ||
560 | } | ||
561 | |||
562 | static int ad198x_eapd_put(struct snd_kcontrol *kcontrol, | ||
563 | struct snd_ctl_elem_value *ucontrol) | ||
564 | { | ||
565 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
566 | struct ad198x_spec *spec = codec->spec; | ||
567 | hda_nid_t nid = kcontrol->private_value & 0xff; | ||
568 | unsigned int eapd; | ||
569 | eapd = !!ucontrol->value.integer.value[0]; | ||
570 | if (codec->inv_eapd) | ||
571 | eapd = !eapd; | ||
572 | if (eapd == spec->cur_eapd) | ||
573 | return 0; | ||
574 | spec->cur_eapd = eapd; | ||
575 | snd_hda_codec_write_cache(codec, nid, | ||
576 | 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
577 | eapd ? 0x02 : 0x00); | ||
578 | return 1; | ||
579 | } | ||
580 | |||
581 | static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol, | ||
582 | struct snd_ctl_elem_info *uinfo); | ||
583 | static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol, | ||
584 | struct snd_ctl_elem_value *ucontrol); | ||
585 | static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, | ||
586 | struct snd_ctl_elem_value *ucontrol); | ||
587 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
588 | |||
589 | 142 | ||
590 | /* | 143 | /* |
591 | * Automatic parse of I/O pins from the BIOS configuration | 144 | * Automatic parse of I/O pins from the BIOS configuration |
@@ -646,537 +199,6 @@ static int ad198x_parse_auto_config(struct hda_codec *codec) | |||
646 | * AD1986A specific | 199 | * AD1986A specific |
647 | */ | 200 | */ |
648 | 201 | ||
649 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
650 | #define AD1986A_SPDIF_OUT 0x02 | ||
651 | #define AD1986A_FRONT_DAC 0x03 | ||
652 | #define AD1986A_SURR_DAC 0x04 | ||
653 | #define AD1986A_CLFE_DAC 0x05 | ||
654 | #define AD1986A_ADC 0x06 | ||
655 | |||
656 | static const hda_nid_t ad1986a_dac_nids[3] = { | ||
657 | AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC | ||
658 | }; | ||
659 | static const hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC }; | ||
660 | static const hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 }; | ||
661 | |||
662 | static const struct hda_input_mux ad1986a_capture_source = { | ||
663 | .num_items = 7, | ||
664 | .items = { | ||
665 | { "Mic", 0x0 }, | ||
666 | { "CD", 0x1 }, | ||
667 | { "Aux", 0x3 }, | ||
668 | { "Line", 0x4 }, | ||
669 | { "Mix", 0x5 }, | ||
670 | { "Mono", 0x6 }, | ||
671 | { "Phone", 0x7 }, | ||
672 | }, | ||
673 | }; | ||
674 | |||
675 | |||
676 | static const struct hda_bind_ctls ad1986a_bind_pcm_vol = { | ||
677 | .ops = &snd_hda_bind_vol, | ||
678 | .values = { | ||
679 | HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT), | ||
680 | HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT), | ||
681 | HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT), | ||
682 | 0 | ||
683 | }, | ||
684 | }; | ||
685 | |||
686 | static const struct hda_bind_ctls ad1986a_bind_pcm_sw = { | ||
687 | .ops = &snd_hda_bind_sw, | ||
688 | .values = { | ||
689 | HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT), | ||
690 | HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT), | ||
691 | HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT), | ||
692 | 0 | ||
693 | }, | ||
694 | }; | ||
695 | |||
696 | /* | ||
697 | * mixers | ||
698 | */ | ||
699 | static const struct snd_kcontrol_new ad1986a_mixers[] = { | ||
700 | /* | ||
701 | * bind volumes/mutes of 3 DACs as a single PCM control for simplicity | ||
702 | */ | ||
703 | HDA_BIND_VOL("PCM Playback Volume", &ad1986a_bind_pcm_vol), | ||
704 | HDA_BIND_SW("PCM Playback Switch", &ad1986a_bind_pcm_sw), | ||
705 | HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
706 | HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
707 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT), | ||
708 | HDA_CODEC_MUTE("Surround Playback Switch", 0x1c, 0x0, HDA_OUTPUT), | ||
709 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x1d, 1, 0x0, HDA_OUTPUT), | ||
710 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x1d, 2, 0x0, HDA_OUTPUT), | ||
711 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x1d, 1, 0x0, HDA_OUTPUT), | ||
712 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x1d, 2, 0x0, HDA_OUTPUT), | ||
713 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT), | ||
714 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT), | ||
715 | HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT), | ||
716 | HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
717 | HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT), | ||
718 | HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT), | ||
719 | HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT), | ||
720 | HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT), | ||
721 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
722 | HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||
723 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT), | ||
724 | HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT), | ||
725 | HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), | ||
726 | HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), | ||
727 | HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), | ||
728 | { | ||
729 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
730 | .name = "Capture Source", | ||
731 | .info = ad198x_mux_enum_info, | ||
732 | .get = ad198x_mux_enum_get, | ||
733 | .put = ad198x_mux_enum_put, | ||
734 | }, | ||
735 | HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT), | ||
736 | { } /* end */ | ||
737 | }; | ||
738 | |||
739 | /* additional mixers for 3stack mode */ | ||
740 | static const struct snd_kcontrol_new ad1986a_3st_mixers[] = { | ||
741 | { | ||
742 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
743 | .name = "Channel Mode", | ||
744 | .info = ad198x_ch_mode_info, | ||
745 | .get = ad198x_ch_mode_get, | ||
746 | .put = ad198x_ch_mode_put, | ||
747 | }, | ||
748 | { } /* end */ | ||
749 | }; | ||
750 | |||
751 | /* laptop model - 2ch only */ | ||
752 | static const hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC }; | ||
753 | |||
754 | /* master controls both pins 0x1a and 0x1b */ | ||
755 | static const struct hda_bind_ctls ad1986a_laptop_master_vol = { | ||
756 | .ops = &snd_hda_bind_vol, | ||
757 | .values = { | ||
758 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), | ||
759 | HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), | ||
760 | 0, | ||
761 | }, | ||
762 | }; | ||
763 | |||
764 | static const struct hda_bind_ctls ad1986a_laptop_master_sw = { | ||
765 | .ops = &snd_hda_bind_sw, | ||
766 | .values = { | ||
767 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), | ||
768 | HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), | ||
769 | 0, | ||
770 | }, | ||
771 | }; | ||
772 | |||
773 | static const struct snd_kcontrol_new ad1986a_laptop_mixers[] = { | ||
774 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
775 | HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), | ||
776 | HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), | ||
777 | HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), | ||
778 | HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT), | ||
779 | HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
780 | HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT), | ||
781 | HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT), | ||
782 | HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT), | ||
783 | HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT), | ||
784 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
785 | HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||
786 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT), | ||
787 | /* | ||
788 | HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT), | ||
789 | HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */ | ||
790 | HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), | ||
791 | HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), | ||
792 | { | ||
793 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
794 | .name = "Capture Source", | ||
795 | .info = ad198x_mux_enum_info, | ||
796 | .get = ad198x_mux_enum_get, | ||
797 | .put = ad198x_mux_enum_put, | ||
798 | }, | ||
799 | { } /* end */ | ||
800 | }; | ||
801 | |||
802 | /* laptop-eapd model - 2ch only */ | ||
803 | |||
804 | static const struct hda_input_mux ad1986a_laptop_eapd_capture_source = { | ||
805 | .num_items = 3, | ||
806 | .items = { | ||
807 | { "Mic", 0x0 }, | ||
808 | { "Internal Mic", 0x4 }, | ||
809 | { "Mix", 0x5 }, | ||
810 | }, | ||
811 | }; | ||
812 | |||
813 | static const struct hda_input_mux ad1986a_automic_capture_source = { | ||
814 | .num_items = 2, | ||
815 | .items = { | ||
816 | { "Mic", 0x0 }, | ||
817 | { "Mix", 0x5 }, | ||
818 | }, | ||
819 | }; | ||
820 | |||
821 | static const struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = { | ||
822 | HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), | ||
823 | HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), | ||
824 | { } /* end */ | ||
825 | }; | ||
826 | |||
827 | static const struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { | ||
828 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
829 | HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), | ||
830 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
831 | HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||
832 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT), | ||
833 | HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), | ||
834 | HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), | ||
835 | { | ||
836 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
837 | .name = "Capture Source", | ||
838 | .info = ad198x_mux_enum_info, | ||
839 | .get = ad198x_mux_enum_get, | ||
840 | .put = ad198x_mux_enum_put, | ||
841 | }, | ||
842 | { | ||
843 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
844 | .name = "External Amplifier", | ||
845 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, | ||
846 | .info = ad198x_eapd_info, | ||
847 | .get = ad198x_eapd_get, | ||
848 | .put = ad198x_eapd_put, | ||
849 | .private_value = 0x1b, /* port-D */ | ||
850 | }, | ||
851 | { } /* end */ | ||
852 | }; | ||
853 | |||
854 | static const struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = { | ||
855 | HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT), | ||
856 | HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT), | ||
857 | { } /* end */ | ||
858 | }; | ||
859 | |||
860 | /* re-connect the mic boost input according to the jack sensing */ | ||
861 | static void ad1986a_automic(struct hda_codec *codec) | ||
862 | { | ||
863 | unsigned int present; | ||
864 | present = snd_hda_jack_detect(codec, 0x1f); | ||
865 | /* 0 = 0x1f, 2 = 0x1d, 4 = mixed */ | ||
866 | snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_CONNECT_SEL, | ||
867 | present ? 0 : 2); | ||
868 | } | ||
869 | |||
870 | #define AD1986A_MIC_EVENT 0x36 | ||
871 | |||
872 | static void ad1986a_automic_unsol_event(struct hda_codec *codec, | ||
873 | unsigned int res) | ||
874 | { | ||
875 | if ((res >> 26) != AD1986A_MIC_EVENT) | ||
876 | return; | ||
877 | ad1986a_automic(codec); | ||
878 | } | ||
879 | |||
880 | static int ad1986a_automic_init(struct hda_codec *codec) | ||
881 | { | ||
882 | ad198x_init(codec); | ||
883 | ad1986a_automic(codec); | ||
884 | return 0; | ||
885 | } | ||
886 | |||
887 | /* laptop-automute - 2ch only */ | ||
888 | |||
889 | static void ad1986a_update_hp(struct hda_codec *codec) | ||
890 | { | ||
891 | struct ad198x_spec *spec = codec->spec; | ||
892 | unsigned int mute; | ||
893 | |||
894 | if (spec->jack_present) | ||
895 | mute = HDA_AMP_MUTE; /* mute internal speaker */ | ||
896 | else | ||
897 | /* unmute internal speaker if necessary */ | ||
898 | mute = snd_hda_codec_amp_read(codec, 0x1a, 0, HDA_OUTPUT, 0); | ||
899 | snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, | ||
900 | HDA_AMP_MUTE, mute); | ||
901 | } | ||
902 | |||
903 | static void ad1986a_hp_automute(struct hda_codec *codec) | ||
904 | { | ||
905 | struct ad198x_spec *spec = codec->spec; | ||
906 | |||
907 | spec->jack_present = snd_hda_jack_detect(codec, 0x1a); | ||
908 | if (spec->inv_jack_detect) | ||
909 | spec->jack_present = !spec->jack_present; | ||
910 | ad1986a_update_hp(codec); | ||
911 | } | ||
912 | |||
913 | #define AD1986A_HP_EVENT 0x37 | ||
914 | |||
915 | static void ad1986a_hp_unsol_event(struct hda_codec *codec, unsigned int res) | ||
916 | { | ||
917 | if ((res >> 26) != AD1986A_HP_EVENT) | ||
918 | return; | ||
919 | ad1986a_hp_automute(codec); | ||
920 | } | ||
921 | |||
922 | static int ad1986a_hp_init(struct hda_codec *codec) | ||
923 | { | ||
924 | ad198x_init(codec); | ||
925 | ad1986a_hp_automute(codec); | ||
926 | return 0; | ||
927 | } | ||
928 | |||
929 | /* bind hp and internal speaker mute (with plug check) */ | ||
930 | static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol, | ||
931 | struct snd_ctl_elem_value *ucontrol) | ||
932 | { | ||
933 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
934 | int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); | ||
935 | if (change) | ||
936 | ad1986a_update_hp(codec); | ||
937 | return change; | ||
938 | } | ||
939 | |||
940 | static const struct snd_kcontrol_new ad1986a_automute_master_mixers[] = { | ||
941 | HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), | ||
942 | { | ||
943 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
944 | .name = "Master Playback Switch", | ||
945 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
946 | .info = snd_hda_mixer_amp_switch_info, | ||
947 | .get = snd_hda_mixer_amp_switch_get, | ||
948 | .put = ad1986a_hp_master_sw_put, | ||
949 | .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), | ||
950 | }, | ||
951 | { } /* end */ | ||
952 | }; | ||
953 | |||
954 | |||
955 | /* | ||
956 | * initialization verbs | ||
957 | */ | ||
958 | static const struct hda_verb ad1986a_init_verbs[] = { | ||
959 | /* Front, Surround, CLFE DAC; mute as default */ | ||
960 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
961 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
962 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
963 | /* Downmix - off */ | ||
964 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
965 | /* HP, Line-Out, Surround, CLFE selectors */ | ||
966 | {0x0a, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
967 | {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
968 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
969 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
970 | /* Mono selector */ | ||
971 | {0x0e, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
972 | /* Mic selector: Mic 1/2 pin */ | ||
973 | {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
974 | /* Line-in selector: Line-in */ | ||
975 | {0x10, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
976 | /* Mic 1/2 swap */ | ||
977 | {0x11, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
978 | /* Record selector: mic */ | ||
979 | {0x12, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
980 | /* Mic, Phone, CD, Aux, Line-In amp; mute as default */ | ||
981 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
982 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
983 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
984 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
985 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
986 | /* PC beep */ | ||
987 | {0x18, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
988 | /* HP, Line-Out, Surround, CLFE, Mono pins; mute as default */ | ||
989 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
990 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
991 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
992 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
993 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
994 | /* HP Pin */ | ||
995 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | ||
996 | /* Front, Surround, CLFE Pins */ | ||
997 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
998 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
999 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
1000 | /* Mono Pin */ | ||
1001 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
1002 | /* Mic Pin */ | ||
1003 | {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
1004 | /* Line, Aux, CD, Beep-In Pin */ | ||
1005 | {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
1006 | {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
1007 | {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
1008 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
1009 | {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
1010 | { } /* end */ | ||
1011 | }; | ||
1012 | |||
1013 | static const struct hda_verb ad1986a_ch2_init[] = { | ||
1014 | /* Surround out -> Line In */ | ||
1015 | { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, | ||
1016 | /* Line-in selectors */ | ||
1017 | { 0x10, AC_VERB_SET_CONNECT_SEL, 0x1 }, | ||
1018 | /* CLFE -> Mic in */ | ||
1019 | { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, | ||
1020 | /* Mic selector, mix C/LFE (backmic) and Mic (frontmic) */ | ||
1021 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 }, | ||
1022 | { } /* end */ | ||
1023 | }; | ||
1024 | |||
1025 | static const struct hda_verb ad1986a_ch4_init[] = { | ||
1026 | /* Surround out -> Surround */ | ||
1027 | { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
1028 | { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 }, | ||
1029 | /* CLFE -> Mic in */ | ||
1030 | { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, | ||
1031 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 }, | ||
1032 | { } /* end */ | ||
1033 | }; | ||
1034 | |||
1035 | static const struct hda_verb ad1986a_ch6_init[] = { | ||
1036 | /* Surround out -> Surround out */ | ||
1037 | { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
1038 | { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 }, | ||
1039 | /* CLFE -> CLFE */ | ||
1040 | { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
1041 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x0 }, | ||
1042 | { } /* end */ | ||
1043 | }; | ||
1044 | |||
1045 | static const struct hda_channel_mode ad1986a_modes[3] = { | ||
1046 | { 2, ad1986a_ch2_init }, | ||
1047 | { 4, ad1986a_ch4_init }, | ||
1048 | { 6, ad1986a_ch6_init }, | ||
1049 | }; | ||
1050 | |||
1051 | /* eapd initialization */ | ||
1052 | static const struct hda_verb ad1986a_eapd_init_verbs[] = { | ||
1053 | {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, | ||
1054 | {} | ||
1055 | }; | ||
1056 | |||
1057 | static const struct hda_verb ad1986a_automic_verbs[] = { | ||
1058 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1059 | {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1060 | /*{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},*/ | ||
1061 | {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1062 | {0x1f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_MIC_EVENT}, | ||
1063 | {} | ||
1064 | }; | ||
1065 | |||
1066 | /* Ultra initialization */ | ||
1067 | static const struct hda_verb ad1986a_ultra_init[] = { | ||
1068 | /* eapd initialization */ | ||
1069 | { 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, | ||
1070 | /* CLFE -> Mic in */ | ||
1071 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2 }, | ||
1072 | { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
1073 | { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, | ||
1074 | { } /* end */ | ||
1075 | }; | ||
1076 | |||
1077 | /* pin sensing on HP jack */ | ||
1078 | static const struct hda_verb ad1986a_hp_init_verbs[] = { | ||
1079 | {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT}, | ||
1080 | {} | ||
1081 | }; | ||
1082 | |||
1083 | static void ad1986a_samsung_p50_unsol_event(struct hda_codec *codec, | ||
1084 | unsigned int res) | ||
1085 | { | ||
1086 | switch (res >> 26) { | ||
1087 | case AD1986A_HP_EVENT: | ||
1088 | ad1986a_hp_automute(codec); | ||
1089 | break; | ||
1090 | case AD1986A_MIC_EVENT: | ||
1091 | ad1986a_automic(codec); | ||
1092 | break; | ||
1093 | } | ||
1094 | } | ||
1095 | |||
1096 | static int ad1986a_samsung_p50_init(struct hda_codec *codec) | ||
1097 | { | ||
1098 | ad198x_init(codec); | ||
1099 | ad1986a_hp_automute(codec); | ||
1100 | ad1986a_automic(codec); | ||
1101 | return 0; | ||
1102 | } | ||
1103 | |||
1104 | |||
1105 | /* models */ | ||
1106 | enum { | ||
1107 | AD1986A_AUTO, | ||
1108 | AD1986A_6STACK, | ||
1109 | AD1986A_3STACK, | ||
1110 | AD1986A_LAPTOP, | ||
1111 | AD1986A_LAPTOP_EAPD, | ||
1112 | AD1986A_LAPTOP_AUTOMUTE, | ||
1113 | AD1986A_ULTRA, | ||
1114 | AD1986A_SAMSUNG, | ||
1115 | AD1986A_SAMSUNG_P50, | ||
1116 | AD1986A_MODELS | ||
1117 | }; | ||
1118 | |||
1119 | static const char * const ad1986a_models[AD1986A_MODELS] = { | ||
1120 | [AD1986A_AUTO] = "auto", | ||
1121 | [AD1986A_6STACK] = "6stack", | ||
1122 | [AD1986A_3STACK] = "3stack", | ||
1123 | [AD1986A_LAPTOP] = "laptop", | ||
1124 | [AD1986A_LAPTOP_EAPD] = "laptop-eapd", | ||
1125 | [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute", | ||
1126 | [AD1986A_ULTRA] = "ultra", | ||
1127 | [AD1986A_SAMSUNG] = "samsung", | ||
1128 | [AD1986A_SAMSUNG_P50] = "samsung-p50", | ||
1129 | }; | ||
1130 | |||
1131 | static const struct snd_pci_quirk ad1986a_cfg_tbl[] = { | ||
1132 | SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD), | ||
1133 | SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD), | ||
1134 | SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD), | ||
1135 | SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD), | ||
1136 | SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD), | ||
1137 | SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD), | ||
1138 | SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD), | ||
1139 | SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD), | ||
1140 | SND_PCI_QUIRK(0x1043, 0x1443, "ASUS VX1", AD1986A_LAPTOP), | ||
1141 | SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8J", AD1986A_3STACK), | ||
1142 | SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK), | ||
1143 | SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP), | ||
1144 | SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK), | ||
1145 | SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK), | ||
1146 | SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK), | ||
1147 | SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK), | ||
1148 | SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40-10Q", AD1986A_3STACK), | ||
1149 | SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK), | ||
1150 | SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), | ||
1151 | SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50), | ||
1152 | SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA), | ||
1153 | SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_SAMSUNG), | ||
1154 | SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK), | ||
1155 | SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), | ||
1156 | SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK), | ||
1157 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE), | ||
1158 | SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP), | ||
1159 | {} | ||
1160 | }; | ||
1161 | |||
1162 | #ifdef CONFIG_PM | ||
1163 | static const struct hda_amp_list ad1986a_loopbacks[] = { | ||
1164 | { 0x13, HDA_OUTPUT, 0 }, /* Mic */ | ||
1165 | { 0x14, HDA_OUTPUT, 0 }, /* Phone */ | ||
1166 | { 0x15, HDA_OUTPUT, 0 }, /* CD */ | ||
1167 | { 0x16, HDA_OUTPUT, 0 }, /* Aux */ | ||
1168 | { 0x17, HDA_OUTPUT, 0 }, /* Line */ | ||
1169 | { } /* end */ | ||
1170 | }; | ||
1171 | #endif | ||
1172 | |||
1173 | static int is_jack_available(struct hda_codec *codec, hda_nid_t nid) | ||
1174 | { | ||
1175 | unsigned int conf = snd_hda_codec_get_pincfg(codec, nid); | ||
1176 | return get_defcfg_connect(conf) != AC_JACK_PORT_NONE; | ||
1177 | } | ||
1178 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
1179 | |||
1180 | static int alloc_ad_spec(struct hda_codec *codec) | 202 | static int alloc_ad_spec(struct hda_codec *codec) |
1181 | { | 203 | { |
1182 | struct ad198x_spec *spec; | 204 | struct ad198x_spec *spec; |
@@ -1203,6 +225,11 @@ static void ad_fixup_inv_jack_detect(struct hda_codec *codec, | |||
1203 | 225 | ||
1204 | enum { | 226 | enum { |
1205 | AD1986A_FIXUP_INV_JACK_DETECT, | 227 | AD1986A_FIXUP_INV_JACK_DETECT, |
228 | AD1986A_FIXUP_ULTRA, | ||
229 | AD1986A_FIXUP_SAMSUNG, | ||
230 | AD1986A_FIXUP_3STACK, | ||
231 | AD1986A_FIXUP_LAPTOP, | ||
232 | AD1986A_FIXUP_LAPTOP_IMIC, | ||
1206 | }; | 233 | }; |
1207 | 234 | ||
1208 | static const struct hda_fixup ad1986a_fixups[] = { | 235 | static const struct hda_fixup ad1986a_fixups[] = { |
@@ -1210,16 +237,86 @@ static const struct hda_fixup ad1986a_fixups[] = { | |||
1210 | .type = HDA_FIXUP_FUNC, | 237 | .type = HDA_FIXUP_FUNC, |
1211 | .v.func = ad_fixup_inv_jack_detect, | 238 | .v.func = ad_fixup_inv_jack_detect, |
1212 | }, | 239 | }, |
240 | [AD1986A_FIXUP_ULTRA] = { | ||
241 | .type = HDA_FIXUP_PINS, | ||
242 | .v.pins = (const struct hda_pintbl[]) { | ||
243 | { 0x1b, 0x90170110 }, /* speaker */ | ||
244 | { 0x1d, 0x90a7013e }, /* int mic */ | ||
245 | {} | ||
246 | }, | ||
247 | }, | ||
248 | [AD1986A_FIXUP_SAMSUNG] = { | ||
249 | .type = HDA_FIXUP_PINS, | ||
250 | .v.pins = (const struct hda_pintbl[]) { | ||
251 | { 0x1b, 0x90170110 }, /* speaker */ | ||
252 | { 0x1d, 0x90a7013e }, /* int mic */ | ||
253 | { 0x20, 0x411111f0 }, /* N/A */ | ||
254 | { 0x24, 0x411111f0 }, /* N/A */ | ||
255 | {} | ||
256 | }, | ||
257 | }, | ||
258 | [AD1986A_FIXUP_3STACK] = { | ||
259 | .type = HDA_FIXUP_PINS, | ||
260 | .v.pins = (const struct hda_pintbl[]) { | ||
261 | { 0x1a, 0x02214021 }, /* headphone */ | ||
262 | { 0x1b, 0x01014011 }, /* front */ | ||
263 | { 0x1c, 0x01013012 }, /* surround */ | ||
264 | { 0x1d, 0x01019015 }, /* clfe */ | ||
265 | { 0x1e, 0x411111f0 }, /* N/A */ | ||
266 | { 0x1f, 0x02a190f0 }, /* mic */ | ||
267 | { 0x20, 0x018130f0 }, /* line-in */ | ||
268 | {} | ||
269 | }, | ||
270 | }, | ||
271 | [AD1986A_FIXUP_LAPTOP] = { | ||
272 | .type = HDA_FIXUP_PINS, | ||
273 | .v.pins = (const struct hda_pintbl[]) { | ||
274 | { 0x1a, 0x02214021 }, /* headphone */ | ||
275 | { 0x1b, 0x90170110 }, /* speaker */ | ||
276 | { 0x1c, 0x411111f0 }, /* N/A */ | ||
277 | { 0x1d, 0x411111f0 }, /* N/A */ | ||
278 | { 0x1e, 0x411111f0 }, /* N/A */ | ||
279 | { 0x1f, 0x02a191f0 }, /* mic */ | ||
280 | { 0x20, 0x411111f0 }, /* N/A */ | ||
281 | {} | ||
282 | }, | ||
283 | }, | ||
284 | [AD1986A_FIXUP_LAPTOP_IMIC] = { | ||
285 | .type = HDA_FIXUP_PINS, | ||
286 | .v.pins = (const struct hda_pintbl[]) { | ||
287 | { 0x1d, 0x90a7013e }, /* int mic */ | ||
288 | {} | ||
289 | }, | ||
290 | .chained_before = 1, | ||
291 | .chain_id = AD1986A_FIXUP_LAPTOP, | ||
292 | }, | ||
1213 | }; | 293 | }; |
1214 | 294 | ||
1215 | static const struct snd_pci_quirk ad1986a_fixup_tbl[] = { | 295 | static const struct snd_pci_quirk ad1986a_fixup_tbl[] = { |
296 | SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_FIXUP_LAPTOP_IMIC), | ||
297 | SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8100, "ASUS P5", AD1986A_FIXUP_3STACK), | ||
298 | SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8200, "ASUS M2", AD1986A_FIXUP_3STACK), | ||
299 | SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_FIXUP_3STACK), | ||
300 | SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_FIXUP_LAPTOP), | ||
301 | SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_FIXUP_SAMSUNG), | ||
302 | SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_FIXUP_ULTRA), | ||
1216 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT), | 303 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT), |
304 | SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_FIXUP_3STACK), | ||
305 | SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_FIXUP_3STACK), | ||
306 | {} | ||
307 | }; | ||
308 | |||
309 | static const struct hda_model_fixup ad1986a_fixup_models[] = { | ||
310 | { .id = AD1986A_FIXUP_3STACK, .name = "3stack" }, | ||
311 | { .id = AD1986A_FIXUP_LAPTOP, .name = "laptop" }, | ||
312 | { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-imic" }, | ||
313 | { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-eapd" }, /* alias */ | ||
1217 | {} | 314 | {} |
1218 | }; | 315 | }; |
1219 | 316 | ||
1220 | /* | 317 | /* |
1221 | */ | 318 | */ |
1222 | static int ad1986a_parse_auto_config(struct hda_codec *codec) | 319 | static int patch_ad1986a(struct hda_codec *codec) |
1223 | { | 320 | { |
1224 | int err; | 321 | int err; |
1225 | struct ad198x_spec *spec; | 322 | struct ad198x_spec *spec; |
@@ -1244,7 +341,8 @@ static int ad1986a_parse_auto_config(struct hda_codec *codec) | |||
1244 | */ | 341 | */ |
1245 | spec->gen.multiout.no_share_stream = 1; | 342 | spec->gen.multiout.no_share_stream = 1; |
1246 | 343 | ||
1247 | snd_hda_pick_fixup(codec, NULL, ad1986a_fixup_tbl, ad1986a_fixups); | 344 | snd_hda_pick_fixup(codec, ad1986a_fixup_models, ad1986a_fixup_tbl, |
345 | ad1986a_fixups); | ||
1248 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); | 346 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); |
1249 | 347 | ||
1250 | err = ad198x_parse_auto_config(codec); | 348 | err = ad198x_parse_auto_config(codec); |
@@ -1258,330 +356,11 @@ static int ad1986a_parse_auto_config(struct hda_codec *codec) | |||
1258 | return 0; | 356 | return 0; |
1259 | } | 357 | } |
1260 | 358 | ||
1261 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
1262 | static int patch_ad1986a(struct hda_codec *codec) | ||
1263 | { | ||
1264 | struct ad198x_spec *spec; | ||
1265 | int err, board_config; | ||
1266 | |||
1267 | board_config = snd_hda_check_board_config(codec, AD1986A_MODELS, | ||
1268 | ad1986a_models, | ||
1269 | ad1986a_cfg_tbl); | ||
1270 | if (board_config < 0) { | ||
1271 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
1272 | codec->chip_name); | ||
1273 | board_config = AD1986A_AUTO; | ||
1274 | } | ||
1275 | |||
1276 | if (board_config == AD1986A_AUTO) | ||
1277 | return ad1986a_parse_auto_config(codec); | ||
1278 | |||
1279 | err = alloc_ad_spec(codec); | ||
1280 | if (err < 0) | ||
1281 | return err; | ||
1282 | spec = codec->spec; | ||
1283 | |||
1284 | err = snd_hda_attach_beep_device(codec, 0x19); | ||
1285 | if (err < 0) { | ||
1286 | ad198x_free(codec); | ||
1287 | return err; | ||
1288 | } | ||
1289 | set_beep_amp(spec, 0x18, 0, HDA_OUTPUT); | ||
1290 | |||
1291 | spec->multiout.max_channels = 6; | ||
1292 | spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids); | ||
1293 | spec->multiout.dac_nids = ad1986a_dac_nids; | ||
1294 | spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT; | ||
1295 | spec->num_adc_nids = 1; | ||
1296 | spec->adc_nids = ad1986a_adc_nids; | ||
1297 | spec->capsrc_nids = ad1986a_capsrc_nids; | ||
1298 | spec->input_mux = &ad1986a_capture_source; | ||
1299 | spec->num_mixers = 1; | ||
1300 | spec->mixers[0] = ad1986a_mixers; | ||
1301 | spec->num_init_verbs = 1; | ||
1302 | spec->init_verbs[0] = ad1986a_init_verbs; | ||
1303 | #ifdef CONFIG_PM | ||
1304 | spec->loopback.amplist = ad1986a_loopbacks; | ||
1305 | #endif | ||
1306 | spec->vmaster_nid = 0x1b; | ||
1307 | codec->inv_eapd = 1; /* AD1986A has the inverted EAPD implementation */ | ||
1308 | |||
1309 | codec->patch_ops = ad198x_patch_ops; | ||
1310 | |||
1311 | /* override some parameters */ | ||
1312 | switch (board_config) { | ||
1313 | case AD1986A_3STACK: | ||
1314 | spec->num_mixers = 2; | ||
1315 | spec->mixers[1] = ad1986a_3st_mixers; | ||
1316 | spec->num_init_verbs = 2; | ||
1317 | spec->init_verbs[1] = ad1986a_ch2_init; | ||
1318 | spec->channel_mode = ad1986a_modes; | ||
1319 | spec->num_channel_mode = ARRAY_SIZE(ad1986a_modes); | ||
1320 | spec->need_dac_fix = 1; | ||
1321 | spec->multiout.max_channels = 2; | ||
1322 | spec->multiout.num_dacs = 1; | ||
1323 | break; | ||
1324 | case AD1986A_LAPTOP: | ||
1325 | spec->mixers[0] = ad1986a_laptop_mixers; | ||
1326 | spec->multiout.max_channels = 2; | ||
1327 | spec->multiout.num_dacs = 1; | ||
1328 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | ||
1329 | break; | ||
1330 | case AD1986A_LAPTOP_EAPD: | ||
1331 | spec->num_mixers = 3; | ||
1332 | spec->mixers[0] = ad1986a_laptop_master_mixers; | ||
1333 | spec->mixers[1] = ad1986a_laptop_eapd_mixers; | ||
1334 | spec->mixers[2] = ad1986a_laptop_intmic_mixers; | ||
1335 | spec->num_init_verbs = 2; | ||
1336 | spec->init_verbs[1] = ad1986a_eapd_init_verbs; | ||
1337 | spec->multiout.max_channels = 2; | ||
1338 | spec->multiout.num_dacs = 1; | ||
1339 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | ||
1340 | if (!is_jack_available(codec, 0x25)) | ||
1341 | spec->multiout.dig_out_nid = 0; | ||
1342 | spec->input_mux = &ad1986a_laptop_eapd_capture_source; | ||
1343 | break; | ||
1344 | case AD1986A_SAMSUNG: | ||
1345 | spec->num_mixers = 2; | ||
1346 | spec->mixers[0] = ad1986a_laptop_master_mixers; | ||
1347 | spec->mixers[1] = ad1986a_laptop_eapd_mixers; | ||
1348 | spec->num_init_verbs = 3; | ||
1349 | spec->init_verbs[1] = ad1986a_eapd_init_verbs; | ||
1350 | spec->init_verbs[2] = ad1986a_automic_verbs; | ||
1351 | spec->multiout.max_channels = 2; | ||
1352 | spec->multiout.num_dacs = 1; | ||
1353 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | ||
1354 | if (!is_jack_available(codec, 0x25)) | ||
1355 | spec->multiout.dig_out_nid = 0; | ||
1356 | spec->input_mux = &ad1986a_automic_capture_source; | ||
1357 | codec->patch_ops.unsol_event = ad1986a_automic_unsol_event; | ||
1358 | codec->patch_ops.init = ad1986a_automic_init; | ||
1359 | break; | ||
1360 | case AD1986A_SAMSUNG_P50: | ||
1361 | spec->num_mixers = 2; | ||
1362 | spec->mixers[0] = ad1986a_automute_master_mixers; | ||
1363 | spec->mixers[1] = ad1986a_laptop_eapd_mixers; | ||
1364 | spec->num_init_verbs = 4; | ||
1365 | spec->init_verbs[1] = ad1986a_eapd_init_verbs; | ||
1366 | spec->init_verbs[2] = ad1986a_automic_verbs; | ||
1367 | spec->init_verbs[3] = ad1986a_hp_init_verbs; | ||
1368 | spec->multiout.max_channels = 2; | ||
1369 | spec->multiout.num_dacs = 1; | ||
1370 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | ||
1371 | if (!is_jack_available(codec, 0x25)) | ||
1372 | spec->multiout.dig_out_nid = 0; | ||
1373 | spec->input_mux = &ad1986a_automic_capture_source; | ||
1374 | codec->patch_ops.unsol_event = ad1986a_samsung_p50_unsol_event; | ||
1375 | codec->patch_ops.init = ad1986a_samsung_p50_init; | ||
1376 | break; | ||
1377 | case AD1986A_LAPTOP_AUTOMUTE: | ||
1378 | spec->num_mixers = 3; | ||
1379 | spec->mixers[0] = ad1986a_automute_master_mixers; | ||
1380 | spec->mixers[1] = ad1986a_laptop_eapd_mixers; | ||
1381 | spec->mixers[2] = ad1986a_laptop_intmic_mixers; | ||
1382 | spec->num_init_verbs = 3; | ||
1383 | spec->init_verbs[1] = ad1986a_eapd_init_verbs; | ||
1384 | spec->init_verbs[2] = ad1986a_hp_init_verbs; | ||
1385 | spec->multiout.max_channels = 2; | ||
1386 | spec->multiout.num_dacs = 1; | ||
1387 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | ||
1388 | if (!is_jack_available(codec, 0x25)) | ||
1389 | spec->multiout.dig_out_nid = 0; | ||
1390 | spec->input_mux = &ad1986a_laptop_eapd_capture_source; | ||
1391 | codec->patch_ops.unsol_event = ad1986a_hp_unsol_event; | ||
1392 | codec->patch_ops.init = ad1986a_hp_init; | ||
1393 | /* Lenovo N100 seems to report the reversed bit | ||
1394 | * for HP jack-sensing | ||
1395 | */ | ||
1396 | spec->inv_jack_detect = 1; | ||
1397 | break; | ||
1398 | case AD1986A_ULTRA: | ||
1399 | spec->mixers[0] = ad1986a_laptop_eapd_mixers; | ||
1400 | spec->num_init_verbs = 2; | ||
1401 | spec->init_verbs[1] = ad1986a_ultra_init; | ||
1402 | spec->multiout.max_channels = 2; | ||
1403 | spec->multiout.num_dacs = 1; | ||
1404 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | ||
1405 | spec->multiout.dig_out_nid = 0; | ||
1406 | break; | ||
1407 | } | ||
1408 | |||
1409 | /* AD1986A has a hardware problem that it can't share a stream | ||
1410 | * with multiple output pins. The copy of front to surrounds | ||
1411 | * causes noisy or silent outputs at a certain timing, e.g. | ||
1412 | * changing the volume. | ||
1413 | * So, let's disable the shared stream. | ||
1414 | */ | ||
1415 | spec->multiout.no_share_stream = 1; | ||
1416 | |||
1417 | codec->no_trigger_sense = 1; | ||
1418 | codec->no_sticky_stream = 1; | ||
1419 | |||
1420 | return 0; | ||
1421 | } | ||
1422 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
1423 | #define patch_ad1986a ad1986a_parse_auto_config | ||
1424 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
1425 | 359 | ||
1426 | /* | 360 | /* |
1427 | * AD1983 specific | 361 | * AD1983 specific |
1428 | */ | 362 | */ |
1429 | 363 | ||
1430 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
1431 | #define AD1983_SPDIF_OUT 0x02 | ||
1432 | #define AD1983_DAC 0x03 | ||
1433 | #define AD1983_ADC 0x04 | ||
1434 | |||
1435 | static const hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC }; | ||
1436 | static const hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC }; | ||
1437 | static const hda_nid_t ad1983_capsrc_nids[1] = { 0x15 }; | ||
1438 | |||
1439 | static const struct hda_input_mux ad1983_capture_source = { | ||
1440 | .num_items = 4, | ||
1441 | .items = { | ||
1442 | { "Mic", 0x0 }, | ||
1443 | { "Line", 0x1 }, | ||
1444 | { "Mix", 0x2 }, | ||
1445 | { "Mix Mono", 0x3 }, | ||
1446 | }, | ||
1447 | }; | ||
1448 | |||
1449 | /* | ||
1450 | * SPDIF playback route | ||
1451 | */ | ||
1452 | static int ad1983_spdif_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | ||
1453 | { | ||
1454 | static const char * const texts[] = { "PCM", "ADC" }; | ||
1455 | |||
1456 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
1457 | uinfo->count = 1; | ||
1458 | uinfo->value.enumerated.items = 2; | ||
1459 | if (uinfo->value.enumerated.item > 1) | ||
1460 | uinfo->value.enumerated.item = 1; | ||
1461 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
1462 | return 0; | ||
1463 | } | ||
1464 | |||
1465 | static int ad1983_spdif_route_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
1466 | { | ||
1467 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1468 | struct ad198x_spec *spec = codec->spec; | ||
1469 | |||
1470 | ucontrol->value.enumerated.item[0] = spec->spdif_route; | ||
1471 | return 0; | ||
1472 | } | ||
1473 | |||
1474 | static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
1475 | { | ||
1476 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1477 | struct ad198x_spec *spec = codec->spec; | ||
1478 | |||
1479 | if (ucontrol->value.enumerated.item[0] > 1) | ||
1480 | return -EINVAL; | ||
1481 | if (spec->spdif_route != ucontrol->value.enumerated.item[0]) { | ||
1482 | spec->spdif_route = ucontrol->value.enumerated.item[0]; | ||
1483 | snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0, | ||
1484 | AC_VERB_SET_CONNECT_SEL, | ||
1485 | spec->spdif_route); | ||
1486 | return 1; | ||
1487 | } | ||
1488 | return 0; | ||
1489 | } | ||
1490 | |||
1491 | static const struct snd_kcontrol_new ad1983_mixers[] = { | ||
1492 | HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT), | ||
1493 | HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT), | ||
1494 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT), | ||
1495 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT), | ||
1496 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT), | ||
1497 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT), | ||
1498 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), | ||
1499 | HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
1500 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), | ||
1501 | HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
1502 | HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
1503 | HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||
1504 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
1505 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), | ||
1506 | HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), | ||
1507 | { | ||
1508 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1509 | .name = "Capture Source", | ||
1510 | .info = ad198x_mux_enum_info, | ||
1511 | .get = ad198x_mux_enum_get, | ||
1512 | .put = ad198x_mux_enum_put, | ||
1513 | }, | ||
1514 | { | ||
1515 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1516 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
1517 | .info = ad1983_spdif_route_info, | ||
1518 | .get = ad1983_spdif_route_get, | ||
1519 | .put = ad1983_spdif_route_put, | ||
1520 | }, | ||
1521 | { } /* end */ | ||
1522 | }; | ||
1523 | |||
1524 | static const struct hda_verb ad1983_init_verbs[] = { | ||
1525 | /* Front, HP, Mono; mute as default */ | ||
1526 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1527 | {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1528 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1529 | /* Beep, PCM, Mic, Line-In: mute */ | ||
1530 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1531 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1532 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1533 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1534 | /* Front, HP selectors; from Mix */ | ||
1535 | {0x05, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
1536 | {0x06, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
1537 | /* Mono selector; from Mix */ | ||
1538 | {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03}, | ||
1539 | /* Mic selector; Mic */ | ||
1540 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1541 | /* Line-in selector: Line-in */ | ||
1542 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1543 | /* Mic boost: 0dB */ | ||
1544 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
1545 | /* Record selector: mic */ | ||
1546 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1547 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1548 | /* SPDIF route: PCM */ | ||
1549 | {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1550 | /* Front Pin */ | ||
1551 | {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
1552 | /* HP Pin */ | ||
1553 | {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | ||
1554 | /* Mono Pin */ | ||
1555 | {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
1556 | /* Mic Pin */ | ||
1557 | {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
1558 | /* Line Pin */ | ||
1559 | {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
1560 | { } /* end */ | ||
1561 | }; | ||
1562 | |||
1563 | #ifdef CONFIG_PM | ||
1564 | static const struct hda_amp_list ad1983_loopbacks[] = { | ||
1565 | { 0x12, HDA_OUTPUT, 0 }, /* Mic */ | ||
1566 | { 0x13, HDA_OUTPUT, 0 }, /* Line */ | ||
1567 | { } /* end */ | ||
1568 | }; | ||
1569 | #endif | ||
1570 | |||
1571 | /* models */ | ||
1572 | enum { | ||
1573 | AD1983_AUTO, | ||
1574 | AD1983_BASIC, | ||
1575 | AD1983_MODELS | ||
1576 | }; | ||
1577 | |||
1578 | static const char * const ad1983_models[AD1983_MODELS] = { | ||
1579 | [AD1983_AUTO] = "auto", | ||
1580 | [AD1983_BASIC] = "basic", | ||
1581 | }; | ||
1582 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
1583 | |||
1584 | |||
1585 | /* | 364 | /* |
1586 | * SPDIF mux control for AD1983 auto-parser | 365 | * SPDIF mux control for AD1983 auto-parser |
1587 | */ | 366 | */ |
@@ -1656,7 +435,7 @@ static int ad1983_add_spdif_mux_ctl(struct hda_codec *codec) | |||
1656 | return 0; | 435 | return 0; |
1657 | } | 436 | } |
1658 | 437 | ||
1659 | static int ad1983_parse_auto_config(struct hda_codec *codec) | 438 | static int patch_ad1983(struct hda_codec *codec) |
1660 | { | 439 | { |
1661 | struct ad198x_spec *spec; | 440 | struct ad198x_spec *spec; |
1662 | int err; | 441 | int err; |
@@ -1681,432 +460,11 @@ static int ad1983_parse_auto_config(struct hda_codec *codec) | |||
1681 | return err; | 460 | return err; |
1682 | } | 461 | } |
1683 | 462 | ||
1684 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
1685 | static int patch_ad1983(struct hda_codec *codec) | ||
1686 | { | ||
1687 | struct ad198x_spec *spec; | ||
1688 | int board_config; | ||
1689 | int err; | ||
1690 | |||
1691 | board_config = snd_hda_check_board_config(codec, AD1983_MODELS, | ||
1692 | ad1983_models, NULL); | ||
1693 | if (board_config < 0) { | ||
1694 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
1695 | codec->chip_name); | ||
1696 | board_config = AD1983_AUTO; | ||
1697 | } | ||
1698 | |||
1699 | if (board_config == AD1983_AUTO) | ||
1700 | return ad1983_parse_auto_config(codec); | ||
1701 | |||
1702 | err = alloc_ad_spec(codec); | ||
1703 | if (err < 0) | ||
1704 | return err; | ||
1705 | spec = codec->spec; | ||
1706 | |||
1707 | err = snd_hda_attach_beep_device(codec, 0x10); | ||
1708 | if (err < 0) { | ||
1709 | ad198x_free(codec); | ||
1710 | return err; | ||
1711 | } | ||
1712 | set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); | ||
1713 | |||
1714 | spec->multiout.max_channels = 2; | ||
1715 | spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids); | ||
1716 | spec->multiout.dac_nids = ad1983_dac_nids; | ||
1717 | spec->multiout.dig_out_nid = AD1983_SPDIF_OUT; | ||
1718 | spec->num_adc_nids = 1; | ||
1719 | spec->adc_nids = ad1983_adc_nids; | ||
1720 | spec->capsrc_nids = ad1983_capsrc_nids; | ||
1721 | spec->input_mux = &ad1983_capture_source; | ||
1722 | spec->num_mixers = 1; | ||
1723 | spec->mixers[0] = ad1983_mixers; | ||
1724 | spec->num_init_verbs = 1; | ||
1725 | spec->init_verbs[0] = ad1983_init_verbs; | ||
1726 | spec->spdif_route = 0; | ||
1727 | #ifdef CONFIG_PM | ||
1728 | spec->loopback.amplist = ad1983_loopbacks; | ||
1729 | #endif | ||
1730 | spec->vmaster_nid = 0x05; | ||
1731 | |||
1732 | codec->patch_ops = ad198x_patch_ops; | ||
1733 | |||
1734 | codec->no_trigger_sense = 1; | ||
1735 | codec->no_sticky_stream = 1; | ||
1736 | |||
1737 | return 0; | ||
1738 | } | ||
1739 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
1740 | #define patch_ad1983 ad1983_parse_auto_config | ||
1741 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
1742 | |||
1743 | 463 | ||
1744 | /* | 464 | /* |
1745 | * AD1981 HD specific | 465 | * AD1981 HD specific |
1746 | */ | 466 | */ |
1747 | 467 | ||
1748 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
1749 | #define AD1981_SPDIF_OUT 0x02 | ||
1750 | #define AD1981_DAC 0x03 | ||
1751 | #define AD1981_ADC 0x04 | ||
1752 | |||
1753 | static const hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC }; | ||
1754 | static const hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC }; | ||
1755 | static const hda_nid_t ad1981_capsrc_nids[1] = { 0x15 }; | ||
1756 | |||
1757 | /* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */ | ||
1758 | static const struct hda_input_mux ad1981_capture_source = { | ||
1759 | .num_items = 7, | ||
1760 | .items = { | ||
1761 | { "Front Mic", 0x0 }, | ||
1762 | { "Line", 0x1 }, | ||
1763 | { "Mix", 0x2 }, | ||
1764 | { "Mix Mono", 0x3 }, | ||
1765 | { "CD", 0x4 }, | ||
1766 | { "Mic", 0x6 }, | ||
1767 | { "Aux", 0x7 }, | ||
1768 | }, | ||
1769 | }; | ||
1770 | |||
1771 | static const struct snd_kcontrol_new ad1981_mixers[] = { | ||
1772 | HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT), | ||
1773 | HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT), | ||
1774 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT), | ||
1775 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT), | ||
1776 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT), | ||
1777 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT), | ||
1778 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), | ||
1779 | HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
1780 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), | ||
1781 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
1782 | HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
1783 | HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||
1784 | HDA_CODEC_VOLUME("Aux Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
1785 | HDA_CODEC_MUTE("Aux Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
1786 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT), | ||
1787 | HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT), | ||
1788 | HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), | ||
1789 | HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), | ||
1790 | HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x08, 0x0, HDA_INPUT), | ||
1791 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x0, HDA_INPUT), | ||
1792 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), | ||
1793 | HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), | ||
1794 | { | ||
1795 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1796 | .name = "Capture Source", | ||
1797 | .info = ad198x_mux_enum_info, | ||
1798 | .get = ad198x_mux_enum_get, | ||
1799 | .put = ad198x_mux_enum_put, | ||
1800 | }, | ||
1801 | /* identical with AD1983 */ | ||
1802 | { | ||
1803 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1804 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
1805 | .info = ad1983_spdif_route_info, | ||
1806 | .get = ad1983_spdif_route_get, | ||
1807 | .put = ad1983_spdif_route_put, | ||
1808 | }, | ||
1809 | { } /* end */ | ||
1810 | }; | ||
1811 | |||
1812 | static const struct hda_verb ad1981_init_verbs[] = { | ||
1813 | /* Front, HP, Mono; mute as default */ | ||
1814 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1815 | {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1816 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1817 | /* Beep, PCM, Front Mic, Line, Rear Mic, Aux, CD-In: mute */ | ||
1818 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1819 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1820 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1821 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1822 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1823 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1824 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1825 | /* Front, HP selectors; from Mix */ | ||
1826 | {0x05, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
1827 | {0x06, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
1828 | /* Mono selector; from Mix */ | ||
1829 | {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03}, | ||
1830 | /* Mic Mixer; select Front Mic */ | ||
1831 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
1832 | {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1833 | /* Mic boost: 0dB */ | ||
1834 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
1835 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
1836 | /* Record selector: Front mic */ | ||
1837 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1838 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1839 | /* SPDIF route: PCM */ | ||
1840 | {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1841 | /* Front Pin */ | ||
1842 | {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
1843 | /* HP Pin */ | ||
1844 | {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | ||
1845 | /* Mono Pin */ | ||
1846 | {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
1847 | /* Front & Rear Mic Pins */ | ||
1848 | {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
1849 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
1850 | /* Line Pin */ | ||
1851 | {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
1852 | /* Digital Beep */ | ||
1853 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
1854 | /* Line-Out as Input: disabled */ | ||
1855 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1856 | { } /* end */ | ||
1857 | }; | ||
1858 | |||
1859 | #ifdef CONFIG_PM | ||
1860 | static const struct hda_amp_list ad1981_loopbacks[] = { | ||
1861 | { 0x12, HDA_OUTPUT, 0 }, /* Front Mic */ | ||
1862 | { 0x13, HDA_OUTPUT, 0 }, /* Line */ | ||
1863 | { 0x1b, HDA_OUTPUT, 0 }, /* Aux */ | ||
1864 | { 0x1c, HDA_OUTPUT, 0 }, /* Mic */ | ||
1865 | { 0x1d, HDA_OUTPUT, 0 }, /* CD */ | ||
1866 | { } /* end */ | ||
1867 | }; | ||
1868 | #endif | ||
1869 | |||
1870 | /* | ||
1871 | * Patch for HP nx6320 | ||
1872 | * | ||
1873 | * nx6320 uses EAPD in the reverse way - EAPD-on means the internal | ||
1874 | * speaker output enabled _and_ mute-LED off. | ||
1875 | */ | ||
1876 | |||
1877 | #define AD1981_HP_EVENT 0x37 | ||
1878 | #define AD1981_MIC_EVENT 0x38 | ||
1879 | |||
1880 | static const struct hda_verb ad1981_hp_init_verbs[] = { | ||
1881 | {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* default off */ | ||
1882 | /* pin sensing on HP and Mic jacks */ | ||
1883 | {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT}, | ||
1884 | {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT}, | ||
1885 | {} | ||
1886 | }; | ||
1887 | |||
1888 | /* turn on/off EAPD (+ mute HP) as a master switch */ | ||
1889 | static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol, | ||
1890 | struct snd_ctl_elem_value *ucontrol) | ||
1891 | { | ||
1892 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1893 | struct ad198x_spec *spec = codec->spec; | ||
1894 | |||
1895 | if (! ad198x_eapd_put(kcontrol, ucontrol)) | ||
1896 | return 0; | ||
1897 | /* change speaker pin appropriately */ | ||
1898 | snd_hda_set_pin_ctl(codec, 0x05, spec->cur_eapd ? PIN_OUT : 0); | ||
1899 | /* toggle HP mute appropriately */ | ||
1900 | snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0, | ||
1901 | HDA_AMP_MUTE, | ||
1902 | spec->cur_eapd ? 0 : HDA_AMP_MUTE); | ||
1903 | return 1; | ||
1904 | } | ||
1905 | |||
1906 | /* bind volumes of both NID 0x05 and 0x06 */ | ||
1907 | static const struct hda_bind_ctls ad1981_hp_bind_master_vol = { | ||
1908 | .ops = &snd_hda_bind_vol, | ||
1909 | .values = { | ||
1910 | HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), | ||
1911 | HDA_COMPOSE_AMP_VAL(0x06, 3, 0, HDA_OUTPUT), | ||
1912 | 0 | ||
1913 | }, | ||
1914 | }; | ||
1915 | |||
1916 | /* mute internal speaker if HP is plugged */ | ||
1917 | static void ad1981_hp_automute(struct hda_codec *codec) | ||
1918 | { | ||
1919 | unsigned int present; | ||
1920 | |||
1921 | present = snd_hda_jack_detect(codec, 0x06); | ||
1922 | snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0, | ||
1923 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
1924 | } | ||
1925 | |||
1926 | /* toggle input of built-in and mic jack appropriately */ | ||
1927 | static void ad1981_hp_automic(struct hda_codec *codec) | ||
1928 | { | ||
1929 | static const struct hda_verb mic_jack_on[] = { | ||
1930 | {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1931 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
1932 | {} | ||
1933 | }; | ||
1934 | static const struct hda_verb mic_jack_off[] = { | ||
1935 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1936 | {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
1937 | {} | ||
1938 | }; | ||
1939 | unsigned int present; | ||
1940 | |||
1941 | present = snd_hda_jack_detect(codec, 0x08); | ||
1942 | if (present) | ||
1943 | snd_hda_sequence_write(codec, mic_jack_on); | ||
1944 | else | ||
1945 | snd_hda_sequence_write(codec, mic_jack_off); | ||
1946 | } | ||
1947 | |||
1948 | /* unsolicited event for HP jack sensing */ | ||
1949 | static void ad1981_hp_unsol_event(struct hda_codec *codec, | ||
1950 | unsigned int res) | ||
1951 | { | ||
1952 | res >>= 26; | ||
1953 | switch (res) { | ||
1954 | case AD1981_HP_EVENT: | ||
1955 | ad1981_hp_automute(codec); | ||
1956 | break; | ||
1957 | case AD1981_MIC_EVENT: | ||
1958 | ad1981_hp_automic(codec); | ||
1959 | break; | ||
1960 | } | ||
1961 | } | ||
1962 | |||
1963 | static const struct hda_input_mux ad1981_hp_capture_source = { | ||
1964 | .num_items = 3, | ||
1965 | .items = { | ||
1966 | { "Mic", 0x0 }, | ||
1967 | { "Dock Mic", 0x1 }, | ||
1968 | { "Mix", 0x2 }, | ||
1969 | }, | ||
1970 | }; | ||
1971 | |||
1972 | static const struct snd_kcontrol_new ad1981_hp_mixers[] = { | ||
1973 | HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol), | ||
1974 | { | ||
1975 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1976 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x05, | ||
1977 | .name = "Master Playback Switch", | ||
1978 | .info = ad198x_eapd_info, | ||
1979 | .get = ad198x_eapd_get, | ||
1980 | .put = ad1981_hp_master_sw_put, | ||
1981 | .private_value = 0x05, | ||
1982 | }, | ||
1983 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), | ||
1984 | HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
1985 | #if 0 | ||
1986 | /* FIXME: analog mic/line loopback doesn't work with my tests... | ||
1987 | * (although recording is OK) | ||
1988 | */ | ||
1989 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), | ||
1990 | HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
1991 | HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
1992 | HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||
1993 | HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT), | ||
1994 | HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT), | ||
1995 | /* FIXME: does this laptop have analog CD connection? */ | ||
1996 | HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), | ||
1997 | HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), | ||
1998 | #endif | ||
1999 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT), | ||
2000 | HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x18, 0x0, HDA_INPUT), | ||
2001 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), | ||
2002 | HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), | ||
2003 | { | ||
2004 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2005 | .name = "Capture Source", | ||
2006 | .info = ad198x_mux_enum_info, | ||
2007 | .get = ad198x_mux_enum_get, | ||
2008 | .put = ad198x_mux_enum_put, | ||
2009 | }, | ||
2010 | { } /* end */ | ||
2011 | }; | ||
2012 | |||
2013 | /* initialize jack-sensing, too */ | ||
2014 | static int ad1981_hp_init(struct hda_codec *codec) | ||
2015 | { | ||
2016 | ad198x_init(codec); | ||
2017 | ad1981_hp_automute(codec); | ||
2018 | ad1981_hp_automic(codec); | ||
2019 | return 0; | ||
2020 | } | ||
2021 | |||
2022 | /* configuration for Toshiba Laptops */ | ||
2023 | static const struct hda_verb ad1981_toshiba_init_verbs[] = { | ||
2024 | {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x01 }, /* default on */ | ||
2025 | /* pin sensing on HP and Mic jacks */ | ||
2026 | {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT}, | ||
2027 | {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT}, | ||
2028 | {} | ||
2029 | }; | ||
2030 | |||
2031 | static const struct snd_kcontrol_new ad1981_toshiba_mixers[] = { | ||
2032 | HDA_CODEC_VOLUME("Amp Volume", 0x1a, 0x0, HDA_OUTPUT), | ||
2033 | HDA_CODEC_MUTE("Amp Switch", 0x1a, 0x0, HDA_OUTPUT), | ||
2034 | { } | ||
2035 | }; | ||
2036 | |||
2037 | /* configuration for Lenovo Thinkpad T60 */ | ||
2038 | static const struct snd_kcontrol_new ad1981_thinkpad_mixers[] = { | ||
2039 | HDA_CODEC_VOLUME("Master Playback Volume", 0x05, 0x0, HDA_OUTPUT), | ||
2040 | HDA_CODEC_MUTE("Master Playback Switch", 0x05, 0x0, HDA_OUTPUT), | ||
2041 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), | ||
2042 | HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
2043 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), | ||
2044 | HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
2045 | HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), | ||
2046 | HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), | ||
2047 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT), | ||
2048 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), | ||
2049 | HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), | ||
2050 | { | ||
2051 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2052 | .name = "Capture Source", | ||
2053 | .info = ad198x_mux_enum_info, | ||
2054 | .get = ad198x_mux_enum_get, | ||
2055 | .put = ad198x_mux_enum_put, | ||
2056 | }, | ||
2057 | /* identical with AD1983 */ | ||
2058 | { | ||
2059 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2060 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
2061 | .info = ad1983_spdif_route_info, | ||
2062 | .get = ad1983_spdif_route_get, | ||
2063 | .put = ad1983_spdif_route_put, | ||
2064 | }, | ||
2065 | { } /* end */ | ||
2066 | }; | ||
2067 | |||
2068 | static const struct hda_input_mux ad1981_thinkpad_capture_source = { | ||
2069 | .num_items = 3, | ||
2070 | .items = { | ||
2071 | { "Mic", 0x0 }, | ||
2072 | { "Mix", 0x2 }, | ||
2073 | { "CD", 0x4 }, | ||
2074 | }, | ||
2075 | }; | ||
2076 | |||
2077 | /* models */ | ||
2078 | enum { | ||
2079 | AD1981_AUTO, | ||
2080 | AD1981_BASIC, | ||
2081 | AD1981_HP, | ||
2082 | AD1981_THINKPAD, | ||
2083 | AD1981_TOSHIBA, | ||
2084 | AD1981_MODELS | ||
2085 | }; | ||
2086 | |||
2087 | static const char * const ad1981_models[AD1981_MODELS] = { | ||
2088 | [AD1981_AUTO] = "auto", | ||
2089 | [AD1981_HP] = "hp", | ||
2090 | [AD1981_THINKPAD] = "thinkpad", | ||
2091 | [AD1981_BASIC] = "basic", | ||
2092 | [AD1981_TOSHIBA] = "toshiba" | ||
2093 | }; | ||
2094 | |||
2095 | static const struct snd_pci_quirk ad1981_cfg_tbl[] = { | ||
2096 | SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD), | ||
2097 | SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD), | ||
2098 | /* All HP models */ | ||
2099 | SND_PCI_QUIRK_VENDOR(0x103c, "HP nx", AD1981_HP), | ||
2100 | SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA), | ||
2101 | /* Lenovo Thinkpad T60/X60/Z6xx */ | ||
2102 | SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1981_THINKPAD), | ||
2103 | /* HP nx6320 (reversed SSID, H/W bug) */ | ||
2104 | SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP), | ||
2105 | {} | ||
2106 | }; | ||
2107 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
2108 | |||
2109 | |||
2110 | /* follow EAPD via vmaster hook */ | 468 | /* follow EAPD via vmaster hook */ |
2111 | static void ad_vmaster_eapd_hook(void *private_data, int enabled) | 469 | static void ad_vmaster_eapd_hook(void *private_data, int enabled) |
2112 | { | 470 | { |
@@ -2172,7 +530,7 @@ static const struct snd_pci_quirk ad1981_fixup_tbl[] = { | |||
2172 | {} | 530 | {} |
2173 | }; | 531 | }; |
2174 | 532 | ||
2175 | static int ad1981_parse_auto_config(struct hda_codec *codec) | 533 | static int patch_ad1981(struct hda_codec *codec) |
2176 | { | 534 | { |
2177 | struct ad198x_spec *spec; | 535 | struct ad198x_spec *spec; |
2178 | int err; | 536 | int err; |
@@ -2205,110 +563,6 @@ static int ad1981_parse_auto_config(struct hda_codec *codec) | |||
2205 | return err; | 563 | return err; |
2206 | } | 564 | } |
2207 | 565 | ||
2208 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
2209 | static int patch_ad1981(struct hda_codec *codec) | ||
2210 | { | ||
2211 | struct ad198x_spec *spec; | ||
2212 | int err, board_config; | ||
2213 | |||
2214 | board_config = snd_hda_check_board_config(codec, AD1981_MODELS, | ||
2215 | ad1981_models, | ||
2216 | ad1981_cfg_tbl); | ||
2217 | if (board_config < 0) { | ||
2218 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
2219 | codec->chip_name); | ||
2220 | board_config = AD1981_AUTO; | ||
2221 | } | ||
2222 | |||
2223 | if (board_config == AD1981_AUTO) | ||
2224 | return ad1981_parse_auto_config(codec); | ||
2225 | |||
2226 | err = alloc_ad_spec(codec); | ||
2227 | if (err < 0) | ||
2228 | return -ENOMEM; | ||
2229 | spec = codec->spec; | ||
2230 | |||
2231 | err = snd_hda_attach_beep_device(codec, 0x10); | ||
2232 | if (err < 0) { | ||
2233 | ad198x_free(codec); | ||
2234 | return err; | ||
2235 | } | ||
2236 | set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT); | ||
2237 | |||
2238 | spec->multiout.max_channels = 2; | ||
2239 | spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids); | ||
2240 | spec->multiout.dac_nids = ad1981_dac_nids; | ||
2241 | spec->multiout.dig_out_nid = AD1981_SPDIF_OUT; | ||
2242 | spec->num_adc_nids = 1; | ||
2243 | spec->adc_nids = ad1981_adc_nids; | ||
2244 | spec->capsrc_nids = ad1981_capsrc_nids; | ||
2245 | spec->input_mux = &ad1981_capture_source; | ||
2246 | spec->num_mixers = 1; | ||
2247 | spec->mixers[0] = ad1981_mixers; | ||
2248 | spec->num_init_verbs = 1; | ||
2249 | spec->init_verbs[0] = ad1981_init_verbs; | ||
2250 | spec->spdif_route = 0; | ||
2251 | #ifdef CONFIG_PM | ||
2252 | spec->loopback.amplist = ad1981_loopbacks; | ||
2253 | #endif | ||
2254 | spec->vmaster_nid = 0x05; | ||
2255 | |||
2256 | codec->patch_ops = ad198x_patch_ops; | ||
2257 | |||
2258 | /* override some parameters */ | ||
2259 | switch (board_config) { | ||
2260 | case AD1981_HP: | ||
2261 | spec->mixers[0] = ad1981_hp_mixers; | ||
2262 | spec->num_init_verbs = 2; | ||
2263 | spec->init_verbs[1] = ad1981_hp_init_verbs; | ||
2264 | if (!is_jack_available(codec, 0x0a)) | ||
2265 | spec->multiout.dig_out_nid = 0; | ||
2266 | spec->input_mux = &ad1981_hp_capture_source; | ||
2267 | |||
2268 | codec->patch_ops.init = ad1981_hp_init; | ||
2269 | codec->patch_ops.unsol_event = ad1981_hp_unsol_event; | ||
2270 | /* set the upper-limit for mixer amp to 0dB for avoiding the | ||
2271 | * possible damage by overloading | ||
2272 | */ | ||
2273 | snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT, | ||
2274 | (0x17 << AC_AMPCAP_OFFSET_SHIFT) | | ||
2275 | (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||
2276 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
2277 | (1 << AC_AMPCAP_MUTE_SHIFT)); | ||
2278 | break; | ||
2279 | case AD1981_THINKPAD: | ||
2280 | spec->mixers[0] = ad1981_thinkpad_mixers; | ||
2281 | spec->input_mux = &ad1981_thinkpad_capture_source; | ||
2282 | /* set the upper-limit for mixer amp to 0dB for avoiding the | ||
2283 | * possible damage by overloading | ||
2284 | */ | ||
2285 | snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT, | ||
2286 | (0x17 << AC_AMPCAP_OFFSET_SHIFT) | | ||
2287 | (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||
2288 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
2289 | (1 << AC_AMPCAP_MUTE_SHIFT)); | ||
2290 | break; | ||
2291 | case AD1981_TOSHIBA: | ||
2292 | spec->mixers[0] = ad1981_hp_mixers; | ||
2293 | spec->mixers[1] = ad1981_toshiba_mixers; | ||
2294 | spec->num_init_verbs = 2; | ||
2295 | spec->init_verbs[1] = ad1981_toshiba_init_verbs; | ||
2296 | spec->multiout.dig_out_nid = 0; | ||
2297 | spec->input_mux = &ad1981_hp_capture_source; | ||
2298 | codec->patch_ops.init = ad1981_hp_init; | ||
2299 | codec->patch_ops.unsol_event = ad1981_hp_unsol_event; | ||
2300 | break; | ||
2301 | } | ||
2302 | |||
2303 | codec->no_trigger_sense = 1; | ||
2304 | codec->no_sticky_stream = 1; | ||
2305 | |||
2306 | return 0; | ||
2307 | } | ||
2308 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
2309 | #define patch_ad1981 ad1981_parse_auto_config | ||
2310 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
2311 | |||
2312 | 566 | ||
2313 | /* | 567 | /* |
2314 | * AD1988 | 568 | * AD1988 |
@@ -2395,90 +649,7 @@ static int patch_ad1981(struct hda_codec *codec) | |||
2395 | * E/F quad mic array | 649 | * E/F quad mic array |
2396 | */ | 650 | */ |
2397 | 651 | ||
2398 | |||
2399 | #ifdef ENABLE_AD_STATIC_QUIRKS | 652 | #ifdef ENABLE_AD_STATIC_QUIRKS |
2400 | /* models */ | ||
2401 | enum { | ||
2402 | AD1988_AUTO, | ||
2403 | AD1988_6STACK, | ||
2404 | AD1988_6STACK_DIG, | ||
2405 | AD1988_3STACK, | ||
2406 | AD1988_3STACK_DIG, | ||
2407 | AD1988_LAPTOP, | ||
2408 | AD1988_LAPTOP_DIG, | ||
2409 | AD1988_MODEL_LAST, | ||
2410 | }; | ||
2411 | |||
2412 | /* reivision id to check workarounds */ | ||
2413 | #define AD1988A_REV2 0x100200 | ||
2414 | |||
2415 | #define is_rev2(codec) \ | ||
2416 | ((codec)->vendor_id == 0x11d41988 && \ | ||
2417 | (codec)->revision_id == AD1988A_REV2) | ||
2418 | |||
2419 | /* | ||
2420 | * mixers | ||
2421 | */ | ||
2422 | |||
2423 | static const hda_nid_t ad1988_6stack_dac_nids[4] = { | ||
2424 | 0x04, 0x06, 0x05, 0x0a | ||
2425 | }; | ||
2426 | |||
2427 | static const hda_nid_t ad1988_3stack_dac_nids[3] = { | ||
2428 | 0x04, 0x05, 0x0a | ||
2429 | }; | ||
2430 | |||
2431 | /* for AD1988A revision-2, DAC2-4 are swapped */ | ||
2432 | static const hda_nid_t ad1988_6stack_dac_nids_rev2[4] = { | ||
2433 | 0x04, 0x05, 0x0a, 0x06 | ||
2434 | }; | ||
2435 | |||
2436 | static const hda_nid_t ad1988_alt_dac_nid[1] = { | ||
2437 | 0x03 | ||
2438 | }; | ||
2439 | |||
2440 | static const hda_nid_t ad1988_3stack_dac_nids_rev2[3] = { | ||
2441 | 0x04, 0x0a, 0x06 | ||
2442 | }; | ||
2443 | |||
2444 | static const hda_nid_t ad1988_adc_nids[3] = { | ||
2445 | 0x08, 0x09, 0x0f | ||
2446 | }; | ||
2447 | |||
2448 | static const hda_nid_t ad1988_capsrc_nids[3] = { | ||
2449 | 0x0c, 0x0d, 0x0e | ||
2450 | }; | ||
2451 | |||
2452 | #define AD1988_SPDIF_OUT 0x02 | ||
2453 | #define AD1988_SPDIF_OUT_HDMI 0x0b | ||
2454 | #define AD1988_SPDIF_IN 0x07 | ||
2455 | |||
2456 | static const hda_nid_t ad1989b_slave_dig_outs[] = { | ||
2457 | AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI, 0 | ||
2458 | }; | ||
2459 | |||
2460 | static const struct hda_input_mux ad1988_6stack_capture_source = { | ||
2461 | .num_items = 5, | ||
2462 | .items = { | ||
2463 | { "Front Mic", 0x1 }, /* port-B */ | ||
2464 | { "Line", 0x2 }, /* port-C */ | ||
2465 | { "Mic", 0x4 }, /* port-E */ | ||
2466 | { "CD", 0x5 }, | ||
2467 | { "Mix", 0x9 }, | ||
2468 | }, | ||
2469 | }; | ||
2470 | |||
2471 | static const struct hda_input_mux ad1988_laptop_capture_source = { | ||
2472 | .num_items = 3, | ||
2473 | .items = { | ||
2474 | { "Mic/Line", 0x1 }, /* port-B */ | ||
2475 | { "CD", 0x5 }, | ||
2476 | { "Mix", 0x9 }, | ||
2477 | }, | ||
2478 | }; | ||
2479 | |||
2480 | /* | ||
2481 | */ | ||
2482 | static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol, | 653 | static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol, |
2483 | struct snd_ctl_elem_info *uinfo) | 654 | struct snd_ctl_elem_info *uinfo) |
2484 | { | 655 | { |
@@ -2509,569 +680,6 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, | |||
2509 | spec->multiout.num_dacs = spec->multiout.max_channels / 2; | 680 | spec->multiout.num_dacs = spec->multiout.max_channels / 2; |
2510 | return err; | 681 | return err; |
2511 | } | 682 | } |
2512 | |||
2513 | /* 6-stack mode */ | ||
2514 | static const struct snd_kcontrol_new ad1988_6stack_mixers1[] = { | ||
2515 | HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
2516 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT), | ||
2517 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT), | ||
2518 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT), | ||
2519 | HDA_CODEC_VOLUME("Side Playback Volume", 0x0a, 0x0, HDA_OUTPUT), | ||
2520 | { } /* end */ | ||
2521 | }; | ||
2522 | |||
2523 | static const struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = { | ||
2524 | HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
2525 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x05, 0x0, HDA_OUTPUT), | ||
2526 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), | ||
2527 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0a, 2, 0x0, HDA_OUTPUT), | ||
2528 | HDA_CODEC_VOLUME("Side Playback Volume", 0x06, 0x0, HDA_OUTPUT), | ||
2529 | { } /* end */ | ||
2530 | }; | ||
2531 | |||
2532 | static const struct snd_kcontrol_new ad1988_6stack_mixers2[] = { | ||
2533 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
2534 | HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT), | ||
2535 | HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT), | ||
2536 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT), | ||
2537 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT), | ||
2538 | HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT), | ||
2539 | HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT), | ||
2540 | HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), | ||
2541 | |||
2542 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT), | ||
2543 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT), | ||
2544 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT), | ||
2545 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT), | ||
2546 | HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT), | ||
2547 | HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT), | ||
2548 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT), | ||
2549 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT), | ||
2550 | |||
2551 | HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
2552 | HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
2553 | |||
2554 | HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), | ||
2555 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT), | ||
2556 | { } /* end */ | ||
2557 | }; | ||
2558 | |||
2559 | /* 3-stack mode */ | ||
2560 | static const struct snd_kcontrol_new ad1988_3stack_mixers1[] = { | ||
2561 | HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
2562 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT), | ||
2563 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT), | ||
2564 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT), | ||
2565 | { } /* end */ | ||
2566 | }; | ||
2567 | |||
2568 | static const struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = { | ||
2569 | HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
2570 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT), | ||
2571 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x06, 1, 0x0, HDA_OUTPUT), | ||
2572 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x06, 2, 0x0, HDA_OUTPUT), | ||
2573 | { } /* end */ | ||
2574 | }; | ||
2575 | |||
2576 | static const struct snd_kcontrol_new ad1988_3stack_mixers2[] = { | ||
2577 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
2578 | HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT), | ||
2579 | HDA_BIND_MUTE("Surround Playback Switch", 0x2c, 2, HDA_INPUT), | ||
2580 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x26, 1, 2, HDA_INPUT), | ||
2581 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x26, 2, 2, HDA_INPUT), | ||
2582 | HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT), | ||
2583 | HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), | ||
2584 | |||
2585 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT), | ||
2586 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT), | ||
2587 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT), | ||
2588 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT), | ||
2589 | HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT), | ||
2590 | HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT), | ||
2591 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT), | ||
2592 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT), | ||
2593 | |||
2594 | HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
2595 | HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
2596 | |||
2597 | HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), | ||
2598 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT), | ||
2599 | { | ||
2600 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2601 | .name = "Channel Mode", | ||
2602 | .info = ad198x_ch_mode_info, | ||
2603 | .get = ad198x_ch_mode_get, | ||
2604 | .put = ad198x_ch_mode_put, | ||
2605 | }, | ||
2606 | |||
2607 | { } /* end */ | ||
2608 | }; | ||
2609 | |||
2610 | /* laptop mode */ | ||
2611 | static const struct snd_kcontrol_new ad1988_laptop_mixers[] = { | ||
2612 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
2613 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
2614 | HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT), | ||
2615 | HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), | ||
2616 | |||
2617 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT), | ||
2618 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT), | ||
2619 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x0, HDA_INPUT), | ||
2620 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x0, HDA_INPUT), | ||
2621 | HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT), | ||
2622 | HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT), | ||
2623 | |||
2624 | HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
2625 | HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
2626 | |||
2627 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), | ||
2628 | |||
2629 | { | ||
2630 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2631 | .name = "External Amplifier", | ||
2632 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x12, | ||
2633 | .info = ad198x_eapd_info, | ||
2634 | .get = ad198x_eapd_get, | ||
2635 | .put = ad198x_eapd_put, | ||
2636 | .private_value = 0x12, /* port-D */ | ||
2637 | }, | ||
2638 | |||
2639 | { } /* end */ | ||
2640 | }; | ||
2641 | |||
2642 | /* capture */ | ||
2643 | static const struct snd_kcontrol_new ad1988_capture_mixers[] = { | ||
2644 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
2645 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
2646 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
2647 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
2648 | HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x0e, 0x0, HDA_OUTPUT), | ||
2649 | HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x0e, 0x0, HDA_OUTPUT), | ||
2650 | { | ||
2651 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2652 | /* The multiple "Capture Source" controls confuse alsamixer | ||
2653 | * So call somewhat different.. | ||
2654 | */ | ||
2655 | /* .name = "Capture Source", */ | ||
2656 | .name = "Input Source", | ||
2657 | .count = 3, | ||
2658 | .info = ad198x_mux_enum_info, | ||
2659 | .get = ad198x_mux_enum_get, | ||
2660 | .put = ad198x_mux_enum_put, | ||
2661 | }, | ||
2662 | { } /* end */ | ||
2663 | }; | ||
2664 | |||
2665 | static int ad1988_spdif_playback_source_info(struct snd_kcontrol *kcontrol, | ||
2666 | struct snd_ctl_elem_info *uinfo) | ||
2667 | { | ||
2668 | static const char * const texts[] = { | ||
2669 | "PCM", "ADC1", "ADC2", "ADC3" | ||
2670 | }; | ||
2671 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
2672 | uinfo->count = 1; | ||
2673 | uinfo->value.enumerated.items = 4; | ||
2674 | if (uinfo->value.enumerated.item >= 4) | ||
2675 | uinfo->value.enumerated.item = 3; | ||
2676 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
2677 | return 0; | ||
2678 | } | ||
2679 | |||
2680 | static int ad1988_spdif_playback_source_get(struct snd_kcontrol *kcontrol, | ||
2681 | struct snd_ctl_elem_value *ucontrol) | ||
2682 | { | ||
2683 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2684 | unsigned int sel; | ||
2685 | |||
2686 | sel = snd_hda_codec_read(codec, 0x1d, 0, AC_VERB_GET_AMP_GAIN_MUTE, | ||
2687 | AC_AMP_GET_INPUT); | ||
2688 | if (!(sel & 0x80)) | ||
2689 | ucontrol->value.enumerated.item[0] = 0; | ||
2690 | else { | ||
2691 | sel = snd_hda_codec_read(codec, 0x0b, 0, | ||
2692 | AC_VERB_GET_CONNECT_SEL, 0); | ||
2693 | if (sel < 3) | ||
2694 | sel++; | ||
2695 | else | ||
2696 | sel = 0; | ||
2697 | ucontrol->value.enumerated.item[0] = sel; | ||
2698 | } | ||
2699 | return 0; | ||
2700 | } | ||
2701 | |||
2702 | static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol, | ||
2703 | struct snd_ctl_elem_value *ucontrol) | ||
2704 | { | ||
2705 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2706 | unsigned int val, sel; | ||
2707 | int change; | ||
2708 | |||
2709 | val = ucontrol->value.enumerated.item[0]; | ||
2710 | if (val > 3) | ||
2711 | return -EINVAL; | ||
2712 | if (!val) { | ||
2713 | sel = snd_hda_codec_read(codec, 0x1d, 0, | ||
2714 | AC_VERB_GET_AMP_GAIN_MUTE, | ||
2715 | AC_AMP_GET_INPUT); | ||
2716 | change = sel & 0x80; | ||
2717 | if (change) { | ||
2718 | snd_hda_codec_write_cache(codec, 0x1d, 0, | ||
2719 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
2720 | AMP_IN_UNMUTE(0)); | ||
2721 | snd_hda_codec_write_cache(codec, 0x1d, 0, | ||
2722 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
2723 | AMP_IN_MUTE(1)); | ||
2724 | } | ||
2725 | } else { | ||
2726 | sel = snd_hda_codec_read(codec, 0x1d, 0, | ||
2727 | AC_VERB_GET_AMP_GAIN_MUTE, | ||
2728 | AC_AMP_GET_INPUT | 0x01); | ||
2729 | change = sel & 0x80; | ||
2730 | if (change) { | ||
2731 | snd_hda_codec_write_cache(codec, 0x1d, 0, | ||
2732 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
2733 | AMP_IN_MUTE(0)); | ||
2734 | snd_hda_codec_write_cache(codec, 0x1d, 0, | ||
2735 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
2736 | AMP_IN_UNMUTE(1)); | ||
2737 | } | ||
2738 | sel = snd_hda_codec_read(codec, 0x0b, 0, | ||
2739 | AC_VERB_GET_CONNECT_SEL, 0) + 1; | ||
2740 | change |= sel != val; | ||
2741 | if (change) | ||
2742 | snd_hda_codec_write_cache(codec, 0x0b, 0, | ||
2743 | AC_VERB_SET_CONNECT_SEL, | ||
2744 | val - 1); | ||
2745 | } | ||
2746 | return change; | ||
2747 | } | ||
2748 | |||
2749 | static const struct snd_kcontrol_new ad1988_spdif_out_mixers[] = { | ||
2750 | HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
2751 | { | ||
2752 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2753 | .name = "IEC958 Playback Source", | ||
2754 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, | ||
2755 | .info = ad1988_spdif_playback_source_info, | ||
2756 | .get = ad1988_spdif_playback_source_get, | ||
2757 | .put = ad1988_spdif_playback_source_put, | ||
2758 | }, | ||
2759 | { } /* end */ | ||
2760 | }; | ||
2761 | |||
2762 | static const struct snd_kcontrol_new ad1988_spdif_in_mixers[] = { | ||
2763 | HDA_CODEC_VOLUME("IEC958 Capture Volume", 0x1c, 0x0, HDA_INPUT), | ||
2764 | { } /* end */ | ||
2765 | }; | ||
2766 | |||
2767 | static const struct snd_kcontrol_new ad1989_spdif_out_mixers[] = { | ||
2768 | HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
2769 | HDA_CODEC_VOLUME("HDMI Playback Volume", 0x1d, 0x0, HDA_OUTPUT), | ||
2770 | { } /* end */ | ||
2771 | }; | ||
2772 | |||
2773 | /* | ||
2774 | * initialization verbs | ||
2775 | */ | ||
2776 | |||
2777 | /* | ||
2778 | * for 6-stack (+dig) | ||
2779 | */ | ||
2780 | static const struct hda_verb ad1988_6stack_init_verbs[] = { | ||
2781 | /* Front, Surround, CLFE, side DAC; unmute as default */ | ||
2782 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2783 | {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2784 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2785 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2786 | /* Port-A front headphon path */ | ||
2787 | {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ | ||
2788 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2789 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2790 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2791 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
2792 | /* Port-D line-out path */ | ||
2793 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2794 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2795 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2796 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2797 | /* Port-F surround path */ | ||
2798 | {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2799 | {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2800 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2801 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2802 | /* Port-G CLFE path */ | ||
2803 | {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2804 | {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2805 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2806 | {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2807 | /* Port-H side path */ | ||
2808 | {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2809 | {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2810 | {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2811 | {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2812 | /* Mono out path */ | ||
2813 | {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */ | ||
2814 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2815 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2816 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2817 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */ | ||
2818 | /* Port-B front mic-in path */ | ||
2819 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
2820 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
2821 | {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
2822 | /* Port-C line-in path */ | ||
2823 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
2824 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
2825 | {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
2826 | {0x33, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
2827 | /* Port-E mic-in path */ | ||
2828 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
2829 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
2830 | {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
2831 | {0x34, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
2832 | /* Analog CD Input */ | ||
2833 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
2834 | /* Analog Mix output amp */ | ||
2835 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ | ||
2836 | |||
2837 | { } | ||
2838 | }; | ||
2839 | |||
2840 | static const struct hda_verb ad1988_6stack_fp_init_verbs[] = { | ||
2841 | /* Headphone; unmute as default */ | ||
2842 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2843 | /* Port-A front headphon path */ | ||
2844 | {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ | ||
2845 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2846 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2847 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2848 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
2849 | |||
2850 | { } | ||
2851 | }; | ||
2852 | |||
2853 | static const struct hda_verb ad1988_capture_init_verbs[] = { | ||
2854 | /* mute analog mix */ | ||
2855 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2856 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2857 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
2858 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
2859 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
2860 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
2861 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, | ||
2862 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, | ||
2863 | /* select ADCs - front-mic */ | ||
2864 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
2865 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
2866 | {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
2867 | |||
2868 | { } | ||
2869 | }; | ||
2870 | |||
2871 | static const struct hda_verb ad1988_spdif_init_verbs[] = { | ||
2872 | /* SPDIF out sel */ | ||
2873 | {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */ | ||
2874 | {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */ | ||
2875 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
2876 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2877 | /* SPDIF out pin */ | ||
2878 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | ||
2879 | |||
2880 | { } | ||
2881 | }; | ||
2882 | |||
2883 | static const struct hda_verb ad1988_spdif_in_init_verbs[] = { | ||
2884 | /* unmute SPDIF input pin */ | ||
2885 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
2886 | { } | ||
2887 | }; | ||
2888 | |||
2889 | /* AD1989 has no ADC -> SPDIF route */ | ||
2890 | static const struct hda_verb ad1989_spdif_init_verbs[] = { | ||
2891 | /* SPDIF-1 out pin */ | ||
2892 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
2893 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | ||
2894 | /* SPDIF-2/HDMI out pin */ | ||
2895 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
2896 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | ||
2897 | { } | ||
2898 | }; | ||
2899 | |||
2900 | /* | ||
2901 | * verbs for 3stack (+dig) | ||
2902 | */ | ||
2903 | static const struct hda_verb ad1988_3stack_ch2_init[] = { | ||
2904 | /* set port-C to line-in */ | ||
2905 | { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
2906 | { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, | ||
2907 | /* set port-E to mic-in */ | ||
2908 | { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
2909 | { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, | ||
2910 | { } /* end */ | ||
2911 | }; | ||
2912 | |||
2913 | static const struct hda_verb ad1988_3stack_ch6_init[] = { | ||
2914 | /* set port-C to surround out */ | ||
2915 | { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
2916 | { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
2917 | /* set port-E to CLFE out */ | ||
2918 | { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
2919 | { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
2920 | { } /* end */ | ||
2921 | }; | ||
2922 | |||
2923 | static const struct hda_channel_mode ad1988_3stack_modes[2] = { | ||
2924 | { 2, ad1988_3stack_ch2_init }, | ||
2925 | { 6, ad1988_3stack_ch6_init }, | ||
2926 | }; | ||
2927 | |||
2928 | static const struct hda_verb ad1988_3stack_init_verbs[] = { | ||
2929 | /* Front, Surround, CLFE, side DAC; unmute as default */ | ||
2930 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2931 | {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2932 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2933 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2934 | /* Port-A front headphon path */ | ||
2935 | {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ | ||
2936 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2937 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2938 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2939 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
2940 | /* Port-D line-out path */ | ||
2941 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2942 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2943 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2944 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2945 | /* Mono out path */ | ||
2946 | {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */ | ||
2947 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2948 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2949 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2950 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */ | ||
2951 | /* Port-B front mic-in path */ | ||
2952 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
2953 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
2954 | {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
2955 | /* Port-C line-in/surround path - 6ch mode as default */ | ||
2956 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2957 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2958 | {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
2959 | {0x31, AC_VERB_SET_CONNECT_SEL, 0x0}, /* output sel: DAC 0x05 */ | ||
2960 | {0x33, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
2961 | /* Port-E mic-in/CLFE path - 6ch mode as default */ | ||
2962 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2963 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2964 | {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
2965 | {0x32, AC_VERB_SET_CONNECT_SEL, 0x1}, /* output sel: DAC 0x0a */ | ||
2966 | {0x34, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
2967 | /* mute analog mix */ | ||
2968 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2969 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2970 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
2971 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
2972 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
2973 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
2974 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, | ||
2975 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, | ||
2976 | /* select ADCs - front-mic */ | ||
2977 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
2978 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
2979 | {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
2980 | /* Analog Mix output amp */ | ||
2981 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ | ||
2982 | { } | ||
2983 | }; | ||
2984 | |||
2985 | /* | ||
2986 | * verbs for laptop mode (+dig) | ||
2987 | */ | ||
2988 | static const struct hda_verb ad1988_laptop_hp_on[] = { | ||
2989 | /* unmute port-A and mute port-D */ | ||
2990 | { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
2991 | { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
2992 | { } /* end */ | ||
2993 | }; | ||
2994 | static const struct hda_verb ad1988_laptop_hp_off[] = { | ||
2995 | /* mute port-A and unmute port-D */ | ||
2996 | { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
2997 | { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
2998 | { } /* end */ | ||
2999 | }; | ||
3000 | |||
3001 | #define AD1988_HP_EVENT 0x01 | ||
3002 | |||
3003 | static const struct hda_verb ad1988_laptop_init_verbs[] = { | ||
3004 | /* Front, Surround, CLFE, side DAC; unmute as default */ | ||
3005 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
3006 | {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
3007 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
3008 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
3009 | /* Port-A front headphon path */ | ||
3010 | {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ | ||
3011 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
3012 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
3013 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
3014 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
3015 | /* unsolicited event for pin-sense */ | ||
3016 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1988_HP_EVENT }, | ||
3017 | /* Port-D line-out path + EAPD */ | ||
3018 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
3019 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
3020 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
3021 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
3022 | {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x00}, /* EAPD-off */ | ||
3023 | /* Mono out path */ | ||
3024 | {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */ | ||
3025 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
3026 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
3027 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
3028 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */ | ||
3029 | /* Port-B mic-in path */ | ||
3030 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
3031 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
3032 | {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3033 | /* Port-C docking station - try to output */ | ||
3034 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
3035 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
3036 | {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3037 | {0x33, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
3038 | /* mute analog mix */ | ||
3039 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
3040 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
3041 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
3042 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
3043 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
3044 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
3045 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, | ||
3046 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, | ||
3047 | /* select ADCs - mic */ | ||
3048 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
3049 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
3050 | {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
3051 | /* Analog Mix output amp */ | ||
3052 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ | ||
3053 | { } | ||
3054 | }; | ||
3055 | |||
3056 | static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res) | ||
3057 | { | ||
3058 | if ((res >> 26) != AD1988_HP_EVENT) | ||
3059 | return; | ||
3060 | if (snd_hda_jack_detect(codec, 0x11)) | ||
3061 | snd_hda_sequence_write(codec, ad1988_laptop_hp_on); | ||
3062 | else | ||
3063 | snd_hda_sequence_write(codec, ad1988_laptop_hp_off); | ||
3064 | } | ||
3065 | |||
3066 | #ifdef CONFIG_PM | ||
3067 | static const struct hda_amp_list ad1988_loopbacks[] = { | ||
3068 | { 0x20, HDA_INPUT, 0 }, /* Front Mic */ | ||
3069 | { 0x20, HDA_INPUT, 1 }, /* Line */ | ||
3070 | { 0x20, HDA_INPUT, 4 }, /* Mic */ | ||
3071 | { 0x20, HDA_INPUT, 6 }, /* CD */ | ||
3072 | { } /* end */ | ||
3073 | }; | ||
3074 | #endif | ||
3075 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | 683 | #endif /* ENABLE_AD_STATIC_QUIRKS */ |
3076 | 684 | ||
3077 | static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol, | 685 | static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol, |
@@ -3220,7 +828,34 @@ static int ad1988_add_spdif_mux_ctl(struct hda_codec *codec) | |||
3220 | /* | 828 | /* |
3221 | */ | 829 | */ |
3222 | 830 | ||
3223 | static int ad1988_parse_auto_config(struct hda_codec *codec) | 831 | enum { |
832 | AD1988_FIXUP_6STACK_DIG, | ||
833 | }; | ||
834 | |||
835 | static const struct hda_fixup ad1988_fixups[] = { | ||
836 | [AD1988_FIXUP_6STACK_DIG] = { | ||
837 | .type = HDA_FIXUP_PINS, | ||
838 | .v.pins = (const struct hda_pintbl[]) { | ||
839 | { 0x11, 0x02214130 }, /* front-hp */ | ||
840 | { 0x12, 0x01014010 }, /* line-out */ | ||
841 | { 0x14, 0x02a19122 }, /* front-mic */ | ||
842 | { 0x15, 0x01813021 }, /* line-in */ | ||
843 | { 0x16, 0x01011012 }, /* line-out */ | ||
844 | { 0x17, 0x01a19020 }, /* mic */ | ||
845 | { 0x1b, 0x0145f1f0 }, /* SPDIF */ | ||
846 | { 0x24, 0x01016011 }, /* line-out */ | ||
847 | { 0x25, 0x01012013 }, /* line-out */ | ||
848 | { } | ||
849 | } | ||
850 | }, | ||
851 | }; | ||
852 | |||
853 | static const struct hda_model_fixup ad1988_fixup_models[] = { | ||
854 | { .id = AD1988_FIXUP_6STACK_DIG, .name = "6stack-dig" }, | ||
855 | {} | ||
856 | }; | ||
857 | |||
858 | static int patch_ad1988(struct hda_codec *codec) | ||
3224 | { | 859 | { |
3225 | struct ad198x_spec *spec; | 860 | struct ad198x_spec *spec; |
3226 | int err; | 861 | int err; |
@@ -3234,12 +869,19 @@ static int ad1988_parse_auto_config(struct hda_codec *codec) | |||
3234 | spec->gen.mixer_merge_nid = 0x21; | 869 | spec->gen.mixer_merge_nid = 0x21; |
3235 | spec->gen.beep_nid = 0x10; | 870 | spec->gen.beep_nid = 0x10; |
3236 | set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); | 871 | set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); |
872 | |||
873 | snd_hda_pick_fixup(codec, ad1988_fixup_models, NULL, ad1988_fixups); | ||
874 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); | ||
875 | |||
3237 | err = ad198x_parse_auto_config(codec); | 876 | err = ad198x_parse_auto_config(codec); |
3238 | if (err < 0) | 877 | if (err < 0) |
3239 | goto error; | 878 | goto error; |
3240 | err = ad1988_add_spdif_mux_ctl(codec); | 879 | err = ad1988_add_spdif_mux_ctl(codec); |
3241 | if (err < 0) | 880 | if (err < 0) |
3242 | goto error; | 881 | goto error; |
882 | |||
883 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); | ||
884 | |||
3243 | return 0; | 885 | return 0; |
3244 | 886 | ||
3245 | error: | 887 | error: |
@@ -3247,169 +889,6 @@ static int ad1988_parse_auto_config(struct hda_codec *codec) | |||
3247 | return err; | 889 | return err; |
3248 | } | 890 | } |
3249 | 891 | ||
3250 | /* | ||
3251 | */ | ||
3252 | |||
3253 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
3254 | static const char * const ad1988_models[AD1988_MODEL_LAST] = { | ||
3255 | [AD1988_6STACK] = "6stack", | ||
3256 | [AD1988_6STACK_DIG] = "6stack-dig", | ||
3257 | [AD1988_3STACK] = "3stack", | ||
3258 | [AD1988_3STACK_DIG] = "3stack-dig", | ||
3259 | [AD1988_LAPTOP] = "laptop", | ||
3260 | [AD1988_LAPTOP_DIG] = "laptop-dig", | ||
3261 | [AD1988_AUTO] = "auto", | ||
3262 | }; | ||
3263 | |||
3264 | static const struct snd_pci_quirk ad1988_cfg_tbl[] = { | ||
3265 | SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG), | ||
3266 | SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG), | ||
3267 | SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG), | ||
3268 | SND_PCI_QUIRK(0x1043, 0x82c0, "Asus M3N-HT Deluxe", AD1988_6STACK_DIG), | ||
3269 | SND_PCI_QUIRK(0x1043, 0x8311, "Asus P5Q-Premium/Pro", AD1988_6STACK_DIG), | ||
3270 | {} | ||
3271 | }; | ||
3272 | |||
3273 | static int patch_ad1988(struct hda_codec *codec) | ||
3274 | { | ||
3275 | struct ad198x_spec *spec; | ||
3276 | int err, board_config; | ||
3277 | |||
3278 | board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST, | ||
3279 | ad1988_models, ad1988_cfg_tbl); | ||
3280 | if (board_config < 0) { | ||
3281 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
3282 | codec->chip_name); | ||
3283 | board_config = AD1988_AUTO; | ||
3284 | } | ||
3285 | |||
3286 | if (board_config == AD1988_AUTO) | ||
3287 | return ad1988_parse_auto_config(codec); | ||
3288 | |||
3289 | err = alloc_ad_spec(codec); | ||
3290 | if (err < 0) | ||
3291 | return err; | ||
3292 | spec = codec->spec; | ||
3293 | |||
3294 | if (is_rev2(codec)) | ||
3295 | snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n"); | ||
3296 | |||
3297 | err = snd_hda_attach_beep_device(codec, 0x10); | ||
3298 | if (err < 0) { | ||
3299 | ad198x_free(codec); | ||
3300 | return err; | ||
3301 | } | ||
3302 | set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); | ||
3303 | |||
3304 | if (!spec->multiout.hp_nid) | ||
3305 | spec->multiout.hp_nid = ad1988_alt_dac_nid[0]; | ||
3306 | switch (board_config) { | ||
3307 | case AD1988_6STACK: | ||
3308 | case AD1988_6STACK_DIG: | ||
3309 | spec->multiout.max_channels = 8; | ||
3310 | spec->multiout.num_dacs = 4; | ||
3311 | if (is_rev2(codec)) | ||
3312 | spec->multiout.dac_nids = ad1988_6stack_dac_nids_rev2; | ||
3313 | else | ||
3314 | spec->multiout.dac_nids = ad1988_6stack_dac_nids; | ||
3315 | spec->input_mux = &ad1988_6stack_capture_source; | ||
3316 | spec->num_mixers = 2; | ||
3317 | if (is_rev2(codec)) | ||
3318 | spec->mixers[0] = ad1988_6stack_mixers1_rev2; | ||
3319 | else | ||
3320 | spec->mixers[0] = ad1988_6stack_mixers1; | ||
3321 | spec->mixers[1] = ad1988_6stack_mixers2; | ||
3322 | spec->num_init_verbs = 1; | ||
3323 | spec->init_verbs[0] = ad1988_6stack_init_verbs; | ||
3324 | if (board_config == AD1988_6STACK_DIG) { | ||
3325 | spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; | ||
3326 | spec->dig_in_nid = AD1988_SPDIF_IN; | ||
3327 | } | ||
3328 | break; | ||
3329 | case AD1988_3STACK: | ||
3330 | case AD1988_3STACK_DIG: | ||
3331 | spec->multiout.max_channels = 6; | ||
3332 | spec->multiout.num_dacs = 3; | ||
3333 | if (is_rev2(codec)) | ||
3334 | spec->multiout.dac_nids = ad1988_3stack_dac_nids_rev2; | ||
3335 | else | ||
3336 | spec->multiout.dac_nids = ad1988_3stack_dac_nids; | ||
3337 | spec->input_mux = &ad1988_6stack_capture_source; | ||
3338 | spec->channel_mode = ad1988_3stack_modes; | ||
3339 | spec->num_channel_mode = ARRAY_SIZE(ad1988_3stack_modes); | ||
3340 | spec->num_mixers = 2; | ||
3341 | if (is_rev2(codec)) | ||
3342 | spec->mixers[0] = ad1988_3stack_mixers1_rev2; | ||
3343 | else | ||
3344 | spec->mixers[0] = ad1988_3stack_mixers1; | ||
3345 | spec->mixers[1] = ad1988_3stack_mixers2; | ||
3346 | spec->num_init_verbs = 1; | ||
3347 | spec->init_verbs[0] = ad1988_3stack_init_verbs; | ||
3348 | if (board_config == AD1988_3STACK_DIG) | ||
3349 | spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; | ||
3350 | break; | ||
3351 | case AD1988_LAPTOP: | ||
3352 | case AD1988_LAPTOP_DIG: | ||
3353 | spec->multiout.max_channels = 2; | ||
3354 | spec->multiout.num_dacs = 1; | ||
3355 | spec->multiout.dac_nids = ad1988_3stack_dac_nids; | ||
3356 | spec->input_mux = &ad1988_laptop_capture_source; | ||
3357 | spec->num_mixers = 1; | ||
3358 | spec->mixers[0] = ad1988_laptop_mixers; | ||
3359 | codec->inv_eapd = 1; /* inverted EAPD */ | ||
3360 | spec->num_init_verbs = 1; | ||
3361 | spec->init_verbs[0] = ad1988_laptop_init_verbs; | ||
3362 | if (board_config == AD1988_LAPTOP_DIG) | ||
3363 | spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; | ||
3364 | break; | ||
3365 | } | ||
3366 | |||
3367 | spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids); | ||
3368 | spec->adc_nids = ad1988_adc_nids; | ||
3369 | spec->capsrc_nids = ad1988_capsrc_nids; | ||
3370 | spec->mixers[spec->num_mixers++] = ad1988_capture_mixers; | ||
3371 | spec->init_verbs[spec->num_init_verbs++] = ad1988_capture_init_verbs; | ||
3372 | if (spec->multiout.dig_out_nid) { | ||
3373 | if (codec->vendor_id >= 0x11d4989a) { | ||
3374 | spec->mixers[spec->num_mixers++] = | ||
3375 | ad1989_spdif_out_mixers; | ||
3376 | spec->init_verbs[spec->num_init_verbs++] = | ||
3377 | ad1989_spdif_init_verbs; | ||
3378 | codec->slave_dig_outs = ad1989b_slave_dig_outs; | ||
3379 | } else { | ||
3380 | spec->mixers[spec->num_mixers++] = | ||
3381 | ad1988_spdif_out_mixers; | ||
3382 | spec->init_verbs[spec->num_init_verbs++] = | ||
3383 | ad1988_spdif_init_verbs; | ||
3384 | } | ||
3385 | } | ||
3386 | if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) { | ||
3387 | spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers; | ||
3388 | spec->init_verbs[spec->num_init_verbs++] = | ||
3389 | ad1988_spdif_in_init_verbs; | ||
3390 | } | ||
3391 | |||
3392 | codec->patch_ops = ad198x_patch_ops; | ||
3393 | switch (board_config) { | ||
3394 | case AD1988_LAPTOP: | ||
3395 | case AD1988_LAPTOP_DIG: | ||
3396 | codec->patch_ops.unsol_event = ad1988_laptop_unsol_event; | ||
3397 | break; | ||
3398 | } | ||
3399 | #ifdef CONFIG_PM | ||
3400 | spec->loopback.amplist = ad1988_loopbacks; | ||
3401 | #endif | ||
3402 | spec->vmaster_nid = 0x04; | ||
3403 | |||
3404 | codec->no_trigger_sense = 1; | ||
3405 | codec->no_sticky_stream = 1; | ||
3406 | |||
3407 | return 0; | ||
3408 | } | ||
3409 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
3410 | #define patch_ad1988 ad1988_parse_auto_config | ||
3411 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
3412 | |||
3413 | 892 | ||
3414 | /* | 893 | /* |
3415 | * AD1884 / AD1984 | 894 | * AD1884 / AD1984 |
@@ -3423,167 +902,19 @@ static int patch_ad1988(struct hda_codec *codec) | |||
3423 | * | 902 | * |
3424 | * AD1984 = AD1884 + two digital mic-ins | 903 | * AD1984 = AD1884 + two digital mic-ins |
3425 | * | 904 | * |
3426 | * FIXME: | 905 | * AD1883 / AD1884A / AD1984A / AD1984B |
3427 | * For simplicity, we share the single DAC for both HP and line-outs | 906 | * |
3428 | * right now. The inidividual playbacks could be easily implemented, | 907 | * port-B (0x14) - front mic-in |
3429 | * but no build-up framework is given, so far. | 908 | * port-E (0x1c) - rear mic-in |
3430 | */ | 909 | * port-F (0x16) - CD / ext out |
3431 | 910 | * port-C (0x15) - rear line-in | |
3432 | #ifdef ENABLE_AD_STATIC_QUIRKS | 911 | * port-D (0x12) - rear line-out |
3433 | static const hda_nid_t ad1884_dac_nids[1] = { | 912 | * port-A (0x11) - front hp-out |
3434 | 0x04, | 913 | * |
3435 | }; | 914 | * AD1984A = AD1884A + digital-mic |
3436 | 915 | * AD1883 = equivalent with AD1984A | |
3437 | static const hda_nid_t ad1884_adc_nids[2] = { | 916 | * AD1984B = AD1984A + extra SPDIF-out |
3438 | 0x08, 0x09, | ||
3439 | }; | ||
3440 | |||
3441 | static const hda_nid_t ad1884_capsrc_nids[2] = { | ||
3442 | 0x0c, 0x0d, | ||
3443 | }; | ||
3444 | |||
3445 | #define AD1884_SPDIF_OUT 0x02 | ||
3446 | |||
3447 | static const struct hda_input_mux ad1884_capture_source = { | ||
3448 | .num_items = 4, | ||
3449 | .items = { | ||
3450 | { "Front Mic", 0x0 }, | ||
3451 | { "Mic", 0x1 }, | ||
3452 | { "CD", 0x2 }, | ||
3453 | { "Mix", 0x3 }, | ||
3454 | }, | ||
3455 | }; | ||
3456 | |||
3457 | static const struct snd_kcontrol_new ad1884_base_mixers[] = { | ||
3458 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
3459 | /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */ | ||
3460 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
3461 | HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
3462 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), | ||
3463 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), | ||
3464 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
3465 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
3466 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
3467 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
3468 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT), | ||
3469 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT), | ||
3470 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT), | ||
3471 | HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT), | ||
3472 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
3473 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
3474 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3475 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3476 | { | ||
3477 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3478 | /* The multiple "Capture Source" controls confuse alsamixer | ||
3479 | * So call somewhat different.. | ||
3480 | */ | ||
3481 | /* .name = "Capture Source", */ | ||
3482 | .name = "Input Source", | ||
3483 | .count = 2, | ||
3484 | .info = ad198x_mux_enum_info, | ||
3485 | .get = ad198x_mux_enum_get, | ||
3486 | .put = ad198x_mux_enum_put, | ||
3487 | }, | ||
3488 | /* SPDIF controls */ | ||
3489 | HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
3490 | { | ||
3491 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3492 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
3493 | /* identical with ad1983 */ | ||
3494 | .info = ad1983_spdif_route_info, | ||
3495 | .get = ad1983_spdif_route_get, | ||
3496 | .put = ad1983_spdif_route_put, | ||
3497 | }, | ||
3498 | { } /* end */ | ||
3499 | }; | ||
3500 | |||
3501 | static const struct snd_kcontrol_new ad1984_dmic_mixers[] = { | ||
3502 | HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT), | ||
3503 | HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT), | ||
3504 | HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0, | ||
3505 | HDA_INPUT), | ||
3506 | HDA_CODEC_MUTE_IDX("Digital Mic Capture Switch", 1, 0x06, 0x0, | ||
3507 | HDA_INPUT), | ||
3508 | { } /* end */ | ||
3509 | }; | ||
3510 | |||
3511 | /* | ||
3512 | * initialization verbs | ||
3513 | */ | 917 | */ |
3514 | static const struct hda_verb ad1884_init_verbs[] = { | ||
3515 | /* DACs; mute as default */ | ||
3516 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3517 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3518 | /* Port-A (HP) mixer */ | ||
3519 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3520 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3521 | /* Port-A pin */ | ||
3522 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
3523 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
3524 | /* HP selector - select DAC2 */ | ||
3525 | {0x22, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
3526 | /* Port-D (Line-out) mixer */ | ||
3527 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3528 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3529 | /* Port-D pin */ | ||
3530 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
3531 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
3532 | /* Mono-out mixer */ | ||
3533 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3534 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3535 | /* Mono-out pin */ | ||
3536 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
3537 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
3538 | /* Mono selector */ | ||
3539 | {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
3540 | /* Port-B (front mic) pin */ | ||
3541 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
3542 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3543 | /* Port-C (rear mic) pin */ | ||
3544 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
3545 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3546 | /* Analog mixer; mute as default */ | ||
3547 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
3548 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
3549 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
3550 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
3551 | /* Analog Mix output amp */ | ||
3552 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ | ||
3553 | /* SPDIF output selector */ | ||
3554 | {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */ | ||
3555 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | ||
3556 | { } /* end */ | ||
3557 | }; | ||
3558 | |||
3559 | #ifdef CONFIG_PM | ||
3560 | static const struct hda_amp_list ad1884_loopbacks[] = { | ||
3561 | { 0x20, HDA_INPUT, 0 }, /* Front Mic */ | ||
3562 | { 0x20, HDA_INPUT, 1 }, /* Mic */ | ||
3563 | { 0x20, HDA_INPUT, 2 }, /* CD */ | ||
3564 | { 0x20, HDA_INPUT, 4 }, /* Docking */ | ||
3565 | { } /* end */ | ||
3566 | }; | ||
3567 | #endif | ||
3568 | |||
3569 | static const char * const ad1884_slave_vols[] = { | ||
3570 | "PCM", "Mic", "Mono", "Front Mic", "Mic", "CD", | ||
3571 | "Internal Mic", "Dock Mic", /* "Beep", */ "IEC958", | ||
3572 | NULL | ||
3573 | }; | ||
3574 | |||
3575 | enum { | ||
3576 | AD1884_AUTO, | ||
3577 | AD1884_BASIC, | ||
3578 | AD1884_MODELS | ||
3579 | }; | ||
3580 | |||
3581 | static const char * const ad1884_models[AD1884_MODELS] = { | ||
3582 | [AD1884_AUTO] = "auto", | ||
3583 | [AD1884_BASIC] = "basic", | ||
3584 | }; | ||
3585 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
3586 | |||
3587 | 918 | ||
3588 | /* set the upper-limit for mixer amp to 0dB for avoiding the possible | 919 | /* set the upper-limit for mixer amp to 0dB for avoiding the possible |
3589 | * damage by overloading | 920 | * damage by overloading |
@@ -3599,14 +930,34 @@ static void ad1884_fixup_amp_override(struct hda_codec *codec, | |||
3599 | (1 << AC_AMPCAP_MUTE_SHIFT)); | 930 | (1 << AC_AMPCAP_MUTE_SHIFT)); |
3600 | } | 931 | } |
3601 | 932 | ||
933 | /* toggle GPIO1 according to the mute state */ | ||
934 | static void ad1884_vmaster_hp_gpio_hook(void *private_data, int enabled) | ||
935 | { | ||
936 | struct hda_codec *codec = private_data; | ||
937 | struct ad198x_spec *spec = codec->spec; | ||
938 | |||
939 | if (spec->eapd_nid) | ||
940 | ad_vmaster_eapd_hook(private_data, enabled); | ||
941 | snd_hda_codec_update_cache(codec, 0x01, 0, | ||
942 | AC_VERB_SET_GPIO_DATA, | ||
943 | enabled ? 0x00 : 0x02); | ||
944 | } | ||
945 | |||
3602 | static void ad1884_fixup_hp_eapd(struct hda_codec *codec, | 946 | static void ad1884_fixup_hp_eapd(struct hda_codec *codec, |
3603 | const struct hda_fixup *fix, int action) | 947 | const struct hda_fixup *fix, int action) |
3604 | { | 948 | { |
3605 | struct ad198x_spec *spec = codec->spec; | 949 | struct ad198x_spec *spec = codec->spec; |
950 | static const struct hda_verb gpio_init_verbs[] = { | ||
951 | {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, | ||
952 | {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, | ||
953 | {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, | ||
954 | {}, | ||
955 | }; | ||
3606 | 956 | ||
3607 | switch (action) { | 957 | switch (action) { |
3608 | case HDA_FIXUP_ACT_PRE_PROBE: | 958 | case HDA_FIXUP_ACT_PRE_PROBE: |
3609 | spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook; | 959 | spec->gen.vmaster_mute.hook = ad1884_vmaster_hp_gpio_hook; |
960 | snd_hda_sequence_write_cache(codec, gpio_init_verbs); | ||
3610 | break; | 961 | break; |
3611 | case HDA_FIXUP_ACT_PROBE: | 962 | case HDA_FIXUP_ACT_PROBE: |
3612 | if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) | 963 | if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) |
@@ -3617,9 +968,18 @@ static void ad1884_fixup_hp_eapd(struct hda_codec *codec, | |||
3617 | } | 968 | } |
3618 | } | 969 | } |
3619 | 970 | ||
971 | /* set magic COEFs for dmic */ | ||
972 | static const struct hda_verb ad1884_dmic_init_verbs[] = { | ||
973 | {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7}, | ||
974 | {0x01, AC_VERB_SET_PROC_COEF, 0x08}, | ||
975 | {} | ||
976 | }; | ||
977 | |||
3620 | enum { | 978 | enum { |
3621 | AD1884_FIXUP_AMP_OVERRIDE, | 979 | AD1884_FIXUP_AMP_OVERRIDE, |
3622 | AD1884_FIXUP_HP_EAPD, | 980 | AD1884_FIXUP_HP_EAPD, |
981 | AD1884_FIXUP_DMIC_COEF, | ||
982 | AD1884_FIXUP_HP_TOUCHSMART, | ||
3623 | }; | 983 | }; |
3624 | 984 | ||
3625 | static const struct hda_fixup ad1884_fixups[] = { | 985 | static const struct hda_fixup ad1884_fixups[] = { |
@@ -3633,15 +993,27 @@ static const struct hda_fixup ad1884_fixups[] = { | |||
3633 | .chained = true, | 993 | .chained = true, |
3634 | .chain_id = AD1884_FIXUP_AMP_OVERRIDE, | 994 | .chain_id = AD1884_FIXUP_AMP_OVERRIDE, |
3635 | }, | 995 | }, |
996 | [AD1884_FIXUP_DMIC_COEF] = { | ||
997 | .type = HDA_FIXUP_VERBS, | ||
998 | .v.verbs = ad1884_dmic_init_verbs, | ||
999 | }, | ||
1000 | [AD1884_FIXUP_HP_TOUCHSMART] = { | ||
1001 | .type = HDA_FIXUP_VERBS, | ||
1002 | .v.verbs = ad1884_dmic_init_verbs, | ||
1003 | .chained = true, | ||
1004 | .chain_id = AD1884_FIXUP_HP_EAPD, | ||
1005 | }, | ||
3636 | }; | 1006 | }; |
3637 | 1007 | ||
3638 | static const struct snd_pci_quirk ad1884_fixup_tbl[] = { | 1008 | static const struct snd_pci_quirk ad1884_fixup_tbl[] = { |
1009 | SND_PCI_QUIRK(0x103c, 0x2a82, "HP Touchsmart", AD1884_FIXUP_HP_TOUCHSMART), | ||
3639 | SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD), | 1010 | SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD), |
1011 | SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1884_FIXUP_DMIC_COEF), | ||
3640 | {} | 1012 | {} |
3641 | }; | 1013 | }; |
3642 | 1014 | ||
3643 | 1015 | ||
3644 | static int ad1884_parse_auto_config(struct hda_codec *codec) | 1016 | static int patch_ad1884(struct hda_codec *codec) |
3645 | { | 1017 | { |
3646 | struct ad198x_spec *spec; | 1018 | struct ad198x_spec *spec; |
3647 | int err; | 1019 | int err; |
@@ -3674,1170 +1046,6 @@ static int ad1884_parse_auto_config(struct hda_codec *codec) | |||
3674 | return err; | 1046 | return err; |
3675 | } | 1047 | } |
3676 | 1048 | ||
3677 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
3678 | static int patch_ad1884_basic(struct hda_codec *codec) | ||
3679 | { | ||
3680 | struct ad198x_spec *spec; | ||
3681 | int err; | ||
3682 | |||
3683 | err = alloc_ad_spec(codec); | ||
3684 | if (err < 0) | ||
3685 | return err; | ||
3686 | spec = codec->spec; | ||
3687 | |||
3688 | err = snd_hda_attach_beep_device(codec, 0x10); | ||
3689 | if (err < 0) { | ||
3690 | ad198x_free(codec); | ||
3691 | return err; | ||
3692 | } | ||
3693 | set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); | ||
3694 | |||
3695 | spec->multiout.max_channels = 2; | ||
3696 | spec->multiout.num_dacs = ARRAY_SIZE(ad1884_dac_nids); | ||
3697 | spec->multiout.dac_nids = ad1884_dac_nids; | ||
3698 | spec->multiout.dig_out_nid = AD1884_SPDIF_OUT; | ||
3699 | spec->num_adc_nids = ARRAY_SIZE(ad1884_adc_nids); | ||
3700 | spec->adc_nids = ad1884_adc_nids; | ||
3701 | spec->capsrc_nids = ad1884_capsrc_nids; | ||
3702 | spec->input_mux = &ad1884_capture_source; | ||
3703 | spec->num_mixers = 1; | ||
3704 | spec->mixers[0] = ad1884_base_mixers; | ||
3705 | spec->num_init_verbs = 1; | ||
3706 | spec->init_verbs[0] = ad1884_init_verbs; | ||
3707 | spec->spdif_route = 0; | ||
3708 | #ifdef CONFIG_PM | ||
3709 | spec->loopback.amplist = ad1884_loopbacks; | ||
3710 | #endif | ||
3711 | spec->vmaster_nid = 0x04; | ||
3712 | /* we need to cover all playback volumes */ | ||
3713 | spec->slave_vols = ad1884_slave_vols; | ||
3714 | /* slaves may contain input volumes, so we can't raise to 0dB blindly */ | ||
3715 | spec->avoid_init_slave_vol = 1; | ||
3716 | |||
3717 | codec->patch_ops = ad198x_patch_ops; | ||
3718 | |||
3719 | codec->no_trigger_sense = 1; | ||
3720 | codec->no_sticky_stream = 1; | ||
3721 | |||
3722 | return 0; | ||
3723 | } | ||
3724 | |||
3725 | static int patch_ad1884(struct hda_codec *codec) | ||
3726 | { | ||
3727 | int board_config; | ||
3728 | |||
3729 | board_config = snd_hda_check_board_config(codec, AD1884_MODELS, | ||
3730 | ad1884_models, NULL); | ||
3731 | if (board_config < 0) { | ||
3732 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
3733 | codec->chip_name); | ||
3734 | board_config = AD1884_AUTO; | ||
3735 | } | ||
3736 | |||
3737 | if (board_config == AD1884_AUTO) | ||
3738 | return ad1884_parse_auto_config(codec); | ||
3739 | else | ||
3740 | return patch_ad1884_basic(codec); | ||
3741 | } | ||
3742 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
3743 | #define patch_ad1884 ad1884_parse_auto_config | ||
3744 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
3745 | |||
3746 | |||
3747 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
3748 | /* | ||
3749 | * Lenovo Thinkpad T61/X61 | ||
3750 | */ | ||
3751 | static const struct hda_input_mux ad1984_thinkpad_capture_source = { | ||
3752 | .num_items = 4, | ||
3753 | .items = { | ||
3754 | { "Mic", 0x0 }, | ||
3755 | { "Internal Mic", 0x1 }, | ||
3756 | { "Mix", 0x3 }, | ||
3757 | { "Dock Mic", 0x4 }, | ||
3758 | }, | ||
3759 | }; | ||
3760 | |||
3761 | |||
3762 | /* | ||
3763 | * Dell Precision T3400 | ||
3764 | */ | ||
3765 | static const struct hda_input_mux ad1984_dell_desktop_capture_source = { | ||
3766 | .num_items = 3, | ||
3767 | .items = { | ||
3768 | { "Front Mic", 0x0 }, | ||
3769 | { "Line-In", 0x1 }, | ||
3770 | { "Mix", 0x3 }, | ||
3771 | }, | ||
3772 | }; | ||
3773 | |||
3774 | |||
3775 | static const struct snd_kcontrol_new ad1984_thinkpad_mixers[] = { | ||
3776 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
3777 | /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */ | ||
3778 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
3779 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
3780 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
3781 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
3782 | HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
3783 | HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
3784 | HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT), | ||
3785 | HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT), | ||
3786 | HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT), | ||
3787 | HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT), | ||
3788 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT), | ||
3789 | HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT), | ||
3790 | HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), | ||
3791 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
3792 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
3793 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3794 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3795 | { | ||
3796 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3797 | /* The multiple "Capture Source" controls confuse alsamixer | ||
3798 | * So call somewhat different.. | ||
3799 | */ | ||
3800 | /* .name = "Capture Source", */ | ||
3801 | .name = "Input Source", | ||
3802 | .count = 2, | ||
3803 | .info = ad198x_mux_enum_info, | ||
3804 | .get = ad198x_mux_enum_get, | ||
3805 | .put = ad198x_mux_enum_put, | ||
3806 | }, | ||
3807 | /* SPDIF controls */ | ||
3808 | HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
3809 | { | ||
3810 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3811 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
3812 | /* identical with ad1983 */ | ||
3813 | .info = ad1983_spdif_route_info, | ||
3814 | .get = ad1983_spdif_route_get, | ||
3815 | .put = ad1983_spdif_route_put, | ||
3816 | }, | ||
3817 | { } /* end */ | ||
3818 | }; | ||
3819 | |||
3820 | /* additional verbs */ | ||
3821 | static const struct hda_verb ad1984_thinkpad_init_verbs[] = { | ||
3822 | /* Port-E (docking station mic) pin */ | ||
3823 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
3824 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
3825 | /* docking mic boost */ | ||
3826 | {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3827 | /* Analog PC Beeper - allow firmware/ACPI beeps */ | ||
3828 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3) | 0x1a}, | ||
3829 | /* Analog mixer - docking mic; mute as default */ | ||
3830 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
3831 | /* enable EAPD bit */ | ||
3832 | {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, | ||
3833 | { } /* end */ | ||
3834 | }; | ||
3835 | |||
3836 | /* | ||
3837 | * Dell Precision T3400 | ||
3838 | */ | ||
3839 | static const struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = { | ||
3840 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
3841 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
3842 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
3843 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), | ||
3844 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), | ||
3845 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
3846 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
3847 | HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
3848 | HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
3849 | HDA_CODEC_VOLUME("Line-In Boost Volume", 0x15, 0x0, HDA_INPUT), | ||
3850 | HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT), | ||
3851 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
3852 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
3853 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3854 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3855 | { | ||
3856 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3857 | /* The multiple "Capture Source" controls confuse alsamixer | ||
3858 | * So call somewhat different.. | ||
3859 | */ | ||
3860 | /* .name = "Capture Source", */ | ||
3861 | .name = "Input Source", | ||
3862 | .count = 2, | ||
3863 | .info = ad198x_mux_enum_info, | ||
3864 | .get = ad198x_mux_enum_get, | ||
3865 | .put = ad198x_mux_enum_put, | ||
3866 | }, | ||
3867 | { } /* end */ | ||
3868 | }; | ||
3869 | |||
3870 | /* Digial MIC ADC NID 0x05 + 0x06 */ | ||
3871 | static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo, | ||
3872 | struct hda_codec *codec, | ||
3873 | unsigned int stream_tag, | ||
3874 | unsigned int format, | ||
3875 | struct snd_pcm_substream *substream) | ||
3876 | { | ||
3877 | snd_hda_codec_setup_stream(codec, 0x05 + substream->number, | ||
3878 | stream_tag, 0, format); | ||
3879 | return 0; | ||
3880 | } | ||
3881 | |||
3882 | static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo, | ||
3883 | struct hda_codec *codec, | ||
3884 | struct snd_pcm_substream *substream) | ||
3885 | { | ||
3886 | snd_hda_codec_cleanup_stream(codec, 0x05 + substream->number); | ||
3887 | return 0; | ||
3888 | } | ||
3889 | |||
3890 | static const struct hda_pcm_stream ad1984_pcm_dmic_capture = { | ||
3891 | .substreams = 2, | ||
3892 | .channels_min = 2, | ||
3893 | .channels_max = 2, | ||
3894 | .nid = 0x05, | ||
3895 | .ops = { | ||
3896 | .prepare = ad1984_pcm_dmic_prepare, | ||
3897 | .cleanup = ad1984_pcm_dmic_cleanup | ||
3898 | }, | ||
3899 | }; | ||
3900 | |||
3901 | static int ad1984_build_pcms(struct hda_codec *codec) | ||
3902 | { | ||
3903 | struct ad198x_spec *spec = codec->spec; | ||
3904 | struct hda_pcm *info; | ||
3905 | int err; | ||
3906 | |||
3907 | err = ad198x_build_pcms(codec); | ||
3908 | if (err < 0) | ||
3909 | return err; | ||
3910 | |||
3911 | info = spec->pcm_rec + codec->num_pcms; | ||
3912 | codec->num_pcms++; | ||
3913 | info->name = "AD1984 Digital Mic"; | ||
3914 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1984_pcm_dmic_capture; | ||
3915 | return 0; | ||
3916 | } | ||
3917 | |||
3918 | /* models */ | ||
3919 | enum { | ||
3920 | AD1984_AUTO, | ||
3921 | AD1984_BASIC, | ||
3922 | AD1984_THINKPAD, | ||
3923 | AD1984_DELL_DESKTOP, | ||
3924 | AD1984_MODELS | ||
3925 | }; | ||
3926 | |||
3927 | static const char * const ad1984_models[AD1984_MODELS] = { | ||
3928 | [AD1984_AUTO] = "auto", | ||
3929 | [AD1984_BASIC] = "basic", | ||
3930 | [AD1984_THINKPAD] = "thinkpad", | ||
3931 | [AD1984_DELL_DESKTOP] = "dell_desktop", | ||
3932 | }; | ||
3933 | |||
3934 | static const struct snd_pci_quirk ad1984_cfg_tbl[] = { | ||
3935 | /* Lenovo Thinkpad T61/X61 */ | ||
3936 | SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD), | ||
3937 | SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP), | ||
3938 | SND_PCI_QUIRK(0x1028, 0x0233, "Dell Latitude E6400", AD1984_DELL_DESKTOP), | ||
3939 | {} | ||
3940 | }; | ||
3941 | |||
3942 | static int patch_ad1984(struct hda_codec *codec) | ||
3943 | { | ||
3944 | struct ad198x_spec *spec; | ||
3945 | int board_config, err; | ||
3946 | |||
3947 | board_config = snd_hda_check_board_config(codec, AD1984_MODELS, | ||
3948 | ad1984_models, ad1984_cfg_tbl); | ||
3949 | if (board_config < 0) { | ||
3950 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
3951 | codec->chip_name); | ||
3952 | board_config = AD1984_AUTO; | ||
3953 | } | ||
3954 | |||
3955 | if (board_config == AD1984_AUTO) | ||
3956 | return ad1884_parse_auto_config(codec); | ||
3957 | |||
3958 | err = patch_ad1884_basic(codec); | ||
3959 | if (err < 0) | ||
3960 | return err; | ||
3961 | spec = codec->spec; | ||
3962 | |||
3963 | switch (board_config) { | ||
3964 | case AD1984_BASIC: | ||
3965 | /* additional digital mics */ | ||
3966 | spec->mixers[spec->num_mixers++] = ad1984_dmic_mixers; | ||
3967 | codec->patch_ops.build_pcms = ad1984_build_pcms; | ||
3968 | break; | ||
3969 | case AD1984_THINKPAD: | ||
3970 | if (codec->subsystem_id == 0x17aa20fb) { | ||
3971 | /* Thinpad X300 does not have the ability to do SPDIF, | ||
3972 | or attach to docking station to use SPDIF */ | ||
3973 | spec->multiout.dig_out_nid = 0; | ||
3974 | } else | ||
3975 | spec->multiout.dig_out_nid = AD1884_SPDIF_OUT; | ||
3976 | spec->input_mux = &ad1984_thinkpad_capture_source; | ||
3977 | spec->mixers[0] = ad1984_thinkpad_mixers; | ||
3978 | spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs; | ||
3979 | spec->analog_beep = 1; | ||
3980 | break; | ||
3981 | case AD1984_DELL_DESKTOP: | ||
3982 | spec->multiout.dig_out_nid = 0; | ||
3983 | spec->input_mux = &ad1984_dell_desktop_capture_source; | ||
3984 | spec->mixers[0] = ad1984_dell_desktop_mixers; | ||
3985 | break; | ||
3986 | } | ||
3987 | return 0; | ||
3988 | } | ||
3989 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
3990 | #define patch_ad1984 ad1884_parse_auto_config | ||
3991 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
3992 | |||
3993 | |||
3994 | /* | ||
3995 | * AD1883 / AD1884A / AD1984A / AD1984B | ||
3996 | * | ||
3997 | * port-B (0x14) - front mic-in | ||
3998 | * port-E (0x1c) - rear mic-in | ||
3999 | * port-F (0x16) - CD / ext out | ||
4000 | * port-C (0x15) - rear line-in | ||
4001 | * port-D (0x12) - rear line-out | ||
4002 | * port-A (0x11) - front hp-out | ||
4003 | * | ||
4004 | * AD1984A = AD1884A + digital-mic | ||
4005 | * AD1883 = equivalent with AD1984A | ||
4006 | * AD1984B = AD1984A + extra SPDIF-out | ||
4007 | * | ||
4008 | * FIXME: | ||
4009 | * We share the single DAC for both HP and line-outs (see AD1884/1984). | ||
4010 | */ | ||
4011 | |||
4012 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
4013 | static const hda_nid_t ad1884a_dac_nids[1] = { | ||
4014 | 0x03, | ||
4015 | }; | ||
4016 | |||
4017 | #define ad1884a_adc_nids ad1884_adc_nids | ||
4018 | #define ad1884a_capsrc_nids ad1884_capsrc_nids | ||
4019 | |||
4020 | #define AD1884A_SPDIF_OUT 0x02 | ||
4021 | |||
4022 | static const struct hda_input_mux ad1884a_capture_source = { | ||
4023 | .num_items = 5, | ||
4024 | .items = { | ||
4025 | { "Front Mic", 0x0 }, | ||
4026 | { "Mic", 0x4 }, | ||
4027 | { "Line", 0x1 }, | ||
4028 | { "CD", 0x2 }, | ||
4029 | { "Mix", 0x3 }, | ||
4030 | }, | ||
4031 | }; | ||
4032 | |||
4033 | static const struct snd_kcontrol_new ad1884a_base_mixers[] = { | ||
4034 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
4035 | HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
4036 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
4037 | HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
4038 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), | ||
4039 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), | ||
4040 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
4041 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
4042 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
4043 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
4044 | HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
4045 | HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
4046 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT), | ||
4047 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT), | ||
4048 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT), | ||
4049 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT), | ||
4050 | HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT), | ||
4051 | HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x0, HDA_INPUT), | ||
4052 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), | ||
4053 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4054 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4055 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
4056 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
4057 | { | ||
4058 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4059 | /* The multiple "Capture Source" controls confuse alsamixer | ||
4060 | * So call somewhat different.. | ||
4061 | */ | ||
4062 | /* .name = "Capture Source", */ | ||
4063 | .name = "Input Source", | ||
4064 | .count = 2, | ||
4065 | .info = ad198x_mux_enum_info, | ||
4066 | .get = ad198x_mux_enum_get, | ||
4067 | .put = ad198x_mux_enum_put, | ||
4068 | }, | ||
4069 | /* SPDIF controls */ | ||
4070 | HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
4071 | { | ||
4072 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4073 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
4074 | /* identical with ad1983 */ | ||
4075 | .info = ad1983_spdif_route_info, | ||
4076 | .get = ad1983_spdif_route_get, | ||
4077 | .put = ad1983_spdif_route_put, | ||
4078 | }, | ||
4079 | { } /* end */ | ||
4080 | }; | ||
4081 | |||
4082 | /* | ||
4083 | * initialization verbs | ||
4084 | */ | ||
4085 | static const struct hda_verb ad1884a_init_verbs[] = { | ||
4086 | /* DACs; unmute as default */ | ||
4087 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4088 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4089 | /* Port-A (HP) mixer - route only from analog mixer */ | ||
4090 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4091 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4092 | /* Port-A pin */ | ||
4093 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4094 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4095 | /* Port-D (Line-out) mixer - route only from analog mixer */ | ||
4096 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4097 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4098 | /* Port-D pin */ | ||
4099 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4100 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4101 | /* Mono-out mixer - route only from analog mixer */ | ||
4102 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4103 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4104 | /* Mono-out pin */ | ||
4105 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4106 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4107 | /* Port-B (front mic) pin */ | ||
4108 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4109 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4110 | /* Port-C (rear line-in) pin */ | ||
4111 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
4112 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4113 | /* Port-E (rear mic) pin */ | ||
4114 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4115 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4116 | {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* no boost */ | ||
4117 | /* Port-F (CD) pin */ | ||
4118 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
4119 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4120 | /* Analog mixer; mute as default */ | ||
4121 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4122 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
4123 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
4124 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
4125 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* aux */ | ||
4126 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
4127 | /* Analog Mix output amp */ | ||
4128 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4129 | /* capture sources */ | ||
4130 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
4131 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4132 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
4133 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4134 | /* SPDIF output amp */ | ||
4135 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | ||
4136 | { } /* end */ | ||
4137 | }; | ||
4138 | |||
4139 | #ifdef CONFIG_PM | ||
4140 | static const struct hda_amp_list ad1884a_loopbacks[] = { | ||
4141 | { 0x20, HDA_INPUT, 0 }, /* Front Mic */ | ||
4142 | { 0x20, HDA_INPUT, 1 }, /* Mic */ | ||
4143 | { 0x20, HDA_INPUT, 2 }, /* CD */ | ||
4144 | { 0x20, HDA_INPUT, 4 }, /* Docking */ | ||
4145 | { } /* end */ | ||
4146 | }; | ||
4147 | #endif | ||
4148 | |||
4149 | /* | ||
4150 | * Laptop model | ||
4151 | * | ||
4152 | * Port A: Headphone jack | ||
4153 | * Port B: MIC jack | ||
4154 | * Port C: Internal MIC | ||
4155 | * Port D: Dock Line Out (if enabled) | ||
4156 | * Port E: Dock Line In (if enabled) | ||
4157 | * Port F: Internal speakers | ||
4158 | */ | ||
4159 | |||
4160 | static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol, | ||
4161 | struct snd_ctl_elem_value *ucontrol) | ||
4162 | { | ||
4163 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
4164 | int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); | ||
4165 | int mute = (!ucontrol->value.integer.value[0] && | ||
4166 | !ucontrol->value.integer.value[1]); | ||
4167 | /* toggle GPIO1 according to the mute state */ | ||
4168 | snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, | ||
4169 | mute ? 0x02 : 0x0); | ||
4170 | return ret; | ||
4171 | } | ||
4172 | |||
4173 | static const struct snd_kcontrol_new ad1884a_laptop_mixers[] = { | ||
4174 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
4175 | { | ||
4176 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4177 | .name = "Master Playback Switch", | ||
4178 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
4179 | .info = snd_hda_mixer_amp_switch_info, | ||
4180 | .get = snd_hda_mixer_amp_switch_get, | ||
4181 | .put = ad1884a_mobile_master_sw_put, | ||
4182 | .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), | ||
4183 | }, | ||
4184 | HDA_CODEC_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
4185 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
4186 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
4187 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
4188 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
4189 | HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
4190 | HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
4191 | HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT), | ||
4192 | HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT), | ||
4193 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT), | ||
4194 | HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT), | ||
4195 | HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), | ||
4196 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4197 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4198 | { } /* end */ | ||
4199 | }; | ||
4200 | |||
4201 | static const struct snd_kcontrol_new ad1884a_mobile_mixers[] = { | ||
4202 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
4203 | /*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ | ||
4204 | { | ||
4205 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4206 | .name = "Master Playback Switch", | ||
4207 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
4208 | .info = snd_hda_mixer_amp_switch_info, | ||
4209 | .get = snd_hda_mixer_amp_switch_get, | ||
4210 | .put = ad1884a_mobile_master_sw_put, | ||
4211 | .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), | ||
4212 | }, | ||
4213 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
4214 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
4215 | HDA_CODEC_VOLUME("Mic Capture Volume", 0x14, 0x0, HDA_INPUT), | ||
4216 | HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x15, 0x0, HDA_INPUT), | ||
4217 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4218 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4219 | { } /* end */ | ||
4220 | }; | ||
4221 | |||
4222 | /* mute internal speaker if HP is plugged */ | ||
4223 | static void ad1884a_hp_automute(struct hda_codec *codec) | ||
4224 | { | ||
4225 | unsigned int present; | ||
4226 | |||
4227 | present = snd_hda_jack_detect(codec, 0x11); | ||
4228 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, | ||
4229 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
4230 | snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
4231 | present ? 0x00 : 0x02); | ||
4232 | } | ||
4233 | |||
4234 | /* switch to external mic if plugged */ | ||
4235 | static void ad1884a_hp_automic(struct hda_codec *codec) | ||
4236 | { | ||
4237 | unsigned int present; | ||
4238 | |||
4239 | present = snd_hda_jack_detect(codec, 0x14); | ||
4240 | snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, | ||
4241 | present ? 0 : 1); | ||
4242 | } | ||
4243 | |||
4244 | #define AD1884A_HP_EVENT 0x37 | ||
4245 | #define AD1884A_MIC_EVENT 0x36 | ||
4246 | |||
4247 | /* unsolicited event for HP jack sensing */ | ||
4248 | static void ad1884a_hp_unsol_event(struct hda_codec *codec, unsigned int res) | ||
4249 | { | ||
4250 | switch (res >> 26) { | ||
4251 | case AD1884A_HP_EVENT: | ||
4252 | ad1884a_hp_automute(codec); | ||
4253 | break; | ||
4254 | case AD1884A_MIC_EVENT: | ||
4255 | ad1884a_hp_automic(codec); | ||
4256 | break; | ||
4257 | } | ||
4258 | } | ||
4259 | |||
4260 | /* initialize jack-sensing, too */ | ||
4261 | static int ad1884a_hp_init(struct hda_codec *codec) | ||
4262 | { | ||
4263 | ad198x_init(codec); | ||
4264 | ad1884a_hp_automute(codec); | ||
4265 | ad1884a_hp_automic(codec); | ||
4266 | return 0; | ||
4267 | } | ||
4268 | |||
4269 | /* mute internal speaker if HP or docking HP is plugged */ | ||
4270 | static void ad1884a_laptop_automute(struct hda_codec *codec) | ||
4271 | { | ||
4272 | unsigned int present; | ||
4273 | |||
4274 | present = snd_hda_jack_detect(codec, 0x11); | ||
4275 | if (!present) | ||
4276 | present = snd_hda_jack_detect(codec, 0x12); | ||
4277 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, | ||
4278 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
4279 | snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
4280 | present ? 0x00 : 0x02); | ||
4281 | } | ||
4282 | |||
4283 | /* switch to external mic if plugged */ | ||
4284 | static void ad1884a_laptop_automic(struct hda_codec *codec) | ||
4285 | { | ||
4286 | unsigned int idx; | ||
4287 | |||
4288 | if (snd_hda_jack_detect(codec, 0x14)) | ||
4289 | idx = 0; | ||
4290 | else if (snd_hda_jack_detect(codec, 0x1c)) | ||
4291 | idx = 4; | ||
4292 | else | ||
4293 | idx = 1; | ||
4294 | snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, idx); | ||
4295 | } | ||
4296 | |||
4297 | /* unsolicited event for HP jack sensing */ | ||
4298 | static void ad1884a_laptop_unsol_event(struct hda_codec *codec, | ||
4299 | unsigned int res) | ||
4300 | { | ||
4301 | switch (res >> 26) { | ||
4302 | case AD1884A_HP_EVENT: | ||
4303 | ad1884a_laptop_automute(codec); | ||
4304 | break; | ||
4305 | case AD1884A_MIC_EVENT: | ||
4306 | ad1884a_laptop_automic(codec); | ||
4307 | break; | ||
4308 | } | ||
4309 | } | ||
4310 | |||
4311 | /* initialize jack-sensing, too */ | ||
4312 | static int ad1884a_laptop_init(struct hda_codec *codec) | ||
4313 | { | ||
4314 | ad198x_init(codec); | ||
4315 | ad1884a_laptop_automute(codec); | ||
4316 | ad1884a_laptop_automic(codec); | ||
4317 | return 0; | ||
4318 | } | ||
4319 | |||
4320 | /* additional verbs for laptop model */ | ||
4321 | static const struct hda_verb ad1884a_laptop_verbs[] = { | ||
4322 | /* Port-A (HP) pin - always unmuted */ | ||
4323 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4324 | /* Port-F (int speaker) mixer - route only from analog mixer */ | ||
4325 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4326 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4327 | /* Port-F (int speaker) pin */ | ||
4328 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
4329 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4330 | /* required for compaq 6530s/6531s speaker output */ | ||
4331 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
4332 | /* Port-C pin - internal mic-in */ | ||
4333 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4334 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ | ||
4335 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ | ||
4336 | /* Port-D (docking line-out) pin - default unmuted */ | ||
4337 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4338 | /* analog mix */ | ||
4339 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
4340 | /* unsolicited event for pin-sense */ | ||
4341 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
4342 | {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
4343 | {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, | ||
4344 | {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, | ||
4345 | /* allow to touch GPIO1 (for mute control) */ | ||
4346 | {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, | ||
4347 | {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, | ||
4348 | {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */ | ||
4349 | { } /* end */ | ||
4350 | }; | ||
4351 | |||
4352 | static const struct hda_verb ad1884a_mobile_verbs[] = { | ||
4353 | /* DACs; unmute as default */ | ||
4354 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4355 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4356 | /* Port-A (HP) mixer - route only from analog mixer */ | ||
4357 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4358 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4359 | /* Port-A pin */ | ||
4360 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4361 | /* Port-A (HP) pin - always unmuted */ | ||
4362 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4363 | /* Port-B (mic jack) pin */ | ||
4364 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4365 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ | ||
4366 | /* Port-C (int mic) pin */ | ||
4367 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4368 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ | ||
4369 | /* Port-F (int speaker) mixer - route only from analog mixer */ | ||
4370 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4371 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4372 | /* Port-F pin */ | ||
4373 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4374 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4375 | /* Analog mixer; mute as default */ | ||
4376 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4377 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
4378 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
4379 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
4380 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
4381 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
4382 | /* Analog Mix output amp */ | ||
4383 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4384 | /* capture sources */ | ||
4385 | /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */ | ||
4386 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4387 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
4388 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4389 | /* unsolicited event for pin-sense */ | ||
4390 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
4391 | {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, | ||
4392 | /* allow to touch GPIO1 (for mute control) */ | ||
4393 | {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, | ||
4394 | {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, | ||
4395 | {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */ | ||
4396 | { } /* end */ | ||
4397 | }; | ||
4398 | |||
4399 | /* | ||
4400 | * Thinkpad X300 | ||
4401 | * 0x11 - HP | ||
4402 | * 0x12 - speaker | ||
4403 | * 0x14 - mic-in | ||
4404 | * 0x17 - built-in mic | ||
4405 | */ | ||
4406 | |||
4407 | static const struct hda_verb ad1984a_thinkpad_verbs[] = { | ||
4408 | /* HP unmute */ | ||
4409 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4410 | /* analog mix */ | ||
4411 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
4412 | /* turn on EAPD */ | ||
4413 | {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, | ||
4414 | /* unsolicited event for pin-sense */ | ||
4415 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
4416 | /* internal mic - dmic */ | ||
4417 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
4418 | /* set magic COEFs for dmic */ | ||
4419 | {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7}, | ||
4420 | {0x01, AC_VERB_SET_PROC_COEF, 0x08}, | ||
4421 | { } /* end */ | ||
4422 | }; | ||
4423 | |||
4424 | static const struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = { | ||
4425 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
4426 | HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
4427 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
4428 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
4429 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
4430 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
4431 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT), | ||
4432 | HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT), | ||
4433 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4434 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4435 | { | ||
4436 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4437 | .name = "Capture Source", | ||
4438 | .info = ad198x_mux_enum_info, | ||
4439 | .get = ad198x_mux_enum_get, | ||
4440 | .put = ad198x_mux_enum_put, | ||
4441 | }, | ||
4442 | { } /* end */ | ||
4443 | }; | ||
4444 | |||
4445 | static const struct hda_input_mux ad1984a_thinkpad_capture_source = { | ||
4446 | .num_items = 3, | ||
4447 | .items = { | ||
4448 | { "Mic", 0x0 }, | ||
4449 | { "Internal Mic", 0x5 }, | ||
4450 | { "Mix", 0x3 }, | ||
4451 | }, | ||
4452 | }; | ||
4453 | |||
4454 | /* mute internal speaker if HP is plugged */ | ||
4455 | static void ad1984a_thinkpad_automute(struct hda_codec *codec) | ||
4456 | { | ||
4457 | unsigned int present; | ||
4458 | |||
4459 | present = snd_hda_jack_detect(codec, 0x11); | ||
4460 | snd_hda_codec_amp_stereo(codec, 0x12, HDA_OUTPUT, 0, | ||
4461 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
4462 | } | ||
4463 | |||
4464 | /* unsolicited event for HP jack sensing */ | ||
4465 | static void ad1984a_thinkpad_unsol_event(struct hda_codec *codec, | ||
4466 | unsigned int res) | ||
4467 | { | ||
4468 | if ((res >> 26) != AD1884A_HP_EVENT) | ||
4469 | return; | ||
4470 | ad1984a_thinkpad_automute(codec); | ||
4471 | } | ||
4472 | |||
4473 | /* initialize jack-sensing, too */ | ||
4474 | static int ad1984a_thinkpad_init(struct hda_codec *codec) | ||
4475 | { | ||
4476 | ad198x_init(codec); | ||
4477 | ad1984a_thinkpad_automute(codec); | ||
4478 | return 0; | ||
4479 | } | ||
4480 | |||
4481 | /* | ||
4482 | * Precision R5500 | ||
4483 | * 0x12 - HP/line-out | ||
4484 | * 0x13 - speaker (mono) | ||
4485 | * 0x15 - mic-in | ||
4486 | */ | ||
4487 | |||
4488 | static const struct hda_verb ad1984a_precision_verbs[] = { | ||
4489 | /* Unmute main output path */ | ||
4490 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4491 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x1f}, /* 0dB */ | ||
4492 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) + 0x17}, /* 0dB */ | ||
4493 | /* Analog mixer; mute as default */ | ||
4494 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4495 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
4496 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
4497 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
4498 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
4499 | /* Select mic as input */ | ||
4500 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
4501 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x27}, /* 0dB */ | ||
4502 | /* Configure as mic */ | ||
4503 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4504 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ | ||
4505 | /* HP unmute */ | ||
4506 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4507 | /* turn on EAPD */ | ||
4508 | {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, | ||
4509 | /* unsolicited event for pin-sense */ | ||
4510 | {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
4511 | { } /* end */ | ||
4512 | }; | ||
4513 | |||
4514 | static const struct snd_kcontrol_new ad1984a_precision_mixers[] = { | ||
4515 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
4516 | HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
4517 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
4518 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
4519 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
4520 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
4521 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT), | ||
4522 | HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
4523 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
4524 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4525 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4526 | { } /* end */ | ||
4527 | }; | ||
4528 | |||
4529 | |||
4530 | /* mute internal speaker if HP is plugged */ | ||
4531 | static void ad1984a_precision_automute(struct hda_codec *codec) | ||
4532 | { | ||
4533 | unsigned int present; | ||
4534 | |||
4535 | present = snd_hda_jack_detect(codec, 0x12); | ||
4536 | snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0, | ||
4537 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
4538 | } | ||
4539 | |||
4540 | |||
4541 | /* unsolicited event for HP jack sensing */ | ||
4542 | static void ad1984a_precision_unsol_event(struct hda_codec *codec, | ||
4543 | unsigned int res) | ||
4544 | { | ||
4545 | if ((res >> 26) != AD1884A_HP_EVENT) | ||
4546 | return; | ||
4547 | ad1984a_precision_automute(codec); | ||
4548 | } | ||
4549 | |||
4550 | /* initialize jack-sensing, too */ | ||
4551 | static int ad1984a_precision_init(struct hda_codec *codec) | ||
4552 | { | ||
4553 | ad198x_init(codec); | ||
4554 | ad1984a_precision_automute(codec); | ||
4555 | return 0; | ||
4556 | } | ||
4557 | |||
4558 | |||
4559 | /* | ||
4560 | * HP Touchsmart | ||
4561 | * port-A (0x11) - front hp-out | ||
4562 | * port-B (0x14) - unused | ||
4563 | * port-C (0x15) - unused | ||
4564 | * port-D (0x12) - rear line out | ||
4565 | * port-E (0x1c) - front mic-in | ||
4566 | * port-F (0x16) - Internal speakers | ||
4567 | * digital-mic (0x17) - Internal mic | ||
4568 | */ | ||
4569 | |||
4570 | static const struct hda_verb ad1984a_touchsmart_verbs[] = { | ||
4571 | /* DACs; unmute as default */ | ||
4572 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4573 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4574 | /* Port-A (HP) mixer - route only from analog mixer */ | ||
4575 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4576 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4577 | /* Port-A pin */ | ||
4578 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4579 | /* Port-A (HP) pin - always unmuted */ | ||
4580 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4581 | /* Port-E (int speaker) mixer - route only from analog mixer */ | ||
4582 | {0x25, AC_VERB_SET_AMP_GAIN_MUTE, 0x03}, | ||
4583 | /* Port-E pin */ | ||
4584 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
4585 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4586 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4587 | /* Port-F (int speaker) mixer - route only from analog mixer */ | ||
4588 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4589 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4590 | /* Port-F pin */ | ||
4591 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4592 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4593 | /* Analog mixer; mute as default */ | ||
4594 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4595 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
4596 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
4597 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
4598 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
4599 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
4600 | /* Analog Mix output amp */ | ||
4601 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4602 | /* capture sources */ | ||
4603 | /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */ | ||
4604 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4605 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
4606 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4607 | /* unsolicited event for pin-sense */ | ||
4608 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
4609 | {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, | ||
4610 | /* allow to touch GPIO1 (for mute control) */ | ||
4611 | {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, | ||
4612 | {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, | ||
4613 | {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */ | ||
4614 | /* internal mic - dmic */ | ||
4615 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
4616 | /* set magic COEFs for dmic */ | ||
4617 | {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7}, | ||
4618 | {0x01, AC_VERB_SET_PROC_COEF, 0x08}, | ||
4619 | { } /* end */ | ||
4620 | }; | ||
4621 | |||
4622 | static const struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = { | ||
4623 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
4624 | /* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ | ||
4625 | { | ||
4626 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4627 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
4628 | .name = "Master Playback Switch", | ||
4629 | .info = snd_hda_mixer_amp_switch_info, | ||
4630 | .get = snd_hda_mixer_amp_switch_get, | ||
4631 | .put = ad1884a_mobile_master_sw_put, | ||
4632 | .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), | ||
4633 | }, | ||
4634 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
4635 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
4636 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4637 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4638 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), | ||
4639 | HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT), | ||
4640 | { } /* end */ | ||
4641 | }; | ||
4642 | |||
4643 | /* switch to external mic if plugged */ | ||
4644 | static void ad1984a_touchsmart_automic(struct hda_codec *codec) | ||
4645 | { | ||
4646 | if (snd_hda_jack_detect(codec, 0x1c)) | ||
4647 | snd_hda_codec_write(codec, 0x0c, 0, | ||
4648 | AC_VERB_SET_CONNECT_SEL, 0x4); | ||
4649 | else | ||
4650 | snd_hda_codec_write(codec, 0x0c, 0, | ||
4651 | AC_VERB_SET_CONNECT_SEL, 0x5); | ||
4652 | } | ||
4653 | |||
4654 | |||
4655 | /* unsolicited event for HP jack sensing */ | ||
4656 | static void ad1984a_touchsmart_unsol_event(struct hda_codec *codec, | ||
4657 | unsigned int res) | ||
4658 | { | ||
4659 | switch (res >> 26) { | ||
4660 | case AD1884A_HP_EVENT: | ||
4661 | ad1884a_hp_automute(codec); | ||
4662 | break; | ||
4663 | case AD1884A_MIC_EVENT: | ||
4664 | ad1984a_touchsmart_automic(codec); | ||
4665 | break; | ||
4666 | } | ||
4667 | } | ||
4668 | |||
4669 | /* initialize jack-sensing, too */ | ||
4670 | static int ad1984a_touchsmart_init(struct hda_codec *codec) | ||
4671 | { | ||
4672 | ad198x_init(codec); | ||
4673 | ad1884a_hp_automute(codec); | ||
4674 | ad1984a_touchsmart_automic(codec); | ||
4675 | return 0; | ||
4676 | } | ||
4677 | |||
4678 | |||
4679 | /* | ||
4680 | */ | ||
4681 | |||
4682 | enum { | ||
4683 | AD1884A_AUTO, | ||
4684 | AD1884A_DESKTOP, | ||
4685 | AD1884A_LAPTOP, | ||
4686 | AD1884A_MOBILE, | ||
4687 | AD1884A_THINKPAD, | ||
4688 | AD1984A_TOUCHSMART, | ||
4689 | AD1984A_PRECISION, | ||
4690 | AD1884A_MODELS | ||
4691 | }; | ||
4692 | |||
4693 | static const char * const ad1884a_models[AD1884A_MODELS] = { | ||
4694 | [AD1884A_AUTO] = "auto", | ||
4695 | [AD1884A_DESKTOP] = "desktop", | ||
4696 | [AD1884A_LAPTOP] = "laptop", | ||
4697 | [AD1884A_MOBILE] = "mobile", | ||
4698 | [AD1884A_THINKPAD] = "thinkpad", | ||
4699 | [AD1984A_TOUCHSMART] = "touchsmart", | ||
4700 | [AD1984A_PRECISION] = "precision", | ||
4701 | }; | ||
4702 | |||
4703 | static const struct snd_pci_quirk ad1884a_cfg_tbl[] = { | ||
4704 | SND_PCI_QUIRK(0x1028, 0x04ac, "Precision R5500", AD1984A_PRECISION), | ||
4705 | SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE), | ||
4706 | SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP), | ||
4707 | SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE), | ||
4708 | SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x3070, "HP", AD1884A_MOBILE), | ||
4709 | SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30d0, "HP laptop", AD1884A_LAPTOP), | ||
4710 | SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP), | ||
4711 | SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP), | ||
4712 | SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x7010, "HP laptop", AD1884A_MOBILE), | ||
4713 | SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD), | ||
4714 | SND_PCI_QUIRK(0x103c, 0x2a82, "Touchsmart", AD1984A_TOUCHSMART), | ||
4715 | {} | ||
4716 | }; | ||
4717 | |||
4718 | static int patch_ad1884a(struct hda_codec *codec) | ||
4719 | { | ||
4720 | struct ad198x_spec *spec; | ||
4721 | int err, board_config; | ||
4722 | |||
4723 | board_config = snd_hda_check_board_config(codec, AD1884A_MODELS, | ||
4724 | ad1884a_models, | ||
4725 | ad1884a_cfg_tbl); | ||
4726 | if (board_config < 0) { | ||
4727 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
4728 | codec->chip_name); | ||
4729 | board_config = AD1884A_AUTO; | ||
4730 | } | ||
4731 | |||
4732 | if (board_config == AD1884A_AUTO) | ||
4733 | return ad1884_parse_auto_config(codec); | ||
4734 | |||
4735 | err = alloc_ad_spec(codec); | ||
4736 | if (err < 0) | ||
4737 | return err; | ||
4738 | spec = codec->spec; | ||
4739 | |||
4740 | err = snd_hda_attach_beep_device(codec, 0x10); | ||
4741 | if (err < 0) { | ||
4742 | ad198x_free(codec); | ||
4743 | return err; | ||
4744 | } | ||
4745 | set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); | ||
4746 | |||
4747 | spec->multiout.max_channels = 2; | ||
4748 | spec->multiout.num_dacs = ARRAY_SIZE(ad1884a_dac_nids); | ||
4749 | spec->multiout.dac_nids = ad1884a_dac_nids; | ||
4750 | spec->multiout.dig_out_nid = AD1884A_SPDIF_OUT; | ||
4751 | spec->num_adc_nids = ARRAY_SIZE(ad1884a_adc_nids); | ||
4752 | spec->adc_nids = ad1884a_adc_nids; | ||
4753 | spec->capsrc_nids = ad1884a_capsrc_nids; | ||
4754 | spec->input_mux = &ad1884a_capture_source; | ||
4755 | spec->num_mixers = 1; | ||
4756 | spec->mixers[0] = ad1884a_base_mixers; | ||
4757 | spec->num_init_verbs = 1; | ||
4758 | spec->init_verbs[0] = ad1884a_init_verbs; | ||
4759 | spec->spdif_route = 0; | ||
4760 | #ifdef CONFIG_PM | ||
4761 | spec->loopback.amplist = ad1884a_loopbacks; | ||
4762 | #endif | ||
4763 | codec->patch_ops = ad198x_patch_ops; | ||
4764 | |||
4765 | /* override some parameters */ | ||
4766 | switch (board_config) { | ||
4767 | case AD1884A_LAPTOP: | ||
4768 | spec->mixers[0] = ad1884a_laptop_mixers; | ||
4769 | spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs; | ||
4770 | spec->multiout.dig_out_nid = 0; | ||
4771 | codec->patch_ops.unsol_event = ad1884a_laptop_unsol_event; | ||
4772 | codec->patch_ops.init = ad1884a_laptop_init; | ||
4773 | /* set the upper-limit for mixer amp to 0dB for avoiding the | ||
4774 | * possible damage by overloading | ||
4775 | */ | ||
4776 | snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT, | ||
4777 | (0x17 << AC_AMPCAP_OFFSET_SHIFT) | | ||
4778 | (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||
4779 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
4780 | (1 << AC_AMPCAP_MUTE_SHIFT)); | ||
4781 | break; | ||
4782 | case AD1884A_MOBILE: | ||
4783 | spec->mixers[0] = ad1884a_mobile_mixers; | ||
4784 | spec->init_verbs[0] = ad1884a_mobile_verbs; | ||
4785 | spec->multiout.dig_out_nid = 0; | ||
4786 | codec->patch_ops.unsol_event = ad1884a_hp_unsol_event; | ||
4787 | codec->patch_ops.init = ad1884a_hp_init; | ||
4788 | /* set the upper-limit for mixer amp to 0dB for avoiding the | ||
4789 | * possible damage by overloading | ||
4790 | */ | ||
4791 | snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT, | ||
4792 | (0x17 << AC_AMPCAP_OFFSET_SHIFT) | | ||
4793 | (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||
4794 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
4795 | (1 << AC_AMPCAP_MUTE_SHIFT)); | ||
4796 | break; | ||
4797 | case AD1884A_THINKPAD: | ||
4798 | spec->mixers[0] = ad1984a_thinkpad_mixers; | ||
4799 | spec->init_verbs[spec->num_init_verbs++] = | ||
4800 | ad1984a_thinkpad_verbs; | ||
4801 | spec->multiout.dig_out_nid = 0; | ||
4802 | spec->input_mux = &ad1984a_thinkpad_capture_source; | ||
4803 | codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event; | ||
4804 | codec->patch_ops.init = ad1984a_thinkpad_init; | ||
4805 | break; | ||
4806 | case AD1984A_PRECISION: | ||
4807 | spec->mixers[0] = ad1984a_precision_mixers; | ||
4808 | spec->init_verbs[spec->num_init_verbs++] = | ||
4809 | ad1984a_precision_verbs; | ||
4810 | spec->multiout.dig_out_nid = 0; | ||
4811 | codec->patch_ops.unsol_event = ad1984a_precision_unsol_event; | ||
4812 | codec->patch_ops.init = ad1984a_precision_init; | ||
4813 | break; | ||
4814 | case AD1984A_TOUCHSMART: | ||
4815 | spec->mixers[0] = ad1984a_touchsmart_mixers; | ||
4816 | spec->init_verbs[0] = ad1984a_touchsmart_verbs; | ||
4817 | spec->multiout.dig_out_nid = 0; | ||
4818 | codec->patch_ops.unsol_event = ad1984a_touchsmart_unsol_event; | ||
4819 | codec->patch_ops.init = ad1984a_touchsmart_init; | ||
4820 | /* set the upper-limit for mixer amp to 0dB for avoiding the | ||
4821 | * possible damage by overloading | ||
4822 | */ | ||
4823 | snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT, | ||
4824 | (0x17 << AC_AMPCAP_OFFSET_SHIFT) | | ||
4825 | (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||
4826 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
4827 | (1 << AC_AMPCAP_MUTE_SHIFT)); | ||
4828 | break; | ||
4829 | } | ||
4830 | |||
4831 | codec->no_trigger_sense = 1; | ||
4832 | codec->no_sticky_stream = 1; | ||
4833 | |||
4834 | return 0; | ||
4835 | } | ||
4836 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
4837 | #define patch_ad1884a ad1884_parse_auto_config | ||
4838 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
4839 | |||
4840 | |||
4841 | /* | 1049 | /* |
4842 | * AD1882 / AD1882A | 1050 | * AD1882 / AD1882A |
4843 | * | 1051 | * |
@@ -4850,299 +1058,7 @@ static int patch_ad1884a(struct hda_codec *codec) | |||
4850 | * port-G - rear clfe-out (6stack) | 1058 | * port-G - rear clfe-out (6stack) |
4851 | */ | 1059 | */ |
4852 | 1060 | ||
4853 | #ifdef ENABLE_AD_STATIC_QUIRKS | 1061 | static int patch_ad1882(struct hda_codec *codec) |
4854 | static const hda_nid_t ad1882_dac_nids[3] = { | ||
4855 | 0x04, 0x03, 0x05 | ||
4856 | }; | ||
4857 | |||
4858 | static const hda_nid_t ad1882_adc_nids[2] = { | ||
4859 | 0x08, 0x09, | ||
4860 | }; | ||
4861 | |||
4862 | static const hda_nid_t ad1882_capsrc_nids[2] = { | ||
4863 | 0x0c, 0x0d, | ||
4864 | }; | ||
4865 | |||
4866 | #define AD1882_SPDIF_OUT 0x02 | ||
4867 | |||
4868 | /* list: 0x11, 0x39, 0x3a, 0x18, 0x3c, 0x3b, 0x12, 0x20 */ | ||
4869 | static const struct hda_input_mux ad1882_capture_source = { | ||
4870 | .num_items = 5, | ||
4871 | .items = { | ||
4872 | { "Front Mic", 0x1 }, | ||
4873 | { "Mic", 0x4 }, | ||
4874 | { "Line", 0x2 }, | ||
4875 | { "CD", 0x3 }, | ||
4876 | { "Mix", 0x7 }, | ||
4877 | }, | ||
4878 | }; | ||
4879 | |||
4880 | /* list: 0x11, 0x39, 0x3a, 0x3c, 0x18, 0x1f, 0x12, 0x20 */ | ||
4881 | static const struct hda_input_mux ad1882a_capture_source = { | ||
4882 | .num_items = 5, | ||
4883 | .items = { | ||
4884 | { "Front Mic", 0x1 }, | ||
4885 | { "Mic", 0x4}, | ||
4886 | { "Line", 0x2 }, | ||
4887 | { "Digital Mic", 0x06 }, | ||
4888 | { "Mix", 0x7 }, | ||
4889 | }, | ||
4890 | }; | ||
4891 | |||
4892 | static const struct snd_kcontrol_new ad1882_base_mixers[] = { | ||
4893 | HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
4894 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
4895 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT), | ||
4896 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT), | ||
4897 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
4898 | HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
4899 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), | ||
4900 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), | ||
4901 | |||
4902 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT), | ||
4903 | HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), | ||
4904 | HDA_CODEC_VOLUME("Line-In Boost Volume", 0x3a, 0x0, HDA_OUTPUT), | ||
4905 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4906 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4907 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
4908 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
4909 | { | ||
4910 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4911 | /* The multiple "Capture Source" controls confuse alsamixer | ||
4912 | * So call somewhat different.. | ||
4913 | */ | ||
4914 | /* .name = "Capture Source", */ | ||
4915 | .name = "Input Source", | ||
4916 | .count = 2, | ||
4917 | .info = ad198x_mux_enum_info, | ||
4918 | .get = ad198x_mux_enum_get, | ||
4919 | .put = ad198x_mux_enum_put, | ||
4920 | }, | ||
4921 | /* SPDIF controls */ | ||
4922 | HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
4923 | { | ||
4924 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4925 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
4926 | /* identical with ad1983 */ | ||
4927 | .info = ad1983_spdif_route_info, | ||
4928 | .get = ad1983_spdif_route_get, | ||
4929 | .put = ad1983_spdif_route_put, | ||
4930 | }, | ||
4931 | { } /* end */ | ||
4932 | }; | ||
4933 | |||
4934 | static const struct snd_kcontrol_new ad1882_loopback_mixers[] = { | ||
4935 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
4936 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
4937 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
4938 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
4939 | HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT), | ||
4940 | HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT), | ||
4941 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT), | ||
4942 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT), | ||
4943 | { } /* end */ | ||
4944 | }; | ||
4945 | |||
4946 | static const struct snd_kcontrol_new ad1882a_loopback_mixers[] = { | ||
4947 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
4948 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
4949 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT), | ||
4950 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT), | ||
4951 | HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
4952 | HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
4953 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT), | ||
4954 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT), | ||
4955 | HDA_CODEC_VOLUME("Digital Mic Boost Volume", 0x1f, 0x0, HDA_INPUT), | ||
4956 | { } /* end */ | ||
4957 | }; | ||
4958 | |||
4959 | static const struct snd_kcontrol_new ad1882_3stack_mixers[] = { | ||
4960 | HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
4961 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT), | ||
4962 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x17, 2, 0x0, HDA_OUTPUT), | ||
4963 | { | ||
4964 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4965 | .name = "Channel Mode", | ||
4966 | .info = ad198x_ch_mode_info, | ||
4967 | .get = ad198x_ch_mode_get, | ||
4968 | .put = ad198x_ch_mode_put, | ||
4969 | }, | ||
4970 | { } /* end */ | ||
4971 | }; | ||
4972 | |||
4973 | /* simple auto-mute control for AD1882 3-stack board */ | ||
4974 | #define AD1882_HP_EVENT 0x01 | ||
4975 | |||
4976 | static void ad1882_3stack_automute(struct hda_codec *codec) | ||
4977 | { | ||
4978 | bool mute = snd_hda_jack_detect(codec, 0x11); | ||
4979 | snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
4980 | mute ? 0 : PIN_OUT); | ||
4981 | } | ||
4982 | |||
4983 | static int ad1882_3stack_automute_init(struct hda_codec *codec) | ||
4984 | { | ||
4985 | ad198x_init(codec); | ||
4986 | ad1882_3stack_automute(codec); | ||
4987 | return 0; | ||
4988 | } | ||
4989 | |||
4990 | static void ad1882_3stack_unsol_event(struct hda_codec *codec, unsigned int res) | ||
4991 | { | ||
4992 | switch (res >> 26) { | ||
4993 | case AD1882_HP_EVENT: | ||
4994 | ad1882_3stack_automute(codec); | ||
4995 | break; | ||
4996 | } | ||
4997 | } | ||
4998 | |||
4999 | static const struct snd_kcontrol_new ad1882_6stack_mixers[] = { | ||
5000 | HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT), | ||
5001 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT), | ||
5002 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x24, 2, 0x0, HDA_OUTPUT), | ||
5003 | { } /* end */ | ||
5004 | }; | ||
5005 | |||
5006 | static const struct hda_verb ad1882_ch2_init[] = { | ||
5007 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
5008 | {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5009 | {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
5010 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
5011 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5012 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
5013 | { } /* end */ | ||
5014 | }; | ||
5015 | |||
5016 | static const struct hda_verb ad1882_ch4_init[] = { | ||
5017 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
5018 | {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5019 | {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5020 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
5021 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5022 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
5023 | { } /* end */ | ||
5024 | }; | ||
5025 | |||
5026 | static const struct hda_verb ad1882_ch6_init[] = { | ||
5027 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
5028 | {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5029 | {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5030 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
5031 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5032 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5033 | { } /* end */ | ||
5034 | }; | ||
5035 | |||
5036 | static const struct hda_channel_mode ad1882_modes[3] = { | ||
5037 | { 2, ad1882_ch2_init }, | ||
5038 | { 4, ad1882_ch4_init }, | ||
5039 | { 6, ad1882_ch6_init }, | ||
5040 | }; | ||
5041 | |||
5042 | /* | ||
5043 | * initialization verbs | ||
5044 | */ | ||
5045 | static const struct hda_verb ad1882_init_verbs[] = { | ||
5046 | /* DACs; mute as default */ | ||
5047 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
5048 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
5049 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
5050 | /* Port-A (HP) mixer */ | ||
5051 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5052 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5053 | /* Port-A pin */ | ||
5054 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
5055 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5056 | /* HP selector - select DAC2 */ | ||
5057 | {0x37, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
5058 | /* Port-D (Line-out) mixer */ | ||
5059 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5060 | {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5061 | /* Port-D pin */ | ||
5062 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
5063 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5064 | /* Mono-out mixer */ | ||
5065 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
5066 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
5067 | /* Mono-out pin */ | ||
5068 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
5069 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5070 | /* Port-B (front mic) pin */ | ||
5071 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
5072 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5073 | {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */ | ||
5074 | /* Port-C (line-in) pin */ | ||
5075 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
5076 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5077 | {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */ | ||
5078 | /* Port-C mixer - mute as input */ | ||
5079 | {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5080 | {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
5081 | /* Port-E (mic-in) pin */ | ||
5082 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
5083 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5084 | {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */ | ||
5085 | /* Port-E mixer - mute as input */ | ||
5086 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5087 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
5088 | /* Port-F (surround) */ | ||
5089 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
5090 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5091 | /* Port-G (CLFE) */ | ||
5092 | {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
5093 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
5094 | /* Analog mixer; mute as default */ | ||
5095 | /* list: 0x39, 0x3a, 0x11, 0x12, 0x3c, 0x3b, 0x18, 0x1a */ | ||
5096 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
5097 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
5098 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
5099 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
5100 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
5101 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
5102 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, | ||
5103 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, | ||
5104 | /* Analog Mix output amp */ | ||
5105 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ | ||
5106 | /* SPDIF output selector */ | ||
5107 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | ||
5108 | {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */ | ||
5109 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | ||
5110 | { } /* end */ | ||
5111 | }; | ||
5112 | |||
5113 | static const struct hda_verb ad1882_3stack_automute_verbs[] = { | ||
5114 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1882_HP_EVENT}, | ||
5115 | { } /* end */ | ||
5116 | }; | ||
5117 | |||
5118 | #ifdef CONFIG_PM | ||
5119 | static const struct hda_amp_list ad1882_loopbacks[] = { | ||
5120 | { 0x20, HDA_INPUT, 0 }, /* Front Mic */ | ||
5121 | { 0x20, HDA_INPUT, 1 }, /* Mic */ | ||
5122 | { 0x20, HDA_INPUT, 4 }, /* Line */ | ||
5123 | { 0x20, HDA_INPUT, 6 }, /* CD */ | ||
5124 | { } /* end */ | ||
5125 | }; | ||
5126 | #endif | ||
5127 | |||
5128 | /* models */ | ||
5129 | enum { | ||
5130 | AD1882_AUTO, | ||
5131 | AD1882_3STACK, | ||
5132 | AD1882_6STACK, | ||
5133 | AD1882_3STACK_AUTOMUTE, | ||
5134 | AD1882_MODELS | ||
5135 | }; | ||
5136 | |||
5137 | static const char * const ad1882_models[AD1986A_MODELS] = { | ||
5138 | [AD1882_AUTO] = "auto", | ||
5139 | [AD1882_3STACK] = "3stack", | ||
5140 | [AD1882_6STACK] = "6stack", | ||
5141 | [AD1882_3STACK_AUTOMUTE] = "3stack-automute", | ||
5142 | }; | ||
5143 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
5144 | |||
5145 | static int ad1882_parse_auto_config(struct hda_codec *codec) | ||
5146 | { | 1062 | { |
5147 | struct ad198x_spec *spec; | 1063 | struct ad198x_spec *spec; |
5148 | int err; | 1064 | int err; |
@@ -5169,110 +1085,20 @@ static int ad1882_parse_auto_config(struct hda_codec *codec) | |||
5169 | return err; | 1085 | return err; |
5170 | } | 1086 | } |
5171 | 1087 | ||
5172 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
5173 | static int patch_ad1882(struct hda_codec *codec) | ||
5174 | { | ||
5175 | struct ad198x_spec *spec; | ||
5176 | int err, board_config; | ||
5177 | |||
5178 | board_config = snd_hda_check_board_config(codec, AD1882_MODELS, | ||
5179 | ad1882_models, NULL); | ||
5180 | if (board_config < 0) { | ||
5181 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
5182 | codec->chip_name); | ||
5183 | board_config = AD1882_AUTO; | ||
5184 | } | ||
5185 | |||
5186 | if (board_config == AD1882_AUTO) | ||
5187 | return ad1882_parse_auto_config(codec); | ||
5188 | |||
5189 | err = alloc_ad_spec(codec); | ||
5190 | if (err < 0) | ||
5191 | return err; | ||
5192 | spec = codec->spec; | ||
5193 | |||
5194 | err = snd_hda_attach_beep_device(codec, 0x10); | ||
5195 | if (err < 0) { | ||
5196 | ad198x_free(codec); | ||
5197 | return err; | ||
5198 | } | ||
5199 | set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); | ||
5200 | |||
5201 | spec->multiout.max_channels = 6; | ||
5202 | spec->multiout.num_dacs = 3; | ||
5203 | spec->multiout.dac_nids = ad1882_dac_nids; | ||
5204 | spec->multiout.dig_out_nid = AD1882_SPDIF_OUT; | ||
5205 | spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids); | ||
5206 | spec->adc_nids = ad1882_adc_nids; | ||
5207 | spec->capsrc_nids = ad1882_capsrc_nids; | ||
5208 | if (codec->vendor_id == 0x11d41882) | ||
5209 | spec->input_mux = &ad1882_capture_source; | ||
5210 | else | ||
5211 | spec->input_mux = &ad1882a_capture_source; | ||
5212 | spec->num_mixers = 2; | ||
5213 | spec->mixers[0] = ad1882_base_mixers; | ||
5214 | if (codec->vendor_id == 0x11d41882) | ||
5215 | spec->mixers[1] = ad1882_loopback_mixers; | ||
5216 | else | ||
5217 | spec->mixers[1] = ad1882a_loopback_mixers; | ||
5218 | spec->num_init_verbs = 1; | ||
5219 | spec->init_verbs[0] = ad1882_init_verbs; | ||
5220 | spec->spdif_route = 0; | ||
5221 | #ifdef CONFIG_PM | ||
5222 | spec->loopback.amplist = ad1882_loopbacks; | ||
5223 | #endif | ||
5224 | spec->vmaster_nid = 0x04; | ||
5225 | |||
5226 | codec->patch_ops = ad198x_patch_ops; | ||
5227 | |||
5228 | /* override some parameters */ | ||
5229 | switch (board_config) { | ||
5230 | default: | ||
5231 | case AD1882_3STACK: | ||
5232 | case AD1882_3STACK_AUTOMUTE: | ||
5233 | spec->num_mixers = 3; | ||
5234 | spec->mixers[2] = ad1882_3stack_mixers; | ||
5235 | spec->channel_mode = ad1882_modes; | ||
5236 | spec->num_channel_mode = ARRAY_SIZE(ad1882_modes); | ||
5237 | spec->need_dac_fix = 1; | ||
5238 | spec->multiout.max_channels = 2; | ||
5239 | spec->multiout.num_dacs = 1; | ||
5240 | if (board_config != AD1882_3STACK) { | ||
5241 | spec->init_verbs[spec->num_init_verbs++] = | ||
5242 | ad1882_3stack_automute_verbs; | ||
5243 | codec->patch_ops.unsol_event = ad1882_3stack_unsol_event; | ||
5244 | codec->patch_ops.init = ad1882_3stack_automute_init; | ||
5245 | } | ||
5246 | break; | ||
5247 | case AD1882_6STACK: | ||
5248 | spec->num_mixers = 3; | ||
5249 | spec->mixers[2] = ad1882_6stack_mixers; | ||
5250 | break; | ||
5251 | } | ||
5252 | |||
5253 | codec->no_trigger_sense = 1; | ||
5254 | codec->no_sticky_stream = 1; | ||
5255 | |||
5256 | return 0; | ||
5257 | } | ||
5258 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
5259 | #define patch_ad1882 ad1882_parse_auto_config | ||
5260 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
5261 | |||
5262 | 1088 | ||
5263 | /* | 1089 | /* |
5264 | * patch entries | 1090 | * patch entries |
5265 | */ | 1091 | */ |
5266 | static const struct hda_codec_preset snd_hda_preset_analog[] = { | 1092 | static const struct hda_codec_preset snd_hda_preset_analog[] = { |
5267 | { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a }, | 1093 | { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884 }, |
5268 | { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 }, | 1094 | { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 }, |
5269 | { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a }, | 1095 | { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884 }, |
5270 | { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 }, | 1096 | { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 }, |
5271 | { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884a }, | 1097 | { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884 }, |
5272 | { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884a }, | 1098 | { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884 }, |
5273 | { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 }, | 1099 | { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 }, |
5274 | { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 }, | 1100 | { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 }, |
5275 | { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 }, | 1101 | { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1884 }, |
5276 | { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a }, | 1102 | { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a }, |
5277 | { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 }, | 1103 | { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 }, |
5278 | { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 }, | 1104 | { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 }, |
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index de00ce166470..4edd2d0f9a3c 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -66,6 +66,8 @@ struct conexant_spec { | |||
66 | hda_nid_t eapds[4]; | 66 | hda_nid_t eapds[4]; |
67 | bool dynamic_eapd; | 67 | bool dynamic_eapd; |
68 | 68 | ||
69 | unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */ | ||
70 | |||
69 | #ifdef ENABLE_CXT_STATIC_QUIRKS | 71 | #ifdef ENABLE_CXT_STATIC_QUIRKS |
70 | const struct snd_kcontrol_new *mixers[5]; | 72 | const struct snd_kcontrol_new *mixers[5]; |
71 | int num_mixers; | 73 | int num_mixers; |
@@ -3200,6 +3202,9 @@ static int cx_auto_init(struct hda_codec *codec) | |||
3200 | snd_hda_gen_init(codec); | 3202 | snd_hda_gen_init(codec); |
3201 | if (!spec->dynamic_eapd) | 3203 | if (!spec->dynamic_eapd) |
3202 | cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true); | 3204 | cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true); |
3205 | |||
3206 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT); | ||
3207 | |||
3203 | return 0; | 3208 | return 0; |
3204 | } | 3209 | } |
3205 | 3210 | ||
@@ -3224,6 +3229,8 @@ enum { | |||
3224 | CXT_PINCFG_LEMOTE_A1205, | 3229 | CXT_PINCFG_LEMOTE_A1205, |
3225 | CXT_FIXUP_STEREO_DMIC, | 3230 | CXT_FIXUP_STEREO_DMIC, |
3226 | CXT_FIXUP_INC_MIC_BOOST, | 3231 | CXT_FIXUP_INC_MIC_BOOST, |
3232 | CXT_FIXUP_HEADPHONE_MIC_PIN, | ||
3233 | CXT_FIXUP_HEADPHONE_MIC, | ||
3227 | }; | 3234 | }; |
3228 | 3235 | ||
3229 | static void cxt_fixup_stereo_dmic(struct hda_codec *codec, | 3236 | static void cxt_fixup_stereo_dmic(struct hda_codec *codec, |
@@ -3246,6 +3253,59 @@ static void cxt5066_increase_mic_boost(struct hda_codec *codec, | |||
3246 | (0 << AC_AMPCAP_MUTE_SHIFT)); | 3253 | (0 << AC_AMPCAP_MUTE_SHIFT)); |
3247 | } | 3254 | } |
3248 | 3255 | ||
3256 | static void cxt_update_headset_mode(struct hda_codec *codec) | ||
3257 | { | ||
3258 | /* The verbs used in this function were tested on a Conexant CX20751/2 codec. */ | ||
3259 | int i; | ||
3260 | bool mic_mode = false; | ||
3261 | struct conexant_spec *spec = codec->spec; | ||
3262 | struct auto_pin_cfg *cfg = &spec->gen.autocfg; | ||
3263 | |||
3264 | hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]]; | ||
3265 | |||
3266 | for (i = 0; i < cfg->num_inputs; i++) | ||
3267 | if (cfg->inputs[i].pin == mux_pin) { | ||
3268 | mic_mode = !!cfg->inputs[i].is_headphone_mic; | ||
3269 | break; | ||
3270 | } | ||
3271 | |||
3272 | if (mic_mode) { | ||
3273 | snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x7c); /* enable merged mode for analog int-mic */ | ||
3274 | spec->gen.hp_jack_present = false; | ||
3275 | } else { | ||
3276 | snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x54); /* disable merged mode for analog int-mic */ | ||
3277 | spec->gen.hp_jack_present = snd_hda_jack_detect(codec, spec->gen.autocfg.hp_pins[0]); | ||
3278 | } | ||
3279 | |||
3280 | snd_hda_gen_update_outputs(codec); | ||
3281 | } | ||
3282 | |||
3283 | static void cxt_update_headset_mode_hook(struct hda_codec *codec, | ||
3284 | struct snd_ctl_elem_value *ucontrol) | ||
3285 | { | ||
3286 | cxt_update_headset_mode(codec); | ||
3287 | } | ||
3288 | |||
3289 | static void cxt_fixup_headphone_mic(struct hda_codec *codec, | ||
3290 | const struct hda_fixup *fix, int action) | ||
3291 | { | ||
3292 | struct conexant_spec *spec = codec->spec; | ||
3293 | |||
3294 | switch (action) { | ||
3295 | case HDA_FIXUP_ACT_PRE_PROBE: | ||
3296 | spec->parse_flags |= HDA_PINCFG_HEADPHONE_MIC; | ||
3297 | break; | ||
3298 | case HDA_FIXUP_ACT_PROBE: | ||
3299 | spec->gen.cap_sync_hook = cxt_update_headset_mode_hook; | ||
3300 | spec->gen.automute_hook = cxt_update_headset_mode; | ||
3301 | break; | ||
3302 | case HDA_FIXUP_ACT_INIT: | ||
3303 | cxt_update_headset_mode(codec); | ||
3304 | break; | ||
3305 | } | ||
3306 | } | ||
3307 | |||
3308 | |||
3249 | /* ThinkPad X200 & co with cxt5051 */ | 3309 | /* ThinkPad X200 & co with cxt5051 */ |
3250 | static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = { | 3310 | static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = { |
3251 | { 0x16, 0x042140ff }, /* HP (seq# overridden) */ | 3311 | { 0x16, 0x042140ff }, /* HP (seq# overridden) */ |
@@ -3302,6 +3362,19 @@ static const struct hda_fixup cxt_fixups[] = { | |||
3302 | .type = HDA_FIXUP_FUNC, | 3362 | .type = HDA_FIXUP_FUNC, |
3303 | .v.func = cxt5066_increase_mic_boost, | 3363 | .v.func = cxt5066_increase_mic_boost, |
3304 | }, | 3364 | }, |
3365 | [CXT_FIXUP_HEADPHONE_MIC_PIN] = { | ||
3366 | .type = HDA_FIXUP_PINS, | ||
3367 | .chained = true, | ||
3368 | .chain_id = CXT_FIXUP_HEADPHONE_MIC, | ||
3369 | .v.pins = (const struct hda_pintbl[]) { | ||
3370 | { 0x18, 0x03a1913d }, /* use as headphone mic, without its own jack detect */ | ||
3371 | { } | ||
3372 | } | ||
3373 | }, | ||
3374 | [CXT_FIXUP_HEADPHONE_MIC] = { | ||
3375 | .type = HDA_FIXUP_FUNC, | ||
3376 | .v.func = cxt_fixup_headphone_mic, | ||
3377 | }, | ||
3305 | }; | 3378 | }; |
3306 | 3379 | ||
3307 | static const struct snd_pci_quirk cxt5051_fixups[] = { | 3380 | static const struct snd_pci_quirk cxt5051_fixups[] = { |
@@ -3311,6 +3384,7 @@ static const struct snd_pci_quirk cxt5051_fixups[] = { | |||
3311 | 3384 | ||
3312 | static const struct snd_pci_quirk cxt5066_fixups[] = { | 3385 | static const struct snd_pci_quirk cxt5066_fixups[] = { |
3313 | SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC), | 3386 | SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC), |
3387 | SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN), | ||
3314 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), | 3388 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), |
3315 | SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410), | 3389 | SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410), |
3316 | SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410), | 3390 | SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410), |
@@ -3395,7 +3469,8 @@ static int patch_conexant_auto(struct hda_codec *codec) | |||
3395 | 3469 | ||
3396 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); | 3470 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); |
3397 | 3471 | ||
3398 | err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0); | 3472 | err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, |
3473 | spec->parse_flags); | ||
3399 | if (err < 0) | 3474 | if (err < 0) |
3400 | goto error; | 3475 | goto error; |
3401 | 3476 | ||
@@ -3416,6 +3491,8 @@ static int patch_conexant_auto(struct hda_codec *codec) | |||
3416 | codec->bus->allow_bus_reset = 1; | 3491 | codec->bus->allow_bus_reset = 1; |
3417 | } | 3492 | } |
3418 | 3493 | ||
3494 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); | ||
3495 | |||
3419 | return 0; | 3496 | return 0; |
3420 | 3497 | ||
3421 | error: | 3498 | error: |
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 9f3586276871..9a58893d52a7 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c | |||
@@ -67,6 +67,8 @@ struct hdmi_spec_per_pin { | |||
67 | struct delayed_work work; | 67 | struct delayed_work work; |
68 | struct snd_kcontrol *eld_ctl; | 68 | struct snd_kcontrol *eld_ctl; |
69 | int repoll_count; | 69 | int repoll_count; |
70 | bool setup; /* the stream has been set up by prepare callback */ | ||
71 | int channels; /* current number of channels */ | ||
70 | bool non_pcm; | 72 | bool non_pcm; |
71 | bool chmap_set; /* channel-map override by ALSA API? */ | 73 | bool chmap_set; /* channel-map override by ALSA API? */ |
72 | unsigned char chmap[8]; /* ALSA API channel-map */ | 74 | unsigned char chmap[8]; /* ALSA API channel-map */ |
@@ -551,6 +553,17 @@ static int hdmi_channel_allocation(struct hdmi_eld *eld, int channels) | |||
551 | } | 553 | } |
552 | } | 554 | } |
553 | 555 | ||
556 | if (!ca) { | ||
557 | /* if there was no match, select the regular ALSA channel | ||
558 | * allocation with the matching number of channels */ | ||
559 | for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { | ||
560 | if (channels == channel_allocations[i].channels) { | ||
561 | ca = channel_allocations[i].ca_index; | ||
562 | break; | ||
563 | } | ||
564 | } | ||
565 | } | ||
566 | |||
554 | snd_print_channel_allocation(eld->info.spk_alloc, buf, sizeof(buf)); | 567 | snd_print_channel_allocation(eld->info.spk_alloc, buf, sizeof(buf)); |
555 | snd_printdd("HDMI: select CA 0x%x for %d-channel allocation: %s\n", | 568 | snd_printdd("HDMI: select CA 0x%x for %d-channel allocation: %s\n", |
556 | ca, channels, buf); | 569 | ca, channels, buf); |
@@ -868,18 +881,19 @@ static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid, | |||
868 | return true; | 881 | return true; |
869 | } | 882 | } |
870 | 883 | ||
871 | static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx, | 884 | static void hdmi_setup_audio_infoframe(struct hda_codec *codec, |
872 | bool non_pcm, | 885 | struct hdmi_spec_per_pin *per_pin, |
873 | struct snd_pcm_substream *substream) | 886 | bool non_pcm) |
874 | { | 887 | { |
875 | struct hdmi_spec *spec = codec->spec; | ||
876 | struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); | ||
877 | hda_nid_t pin_nid = per_pin->pin_nid; | 888 | hda_nid_t pin_nid = per_pin->pin_nid; |
878 | int channels = substream->runtime->channels; | 889 | int channels = per_pin->channels; |
879 | struct hdmi_eld *eld; | 890 | struct hdmi_eld *eld; |
880 | int ca; | 891 | int ca; |
881 | union audio_infoframe ai; | 892 | union audio_infoframe ai; |
882 | 893 | ||
894 | if (!channels) | ||
895 | return; | ||
896 | |||
883 | eld = &per_pin->sink_eld; | 897 | eld = &per_pin->sink_eld; |
884 | if (!eld->monitor_present) | 898 | if (!eld->monitor_present) |
885 | return; | 899 | return; |
@@ -959,6 +973,7 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) | |||
959 | int pin_nid; | 973 | int pin_nid; |
960 | int pin_idx; | 974 | int pin_idx; |
961 | struct hda_jack_tbl *jack; | 975 | struct hda_jack_tbl *jack; |
976 | int dev_entry = (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT; | ||
962 | 977 | ||
963 | jack = snd_hda_jack_tbl_get_from_tag(codec, tag); | 978 | jack = snd_hda_jack_tbl_get_from_tag(codec, tag); |
964 | if (!jack) | 979 | if (!jack) |
@@ -967,8 +982,8 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) | |||
967 | jack->jack_dirty = 1; | 982 | jack->jack_dirty = 1; |
968 | 983 | ||
969 | _snd_printd(SND_PR_VERBOSE, | 984 | _snd_printd(SND_PR_VERBOSE, |
970 | "HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", | 985 | "HDMI hot plug event: Codec=%d Pin=%d Device=%d Inactive=%d Presence_Detect=%d ELD_Valid=%d\n", |
971 | codec->addr, pin_nid, | 986 | codec->addr, pin_nid, dev_entry, !!(res & AC_UNSOL_RES_IA), |
972 | !!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV)); | 987 | !!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV)); |
973 | 988 | ||
974 | pin_idx = pin_nid_to_pin_index(spec, pin_nid); | 989 | pin_idx = pin_nid_to_pin_index(spec, pin_nid); |
@@ -1329,6 +1344,7 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) | |||
1329 | eld_changed = true; | 1344 | eld_changed = true; |
1330 | } | 1345 | } |
1331 | if (update_eld) { | 1346 | if (update_eld) { |
1347 | bool old_eld_valid = pin_eld->eld_valid; | ||
1332 | pin_eld->eld_valid = eld->eld_valid; | 1348 | pin_eld->eld_valid = eld->eld_valid; |
1333 | eld_changed = pin_eld->eld_size != eld->eld_size || | 1349 | eld_changed = pin_eld->eld_size != eld->eld_size || |
1334 | memcmp(pin_eld->eld_buffer, eld->eld_buffer, | 1350 | memcmp(pin_eld->eld_buffer, eld->eld_buffer, |
@@ -1338,6 +1354,18 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) | |||
1338 | eld->eld_size); | 1354 | eld->eld_size); |
1339 | pin_eld->eld_size = eld->eld_size; | 1355 | pin_eld->eld_size = eld->eld_size; |
1340 | pin_eld->info = eld->info; | 1356 | pin_eld->info = eld->info; |
1357 | |||
1358 | /* Haswell-specific workaround: re-setup when the transcoder is | ||
1359 | * changed during the stream playback | ||
1360 | */ | ||
1361 | if (codec->vendor_id == 0x80862807 && | ||
1362 | eld->eld_valid && !old_eld_valid && per_pin->setup) { | ||
1363 | snd_hda_codec_write(codec, pin_nid, 0, | ||
1364 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
1365 | AMP_OUT_UNMUTE); | ||
1366 | hdmi_setup_audio_infoframe(codec, per_pin, | ||
1367 | per_pin->non_pcm); | ||
1368 | } | ||
1341 | } | 1369 | } |
1342 | mutex_unlock(&pin_eld->lock); | 1370 | mutex_unlock(&pin_eld->lock); |
1343 | 1371 | ||
@@ -1510,14 +1538,17 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | |||
1510 | hda_nid_t cvt_nid = hinfo->nid; | 1538 | hda_nid_t cvt_nid = hinfo->nid; |
1511 | struct hdmi_spec *spec = codec->spec; | 1539 | struct hdmi_spec *spec = codec->spec; |
1512 | int pin_idx = hinfo_to_pin_index(spec, hinfo); | 1540 | int pin_idx = hinfo_to_pin_index(spec, hinfo); |
1513 | hda_nid_t pin_nid = get_pin(spec, pin_idx)->pin_nid; | 1541 | struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); |
1542 | hda_nid_t pin_nid = per_pin->pin_nid; | ||
1514 | bool non_pcm; | 1543 | bool non_pcm; |
1515 | 1544 | ||
1516 | non_pcm = check_non_pcm_per_cvt(codec, cvt_nid); | 1545 | non_pcm = check_non_pcm_per_cvt(codec, cvt_nid); |
1546 | per_pin->channels = substream->runtime->channels; | ||
1547 | per_pin->setup = true; | ||
1517 | 1548 | ||
1518 | hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels); | 1549 | hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels); |
1519 | 1550 | ||
1520 | hdmi_setup_audio_infoframe(codec, pin_idx, non_pcm, substream); | 1551 | hdmi_setup_audio_infoframe(codec, per_pin, non_pcm); |
1521 | 1552 | ||
1522 | return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format); | 1553 | return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format); |
1523 | } | 1554 | } |
@@ -1557,6 +1588,9 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, | |||
1557 | snd_hda_spdif_ctls_unassign(codec, pin_idx); | 1588 | snd_hda_spdif_ctls_unassign(codec, pin_idx); |
1558 | per_pin->chmap_set = false; | 1589 | per_pin->chmap_set = false; |
1559 | memset(per_pin->chmap, 0, sizeof(per_pin->chmap)); | 1590 | memset(per_pin->chmap, 0, sizeof(per_pin->chmap)); |
1591 | |||
1592 | per_pin->setup = false; | ||
1593 | per_pin->channels = 0; | ||
1560 | } | 1594 | } |
1561 | 1595 | ||
1562 | return 0; | 1596 | return 0; |
@@ -1692,8 +1726,7 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol, | |||
1692 | per_pin->chmap_set = true; | 1726 | per_pin->chmap_set = true; |
1693 | memcpy(per_pin->chmap, chmap, sizeof(chmap)); | 1727 | memcpy(per_pin->chmap, chmap, sizeof(chmap)); |
1694 | if (prepared) | 1728 | if (prepared) |
1695 | hdmi_setup_audio_infoframe(codec, pin_idx, per_pin->non_pcm, | 1729 | hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm); |
1696 | substream); | ||
1697 | 1730 | ||
1698 | return 0; | 1731 | return 0; |
1699 | } | 1732 | } |
@@ -1992,8 +2025,10 @@ static int patch_generic_hdmi(struct hda_codec *codec) | |||
1992 | return -EINVAL; | 2025 | return -EINVAL; |
1993 | } | 2026 | } |
1994 | codec->patch_ops = generic_hdmi_patch_ops; | 2027 | codec->patch_ops = generic_hdmi_patch_ops; |
1995 | if (codec->vendor_id == 0x80862807) | 2028 | if (codec->vendor_id == 0x80862807) { |
1996 | codec->patch_ops.set_power_state = haswell_set_power_state; | 2029 | codec->patch_ops.set_power_state = haswell_set_power_state; |
2030 | codec->dp_mst = true; | ||
2031 | } | ||
1997 | 2032 | ||
1998 | generic_hdmi_init_per_pins(codec); | 2033 | generic_hdmi_init_per_pins(codec); |
1999 | 2034 | ||
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 389db4c2801b..9e9378cde8fa 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -282,6 +282,7 @@ static void alc_eapd_shutup(struct hda_codec *codec) | |||
282 | { | 282 | { |
283 | alc_auto_setup_eapd(codec, false); | 283 | alc_auto_setup_eapd(codec, false); |
284 | msleep(200); | 284 | msleep(200); |
285 | snd_hda_shutup_pins(codec); | ||
285 | } | 286 | } |
286 | 287 | ||
287 | /* generic EAPD initialization */ | 288 | /* generic EAPD initialization */ |
@@ -826,7 +827,8 @@ static inline void alc_shutup(struct hda_codec *codec) | |||
826 | 827 | ||
827 | if (spec && spec->shutup) | 828 | if (spec && spec->shutup) |
828 | spec->shutup(codec); | 829 | spec->shutup(codec); |
829 | snd_hda_shutup_pins(codec); | 830 | else |
831 | snd_hda_shutup_pins(codec); | ||
830 | } | 832 | } |
831 | 833 | ||
832 | #define alc_free snd_hda_gen_free | 834 | #define alc_free snd_hda_gen_free |
@@ -1853,8 +1855,10 @@ static void alc882_fixup_no_primary_hp(struct hda_codec *codec, | |||
1853 | const struct hda_fixup *fix, int action) | 1855 | const struct hda_fixup *fix, int action) |
1854 | { | 1856 | { |
1855 | struct alc_spec *spec = codec->spec; | 1857 | struct alc_spec *spec = codec->spec; |
1856 | if (action == HDA_FIXUP_ACT_PRE_PROBE) | 1858 | if (action == HDA_FIXUP_ACT_PRE_PROBE) { |
1857 | spec->gen.no_primary_hp = 1; | 1859 | spec->gen.no_primary_hp = 1; |
1860 | spec->gen.no_multi_io = 1; | ||
1861 | } | ||
1858 | } | 1862 | } |
1859 | 1863 | ||
1860 | static const struct hda_fixup alc882_fixups[] = { | 1864 | static const struct hda_fixup alc882_fixups[] = { |
@@ -2533,6 +2537,7 @@ enum { | |||
2533 | ALC269_TYPE_ALC269VD, | 2537 | ALC269_TYPE_ALC269VD, |
2534 | ALC269_TYPE_ALC280, | 2538 | ALC269_TYPE_ALC280, |
2535 | ALC269_TYPE_ALC282, | 2539 | ALC269_TYPE_ALC282, |
2540 | ALC269_TYPE_ALC283, | ||
2536 | ALC269_TYPE_ALC284, | 2541 | ALC269_TYPE_ALC284, |
2537 | ALC269_TYPE_ALC286, | 2542 | ALC269_TYPE_ALC286, |
2538 | }; | 2543 | }; |
@@ -2558,6 +2563,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec) | |||
2558 | case ALC269_TYPE_ALC269VB: | 2563 | case ALC269_TYPE_ALC269VB: |
2559 | case ALC269_TYPE_ALC269VD: | 2564 | case ALC269_TYPE_ALC269VD: |
2560 | case ALC269_TYPE_ALC282: | 2565 | case ALC269_TYPE_ALC282: |
2566 | case ALC269_TYPE_ALC283: | ||
2561 | case ALC269_TYPE_ALC286: | 2567 | case ALC269_TYPE_ALC286: |
2562 | ssids = alc269_ssids; | 2568 | ssids = alc269_ssids; |
2563 | break; | 2569 | break; |
@@ -2583,15 +2589,81 @@ static void alc269_shutup(struct hda_codec *codec) | |||
2583 | { | 2589 | { |
2584 | struct alc_spec *spec = codec->spec; | 2590 | struct alc_spec *spec = codec->spec; |
2585 | 2591 | ||
2586 | if (spec->codec_variant != ALC269_TYPE_ALC269VB) | ||
2587 | return; | ||
2588 | |||
2589 | if (spec->codec_variant == ALC269_TYPE_ALC269VB) | 2592 | if (spec->codec_variant == ALC269_TYPE_ALC269VB) |
2590 | alc269vb_toggle_power_output(codec, 0); | 2593 | alc269vb_toggle_power_output(codec, 0); |
2591 | if (spec->codec_variant == ALC269_TYPE_ALC269VB && | 2594 | if (spec->codec_variant == ALC269_TYPE_ALC269VB && |
2592 | (alc_get_coef0(codec) & 0x00ff) == 0x018) { | 2595 | (alc_get_coef0(codec) & 0x00ff) == 0x018) { |
2593 | msleep(150); | 2596 | msleep(150); |
2594 | } | 2597 | } |
2598 | snd_hda_shutup_pins(codec); | ||
2599 | } | ||
2600 | |||
2601 | static void alc283_init(struct hda_codec *codec) | ||
2602 | { | ||
2603 | struct alc_spec *spec = codec->spec; | ||
2604 | hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; | ||
2605 | bool hp_pin_sense; | ||
2606 | int val; | ||
2607 | |||
2608 | if (!hp_pin) | ||
2609 | return; | ||
2610 | hp_pin_sense = snd_hda_jack_detect(codec, hp_pin); | ||
2611 | |||
2612 | /* Index 0x43 Direct Drive HP AMP LPM Control 1 */ | ||
2613 | /* Headphone capless set to high power mode */ | ||
2614 | alc_write_coef_idx(codec, 0x43, 0x9004); | ||
2615 | |||
2616 | snd_hda_codec_write(codec, hp_pin, 0, | ||
2617 | AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); | ||
2618 | |||
2619 | if (hp_pin_sense) | ||
2620 | msleep(85); | ||
2621 | |||
2622 | snd_hda_codec_write(codec, hp_pin, 0, | ||
2623 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); | ||
2624 | |||
2625 | if (hp_pin_sense) | ||
2626 | msleep(85); | ||
2627 | /* Index 0x46 Combo jack auto switch control 2 */ | ||
2628 | /* 3k pull low control for Headset jack. */ | ||
2629 | val = alc_read_coef_idx(codec, 0x46); | ||
2630 | alc_write_coef_idx(codec, 0x46, val & ~(3 << 12)); | ||
2631 | /* Headphone capless set to normal mode */ | ||
2632 | alc_write_coef_idx(codec, 0x43, 0x9614); | ||
2633 | } | ||
2634 | |||
2635 | static void alc283_shutup(struct hda_codec *codec) | ||
2636 | { | ||
2637 | struct alc_spec *spec = codec->spec; | ||
2638 | hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; | ||
2639 | bool hp_pin_sense; | ||
2640 | int val; | ||
2641 | |||
2642 | if (!hp_pin) { | ||
2643 | alc269_shutup(codec); | ||
2644 | return; | ||
2645 | } | ||
2646 | |||
2647 | hp_pin_sense = snd_hda_jack_detect(codec, hp_pin); | ||
2648 | |||
2649 | alc_write_coef_idx(codec, 0x43, 0x9004); | ||
2650 | |||
2651 | snd_hda_codec_write(codec, hp_pin, 0, | ||
2652 | AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); | ||
2653 | |||
2654 | if (hp_pin_sense) | ||
2655 | msleep(85); | ||
2656 | |||
2657 | snd_hda_codec_write(codec, hp_pin, 0, | ||
2658 | AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); | ||
2659 | |||
2660 | val = alc_read_coef_idx(codec, 0x46); | ||
2661 | alc_write_coef_idx(codec, 0x46, val | (3 << 12)); | ||
2662 | |||
2663 | if (hp_pin_sense) | ||
2664 | msleep(85); | ||
2665 | snd_hda_shutup_pins(codec); | ||
2666 | alc_write_coef_idx(codec, 0x43, 0x9614); | ||
2595 | } | 2667 | } |
2596 | 2668 | ||
2597 | static void alc5505_coef_set(struct hda_codec *codec, unsigned int index_reg, | 2669 | static void alc5505_coef_set(struct hda_codec *codec, unsigned int index_reg, |
@@ -2722,6 +2794,7 @@ static int alc269_resume(struct hda_codec *codec) | |||
2722 | hda_call_check_power_status(codec, 0x01); | 2794 | hda_call_check_power_status(codec, 0x01); |
2723 | if (spec->has_alc5505_dsp) | 2795 | if (spec->has_alc5505_dsp) |
2724 | alc5505_dsp_resume(codec); | 2796 | alc5505_dsp_resume(codec); |
2797 | |||
2725 | return 0; | 2798 | return 0; |
2726 | } | 2799 | } |
2727 | #endif /* CONFIG_PM */ | 2800 | #endif /* CONFIG_PM */ |
@@ -3261,6 +3334,28 @@ static void alc_fixup_headset_mode_alc668(struct hda_codec *codec, | |||
3261 | alc_fixup_headset_mode(codec, fix, action); | 3334 | alc_fixup_headset_mode(codec, fix, action); |
3262 | } | 3335 | } |
3263 | 3336 | ||
3337 | /* Returns the nid of the external mic input pin, or 0 if it cannot be found. */ | ||
3338 | static int find_ext_mic_pin(struct hda_codec *codec) | ||
3339 | { | ||
3340 | struct alc_spec *spec = codec->spec; | ||
3341 | struct auto_pin_cfg *cfg = &spec->gen.autocfg; | ||
3342 | hda_nid_t nid; | ||
3343 | unsigned int defcfg; | ||
3344 | int i; | ||
3345 | |||
3346 | for (i = 0; i < cfg->num_inputs; i++) { | ||
3347 | if (cfg->inputs[i].type != AUTO_PIN_MIC) | ||
3348 | continue; | ||
3349 | nid = cfg->inputs[i].pin; | ||
3350 | defcfg = snd_hda_codec_get_pincfg(codec, nid); | ||
3351 | if (snd_hda_get_input_pin_attr(defcfg) == INPUT_PIN_ATTR_INT) | ||
3352 | continue; | ||
3353 | return nid; | ||
3354 | } | ||
3355 | |||
3356 | return 0; | ||
3357 | } | ||
3358 | |||
3264 | static void alc271_hp_gate_mic_jack(struct hda_codec *codec, | 3359 | static void alc271_hp_gate_mic_jack(struct hda_codec *codec, |
3265 | const struct hda_fixup *fix, | 3360 | const struct hda_fixup *fix, |
3266 | int action) | 3361 | int action) |
@@ -3268,11 +3363,12 @@ static void alc271_hp_gate_mic_jack(struct hda_codec *codec, | |||
3268 | struct alc_spec *spec = codec->spec; | 3363 | struct alc_spec *spec = codec->spec; |
3269 | 3364 | ||
3270 | if (action == HDA_FIXUP_ACT_PROBE) { | 3365 | if (action == HDA_FIXUP_ACT_PROBE) { |
3271 | if (snd_BUG_ON(!spec->gen.am_entry[1].pin || | 3366 | int mic_pin = find_ext_mic_pin(codec); |
3272 | !spec->gen.autocfg.hp_pins[0])) | 3367 | int hp_pin = spec->gen.autocfg.hp_pins[0]; |
3368 | |||
3369 | if (snd_BUG_ON(!mic_pin || !hp_pin)) | ||
3273 | return; | 3370 | return; |
3274 | snd_hda_jack_set_gating_jack(codec, spec->gen.am_entry[1].pin, | 3371 | snd_hda_jack_set_gating_jack(codec, mic_pin, hp_pin); |
3275 | spec->gen.autocfg.hp_pins[0]); | ||
3276 | } | 3372 | } |
3277 | } | 3373 | } |
3278 | 3374 | ||
@@ -3308,6 +3404,45 @@ static void alc269_fixup_limit_int_mic_boost(struct hda_codec *codec, | |||
3308 | } | 3404 | } |
3309 | } | 3405 | } |
3310 | 3406 | ||
3407 | static void alc283_hp_automute_hook(struct hda_codec *codec, | ||
3408 | struct hda_jack_tbl *jack) | ||
3409 | { | ||
3410 | struct alc_spec *spec = codec->spec; | ||
3411 | int vref; | ||
3412 | |||
3413 | msleep(200); | ||
3414 | snd_hda_gen_hp_automute(codec, jack); | ||
3415 | |||
3416 | vref = spec->gen.hp_jack_present ? PIN_VREF80 : 0; | ||
3417 | |||
3418 | msleep(600); | ||
3419 | snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
3420 | vref); | ||
3421 | } | ||
3422 | |||
3423 | static void alc283_chromebook_caps(struct hda_codec *codec) | ||
3424 | { | ||
3425 | snd_hda_override_wcaps(codec, 0x03, 0); | ||
3426 | } | ||
3427 | |||
3428 | static void alc283_fixup_chromebook(struct hda_codec *codec, | ||
3429 | const struct hda_fixup *fix, int action) | ||
3430 | { | ||
3431 | struct alc_spec *spec = codec->spec; | ||
3432 | int val; | ||
3433 | |||
3434 | switch (action) { | ||
3435 | case HDA_FIXUP_ACT_PRE_PROBE: | ||
3436 | alc283_chromebook_caps(codec); | ||
3437 | spec->gen.hp_automute_hook = alc283_hp_automute_hook; | ||
3438 | /* MIC2-VREF control */ | ||
3439 | /* Set to manual mode */ | ||
3440 | val = alc_read_coef_idx(codec, 0x06); | ||
3441 | alc_write_coef_idx(codec, 0x06, val & ~0x000c); | ||
3442 | break; | ||
3443 | } | ||
3444 | } | ||
3445 | |||
3311 | enum { | 3446 | enum { |
3312 | ALC269_FIXUP_SONY_VAIO, | 3447 | ALC269_FIXUP_SONY_VAIO, |
3313 | ALC275_FIXUP_SONY_VAIO_GPIO2, | 3448 | ALC275_FIXUP_SONY_VAIO_GPIO2, |
@@ -3344,6 +3479,7 @@ enum { | |||
3344 | ALC269_FIXUP_ACER_AC700, | 3479 | ALC269_FIXUP_ACER_AC700, |
3345 | ALC269_FIXUP_LIMIT_INT_MIC_BOOST, | 3480 | ALC269_FIXUP_LIMIT_INT_MIC_BOOST, |
3346 | ALC269VB_FIXUP_ORDISSIMO_EVE2, | 3481 | ALC269VB_FIXUP_ORDISSIMO_EVE2, |
3482 | ALC283_FIXUP_CHROME_BOOK, | ||
3347 | }; | 3483 | }; |
3348 | 3484 | ||
3349 | static const struct hda_fixup alc269_fixups[] = { | 3485 | static const struct hda_fixup alc269_fixups[] = { |
@@ -3595,11 +3731,20 @@ static const struct hda_fixup alc269_fixups[] = { | |||
3595 | { } | 3731 | { } |
3596 | }, | 3732 | }, |
3597 | }, | 3733 | }, |
3734 | [ALC283_FIXUP_CHROME_BOOK] = { | ||
3735 | .type = HDA_FIXUP_FUNC, | ||
3736 | .v.func = alc283_fixup_chromebook, | ||
3737 | }, | ||
3598 | }; | 3738 | }; |
3599 | 3739 | ||
3600 | static const struct snd_pci_quirk alc269_fixup_tbl[] = { | 3740 | static const struct snd_pci_quirk alc269_fixup_tbl[] = { |
3601 | SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC), | 3741 | SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC), |
3602 | SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC), | 3742 | SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC), |
3743 | SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700), | ||
3744 | SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK), | ||
3745 | SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK), | ||
3746 | SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC), | ||
3747 | SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), | ||
3603 | SND_PCI_QUIRK(0x1028, 0x05bd, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), | 3748 | SND_PCI_QUIRK(0x1028, 0x05bd, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), |
3604 | SND_PCI_QUIRK(0x1028, 0x05be, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), | 3749 | SND_PCI_QUIRK(0x1028, 0x05be, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), |
3605 | SND_PCI_QUIRK(0x1028, 0x05c4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), | 3750 | SND_PCI_QUIRK(0x1028, 0x05c4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), |
@@ -3637,6 +3782,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
3637 | SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED), | 3782 | SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED), |
3638 | SND_PCI_QUIRK(0x103c, 0x1973, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1), | 3783 | SND_PCI_QUIRK(0x103c, 0x1973, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1), |
3639 | SND_PCI_QUIRK(0x103c, 0x1983, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1), | 3784 | SND_PCI_QUIRK(0x103c, 0x1983, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1), |
3785 | SND_PCI_QUIRK(0x103c, 0x21ed, "HP Falco Chromebook", ALC283_FIXUP_CHROME_BOOK), | ||
3640 | SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED), | 3786 | SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED), |
3641 | SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | 3787 | SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), |
3642 | SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | 3788 | SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), |
@@ -3655,11 +3801,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
3655 | SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), | 3801 | SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), |
3656 | SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), | 3802 | SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), |
3657 | SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), | 3803 | SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), |
3658 | SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), | ||
3659 | SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700), | ||
3660 | SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK), | ||
3661 | SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK), | ||
3662 | SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC), | ||
3663 | SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK), | 3804 | SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK), |
3664 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), | 3805 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), |
3665 | SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE), | 3806 | SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE), |
@@ -3670,8 +3811,16 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
3670 | SND_PCI_QUIRK(0x17aa, 0x21fa, "Thinkpad X230", ALC269_FIXUP_LENOVO_DOCK), | 3811 | SND_PCI_QUIRK(0x17aa, 0x21fa, "Thinkpad X230", ALC269_FIXUP_LENOVO_DOCK), |
3671 | SND_PCI_QUIRK(0x17aa, 0x21f3, "Thinkpad T430", ALC269_FIXUP_LENOVO_DOCK), | 3812 | SND_PCI_QUIRK(0x17aa, 0x21f3, "Thinkpad T430", ALC269_FIXUP_LENOVO_DOCK), |
3672 | SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK), | 3813 | SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK), |
3673 | SND_PCI_QUIRK(0x17aa, 0x2208, "Thinkpad T431s", ALC269_FIXUP_LENOVO_DOCK), | ||
3674 | SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK), | 3814 | SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK), |
3815 | SND_PCI_QUIRK(0x17aa, 0x2208, "Thinkpad T431s", ALC269_FIXUP_LENOVO_DOCK), | ||
3816 | SND_PCI_QUIRK(0x17aa, 0x220c, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | ||
3817 | SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | ||
3818 | SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | ||
3819 | SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | ||
3820 | SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | ||
3821 | SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | ||
3822 | SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | ||
3823 | SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | ||
3675 | SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), | 3824 | SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), |
3676 | SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), | 3825 | SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), |
3677 | SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */ | 3826 | SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */ |
@@ -3840,11 +3989,15 @@ static int patch_alc269(struct hda_codec *codec) | |||
3840 | case 0x10ec0290: | 3989 | case 0x10ec0290: |
3841 | spec->codec_variant = ALC269_TYPE_ALC280; | 3990 | spec->codec_variant = ALC269_TYPE_ALC280; |
3842 | break; | 3991 | break; |
3843 | case 0x10ec0233: | ||
3844 | case 0x10ec0282: | 3992 | case 0x10ec0282: |
3845 | case 0x10ec0283: | ||
3846 | spec->codec_variant = ALC269_TYPE_ALC282; | 3993 | spec->codec_variant = ALC269_TYPE_ALC282; |
3847 | break; | 3994 | break; |
3995 | case 0x10ec0233: | ||
3996 | case 0x10ec0283: | ||
3997 | spec->codec_variant = ALC269_TYPE_ALC283; | ||
3998 | spec->shutup = alc283_shutup; | ||
3999 | spec->init_hook = alc283_init; | ||
4000 | break; | ||
3848 | case 0x10ec0284: | 4001 | case 0x10ec0284: |
3849 | case 0x10ec0292: | 4002 | case 0x10ec0292: |
3850 | spec->codec_variant = ALC269_TYPE_ALC284; | 4003 | spec->codec_variant = ALC269_TYPE_ALC284; |
@@ -3872,7 +4025,8 @@ static int patch_alc269(struct hda_codec *codec) | |||
3872 | codec->patch_ops.suspend = alc269_suspend; | 4025 | codec->patch_ops.suspend = alc269_suspend; |
3873 | codec->patch_ops.resume = alc269_resume; | 4026 | codec->patch_ops.resume = alc269_resume; |
3874 | #endif | 4027 | #endif |
3875 | spec->shutup = alc269_shutup; | 4028 | if (!spec->shutup) |
4029 | spec->shutup = alc269_shutup; | ||
3876 | 4030 | ||
3877 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); | 4031 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); |
3878 | 4032 | ||
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 6d1924c19abf..fba0cef1c47f 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -158,6 +158,7 @@ enum { | |||
158 | STAC_D965_VERBS, | 158 | STAC_D965_VERBS, |
159 | STAC_DELL_3ST, | 159 | STAC_DELL_3ST, |
160 | STAC_DELL_BIOS, | 160 | STAC_DELL_BIOS, |
161 | STAC_DELL_BIOS_AMIC, | ||
161 | STAC_DELL_BIOS_SPDIF, | 162 | STAC_DELL_BIOS_SPDIF, |
162 | STAC_927X_DELL_DMIC, | 163 | STAC_927X_DELL_DMIC, |
163 | STAC_927X_VOLKNOB, | 164 | STAC_927X_VOLKNOB, |
@@ -3231,8 +3232,6 @@ static const struct hda_fixup stac927x_fixups[] = { | |||
3231 | [STAC_DELL_BIOS] = { | 3232 | [STAC_DELL_BIOS] = { |
3232 | .type = HDA_FIXUP_PINS, | 3233 | .type = HDA_FIXUP_PINS, |
3233 | .v.pins = (const struct hda_pintbl[]) { | 3234 | .v.pins = (const struct hda_pintbl[]) { |
3234 | /* configure the analog microphone on some laptops */ | ||
3235 | { 0x0c, 0x90a79130 }, | ||
3236 | /* correct the front output jack as a hp out */ | 3235 | /* correct the front output jack as a hp out */ |
3237 | { 0x0f, 0x0221101f }, | 3236 | { 0x0f, 0x0221101f }, |
3238 | /* correct the front input jack as a mic */ | 3237 | /* correct the front input jack as a mic */ |
@@ -3242,6 +3241,16 @@ static const struct hda_fixup stac927x_fixups[] = { | |||
3242 | .chained = true, | 3241 | .chained = true, |
3243 | .chain_id = STAC_927X_DELL_DMIC, | 3242 | .chain_id = STAC_927X_DELL_DMIC, |
3244 | }, | 3243 | }, |
3244 | [STAC_DELL_BIOS_AMIC] = { | ||
3245 | .type = HDA_FIXUP_PINS, | ||
3246 | .v.pins = (const struct hda_pintbl[]) { | ||
3247 | /* configure the analog microphone on some laptops */ | ||
3248 | { 0x0c, 0x90a79130 }, | ||
3249 | {} | ||
3250 | }, | ||
3251 | .chained = true, | ||
3252 | .chain_id = STAC_DELL_BIOS, | ||
3253 | }, | ||
3245 | [STAC_DELL_BIOS_SPDIF] = { | 3254 | [STAC_DELL_BIOS_SPDIF] = { |
3246 | .type = HDA_FIXUP_PINS, | 3255 | .type = HDA_FIXUP_PINS, |
3247 | .v.pins = (const struct hda_pintbl[]) { | 3256 | .v.pins = (const struct hda_pintbl[]) { |
@@ -3270,6 +3279,7 @@ static const struct hda_model_fixup stac927x_models[] = { | |||
3270 | { .id = STAC_D965_5ST_NO_FP, .name = "5stack-no-fp" }, | 3279 | { .id = STAC_D965_5ST_NO_FP, .name = "5stack-no-fp" }, |
3271 | { .id = STAC_DELL_3ST, .name = "dell-3stack" }, | 3280 | { .id = STAC_DELL_3ST, .name = "dell-3stack" }, |
3272 | { .id = STAC_DELL_BIOS, .name = "dell-bios" }, | 3281 | { .id = STAC_DELL_BIOS, .name = "dell-bios" }, |
3282 | { .id = STAC_DELL_BIOS_AMIC, .name = "dell-bios-amic" }, | ||
3273 | { .id = STAC_927X_VOLKNOB, .name = "volknob" }, | 3283 | { .id = STAC_927X_VOLKNOB, .name = "volknob" }, |
3274 | {} | 3284 | {} |
3275 | }; | 3285 | }; |
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index e2481baddc70..0bc20ef5687a 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c | |||
@@ -207,9 +207,9 @@ static void vt1708_stop_hp_work(struct hda_codec *codec) | |||
207 | return; | 207 | return; |
208 | if (spec->hp_work_active) { | 208 | if (spec->hp_work_active) { |
209 | snd_hda_codec_write(codec, 0x1, 0, 0xf81, 1); | 209 | snd_hda_codec_write(codec, 0x1, 0, 0xf81, 1); |
210 | codec->jackpoll_interval = 0; | ||
210 | cancel_delayed_work_sync(&codec->jackpoll_work); | 211 | cancel_delayed_work_sync(&codec->jackpoll_work); |
211 | spec->hp_work_active = false; | 212 | spec->hp_work_active = false; |
212 | codec->jackpoll_interval = 0; | ||
213 | } | 213 | } |
214 | } | 214 | } |
215 | 215 | ||
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 2a8ad9d1a2ae..bb9ebc5543d7 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
29 | #include <linux/pci.h> | 29 | #include <linux/pci.h> |
30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
31 | #include <linux/vmalloc.h> | ||
31 | 32 | ||
32 | #include <sound/core.h> | 33 | #include <sound/core.h> |
33 | #include <sound/info.h> | 34 | #include <sound/info.h> |
@@ -198,6 +199,31 @@ MODULE_PARM_DESC(enable, "Enable RME Digi96 soundcard."); | |||
198 | #define RME96_AD1852_VOL_BITS 14 | 199 | #define RME96_AD1852_VOL_BITS 14 |
199 | #define RME96_AD1855_VOL_BITS 10 | 200 | #define RME96_AD1855_VOL_BITS 10 |
200 | 201 | ||
202 | /* Defines for snd_rme96_trigger */ | ||
203 | #define RME96_TB_START_PLAYBACK 1 | ||
204 | #define RME96_TB_START_CAPTURE 2 | ||
205 | #define RME96_TB_STOP_PLAYBACK 4 | ||
206 | #define RME96_TB_STOP_CAPTURE 8 | ||
207 | #define RME96_TB_RESET_PLAYPOS 16 | ||
208 | #define RME96_TB_RESET_CAPTUREPOS 32 | ||
209 | #define RME96_TB_CLEAR_PLAYBACK_IRQ 64 | ||
210 | #define RME96_TB_CLEAR_CAPTURE_IRQ 128 | ||
211 | #define RME96_RESUME_PLAYBACK (RME96_TB_START_PLAYBACK) | ||
212 | #define RME96_RESUME_CAPTURE (RME96_TB_START_CAPTURE) | ||
213 | #define RME96_RESUME_BOTH (RME96_RESUME_PLAYBACK \ | ||
214 | | RME96_RESUME_CAPTURE) | ||
215 | #define RME96_START_PLAYBACK (RME96_TB_START_PLAYBACK \ | ||
216 | | RME96_TB_RESET_PLAYPOS) | ||
217 | #define RME96_START_CAPTURE (RME96_TB_START_CAPTURE \ | ||
218 | | RME96_TB_RESET_CAPTUREPOS) | ||
219 | #define RME96_START_BOTH (RME96_START_PLAYBACK \ | ||
220 | | RME96_START_CAPTURE) | ||
221 | #define RME96_STOP_PLAYBACK (RME96_TB_STOP_PLAYBACK \ | ||
222 | | RME96_TB_CLEAR_PLAYBACK_IRQ) | ||
223 | #define RME96_STOP_CAPTURE (RME96_TB_STOP_CAPTURE \ | ||
224 | | RME96_TB_CLEAR_CAPTURE_IRQ) | ||
225 | #define RME96_STOP_BOTH (RME96_STOP_PLAYBACK \ | ||
226 | | RME96_STOP_CAPTURE) | ||
201 | 227 | ||
202 | struct rme96 { | 228 | struct rme96 { |
203 | spinlock_t lock; | 229 | spinlock_t lock; |
@@ -214,6 +240,13 @@ struct rme96 { | |||
214 | 240 | ||
215 | u8 rev; /* card revision number */ | 241 | u8 rev; /* card revision number */ |
216 | 242 | ||
243 | #ifdef CONFIG_PM | ||
244 | u32 playback_pointer; | ||
245 | u32 capture_pointer; | ||
246 | void *playback_suspend_buffer; | ||
247 | void *capture_suspend_buffer; | ||
248 | #endif | ||
249 | |||
217 | struct snd_pcm_substream *playback_substream; | 250 | struct snd_pcm_substream *playback_substream; |
218 | struct snd_pcm_substream *capture_substream; | 251 | struct snd_pcm_substream *capture_substream; |
219 | 252 | ||
@@ -344,6 +377,8 @@ static struct snd_pcm_hardware snd_rme96_playback_spdif_info = | |||
344 | { | 377 | { |
345 | .info = (SNDRV_PCM_INFO_MMAP_IOMEM | | 378 | .info = (SNDRV_PCM_INFO_MMAP_IOMEM | |
346 | SNDRV_PCM_INFO_MMAP_VALID | | 379 | SNDRV_PCM_INFO_MMAP_VALID | |
380 | SNDRV_PCM_INFO_SYNC_START | | ||
381 | SNDRV_PCM_INFO_RESUME | | ||
347 | SNDRV_PCM_INFO_INTERLEAVED | | 382 | SNDRV_PCM_INFO_INTERLEAVED | |
348 | SNDRV_PCM_INFO_PAUSE), | 383 | SNDRV_PCM_INFO_PAUSE), |
349 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | | 384 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | |
@@ -373,6 +408,8 @@ static struct snd_pcm_hardware snd_rme96_capture_spdif_info = | |||
373 | { | 408 | { |
374 | .info = (SNDRV_PCM_INFO_MMAP_IOMEM | | 409 | .info = (SNDRV_PCM_INFO_MMAP_IOMEM | |
375 | SNDRV_PCM_INFO_MMAP_VALID | | 410 | SNDRV_PCM_INFO_MMAP_VALID | |
411 | SNDRV_PCM_INFO_SYNC_START | | ||
412 | SNDRV_PCM_INFO_RESUME | | ||
376 | SNDRV_PCM_INFO_INTERLEAVED | | 413 | SNDRV_PCM_INFO_INTERLEAVED | |
377 | SNDRV_PCM_INFO_PAUSE), | 414 | SNDRV_PCM_INFO_PAUSE), |
378 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | | 415 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | |
@@ -402,6 +439,8 @@ static struct snd_pcm_hardware snd_rme96_playback_adat_info = | |||
402 | { | 439 | { |
403 | .info = (SNDRV_PCM_INFO_MMAP_IOMEM | | 440 | .info = (SNDRV_PCM_INFO_MMAP_IOMEM | |
404 | SNDRV_PCM_INFO_MMAP_VALID | | 441 | SNDRV_PCM_INFO_MMAP_VALID | |
442 | SNDRV_PCM_INFO_SYNC_START | | ||
443 | SNDRV_PCM_INFO_RESUME | | ||
405 | SNDRV_PCM_INFO_INTERLEAVED | | 444 | SNDRV_PCM_INFO_INTERLEAVED | |
406 | SNDRV_PCM_INFO_PAUSE), | 445 | SNDRV_PCM_INFO_PAUSE), |
407 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | | 446 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | |
@@ -427,6 +466,8 @@ static struct snd_pcm_hardware snd_rme96_capture_adat_info = | |||
427 | { | 466 | { |
428 | .info = (SNDRV_PCM_INFO_MMAP_IOMEM | | 467 | .info = (SNDRV_PCM_INFO_MMAP_IOMEM | |
429 | SNDRV_PCM_INFO_MMAP_VALID | | 468 | SNDRV_PCM_INFO_MMAP_VALID | |
469 | SNDRV_PCM_INFO_SYNC_START | | ||
470 | SNDRV_PCM_INFO_RESUME | | ||
430 | SNDRV_PCM_INFO_INTERLEAVED | | 471 | SNDRV_PCM_INFO_INTERLEAVED | |
431 | SNDRV_PCM_INFO_PAUSE), | 472 | SNDRV_PCM_INFO_PAUSE), |
432 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | | 473 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | |
@@ -1045,54 +1086,35 @@ snd_rme96_capture_hw_params(struct snd_pcm_substream *substream, | |||
1045 | } | 1086 | } |
1046 | 1087 | ||
1047 | static void | 1088 | static void |
1048 | snd_rme96_playback_start(struct rme96 *rme96, | 1089 | snd_rme96_trigger(struct rme96 *rme96, |
1049 | int from_pause) | 1090 | int op) |
1050 | { | 1091 | { |
1051 | if (!from_pause) { | 1092 | if (op & RME96_TB_RESET_PLAYPOS) |
1052 | writel(0, rme96->iobase + RME96_IO_RESET_PLAY_POS); | 1093 | writel(0, rme96->iobase + RME96_IO_RESET_PLAY_POS); |
1053 | } | 1094 | if (op & RME96_TB_RESET_CAPTUREPOS) |
1054 | |||
1055 | rme96->wcreg |= RME96_WCR_START; | ||
1056 | writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER); | ||
1057 | } | ||
1058 | |||
1059 | static void | ||
1060 | snd_rme96_capture_start(struct rme96 *rme96, | ||
1061 | int from_pause) | ||
1062 | { | ||
1063 | if (!from_pause) { | ||
1064 | writel(0, rme96->iobase + RME96_IO_RESET_REC_POS); | 1095 | writel(0, rme96->iobase + RME96_IO_RESET_REC_POS); |
1065 | } | 1096 | if (op & RME96_TB_CLEAR_PLAYBACK_IRQ) { |
1066 | 1097 | rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER); | |
1067 | rme96->wcreg |= RME96_WCR_START_2; | 1098 | if (rme96->rcreg & RME96_RCR_IRQ) |
1099 | writel(0, rme96->iobase + RME96_IO_CONFIRM_PLAY_IRQ); | ||
1100 | } | ||
1101 | if (op & RME96_TB_CLEAR_CAPTURE_IRQ) { | ||
1102 | rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER); | ||
1103 | if (rme96->rcreg & RME96_RCR_IRQ_2) | ||
1104 | writel(0, rme96->iobase + RME96_IO_CONFIRM_REC_IRQ); | ||
1105 | } | ||
1106 | if (op & RME96_TB_START_PLAYBACK) | ||
1107 | rme96->wcreg |= RME96_WCR_START; | ||
1108 | if (op & RME96_TB_STOP_PLAYBACK) | ||
1109 | rme96->wcreg &= ~RME96_WCR_START; | ||
1110 | if (op & RME96_TB_START_CAPTURE) | ||
1111 | rme96->wcreg |= RME96_WCR_START_2; | ||
1112 | if (op & RME96_TB_STOP_CAPTURE) | ||
1113 | rme96->wcreg &= ~RME96_WCR_START_2; | ||
1068 | writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER); | 1114 | writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER); |
1069 | } | 1115 | } |
1070 | 1116 | ||
1071 | static void | ||
1072 | snd_rme96_playback_stop(struct rme96 *rme96) | ||
1073 | { | ||
1074 | /* | ||
1075 | * Check if there is an unconfirmed IRQ, if so confirm it, or else | ||
1076 | * the hardware will not stop generating interrupts | ||
1077 | */ | ||
1078 | rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER); | ||
1079 | if (rme96->rcreg & RME96_RCR_IRQ) { | ||
1080 | writel(0, rme96->iobase + RME96_IO_CONFIRM_PLAY_IRQ); | ||
1081 | } | ||
1082 | rme96->wcreg &= ~RME96_WCR_START; | ||
1083 | writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER); | ||
1084 | } | ||
1085 | 1117 | ||
1086 | static void | ||
1087 | snd_rme96_capture_stop(struct rme96 *rme96) | ||
1088 | { | ||
1089 | rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER); | ||
1090 | if (rme96->rcreg & RME96_RCR_IRQ_2) { | ||
1091 | writel(0, rme96->iobase + RME96_IO_CONFIRM_REC_IRQ); | ||
1092 | } | ||
1093 | rme96->wcreg &= ~RME96_WCR_START_2; | ||
1094 | writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER); | ||
1095 | } | ||
1096 | 1118 | ||
1097 | static irqreturn_t | 1119 | static irqreturn_t |
1098 | snd_rme96_interrupt(int irq, | 1120 | snd_rme96_interrupt(int irq, |
@@ -1155,6 +1177,7 @@ snd_rme96_playback_spdif_open(struct snd_pcm_substream *substream) | |||
1155 | struct rme96 *rme96 = snd_pcm_substream_chip(substream); | 1177 | struct rme96 *rme96 = snd_pcm_substream_chip(substream); |
1156 | struct snd_pcm_runtime *runtime = substream->runtime; | 1178 | struct snd_pcm_runtime *runtime = substream->runtime; |
1157 | 1179 | ||
1180 | snd_pcm_set_sync(substream); | ||
1158 | spin_lock_irq(&rme96->lock); | 1181 | spin_lock_irq(&rme96->lock); |
1159 | if (rme96->playback_substream != NULL) { | 1182 | if (rme96->playback_substream != NULL) { |
1160 | spin_unlock_irq(&rme96->lock); | 1183 | spin_unlock_irq(&rme96->lock); |
@@ -1191,6 +1214,7 @@ snd_rme96_capture_spdif_open(struct snd_pcm_substream *substream) | |||
1191 | struct rme96 *rme96 = snd_pcm_substream_chip(substream); | 1214 | struct rme96 *rme96 = snd_pcm_substream_chip(substream); |
1192 | struct snd_pcm_runtime *runtime = substream->runtime; | 1215 | struct snd_pcm_runtime *runtime = substream->runtime; |
1193 | 1216 | ||
1217 | snd_pcm_set_sync(substream); | ||
1194 | runtime->hw = snd_rme96_capture_spdif_info; | 1218 | runtime->hw = snd_rme96_capture_spdif_info; |
1195 | if (snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG && | 1219 | if (snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG && |
1196 | (rate = snd_rme96_capture_getrate(rme96, &isadat)) > 0) | 1220 | (rate = snd_rme96_capture_getrate(rme96, &isadat)) > 0) |
@@ -1222,6 +1246,7 @@ snd_rme96_playback_adat_open(struct snd_pcm_substream *substream) | |||
1222 | struct rme96 *rme96 = snd_pcm_substream_chip(substream); | 1246 | struct rme96 *rme96 = snd_pcm_substream_chip(substream); |
1223 | struct snd_pcm_runtime *runtime = substream->runtime; | 1247 | struct snd_pcm_runtime *runtime = substream->runtime; |
1224 | 1248 | ||
1249 | snd_pcm_set_sync(substream); | ||
1225 | spin_lock_irq(&rme96->lock); | 1250 | spin_lock_irq(&rme96->lock); |
1226 | if (rme96->playback_substream != NULL) { | 1251 | if (rme96->playback_substream != NULL) { |
1227 | spin_unlock_irq(&rme96->lock); | 1252 | spin_unlock_irq(&rme96->lock); |
@@ -1253,6 +1278,7 @@ snd_rme96_capture_adat_open(struct snd_pcm_substream *substream) | |||
1253 | struct rme96 *rme96 = snd_pcm_substream_chip(substream); | 1278 | struct rme96 *rme96 = snd_pcm_substream_chip(substream); |
1254 | struct snd_pcm_runtime *runtime = substream->runtime; | 1279 | struct snd_pcm_runtime *runtime = substream->runtime; |
1255 | 1280 | ||
1281 | snd_pcm_set_sync(substream); | ||
1256 | runtime->hw = snd_rme96_capture_adat_info; | 1282 | runtime->hw = snd_rme96_capture_adat_info; |
1257 | if (snd_rme96_getinputtype(rme96) == RME96_INPUT_ANALOG) { | 1283 | if (snd_rme96_getinputtype(rme96) == RME96_INPUT_ANALOG) { |
1258 | /* makes no sense to use analog input. Note that analog | 1284 | /* makes no sense to use analog input. Note that analog |
@@ -1288,7 +1314,7 @@ snd_rme96_playback_close(struct snd_pcm_substream *substream) | |||
1288 | 1314 | ||
1289 | spin_lock_irq(&rme96->lock); | 1315 | spin_lock_irq(&rme96->lock); |
1290 | if (RME96_ISPLAYING(rme96)) { | 1316 | if (RME96_ISPLAYING(rme96)) { |
1291 | snd_rme96_playback_stop(rme96); | 1317 | snd_rme96_trigger(rme96, RME96_STOP_PLAYBACK); |
1292 | } | 1318 | } |
1293 | rme96->playback_substream = NULL; | 1319 | rme96->playback_substream = NULL; |
1294 | rme96->playback_periodsize = 0; | 1320 | rme96->playback_periodsize = 0; |
@@ -1309,7 +1335,7 @@ snd_rme96_capture_close(struct snd_pcm_substream *substream) | |||
1309 | 1335 | ||
1310 | spin_lock_irq(&rme96->lock); | 1336 | spin_lock_irq(&rme96->lock); |
1311 | if (RME96_ISRECORDING(rme96)) { | 1337 | if (RME96_ISRECORDING(rme96)) { |
1312 | snd_rme96_capture_stop(rme96); | 1338 | snd_rme96_trigger(rme96, RME96_STOP_CAPTURE); |
1313 | } | 1339 | } |
1314 | rme96->capture_substream = NULL; | 1340 | rme96->capture_substream = NULL; |
1315 | rme96->capture_periodsize = 0; | 1341 | rme96->capture_periodsize = 0; |
@@ -1324,7 +1350,7 @@ snd_rme96_playback_prepare(struct snd_pcm_substream *substream) | |||
1324 | 1350 | ||
1325 | spin_lock_irq(&rme96->lock); | 1351 | spin_lock_irq(&rme96->lock); |
1326 | if (RME96_ISPLAYING(rme96)) { | 1352 | if (RME96_ISPLAYING(rme96)) { |
1327 | snd_rme96_playback_stop(rme96); | 1353 | snd_rme96_trigger(rme96, RME96_STOP_PLAYBACK); |
1328 | } | 1354 | } |
1329 | writel(0, rme96->iobase + RME96_IO_RESET_PLAY_POS); | 1355 | writel(0, rme96->iobase + RME96_IO_RESET_PLAY_POS); |
1330 | spin_unlock_irq(&rme96->lock); | 1356 | spin_unlock_irq(&rme96->lock); |
@@ -1338,7 +1364,7 @@ snd_rme96_capture_prepare(struct snd_pcm_substream *substream) | |||
1338 | 1364 | ||
1339 | spin_lock_irq(&rme96->lock); | 1365 | spin_lock_irq(&rme96->lock); |
1340 | if (RME96_ISRECORDING(rme96)) { | 1366 | if (RME96_ISRECORDING(rme96)) { |
1341 | snd_rme96_capture_stop(rme96); | 1367 | snd_rme96_trigger(rme96, RME96_STOP_CAPTURE); |
1342 | } | 1368 | } |
1343 | writel(0, rme96->iobase + RME96_IO_RESET_REC_POS); | 1369 | writel(0, rme96->iobase + RME96_IO_RESET_REC_POS); |
1344 | spin_unlock_irq(&rme96->lock); | 1370 | spin_unlock_irq(&rme96->lock); |
@@ -1350,41 +1376,55 @@ snd_rme96_playback_trigger(struct snd_pcm_substream *substream, | |||
1350 | int cmd) | 1376 | int cmd) |
1351 | { | 1377 | { |
1352 | struct rme96 *rme96 = snd_pcm_substream_chip(substream); | 1378 | struct rme96 *rme96 = snd_pcm_substream_chip(substream); |
1379 | struct snd_pcm_substream *s; | ||
1380 | bool sync; | ||
1381 | |||
1382 | snd_pcm_group_for_each_entry(s, substream) { | ||
1383 | if (snd_pcm_substream_chip(s) == rme96) | ||
1384 | snd_pcm_trigger_done(s, substream); | ||
1385 | } | ||
1386 | |||
1387 | sync = (rme96->playback_substream && rme96->capture_substream) && | ||
1388 | (rme96->playback_substream->group == | ||
1389 | rme96->capture_substream->group); | ||
1353 | 1390 | ||
1354 | switch (cmd) { | 1391 | switch (cmd) { |
1355 | case SNDRV_PCM_TRIGGER_START: | 1392 | case SNDRV_PCM_TRIGGER_START: |
1356 | if (!RME96_ISPLAYING(rme96)) { | 1393 | if (!RME96_ISPLAYING(rme96)) { |
1357 | if (substream != rme96->playback_substream) { | 1394 | if (substream != rme96->playback_substream) |
1358 | return -EBUSY; | 1395 | return -EBUSY; |
1359 | } | 1396 | snd_rme96_trigger(rme96, sync ? RME96_START_BOTH |
1360 | snd_rme96_playback_start(rme96, 0); | 1397 | : RME96_START_PLAYBACK); |
1361 | } | 1398 | } |
1362 | break; | 1399 | break; |
1363 | 1400 | ||
1401 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
1364 | case SNDRV_PCM_TRIGGER_STOP: | 1402 | case SNDRV_PCM_TRIGGER_STOP: |
1365 | if (RME96_ISPLAYING(rme96)) { | 1403 | if (RME96_ISPLAYING(rme96)) { |
1366 | if (substream != rme96->playback_substream) { | 1404 | if (substream != rme96->playback_substream) |
1367 | return -EBUSY; | 1405 | return -EBUSY; |
1368 | } | 1406 | snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH |
1369 | snd_rme96_playback_stop(rme96); | 1407 | : RME96_STOP_PLAYBACK); |
1370 | } | 1408 | } |
1371 | break; | 1409 | break; |
1372 | 1410 | ||
1373 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 1411 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
1374 | if (RME96_ISPLAYING(rme96)) { | 1412 | if (RME96_ISPLAYING(rme96)) |
1375 | snd_rme96_playback_stop(rme96); | 1413 | snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH |
1376 | } | 1414 | : RME96_STOP_PLAYBACK); |
1377 | break; | 1415 | break; |
1378 | 1416 | ||
1417 | case SNDRV_PCM_TRIGGER_RESUME: | ||
1379 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 1418 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
1380 | if (!RME96_ISPLAYING(rme96)) { | 1419 | if (!RME96_ISPLAYING(rme96)) |
1381 | snd_rme96_playback_start(rme96, 1); | 1420 | snd_rme96_trigger(rme96, sync ? RME96_RESUME_BOTH |
1382 | } | 1421 | : RME96_RESUME_PLAYBACK); |
1383 | break; | 1422 | break; |
1384 | 1423 | ||
1385 | default: | 1424 | default: |
1386 | return -EINVAL; | 1425 | return -EINVAL; |
1387 | } | 1426 | } |
1427 | |||
1388 | return 0; | 1428 | return 0; |
1389 | } | 1429 | } |
1390 | 1430 | ||
@@ -1393,38 +1433,51 @@ snd_rme96_capture_trigger(struct snd_pcm_substream *substream, | |||
1393 | int cmd) | 1433 | int cmd) |
1394 | { | 1434 | { |
1395 | struct rme96 *rme96 = snd_pcm_substream_chip(substream); | 1435 | struct rme96 *rme96 = snd_pcm_substream_chip(substream); |
1436 | struct snd_pcm_substream *s; | ||
1437 | bool sync; | ||
1438 | |||
1439 | snd_pcm_group_for_each_entry(s, substream) { | ||
1440 | if (snd_pcm_substream_chip(s) == rme96) | ||
1441 | snd_pcm_trigger_done(s, substream); | ||
1442 | } | ||
1443 | |||
1444 | sync = (rme96->playback_substream && rme96->capture_substream) && | ||
1445 | (rme96->playback_substream->group == | ||
1446 | rme96->capture_substream->group); | ||
1396 | 1447 | ||
1397 | switch (cmd) { | 1448 | switch (cmd) { |
1398 | case SNDRV_PCM_TRIGGER_START: | 1449 | case SNDRV_PCM_TRIGGER_START: |
1399 | if (!RME96_ISRECORDING(rme96)) { | 1450 | if (!RME96_ISRECORDING(rme96)) { |
1400 | if (substream != rme96->capture_substream) { | 1451 | if (substream != rme96->capture_substream) |
1401 | return -EBUSY; | 1452 | return -EBUSY; |
1402 | } | 1453 | snd_rme96_trigger(rme96, sync ? RME96_START_BOTH |
1403 | snd_rme96_capture_start(rme96, 0); | 1454 | : RME96_START_CAPTURE); |
1404 | } | 1455 | } |
1405 | break; | 1456 | break; |
1406 | 1457 | ||
1458 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
1407 | case SNDRV_PCM_TRIGGER_STOP: | 1459 | case SNDRV_PCM_TRIGGER_STOP: |
1408 | if (RME96_ISRECORDING(rme96)) { | 1460 | if (RME96_ISRECORDING(rme96)) { |
1409 | if (substream != rme96->capture_substream) { | 1461 | if (substream != rme96->capture_substream) |
1410 | return -EBUSY; | 1462 | return -EBUSY; |
1411 | } | 1463 | snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH |
1412 | snd_rme96_capture_stop(rme96); | 1464 | : RME96_STOP_CAPTURE); |
1413 | } | 1465 | } |
1414 | break; | 1466 | break; |
1415 | 1467 | ||
1416 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 1468 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
1417 | if (RME96_ISRECORDING(rme96)) { | 1469 | if (RME96_ISRECORDING(rme96)) |
1418 | snd_rme96_capture_stop(rme96); | 1470 | snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH |
1419 | } | 1471 | : RME96_STOP_CAPTURE); |
1420 | break; | 1472 | break; |
1421 | 1473 | ||
1474 | case SNDRV_PCM_TRIGGER_RESUME: | ||
1422 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 1475 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
1423 | if (!RME96_ISRECORDING(rme96)) { | 1476 | if (!RME96_ISRECORDING(rme96)) |
1424 | snd_rme96_capture_start(rme96, 1); | 1477 | snd_rme96_trigger(rme96, sync ? RME96_RESUME_BOTH |
1425 | } | 1478 | : RME96_RESUME_CAPTURE); |
1426 | break; | 1479 | break; |
1427 | 1480 | ||
1428 | default: | 1481 | default: |
1429 | return -EINVAL; | 1482 | return -EINVAL; |
1430 | } | 1483 | } |
@@ -1505,8 +1558,7 @@ snd_rme96_free(void *private_data) | |||
1505 | return; | 1558 | return; |
1506 | } | 1559 | } |
1507 | if (rme96->irq >= 0) { | 1560 | if (rme96->irq >= 0) { |
1508 | snd_rme96_playback_stop(rme96); | 1561 | snd_rme96_trigger(rme96, RME96_STOP_BOTH); |
1509 | snd_rme96_capture_stop(rme96); | ||
1510 | rme96->areg &= ~RME96_AR_DAC_EN; | 1562 | rme96->areg &= ~RME96_AR_DAC_EN; |
1511 | writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG); | 1563 | writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG); |
1512 | free_irq(rme96->irq, (void *)rme96); | 1564 | free_irq(rme96->irq, (void *)rme96); |
@@ -1520,6 +1572,10 @@ snd_rme96_free(void *private_data) | |||
1520 | pci_release_regions(rme96->pci); | 1572 | pci_release_regions(rme96->pci); |
1521 | rme96->port = 0; | 1573 | rme96->port = 0; |
1522 | } | 1574 | } |
1575 | #ifdef CONFIG_PM | ||
1576 | vfree(rme96->playback_suspend_buffer); | ||
1577 | vfree(rme96->capture_suspend_buffer); | ||
1578 | #endif | ||
1523 | pci_disable_device(rme96->pci); | 1579 | pci_disable_device(rme96->pci); |
1524 | } | 1580 | } |
1525 | 1581 | ||
@@ -1606,8 +1662,7 @@ snd_rme96_create(struct rme96 *rme96) | |||
1606 | rme96->capture_periodsize = 0; | 1662 | rme96->capture_periodsize = 0; |
1607 | 1663 | ||
1608 | /* make sure playback/capture is stopped, if by some reason active */ | 1664 | /* make sure playback/capture is stopped, if by some reason active */ |
1609 | snd_rme96_playback_stop(rme96); | 1665 | snd_rme96_trigger(rme96, RME96_STOP_BOTH); |
1610 | snd_rme96_capture_stop(rme96); | ||
1611 | 1666 | ||
1612 | /* set default values in registers */ | 1667 | /* set default values in registers */ |
1613 | rme96->wcreg = | 1668 | rme96->wcreg = |
@@ -2319,6 +2374,87 @@ snd_rme96_create_switches(struct snd_card *card, | |||
2319 | * Card initialisation | 2374 | * Card initialisation |
2320 | */ | 2375 | */ |
2321 | 2376 | ||
2377 | #ifdef CONFIG_PM | ||
2378 | |||
2379 | static int | ||
2380 | snd_rme96_suspend(struct pci_dev *pci, | ||
2381 | pm_message_t state) | ||
2382 | { | ||
2383 | struct snd_card *card = pci_get_drvdata(pci); | ||
2384 | struct rme96 *rme96 = card->private_data; | ||
2385 | |||
2386 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | ||
2387 | snd_pcm_suspend(rme96->playback_substream); | ||
2388 | snd_pcm_suspend(rme96->capture_substream); | ||
2389 | |||
2390 | /* save capture & playback pointers */ | ||
2391 | rme96->playback_pointer = readl(rme96->iobase + RME96_IO_GET_PLAY_POS) | ||
2392 | & RME96_RCR_AUDIO_ADDR_MASK; | ||
2393 | rme96->capture_pointer = readl(rme96->iobase + RME96_IO_GET_REC_POS) | ||
2394 | & RME96_RCR_AUDIO_ADDR_MASK; | ||
2395 | |||
2396 | /* save playback and capture buffers */ | ||
2397 | memcpy_fromio(rme96->playback_suspend_buffer, | ||
2398 | rme96->iobase + RME96_IO_PLAY_BUFFER, RME96_BUFFER_SIZE); | ||
2399 | memcpy_fromio(rme96->capture_suspend_buffer, | ||
2400 | rme96->iobase + RME96_IO_REC_BUFFER, RME96_BUFFER_SIZE); | ||
2401 | |||
2402 | /* disable the DAC */ | ||
2403 | rme96->areg &= ~RME96_AR_DAC_EN; | ||
2404 | writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG); | ||
2405 | |||
2406 | pci_disable_device(pci); | ||
2407 | pci_save_state(pci); | ||
2408 | |||
2409 | return 0; | ||
2410 | } | ||
2411 | |||
2412 | static int | ||
2413 | snd_rme96_resume(struct pci_dev *pci) | ||
2414 | { | ||
2415 | struct snd_card *card = pci_get_drvdata(pci); | ||
2416 | struct rme96 *rme96 = card->private_data; | ||
2417 | |||
2418 | pci_restore_state(pci); | ||
2419 | if (pci_enable_device(pci) < 0) { | ||
2420 | printk(KERN_ERR "rme96: pci_enable_device failed, disabling device\n"); | ||
2421 | snd_card_disconnect(card); | ||
2422 | return -EIO; | ||
2423 | } | ||
2424 | |||
2425 | /* reset playback and record buffer pointers */ | ||
2426 | writel(0, rme96->iobase + RME96_IO_SET_PLAY_POS | ||
2427 | + rme96->playback_pointer); | ||
2428 | writel(0, rme96->iobase + RME96_IO_SET_REC_POS | ||
2429 | + rme96->capture_pointer); | ||
2430 | |||
2431 | /* restore playback and capture buffers */ | ||
2432 | memcpy_toio(rme96->iobase + RME96_IO_PLAY_BUFFER, | ||
2433 | rme96->playback_suspend_buffer, RME96_BUFFER_SIZE); | ||
2434 | memcpy_toio(rme96->iobase + RME96_IO_REC_BUFFER, | ||
2435 | rme96->capture_suspend_buffer, RME96_BUFFER_SIZE); | ||
2436 | |||
2437 | /* reset the ADC */ | ||
2438 | writel(rme96->areg | RME96_AR_PD2, | ||
2439 | rme96->iobase + RME96_IO_ADDITIONAL_REG); | ||
2440 | writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG); | ||
2441 | |||
2442 | /* reset and enable DAC, restore analog volume */ | ||
2443 | snd_rme96_reset_dac(rme96); | ||
2444 | rme96->areg |= RME96_AR_DAC_EN; | ||
2445 | writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG); | ||
2446 | if (RME96_HAS_ANALOG_OUT(rme96)) { | ||
2447 | usleep_range(3000, 10000); | ||
2448 | snd_rme96_apply_dac_volume(rme96); | ||
2449 | } | ||
2450 | |||
2451 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | ||
2452 | |||
2453 | return 0; | ||
2454 | } | ||
2455 | |||
2456 | #endif | ||
2457 | |||
2322 | static void snd_rme96_card_free(struct snd_card *card) | 2458 | static void snd_rme96_card_free(struct snd_card *card) |
2323 | { | 2459 | { |
2324 | snd_rme96_free(card->private_data); | 2460 | snd_rme96_free(card->private_data); |
@@ -2355,6 +2491,23 @@ snd_rme96_probe(struct pci_dev *pci, | |||
2355 | return err; | 2491 | return err; |
2356 | } | 2492 | } |
2357 | 2493 | ||
2494 | #ifdef CONFIG_PM | ||
2495 | rme96->playback_suspend_buffer = vmalloc(RME96_BUFFER_SIZE); | ||
2496 | if (!rme96->playback_suspend_buffer) { | ||
2497 | snd_printk(KERN_ERR | ||
2498 | "Failed to allocate playback suspend buffer!\n"); | ||
2499 | snd_card_free(card); | ||
2500 | return -ENOMEM; | ||
2501 | } | ||
2502 | rme96->capture_suspend_buffer = vmalloc(RME96_BUFFER_SIZE); | ||
2503 | if (!rme96->capture_suspend_buffer) { | ||
2504 | snd_printk(KERN_ERR | ||
2505 | "Failed to allocate capture suspend buffer!\n"); | ||
2506 | snd_card_free(card); | ||
2507 | return -ENOMEM; | ||
2508 | } | ||
2509 | #endif | ||
2510 | |||
2358 | strcpy(card->driver, "Digi96"); | 2511 | strcpy(card->driver, "Digi96"); |
2359 | switch (rme96->pci->device) { | 2512 | switch (rme96->pci->device) { |
2360 | case PCI_DEVICE_ID_RME_DIGI96: | 2513 | case PCI_DEVICE_ID_RME_DIGI96: |
@@ -2397,6 +2550,10 @@ static struct pci_driver rme96_driver = { | |||
2397 | .id_table = snd_rme96_ids, | 2550 | .id_table = snd_rme96_ids, |
2398 | .probe = snd_rme96_probe, | 2551 | .probe = snd_rme96_probe, |
2399 | .remove = snd_rme96_remove, | 2552 | .remove = snd_rme96_remove, |
2553 | #ifdef CONFIG_PM | ||
2554 | .suspend = snd_rme96_suspend, | ||
2555 | .resume = snd_rme96_resume, | ||
2556 | #endif | ||
2400 | }; | 2557 | }; |
2401 | 2558 | ||
2402 | module_pci_driver(rme96_driver); | 2559 | module_pci_driver(rme96_driver); |
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index bd501931ee23..3cde55b753e2 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c | |||
@@ -38,6 +38,97 @@ | |||
38 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 38 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
39 | * | 39 | * |
40 | */ | 40 | */ |
41 | |||
42 | /* ************* Register Documentation ******************************************************* | ||
43 | * | ||
44 | * Work in progress! Documentation is based on the code in this file. | ||
45 | * | ||
46 | * --------- HDSPM_controlRegister --------- | ||
47 | * :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte | ||
48 | * :||||.||||:||||.||||:||||.||||:||||.||||: | ||
49 | * :3322.2222:2222.1111:1111.1100:0000.0000: bit number | ||
50 | * :1098.7654:3210.9876:5432.1098:7654.3210: 0..31 | ||
51 | * :||||.||||:||||.||||:||||.||||:||||.||||: | ||
52 | * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit | ||
53 | * : . : . : . : x . : HDSPM_AudioInterruptEnable \_ setting both bits | ||
54 | * : . : . : . : . x: HDSPM_Start / enables audio IO | ||
55 | * : . : . : . : x. : HDSPM_ClockModeMaster - 1: Master, 0: Slave | ||
56 | * : . : . : . : .210 : HDSPM_LatencyMask - 3 Bit value for latency | ||
57 | * : . : . : . : . : 0:64, 1:128, 2:256, 3:512, | ||
58 | * : . : . : . : . : 4:1024, 5:2048, 6:4096, 7:8192 | ||
59 | * :x . : . : . x:xx . : HDSPM_FrequencyMask | ||
60 | * : . : . : . :10 . : HDSPM_Frequency1|HDSPM_Frequency0: 1=32K,2=44.1K,3=48K,0=?? | ||
61 | * : . : . : . x: . : <MADI> HDSPM_DoubleSpeed | ||
62 | * :x . : . : . : . : <MADI> HDSPM_QuadSpeed | ||
63 | * : . 3 : . 10: 2 . : . : HDSPM_SyncRefMask : | ||
64 | * : . : . x: . : . : HDSPM_SyncRef0 | ||
65 | * : . : . x : . : . : HDSPM_SyncRef1 | ||
66 | * : . : . : x . : . : <AES32> HDSPM_SyncRef2 | ||
67 | * : . x : . : . : . : <AES32> HDSPM_SyncRef3 | ||
68 | * : . : . 10: . : . : <MADI> sync ref: 0:WC, 1:Madi, 2:TCO, 3:SyncIn | ||
69 | * : . 3 : . 10: 2 . : . : <AES32> 0:WC, 1:AES1 ... 8:AES8, 9: TCO, 10:SyncIn? | ||
70 | * : . x : . : . : . : <MADIe> HDSPe_FLOAT_FORMAT | ||
71 | * : . : . : x . : . : <MADI> HDSPM_InputSelect0 : 0=optical,1=coax | ||
72 | * : . : . :x . : . : <MADI> HDSPM_InputSelect1 | ||
73 | * : . : .x : . : . : <MADI> HDSPM_clr_tms | ||
74 | * : . : . : . x : . : <MADI> HDSPM_TX_64ch | ||
75 | * : . : . : . x : . : <AES32> HDSPM_Emphasis | ||
76 | * : . : . : .x : . : <MADI> HDSPM_AutoInp | ||
77 | * : . : . x : . : . : <MADI> HDSPM_SMUX | ||
78 | * : . : .x : . : . : <MADI> HDSPM_clr_tms | ||
79 | * : . : x. : . : . : <MADI> HDSPM_taxi_reset | ||
80 | * : . x: . : . : . : <MADI> HDSPM_LineOut | ||
81 | * : . x: . : . : . : <AES32> ?????????????????? | ||
82 | * : . : x. : . : . : <AES32> HDSPM_WCK48 | ||
83 | * : . : . : .x : . : <AES32> HDSPM_Dolby | ||
84 | * : . : x . : . : . : HDSPM_Midi0InterruptEnable | ||
85 | * : . :x . : . : . : HDSPM_Midi1InterruptEnable | ||
86 | * : . : x . : . : . : HDSPM_Midi2InterruptEnable | ||
87 | * : . x : . : . : . : <MADI> HDSPM_Midi3InterruptEnable | ||
88 | * : . x : . : . : . : <AES32> HDSPM_DS_DoubleWire | ||
89 | * : .x : . : . : . : <AES32> HDSPM_QS_DoubleWire | ||
90 | * : x. : . : . : . : <AES32> HDSPM_QS_QuadWire | ||
91 | * : . : . : . x : . : <AES32> HDSPM_Professional | ||
92 | * : x . : . : . : . : HDSPM_wclk_sel | ||
93 | * : . : . : . : . : | ||
94 | * :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte | ||
95 | * :||||.||||:||||.||||:||||.||||:||||.||||: | ||
96 | * :3322.2222:2222.1111:1111.1100:0000.0000: bit number | ||
97 | * :1098.7654:3210.9876:5432.1098:7654.3210: 0..31 | ||
98 | * :||||.||||:||||.||||:||||.||||:||||.||||: | ||
99 | * :8421.8421:8421.8421:8421.8421:8421.8421:hex digit | ||
100 | * | ||
101 | * | ||
102 | * | ||
103 | * AIO / RayDAT only | ||
104 | * | ||
105 | * ------------ HDSPM_WR_SETTINGS ---------- | ||
106 | * :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte | ||
107 | * :1098.7654:3210.9876:5432.1098:7654.3210: | ||
108 | * :||||.||||:||||.||||:||||.||||:||||.||||: bit number | ||
109 | * :7654.3210:7654.3210:7654.3210:7654.3210: 0..31 | ||
110 | * :||||.||||:||||.||||:||||.||||:||||.||||: | ||
111 | * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit | ||
112 | * : . : . : . : . x: HDSPM_c0Master 1: Master, 0: Slave | ||
113 | * : . : . : . : . x : HDSPM_c0_SyncRef0 | ||
114 | * : . : . : . : . x : HDSPM_c0_SyncRef1 | ||
115 | * : . : . : . : .x : HDSPM_c0_SyncRef2 | ||
116 | * : . : . : . : x. : HDSPM_c0_SyncRef3 | ||
117 | * : . : . : . : 3.210 : HDSPM_c0_SyncRefMask: | ||
118 | * : . : . : . : . : RayDat: 0:WC, 1:AES, 2:SPDIF, 3..6: ADAT1..4, | ||
119 | * : . : . : . : . : 9:TCO, 10:SyncIn | ||
120 | * : . : . : . : . : AIO: 0:WC, 1:AES, 2: SPDIF, 3: ATAT, | ||
121 | * : . : . : . : . : 9:TCO, 10:SyncIn | ||
122 | * : . : . : . : . : | ||
123 | * : . : . : . : . : | ||
124 | * :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte | ||
125 | * :1098.7654:3210.9876:5432.1098:7654.3210: | ||
126 | * :||||.||||:||||.||||:||||.||||:||||.||||: bit number | ||
127 | * :7654.3210:7654.3210:7654.3210:7654.3210: 0..31 | ||
128 | * :||||.||||:||||.||||:||||.||||:||||.||||: | ||
129 | * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit | ||
130 | * | ||
131 | */ | ||
41 | #include <linux/init.h> | 132 | #include <linux/init.h> |
42 | #include <linux/delay.h> | 133 | #include <linux/delay.h> |
43 | #include <linux/interrupt.h> | 134 | #include <linux/interrupt.h> |
@@ -95,7 +186,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); | |||
95 | #define HDSPM_controlRegister 64 | 186 | #define HDSPM_controlRegister 64 |
96 | #define HDSPM_interruptConfirmation 96 | 187 | #define HDSPM_interruptConfirmation 96 |
97 | #define HDSPM_control2Reg 256 /* not in specs ???????? */ | 188 | #define HDSPM_control2Reg 256 /* not in specs ???????? */ |
98 | #define HDSPM_freqReg 256 /* for AES32 */ | 189 | #define HDSPM_freqReg 256 /* for setting arbitrary clock values (DDS feature) */ |
99 | #define HDSPM_midiDataOut0 352 /* just believe in old code */ | 190 | #define HDSPM_midiDataOut0 352 /* just believe in old code */ |
100 | #define HDSPM_midiDataOut1 356 | 191 | #define HDSPM_midiDataOut1 356 |
101 | #define HDSPM_eeprom_wr 384 /* for AES32 */ | 192 | #define HDSPM_eeprom_wr 384 /* for AES32 */ |
@@ -258,6 +349,25 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); | |||
258 | 349 | ||
259 | #define HDSPM_wclk_sel (1<<30) | 350 | #define HDSPM_wclk_sel (1<<30) |
260 | 351 | ||
352 | /* additional control register bits for AIO*/ | ||
353 | #define HDSPM_c0_Wck48 0x20 /* also RayDAT */ | ||
354 | #define HDSPM_c0_Input0 0x1000 | ||
355 | #define HDSPM_c0_Input1 0x2000 | ||
356 | #define HDSPM_c0_Spdif_Opt 0x4000 | ||
357 | #define HDSPM_c0_Pro 0x8000 | ||
358 | #define HDSPM_c0_clr_tms 0x10000 | ||
359 | #define HDSPM_c0_AEB1 0x20000 | ||
360 | #define HDSPM_c0_AEB2 0x40000 | ||
361 | #define HDSPM_c0_LineOut 0x80000 | ||
362 | #define HDSPM_c0_AD_GAIN0 0x100000 | ||
363 | #define HDSPM_c0_AD_GAIN1 0x200000 | ||
364 | #define HDSPM_c0_DA_GAIN0 0x400000 | ||
365 | #define HDSPM_c0_DA_GAIN1 0x800000 | ||
366 | #define HDSPM_c0_PH_GAIN0 0x1000000 | ||
367 | #define HDSPM_c0_PH_GAIN1 0x2000000 | ||
368 | #define HDSPM_c0_Sym6db 0x4000000 | ||
369 | |||
370 | |||
261 | /* --- bit helper defines */ | 371 | /* --- bit helper defines */ |
262 | #define HDSPM_LatencyMask (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2) | 372 | #define HDSPM_LatencyMask (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2) |
263 | #define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1|\ | 373 | #define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1|\ |
@@ -341,11 +451,11 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); | |||
341 | #define HDSPM_madiLock (1<<3) /* MADI Locked =1, no=0 */ | 451 | #define HDSPM_madiLock (1<<3) /* MADI Locked =1, no=0 */ |
342 | #define HDSPM_madiSync (1<<18) /* MADI is in sync */ | 452 | #define HDSPM_madiSync (1<<18) /* MADI is in sync */ |
343 | 453 | ||
344 | #define HDSPM_tcoLock 0x00000020 /* Optional TCO locked status FOR HDSPe MADI! */ | 454 | #define HDSPM_tcoLockMadi 0x00000020 /* Optional TCO locked status for HDSPe MADI*/ |
345 | #define HDSPM_tcoSync 0x10000000 /* Optional TCO sync status */ | 455 | #define HDSPM_tcoSync 0x10000000 /* Optional TCO sync status for HDSPe MADI and AES32!*/ |
346 | 456 | ||
347 | #define HDSPM_syncInLock 0x00010000 /* Sync In lock status FOR HDSPe MADI! */ | 457 | #define HDSPM_syncInLock 0x00010000 /* Sync In lock status for HDSPe MADI! */ |
348 | #define HDSPM_syncInSync 0x00020000 /* Sync In sync status FOR HDSPe MADI! */ | 458 | #define HDSPM_syncInSync 0x00020000 /* Sync In sync status for HDSPe MADI! */ |
349 | 459 | ||
350 | #define HDSPM_BufferPositionMask 0x000FFC0 /* Bit 6..15 : h/w buffer pointer */ | 460 | #define HDSPM_BufferPositionMask 0x000FFC0 /* Bit 6..15 : h/w buffer pointer */ |
351 | /* since 64byte accurate, last 6 bits are not used */ | 461 | /* since 64byte accurate, last 6 bits are not used */ |
@@ -363,7 +473,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); | |||
363 | * Interrupt | 473 | * Interrupt |
364 | */ | 474 | */ |
365 | #define HDSPM_tco_detect 0x08000000 | 475 | #define HDSPM_tco_detect 0x08000000 |
366 | #define HDSPM_tco_lock 0x20000000 | 476 | #define HDSPM_tcoLockAes 0x20000000 /* Optional TCO locked status for HDSPe AES */ |
367 | 477 | ||
368 | #define HDSPM_s2_tco_detect 0x00000040 | 478 | #define HDSPM_s2_tco_detect 0x00000040 |
369 | #define HDSPM_s2_AEBO_D 0x00000080 | 479 | #define HDSPM_s2_AEBO_D 0x00000080 |
@@ -461,7 +571,9 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); | |||
461 | #define HDSPM_AES32_AUTOSYNC_FROM_AES6 6 | 571 | #define HDSPM_AES32_AUTOSYNC_FROM_AES6 6 |
462 | #define HDSPM_AES32_AUTOSYNC_FROM_AES7 7 | 572 | #define HDSPM_AES32_AUTOSYNC_FROM_AES7 7 |
463 | #define HDSPM_AES32_AUTOSYNC_FROM_AES8 8 | 573 | #define HDSPM_AES32_AUTOSYNC_FROM_AES8 8 |
464 | #define HDSPM_AES32_AUTOSYNC_FROM_NONE 9 | 574 | #define HDSPM_AES32_AUTOSYNC_FROM_TCO 9 |
575 | #define HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN 10 | ||
576 | #define HDSPM_AES32_AUTOSYNC_FROM_NONE 11 | ||
465 | 577 | ||
466 | /* status2 */ | 578 | /* status2 */ |
467 | /* HDSPM_LockAES_bit is given by HDSPM_LockAES >> (AES# - 1) */ | 579 | /* HDSPM_LockAES_bit is given by HDSPM_LockAES >> (AES# - 1) */ |
@@ -537,36 +649,39 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); | |||
537 | /* names for speed modes */ | 649 | /* names for speed modes */ |
538 | static char *hdspm_speed_names[] = { "single", "double", "quad" }; | 650 | static char *hdspm_speed_names[] = { "single", "double", "quad" }; |
539 | 651 | ||
540 | static char *texts_autosync_aes_tco[] = { "Word Clock", | 652 | static const char *const texts_autosync_aes_tco[] = { "Word Clock", |
541 | "AES1", "AES2", "AES3", "AES4", | 653 | "AES1", "AES2", "AES3", "AES4", |
542 | "AES5", "AES6", "AES7", "AES8", | 654 | "AES5", "AES6", "AES7", "AES8", |
543 | "TCO" }; | 655 | "TCO", "Sync In" |
544 | static char *texts_autosync_aes[] = { "Word Clock", | 656 | }; |
657 | static const char *const texts_autosync_aes[] = { "Word Clock", | ||
545 | "AES1", "AES2", "AES3", "AES4", | 658 | "AES1", "AES2", "AES3", "AES4", |
546 | "AES5", "AES6", "AES7", "AES8" }; | 659 | "AES5", "AES6", "AES7", "AES8", |
547 | static char *texts_autosync_madi_tco[] = { "Word Clock", | 660 | "Sync In" |
661 | }; | ||
662 | static const char *const texts_autosync_madi_tco[] = { "Word Clock", | ||
548 | "MADI", "TCO", "Sync In" }; | 663 | "MADI", "TCO", "Sync In" }; |
549 | static char *texts_autosync_madi[] = { "Word Clock", | 664 | static const char *const texts_autosync_madi[] = { "Word Clock", |
550 | "MADI", "Sync In" }; | 665 | "MADI", "Sync In" }; |
551 | 666 | ||
552 | static char *texts_autosync_raydat_tco[] = { | 667 | static const char *const texts_autosync_raydat_tco[] = { |
553 | "Word Clock", | 668 | "Word Clock", |
554 | "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4", | 669 | "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4", |
555 | "AES", "SPDIF", "TCO", "Sync In" | 670 | "AES", "SPDIF", "TCO", "Sync In" |
556 | }; | 671 | }; |
557 | static char *texts_autosync_raydat[] = { | 672 | static const char *const texts_autosync_raydat[] = { |
558 | "Word Clock", | 673 | "Word Clock", |
559 | "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4", | 674 | "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4", |
560 | "AES", "SPDIF", "Sync In" | 675 | "AES", "SPDIF", "Sync In" |
561 | }; | 676 | }; |
562 | static char *texts_autosync_aio_tco[] = { | 677 | static const char *const texts_autosync_aio_tco[] = { |
563 | "Word Clock", | 678 | "Word Clock", |
564 | "ADAT", "AES", "SPDIF", "TCO", "Sync In" | 679 | "ADAT", "AES", "SPDIF", "TCO", "Sync In" |
565 | }; | 680 | }; |
566 | static char *texts_autosync_aio[] = { "Word Clock", | 681 | static const char *const texts_autosync_aio[] = { "Word Clock", |
567 | "ADAT", "AES", "SPDIF", "Sync In" }; | 682 | "ADAT", "AES", "SPDIF", "Sync In" }; |
568 | 683 | ||
569 | static char *texts_freq[] = { | 684 | static const char *const texts_freq[] = { |
570 | "No Lock", | 685 | "No Lock", |
571 | "32 kHz", | 686 | "32 kHz", |
572 | "44.1 kHz", | 687 | "44.1 kHz", |
@@ -629,7 +744,8 @@ static char *texts_ports_aio_in_ss[] = { | |||
629 | "AES.L", "AES.R", | 744 | "AES.L", "AES.R", |
630 | "SPDIF.L", "SPDIF.R", | 745 | "SPDIF.L", "SPDIF.R", |
631 | "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6", | 746 | "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6", |
632 | "ADAT.7", "ADAT.8" | 747 | "ADAT.7", "ADAT.8", |
748 | "AEB.1", "AEB.2", "AEB.3", "AEB.4" | ||
633 | }; | 749 | }; |
634 | 750 | ||
635 | static char *texts_ports_aio_out_ss[] = { | 751 | static char *texts_ports_aio_out_ss[] = { |
@@ -638,14 +754,16 @@ static char *texts_ports_aio_out_ss[] = { | |||
638 | "SPDIF.L", "SPDIF.R", | 754 | "SPDIF.L", "SPDIF.R", |
639 | "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6", | 755 | "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6", |
640 | "ADAT.7", "ADAT.8", | 756 | "ADAT.7", "ADAT.8", |
641 | "Phone.L", "Phone.R" | 757 | "Phone.L", "Phone.R", |
758 | "AEB.1", "AEB.2", "AEB.3", "AEB.4" | ||
642 | }; | 759 | }; |
643 | 760 | ||
644 | static char *texts_ports_aio_in_ds[] = { | 761 | static char *texts_ports_aio_in_ds[] = { |
645 | "Analogue.L", "Analogue.R", | 762 | "Analogue.L", "Analogue.R", |
646 | "AES.L", "AES.R", | 763 | "AES.L", "AES.R", |
647 | "SPDIF.L", "SPDIF.R", | 764 | "SPDIF.L", "SPDIF.R", |
648 | "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4" | 765 | "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", |
766 | "AEB.1", "AEB.2", "AEB.3", "AEB.4" | ||
649 | }; | 767 | }; |
650 | 768 | ||
651 | static char *texts_ports_aio_out_ds[] = { | 769 | static char *texts_ports_aio_out_ds[] = { |
@@ -653,14 +771,16 @@ static char *texts_ports_aio_out_ds[] = { | |||
653 | "AES.L", "AES.R", | 771 | "AES.L", "AES.R", |
654 | "SPDIF.L", "SPDIF.R", | 772 | "SPDIF.L", "SPDIF.R", |
655 | "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", | 773 | "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", |
656 | "Phone.L", "Phone.R" | 774 | "Phone.L", "Phone.R", |
775 | "AEB.1", "AEB.2", "AEB.3", "AEB.4" | ||
657 | }; | 776 | }; |
658 | 777 | ||
659 | static char *texts_ports_aio_in_qs[] = { | 778 | static char *texts_ports_aio_in_qs[] = { |
660 | "Analogue.L", "Analogue.R", | 779 | "Analogue.L", "Analogue.R", |
661 | "AES.L", "AES.R", | 780 | "AES.L", "AES.R", |
662 | "SPDIF.L", "SPDIF.R", | 781 | "SPDIF.L", "SPDIF.R", |
663 | "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4" | 782 | "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", |
783 | "AEB.1", "AEB.2", "AEB.3", "AEB.4" | ||
664 | }; | 784 | }; |
665 | 785 | ||
666 | static char *texts_ports_aio_out_qs[] = { | 786 | static char *texts_ports_aio_out_qs[] = { |
@@ -668,7 +788,8 @@ static char *texts_ports_aio_out_qs[] = { | |||
668 | "AES.L", "AES.R", | 788 | "AES.L", "AES.R", |
669 | "SPDIF.L", "SPDIF.R", | 789 | "SPDIF.L", "SPDIF.R", |
670 | "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", | 790 | "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", |
671 | "Phone.L", "Phone.R" | 791 | "Phone.L", "Phone.R", |
792 | "AEB.1", "AEB.2", "AEB.3", "AEB.4" | ||
672 | }; | 793 | }; |
673 | 794 | ||
674 | static char *texts_ports_aes32[] = { | 795 | static char *texts_ports_aes32[] = { |
@@ -745,8 +866,8 @@ static char channel_map_aio_in_ss[HDSPM_MAX_CHANNELS] = { | |||
745 | 8, 9, /* aes in, */ | 866 | 8, 9, /* aes in, */ |
746 | 10, 11, /* spdif in */ | 867 | 10, 11, /* spdif in */ |
747 | 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT in */ | 868 | 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT in */ |
748 | -1, -1, | 869 | 2, 3, 4, 5, /* AEB */ |
749 | -1, -1, -1, -1, -1, -1, -1, -1, | 870 | -1, -1, -1, -1, -1, -1, |
750 | -1, -1, -1, -1, -1, -1, -1, -1, | 871 | -1, -1, -1, -1, -1, -1, -1, -1, |
751 | -1, -1, -1, -1, -1, -1, -1, -1, | 872 | -1, -1, -1, -1, -1, -1, -1, -1, |
752 | -1, -1, -1, -1, -1, -1, -1, -1, | 873 | -1, -1, -1, -1, -1, -1, -1, -1, |
@@ -760,7 +881,8 @@ static char channel_map_aio_out_ss[HDSPM_MAX_CHANNELS] = { | |||
760 | 10, 11, /* spdif out */ | 881 | 10, 11, /* spdif out */ |
761 | 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT out */ | 882 | 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT out */ |
762 | 6, 7, /* phone out */ | 883 | 6, 7, /* phone out */ |
763 | -1, -1, -1, -1, -1, -1, -1, -1, | 884 | 2, 3, 4, 5, /* AEB */ |
885 | -1, -1, -1, -1, | ||
764 | -1, -1, -1, -1, -1, -1, -1, -1, | 886 | -1, -1, -1, -1, -1, -1, -1, -1, |
765 | -1, -1, -1, -1, -1, -1, -1, -1, | 887 | -1, -1, -1, -1, -1, -1, -1, -1, |
766 | -1, -1, -1, -1, -1, -1, -1, -1, | 888 | -1, -1, -1, -1, -1, -1, -1, -1, |
@@ -773,7 +895,8 @@ static char channel_map_aio_in_ds[HDSPM_MAX_CHANNELS] = { | |||
773 | 8, 9, /* aes in */ | 895 | 8, 9, /* aes in */ |
774 | 10, 11, /* spdif in */ | 896 | 10, 11, /* spdif in */ |
775 | 12, 14, 16, 18, /* adat in */ | 897 | 12, 14, 16, 18, /* adat in */ |
776 | -1, -1, -1, -1, -1, -1, | 898 | 2, 3, 4, 5, /* AEB */ |
899 | -1, -1, | ||
777 | -1, -1, -1, -1, -1, -1, -1, -1, | 900 | -1, -1, -1, -1, -1, -1, -1, -1, |
778 | -1, -1, -1, -1, -1, -1, -1, -1, | 901 | -1, -1, -1, -1, -1, -1, -1, -1, |
779 | -1, -1, -1, -1, -1, -1, -1, -1, | 902 | -1, -1, -1, -1, -1, -1, -1, -1, |
@@ -788,7 +911,7 @@ static char channel_map_aio_out_ds[HDSPM_MAX_CHANNELS] = { | |||
788 | 10, 11, /* spdif out */ | 911 | 10, 11, /* spdif out */ |
789 | 12, 14, 16, 18, /* adat out */ | 912 | 12, 14, 16, 18, /* adat out */ |
790 | 6, 7, /* phone out */ | 913 | 6, 7, /* phone out */ |
791 | -1, -1, -1, -1, | 914 | 2, 3, 4, 5, /* AEB */ |
792 | -1, -1, -1, -1, -1, -1, -1, -1, | 915 | -1, -1, -1, -1, -1, -1, -1, -1, |
793 | -1, -1, -1, -1, -1, -1, -1, -1, | 916 | -1, -1, -1, -1, -1, -1, -1, -1, |
794 | -1, -1, -1, -1, -1, -1, -1, -1, | 917 | -1, -1, -1, -1, -1, -1, -1, -1, |
@@ -802,7 +925,8 @@ static char channel_map_aio_in_qs[HDSPM_MAX_CHANNELS] = { | |||
802 | 8, 9, /* aes in */ | 925 | 8, 9, /* aes in */ |
803 | 10, 11, /* spdif in */ | 926 | 10, 11, /* spdif in */ |
804 | 12, 16, /* adat in */ | 927 | 12, 16, /* adat in */ |
805 | -1, -1, -1, -1, -1, -1, -1, -1, | 928 | 2, 3, 4, 5, /* AEB */ |
929 | -1, -1, -1, -1, | ||
806 | -1, -1, -1, -1, -1, -1, -1, -1, | 930 | -1, -1, -1, -1, -1, -1, -1, -1, |
807 | -1, -1, -1, -1, -1, -1, -1, -1, | 931 | -1, -1, -1, -1, -1, -1, -1, -1, |
808 | -1, -1, -1, -1, -1, -1, -1, -1, | 932 | -1, -1, -1, -1, -1, -1, -1, -1, |
@@ -817,7 +941,8 @@ static char channel_map_aio_out_qs[HDSPM_MAX_CHANNELS] = { | |||
817 | 10, 11, /* spdif out */ | 941 | 10, 11, /* spdif out */ |
818 | 12, 16, /* adat out */ | 942 | 12, 16, /* adat out */ |
819 | 6, 7, /* phone out */ | 943 | 6, 7, /* phone out */ |
820 | -1, -1, -1, -1, -1, -1, | 944 | 2, 3, 4, 5, /* AEB */ |
945 | -1, -1, | ||
821 | -1, -1, -1, -1, -1, -1, -1, -1, | 946 | -1, -1, -1, -1, -1, -1, -1, -1, |
822 | -1, -1, -1, -1, -1, -1, -1, -1, | 947 | -1, -1, -1, -1, -1, -1, -1, -1, |
823 | -1, -1, -1, -1, -1, -1, -1, -1, | 948 | -1, -1, -1, -1, -1, -1, -1, -1, |
@@ -856,11 +981,11 @@ struct hdspm_midi { | |||
856 | }; | 981 | }; |
857 | 982 | ||
858 | struct hdspm_tco { | 983 | struct hdspm_tco { |
859 | int input; | 984 | int input; /* 0: LTC, 1:Video, 2: WC*/ |
860 | int framerate; | 985 | int framerate; /* 0=24, 1=25, 2=29.97, 3=29.97d, 4=30, 5=30d */ |
861 | int wordclock; | 986 | int wordclock; /* 0=1:1, 1=44.1->48, 2=48->44.1 */ |
862 | int samplerate; | 987 | int samplerate; /* 0=44.1, 1=48, 2= freq from app */ |
863 | int pull; | 988 | int pull; /* 0=0, 1=+0.1%, 2=-0.1%, 3=+4%, 4=-4%*/ |
864 | int term; /* 0 = off, 1 = on */ | 989 | int term; /* 0 = off, 1 = on */ |
865 | }; | 990 | }; |
866 | 991 | ||
@@ -879,7 +1004,7 @@ struct hdspm { | |||
879 | 1004 | ||
880 | u32 control_register; /* cached value */ | 1005 | u32 control_register; /* cached value */ |
881 | u32 control2_register; /* cached value */ | 1006 | u32 control2_register; /* cached value */ |
882 | u32 settings_register; | 1007 | u32 settings_register; /* cached value for AIO / RayDat (sync reference, master/slave) */ |
883 | 1008 | ||
884 | struct hdspm_midi midi[4]; | 1009 | struct hdspm_midi midi[4]; |
885 | struct tasklet_struct midi_tasklet; | 1010 | struct tasklet_struct midi_tasklet; |
@@ -941,7 +1066,7 @@ struct hdspm { | |||
941 | 1066 | ||
942 | struct hdspm_tco *tco; /* NULL if no TCO detected */ | 1067 | struct hdspm_tco *tco; /* NULL if no TCO detected */ |
943 | 1068 | ||
944 | char **texts_autosync; | 1069 | const char *const *texts_autosync; |
945 | int texts_autosync_items; | 1070 | int texts_autosync_items; |
946 | 1071 | ||
947 | cycles_t last_interrupt; | 1072 | cycles_t last_interrupt; |
@@ -976,12 +1101,24 @@ static inline void snd_hdspm_initialize_midi_flush(struct hdspm *hdspm); | |||
976 | static inline int hdspm_get_pll_freq(struct hdspm *hdspm); | 1101 | static inline int hdspm_get_pll_freq(struct hdspm *hdspm); |
977 | static int hdspm_update_simple_mixer_controls(struct hdspm *hdspm); | 1102 | static int hdspm_update_simple_mixer_controls(struct hdspm *hdspm); |
978 | static int hdspm_autosync_ref(struct hdspm *hdspm); | 1103 | static int hdspm_autosync_ref(struct hdspm *hdspm); |
1104 | static int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out); | ||
979 | static int snd_hdspm_set_defaults(struct hdspm *hdspm); | 1105 | static int snd_hdspm_set_defaults(struct hdspm *hdspm); |
980 | static int hdspm_system_clock_mode(struct hdspm *hdspm); | 1106 | static int hdspm_system_clock_mode(struct hdspm *hdspm); |
981 | static void hdspm_set_sgbuf(struct hdspm *hdspm, | 1107 | static void hdspm_set_sgbuf(struct hdspm *hdspm, |
982 | struct snd_pcm_substream *substream, | 1108 | struct snd_pcm_substream *substream, |
983 | unsigned int reg, int channels); | 1109 | unsigned int reg, int channels); |
984 | 1110 | ||
1111 | static int hdspm_aes_sync_check(struct hdspm *hdspm, int idx); | ||
1112 | static int hdspm_wc_sync_check(struct hdspm *hdspm); | ||
1113 | static int hdspm_tco_sync_check(struct hdspm *hdspm); | ||
1114 | static int hdspm_sync_in_sync_check(struct hdspm *hdspm); | ||
1115 | |||
1116 | static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index); | ||
1117 | static int hdspm_get_tco_sample_rate(struct hdspm *hdspm); | ||
1118 | static int hdspm_get_wc_sample_rate(struct hdspm *hdspm); | ||
1119 | |||
1120 | |||
1121 | |||
985 | static inline int HDSPM_bit2freq(int n) | 1122 | static inline int HDSPM_bit2freq(int n) |
986 | { | 1123 | { |
987 | static const int bit2freq_tab[] = { | 1124 | static const int bit2freq_tab[] = { |
@@ -992,6 +1129,12 @@ static inline int HDSPM_bit2freq(int n) | |||
992 | return bit2freq_tab[n]; | 1129 | return bit2freq_tab[n]; |
993 | } | 1130 | } |
994 | 1131 | ||
1132 | static bool hdspm_is_raydat_or_aio(struct hdspm *hdspm) | ||
1133 | { | ||
1134 | return ((AIO == hdspm->io_type) || (RayDAT == hdspm->io_type)); | ||
1135 | } | ||
1136 | |||
1137 | |||
995 | /* Write/read to/from HDSPM with Adresses in Bytes | 1138 | /* Write/read to/from HDSPM with Adresses in Bytes |
996 | not words but only 32Bit writes are allowed */ | 1139 | not words but only 32Bit writes are allowed */ |
997 | 1140 | ||
@@ -1107,14 +1250,11 @@ static int hdspm_rate_multiplier(struct hdspm *hdspm, int rate) | |||
1107 | else if (hdspm->control_register & | 1250 | else if (hdspm->control_register & |
1108 | HDSPM_DoubleSpeed) | 1251 | HDSPM_DoubleSpeed) |
1109 | return rate * 2; | 1252 | return rate * 2; |
1110 | }; | 1253 | } |
1111 | return rate; | 1254 | return rate; |
1112 | } | 1255 | } |
1113 | 1256 | ||
1114 | static int hdspm_tco_sync_check(struct hdspm *hdspm); | 1257 | /* check for external sample rate, returns the sample rate in Hz*/ |
1115 | static int hdspm_sync_in_sync_check(struct hdspm *hdspm); | ||
1116 | |||
1117 | /* check for external sample rate */ | ||
1118 | static int hdspm_external_sample_rate(struct hdspm *hdspm) | 1258 | static int hdspm_external_sample_rate(struct hdspm *hdspm) |
1119 | { | 1259 | { |
1120 | unsigned int status, status2, timecode; | 1260 | unsigned int status, status2, timecode; |
@@ -1127,17 +1267,36 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm) | |||
1127 | timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); | 1267 | timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); |
1128 | 1268 | ||
1129 | syncref = hdspm_autosync_ref(hdspm); | 1269 | syncref = hdspm_autosync_ref(hdspm); |
1270 | switch (syncref) { | ||
1271 | case HDSPM_AES32_AUTOSYNC_FROM_WORD: | ||
1272 | /* Check WC sync and get sample rate */ | ||
1273 | if (hdspm_wc_sync_check(hdspm)) | ||
1274 | return HDSPM_bit2freq(hdspm_get_wc_sample_rate(hdspm)); | ||
1275 | break; | ||
1130 | 1276 | ||
1131 | if (syncref == HDSPM_AES32_AUTOSYNC_FROM_WORD && | 1277 | case HDSPM_AES32_AUTOSYNC_FROM_AES1: |
1132 | status & HDSPM_AES32_wcLock) | 1278 | case HDSPM_AES32_AUTOSYNC_FROM_AES2: |
1133 | return HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF); | 1279 | case HDSPM_AES32_AUTOSYNC_FROM_AES3: |
1280 | case HDSPM_AES32_AUTOSYNC_FROM_AES4: | ||
1281 | case HDSPM_AES32_AUTOSYNC_FROM_AES5: | ||
1282 | case HDSPM_AES32_AUTOSYNC_FROM_AES6: | ||
1283 | case HDSPM_AES32_AUTOSYNC_FROM_AES7: | ||
1284 | case HDSPM_AES32_AUTOSYNC_FROM_AES8: | ||
1285 | /* Check AES sync and get sample rate */ | ||
1286 | if (hdspm_aes_sync_check(hdspm, syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1)) | ||
1287 | return HDSPM_bit2freq(hdspm_get_aes_sample_rate(hdspm, | ||
1288 | syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1)); | ||
1289 | break; | ||
1134 | 1290 | ||
1135 | if (syncref >= HDSPM_AES32_AUTOSYNC_FROM_AES1 && | 1291 | |
1136 | syncref <= HDSPM_AES32_AUTOSYNC_FROM_AES8 && | 1292 | case HDSPM_AES32_AUTOSYNC_FROM_TCO: |
1137 | status2 & (HDSPM_LockAES >> | 1293 | /* Check TCO sync and get sample rate */ |
1138 | (syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1))) | 1294 | if (hdspm_tco_sync_check(hdspm)) |
1139 | return HDSPM_bit2freq((timecode >> (4*(syncref-HDSPM_AES32_AUTOSYNC_FROM_AES1))) & 0xF); | 1295 | return HDSPM_bit2freq(hdspm_get_tco_sample_rate(hdspm)); |
1140 | return 0; | 1296 | break; |
1297 | default: | ||
1298 | return 0; | ||
1299 | } /* end switch(syncref) */ | ||
1141 | break; | 1300 | break; |
1142 | 1301 | ||
1143 | case MADIface: | 1302 | case MADIface: |
@@ -2129,6 +2288,9 @@ static int hdspm_get_wc_sample_rate(struct hdspm *hdspm) | |||
2129 | status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); | 2288 | status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); |
2130 | return (status >> 16) & 0xF; | 2289 | return (status >> 16) & 0xF; |
2131 | break; | 2290 | break; |
2291 | case AES32: | ||
2292 | status = hdspm_read(hdspm, HDSPM_statusRegister); | ||
2293 | return (status >> HDSPM_AES32_wcFreq_bit) & 0xF; | ||
2132 | default: | 2294 | default: |
2133 | break; | 2295 | break; |
2134 | } | 2296 | } |
@@ -2152,6 +2314,9 @@ static int hdspm_get_tco_sample_rate(struct hdspm *hdspm) | |||
2152 | status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); | 2314 | status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); |
2153 | return (status >> 20) & 0xF; | 2315 | return (status >> 20) & 0xF; |
2154 | break; | 2316 | break; |
2317 | case AES32: | ||
2318 | status = hdspm_read(hdspm, HDSPM_statusRegister); | ||
2319 | return (status >> 1) & 0xF; | ||
2155 | default: | 2320 | default: |
2156 | break; | 2321 | break; |
2157 | } | 2322 | } |
@@ -2183,6 +2348,23 @@ static int hdspm_get_sync_in_sample_rate(struct hdspm *hdspm) | |||
2183 | return 0; | 2348 | return 0; |
2184 | } | 2349 | } |
2185 | 2350 | ||
2351 | /** | ||
2352 | * Returns the AES sample rate class for the given card. | ||
2353 | **/ | ||
2354 | static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index) | ||
2355 | { | ||
2356 | int timecode; | ||
2357 | |||
2358 | switch (hdspm->io_type) { | ||
2359 | case AES32: | ||
2360 | timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); | ||
2361 | return (timecode >> (4*index)) & 0xF; | ||
2362 | break; | ||
2363 | default: | ||
2364 | break; | ||
2365 | } | ||
2366 | return 0; | ||
2367 | } | ||
2186 | 2368 | ||
2187 | /** | 2369 | /** |
2188 | * Returns the sample rate class for input source <idx> for | 2370 | * Returns the sample rate class for input source <idx> for |
@@ -2196,15 +2378,23 @@ static int hdspm_get_s1_sample_rate(struct hdspm *hdspm, unsigned int idx) | |||
2196 | } | 2378 | } |
2197 | 2379 | ||
2198 | #define ENUMERATED_CTL_INFO(info, texts) \ | 2380 | #define ENUMERATED_CTL_INFO(info, texts) \ |
2199 | { \ | 2381 | snd_ctl_enum_info(info, 1, ARRAY_SIZE(texts), texts) |
2200 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; \ | 2382 | |
2201 | uinfo->count = 1; \ | ||
2202 | uinfo->value.enumerated.items = ARRAY_SIZE(texts); \ | ||
2203 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) \ | ||
2204 | uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; \ | ||
2205 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); \ | ||
2206 | } | ||
2207 | 2383 | ||
2384 | /* Helper function to query the external sample rate and return the | ||
2385 | * corresponding enum to be returned to userspace. | ||
2386 | */ | ||
2387 | static int hdspm_external_rate_to_enum(struct hdspm *hdspm) | ||
2388 | { | ||
2389 | int rate = hdspm_external_sample_rate(hdspm); | ||
2390 | int i, selected_rate = 0; | ||
2391 | for (i = 1; i < 10; i++) | ||
2392 | if (HDSPM_bit2freq(i) == rate) { | ||
2393 | selected_rate = i; | ||
2394 | break; | ||
2395 | } | ||
2396 | return selected_rate; | ||
2397 | } | ||
2208 | 2398 | ||
2209 | 2399 | ||
2210 | #define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \ | 2400 | #define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \ |
@@ -2270,7 +2460,7 @@ static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol, | |||
2270 | default: | 2460 | default: |
2271 | ucontrol->value.enumerated.item[0] = | 2461 | ucontrol->value.enumerated.item[0] = |
2272 | hdspm_get_s1_sample_rate(hdspm, | 2462 | hdspm_get_s1_sample_rate(hdspm, |
2273 | ucontrol->id.index-1); | 2463 | kcontrol->private_value-1); |
2274 | } | 2464 | } |
2275 | break; | 2465 | break; |
2276 | 2466 | ||
@@ -2289,28 +2479,24 @@ static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol, | |||
2289 | ucontrol->value.enumerated.item[0] = | 2479 | ucontrol->value.enumerated.item[0] = |
2290 | hdspm_get_sync_in_sample_rate(hdspm); | 2480 | hdspm_get_sync_in_sample_rate(hdspm); |
2291 | break; | 2481 | break; |
2482 | case 11: /* External Rate */ | ||
2483 | ucontrol->value.enumerated.item[0] = | ||
2484 | hdspm_external_rate_to_enum(hdspm); | ||
2485 | break; | ||
2292 | default: /* AES1 to AES8 */ | 2486 | default: /* AES1 to AES8 */ |
2293 | ucontrol->value.enumerated.item[0] = | 2487 | ucontrol->value.enumerated.item[0] = |
2294 | hdspm_get_s1_sample_rate(hdspm, | 2488 | hdspm_get_aes_sample_rate(hdspm, |
2295 | kcontrol->private_value-1); | 2489 | kcontrol->private_value - |
2490 | HDSPM_AES32_AUTOSYNC_FROM_AES1); | ||
2296 | break; | 2491 | break; |
2297 | } | 2492 | } |
2298 | break; | 2493 | break; |
2299 | 2494 | ||
2300 | case MADI: | 2495 | case MADI: |
2301 | case MADIface: | 2496 | case MADIface: |
2302 | { | 2497 | ucontrol->value.enumerated.item[0] = |
2303 | int rate = hdspm_external_sample_rate(hdspm); | 2498 | hdspm_external_rate_to_enum(hdspm); |
2304 | int i, selected_rate = 0; | ||
2305 | for (i = 1; i < 10; i++) | ||
2306 | if (HDSPM_bit2freq(i) == rate) { | ||
2307 | selected_rate = i; | ||
2308 | break; | ||
2309 | } | ||
2310 | ucontrol->value.enumerated.item[0] = selected_rate; | ||
2311 | } | ||
2312 | break; | 2499 | break; |
2313 | |||
2314 | default: | 2500 | default: |
2315 | break; | 2501 | break; |
2316 | } | 2502 | } |
@@ -2359,33 +2545,17 @@ static int hdspm_system_clock_mode(struct hdspm *hdspm) | |||
2359 | **/ | 2545 | **/ |
2360 | static void hdspm_set_system_clock_mode(struct hdspm *hdspm, int mode) | 2546 | static void hdspm_set_system_clock_mode(struct hdspm *hdspm, int mode) |
2361 | { | 2547 | { |
2362 | switch (hdspm->io_type) { | 2548 | hdspm_set_toggle_setting(hdspm, |
2363 | case AIO: | 2549 | (hdspm_is_raydat_or_aio(hdspm)) ? |
2364 | case RayDAT: | 2550 | HDSPM_c0Master : HDSPM_ClockModeMaster, |
2365 | if (0 == mode) | 2551 | (0 == mode)); |
2366 | hdspm->settings_register |= HDSPM_c0Master; | ||
2367 | else | ||
2368 | hdspm->settings_register &= ~HDSPM_c0Master; | ||
2369 | |||
2370 | hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); | ||
2371 | break; | ||
2372 | |||
2373 | default: | ||
2374 | if (0 == mode) | ||
2375 | hdspm->control_register |= HDSPM_ClockModeMaster; | ||
2376 | else | ||
2377 | hdspm->control_register &= ~HDSPM_ClockModeMaster; | ||
2378 | |||
2379 | hdspm_write(hdspm, HDSPM_controlRegister, | ||
2380 | hdspm->control_register); | ||
2381 | } | ||
2382 | } | 2552 | } |
2383 | 2553 | ||
2384 | 2554 | ||
2385 | static int snd_hdspm_info_system_clock_mode(struct snd_kcontrol *kcontrol, | 2555 | static int snd_hdspm_info_system_clock_mode(struct snd_kcontrol *kcontrol, |
2386 | struct snd_ctl_elem_info *uinfo) | 2556 | struct snd_ctl_elem_info *uinfo) |
2387 | { | 2557 | { |
2388 | static char *texts[] = { "Master", "AutoSync" }; | 2558 | static const char *const texts[] = { "Master", "AutoSync" }; |
2389 | ENUMERATED_CTL_INFO(uinfo, texts); | 2559 | ENUMERATED_CTL_INFO(uinfo, texts); |
2390 | return 0; | 2560 | return 0; |
2391 | } | 2561 | } |
@@ -2809,16 +2979,7 @@ static int snd_hdspm_info_pref_sync_ref(struct snd_kcontrol *kcontrol, | |||
2809 | { | 2979 | { |
2810 | struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); | 2980 | struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); |
2811 | 2981 | ||
2812 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 2982 | snd_ctl_enum_info(uinfo, 1, hdspm->texts_autosync_items, hdspm->texts_autosync); |
2813 | uinfo->count = 1; | ||
2814 | uinfo->value.enumerated.items = hdspm->texts_autosync_items; | ||
2815 | |||
2816 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
2817 | uinfo->value.enumerated.item = | ||
2818 | uinfo->value.enumerated.items - 1; | ||
2819 | |||
2820 | strcpy(uinfo->value.enumerated.name, | ||
2821 | hdspm->texts_autosync[uinfo->value.enumerated.item]); | ||
2822 | 2983 | ||
2823 | return 0; | 2984 | return 0; |
2824 | } | 2985 | } |
@@ -2873,19 +3034,20 @@ static int snd_hdspm_put_pref_sync_ref(struct snd_kcontrol *kcontrol, | |||
2873 | 3034 | ||
2874 | static int hdspm_autosync_ref(struct hdspm *hdspm) | 3035 | static int hdspm_autosync_ref(struct hdspm *hdspm) |
2875 | { | 3036 | { |
3037 | /* This looks at the autosync selected sync reference */ | ||
2876 | if (AES32 == hdspm->io_type) { | 3038 | if (AES32 == hdspm->io_type) { |
3039 | |||
2877 | unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); | 3040 | unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); |
2878 | unsigned int syncref = | 3041 | unsigned int syncref = (status >> HDSPM_AES32_syncref_bit) & 0xF; |
2879 | (status >> HDSPM_AES32_syncref_bit) & 0xF; | 3042 | if ((syncref >= HDSPM_AES32_AUTOSYNC_FROM_WORD) && |
2880 | if (syncref == 0) | 3043 | (syncref <= HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN)) { |
2881 | return HDSPM_AES32_AUTOSYNC_FROM_WORD; | ||
2882 | if (syncref <= 8) | ||
2883 | return syncref; | 3044 | return syncref; |
3045 | } | ||
2884 | return HDSPM_AES32_AUTOSYNC_FROM_NONE; | 3046 | return HDSPM_AES32_AUTOSYNC_FROM_NONE; |
3047 | |||
2885 | } else if (MADI == hdspm->io_type) { | 3048 | } else if (MADI == hdspm->io_type) { |
2886 | /* This looks at the autosync selected sync reference */ | ||
2887 | unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); | ||
2888 | 3049 | ||
3050 | unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); | ||
2889 | switch (status2 & HDSPM_SelSyncRefMask) { | 3051 | switch (status2 & HDSPM_SelSyncRefMask) { |
2890 | case HDSPM_SelSyncRef_WORD: | 3052 | case HDSPM_SelSyncRef_WORD: |
2891 | return HDSPM_AUTOSYNC_FROM_WORD; | 3053 | return HDSPM_AUTOSYNC_FROM_WORD; |
@@ -2898,7 +3060,7 @@ static int hdspm_autosync_ref(struct hdspm *hdspm) | |||
2898 | case HDSPM_SelSyncRef_NVALID: | 3060 | case HDSPM_SelSyncRef_NVALID: |
2899 | return HDSPM_AUTOSYNC_FROM_NONE; | 3061 | return HDSPM_AUTOSYNC_FROM_NONE; |
2900 | default: | 3062 | default: |
2901 | return 0; | 3063 | return HDSPM_AUTOSYNC_FROM_NONE; |
2902 | } | 3064 | } |
2903 | 3065 | ||
2904 | } | 3066 | } |
@@ -2912,31 +3074,15 @@ static int snd_hdspm_info_autosync_ref(struct snd_kcontrol *kcontrol, | |||
2912 | struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); | 3074 | struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); |
2913 | 3075 | ||
2914 | if (AES32 == hdspm->io_type) { | 3076 | if (AES32 == hdspm->io_type) { |
2915 | static char *texts[] = { "WordClock", "AES1", "AES2", "AES3", | 3077 | static const char *const texts[] = { "WordClock", "AES1", "AES2", "AES3", |
2916 | "AES4", "AES5", "AES6", "AES7", "AES8", "None"}; | 3078 | "AES4", "AES5", "AES6", "AES7", "AES8", "TCO", "Sync In", "None"}; |
2917 | 3079 | ||
2918 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 3080 | ENUMERATED_CTL_INFO(uinfo, texts); |
2919 | uinfo->count = 1; | ||
2920 | uinfo->value.enumerated.items = 10; | ||
2921 | if (uinfo->value.enumerated.item >= | ||
2922 | uinfo->value.enumerated.items) | ||
2923 | uinfo->value.enumerated.item = | ||
2924 | uinfo->value.enumerated.items - 1; | ||
2925 | strcpy(uinfo->value.enumerated.name, | ||
2926 | texts[uinfo->value.enumerated.item]); | ||
2927 | } else if (MADI == hdspm->io_type) { | 3081 | } else if (MADI == hdspm->io_type) { |
2928 | static char *texts[] = {"Word Clock", "MADI", "TCO", | 3082 | static const char *const texts[] = {"Word Clock", "MADI", "TCO", |
2929 | "Sync In", "None" }; | 3083 | "Sync In", "None" }; |
2930 | 3084 | ||
2931 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 3085 | ENUMERATED_CTL_INFO(uinfo, texts); |
2932 | uinfo->count = 1; | ||
2933 | uinfo->value.enumerated.items = 5; | ||
2934 | if (uinfo->value.enumerated.item >= | ||
2935 | uinfo->value.enumerated.items) | ||
2936 | uinfo->value.enumerated.item = | ||
2937 | uinfo->value.enumerated.items - 1; | ||
2938 | strcpy(uinfo->value.enumerated.name, | ||
2939 | texts[uinfo->value.enumerated.item]); | ||
2940 | } | 3086 | } |
2941 | return 0; | 3087 | return 0; |
2942 | } | 3088 | } |
@@ -2964,7 +3110,7 @@ static int snd_hdspm_get_autosync_ref(struct snd_kcontrol *kcontrol, | |||
2964 | static int snd_hdspm_info_tco_video_input_format(struct snd_kcontrol *kcontrol, | 3110 | static int snd_hdspm_info_tco_video_input_format(struct snd_kcontrol *kcontrol, |
2965 | struct snd_ctl_elem_info *uinfo) | 3111 | struct snd_ctl_elem_info *uinfo) |
2966 | { | 3112 | { |
2967 | static char *texts[] = {"No video", "NTSC", "PAL"}; | 3113 | static const char *const texts[] = {"No video", "NTSC", "PAL"}; |
2968 | ENUMERATED_CTL_INFO(uinfo, texts); | 3114 | ENUMERATED_CTL_INFO(uinfo, texts); |
2969 | return 0; | 3115 | return 0; |
2970 | } | 3116 | } |
@@ -3010,7 +3156,7 @@ static int snd_hdspm_get_tco_video_input_format(struct snd_kcontrol *kcontrol, | |||
3010 | static int snd_hdspm_info_tco_ltc_frames(struct snd_kcontrol *kcontrol, | 3156 | static int snd_hdspm_info_tco_ltc_frames(struct snd_kcontrol *kcontrol, |
3011 | struct snd_ctl_elem_info *uinfo) | 3157 | struct snd_ctl_elem_info *uinfo) |
3012 | { | 3158 | { |
3013 | static char *texts[] = {"No lock", "24 fps", "25 fps", "29.97 fps", | 3159 | static const char *const texts[] = {"No lock", "24 fps", "25 fps", "29.97 fps", |
3014 | "30 fps"}; | 3160 | "30 fps"}; |
3015 | ENUMERATED_CTL_INFO(uinfo, texts); | 3161 | ENUMERATED_CTL_INFO(uinfo, texts); |
3016 | return 0; | 3162 | return 0; |
@@ -3027,19 +3173,19 @@ static int hdspm_tco_ltc_frames(struct hdspm *hdspm) | |||
3027 | HDSPM_TCO1_LTC_Format_MSB)) { | 3173 | HDSPM_TCO1_LTC_Format_MSB)) { |
3028 | case 0: | 3174 | case 0: |
3029 | /* 24 fps */ | 3175 | /* 24 fps */ |
3030 | ret = 1; | 3176 | ret = fps_24; |
3031 | break; | 3177 | break; |
3032 | case HDSPM_TCO1_LTC_Format_LSB: | 3178 | case HDSPM_TCO1_LTC_Format_LSB: |
3033 | /* 25 fps */ | 3179 | /* 25 fps */ |
3034 | ret = 2; | 3180 | ret = fps_25; |
3035 | break; | 3181 | break; |
3036 | case HDSPM_TCO1_LTC_Format_MSB: | 3182 | case HDSPM_TCO1_LTC_Format_MSB: |
3037 | /* 25 fps */ | 3183 | /* 29.97 fps */ |
3038 | ret = 3; | 3184 | ret = fps_2997; |
3039 | break; | 3185 | break; |
3040 | default: | 3186 | default: |
3041 | /* 30 fps */ | 3187 | /* 30 fps */ |
3042 | ret = 4; | 3188 | ret = fps_30; |
3043 | break; | 3189 | break; |
3044 | } | 3190 | } |
3045 | } | 3191 | } |
@@ -3067,16 +3213,35 @@ static int snd_hdspm_get_tco_ltc_frames(struct snd_kcontrol *kcontrol, | |||
3067 | 3213 | ||
3068 | static int hdspm_toggle_setting(struct hdspm *hdspm, u32 regmask) | 3214 | static int hdspm_toggle_setting(struct hdspm *hdspm, u32 regmask) |
3069 | { | 3215 | { |
3070 | return (hdspm->control_register & regmask) ? 1 : 0; | 3216 | u32 reg; |
3217 | |||
3218 | if (hdspm_is_raydat_or_aio(hdspm)) | ||
3219 | reg = hdspm->settings_register; | ||
3220 | else | ||
3221 | reg = hdspm->control_register; | ||
3222 | |||
3223 | return (reg & regmask) ? 1 : 0; | ||
3071 | } | 3224 | } |
3072 | 3225 | ||
3073 | static int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out) | 3226 | static int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out) |
3074 | { | 3227 | { |
3228 | u32 *reg; | ||
3229 | u32 target_reg; | ||
3230 | |||
3231 | if (hdspm_is_raydat_or_aio(hdspm)) { | ||
3232 | reg = &(hdspm->settings_register); | ||
3233 | target_reg = HDSPM_WR_SETTINGS; | ||
3234 | } else { | ||
3235 | reg = &(hdspm->control_register); | ||
3236 | target_reg = HDSPM_controlRegister; | ||
3237 | } | ||
3238 | |||
3075 | if (out) | 3239 | if (out) |
3076 | hdspm->control_register |= regmask; | 3240 | *reg |= regmask; |
3077 | else | 3241 | else |
3078 | hdspm->control_register &= ~regmask; | 3242 | *reg &= ~regmask; |
3079 | hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); | 3243 | |
3244 | hdspm_write(hdspm, target_reg, *reg); | ||
3080 | 3245 | ||
3081 | return 0; | 3246 | return 0; |
3082 | } | 3247 | } |
@@ -3141,7 +3306,7 @@ static int hdspm_set_input_select(struct hdspm * hdspm, int out) | |||
3141 | static int snd_hdspm_info_input_select(struct snd_kcontrol *kcontrol, | 3306 | static int snd_hdspm_info_input_select(struct snd_kcontrol *kcontrol, |
3142 | struct snd_ctl_elem_info *uinfo) | 3307 | struct snd_ctl_elem_info *uinfo) |
3143 | { | 3308 | { |
3144 | static char *texts[] = { "optical", "coaxial" }; | 3309 | static const char *const texts[] = { "optical", "coaxial" }; |
3145 | ENUMERATED_CTL_INFO(uinfo, texts); | 3310 | ENUMERATED_CTL_INFO(uinfo, texts); |
3146 | return 0; | 3311 | return 0; |
3147 | } | 3312 | } |
@@ -3203,7 +3368,7 @@ static int hdspm_set_ds_wire(struct hdspm * hdspm, int ds) | |||
3203 | static int snd_hdspm_info_ds_wire(struct snd_kcontrol *kcontrol, | 3368 | static int snd_hdspm_info_ds_wire(struct snd_kcontrol *kcontrol, |
3204 | struct snd_ctl_elem_info *uinfo) | 3369 | struct snd_ctl_elem_info *uinfo) |
3205 | { | 3370 | { |
3206 | static char *texts[] = { "Single", "Double" }; | 3371 | static const char *const texts[] = { "Single", "Double" }; |
3207 | ENUMERATED_CTL_INFO(uinfo, texts); | 3372 | ENUMERATED_CTL_INFO(uinfo, texts); |
3208 | return 0; | 3373 | return 0; |
3209 | } | 3374 | } |
@@ -3276,7 +3441,7 @@ static int hdspm_set_qs_wire(struct hdspm * hdspm, int mode) | |||
3276 | static int snd_hdspm_info_qs_wire(struct snd_kcontrol *kcontrol, | 3441 | static int snd_hdspm_info_qs_wire(struct snd_kcontrol *kcontrol, |
3277 | struct snd_ctl_elem_info *uinfo) | 3442 | struct snd_ctl_elem_info *uinfo) |
3278 | { | 3443 | { |
3279 | static char *texts[] = { "Single", "Double", "Quad" }; | 3444 | static const char *const texts[] = { "Single", "Double", "Quad" }; |
3280 | ENUMERATED_CTL_INFO(uinfo, texts); | 3445 | ENUMERATED_CTL_INFO(uinfo, texts); |
3281 | return 0; | 3446 | return 0; |
3282 | } | 3447 | } |
@@ -3313,6 +3478,84 @@ static int snd_hdspm_put_qs_wire(struct snd_kcontrol *kcontrol, | |||
3313 | return change; | 3478 | return change; |
3314 | } | 3479 | } |
3315 | 3480 | ||
3481 | #define HDSPM_CONTROL_TRISTATE(xname, xindex) \ | ||
3482 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
3483 | .name = xname, \ | ||
3484 | .private_value = xindex, \ | ||
3485 | .info = snd_hdspm_info_tristate, \ | ||
3486 | .get = snd_hdspm_get_tristate, \ | ||
3487 | .put = snd_hdspm_put_tristate \ | ||
3488 | } | ||
3489 | |||
3490 | static int hdspm_tristate(struct hdspm *hdspm, u32 regmask) | ||
3491 | { | ||
3492 | u32 reg = hdspm->settings_register & (regmask * 3); | ||
3493 | return reg / regmask; | ||
3494 | } | ||
3495 | |||
3496 | static int hdspm_set_tristate(struct hdspm *hdspm, int mode, u32 regmask) | ||
3497 | { | ||
3498 | hdspm->settings_register &= ~(regmask * 3); | ||
3499 | hdspm->settings_register |= (regmask * mode); | ||
3500 | hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); | ||
3501 | |||
3502 | return 0; | ||
3503 | } | ||
3504 | |||
3505 | static int snd_hdspm_info_tristate(struct snd_kcontrol *kcontrol, | ||
3506 | struct snd_ctl_elem_info *uinfo) | ||
3507 | { | ||
3508 | u32 regmask = kcontrol->private_value; | ||
3509 | |||
3510 | static const char *const texts_spdif[] = { "Optical", "Coaxial", "Internal" }; | ||
3511 | static const char *const texts_levels[] = { "Hi Gain", "+4 dBu", "-10 dBV" }; | ||
3512 | |||
3513 | switch (regmask) { | ||
3514 | case HDSPM_c0_Input0: | ||
3515 | ENUMERATED_CTL_INFO(uinfo, texts_spdif); | ||
3516 | break; | ||
3517 | default: | ||
3518 | ENUMERATED_CTL_INFO(uinfo, texts_levels); | ||
3519 | break; | ||
3520 | } | ||
3521 | return 0; | ||
3522 | } | ||
3523 | |||
3524 | static int snd_hdspm_get_tristate(struct snd_kcontrol *kcontrol, | ||
3525 | struct snd_ctl_elem_value *ucontrol) | ||
3526 | { | ||
3527 | struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); | ||
3528 | u32 regmask = kcontrol->private_value; | ||
3529 | |||
3530 | spin_lock_irq(&hdspm->lock); | ||
3531 | ucontrol->value.enumerated.item[0] = hdspm_tristate(hdspm, regmask); | ||
3532 | spin_unlock_irq(&hdspm->lock); | ||
3533 | return 0; | ||
3534 | } | ||
3535 | |||
3536 | static int snd_hdspm_put_tristate(struct snd_kcontrol *kcontrol, | ||
3537 | struct snd_ctl_elem_value *ucontrol) | ||
3538 | { | ||
3539 | struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); | ||
3540 | u32 regmask = kcontrol->private_value; | ||
3541 | int change; | ||
3542 | int val; | ||
3543 | |||
3544 | if (!snd_hdspm_use_is_exclusive(hdspm)) | ||
3545 | return -EBUSY; | ||
3546 | val = ucontrol->value.integer.value[0]; | ||
3547 | if (val < 0) | ||
3548 | val = 0; | ||
3549 | if (val > 2) | ||
3550 | val = 2; | ||
3551 | |||
3552 | spin_lock_irq(&hdspm->lock); | ||
3553 | change = val != hdspm_tristate(hdspm, regmask); | ||
3554 | hdspm_set_tristate(hdspm, val, regmask); | ||
3555 | spin_unlock_irq(&hdspm->lock); | ||
3556 | return change; | ||
3557 | } | ||
3558 | |||
3316 | #define HDSPM_MADI_SPEEDMODE(xname, xindex) \ | 3559 | #define HDSPM_MADI_SPEEDMODE(xname, xindex) \ |
3317 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | 3560 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
3318 | .name = xname, \ | 3561 | .name = xname, \ |
@@ -3352,7 +3595,7 @@ static int hdspm_set_madi_speedmode(struct hdspm *hdspm, int mode) | |||
3352 | static int snd_hdspm_info_madi_speedmode(struct snd_kcontrol *kcontrol, | 3595 | static int snd_hdspm_info_madi_speedmode(struct snd_kcontrol *kcontrol, |
3353 | struct snd_ctl_elem_info *uinfo) | 3596 | struct snd_ctl_elem_info *uinfo) |
3354 | { | 3597 | { |
3355 | static char *texts[] = { "Single", "Double", "Quad" }; | 3598 | static const char *const texts[] = { "Single", "Double", "Quad" }; |
3356 | ENUMERATED_CTL_INFO(uinfo, texts); | 3599 | ENUMERATED_CTL_INFO(uinfo, texts); |
3357 | return 0; | 3600 | return 0; |
3358 | } | 3601 | } |
@@ -3587,7 +3830,7 @@ static int snd_hdspm_put_playback_mixer(struct snd_kcontrol *kcontrol, | |||
3587 | static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol, | 3830 | static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol, |
3588 | struct snd_ctl_elem_info *uinfo) | 3831 | struct snd_ctl_elem_info *uinfo) |
3589 | { | 3832 | { |
3590 | static char *texts[] = { "No Lock", "Lock", "Sync", "N/A" }; | 3833 | static const char *const texts[] = { "No Lock", "Lock", "Sync", "N/A" }; |
3591 | ENUMERATED_CTL_INFO(uinfo, texts); | 3834 | ENUMERATED_CTL_INFO(uinfo, texts); |
3592 | return 0; | 3835 | return 0; |
3593 | } | 3836 | } |
@@ -3595,7 +3838,7 @@ static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol, | |||
3595 | static int snd_hdspm_tco_info_lock_check(struct snd_kcontrol *kcontrol, | 3838 | static int snd_hdspm_tco_info_lock_check(struct snd_kcontrol *kcontrol, |
3596 | struct snd_ctl_elem_info *uinfo) | 3839 | struct snd_ctl_elem_info *uinfo) |
3597 | { | 3840 | { |
3598 | static char *texts[] = { "No Lock", "Lock" }; | 3841 | static const char *const texts[] = { "No Lock", "Lock" }; |
3599 | ENUMERATED_CTL_INFO(uinfo, texts); | 3842 | ENUMERATED_CTL_INFO(uinfo, texts); |
3600 | return 0; | 3843 | return 0; |
3601 | } | 3844 | } |
@@ -3745,9 +3988,18 @@ static int hdspm_tco_sync_check(struct hdspm *hdspm) | |||
3745 | if (hdspm->tco) { | 3988 | if (hdspm->tco) { |
3746 | switch (hdspm->io_type) { | 3989 | switch (hdspm->io_type) { |
3747 | case MADI: | 3990 | case MADI: |
3991 | status = hdspm_read(hdspm, HDSPM_statusRegister); | ||
3992 | if (status & HDSPM_tcoLockMadi) { | ||
3993 | if (status & HDSPM_tcoSync) | ||
3994 | return 2; | ||
3995 | else | ||
3996 | return 1; | ||
3997 | } | ||
3998 | return 0; | ||
3999 | break; | ||
3748 | case AES32: | 4000 | case AES32: |
3749 | status = hdspm_read(hdspm, HDSPM_statusRegister); | 4001 | status = hdspm_read(hdspm, HDSPM_statusRegister); |
3750 | if (status & HDSPM_tcoLock) { | 4002 | if (status & HDSPM_tcoLockAes) { |
3751 | if (status & HDSPM_tcoSync) | 4003 | if (status & HDSPM_tcoSync) |
3752 | return 2; | 4004 | return 2; |
3753 | else | 4005 | else |
@@ -3807,7 +4059,8 @@ static int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol, | |||
3807 | case 5: /* SYNC IN */ | 4059 | case 5: /* SYNC IN */ |
3808 | val = hdspm_sync_in_sync_check(hdspm); break; | 4060 | val = hdspm_sync_in_sync_check(hdspm); break; |
3809 | default: | 4061 | default: |
3810 | val = hdspm_s1_sync_check(hdspm, ucontrol->id.index-1); | 4062 | val = hdspm_s1_sync_check(hdspm, |
4063 | kcontrol->private_value-1); | ||
3811 | } | 4064 | } |
3812 | break; | 4065 | break; |
3813 | 4066 | ||
@@ -3975,7 +4228,8 @@ static void hdspm_tco_write(struct hdspm *hdspm) | |||
3975 | static int snd_hdspm_info_tco_sample_rate(struct snd_kcontrol *kcontrol, | 4228 | static int snd_hdspm_info_tco_sample_rate(struct snd_kcontrol *kcontrol, |
3976 | struct snd_ctl_elem_info *uinfo) | 4229 | struct snd_ctl_elem_info *uinfo) |
3977 | { | 4230 | { |
3978 | static char *texts[] = { "44.1 kHz", "48 kHz" }; | 4231 | /* TODO freq from app could be supported here, see tco->samplerate */ |
4232 | static const char *const texts[] = { "44.1 kHz", "48 kHz" }; | ||
3979 | ENUMERATED_CTL_INFO(uinfo, texts); | 4233 | ENUMERATED_CTL_INFO(uinfo, texts); |
3980 | return 0; | 4234 | return 0; |
3981 | } | 4235 | } |
@@ -4021,7 +4275,8 @@ static int snd_hdspm_put_tco_sample_rate(struct snd_kcontrol *kcontrol, | |||
4021 | static int snd_hdspm_info_tco_pull(struct snd_kcontrol *kcontrol, | 4275 | static int snd_hdspm_info_tco_pull(struct snd_kcontrol *kcontrol, |
4022 | struct snd_ctl_elem_info *uinfo) | 4276 | struct snd_ctl_elem_info *uinfo) |
4023 | { | 4277 | { |
4024 | static char *texts[] = { "0", "+ 0.1 %", "- 0.1 %", "+ 4 %", "- 4 %" }; | 4278 | static const char *const texts[] = { "0", "+ 0.1 %", "- 0.1 %", |
4279 | "+ 4 %", "- 4 %" }; | ||
4025 | ENUMERATED_CTL_INFO(uinfo, texts); | 4280 | ENUMERATED_CTL_INFO(uinfo, texts); |
4026 | return 0; | 4281 | return 0; |
4027 | } | 4282 | } |
@@ -4066,7 +4321,7 @@ static int snd_hdspm_put_tco_pull(struct snd_kcontrol *kcontrol, | |||
4066 | static int snd_hdspm_info_tco_wck_conversion(struct snd_kcontrol *kcontrol, | 4321 | static int snd_hdspm_info_tco_wck_conversion(struct snd_kcontrol *kcontrol, |
4067 | struct snd_ctl_elem_info *uinfo) | 4322 | struct snd_ctl_elem_info *uinfo) |
4068 | { | 4323 | { |
4069 | static char *texts[] = { "1:1", "44.1 -> 48", "48 -> 44.1" }; | 4324 | static const char *const texts[] = { "1:1", "44.1 -> 48", "48 -> 44.1" }; |
4070 | ENUMERATED_CTL_INFO(uinfo, texts); | 4325 | ENUMERATED_CTL_INFO(uinfo, texts); |
4071 | return 0; | 4326 | return 0; |
4072 | } | 4327 | } |
@@ -4112,7 +4367,7 @@ static int snd_hdspm_put_tco_wck_conversion(struct snd_kcontrol *kcontrol, | |||
4112 | static int snd_hdspm_info_tco_frame_rate(struct snd_kcontrol *kcontrol, | 4367 | static int snd_hdspm_info_tco_frame_rate(struct snd_kcontrol *kcontrol, |
4113 | struct snd_ctl_elem_info *uinfo) | 4368 | struct snd_ctl_elem_info *uinfo) |
4114 | { | 4369 | { |
4115 | static char *texts[] = { "24 fps", "25 fps", "29.97fps", | 4370 | static const char *const texts[] = { "24 fps", "25 fps", "29.97fps", |
4116 | "29.97 dfps", "30 fps", "30 dfps" }; | 4371 | "29.97 dfps", "30 fps", "30 dfps" }; |
4117 | ENUMERATED_CTL_INFO(uinfo, texts); | 4372 | ENUMERATED_CTL_INFO(uinfo, texts); |
4118 | return 0; | 4373 | return 0; |
@@ -4159,7 +4414,7 @@ static int snd_hdspm_put_tco_frame_rate(struct snd_kcontrol *kcontrol, | |||
4159 | static int snd_hdspm_info_tco_sync_source(struct snd_kcontrol *kcontrol, | 4414 | static int snd_hdspm_info_tco_sync_source(struct snd_kcontrol *kcontrol, |
4160 | struct snd_ctl_elem_info *uinfo) | 4415 | struct snd_ctl_elem_info *uinfo) |
4161 | { | 4416 | { |
4162 | static char *texts[] = { "LTC", "Video", "WCK" }; | 4417 | static const char *const texts[] = { "LTC", "Video", "WCK" }; |
4163 | ENUMERATED_CTL_INFO(uinfo, texts); | 4418 | ENUMERATED_CTL_INFO(uinfo, texts); |
4164 | return 0; | 4419 | return 0; |
4165 | } | 4420 | } |
@@ -4284,7 +4539,6 @@ static struct snd_kcontrol_new snd_hdspm_controls_aio[] = { | |||
4284 | HDSPM_INTERNAL_CLOCK("Internal Clock", 0), | 4539 | HDSPM_INTERNAL_CLOCK("Internal Clock", 0), |
4285 | HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), | 4540 | HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), |
4286 | HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), | 4541 | HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), |
4287 | HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), | ||
4288 | HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), | 4542 | HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), |
4289 | HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), | 4543 | HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), |
4290 | HDSPM_SYNC_CHECK("WC SyncCheck", 0), | 4544 | HDSPM_SYNC_CHECK("WC SyncCheck", 0), |
@@ -4298,7 +4552,16 @@ static struct snd_kcontrol_new snd_hdspm_controls_aio[] = { | |||
4298 | HDSPM_AUTOSYNC_SAMPLE_RATE("SPDIF Frequency", 2), | 4552 | HDSPM_AUTOSYNC_SAMPLE_RATE("SPDIF Frequency", 2), |
4299 | HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT Frequency", 3), | 4553 | HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT Frequency", 3), |
4300 | HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 4), | 4554 | HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 4), |
4301 | HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 5) | 4555 | HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 5), |
4556 | HDSPM_CONTROL_TRISTATE("S/PDIF Input", HDSPM_c0_Input0), | ||
4557 | HDSPM_TOGGLE_SETTING("S/PDIF Out Optical", HDSPM_c0_Spdif_Opt), | ||
4558 | HDSPM_TOGGLE_SETTING("S/PDIF Out Professional", HDSPM_c0_Pro), | ||
4559 | HDSPM_TOGGLE_SETTING("ADAT internal (AEB/TEB)", HDSPM_c0_AEB1), | ||
4560 | HDSPM_TOGGLE_SETTING("XLR Breakout Cable", HDSPM_c0_Sym6db), | ||
4561 | HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48), | ||
4562 | HDSPM_CONTROL_TRISTATE("Input Level", HDSPM_c0_AD_GAIN0), | ||
4563 | HDSPM_CONTROL_TRISTATE("Output Level", HDSPM_c0_DA_GAIN0), | ||
4564 | HDSPM_CONTROL_TRISTATE("Phones Level", HDSPM_c0_PH_GAIN0) | ||
4302 | 4565 | ||
4303 | /* | 4566 | /* |
4304 | HDSPM_INPUT_SELECT("Input Select", 0), | 4567 | HDSPM_INPUT_SELECT("Input Select", 0), |
@@ -4335,7 +4598,9 @@ static struct snd_kcontrol_new snd_hdspm_controls_raydat[] = { | |||
4335 | HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT3 Frequency", 5), | 4598 | HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT3 Frequency", 5), |
4336 | HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT4 Frequency", 6), | 4599 | HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT4 Frequency", 6), |
4337 | HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 7), | 4600 | HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 7), |
4338 | HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 8) | 4601 | HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 8), |
4602 | HDSPM_TOGGLE_SETTING("S/PDIF Out Professional", HDSPM_c0_Pro), | ||
4603 | HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48) | ||
4339 | }; | 4604 | }; |
4340 | 4605 | ||
4341 | static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = { | 4606 | static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = { |
@@ -4345,7 +4610,7 @@ static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = { | |||
4345 | HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), | 4610 | HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), |
4346 | HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), | 4611 | HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), |
4347 | HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), | 4612 | HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), |
4348 | HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), | 4613 | HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 11), |
4349 | HDSPM_SYNC_CHECK("WC Sync Check", 0), | 4614 | HDSPM_SYNC_CHECK("WC Sync Check", 0), |
4350 | HDSPM_SYNC_CHECK("AES1 Sync Check", 1), | 4615 | HDSPM_SYNC_CHECK("AES1 Sync Check", 1), |
4351 | HDSPM_SYNC_CHECK("AES2 Sync Check", 2), | 4616 | HDSPM_SYNC_CHECK("AES2 Sync Check", 2), |
@@ -4501,77 +4766,22 @@ static int snd_hdspm_create_controls(struct snd_card *card, | |||
4501 | ------------------------------------------------------------*/ | 4766 | ------------------------------------------------------------*/ |
4502 | 4767 | ||
4503 | static void | 4768 | static void |
4504 | snd_hdspm_proc_read_madi(struct snd_info_entry * entry, | 4769 | snd_hdspm_proc_read_tco(struct snd_info_entry *entry, |
4505 | struct snd_info_buffer *buffer) | 4770 | struct snd_info_buffer *buffer) |
4506 | { | 4771 | { |
4507 | struct hdspm *hdspm = entry->private_data; | 4772 | struct hdspm *hdspm = entry->private_data; |
4508 | unsigned int status, status2, control, freq; | 4773 | unsigned int status, control; |
4509 | |||
4510 | char *pref_sync_ref; | ||
4511 | char *autosync_ref; | ||
4512 | char *system_clock_mode; | ||
4513 | char *insel; | ||
4514 | int x, x2; | ||
4515 | |||
4516 | /* TCO stuff */ | ||
4517 | int a, ltc, frames, seconds, minutes, hours; | 4774 | int a, ltc, frames, seconds, minutes, hours; |
4518 | unsigned int period; | 4775 | unsigned int period; |
4519 | u64 freq_const = 0; | 4776 | u64 freq_const = 0; |
4520 | u32 rate; | 4777 | u32 rate; |
4521 | 4778 | ||
4779 | snd_iprintf(buffer, "--- TCO ---\n"); | ||
4780 | |||
4522 | status = hdspm_read(hdspm, HDSPM_statusRegister); | 4781 | status = hdspm_read(hdspm, HDSPM_statusRegister); |
4523 | status2 = hdspm_read(hdspm, HDSPM_statusRegister2); | ||
4524 | control = hdspm->control_register; | 4782 | control = hdspm->control_register; |
4525 | freq = hdspm_read(hdspm, HDSPM_timecodeRegister); | ||
4526 | 4783 | ||
4527 | snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n", | ||
4528 | hdspm->card_name, hdspm->card->number + 1, | ||
4529 | hdspm->firmware_rev, | ||
4530 | (status2 & HDSPM_version0) | | ||
4531 | (status2 & HDSPM_version1) | (status2 & | ||
4532 | HDSPM_version2)); | ||
4533 | 4784 | ||
4534 | snd_iprintf(buffer, "HW Serial: 0x%06x%06x\n", | ||
4535 | (hdspm_read(hdspm, HDSPM_midiStatusIn1)>>8) & 0xFFFFFF, | ||
4536 | hdspm->serial); | ||
4537 | |||
4538 | snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", | ||
4539 | hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase); | ||
4540 | |||
4541 | snd_iprintf(buffer, "--- System ---\n"); | ||
4542 | |||
4543 | snd_iprintf(buffer, | ||
4544 | "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n", | ||
4545 | status & HDSPM_audioIRQPending, | ||
4546 | (status & HDSPM_midi0IRQPending) ? 1 : 0, | ||
4547 | (status & HDSPM_midi1IRQPending) ? 1 : 0, | ||
4548 | hdspm->irq_count); | ||
4549 | snd_iprintf(buffer, | ||
4550 | "HW pointer: id = %d, rawptr = %d (%d->%d) " | ||
4551 | "estimated= %ld (bytes)\n", | ||
4552 | ((status & HDSPM_BufferID) ? 1 : 0), | ||
4553 | (status & HDSPM_BufferPositionMask), | ||
4554 | (status & HDSPM_BufferPositionMask) % | ||
4555 | (2 * (int)hdspm->period_bytes), | ||
4556 | ((status & HDSPM_BufferPositionMask) - 64) % | ||
4557 | (2 * (int)hdspm->period_bytes), | ||
4558 | (long) hdspm_hw_pointer(hdspm) * 4); | ||
4559 | |||
4560 | snd_iprintf(buffer, | ||
4561 | "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n", | ||
4562 | hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF, | ||
4563 | hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF, | ||
4564 | hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF, | ||
4565 | hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF); | ||
4566 | snd_iprintf(buffer, | ||
4567 | "MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n", | ||
4568 | hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF, | ||
4569 | hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF); | ||
4570 | snd_iprintf(buffer, | ||
4571 | "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, " | ||
4572 | "status2=0x%x\n", | ||
4573 | hdspm->control_register, hdspm->control2_register, | ||
4574 | status, status2); | ||
4575 | if (status & HDSPM_tco_detect) { | 4785 | if (status & HDSPM_tco_detect) { |
4576 | snd_iprintf(buffer, "TCO module detected.\n"); | 4786 | snd_iprintf(buffer, "TCO module detected.\n"); |
4577 | a = hdspm_read(hdspm, HDSPM_RD_TCO+4); | 4787 | a = hdspm_read(hdspm, HDSPM_RD_TCO+4); |
@@ -4665,6 +4875,75 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry, | |||
4665 | } else { | 4875 | } else { |
4666 | snd_iprintf(buffer, "No TCO module detected.\n"); | 4876 | snd_iprintf(buffer, "No TCO module detected.\n"); |
4667 | } | 4877 | } |
4878 | } | ||
4879 | |||
4880 | static void | ||
4881 | snd_hdspm_proc_read_madi(struct snd_info_entry *entry, | ||
4882 | struct snd_info_buffer *buffer) | ||
4883 | { | ||
4884 | struct hdspm *hdspm = entry->private_data; | ||
4885 | unsigned int status, status2, control, freq; | ||
4886 | |||
4887 | char *pref_sync_ref; | ||
4888 | char *autosync_ref; | ||
4889 | char *system_clock_mode; | ||
4890 | char *insel; | ||
4891 | int x, x2; | ||
4892 | |||
4893 | status = hdspm_read(hdspm, HDSPM_statusRegister); | ||
4894 | status2 = hdspm_read(hdspm, HDSPM_statusRegister2); | ||
4895 | control = hdspm->control_register; | ||
4896 | freq = hdspm_read(hdspm, HDSPM_timecodeRegister); | ||
4897 | |||
4898 | snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n", | ||
4899 | hdspm->card_name, hdspm->card->number + 1, | ||
4900 | hdspm->firmware_rev, | ||
4901 | (status2 & HDSPM_version0) | | ||
4902 | (status2 & HDSPM_version1) | (status2 & | ||
4903 | HDSPM_version2)); | ||
4904 | |||
4905 | snd_iprintf(buffer, "HW Serial: 0x%06x%06x\n", | ||
4906 | (hdspm_read(hdspm, HDSPM_midiStatusIn1)>>8) & 0xFFFFFF, | ||
4907 | hdspm->serial); | ||
4908 | |||
4909 | snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", | ||
4910 | hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase); | ||
4911 | |||
4912 | snd_iprintf(buffer, "--- System ---\n"); | ||
4913 | |||
4914 | snd_iprintf(buffer, | ||
4915 | "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n", | ||
4916 | status & HDSPM_audioIRQPending, | ||
4917 | (status & HDSPM_midi0IRQPending) ? 1 : 0, | ||
4918 | (status & HDSPM_midi1IRQPending) ? 1 : 0, | ||
4919 | hdspm->irq_count); | ||
4920 | snd_iprintf(buffer, | ||
4921 | "HW pointer: id = %d, rawptr = %d (%d->%d) " | ||
4922 | "estimated= %ld (bytes)\n", | ||
4923 | ((status & HDSPM_BufferID) ? 1 : 0), | ||
4924 | (status & HDSPM_BufferPositionMask), | ||
4925 | (status & HDSPM_BufferPositionMask) % | ||
4926 | (2 * (int)hdspm->period_bytes), | ||
4927 | ((status & HDSPM_BufferPositionMask) - 64) % | ||
4928 | (2 * (int)hdspm->period_bytes), | ||
4929 | (long) hdspm_hw_pointer(hdspm) * 4); | ||
4930 | |||
4931 | snd_iprintf(buffer, | ||
4932 | "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n", | ||
4933 | hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF, | ||
4934 | hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF, | ||
4935 | hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF, | ||
4936 | hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF); | ||
4937 | snd_iprintf(buffer, | ||
4938 | "MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n", | ||
4939 | hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF, | ||
4940 | hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF); | ||
4941 | snd_iprintf(buffer, | ||
4942 | "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, " | ||
4943 | "status2=0x%x\n", | ||
4944 | hdspm->control_register, hdspm->control2_register, | ||
4945 | status, status2); | ||
4946 | |||
4668 | 4947 | ||
4669 | snd_iprintf(buffer, "--- Settings ---\n"); | 4948 | snd_iprintf(buffer, "--- Settings ---\n"); |
4670 | 4949 | ||
@@ -4768,6 +5047,9 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry, | |||
4768 | (status & HDSPM_RX_64ch) ? "64 channels" : | 5047 | (status & HDSPM_RX_64ch) ? "64 channels" : |
4769 | "56 channels"); | 5048 | "56 channels"); |
4770 | 5049 | ||
5050 | /* call readout function for TCO specific status */ | ||
5051 | snd_hdspm_proc_read_tco(entry, buffer); | ||
5052 | |||
4771 | snd_iprintf(buffer, "\n"); | 5053 | snd_iprintf(buffer, "\n"); |
4772 | } | 5054 | } |
4773 | 5055 | ||
@@ -4909,11 +5191,18 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry, | |||
4909 | autosync_ref = "AES7"; break; | 5191 | autosync_ref = "AES7"; break; |
4910 | case HDSPM_AES32_AUTOSYNC_FROM_AES8: | 5192 | case HDSPM_AES32_AUTOSYNC_FROM_AES8: |
4911 | autosync_ref = "AES8"; break; | 5193 | autosync_ref = "AES8"; break; |
5194 | case HDSPM_AES32_AUTOSYNC_FROM_TCO: | ||
5195 | autosync_ref = "TCO"; break; | ||
5196 | case HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN: | ||
5197 | autosync_ref = "Sync In"; break; | ||
4912 | default: | 5198 | default: |
4913 | autosync_ref = "---"; break; | 5199 | autosync_ref = "---"; break; |
4914 | } | 5200 | } |
4915 | snd_iprintf(buffer, "AutoSync ref = %s\n", autosync_ref); | 5201 | snd_iprintf(buffer, "AutoSync ref = %s\n", autosync_ref); |
4916 | 5202 | ||
5203 | /* call readout function for TCO specific status */ | ||
5204 | snd_hdspm_proc_read_tco(entry, buffer); | ||
5205 | |||
4917 | snd_iprintf(buffer, "\n"); | 5206 | snd_iprintf(buffer, "\n"); |
4918 | } | 5207 | } |
4919 | 5208 | ||
@@ -5097,7 +5386,7 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm) | |||
5097 | 5386 | ||
5098 | case AES32: | 5387 | case AES32: |
5099 | hdspm->control_register = | 5388 | hdspm->control_register = |
5100 | HDSPM_ClockModeMaster | /* Master Cloack Mode on */ | 5389 | HDSPM_ClockModeMaster | /* Master Clock Mode on */ |
5101 | hdspm_encode_latency(7) | /* latency max=8192samples */ | 5390 | hdspm_encode_latency(7) | /* latency max=8192samples */ |
5102 | HDSPM_SyncRef0 | /* AES1 is syncclock */ | 5391 | HDSPM_SyncRef0 | /* AES1 is syncclock */ |
5103 | HDSPM_LineOut | /* Analog output in */ | 5392 | HDSPM_LineOut | /* Analog output in */ |
@@ -5123,9 +5412,8 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm) | |||
5123 | 5412 | ||
5124 | all_in_all_mixer(hdspm, 0 * UNITY_GAIN); | 5413 | all_in_all_mixer(hdspm, 0 * UNITY_GAIN); |
5125 | 5414 | ||
5126 | if (hdspm->io_type == AIO || hdspm->io_type == RayDAT) { | 5415 | if (hdspm_is_raydat_or_aio(hdspm)) |
5127 | hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); | 5416 | hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); |
5128 | } | ||
5129 | 5417 | ||
5130 | /* set a default rate so that the channel map is set up. */ | 5418 | /* set a default rate so that the channel map is set up. */ |
5131 | hdspm_set_rate(hdspm, 48000, 1); | 5419 | hdspm_set_rate(hdspm, 48000, 1); |
@@ -5371,6 +5659,16 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream, | |||
5371 | */ | 5659 | */ |
5372 | 5660 | ||
5373 | 5661 | ||
5662 | /* For AES cards, the float format bit is the same as the | ||
5663 | * preferred sync reference. Since we don't want to break | ||
5664 | * sync settings, we have to skip the remaining part of this | ||
5665 | * function. | ||
5666 | */ | ||
5667 | if (hdspm->io_type == AES32) { | ||
5668 | return 0; | ||
5669 | } | ||
5670 | |||
5671 | |||
5374 | /* Switch to native float format if requested */ | 5672 | /* Switch to native float format if requested */ |
5375 | if (SNDRV_PCM_FORMAT_FLOAT_LE == params_format(params)) { | 5673 | if (SNDRV_PCM_FORMAT_FLOAT_LE == params_format(params)) { |
5376 | if (!(hdspm->control_register & HDSPe_FLOAT_FORMAT)) | 5674 | if (!(hdspm->control_register & HDSPe_FLOAT_FORMAT)) |
@@ -6013,7 +6311,7 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, | |||
6013 | ltc.format = fps_2997; | 6311 | ltc.format = fps_2997; |
6014 | break; | 6312 | break; |
6015 | default: | 6313 | default: |
6016 | ltc.format = 30; | 6314 | ltc.format = fps_30; |
6017 | break; | 6315 | break; |
6018 | } | 6316 | } |
6019 | if (i & HDSPM_TCO1_set_drop_frame_flag) { | 6317 | if (i & HDSPM_TCO1_set_drop_frame_flag) { |
@@ -6479,10 +6777,6 @@ static int snd_hdspm_create(struct snd_card *card, | |||
6479 | break; | 6777 | break; |
6480 | 6778 | ||
6481 | case AIO: | 6779 | case AIO: |
6482 | if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBI_D)) { | ||
6483 | snd_printk(KERN_INFO "HDSPM: AEB input board found, but not supported\n"); | ||
6484 | } | ||
6485 | |||
6486 | hdspm->ss_in_channels = AIO_IN_SS_CHANNELS; | 6780 | hdspm->ss_in_channels = AIO_IN_SS_CHANNELS; |
6487 | hdspm->ds_in_channels = AIO_IN_DS_CHANNELS; | 6781 | hdspm->ds_in_channels = AIO_IN_DS_CHANNELS; |
6488 | hdspm->qs_in_channels = AIO_IN_QS_CHANNELS; | 6782 | hdspm->qs_in_channels = AIO_IN_QS_CHANNELS; |
@@ -6490,6 +6784,20 @@ static int snd_hdspm_create(struct snd_card *card, | |||
6490 | hdspm->ds_out_channels = AIO_OUT_DS_CHANNELS; | 6784 | hdspm->ds_out_channels = AIO_OUT_DS_CHANNELS; |
6491 | hdspm->qs_out_channels = AIO_OUT_QS_CHANNELS; | 6785 | hdspm->qs_out_channels = AIO_OUT_QS_CHANNELS; |
6492 | 6786 | ||
6787 | if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBI_D)) { | ||
6788 | snd_printk(KERN_INFO "HDSPM: AEB input board found\n"); | ||
6789 | hdspm->ss_in_channels += 4; | ||
6790 | hdspm->ds_in_channels += 4; | ||
6791 | hdspm->qs_in_channels += 4; | ||
6792 | } | ||
6793 | |||
6794 | if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBO_D)) { | ||
6795 | snd_printk(KERN_INFO "HDSPM: AEB output board found\n"); | ||
6796 | hdspm->ss_out_channels += 4; | ||
6797 | hdspm->ds_out_channels += 4; | ||
6798 | hdspm->qs_out_channels += 4; | ||
6799 | } | ||
6800 | |||
6493 | hdspm->channel_map_out_ss = channel_map_aio_out_ss; | 6801 | hdspm->channel_map_out_ss = channel_map_aio_out_ss; |
6494 | hdspm->channel_map_out_ds = channel_map_aio_out_ds; | 6802 | hdspm->channel_map_out_ds = channel_map_aio_out_ds; |
6495 | hdspm->channel_map_out_qs = channel_map_aio_out_qs; | 6803 | hdspm->channel_map_out_qs = channel_map_aio_out_qs; |
@@ -6558,6 +6866,7 @@ static int snd_hdspm_create(struct snd_card *card, | |||
6558 | break; | 6866 | break; |
6559 | 6867 | ||
6560 | case MADI: | 6868 | case MADI: |
6869 | case AES32: | ||
6561 | if (hdspm_read(hdspm, HDSPM_statusRegister) & HDSPM_tco_detect) { | 6870 | if (hdspm_read(hdspm, HDSPM_statusRegister) & HDSPM_tco_detect) { |
6562 | hdspm->midiPorts++; | 6871 | hdspm->midiPorts++; |
6563 | hdspm->tco = kzalloc(sizeof(struct hdspm_tco), | 6872 | hdspm->tco = kzalloc(sizeof(struct hdspm_tco), |
@@ -6565,7 +6874,7 @@ static int snd_hdspm_create(struct snd_card *card, | |||
6565 | if (NULL != hdspm->tco) { | 6874 | if (NULL != hdspm->tco) { |
6566 | hdspm_tco_write(hdspm); | 6875 | hdspm_tco_write(hdspm); |
6567 | } | 6876 | } |
6568 | snd_printk(KERN_INFO "HDSPM: MADI TCO module found\n"); | 6877 | snd_printk(KERN_INFO "HDSPM: MADI/AES TCO module found\n"); |
6569 | } else { | 6878 | } else { |
6570 | hdspm->tco = NULL; | 6879 | hdspm->tco = NULL; |
6571 | } | 6880 | } |
@@ -6580,10 +6889,12 @@ static int snd_hdspm_create(struct snd_card *card, | |||
6580 | case AES32: | 6889 | case AES32: |
6581 | if (hdspm->tco) { | 6890 | if (hdspm->tco) { |
6582 | hdspm->texts_autosync = texts_autosync_aes_tco; | 6891 | hdspm->texts_autosync = texts_autosync_aes_tco; |
6583 | hdspm->texts_autosync_items = 10; | 6892 | hdspm->texts_autosync_items = |
6893 | ARRAY_SIZE(texts_autosync_aes_tco); | ||
6584 | } else { | 6894 | } else { |
6585 | hdspm->texts_autosync = texts_autosync_aes; | 6895 | hdspm->texts_autosync = texts_autosync_aes; |
6586 | hdspm->texts_autosync_items = 9; | 6896 | hdspm->texts_autosync_items = |
6897 | ARRAY_SIZE(texts_autosync_aes); | ||
6587 | } | 6898 | } |
6588 | break; | 6899 | break; |
6589 | 6900 | ||