diff options
| -rw-r--r-- | include/sound/pcm.h | 35 | ||||
| -rw-r--r-- | include/sound/pcm_params.h | 16 | ||||
| -rw-r--r-- | include/sound/soc-dapm.h | 6 | ||||
| -rw-r--r-- | sound/core/pcm_lib.c | 13 | ||||
| -rw-r--r-- | sound/pci/asihpi/asihpi.c | 21 | ||||
| -rw-r--r-- | sound/pci/hda/Kconfig | 1 | ||||
| -rw-r--r-- | sound/pci/hda/hda_codec.c | 114 | ||||
| -rw-r--r-- | sound/pci/hda/hda_codec.h | 15 | ||||
| -rw-r--r-- | sound/pci/hda/hda_local.h | 2 | ||||
| -rw-r--r-- | sound/pci/hda/patch_analog.c | 4 | ||||
| -rw-r--r-- | sound/pci/hda/patch_cirrus.c | 743 | ||||
| -rw-r--r-- | sound/pci/hda/patch_conexant.c | 14 | ||||
| -rw-r--r-- | sound/pci/hda/patch_realtek.c | 15 | ||||
| -rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 122 | ||||
| -rw-r--r-- | sound/pci/hda/patch_via.c | 4 | ||||
| -rw-r--r-- | sound/soc/codecs/sgtl5000.c | 70 | ||||
| -rw-r--r-- | sound/soc/codecs/wm8962.c | 6 | ||||
| -rw-r--r-- | sound/soc/davinci/davinci-vcif.c | 9 | ||||
| -rw-r--r-- | sound/soc/samsung/i2s.c | 7 | ||||
| -rw-r--r-- | sound/soc/soc-core.c | 5 | ||||
| -rw-r--r-- | sound/soc/soc-dapm.c | 30 |
21 files changed, 1035 insertions, 217 deletions
diff --git a/include/sound/pcm.h b/include/sound/pcm.h index e1bad1130616..57e71fa33f7c 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h | |||
| @@ -507,6 +507,18 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream); | |||
| 507 | void snd_pcm_vma_notify_data(void *client, void *data); | 507 | void snd_pcm_vma_notify_data(void *client, void *data); |
| 508 | int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area); | 508 | int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area); |
| 509 | 509 | ||
| 510 | |||
| 511 | #ifdef CONFIG_SND_DEBUG | ||
| 512 | void snd_pcm_debug_name(struct snd_pcm_substream *substream, | ||
| 513 | char *name, size_t len); | ||
| 514 | #else | ||
| 515 | static inline void | ||
| 516 | snd_pcm_debug_name(struct snd_pcm_substream *substream, char *buf, size_t size) | ||
| 517 | { | ||
| 518 | *buf = 0; | ||
| 519 | } | ||
| 520 | #endif | ||
| 521 | |||
| 510 | /* | 522 | /* |
| 511 | * PCM library | 523 | * PCM library |
| 512 | */ | 524 | */ |
| @@ -749,17 +761,18 @@ static inline const struct snd_interval *hw_param_interval_c(const struct snd_pc | |||
| 749 | return ¶ms->intervals[var - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]; | 761 | return ¶ms->intervals[var - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]; |
| 750 | } | 762 | } |
| 751 | 763 | ||
| 752 | #define params_access(p) ((__force snd_pcm_access_t)snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_ACCESS))) | 764 | #define params_channels(p) \ |
| 753 | #define params_format(p) ((__force snd_pcm_format_t)snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_FORMAT))) | 765 | (hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_CHANNELS)->min) |
| 754 | #define params_subformat(p) snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_SUBFORMAT)) | 766 | #define params_rate(p) \ |
| 755 | #define params_channels(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_CHANNELS)->min | 767 | (hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_RATE)->min) |
| 756 | #define params_rate(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_RATE)->min | 768 | #define params_period_size(p) \ |
| 757 | #define params_period_size(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_PERIOD_SIZE)->min | 769 | (hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_PERIOD_SIZE)->min) |
| 758 | #define params_period_bytes(p) ((params_period_size(p)*snd_pcm_format_physical_width(params_format(p))*params_channels(p))/8) | 770 | #define params_periods(p) \ |
| 759 | #define params_periods(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_PERIODS)->min | 771 | (hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_PERIODS)->min) |
| 760 | #define params_buffer_size(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_BUFFER_SIZE)->min | 772 | #define params_buffer_size(p) \ |
| 761 | #define params_buffer_bytes(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_BUFFER_BYTES)->min | 773 | (hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_BUFFER_SIZE)->min) |
| 762 | 774 | #define params_buffer_bytes(p) \ | |
| 775 | (hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_BUFFER_BYTES)->min) | ||
| 763 | 776 | ||
| 764 | int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v); | 777 | int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v); |
| 765 | void snd_interval_mul(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c); | 778 | void snd_interval_mul(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c); |
diff --git a/include/sound/pcm_params.h b/include/sound/pcm_params.h index 85cf1cf4f31a..f494f1e3c900 100644 --- a/include/sound/pcm_params.h +++ b/include/sound/pcm_params.h | |||
| @@ -337,5 +337,19 @@ static inline unsigned int sub(unsigned int a, unsigned int b) | |||
| 337 | return 0; | 337 | return 0; |
| 338 | } | 338 | } |
| 339 | 339 | ||
| 340 | #endif /* __SOUND_PCM_PARAMS_H */ | 340 | #define params_access(p) ((__force snd_pcm_access_t)\ |
| 341 | snd_mask_min(hw_param_mask_c((p), SNDRV_PCM_HW_PARAM_ACCESS))) | ||
| 342 | #define params_format(p) ((__force snd_pcm_format_t)\ | ||
| 343 | snd_mask_min(hw_param_mask_c((p), SNDRV_PCM_HW_PARAM_FORMAT))) | ||
| 344 | #define params_subformat(p) \ | ||
| 345 | snd_mask_min(hw_param_mask_c((p), SNDRV_PCM_HW_PARAM_SUBFORMAT)) | ||
| 341 | 346 | ||
| 347 | static inline unsigned int | ||
| 348 | params_period_bytes(const struct snd_pcm_hw_params *p) | ||
| 349 | { | ||
| 350 | return (params_period_size(p) * | ||
| 351 | snd_pcm_format_physical_width(params_format(p)) * | ||
| 352 | params_channels(p)) / 8; | ||
| 353 | } | ||
| 354 | |||
| 355 | #endif /* __SOUND_PCM_PARAMS_H */ | ||
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index e09505c5a490..e0583b7769cb 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h | |||
| @@ -266,6 +266,12 @@ | |||
| 266 | .get = snd_soc_dapm_get_enum_virt, \ | 266 | .get = snd_soc_dapm_get_enum_virt, \ |
| 267 | .put = snd_soc_dapm_put_enum_virt, \ | 267 | .put = snd_soc_dapm_put_enum_virt, \ |
| 268 | .private_value = (unsigned long)&xenum } | 268 | .private_value = (unsigned long)&xenum } |
| 269 | #define SOC_DAPM_ENUM_EXT(xname, xenum, xget, xput) \ | ||
| 270 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
| 271 | .info = snd_soc_info_enum_double, \ | ||
| 272 | .get = xget, \ | ||
| 273 | .put = xput, \ | ||
| 274 | .private_value = (unsigned long)&xenum } | ||
| 269 | #define SOC_DAPM_VALUE_ENUM(xname, xenum) \ | 275 | #define SOC_DAPM_VALUE_ENUM(xname, xenum) \ |
| 270 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 276 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
| 271 | .info = snd_soc_info_enum_double, \ | 277 | .info = snd_soc_info_enum_double, \ |
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index f1341308beda..86d0caf91b35 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c | |||
| @@ -128,7 +128,8 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram | |||
| 128 | } | 128 | } |
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | static void pcm_debug_name(struct snd_pcm_substream *substream, | 131 | #ifdef CONFIG_SND_DEBUG |
| 132 | void snd_pcm_debug_name(struct snd_pcm_substream *substream, | ||
| 132 | char *name, size_t len) | 133 | char *name, size_t len) |
| 133 | { | 134 | { |
| 134 | snprintf(name, len, "pcmC%dD%d%c:%d", | 135 | snprintf(name, len, "pcmC%dD%d%c:%d", |
| @@ -137,6 +138,8 @@ static void pcm_debug_name(struct snd_pcm_substream *substream, | |||
| 137 | substream->stream ? 'c' : 'p', | 138 | substream->stream ? 'c' : 'p', |
| 138 | substream->number); | 139 | substream->number); |
| 139 | } | 140 | } |
| 141 | EXPORT_SYMBOL(snd_pcm_debug_name); | ||
| 142 | #endif | ||
| 140 | 143 | ||
| 141 | #define XRUN_DEBUG_BASIC (1<<0) | 144 | #define XRUN_DEBUG_BASIC (1<<0) |
| 142 | #define XRUN_DEBUG_STACK (1<<1) /* dump also stack */ | 145 | #define XRUN_DEBUG_STACK (1<<1) /* dump also stack */ |
| @@ -168,7 +171,7 @@ static void xrun(struct snd_pcm_substream *substream) | |||
| 168 | snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); | 171 | snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); |
| 169 | if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { | 172 | if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { |
| 170 | char name[16]; | 173 | char name[16]; |
| 171 | pcm_debug_name(substream, name, sizeof(name)); | 174 | snd_pcm_debug_name(substream, name, sizeof(name)); |
| 172 | snd_printd(KERN_DEBUG "XRUN: %s\n", name); | 175 | snd_printd(KERN_DEBUG "XRUN: %s\n", name); |
| 173 | dump_stack_on_xrun(substream); | 176 | dump_stack_on_xrun(substream); |
| 174 | } | 177 | } |
| @@ -243,7 +246,7 @@ static void xrun_log_show(struct snd_pcm_substream *substream) | |||
| 243 | return; | 246 | return; |
| 244 | if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit) | 247 | if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit) |
| 245 | return; | 248 | return; |
| 246 | pcm_debug_name(substream, name, sizeof(name)); | 249 | snd_pcm_debug_name(substream, name, sizeof(name)); |
| 247 | for (cnt = 0, idx = log->idx; cnt < XRUN_LOG_CNT; cnt++) { | 250 | for (cnt = 0, idx = log->idx; cnt < XRUN_LOG_CNT; cnt++) { |
| 248 | entry = &log->entries[idx]; | 251 | entry = &log->entries[idx]; |
| 249 | if (entry->period_size == 0) | 252 | if (entry->period_size == 0) |
| @@ -319,7 +322,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, | |||
| 319 | if (pos >= runtime->buffer_size) { | 322 | if (pos >= runtime->buffer_size) { |
| 320 | if (printk_ratelimit()) { | 323 | if (printk_ratelimit()) { |
| 321 | char name[16]; | 324 | char name[16]; |
| 322 | pcm_debug_name(substream, name, sizeof(name)); | 325 | snd_pcm_debug_name(substream, name, sizeof(name)); |
| 323 | xrun_log_show(substream); | 326 | xrun_log_show(substream); |
| 324 | snd_printd(KERN_ERR "BUG: %s, pos = %ld, " | 327 | snd_printd(KERN_ERR "BUG: %s, pos = %ld, " |
| 325 | "buffer size = %ld, period size = %ld\n", | 328 | "buffer size = %ld, period size = %ld\n", |
| @@ -364,7 +367,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, | |||
| 364 | if (xrun_debug(substream, in_interrupt ? | 367 | if (xrun_debug(substream, in_interrupt ? |
| 365 | XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) { | 368 | XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) { |
| 366 | char name[16]; | 369 | char name[16]; |
| 367 | pcm_debug_name(substream, name, sizeof(name)); | 370 | snd_pcm_debug_name(substream, name, sizeof(name)); |
| 368 | snd_printd("%s_update: %s: pos=%u/%u/%u, " | 371 | snd_printd("%s_update: %s: pos=%u/%u/%u, " |
| 369 | "hwptr=%ld/%ld/%ld/%ld\n", | 372 | "hwptr=%ld/%ld/%ld/%ld\n", |
| 370 | in_interrupt ? "period" : "hwptr", | 373 | in_interrupt ? "period" : "hwptr", |
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index b941d2541dda..eae62ebbd295 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c | |||
| @@ -41,31 +41,10 @@ | |||
| 41 | #include <sound/tlv.h> | 41 | #include <sound/tlv.h> |
| 42 | #include <sound/hwdep.h> | 42 | #include <sound/hwdep.h> |
| 43 | 43 | ||
| 44 | |||
| 45 | MODULE_LICENSE("GPL"); | 44 | MODULE_LICENSE("GPL"); |
| 46 | MODULE_AUTHOR("AudioScience inc. <support@audioscience.com>"); | 45 | MODULE_AUTHOR("AudioScience inc. <support@audioscience.com>"); |
| 47 | MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx"); | 46 | MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx"); |
| 48 | 47 | ||
| 49 | #if defined CONFIG_SND_DEBUG | ||
| 50 | /* copied from pcm_lib.c, hope later patch will make that version public | ||
| 51 | and this copy can be removed */ | ||
| 52 | static inline void | ||
| 53 | snd_pcm_debug_name(struct snd_pcm_substream *substream, char *buf, size_t size) | ||
| 54 | { | ||
| 55 | snprintf(buf, size, "pcmC%dD%d%c:%d", | ||
| 56 | substream->pcm->card->number, | ||
| 57 | substream->pcm->device, | ||
| 58 | substream->stream ? 'c' : 'p', | ||
| 59 | substream->number); | ||
| 60 | } | ||
| 61 | #else | ||
| 62 | static inline void | ||
| 63 | snd_pcm_debug_name(struct snd_pcm_substream *substream, char *buf, size_t size) | ||
| 64 | { | ||
| 65 | *buf = 0; | ||
| 66 | } | ||
| 67 | #endif | ||
| 68 | |||
| 69 | #if defined CONFIG_SND_DEBUG_VERBOSE | 48 | #if defined CONFIG_SND_DEBUG_VERBOSE |
| 70 | /** | 49 | /** |
| 71 | * snd_printddd - very verbose debug printk | 50 | * snd_printddd - very verbose debug printk |
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 7489b4608551..bb7e102d6726 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig | |||
| @@ -243,6 +243,7 @@ config SND_HDA_GENERIC | |||
| 243 | 243 | ||
| 244 | config SND_HDA_POWER_SAVE | 244 | config SND_HDA_POWER_SAVE |
| 245 | bool "Aggressive power-saving on HD-audio" | 245 | bool "Aggressive power-saving on HD-audio" |
| 246 | depends on PM | ||
| 246 | help | 247 | help |
| 247 | Say Y here to enable more aggressive power-saving mode on | 248 | Say Y here to enable more aggressive power-saving mode on |
| 248 | HD-audio driver. The power-saving timeout can be configured | 249 | HD-audio driver. The power-saving timeout can be configured |
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 9c27a3a4c4d5..3e7850c238c3 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
| @@ -91,8 +91,10 @@ EXPORT_SYMBOL_HDA(snd_hda_delete_codec_preset); | |||
| 91 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 91 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
| 92 | static void hda_power_work(struct work_struct *work); | 92 | static void hda_power_work(struct work_struct *work); |
| 93 | static void hda_keep_power_on(struct hda_codec *codec); | 93 | static void hda_keep_power_on(struct hda_codec *codec); |
| 94 | #define hda_codec_is_power_on(codec) ((codec)->power_on) | ||
| 94 | #else | 95 | #else |
| 95 | static inline void hda_keep_power_on(struct hda_codec *codec) {} | 96 | static inline void hda_keep_power_on(struct hda_codec *codec) {} |
| 97 | #define hda_codec_is_power_on(codec) 1 | ||
| 96 | #endif | 98 | #endif |
| 97 | 99 | ||
| 98 | /** | 100 | /** |
| @@ -1101,7 +1103,7 @@ void snd_hda_shutup_pins(struct hda_codec *codec) | |||
| 1101 | } | 1103 | } |
| 1102 | EXPORT_SYMBOL_HDA(snd_hda_shutup_pins); | 1104 | EXPORT_SYMBOL_HDA(snd_hda_shutup_pins); |
| 1103 | 1105 | ||
| 1104 | #ifdef SND_HDA_NEEDS_RESUME | 1106 | #ifdef CONFIG_PM |
| 1105 | /* Restore the pin controls cleared previously via snd_hda_shutup_pins() */ | 1107 | /* Restore the pin controls cleared previously via snd_hda_shutup_pins() */ |
| 1106 | static void restore_shutup_pins(struct hda_codec *codec) | 1108 | static void restore_shutup_pins(struct hda_codec *codec) |
| 1107 | { | 1109 | { |
| @@ -1499,7 +1501,7 @@ static void purify_inactive_streams(struct hda_codec *codec) | |||
| 1499 | } | 1501 | } |
| 1500 | } | 1502 | } |
| 1501 | 1503 | ||
| 1502 | #ifdef SND_HDA_NEEDS_RESUME | 1504 | #ifdef CONFIG_PM |
| 1503 | /* clean up all streams; called from suspend */ | 1505 | /* clean up all streams; called from suspend */ |
| 1504 | static void hda_cleanup_all_streams(struct hda_codec *codec) | 1506 | static void hda_cleanup_all_streams(struct hda_codec *codec) |
| 1505 | { | 1507 | { |
| @@ -1838,7 +1840,7 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, | |||
| 1838 | } | 1840 | } |
| 1839 | EXPORT_SYMBOL_HDA(snd_hda_codec_amp_stereo); | 1841 | EXPORT_SYMBOL_HDA(snd_hda_codec_amp_stereo); |
| 1840 | 1842 | ||
| 1841 | #ifdef SND_HDA_NEEDS_RESUME | 1843 | #ifdef CONFIG_PM |
| 1842 | /** | 1844 | /** |
| 1843 | * snd_hda_codec_resume_amp - Resume all AMP commands from the cache | 1845 | * snd_hda_codec_resume_amp - Resume all AMP commands from the cache |
| 1844 | * @codec: HD-audio codec | 1846 | * @codec: HD-audio codec |
| @@ -1868,7 +1870,7 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec) | |||
| 1868 | } | 1870 | } |
| 1869 | } | 1871 | } |
| 1870 | EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp); | 1872 | EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp); |
| 1871 | #endif /* SND_HDA_NEEDS_RESUME */ | 1873 | #endif /* CONFIG_PM */ |
| 1872 | 1874 | ||
| 1873 | static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir, | 1875 | static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir, |
| 1874 | unsigned int ofs) | 1876 | unsigned int ofs) |
| @@ -3082,7 +3084,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) | |||
| 3082 | } | 3084 | } |
| 3083 | EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls); | 3085 | EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls); |
| 3084 | 3086 | ||
| 3085 | #ifdef SND_HDA_NEEDS_RESUME | 3087 | #ifdef CONFIG_PM |
| 3086 | /* | 3088 | /* |
| 3087 | * command cache | 3089 | * command cache |
| 3088 | */ | 3090 | */ |
| @@ -3199,53 +3201,32 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec, | |||
| 3199 | seq->param); | 3201 | seq->param); |
| 3200 | } | 3202 | } |
| 3201 | EXPORT_SYMBOL_HDA(snd_hda_sequence_write_cache); | 3203 | EXPORT_SYMBOL_HDA(snd_hda_sequence_write_cache); |
| 3202 | #endif /* SND_HDA_NEEDS_RESUME */ | 3204 | #endif /* CONFIG_PM */ |
| 3203 | 3205 | ||
| 3204 | /* | 3206 | void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg, |
| 3205 | * set power state of the codec | 3207 | unsigned int power_state, |
| 3206 | */ | 3208 | bool eapd_workaround) |
| 3207 | static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, | ||
| 3208 | unsigned int power_state) | ||
| 3209 | { | 3209 | { |
| 3210 | hda_nid_t nid; | 3210 | hda_nid_t nid = codec->start_nid; |
| 3211 | int i; | 3211 | int i; |
| 3212 | 3212 | ||
| 3213 | /* this delay seems necessary to avoid click noise at power-down */ | ||
| 3214 | if (power_state == AC_PWRST_D3) | ||
| 3215 | msleep(100); | ||
| 3216 | snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, | ||
| 3217 | power_state); | ||
| 3218 | /* partial workaround for "azx_get_response timeout" */ | ||
| 3219 | if (power_state == AC_PWRST_D0 && | ||
| 3220 | (codec->vendor_id & 0xffff0000) == 0x14f10000) | ||
| 3221 | msleep(10); | ||
| 3222 | |||
| 3223 | nid = codec->start_nid; | ||
| 3224 | for (i = 0; i < codec->num_nodes; i++, nid++) { | 3213 | for (i = 0; i < codec->num_nodes; i++, nid++) { |
| 3225 | unsigned int wcaps = get_wcaps(codec, nid); | 3214 | unsigned int wcaps = get_wcaps(codec, nid); |
| 3226 | if (wcaps & AC_WCAP_POWER) { | 3215 | if (!(wcaps & AC_WCAP_POWER)) |
| 3227 | unsigned int wid_type = get_wcaps_type(wcaps); | 3216 | continue; |
| 3228 | if (power_state == AC_PWRST_D3 && | 3217 | /* don't power down the widget if it controls eapd and |
| 3229 | wid_type == AC_WID_PIN) { | 3218 | * EAPD_BTLENABLE is set. |
| 3230 | unsigned int pincap; | 3219 | */ |
| 3231 | /* | 3220 | if (eapd_workaround && power_state == AC_PWRST_D3 && |
| 3232 | * don't power down the widget if it controls | 3221 | get_wcaps_type(wcaps) == AC_WID_PIN && |
| 3233 | * eapd and EAPD_BTLENABLE is set. | 3222 | (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) { |
| 3234 | */ | 3223 | int eapd = snd_hda_codec_read(codec, nid, 0, |
| 3235 | pincap = snd_hda_query_pin_caps(codec, nid); | ||
| 3236 | if (pincap & AC_PINCAP_EAPD) { | ||
| 3237 | int eapd = snd_hda_codec_read(codec, | ||
| 3238 | nid, 0, | ||
| 3239 | AC_VERB_GET_EAPD_BTLENABLE, 0); | 3224 | AC_VERB_GET_EAPD_BTLENABLE, 0); |
| 3240 | eapd &= 0x02; | 3225 | if (eapd & 0x02) |
| 3241 | if (eapd) | 3226 | continue; |
| 3242 | continue; | ||
| 3243 | } | ||
| 3244 | } | ||
| 3245 | snd_hda_codec_write(codec, nid, 0, | ||
| 3246 | AC_VERB_SET_POWER_STATE, | ||
| 3247 | power_state); | ||
| 3248 | } | 3227 | } |
| 3228 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, | ||
| 3229 | power_state); | ||
| 3249 | } | 3230 | } |
| 3250 | 3231 | ||
| 3251 | if (power_state == AC_PWRST_D0) { | 3232 | if (power_state == AC_PWRST_D0) { |
| @@ -3262,6 +3243,26 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, | |||
| 3262 | } while (time_after_eq(end_time, jiffies)); | 3243 | } while (time_after_eq(end_time, jiffies)); |
| 3263 | } | 3244 | } |
| 3264 | } | 3245 | } |
| 3246 | EXPORT_SYMBOL_HDA(snd_hda_codec_set_power_to_all); | ||
| 3247 | |||
| 3248 | /* | ||
| 3249 | * set power state of the codec | ||
| 3250 | */ | ||
| 3251 | static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, | ||
| 3252 | unsigned int power_state) | ||
| 3253 | { | ||
| 3254 | if (codec->patch_ops.set_power_state) { | ||
| 3255 | codec->patch_ops.set_power_state(codec, fg, power_state); | ||
| 3256 | return; | ||
| 3257 | } | ||
| 3258 | |||
| 3259 | /* this delay seems necessary to avoid click noise at power-down */ | ||
| 3260 | if (power_state == AC_PWRST_D3) | ||
| 3261 | msleep(100); | ||
| 3262 | snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, | ||
| 3263 | power_state); | ||
| 3264 | snd_hda_codec_set_power_to_all(codec, fg, power_state, true); | ||
| 3265 | } | ||
| 3265 | 3266 | ||
| 3266 | #ifdef CONFIG_SND_HDA_HWDEP | 3267 | #ifdef CONFIG_SND_HDA_HWDEP |
| 3267 | /* execute additional init verbs */ | 3268 | /* execute additional init verbs */ |
| @@ -3274,7 +3275,7 @@ static void hda_exec_init_verbs(struct hda_codec *codec) | |||
| 3274 | static inline void hda_exec_init_verbs(struct hda_codec *codec) {} | 3275 | static inline void hda_exec_init_verbs(struct hda_codec *codec) {} |
| 3275 | #endif | 3276 | #endif |
| 3276 | 3277 | ||
| 3277 | #ifdef SND_HDA_NEEDS_RESUME | 3278 | #ifdef CONFIG_PM |
| 3278 | /* | 3279 | /* |
| 3279 | * call suspend and power-down; used both from PM and power-save | 3280 | * call suspend and power-down; used both from PM and power-save |
| 3280 | */ | 3281 | */ |
| @@ -3315,7 +3316,7 @@ static void hda_call_codec_resume(struct hda_codec *codec) | |||
| 3315 | snd_hda_codec_resume_cache(codec); | 3316 | snd_hda_codec_resume_cache(codec); |
| 3316 | } | 3317 | } |
| 3317 | } | 3318 | } |
| 3318 | #endif /* SND_HDA_NEEDS_RESUME */ | 3319 | #endif /* CONFIG_PM */ |
| 3319 | 3320 | ||
| 3320 | 3321 | ||
| 3321 | /** | 3322 | /** |
| @@ -4071,9 +4072,6 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, | |||
| 4071 | EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls); | 4072 | EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls); |
| 4072 | 4073 | ||
| 4073 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 4074 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
| 4074 | static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, | ||
| 4075 | unsigned int power_state); | ||
| 4076 | |||
| 4077 | static void hda_power_work(struct work_struct *work) | 4075 | static void hda_power_work(struct work_struct *work) |
| 4078 | { | 4076 | { |
| 4079 | struct hda_codec *codec = | 4077 | struct hda_codec *codec = |
| @@ -4376,11 +4374,8 @@ void snd_hda_bus_reboot_notify(struct hda_bus *bus) | |||
| 4376 | if (!bus) | 4374 | if (!bus) |
| 4377 | return; | 4375 | return; |
| 4378 | list_for_each_entry(codec, &bus->codec_list, list) { | 4376 | list_for_each_entry(codec, &bus->codec_list, list) { |
| 4379 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 4377 | if (hda_codec_is_power_on(codec) && |
| 4380 | if (!codec->power_on) | 4378 | codec->patch_ops.reboot_notify) |
| 4381 | continue; | ||
| 4382 | #endif | ||
| 4383 | if (codec->patch_ops.reboot_notify) | ||
| 4384 | codec->patch_ops.reboot_notify(codec); | 4379 | codec->patch_ops.reboot_notify(codec); |
| 4385 | } | 4380 | } |
| 4386 | } | 4381 | } |
| @@ -5079,11 +5074,10 @@ int snd_hda_suspend(struct hda_bus *bus) | |||
| 5079 | struct hda_codec *codec; | 5074 | struct hda_codec *codec; |
| 5080 | 5075 | ||
| 5081 | list_for_each_entry(codec, &bus->codec_list, list) { | 5076 | list_for_each_entry(codec, &bus->codec_list, list) { |
| 5082 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 5077 | if (hda_codec_is_power_on(codec)) |
| 5083 | if (!codec->power_on) | 5078 | hda_call_codec_suspend(codec); |
| 5084 | continue; | 5079 | if (codec->patch_ops.post_suspend) |
| 5085 | #endif | 5080 | codec->patch_ops.post_suspend(codec); |
| 5086 | hda_call_codec_suspend(codec); | ||
| 5087 | } | 5081 | } |
| 5088 | return 0; | 5082 | return 0; |
| 5089 | } | 5083 | } |
| @@ -5103,6 +5097,8 @@ int snd_hda_resume(struct hda_bus *bus) | |||
| 5103 | struct hda_codec *codec; | 5097 | struct hda_codec *codec; |
| 5104 | 5098 | ||
| 5105 | list_for_each_entry(codec, &bus->codec_list, list) { | 5099 | list_for_each_entry(codec, &bus->codec_list, list) { |
| 5100 | if (codec->patch_ops.pre_resume) | ||
| 5101 | codec->patch_ops.pre_resume(codec); | ||
| 5106 | if (snd_hda_codec_needs_resume(codec)) | 5102 | if (snd_hda_codec_needs_resume(codec)) |
| 5107 | hda_call_codec_resume(codec); | 5103 | hda_call_codec_resume(codec); |
| 5108 | } | 5104 | } |
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index f465e07a4879..755f2b0f9d8e 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h | |||
| @@ -26,10 +26,6 @@ | |||
| 26 | #include <sound/pcm.h> | 26 | #include <sound/pcm.h> |
| 27 | #include <sound/hwdep.h> | 27 | #include <sound/hwdep.h> |
| 28 | 28 | ||
| 29 | #if defined(CONFIG_PM) || defined(CONFIG_SND_HDA_POWER_SAVE) | ||
| 30 | #define SND_HDA_NEEDS_RESUME /* resume control code is required */ | ||
| 31 | #endif | ||
| 32 | |||
| 33 | /* | 29 | /* |
| 34 | * nodes | 30 | * nodes |
| 35 | */ | 31 | */ |
| @@ -704,8 +700,12 @@ struct hda_codec_ops { | |||
| 704 | int (*init)(struct hda_codec *codec); | 700 | int (*init)(struct hda_codec *codec); |
| 705 | void (*free)(struct hda_codec *codec); | 701 | void (*free)(struct hda_codec *codec); |
| 706 | void (*unsol_event)(struct hda_codec *codec, unsigned int res); | 702 | void (*unsol_event)(struct hda_codec *codec, unsigned int res); |
| 707 | #ifdef SND_HDA_NEEDS_RESUME | 703 | void (*set_power_state)(struct hda_codec *codec, hda_nid_t fg, |
| 704 | unsigned int power_state); | ||
| 705 | #ifdef CONFIG_PM | ||
| 708 | int (*suspend)(struct hda_codec *codec, pm_message_t state); | 706 | int (*suspend)(struct hda_codec *codec, pm_message_t state); |
| 707 | int (*post_suspend)(struct hda_codec *codec); | ||
| 708 | int (*pre_resume)(struct hda_codec *codec); | ||
| 709 | int (*resume)(struct hda_codec *codec); | 709 | int (*resume)(struct hda_codec *codec); |
| 710 | #endif | 710 | #endif |
| 711 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 711 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
| @@ -927,7 +927,7 @@ void snd_hda_sequence_write(struct hda_codec *codec, | |||
| 927 | int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex); | 927 | int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex); |
| 928 | 928 | ||
| 929 | /* cached write */ | 929 | /* cached write */ |
| 930 | #ifdef SND_HDA_NEEDS_RESUME | 930 | #ifdef CONFIG_PM |
| 931 | int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, | 931 | int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, |
| 932 | int direct, unsigned int verb, unsigned int parm); | 932 | int direct, unsigned int verb, unsigned int parm); |
| 933 | void snd_hda_sequence_write_cache(struct hda_codec *codec, | 933 | void snd_hda_sequence_write_cache(struct hda_codec *codec, |
| @@ -1008,6 +1008,9 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, | |||
| 1008 | */ | 1008 | */ |
| 1009 | void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen); | 1009 | void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen); |
| 1010 | void snd_hda_bus_reboot_notify(struct hda_bus *bus); | 1010 | void snd_hda_bus_reboot_notify(struct hda_bus *bus); |
| 1011 | void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg, | ||
| 1012 | unsigned int power_state, | ||
| 1013 | bool eapd_workaround); | ||
| 1011 | 1014 | ||
| 1012 | /* | 1015 | /* |
| 1013 | * power management | 1016 | * power management |
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 88b277e97409..2e7ac31afa8d 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h | |||
| @@ -131,7 +131,7 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, | |||
| 131 | int direction, int idx, int mask, int val); | 131 | int direction, int idx, int mask, int val); |
| 132 | int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, | 132 | int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, |
| 133 | int dir, int idx, int mask, int val); | 133 | int dir, int idx, int mask, int val); |
| 134 | #ifdef SND_HDA_NEEDS_RESUME | 134 | #ifdef CONFIG_PM |
| 135 | void snd_hda_codec_resume_amp(struct hda_codec *codec); | 135 | void snd_hda_codec_resume_amp(struct hda_codec *codec); |
| 136 | #endif | 136 | #endif |
| 137 | 137 | ||
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 1362c8ba4d1f..8648917acffb 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
| @@ -563,7 +563,7 @@ static void ad198x_free(struct hda_codec *codec) | |||
| 563 | snd_hda_detach_beep_device(codec); | 563 | snd_hda_detach_beep_device(codec); |
| 564 | } | 564 | } |
| 565 | 565 | ||
| 566 | #ifdef SND_HDA_NEEDS_RESUME | 566 | #ifdef CONFIG_PM |
| 567 | static int ad198x_suspend(struct hda_codec *codec, pm_message_t state) | 567 | static int ad198x_suspend(struct hda_codec *codec, pm_message_t state) |
| 568 | { | 568 | { |
| 569 | ad198x_shutup(codec); | 569 | ad198x_shutup(codec); |
| @@ -579,7 +579,7 @@ static const struct hda_codec_ops ad198x_patch_ops = { | |||
| 579 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 579 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
| 580 | .check_power_status = ad198x_check_power_status, | 580 | .check_power_status = ad198x_check_power_status, |
| 581 | #endif | 581 | #endif |
| 582 | #ifdef SND_HDA_NEEDS_RESUME | 582 | #ifdef CONFIG_PM |
| 583 | .suspend = ad198x_suspend, | 583 | .suspend = ad198x_suspend, |
| 584 | #endif | 584 | #endif |
| 585 | .reboot_notify = ad198x_shutup, | 585 | .reboot_notify = ad198x_shutup, |
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 7f93739b1e33..47d6ffc9b5b5 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <sound/core.h> | 25 | #include <sound/core.h> |
| 26 | #include "hda_codec.h" | 26 | #include "hda_codec.h" |
| 27 | #include "hda_local.h" | 27 | #include "hda_local.h" |
| 28 | #include <sound/tlv.h> | ||
| 28 | 29 | ||
| 29 | /* | 30 | /* |
| 30 | */ | 31 | */ |
| @@ -61,9 +62,15 @@ struct cs_spec { | |||
| 61 | 62 | ||
| 62 | unsigned int hp_detect:1; | 63 | unsigned int hp_detect:1; |
| 63 | unsigned int mic_detect:1; | 64 | unsigned int mic_detect:1; |
| 65 | /* CS421x */ | ||
| 66 | unsigned int spdif_detect:1; | ||
| 67 | unsigned int sense_b:1; | ||
| 68 | hda_nid_t vendor_nid; | ||
| 69 | struct hda_input_mux input_mux; | ||
| 70 | unsigned int last_input; | ||
| 64 | }; | 71 | }; |
| 65 | 72 | ||
| 66 | /* available models */ | 73 | /* available models with CS420x */ |
| 67 | enum { | 74 | enum { |
| 68 | CS420X_MBP53, | 75 | CS420X_MBP53, |
| 69 | CS420X_MBP55, | 76 | CS420X_MBP55, |
| @@ -72,6 +79,12 @@ enum { | |||
| 72 | CS420X_MODELS | 79 | CS420X_MODELS |
| 73 | }; | 80 | }; |
| 74 | 81 | ||
| 82 | /* CS421x boards */ | ||
| 83 | enum { | ||
| 84 | CS421X_CDB4210, | ||
| 85 | CS421X_MODELS | ||
| 86 | }; | ||
| 87 | |||
| 75 | /* Vendor-specific processing widget */ | 88 | /* Vendor-specific processing widget */ |
| 76 | #define CS420X_VENDOR_NID 0x11 | 89 | #define CS420X_VENDOR_NID 0x11 |
| 77 | #define CS_DIG_OUT1_PIN_NID 0x10 | 90 | #define CS_DIG_OUT1_PIN_NID 0x10 |
| @@ -111,21 +124,42 @@ enum { | |||
| 111 | /* 0x0009 - 0x0014 -> 12 test regs */ | 124 | /* 0x0009 - 0x0014 -> 12 test regs */ |
| 112 | /* 0x0015 - visibility reg */ | 125 | /* 0x0015 - visibility reg */ |
| 113 | 126 | ||
| 127 | /* | ||
| 128 | * Cirrus Logic CS4210 | ||
| 129 | * | ||
| 130 | * 1 DAC => HP(sense) / Speakers, | ||
| 131 | * 1 ADC <= LineIn(sense) / MicIn / DMicIn, | ||
| 132 | * 1 SPDIF OUT => SPDIF Trasmitter(sense) | ||
| 133 | */ | ||
| 134 | #define CS4210_DAC_NID 0x02 | ||
| 135 | #define CS4210_ADC_NID 0x03 | ||
| 136 | #define CS421X_VENDOR_NID 0x0B | ||
| 137 | #define CS421X_DMIC_PIN_NID 0x09 /* Port E */ | ||
| 138 | #define CS421X_SPDIF_PIN_NID 0x0A /* Port H */ | ||
| 139 | |||
| 140 | #define CS421X_IDX_DEV_CFG 0x01 | ||
| 141 | #define CS421X_IDX_ADC_CFG 0x02 | ||
| 142 | #define CS421X_IDX_DAC_CFG 0x03 | ||
| 143 | #define CS421X_IDX_SPK_CTL 0x04 | ||
| 144 | |||
| 145 | #define SPDIF_EVENT 0x04 | ||
| 114 | 146 | ||
| 115 | static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx) | 147 | static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx) |
| 116 | { | 148 | { |
| 117 | snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0, | 149 | struct cs_spec *spec = codec->spec; |
| 150 | snd_hda_codec_write(codec, spec->vendor_nid, 0, | ||
| 118 | AC_VERB_SET_COEF_INDEX, idx); | 151 | AC_VERB_SET_COEF_INDEX, idx); |
| 119 | return snd_hda_codec_read(codec, CS420X_VENDOR_NID, 0, | 152 | return snd_hda_codec_read(codec, spec->vendor_nid, 0, |
| 120 | AC_VERB_GET_PROC_COEF, 0); | 153 | AC_VERB_GET_PROC_COEF, 0); |
| 121 | } | 154 | } |
| 122 | 155 | ||
| 123 | static inline void cs_vendor_coef_set(struct hda_codec *codec, unsigned int idx, | 156 | static inline void cs_vendor_coef_set(struct hda_codec *codec, unsigned int idx, |
| 124 | unsigned int coef) | 157 | unsigned int coef) |
| 125 | { | 158 | { |
| 126 | snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0, | 159 | struct cs_spec *spec = codec->spec; |
| 160 | snd_hda_codec_write(codec, spec->vendor_nid, 0, | ||
| 127 | AC_VERB_SET_COEF_INDEX, idx); | 161 | AC_VERB_SET_COEF_INDEX, idx); |
| 128 | snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0, | 162 | snd_hda_codec_write(codec, spec->vendor_nid, 0, |
| 129 | AC_VERB_SET_PROC_COEF, coef); | 163 | AC_VERB_SET_PROC_COEF, coef); |
| 130 | } | 164 | } |
| 131 | 165 | ||
| @@ -347,15 +381,12 @@ static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin, | |||
| 347 | nid = codec->start_nid; | 381 | nid = codec->start_nid; |
| 348 | for (i = 0; i < codec->num_nodes; i++, nid++) { | 382 | for (i = 0; i < codec->num_nodes; i++, nid++) { |
| 349 | unsigned int type; | 383 | unsigned int type; |
| 350 | int idx; | ||
| 351 | type = get_wcaps_type(get_wcaps(codec, nid)); | 384 | type = get_wcaps_type(get_wcaps(codec, nid)); |
| 352 | if (type != AC_WID_AUD_IN) | 385 | if (type != AC_WID_AUD_IN) |
| 353 | continue; | 386 | continue; |
| 354 | idx = snd_hda_get_conn_index(codec, nid, pin, 0); | 387 | *idxp = snd_hda_get_conn_index(codec, nid, pin, false); |
| 355 | if (idx >= 0) { | 388 | if (*idxp >= 0) |
| 356 | *idxp = idx; | ||
| 357 | return nid; | 389 | return nid; |
| 358 | } | ||
| 359 | } | 390 | } |
| 360 | return 0; | 391 | return 0; |
| 361 | } | 392 | } |
| @@ -835,6 +866,8 @@ static int build_digital_input(struct hda_codec *codec) | |||
| 835 | 866 | ||
| 836 | /* | 867 | /* |
| 837 | * auto-mute and auto-mic switching | 868 | * auto-mute and auto-mic switching |
| 869 | * CS421x auto-output redirecting | ||
| 870 | * HP/SPK/SPDIF | ||
| 838 | */ | 871 | */ |
| 839 | 872 | ||
| 840 | static void cs_automute(struct hda_codec *codec) | 873 | static void cs_automute(struct hda_codec *codec) |
| @@ -842,9 +875,25 @@ static void cs_automute(struct hda_codec *codec) | |||
| 842 | struct cs_spec *spec = codec->spec; | 875 | struct cs_spec *spec = codec->spec; |
| 843 | struct auto_pin_cfg *cfg = &spec->autocfg; | 876 | struct auto_pin_cfg *cfg = &spec->autocfg; |
| 844 | unsigned int hp_present; | 877 | unsigned int hp_present; |
| 878 | unsigned int spdif_present; | ||
| 845 | hda_nid_t nid; | 879 | hda_nid_t nid; |
| 846 | int i; | 880 | int i; |
| 847 | 881 | ||
| 882 | spdif_present = 0; | ||
| 883 | if (cfg->dig_outs) { | ||
| 884 | nid = cfg->dig_out_pins[0]; | ||
| 885 | if (is_jack_detectable(codec, nid)) { | ||
| 886 | /* | ||
| 887 | TODO: SPDIF output redirect when SENSE_B is enabled. | ||
| 888 | Shared (SENSE_A) jack (e.g HP/mini-TOSLINK) | ||
| 889 | assumed. | ||
| 890 | */ | ||
| 891 | if (snd_hda_jack_detect(codec, nid) | ||
| 892 | /* && spec->sense_b */) | ||
| 893 | spdif_present = 1; | ||
| 894 | } | ||
| 895 | } | ||
| 896 | |||
| 848 | hp_present = 0; | 897 | hp_present = 0; |
| 849 | for (i = 0; i < cfg->hp_outs; i++) { | 898 | for (i = 0; i < cfg->hp_outs; i++) { |
| 850 | nid = cfg->hp_pins[i]; | 899 | nid = cfg->hp_pins[i]; |
| @@ -854,11 +903,19 @@ static void cs_automute(struct hda_codec *codec) | |||
| 854 | if (hp_present) | 903 | if (hp_present) |
| 855 | break; | 904 | break; |
| 856 | } | 905 | } |
| 906 | |||
| 907 | /* mute speakers if spdif or hp jack is plugged in */ | ||
| 857 | for (i = 0; i < cfg->speaker_outs; i++) { | 908 | for (i = 0; i < cfg->speaker_outs; i++) { |
| 858 | nid = cfg->speaker_pins[i]; | 909 | nid = cfg->speaker_pins[i]; |
| 859 | snd_hda_codec_write(codec, nid, 0, | 910 | snd_hda_codec_write(codec, nid, 0, |
| 860 | AC_VERB_SET_PIN_WIDGET_CONTROL, | 911 | AC_VERB_SET_PIN_WIDGET_CONTROL, |
| 861 | hp_present ? 0 : PIN_OUT); | 912 | hp_present ? 0 : PIN_OUT); |
| 913 | /* detect on spdif is specific to CS421x */ | ||
| 914 | if (spec->vendor_nid == CS421X_VENDOR_NID) { | ||
| 915 | snd_hda_codec_write(codec, nid, 0, | ||
| 916 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
| 917 | spdif_present ? 0 : PIN_OUT); | ||
| 918 | } | ||
| 862 | } | 919 | } |
| 863 | if (spec->board_config == CS420X_MBP53 || | 920 | if (spec->board_config == CS420X_MBP53 || |
| 864 | spec->board_config == CS420X_MBP55 || | 921 | spec->board_config == CS420X_MBP55 || |
| @@ -867,21 +924,62 @@ static void cs_automute(struct hda_codec *codec) | |||
| 867 | snd_hda_codec_write(codec, 0x01, 0, | 924 | snd_hda_codec_write(codec, 0x01, 0, |
| 868 | AC_VERB_SET_GPIO_DATA, gpio); | 925 | AC_VERB_SET_GPIO_DATA, gpio); |
| 869 | } | 926 | } |
| 927 | |||
| 928 | /* specific to CS421x */ | ||
| 929 | if (spec->vendor_nid == CS421X_VENDOR_NID) { | ||
| 930 | /* mute HPs if spdif jack (SENSE_B) is present */ | ||
| 931 | for (i = 0; i < cfg->hp_outs; i++) { | ||
| 932 | nid = cfg->hp_pins[i]; | ||
| 933 | snd_hda_codec_write(codec, nid, 0, | ||
| 934 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
| 935 | (spdif_present && spec->sense_b) ? 0 : PIN_HP); | ||
| 936 | } | ||
| 937 | |||
| 938 | /* SPDIF TX on/off */ | ||
| 939 | if (cfg->dig_outs) { | ||
| 940 | nid = cfg->dig_out_pins[0]; | ||
| 941 | snd_hda_codec_write(codec, nid, 0, | ||
| 942 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
| 943 | spdif_present ? PIN_OUT : 0); | ||
| 944 | |||
| 945 | } | ||
| 946 | /* Update board GPIOs if neccessary ... */ | ||
| 947 | } | ||
| 870 | } | 948 | } |
| 871 | 949 | ||
| 950 | /* | ||
| 951 | * Auto-input redirect for CS421x | ||
| 952 | * Switch max 3 inputs of a single ADC (nid 3) | ||
| 953 | */ | ||
| 954 | |||
| 872 | static void cs_automic(struct hda_codec *codec) | 955 | static void cs_automic(struct hda_codec *codec) |
| 873 | { | 956 | { |
| 874 | struct cs_spec *spec = codec->spec; | 957 | struct cs_spec *spec = codec->spec; |
| 875 | struct auto_pin_cfg *cfg = &spec->autocfg; | 958 | struct auto_pin_cfg *cfg = &spec->autocfg; |
| 876 | hda_nid_t nid; | 959 | hda_nid_t nid; |
| 877 | unsigned int present; | 960 | unsigned int present; |
| 878 | 961 | ||
| 879 | nid = cfg->inputs[spec->automic_idx].pin; | 962 | nid = cfg->inputs[spec->automic_idx].pin; |
| 880 | present = snd_hda_jack_detect(codec, nid); | 963 | present = snd_hda_jack_detect(codec, nid); |
| 881 | if (present) | 964 | |
| 882 | change_cur_input(codec, spec->automic_idx, 0); | 965 | /* specific to CS421x, single ADC */ |
| 883 | else | 966 | if (spec->vendor_nid == CS421X_VENDOR_NID) { |
| 884 | change_cur_input(codec, !spec->automic_idx, 0); | 967 | if (present) { |
| 968 | spec->last_input = spec->cur_input; | ||
| 969 | spec->cur_input = spec->automic_idx; | ||
| 970 | } else { | ||
| 971 | spec->cur_input = spec->last_input; | ||
| 972 | } | ||
| 973 | |||
| 974 | snd_hda_codec_write_cache(codec, spec->cur_adc, 0, | ||
| 975 | AC_VERB_SET_CONNECT_SEL, | ||
| 976 | spec->adc_idx[spec->cur_input]); | ||
| 977 | } else { | ||
| 978 | if (present) | ||
| 979 | change_cur_input(codec, spec->automic_idx, 0); | ||
| 980 | else | ||
| 981 | change_cur_input(codec, !spec->automic_idx, 0); | ||
| 982 | } | ||
| 885 | } | 983 | } |
| 886 | 984 | ||
| 887 | /* | 985 | /* |
| @@ -911,23 +1009,28 @@ static void init_output(struct hda_codec *codec) | |||
| 911 | for (i = 0; i < cfg->line_outs; i++) | 1009 | for (i = 0; i < cfg->line_outs; i++) |
| 912 | snd_hda_codec_write(codec, cfg->line_out_pins[i], 0, | 1010 | snd_hda_codec_write(codec, cfg->line_out_pins[i], 0, |
| 913 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); | 1011 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); |
| 1012 | /* HP */ | ||
| 914 | for (i = 0; i < cfg->hp_outs; i++) { | 1013 | for (i = 0; i < cfg->hp_outs; i++) { |
| 915 | hda_nid_t nid = cfg->hp_pins[i]; | 1014 | hda_nid_t nid = cfg->hp_pins[i]; |
| 916 | snd_hda_codec_write(codec, nid, 0, | 1015 | snd_hda_codec_write(codec, nid, 0, |
| 917 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); | 1016 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); |
| 918 | if (!cfg->speaker_outs) | 1017 | if (!cfg->speaker_outs) |
| 919 | continue; | 1018 | continue; |
| 920 | if (is_jack_detectable(codec, nid)) { | 1019 | if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { |
| 921 | snd_hda_codec_write(codec, nid, 0, | 1020 | snd_hda_codec_write(codec, nid, 0, |
| 922 | AC_VERB_SET_UNSOLICITED_ENABLE, | 1021 | AC_VERB_SET_UNSOLICITED_ENABLE, |
| 923 | AC_USRSP_EN | HP_EVENT); | 1022 | AC_USRSP_EN | HP_EVENT); |
| 924 | spec->hp_detect = 1; | 1023 | spec->hp_detect = 1; |
| 925 | } | 1024 | } |
| 926 | } | 1025 | } |
| 1026 | |||
| 1027 | /* Speaker */ | ||
| 927 | for (i = 0; i < cfg->speaker_outs; i++) | 1028 | for (i = 0; i < cfg->speaker_outs; i++) |
| 928 | snd_hda_codec_write(codec, cfg->speaker_pins[i], 0, | 1029 | snd_hda_codec_write(codec, cfg->speaker_pins[i], 0, |
| 929 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); | 1030 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); |
| 930 | if (spec->hp_detect) | 1031 | |
| 1032 | /* SPDIF is enabled on presence detect for CS421x */ | ||
| 1033 | if (spec->hp_detect || spec->spdif_detect) | ||
| 931 | cs_automute(codec); | 1034 | cs_automute(codec); |
| 932 | } | 1035 | } |
| 933 | 1036 | ||
| @@ -961,19 +1064,31 @@ static void init_input(struct hda_codec *codec) | |||
| 961 | AC_VERB_SET_UNSOLICITED_ENABLE, | 1064 | AC_VERB_SET_UNSOLICITED_ENABLE, |
| 962 | AC_USRSP_EN | MIC_EVENT); | 1065 | AC_USRSP_EN | MIC_EVENT); |
| 963 | } | 1066 | } |
| 964 | change_cur_input(codec, spec->cur_input, 1); | 1067 | /* specific to CS421x */ |
| 965 | if (spec->mic_detect) | 1068 | if (spec->vendor_nid == CS421X_VENDOR_NID) { |
| 966 | cs_automic(codec); | 1069 | if (spec->mic_detect) |
| 967 | 1070 | cs_automic(codec); | |
| 968 | coef = 0x000a; /* ADC1/2 - Digital and Analog Soft Ramp */ | 1071 | else { |
| 969 | if (is_active_pin(codec, CS_DMIC2_PIN_NID)) | 1072 | spec->cur_adc = spec->adc_nid[spec->cur_input]; |
| 970 | coef |= 0x0500; /* DMIC2 enable 2 channels, disable GPIO1 */ | 1073 | snd_hda_codec_write(codec, spec->cur_adc, 0, |
| 971 | if (is_active_pin(codec, CS_DMIC1_PIN_NID)) | 1074 | AC_VERB_SET_CONNECT_SEL, |
| 972 | coef |= 0x1800; /* DMIC1 enable 2 channels, disable GPIO0 | 1075 | spec->adc_idx[spec->cur_input]); |
| 973 | * No effect if SPDIF_OUT2 is selected in | 1076 | } |
| 974 | * IDX_SPDIF_CTL. | 1077 | } else { |
| 975 | */ | 1078 | change_cur_input(codec, spec->cur_input, 1); |
| 976 | cs_vendor_coef_set(codec, IDX_ADC_CFG, coef); | 1079 | if (spec->mic_detect) |
| 1080 | cs_automic(codec); | ||
| 1081 | |||
| 1082 | coef = 0x000a; /* ADC1/2 - Digital and Analog Soft Ramp */ | ||
| 1083 | if (is_active_pin(codec, CS_DMIC2_PIN_NID)) | ||
| 1084 | coef |= 0x0500; /* DMIC2 2 chan on, GPIO1 off */ | ||
| 1085 | if (is_active_pin(codec, CS_DMIC1_PIN_NID)) | ||
| 1086 | coef |= 0x1800; /* DMIC1 2 chan on, GPIO0 off | ||
| 1087 | * No effect if SPDIF_OUT2 is | ||
| 1088 | * selected in IDX_SPDIF_CTL. | ||
| 1089 | */ | ||
| 1090 | cs_vendor_coef_set(codec, IDX_ADC_CFG, coef); | ||
| 1091 | } | ||
| 977 | } | 1092 | } |
| 978 | 1093 | ||
| 979 | static const struct hda_verb cs_coef_init_verbs[] = { | 1094 | static const struct hda_verb cs_coef_init_verbs[] = { |
| @@ -1221,16 +1336,16 @@ static const struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = { | |||
| 1221 | [CS420X_IMAC27] = imac27_pincfgs, | 1336 | [CS420X_IMAC27] = imac27_pincfgs, |
| 1222 | }; | 1337 | }; |
| 1223 | 1338 | ||
| 1224 | static void fix_pincfg(struct hda_codec *codec, int model) | 1339 | static void fix_pincfg(struct hda_codec *codec, int model, |
| 1340 | const struct cs_pincfg **pin_configs) | ||
| 1225 | { | 1341 | { |
| 1226 | const struct cs_pincfg *cfg = cs_pincfgs[model]; | 1342 | const struct cs_pincfg *cfg = pin_configs[model]; |
| 1227 | if (!cfg) | 1343 | if (!cfg) |
| 1228 | return; | 1344 | return; |
| 1229 | for (; cfg->nid; cfg++) | 1345 | for (; cfg->nid; cfg++) |
| 1230 | snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val); | 1346 | snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val); |
| 1231 | } | 1347 | } |
| 1232 | 1348 | ||
| 1233 | |||
| 1234 | static int patch_cs420x(struct hda_codec *codec) | 1349 | static int patch_cs420x(struct hda_codec *codec) |
| 1235 | { | 1350 | { |
| 1236 | struct cs_spec *spec; | 1351 | struct cs_spec *spec; |
| @@ -1241,11 +1356,13 @@ static int patch_cs420x(struct hda_codec *codec) | |||
| 1241 | return -ENOMEM; | 1356 | return -ENOMEM; |
| 1242 | codec->spec = spec; | 1357 | codec->spec = spec; |
| 1243 | 1358 | ||
| 1359 | spec->vendor_nid = CS420X_VENDOR_NID; | ||
| 1360 | |||
| 1244 | spec->board_config = | 1361 | spec->board_config = |
| 1245 | snd_hda_check_board_config(codec, CS420X_MODELS, | 1362 | snd_hda_check_board_config(codec, CS420X_MODELS, |
| 1246 | cs420x_models, cs420x_cfg_tbl); | 1363 | cs420x_models, cs420x_cfg_tbl); |
| 1247 | if (spec->board_config >= 0) | 1364 | if (spec->board_config >= 0) |
| 1248 | fix_pincfg(codec, spec->board_config); | 1365 | fix_pincfg(codec, spec->board_config, cs_pincfgs); |
| 1249 | 1366 | ||
| 1250 | switch (spec->board_config) { | 1367 | switch (spec->board_config) { |
| 1251 | case CS420X_IMAC27: | 1368 | case CS420X_IMAC27: |
| @@ -1272,6 +1389,562 @@ static int patch_cs420x(struct hda_codec *codec) | |||
| 1272 | return err; | 1389 | return err; |
| 1273 | } | 1390 | } |
| 1274 | 1391 | ||
| 1392 | /* | ||
| 1393 | * Cirrus Logic CS4210 | ||
| 1394 | * | ||
| 1395 | * 1 DAC => HP(sense) / Speakers, | ||
| 1396 | * 1 ADC <= LineIn(sense) / MicIn / DMicIn, | ||
| 1397 | * 1 SPDIF OUT => SPDIF Trasmitter(sense) | ||
| 1398 | */ | ||
| 1399 | |||
| 1400 | /* CS4210 board names */ | ||
| 1401 | static const char *cs421x_models[CS421X_MODELS] = { | ||
| 1402 | [CS421X_CDB4210] = "cdb4210", | ||
| 1403 | }; | ||
| 1404 | |||
| 1405 | static const struct snd_pci_quirk cs421x_cfg_tbl[] = { | ||
| 1406 | /* Test Intel board + CDB2410 */ | ||
| 1407 | SND_PCI_QUIRK(0x8086, 0x5001, "DP45SG/CDB4210", CS421X_CDB4210), | ||
| 1408 | {} /* terminator */ | ||
| 1409 | }; | ||
| 1410 | |||
| 1411 | /* CS4210 board pinconfigs */ | ||
| 1412 | /* Default CS4210 (CDB4210)*/ | ||
| 1413 | static const struct cs_pincfg cdb4210_pincfgs[] = { | ||
| 1414 | { 0x05, 0x0321401f }, | ||
| 1415 | { 0x06, 0x90170010 }, | ||
| 1416 | { 0x07, 0x03813031 }, | ||
| 1417 | { 0x08, 0xb7a70037 }, | ||
| 1418 | { 0x09, 0xb7a6003e }, | ||
| 1419 | { 0x0a, 0x034510f0 }, | ||
| 1420 | {} /* terminator */ | ||
| 1421 | }; | ||
| 1422 | |||
| 1423 | static const struct cs_pincfg *cs421x_pincfgs[CS421X_MODELS] = { | ||
| 1424 | [CS421X_CDB4210] = cdb4210_pincfgs, | ||
| 1425 | }; | ||
| 1426 | |||
| 1427 | static const struct hda_verb cs421x_coef_init_verbs[] = { | ||
| 1428 | {0x0B, AC_VERB_SET_PROC_STATE, 1}, | ||
| 1429 | {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DEV_CFG}, | ||
| 1430 | /* | ||
| 1431 | Disable Coefficient Index Auto-Increment(DAI)=1, | ||
| 1432 | PDREF=0 | ||
| 1433 | */ | ||
| 1434 | {0x0B, AC_VERB_SET_PROC_COEF, 0x0001 }, | ||
| 1435 | |||
| 1436 | {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_ADC_CFG}, | ||
| 1437 | /* ADC SZCMode = Digital Soft Ramp */ | ||
| 1438 | {0x0B, AC_VERB_SET_PROC_COEF, 0x0002 }, | ||
| 1439 | |||
| 1440 | {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DAC_CFG}, | ||
| 1441 | {0x0B, AC_VERB_SET_PROC_COEF, | ||
| 1442 | (0x0002 /* DAC SZCMode = Digital Soft Ramp */ | ||
| 1443 | | 0x0004 /* Mute DAC on FIFO error */ | ||
| 1444 | | 0x0008 /* Enable DAC High Pass Filter */ | ||
| 1445 | )}, | ||
| 1446 | {} /* terminator */ | ||
| 1447 | }; | ||
| 1448 | |||
| 1449 | /* Errata: CS4210 rev A1 Silicon | ||
| 1450 | * | ||
| 1451 | * http://www.cirrus.com/en/pubs/errata/ | ||
| 1452 | * | ||
| 1453 | * Description: | ||
| 1454 | * 1. Performance degredation is present in the ADC. | ||
| 1455 | * 2. Speaker output is not completely muted upon HP detect. | ||
| 1456 | * 3. Noise is present when clipping occurs on the amplified | ||
| 1457 | * speaker outputs. | ||
| 1458 | * | ||
| 1459 | * Workaround: | ||
| 1460 | * The following verb sequence written to the registers during | ||
| 1461 | * initialization will correct the issues listed above. | ||
| 1462 | */ | ||
| 1463 | |||
| 1464 | static const struct hda_verb cs421x_coef_init_verbs_A1_silicon_fixes[] = { | ||
| 1465 | {0x0B, AC_VERB_SET_PROC_STATE, 0x01}, /* VPW: processing on */ | ||
| 1466 | |||
| 1467 | {0x0B, AC_VERB_SET_COEF_INDEX, 0x0006}, | ||
| 1468 | {0x0B, AC_VERB_SET_PROC_COEF, 0x9999}, /* Test mode: on */ | ||
| 1469 | |||
| 1470 | {0x0B, AC_VERB_SET_COEF_INDEX, 0x000A}, | ||
| 1471 | {0x0B, AC_VERB_SET_PROC_COEF, 0x14CB}, /* Chop double */ | ||
| 1472 | |||
| 1473 | {0x0B, AC_VERB_SET_COEF_INDEX, 0x0011}, | ||
| 1474 | {0x0B, AC_VERB_SET_PROC_COEF, 0xA2D0}, /* Increase ADC current */ | ||
| 1475 | |||
| 1476 | {0x0B, AC_VERB_SET_COEF_INDEX, 0x001A}, | ||
| 1477 | {0x0B, AC_VERB_SET_PROC_COEF, 0x02A9}, /* Mute speaker */ | ||
| 1478 | |||
| 1479 | {0x0B, AC_VERB_SET_COEF_INDEX, 0x001B}, | ||
| 1480 | {0x0B, AC_VERB_SET_PROC_COEF, 0X1006}, /* Remove noise */ | ||
| 1481 | |||
| 1482 | {} /* terminator */ | ||
| 1483 | }; | ||
| 1484 | |||
| 1485 | /* Speaker Amp Gain is controlled by the vendor widget's coef 4 */ | ||
| 1486 | static const DECLARE_TLV_DB_SCALE(cs421x_speaker_boost_db_scale, 900, 300, 0); | ||
| 1487 | |||
| 1488 | static int cs421x_boost_vol_info(struct snd_kcontrol *kcontrol, | ||
| 1489 | struct snd_ctl_elem_info *uinfo) | ||
| 1490 | { | ||
| 1491 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
| 1492 | uinfo->count = 1; | ||
| 1493 | uinfo->value.integer.min = 0; | ||
| 1494 | uinfo->value.integer.max = 3; | ||
| 1495 | return 0; | ||
| 1496 | } | ||
| 1497 | |||
| 1498 | static int cs421x_boost_vol_get(struct snd_kcontrol *kcontrol, | ||
| 1499 | struct snd_ctl_elem_value *ucontrol) | ||
| 1500 | { | ||
| 1501 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
| 1502 | |||
| 1503 | ucontrol->value.integer.value[0] = | ||
| 1504 | cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL) & 0x0003; | ||
| 1505 | return 0; | ||
| 1506 | } | ||
| 1507 | |||
| 1508 | static int cs421x_boost_vol_put(struct snd_kcontrol *kcontrol, | ||
| 1509 | struct snd_ctl_elem_value *ucontrol) | ||
| 1510 | { | ||
| 1511 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
| 1512 | |||
| 1513 | unsigned int vol = ucontrol->value.integer.value[0]; | ||
| 1514 | unsigned int coef = | ||
| 1515 | cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL); | ||
| 1516 | unsigned int original_coef = coef; | ||
| 1517 | |||
| 1518 | coef &= ~0x0003; | ||
| 1519 | coef |= (vol & 0x0003); | ||
| 1520 | if (original_coef == coef) | ||
| 1521 | return 0; | ||
| 1522 | else { | ||
| 1523 | cs_vendor_coef_set(codec, CS421X_IDX_SPK_CTL, coef); | ||
| 1524 | return 1; | ||
| 1525 | } | ||
| 1526 | } | ||
| 1527 | |||
| 1528 | static const struct snd_kcontrol_new cs421x_speaker_bost_ctl = { | ||
| 1529 | |||
| 1530 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 1531 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
| 1532 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
| 1533 | .name = "Speaker Boost Playback Volume", | ||
| 1534 | .info = cs421x_boost_vol_info, | ||
| 1535 | .get = cs421x_boost_vol_get, | ||
| 1536 | .put = cs421x_boost_vol_put, | ||
| 1537 | .tlv = { .p = cs421x_speaker_boost_db_scale }, | ||
| 1538 | }; | ||
| 1539 | |||
| 1540 | static void cs421x_pinmux_init(struct hda_codec *codec) | ||
| 1541 | { | ||
| 1542 | struct cs_spec *spec = codec->spec; | ||
| 1543 | unsigned int def_conf, coef; | ||
| 1544 | |||
| 1545 | /* GPIO, DMIC_SCL, DMIC_SDA and SENSE_B are multiplexed */ | ||
| 1546 | coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG); | ||
| 1547 | |||
| 1548 | if (spec->gpio_mask) | ||
| 1549 | coef |= 0x0008; /* B1,B2 are GPIOs */ | ||
| 1550 | else | ||
| 1551 | coef &= ~0x0008; | ||
| 1552 | |||
| 1553 | if (spec->sense_b) | ||
| 1554 | coef |= 0x0010; /* B2 is SENSE_B, not inverted */ | ||
| 1555 | else | ||
| 1556 | coef &= ~0x0010; | ||
| 1557 | |||
| 1558 | cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef); | ||
| 1559 | |||
| 1560 | if ((spec->gpio_mask || spec->sense_b) && | ||
| 1561 | is_active_pin(codec, CS421X_DMIC_PIN_NID)) { | ||
| 1562 | |||
| 1563 | /* | ||
| 1564 | GPIO or SENSE_B forced - disconnect the DMIC pin. | ||
| 1565 | */ | ||
| 1566 | def_conf = snd_hda_codec_get_pincfg(codec, CS421X_DMIC_PIN_NID); | ||
| 1567 | def_conf &= ~AC_DEFCFG_PORT_CONN; | ||
| 1568 | def_conf |= (AC_JACK_PORT_NONE << AC_DEFCFG_PORT_CONN_SHIFT); | ||
| 1569 | snd_hda_codec_set_pincfg(codec, CS421X_DMIC_PIN_NID, def_conf); | ||
| 1570 | } | ||
| 1571 | } | ||
| 1572 | |||
| 1573 | static void init_cs421x_digital(struct hda_codec *codec) | ||
| 1574 | { | ||
| 1575 | struct cs_spec *spec = codec->spec; | ||
| 1576 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
| 1577 | int i; | ||
| 1578 | |||
| 1579 | |||
| 1580 | for (i = 0; i < cfg->dig_outs; i++) { | ||
| 1581 | hda_nid_t nid = cfg->dig_out_pins[i]; | ||
| 1582 | if (!cfg->speaker_outs) | ||
| 1583 | continue; | ||
| 1584 | if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { | ||
| 1585 | |||
| 1586 | snd_hda_codec_write(codec, nid, 0, | ||
| 1587 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
| 1588 | AC_USRSP_EN | SPDIF_EVENT); | ||
| 1589 | spec->spdif_detect = 1; | ||
| 1590 | } | ||
| 1591 | } | ||
| 1592 | } | ||
| 1593 | |||
| 1594 | static int cs421x_init(struct hda_codec *codec) | ||
| 1595 | { | ||
| 1596 | struct cs_spec *spec = codec->spec; | ||
| 1597 | |||
| 1598 | snd_hda_sequence_write(codec, cs421x_coef_init_verbs); | ||
| 1599 | snd_hda_sequence_write(codec, cs421x_coef_init_verbs_A1_silicon_fixes); | ||
| 1600 | |||
| 1601 | cs421x_pinmux_init(codec); | ||
| 1602 | |||
| 1603 | if (spec->gpio_mask) { | ||
| 1604 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, | ||
| 1605 | spec->gpio_mask); | ||
| 1606 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION, | ||
| 1607 | spec->gpio_dir); | ||
| 1608 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, | ||
| 1609 | spec->gpio_data); | ||
| 1610 | } | ||
| 1611 | |||
| 1612 | init_output(codec); | ||
| 1613 | init_input(codec); | ||
| 1614 | init_cs421x_digital(codec); | ||
| 1615 | |||
| 1616 | return 0; | ||
| 1617 | } | ||
| 1618 | |||
| 1619 | /* | ||
| 1620 | * CS4210 Input MUX (1 ADC) | ||
| 1621 | */ | ||
| 1622 | static int cs421x_mux_enum_info(struct snd_kcontrol *kcontrol, | ||
| 1623 | struct snd_ctl_elem_info *uinfo) | ||
| 1624 | { | ||
| 1625 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
| 1626 | struct cs_spec *spec = codec->spec; | ||
| 1627 | |||
| 1628 | return snd_hda_input_mux_info(&spec->input_mux, uinfo); | ||
| 1629 | } | ||
| 1630 | |||
| 1631 | static int cs421x_mux_enum_get(struct snd_kcontrol *kcontrol, | ||
| 1632 | struct snd_ctl_elem_value *ucontrol) | ||
| 1633 | { | ||
| 1634 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
| 1635 | struct cs_spec *spec = codec->spec; | ||
| 1636 | |||
| 1637 | ucontrol->value.enumerated.item[0] = spec->cur_input; | ||
| 1638 | return 0; | ||
| 1639 | } | ||
| 1640 | |||
| 1641 | static int cs421x_mux_enum_put(struct snd_kcontrol *kcontrol, | ||
| 1642 | struct snd_ctl_elem_value *ucontrol) | ||
| 1643 | { | ||
| 1644 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
| 1645 | struct cs_spec *spec = codec->spec; | ||
| 1646 | |||
| 1647 | return snd_hda_input_mux_put(codec, &spec->input_mux, ucontrol, | ||
| 1648 | spec->adc_nid[0], &spec->cur_input); | ||
| 1649 | |||
| 1650 | } | ||
| 1651 | |||
| 1652 | static struct snd_kcontrol_new cs421x_capture_source = { | ||
| 1653 | |||
| 1654 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 1655 | .name = "Capture Source", | ||
| 1656 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
| 1657 | .info = cs421x_mux_enum_info, | ||
| 1658 | .get = cs421x_mux_enum_get, | ||
| 1659 | .put = cs421x_mux_enum_put, | ||
| 1660 | }; | ||
| 1661 | |||
| 1662 | static int cs421x_add_input_volume_control(struct hda_codec *codec, int item) | ||
| 1663 | { | ||
| 1664 | struct cs_spec *spec = codec->spec; | ||
| 1665 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
| 1666 | const struct hda_input_mux *imux = &spec->input_mux; | ||
| 1667 | hda_nid_t pin = cfg->inputs[item].pin; | ||
| 1668 | struct snd_kcontrol *kctl; | ||
| 1669 | u32 caps; | ||
| 1670 | |||
| 1671 | if (!(get_wcaps(codec, pin) & AC_WCAP_IN_AMP)) | ||
| 1672 | return 0; | ||
| 1673 | |||
| 1674 | caps = query_amp_caps(codec, pin, HDA_INPUT); | ||
| 1675 | caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; | ||
| 1676 | if (caps <= 1) | ||
| 1677 | return 0; | ||
| 1678 | |||
| 1679 | return add_volume(codec, imux->items[item].label, 0, | ||
| 1680 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT), 1, &kctl); | ||
| 1681 | } | ||
| 1682 | |||
| 1683 | /* add a (input-boost) volume control to the given input pin */ | ||
| 1684 | static int build_cs421x_input(struct hda_codec *codec) | ||
| 1685 | { | ||
| 1686 | struct cs_spec *spec = codec->spec; | ||
| 1687 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
| 1688 | struct hda_input_mux *imux = &spec->input_mux; | ||
| 1689 | int i, err, type_idx; | ||
| 1690 | const char *label; | ||
| 1691 | |||
| 1692 | if (!spec->num_inputs) | ||
| 1693 | return 0; | ||
| 1694 | |||
| 1695 | /* make bind-capture */ | ||
| 1696 | spec->capture_bind[0] = make_bind_capture(codec, &snd_hda_bind_sw); | ||
| 1697 | spec->capture_bind[1] = make_bind_capture(codec, &snd_hda_bind_vol); | ||
| 1698 | for (i = 0; i < 2; i++) { | ||
| 1699 | struct snd_kcontrol *kctl; | ||
| 1700 | int n; | ||
| 1701 | if (!spec->capture_bind[i]) | ||
| 1702 | return -ENOMEM; | ||
| 1703 | kctl = snd_ctl_new1(&cs_capture_ctls[i], codec); | ||
| 1704 | if (!kctl) | ||
| 1705 | return -ENOMEM; | ||
| 1706 | kctl->private_value = (long)spec->capture_bind[i]; | ||
| 1707 | err = snd_hda_ctl_add(codec, 0, kctl); | ||
| 1708 | if (err < 0) | ||
| 1709 | return err; | ||
| 1710 | for (n = 0; n < AUTO_PIN_LAST; n++) { | ||
| 1711 | if (!spec->adc_nid[n]) | ||
| 1712 | continue; | ||
| 1713 | err = snd_hda_add_nid(codec, kctl, 0, spec->adc_nid[n]); | ||
| 1714 | if (err < 0) | ||
| 1715 | return err; | ||
| 1716 | } | ||
| 1717 | } | ||
| 1718 | |||
| 1719 | /* Add Input MUX Items + Capture Volume/Switch */ | ||
| 1720 | for (i = 0; i < spec->num_inputs; i++) { | ||
| 1721 | label = hda_get_autocfg_input_label(codec, cfg, i); | ||
| 1722 | snd_hda_add_imux_item(imux, label, spec->adc_idx[i], &type_idx); | ||
| 1723 | |||
| 1724 | err = cs421x_add_input_volume_control(codec, i); | ||
| 1725 | if (err < 0) | ||
| 1726 | return err; | ||
| 1727 | } | ||
| 1728 | |||
| 1729 | /* | ||
| 1730 | Add 'Capture Source' Switch if | ||
| 1731 | * 2 inputs and no mic detec | ||
| 1732 | * 3 inputs | ||
| 1733 | */ | ||
| 1734 | if ((spec->num_inputs == 2 && !spec->mic_detect) || | ||
| 1735 | (spec->num_inputs == 3)) { | ||
| 1736 | |||
| 1737 | err = snd_hda_ctl_add(codec, spec->adc_nid[0], | ||
| 1738 | snd_ctl_new1(&cs421x_capture_source, codec)); | ||
| 1739 | if (err < 0) | ||
| 1740 | return err; | ||
| 1741 | } | ||
| 1742 | |||
| 1743 | return 0; | ||
| 1744 | } | ||
| 1745 | |||
| 1746 | /* Single DAC (Mute/Gain) */ | ||
| 1747 | static int build_cs421x_output(struct hda_codec *codec) | ||
| 1748 | { | ||
| 1749 | hda_nid_t dac = CS4210_DAC_NID; | ||
| 1750 | struct cs_spec *spec = codec->spec; | ||
| 1751 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
| 1752 | struct snd_kcontrol *kctl; | ||
| 1753 | int err; | ||
| 1754 | char *name = "HP/Speakers"; | ||
| 1755 | |||
| 1756 | fix_volume_caps(codec, dac); | ||
| 1757 | if (!spec->vmaster_sw) { | ||
| 1758 | err = add_vmaster(codec, dac); | ||
| 1759 | if (err < 0) | ||
| 1760 | return err; | ||
| 1761 | } | ||
| 1762 | |||
| 1763 | err = add_mute(codec, name, 0, | ||
| 1764 | HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl); | ||
| 1765 | if (err < 0) | ||
| 1766 | return err; | ||
| 1767 | err = snd_ctl_add_slave(spec->vmaster_sw, kctl); | ||
| 1768 | if (err < 0) | ||
| 1769 | return err; | ||
| 1770 | |||
| 1771 | err = add_volume(codec, name, 0, | ||
| 1772 | HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl); | ||
| 1773 | if (err < 0) | ||
| 1774 | return err; | ||
| 1775 | err = snd_ctl_add_slave(spec->vmaster_vol, kctl); | ||
| 1776 | if (err < 0) | ||
| 1777 | return err; | ||
| 1778 | |||
| 1779 | if (cfg->speaker_outs) { | ||
| 1780 | err = snd_hda_ctl_add(codec, 0, | ||
| 1781 | snd_ctl_new1(&cs421x_speaker_bost_ctl, codec)); | ||
| 1782 | if (err < 0) | ||
| 1783 | return err; | ||
| 1784 | } | ||
| 1785 | return err; | ||
| 1786 | } | ||
| 1787 | |||
| 1788 | static int cs421x_build_controls(struct hda_codec *codec) | ||
| 1789 | { | ||
| 1790 | int err; | ||
| 1791 | |||
| 1792 | err = build_cs421x_output(codec); | ||
| 1793 | if (err < 0) | ||
| 1794 | return err; | ||
| 1795 | err = build_cs421x_input(codec); | ||
| 1796 | if (err < 0) | ||
| 1797 | return err; | ||
| 1798 | err = build_digital_output(codec); | ||
| 1799 | if (err < 0) | ||
| 1800 | return err; | ||
| 1801 | return cs421x_init(codec); | ||
| 1802 | } | ||
| 1803 | |||
| 1804 | static void cs421x_unsol_event(struct hda_codec *codec, unsigned int res) | ||
| 1805 | { | ||
| 1806 | switch ((res >> 26) & 0x3f) { | ||
| 1807 | case HP_EVENT: | ||
| 1808 | case SPDIF_EVENT: | ||
| 1809 | cs_automute(codec); | ||
| 1810 | break; | ||
| 1811 | |||
| 1812 | case MIC_EVENT: | ||
| 1813 | cs_automic(codec); | ||
| 1814 | break; | ||
| 1815 | } | ||
| 1816 | } | ||
| 1817 | |||
| 1818 | static int parse_cs421x_input(struct hda_codec *codec) | ||
| 1819 | { | ||
| 1820 | struct cs_spec *spec = codec->spec; | ||
| 1821 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
| 1822 | int i; | ||
| 1823 | |||
| 1824 | for (i = 0; i < cfg->num_inputs; i++) { | ||
| 1825 | hda_nid_t pin = cfg->inputs[i].pin; | ||
| 1826 | spec->adc_nid[i] = get_adc(codec, pin, &spec->adc_idx[i]); | ||
| 1827 | spec->cur_input = spec->last_input = i; | ||
| 1828 | spec->num_inputs++; | ||
| 1829 | |||
| 1830 | /* check whether the automatic mic switch is available */ | ||
| 1831 | if (is_ext_mic(codec, i) && cfg->num_inputs >= 2) { | ||
| 1832 | spec->mic_detect = 1; | ||
| 1833 | spec->automic_idx = i; | ||
| 1834 | } | ||
| 1835 | } | ||
| 1836 | return 0; | ||
| 1837 | } | ||
| 1838 | |||
| 1839 | static int cs421x_parse_auto_config(struct hda_codec *codec) | ||
| 1840 | { | ||
| 1841 | struct cs_spec *spec = codec->spec; | ||
| 1842 | int err; | ||
| 1843 | |||
| 1844 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); | ||
| 1845 | if (err < 0) | ||
| 1846 | return err; | ||
| 1847 | err = parse_output(codec); | ||
| 1848 | if (err < 0) | ||
| 1849 | return err; | ||
| 1850 | err = parse_cs421x_input(codec); | ||
| 1851 | if (err < 0) | ||
| 1852 | return err; | ||
| 1853 | err = parse_digital_output(codec); | ||
| 1854 | if (err < 0) | ||
| 1855 | return err; | ||
| 1856 | return 0; | ||
| 1857 | } | ||
| 1858 | |||
| 1859 | #ifdef CONFIG_PM | ||
| 1860 | /* | ||
| 1861 | Manage PDREF, when transitioning to D3hot | ||
| 1862 | (DAC,ADC) -> D3, PDREF=1, AFG->D3 | ||
| 1863 | */ | ||
| 1864 | static int cs421x_suspend(struct hda_codec *codec, pm_message_t state) | ||
| 1865 | { | ||
| 1866 | unsigned int coef; | ||
| 1867 | |||
| 1868 | snd_hda_shutup_pins(codec); | ||
| 1869 | |||
| 1870 | snd_hda_codec_write(codec, CS4210_DAC_NID, 0, | ||
| 1871 | AC_VERB_SET_POWER_STATE, AC_PWRST_D3); | ||
| 1872 | snd_hda_codec_write(codec, CS4210_ADC_NID, 0, | ||
| 1873 | AC_VERB_SET_POWER_STATE, AC_PWRST_D3); | ||
| 1874 | |||
| 1875 | coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG); | ||
| 1876 | coef |= 0x0004; /* PDREF */ | ||
| 1877 | cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef); | ||
| 1878 | |||
| 1879 | return 0; | ||
| 1880 | } | ||
| 1881 | #endif | ||
| 1882 | |||
| 1883 | static struct hda_codec_ops cs4210_patch_ops = { | ||
| 1884 | .build_controls = cs421x_build_controls, | ||
| 1885 | .build_pcms = cs_build_pcms, | ||
| 1886 | .init = cs421x_init, | ||
| 1887 | .free = cs_free, | ||
| 1888 | .unsol_event = cs421x_unsol_event, | ||
| 1889 | #ifdef CONFIG_PM | ||
| 1890 | .suspend = cs421x_suspend, | ||
| 1891 | #endif | ||
| 1892 | }; | ||
| 1893 | |||
| 1894 | static int patch_cs421x(struct hda_codec *codec) | ||
| 1895 | { | ||
| 1896 | struct cs_spec *spec; | ||
| 1897 | int err; | ||
| 1898 | |||
| 1899 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
| 1900 | if (!spec) | ||
| 1901 | return -ENOMEM; | ||
| 1902 | codec->spec = spec; | ||
| 1903 | |||
| 1904 | spec->vendor_nid = CS421X_VENDOR_NID; | ||
| 1905 | |||
| 1906 | spec->board_config = | ||
| 1907 | snd_hda_check_board_config(codec, CS421X_MODELS, | ||
| 1908 | cs421x_models, cs421x_cfg_tbl); | ||
| 1909 | if (spec->board_config >= 0) | ||
| 1910 | fix_pincfg(codec, spec->board_config, cs421x_pincfgs); | ||
| 1911 | /* | ||
| 1912 | Setup GPIO/SENSE for each board (if used) | ||
| 1913 | */ | ||
| 1914 | switch (spec->board_config) { | ||
| 1915 | case CS421X_CDB4210: | ||
| 1916 | snd_printd("CS4210 board: %s\n", | ||
| 1917 | cs421x_models[spec->board_config]); | ||
| 1918 | /* spec->gpio_mask = 3; | ||
| 1919 | spec->gpio_dir = 3; | ||
| 1920 | spec->gpio_data = 3; | ||
| 1921 | */ | ||
| 1922 | spec->sense_b = 1; | ||
| 1923 | |||
| 1924 | break; | ||
| 1925 | } | ||
| 1926 | |||
| 1927 | /* | ||
| 1928 | Update the GPIO/DMIC/SENSE_B pinmux before the configuration | ||
| 1929 | is auto-parsed. If GPIO or SENSE_B is forced, DMIC input | ||
| 1930 | is disabled. | ||
| 1931 | */ | ||
| 1932 | cs421x_pinmux_init(codec); | ||
| 1933 | |||
| 1934 | err = cs421x_parse_auto_config(codec); | ||
| 1935 | if (err < 0) | ||
| 1936 | goto error; | ||
| 1937 | |||
| 1938 | codec->patch_ops = cs4210_patch_ops; | ||
| 1939 | |||
| 1940 | return 0; | ||
| 1941 | |||
| 1942 | error: | ||
| 1943 | kfree(codec->spec); | ||
| 1944 | codec->spec = NULL; | ||
| 1945 | return err; | ||
| 1946 | } | ||
| 1947 | |||
| 1275 | 1948 | ||
| 1276 | /* | 1949 | /* |
| 1277 | * patch entries | 1950 | * patch entries |
| @@ -1279,11 +1952,13 @@ static int patch_cs420x(struct hda_codec *codec) | |||
| 1279 | static const struct hda_codec_preset snd_hda_preset_cirrus[] = { | 1952 | static const struct hda_codec_preset snd_hda_preset_cirrus[] = { |
| 1280 | { .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x }, | 1953 | { .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x }, |
| 1281 | { .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x }, | 1954 | { .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x }, |
| 1955 | { .id = 0x10134210, .name = "CS4210", .patch = patch_cs421x }, | ||
| 1282 | {} /* terminator */ | 1956 | {} /* terminator */ |
| 1283 | }; | 1957 | }; |
| 1284 | 1958 | ||
| 1285 | MODULE_ALIAS("snd-hda-codec-id:10134206"); | 1959 | MODULE_ALIAS("snd-hda-codec-id:10134206"); |
| 1286 | MODULE_ALIAS("snd-hda-codec-id:10134207"); | 1960 | MODULE_ALIAS("snd-hda-codec-id:10134207"); |
| 1961 | MODULE_ALIAS("snd-hda-codec-id:10134210"); | ||
| 1287 | 1962 | ||
| 1288 | MODULE_LICENSE("GPL"); | 1963 | MODULE_LICENSE("GPL"); |
| 1289 | MODULE_DESCRIPTION("Cirrus Logic HD-audio codec"); | 1964 | MODULE_DESCRIPTION("Cirrus Logic HD-audio codec"); |
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 884f67b8f4e0..502fc9499453 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
| @@ -446,6 +446,19 @@ static int conexant_init_jacks(struct hda_codec *codec) | |||
| 446 | return 0; | 446 | return 0; |
| 447 | } | 447 | } |
| 448 | 448 | ||
| 449 | static void conexant_set_power(struct hda_codec *codec, hda_nid_t fg, | ||
| 450 | unsigned int power_state) | ||
| 451 | { | ||
| 452 | if (power_state == AC_PWRST_D3) | ||
| 453 | msleep(100); | ||
| 454 | snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, | ||
| 455 | power_state); | ||
| 456 | /* partial workaround for "azx_get_response timeout" */ | ||
| 457 | if (power_state == AC_PWRST_D0) | ||
| 458 | msleep(10); | ||
| 459 | snd_hda_codec_set_power_to_all(codec, fg, power_state, true); | ||
| 460 | } | ||
| 461 | |||
| 449 | static int conexant_init(struct hda_codec *codec) | 462 | static int conexant_init(struct hda_codec *codec) |
| 450 | { | 463 | { |
| 451 | struct conexant_spec *spec = codec->spec; | 464 | struct conexant_spec *spec = codec->spec; |
| @@ -588,6 +601,7 @@ static const struct hda_codec_ops conexant_patch_ops = { | |||
| 588 | .build_pcms = conexant_build_pcms, | 601 | .build_pcms = conexant_build_pcms, |
| 589 | .init = conexant_init, | 602 | .init = conexant_init, |
| 590 | .free = conexant_free, | 603 | .free = conexant_free, |
| 604 | .set_power_state = conexant_set_power, | ||
| 591 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 605 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
| 592 | .suspend = conexant_suspend, | 606 | .suspend = conexant_suspend, |
| 593 | #endif | 607 | #endif |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 52ce07534e5b..694327ae8b71 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
| @@ -2386,7 +2386,7 @@ static int alc_suspend(struct hda_codec *codec, pm_message_t state) | |||
| 2386 | } | 2386 | } |
| 2387 | #endif | 2387 | #endif |
| 2388 | 2388 | ||
| 2389 | #ifdef SND_HDA_NEEDS_RESUME | 2389 | #ifdef CONFIG_PM |
| 2390 | static int alc_resume(struct hda_codec *codec) | 2390 | static int alc_resume(struct hda_codec *codec) |
| 2391 | { | 2391 | { |
| 2392 | msleep(150); /* to avoid pop noise */ | 2392 | msleep(150); /* to avoid pop noise */ |
| @@ -2406,7 +2406,7 @@ static const struct hda_codec_ops alc_patch_ops = { | |||
| 2406 | .init = alc_init, | 2406 | .init = alc_init, |
| 2407 | .free = alc_free, | 2407 | .free = alc_free, |
| 2408 | .unsol_event = alc_unsol_event, | 2408 | .unsol_event = alc_unsol_event, |
| 2409 | #ifdef SND_HDA_NEEDS_RESUME | 2409 | #ifdef CONFIG_PM |
| 2410 | .resume = alc_resume, | 2410 | .resume = alc_resume, |
| 2411 | #endif | 2411 | #endif |
| 2412 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 2412 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
| @@ -2801,7 +2801,8 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec) | |||
| 2801 | int i; | 2801 | int i; |
| 2802 | 2802 | ||
| 2803 | again: | 2803 | again: |
| 2804 | spec->multiout.num_dacs = 0; | 2804 | /* set num_dacs once to full for alc_auto_look_for_dac() */ |
| 2805 | spec->multiout.num_dacs = cfg->line_outs; | ||
| 2805 | spec->multiout.hp_nid = 0; | 2806 | spec->multiout.hp_nid = 0; |
| 2806 | spec->multiout.extra_out_nid[0] = 0; | 2807 | spec->multiout.extra_out_nid[0] = 0; |
| 2807 | memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids)); | 2808 | memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids)); |
| @@ -2834,6 +2835,8 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec) | |||
| 2834 | } | 2835 | } |
| 2835 | } | 2836 | } |
| 2836 | 2837 | ||
| 2838 | /* re-count num_dacs and squash invalid entries */ | ||
| 2839 | spec->multiout.num_dacs = 0; | ||
| 2837 | for (i = 0; i < cfg->line_outs; i++) { | 2840 | for (i = 0; i < cfg->line_outs; i++) { |
| 2838 | if (spec->private_dac_nids[i]) | 2841 | if (spec->private_dac_nids[i]) |
| 2839 | spec->multiout.num_dacs++; | 2842 | spec->multiout.num_dacs++; |
| @@ -4410,7 +4413,7 @@ static void alc269_shutup(struct hda_codec *codec) | |||
| 4410 | } | 4413 | } |
| 4411 | } | 4414 | } |
| 4412 | 4415 | ||
| 4413 | #ifdef SND_HDA_NEEDS_RESUME | 4416 | #ifdef CONFIG_PM |
| 4414 | static int alc269_resume(struct hda_codec *codec) | 4417 | static int alc269_resume(struct hda_codec *codec) |
| 4415 | { | 4418 | { |
| 4416 | if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { | 4419 | if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { |
| @@ -4433,7 +4436,7 @@ static int alc269_resume(struct hda_codec *codec) | |||
| 4433 | hda_call_check_power_status(codec, 0x01); | 4436 | hda_call_check_power_status(codec, 0x01); |
| 4434 | return 0; | 4437 | return 0; |
| 4435 | } | 4438 | } |
| 4436 | #endif /* SND_HDA_NEEDS_RESUME */ | 4439 | #endif /* CONFIG_PM */ |
| 4437 | 4440 | ||
| 4438 | static void alc269_fixup_hweq(struct hda_codec *codec, | 4441 | static void alc269_fixup_hweq(struct hda_codec *codec, |
| 4439 | const struct alc_fixup *fix, int action) | 4442 | const struct alc_fixup *fix, int action) |
| @@ -4725,7 +4728,7 @@ static int patch_alc269(struct hda_codec *codec) | |||
| 4725 | spec->vmaster_nid = 0x02; | 4728 | spec->vmaster_nid = 0x02; |
| 4726 | 4729 | ||
| 4727 | codec->patch_ops = alc_patch_ops; | 4730 | codec->patch_ops = alc_patch_ops; |
| 4728 | #ifdef SND_HDA_NEEDS_RESUME | 4731 | #ifdef CONFIG_PM |
| 4729 | codec->patch_ops.resume = alc269_resume; | 4732 | codec->patch_ops.resume = alc269_resume; |
| 4730 | #endif | 4733 | #endif |
| 4731 | if (board_config == ALC_MODEL_AUTO) | 4734 | if (board_config == ALC_MODEL_AUTO) |
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 56425a53cf1b..fcf4c7142103 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
| @@ -95,6 +95,7 @@ enum { | |||
| 95 | STAC_92HD83XXX_PWR_REF, | 95 | STAC_92HD83XXX_PWR_REF, |
| 96 | STAC_DELL_S14, | 96 | STAC_DELL_S14, |
| 97 | STAC_92HD83XXX_HP, | 97 | STAC_92HD83XXX_HP, |
| 98 | STAC_92HD83XXX_HP_cNB11_INTQUAD, | ||
| 98 | STAC_HP_DV7_4000, | 99 | STAC_HP_DV7_4000, |
| 99 | STAC_92HD83XXX_MODELS | 100 | STAC_92HD83XXX_MODELS |
| 100 | }; | 101 | }; |
| @@ -1636,10 +1637,17 @@ static const unsigned int hp_dv7_4000_pin_configs[10] = { | |||
| 1636 | 0x40f000f0, 0x40f000f0, | 1637 | 0x40f000f0, 0x40f000f0, |
| 1637 | }; | 1638 | }; |
| 1638 | 1639 | ||
| 1640 | static const unsigned int hp_cNB11_intquad_pin_configs[10] = { | ||
| 1641 | 0x40f000f0, 0x0221101f, 0x02a11020, 0x92170110, | ||
| 1642 | 0x40f000f0, 0x92170110, 0x40f000f0, 0xd5a30130, | ||
| 1643 | 0x40f000f0, 0x40f000f0, | ||
| 1644 | }; | ||
| 1645 | |||
| 1639 | static const unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = { | 1646 | static const unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = { |
| 1640 | [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs, | 1647 | [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs, |
| 1641 | [STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs, | 1648 | [STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs, |
| 1642 | [STAC_DELL_S14] = dell_s14_pin_configs, | 1649 | [STAC_DELL_S14] = dell_s14_pin_configs, |
| 1650 | [STAC_92HD83XXX_HP_cNB11_INTQUAD] = hp_cNB11_intquad_pin_configs, | ||
| 1643 | [STAC_HP_DV7_4000] = hp_dv7_4000_pin_configs, | 1651 | [STAC_HP_DV7_4000] = hp_dv7_4000_pin_configs, |
| 1644 | }; | 1652 | }; |
| 1645 | 1653 | ||
| @@ -1649,6 +1657,7 @@ static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { | |||
| 1649 | [STAC_92HD83XXX_PWR_REF] = "mic-ref", | 1657 | [STAC_92HD83XXX_PWR_REF] = "mic-ref", |
| 1650 | [STAC_DELL_S14] = "dell-s14", | 1658 | [STAC_DELL_S14] = "dell-s14", |
| 1651 | [STAC_92HD83XXX_HP] = "hp", | 1659 | [STAC_92HD83XXX_HP] = "hp", |
| 1660 | [STAC_92HD83XXX_HP_cNB11_INTQUAD] = "hp_cNB11_intquad", | ||
| 1652 | [STAC_HP_DV7_4000] = "hp-dv7-4000", | 1661 | [STAC_HP_DV7_4000] = "hp-dv7-4000", |
| 1653 | }; | 1662 | }; |
| 1654 | 1663 | ||
| @@ -1661,7 +1670,47 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { | |||
| 1661 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ba, | 1670 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ba, |
| 1662 | "unknown Dell", STAC_DELL_S14), | 1671 | "unknown Dell", STAC_DELL_S14), |
| 1663 | SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x3600, | 1672 | SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x3600, |
| 1664 | "HP", STAC_92HD83XXX_HP), | 1673 | "HP", STAC_92HD83XXX_HP), |
| 1674 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1656, | ||
| 1675 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), | ||
| 1676 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1657, | ||
| 1677 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), | ||
| 1678 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1658, | ||
| 1679 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), | ||
| 1680 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1659, | ||
| 1681 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), | ||
| 1682 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165A, | ||
| 1683 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), | ||
| 1684 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165B, | ||
| 1685 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), | ||
| 1686 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3388, | ||
| 1687 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), | ||
| 1688 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3389, | ||
| 1689 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), | ||
| 1690 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355B, | ||
| 1691 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), | ||
| 1692 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355C, | ||
| 1693 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), | ||
| 1694 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355D, | ||
| 1695 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), | ||
| 1696 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355E, | ||
| 1697 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), | ||
| 1698 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355F, | ||
| 1699 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), | ||
| 1700 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3560, | ||
| 1701 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), | ||
| 1702 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x358B, | ||
| 1703 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), | ||
| 1704 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x358C, | ||
| 1705 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), | ||
| 1706 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x358D, | ||
| 1707 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), | ||
| 1708 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3591, | ||
| 1709 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), | ||
| 1710 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3592, | ||
| 1711 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), | ||
| 1712 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3593, | ||
| 1713 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), | ||
| 1665 | {} /* terminator */ | 1714 | {} /* terminator */ |
| 1666 | }; | 1715 | }; |
| 1667 | 1716 | ||
| @@ -4885,7 +4934,18 @@ static void stac927x_proc_hook(struct snd_info_buffer *buffer, | |||
| 4885 | #define stac927x_proc_hook NULL | 4934 | #define stac927x_proc_hook NULL |
| 4886 | #endif | 4935 | #endif |
| 4887 | 4936 | ||
| 4888 | #ifdef SND_HDA_NEEDS_RESUME | 4937 | #ifdef CONFIG_PM |
| 4938 | static int stac92xx_pre_resume(struct hda_codec *codec) | ||
| 4939 | { | ||
| 4940 | struct sigmatel_spec *spec = codec->spec; | ||
| 4941 | |||
| 4942 | /* sync mute LED */ | ||
| 4943 | if (spec->gpio_led) | ||
| 4944 | stac_gpio_set(codec, spec->gpio_mask, | ||
| 4945 | spec->gpio_dir, spec->gpio_data); | ||
| 4946 | return 0; | ||
| 4947 | } | ||
| 4948 | |||
| 4889 | static int stac92xx_resume(struct hda_codec *codec) | 4949 | static int stac92xx_resume(struct hda_codec *codec) |
| 4890 | { | 4950 | { |
| 4891 | struct sigmatel_spec *spec = codec->spec; | 4951 | struct sigmatel_spec *spec = codec->spec; |
| @@ -4901,29 +4961,19 @@ static int stac92xx_resume(struct hda_codec *codec) | |||
| 4901 | stac_issue_unsol_event(codec, | 4961 | stac_issue_unsol_event(codec, |
| 4902 | spec->autocfg.line_out_pins[0]); | 4962 | spec->autocfg.line_out_pins[0]); |
| 4903 | } | 4963 | } |
| 4904 | /* sync mute LED */ | ||
| 4905 | if (spec->gpio_led) | ||
| 4906 | hda_call_check_power_status(codec, 0x01); | ||
| 4907 | return 0; | 4964 | return 0; |
| 4908 | } | 4965 | } |
| 4909 | 4966 | ||
| 4967 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
| 4910 | /* | 4968 | /* |
| 4911 | * using power check for controlling mute led of HP notebooks | 4969 | * For this feature CONFIG_SND_HDA_POWER_SAVE is needed |
| 4912 | * check for mute state only on Speakers (nid = 0x10) | 4970 | * as mute LED state is updated in check_power_status hook |
| 4913 | * | ||
| 4914 | * For this feature CONFIG_SND_HDA_POWER_SAVE is needed, otherwise | ||
| 4915 | * the LED is NOT working properly ! | ||
| 4916 | * | ||
| 4917 | * Changed name to reflect that it now works for any designated | ||
| 4918 | * model, not just HP HDX. | ||
| 4919 | */ | 4971 | */ |
| 4920 | 4972 | static int stac92xx_update_led_status(struct hda_codec *codec) | |
| 4921 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
| 4922 | static int stac92xx_hp_check_power_status(struct hda_codec *codec, | ||
| 4923 | hda_nid_t nid) | ||
| 4924 | { | 4973 | { |
| 4925 | struct sigmatel_spec *spec = codec->spec; | 4974 | struct sigmatel_spec *spec = codec->spec; |
| 4926 | int i, muted = 1; | 4975 | int i, num_ext_dacs, muted = 1; |
| 4976 | hda_nid_t nid; | ||
| 4927 | 4977 | ||
| 4928 | for (i = 0; i < spec->multiout.num_dacs; i++) { | 4978 | for (i = 0; i < spec->multiout.num_dacs; i++) { |
| 4929 | nid = spec->multiout.dac_nids[i]; | 4979 | nid = spec->multiout.dac_nids[i]; |
| @@ -4933,6 +4983,22 @@ static int stac92xx_hp_check_power_status(struct hda_codec *codec, | |||
| 4933 | break; | 4983 | break; |
| 4934 | } | 4984 | } |
| 4935 | } | 4985 | } |
| 4986 | if (muted && spec->multiout.hp_nid) | ||
| 4987 | if (!(snd_hda_codec_amp_read(codec, | ||
| 4988 | spec->multiout.hp_nid, 0, HDA_OUTPUT, 0) & | ||
| 4989 | HDA_AMP_MUTE)) { | ||
| 4990 | muted = 0; /* HP is not muted */ | ||
| 4991 | } | ||
| 4992 | num_ext_dacs = ARRAY_SIZE(spec->multiout.extra_out_nid); | ||
| 4993 | for (i = 0; muted && i < num_ext_dacs; i++) { | ||
| 4994 | nid = spec->multiout.extra_out_nid[i]; | ||
| 4995 | if (nid == 0) | ||
| 4996 | break; | ||
| 4997 | if (!(snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) & | ||
| 4998 | HDA_AMP_MUTE)) { | ||
| 4999 | muted = 0; /* extra output is not muted */ | ||
| 5000 | } | ||
| 5001 | } | ||
| 4936 | if (muted) | 5002 | if (muted) |
| 4937 | spec->gpio_data &= ~spec->gpio_led; /* orange */ | 5003 | spec->gpio_data &= ~spec->gpio_led; /* orange */ |
| 4938 | else | 5004 | else |
| @@ -4946,6 +5012,17 @@ static int stac92xx_hp_check_power_status(struct hda_codec *codec, | |||
| 4946 | stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data); | 5012 | stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data); |
| 4947 | return 0; | 5013 | return 0; |
| 4948 | } | 5014 | } |
| 5015 | |||
| 5016 | /* | ||
| 5017 | * use power check for controlling mute led of HP notebooks | ||
| 5018 | */ | ||
| 5019 | static int stac92xx_check_power_status(struct hda_codec *codec, | ||
| 5020 | hda_nid_t nid) | ||
| 5021 | { | ||
| 5022 | stac92xx_update_led_status(codec); | ||
| 5023 | |||
| 5024 | return 0; | ||
| 5025 | } | ||
| 4949 | #endif | 5026 | #endif |
| 4950 | 5027 | ||
| 4951 | static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) | 5028 | static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) |
| @@ -4953,7 +5030,7 @@ static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) | |||
| 4953 | stac92xx_shutup(codec); | 5030 | stac92xx_shutup(codec); |
| 4954 | return 0; | 5031 | return 0; |
| 4955 | } | 5032 | } |
| 4956 | #endif | 5033 | #endif /* CONFIG_PM */ |
| 4957 | 5034 | ||
| 4958 | static const struct hda_codec_ops stac92xx_patch_ops = { | 5035 | static const struct hda_codec_ops stac92xx_patch_ops = { |
| 4959 | .build_controls = stac92xx_build_controls, | 5036 | .build_controls = stac92xx_build_controls, |
| @@ -4961,9 +5038,10 @@ static const struct hda_codec_ops stac92xx_patch_ops = { | |||
| 4961 | .init = stac92xx_init, | 5038 | .init = stac92xx_init, |
| 4962 | .free = stac92xx_free, | 5039 | .free = stac92xx_free, |
| 4963 | .unsol_event = stac92xx_unsol_event, | 5040 | .unsol_event = stac92xx_unsol_event, |
| 4964 | #ifdef SND_HDA_NEEDS_RESUME | 5041 | #ifdef CONFIG_PM |
| 4965 | .suspend = stac92xx_suspend, | 5042 | .suspend = stac92xx_suspend, |
| 4966 | .resume = stac92xx_resume, | 5043 | .resume = stac92xx_resume, |
| 5044 | .pre_resume = stac92xx_pre_resume, | ||
| 4967 | #endif | 5045 | #endif |
| 4968 | .reboot_notify = stac92xx_shutup, | 5046 | .reboot_notify = stac92xx_shutup, |
| 4969 | }; | 5047 | }; |
| @@ -5482,7 +5560,7 @@ again: | |||
| 5482 | spec->gpio_data |= spec->gpio_led; | 5560 | spec->gpio_data |= spec->gpio_led; |
| 5483 | /* register check_power_status callback. */ | 5561 | /* register check_power_status callback. */ |
| 5484 | codec->patch_ops.check_power_status = | 5562 | codec->patch_ops.check_power_status = |
| 5485 | stac92xx_hp_check_power_status; | 5563 | stac92xx_check_power_status; |
| 5486 | } | 5564 | } |
| 5487 | #endif | 5565 | #endif |
| 5488 | 5566 | ||
| @@ -5810,7 +5888,7 @@ again: | |||
| 5810 | spec->gpio_data |= spec->gpio_led; | 5888 | spec->gpio_data |= spec->gpio_led; |
| 5811 | /* register check_power_status callback. */ | 5889 | /* register check_power_status callback. */ |
| 5812 | codec->patch_ops.check_power_status = | 5890 | codec->patch_ops.check_power_status = |
| 5813 | stac92xx_hp_check_power_status; | 5891 | stac92xx_check_power_status; |
| 5814 | } | 5892 | } |
| 5815 | #endif | 5893 | #endif |
| 5816 | 5894 | ||
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index f38160b00e16..84d8798bf33a 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c | |||
| @@ -1708,7 +1708,7 @@ static void via_unsol_event(struct hda_codec *codec, | |||
| 1708 | via_gpio_control(codec); | 1708 | via_gpio_control(codec); |
| 1709 | } | 1709 | } |
| 1710 | 1710 | ||
| 1711 | #ifdef SND_HDA_NEEDS_RESUME | 1711 | #ifdef CONFIG_PM |
| 1712 | static int via_suspend(struct hda_codec *codec, pm_message_t state) | 1712 | static int via_suspend(struct hda_codec *codec, pm_message_t state) |
| 1713 | { | 1713 | { |
| 1714 | struct via_spec *spec = codec->spec; | 1714 | struct via_spec *spec = codec->spec; |
| @@ -1736,7 +1736,7 @@ static const struct hda_codec_ops via_patch_ops = { | |||
| 1736 | .init = via_init, | 1736 | .init = via_init, |
| 1737 | .free = via_free, | 1737 | .free = via_free, |
| 1738 | .unsol_event = via_unsol_event, | 1738 | .unsol_event = via_unsol_event, |
| 1739 | #ifdef SND_HDA_NEEDS_RESUME | 1739 | #ifdef CONFIG_PM |
| 1740 | .suspend = via_suspend, | 1740 | .suspend = via_suspend, |
| 1741 | #endif | 1741 | #endif |
| 1742 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 1742 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index ff29380c9ed3..76258f2a2ffb 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c | |||
| @@ -907,6 +907,7 @@ static int ldo_regulator_register(struct snd_soc_codec *codec, | |||
| 907 | struct regulator_init_data *init_data, | 907 | struct regulator_init_data *init_data, |
| 908 | int voltage) | 908 | int voltage) |
| 909 | { | 909 | { |
| 910 | dev_err(codec->dev, "this setup needs regulator support in the kernel\n"); | ||
| 910 | return -EINVAL; | 911 | return -EINVAL; |
| 911 | } | 912 | } |
| 912 | 913 | ||
| @@ -1218,6 +1219,34 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec) | |||
| 1218 | return 0; | 1219 | return 0; |
| 1219 | } | 1220 | } |
| 1220 | 1221 | ||
| 1222 | static int sgtl5000_replace_vddd_with_ldo(struct snd_soc_codec *codec) | ||
| 1223 | { | ||
| 1224 | struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); | ||
| 1225 | int ret; | ||
| 1226 | |||
| 1227 | /* set internal ldo to 1.2v */ | ||
| 1228 | ret = ldo_regulator_register(codec, &ldo_init_data, LDO_VOLTAGE); | ||
| 1229 | if (ret) { | ||
| 1230 | dev_err(codec->dev, | ||
| 1231 | "Failed to register vddd internal supplies: %d\n", ret); | ||
| 1232 | return ret; | ||
| 1233 | } | ||
| 1234 | |||
| 1235 | sgtl5000->supplies[VDDD].supply = LDO_CONSUMER_NAME; | ||
| 1236 | |||
| 1237 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies), | ||
| 1238 | sgtl5000->supplies); | ||
| 1239 | |||
| 1240 | if (ret) { | ||
| 1241 | ldo_regulator_remove(codec); | ||
| 1242 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); | ||
| 1243 | return ret; | ||
| 1244 | } | ||
| 1245 | |||
| 1246 | dev_info(codec->dev, "Using internal LDO instead of VDDD\n"); | ||
| 1247 | return 0; | ||
| 1248 | } | ||
| 1249 | |||
| 1221 | static int sgtl5000_enable_regulators(struct snd_soc_codec *codec) | 1250 | static int sgtl5000_enable_regulators(struct snd_soc_codec *codec) |
| 1222 | { | 1251 | { |
| 1223 | u16 reg; | 1252 | u16 reg; |
| @@ -1235,30 +1264,9 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec) | |||
| 1235 | if (!ret) | 1264 | if (!ret) |
| 1236 | external_vddd = 1; | 1265 | external_vddd = 1; |
| 1237 | else { | 1266 | else { |
| 1238 | /* set internal ldo to 1.2v */ | 1267 | ret = sgtl5000_replace_vddd_with_ldo(codec); |
| 1239 | int voltage = LDO_VOLTAGE; | 1268 | if (ret) |
| 1240 | |||
| 1241 | ret = ldo_regulator_register(codec, &ldo_init_data, voltage); | ||
| 1242 | if (ret) { | ||
| 1243 | dev_err(codec->dev, | ||
| 1244 | "Failed to register vddd internal supplies: %d\n", | ||
| 1245 | ret); | ||
| 1246 | return ret; | ||
| 1247 | } | ||
| 1248 | |||
| 1249 | sgtl5000->supplies[VDDD].supply = LDO_CONSUMER_NAME; | ||
| 1250 | |||
| 1251 | ret = regulator_bulk_get(codec->dev, | ||
| 1252 | ARRAY_SIZE(sgtl5000->supplies), | ||
| 1253 | sgtl5000->supplies); | ||
| 1254 | |||
| 1255 | if (ret) { | ||
| 1256 | ldo_regulator_remove(codec); | ||
| 1257 | dev_err(codec->dev, | ||
| 1258 | "Failed to request supplies: %d\n", ret); | ||
| 1259 | |||
| 1260 | return ret; | 1269 | return ret; |
| 1261 | } | ||
| 1262 | } | 1270 | } |
| 1263 | 1271 | ||
| 1264 | ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies), | 1272 | ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies), |
| @@ -1287,7 +1295,6 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec) | |||
| 1287 | * roll back to use internal LDO | 1295 | * roll back to use internal LDO |
| 1288 | */ | 1296 | */ |
| 1289 | if (external_vddd && rev >= 0x11) { | 1297 | if (external_vddd && rev >= 0x11) { |
| 1290 | int voltage = LDO_VOLTAGE; | ||
| 1291 | /* disable all regulator first */ | 1298 | /* disable all regulator first */ |
| 1292 | regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies), | 1299 | regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies), |
| 1293 | sgtl5000->supplies); | 1300 | sgtl5000->supplies); |
| @@ -1295,23 +1302,10 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec) | |||
| 1295 | regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), | 1302 | regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), |
| 1296 | sgtl5000->supplies); | 1303 | sgtl5000->supplies); |
| 1297 | 1304 | ||
| 1298 | ret = ldo_regulator_register(codec, &ldo_init_data, voltage); | 1305 | ret = sgtl5000_replace_vddd_with_ldo(codec); |
| 1299 | if (ret) | 1306 | if (ret) |
| 1300 | return ret; | 1307 | return ret; |
| 1301 | 1308 | ||
| 1302 | sgtl5000->supplies[VDDD].supply = LDO_CONSUMER_NAME; | ||
| 1303 | |||
| 1304 | ret = regulator_bulk_get(codec->dev, | ||
| 1305 | ARRAY_SIZE(sgtl5000->supplies), | ||
| 1306 | sgtl5000->supplies); | ||
| 1307 | if (ret) { | ||
| 1308 | ldo_regulator_remove(codec); | ||
| 1309 | dev_err(codec->dev, | ||
| 1310 | "Failed to request supplies: %d\n", ret); | ||
| 1311 | |||
| 1312 | return ret; | ||
| 1313 | } | ||
| 1314 | |||
| 1315 | ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies), | 1309 | ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies), |
| 1316 | sgtl5000->supplies); | 1310 | sgtl5000->supplies); |
| 1317 | if (ret) | 1311 | if (ret) |
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 8499c563a9b5..60d740ebeb5b 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c | |||
| @@ -3409,6 +3409,9 @@ static irqreturn_t wm8962_irq(int irq, void *data) | |||
| 3409 | active = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2); | 3409 | active = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2); |
| 3410 | active &= ~mask; | 3410 | active &= ~mask; |
| 3411 | 3411 | ||
| 3412 | /* Acknowledge the interrupts */ | ||
| 3413 | snd_soc_write(codec, WM8962_INTERRUPT_STATUS_2, active); | ||
| 3414 | |||
| 3412 | if (active & WM8962_FLL_LOCK_EINT) { | 3415 | if (active & WM8962_FLL_LOCK_EINT) { |
| 3413 | dev_dbg(codec->dev, "FLL locked\n"); | 3416 | dev_dbg(codec->dev, "FLL locked\n"); |
| 3414 | complete(&wm8962->fll_lock); | 3417 | complete(&wm8962->fll_lock); |
| @@ -3433,9 +3436,6 @@ static irqreturn_t wm8962_irq(int irq, void *data) | |||
| 3433 | msecs_to_jiffies(250)); | 3436 | msecs_to_jiffies(250)); |
| 3434 | } | 3437 | } |
| 3435 | 3438 | ||
| 3436 | /* Acknowledge the interrupts */ | ||
| 3437 | snd_soc_write(codec, WM8962_INTERRUPT_STATUS_2, active); | ||
| 3438 | |||
| 3439 | return IRQ_HANDLED; | 3439 | return IRQ_HANDLED; |
| 3440 | } | 3440 | } |
| 3441 | 3441 | ||
diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/davinci/davinci-vcif.c index 9259f1f34899..1f11525d97e8 100644 --- a/sound/soc/davinci/davinci-vcif.c +++ b/sound/soc/davinci/davinci-vcif.c | |||
| @@ -62,9 +62,9 @@ static void davinci_vcif_start(struct snd_pcm_substream *substream) | |||
| 62 | w = readl(davinci_vc->base + DAVINCI_VC_CTRL); | 62 | w = readl(davinci_vc->base + DAVINCI_VC_CTRL); |
| 63 | 63 | ||
| 64 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 64 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
| 65 | MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 1); | 65 | MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 0); |
| 66 | else | 66 | else |
| 67 | MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 1); | 67 | MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 0); |
| 68 | 68 | ||
| 69 | writel(w, davinci_vc->base + DAVINCI_VC_CTRL); | 69 | writel(w, davinci_vc->base + DAVINCI_VC_CTRL); |
| 70 | } | 70 | } |
| @@ -80,9 +80,9 @@ static void davinci_vcif_stop(struct snd_pcm_substream *substream) | |||
| 80 | /* Reset transmitter/receiver and sample rate/frame sync generators */ | 80 | /* Reset transmitter/receiver and sample rate/frame sync generators */ |
| 81 | w = readl(davinci_vc->base + DAVINCI_VC_CTRL); | 81 | w = readl(davinci_vc->base + DAVINCI_VC_CTRL); |
| 82 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 82 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
| 83 | MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 0); | 83 | MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 1); |
| 84 | else | 84 | else |
| 85 | MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 0); | 85 | MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 1); |
| 86 | 86 | ||
| 87 | writel(w, davinci_vc->base + DAVINCI_VC_CTRL); | 87 | writel(w, davinci_vc->base + DAVINCI_VC_CTRL); |
| 88 | } | 88 | } |
| @@ -159,6 +159,7 @@ static int davinci_vcif_trigger(struct snd_pcm_substream *substream, int cmd, | |||
| 159 | case SNDRV_PCM_TRIGGER_RESUME: | 159 | case SNDRV_PCM_TRIGGER_RESUME: |
| 160 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 160 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
| 161 | davinci_vcif_start(substream); | 161 | davinci_vcif_start(substream); |
| 162 | break; | ||
| 162 | case SNDRV_PCM_TRIGGER_STOP: | 163 | case SNDRV_PCM_TRIGGER_STOP: |
| 163 | case SNDRV_PCM_TRIGGER_SUSPEND: | 164 | case SNDRV_PCM_TRIGGER_SUSPEND: |
| 164 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 165 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 1568eea31f41..c086b78539ee 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <plat/audio.h> | 21 | #include <plat/audio.h> |
| 22 | 22 | ||
| 23 | #include "dma.h" | 23 | #include "dma.h" |
| 24 | #include "idma.h" | ||
| 24 | #include "i2s.h" | 25 | #include "i2s.h" |
| 25 | #include "i2s-regs.h" | 26 | #include "i2s-regs.h" |
| 26 | 27 | ||
| @@ -60,6 +61,7 @@ struct i2s_dai { | |||
| 60 | /* DMA parameters */ | 61 | /* DMA parameters */ |
| 61 | struct s3c_dma_params dma_playback; | 62 | struct s3c_dma_params dma_playback; |
| 62 | struct s3c_dma_params dma_capture; | 63 | struct s3c_dma_params dma_capture; |
| 64 | struct s3c_dma_params idma_playback; | ||
| 63 | u32 quirks; | 65 | u32 quirks; |
| 64 | u32 suspend_i2smod; | 66 | u32 suspend_i2smod; |
| 65 | u32 suspend_i2scon; | 67 | u32 suspend_i2scon; |
| @@ -877,6 +879,10 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) | |||
| 877 | if (i2s->quirks & QUIRK_NEED_RSTCLR) | 879 | if (i2s->quirks & QUIRK_NEED_RSTCLR) |
| 878 | writel(CON_RSTCLR, i2s->addr + I2SCON); | 880 | writel(CON_RSTCLR, i2s->addr + I2SCON); |
| 879 | 881 | ||
| 882 | if (i2s->quirks & QUIRK_SEC_DAI) | ||
| 883 | idma_reg_addr_init((void *)i2s->addr, | ||
| 884 | i2s->sec_dai->idma_playback.dma_addr); | ||
| 885 | |||
| 880 | probe_exit: | 886 | probe_exit: |
| 881 | /* Reset any constraint on RFS and BFS */ | 887 | /* Reset any constraint on RFS and BFS */ |
| 882 | i2s->rfs = 0; | 888 | i2s->rfs = 0; |
| @@ -1077,6 +1083,7 @@ static __devinit int samsung_i2s_probe(struct platform_device *pdev) | |||
| 1077 | sec_dai->dma_playback.dma_size = 4; | 1083 | sec_dai->dma_playback.dma_size = 4; |
| 1078 | sec_dai->base = regs_base; | 1084 | sec_dai->base = regs_base; |
| 1079 | sec_dai->quirks = quirks; | 1085 | sec_dai->quirks = quirks; |
| 1086 | sec_dai->idma_playback.dma_addr = i2s_cfg->idma_addr; | ||
| 1080 | sec_dai->pri_dai = pri_dai; | 1087 | sec_dai->pri_dai = pri_dai; |
| 1081 | pri_dai->sec_dai = sec_dai; | 1088 | pri_dai->sec_dai = sec_dai; |
| 1082 | } | 1089 | } |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e44267f66216..83ad8ca27490 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
| @@ -577,6 +577,7 @@ int snd_soc_suspend(struct device *dev) | |||
| 577 | case SND_SOC_BIAS_OFF: | 577 | case SND_SOC_BIAS_OFF: |
| 578 | codec->driver->suspend(codec, PMSG_SUSPEND); | 578 | codec->driver->suspend(codec, PMSG_SUSPEND); |
| 579 | codec->suspended = 1; | 579 | codec->suspended = 1; |
| 580 | codec->cache_sync = 1; | ||
| 580 | break; | 581 | break; |
| 581 | default: | 582 | default: |
| 582 | dev_dbg(codec->dev, "CODEC is on over suspend\n"); | 583 | dev_dbg(codec->dev, "CODEC is on over suspend\n"); |
| @@ -1140,7 +1141,7 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order) | |||
| 1140 | } | 1141 | } |
| 1141 | } | 1142 | } |
| 1142 | cpu_dai->probed = 1; | 1143 | cpu_dai->probed = 1; |
| 1143 | /* mark cpu_dai as probed and add to card cpu_dai list */ | 1144 | /* mark cpu_dai as probed and add to card dai list */ |
| 1144 | list_add(&cpu_dai->card_list, &card->dai_dev_list); | 1145 | list_add(&cpu_dai->card_list, &card->dai_dev_list); |
| 1145 | } | 1146 | } |
| 1146 | 1147 | ||
| @@ -1171,7 +1172,7 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order) | |||
| 1171 | } | 1172 | } |
| 1172 | } | 1173 | } |
| 1173 | 1174 | ||
| 1174 | /* mark cpu_dai as probed and add to card cpu_dai list */ | 1175 | /* mark codec_dai as probed and add to card dai list */ |
| 1175 | codec_dai->probed = 1; | 1176 | codec_dai->probed = 1; |
| 1176 | list_add(&codec_dai->card_list, &card->dai_dev_list); | 1177 | list_add(&codec_dai->card_list, &card->dai_dev_list); |
| 1177 | } | 1178 | } |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index fbfcda062839..7e15914b3633 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
| @@ -124,6 +124,36 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget( | |||
| 124 | return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); | 124 | return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | /* get snd_card from DAPM context */ | ||
| 128 | static inline struct snd_card *dapm_get_snd_card( | ||
| 129 | struct snd_soc_dapm_context *dapm) | ||
| 130 | { | ||
| 131 | if (dapm->codec) | ||
| 132 | return dapm->codec->card->snd_card; | ||
| 133 | else if (dapm->platform) | ||
| 134 | return dapm->platform->card->snd_card; | ||
| 135 | else | ||
| 136 | BUG(); | ||
| 137 | |||
| 138 | /* unreachable */ | ||
| 139 | return NULL; | ||
| 140 | } | ||
| 141 | |||
| 142 | /* get soc_card from DAPM context */ | ||
| 143 | static inline struct snd_soc_card *dapm_get_soc_card( | ||
| 144 | struct snd_soc_dapm_context *dapm) | ||
| 145 | { | ||
| 146 | if (dapm->codec) | ||
| 147 | return dapm->codec->card; | ||
| 148 | else if (dapm->platform) | ||
| 149 | return dapm->platform->card; | ||
| 150 | else | ||
| 151 | BUG(); | ||
| 152 | |||
| 153 | /* unreachable */ | ||
| 154 | return NULL; | ||
| 155 | } | ||
| 156 | |||
| 127 | static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg) | 157 | static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg) |
| 128 | { | 158 | { |
| 129 | if (w->codec) | 159 | if (w->codec) |
