forked from Minki/linux
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6: (22 commits) ALSA: hda - Cirrus Logic CS421x support ALSA: Make pcm.h self-contained ALSA: hda - Allow codec-specific set_power_state ops ALSA: hda - Add post_suspend patch ops ALSA: hda - Make CONFIG_SND_HDA_POWER_SAVE depending on CONFIG_PM ALSA: hda - Make sure mute led reflects master mute state ALSA: hda - Fix invalid mute led state on resume of IDT codecs ASoC: Revert "ASoC: SAMSUNG: Add I2S0 internal dma driver" ALSA: hda - Add support of the 4 internal speakers on certain HP laptops ALSA: Make snd_pcm_debug_name usable outside pcm_lib ALSA: hda - Fix DAC filling for multi-connection pins in Realtek parser ASoC: dapm - Add methods to retrieve snd_card and soc_card from dapm context. ASoC: SAMSUNG: Add I2S0 internal dma driver ASoC: SAMSUNG: Modify I2S driver to support idma ASoC: davinci: add missing break statement ASoC: davinci: fix codec start and stop functions ASoC: dapm - add DAPM macro for external enum widgets ASoC: Acknowledge WM8962 interrupts before acting on them ASoC: sgtl5000: guide user when regulator support is needed ASoC: sgtl5000: refactor registering internal ldo ...
This commit is contained in:
commit
7562343716
@ -507,6 +507,18 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream);
|
||||
void snd_pcm_vma_notify_data(void *client, void *data);
|
||||
int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area);
|
||||
|
||||
|
||||
#ifdef CONFIG_SND_DEBUG
|
||||
void snd_pcm_debug_name(struct snd_pcm_substream *substream,
|
||||
char *name, size_t len);
|
||||
#else
|
||||
static inline void
|
||||
snd_pcm_debug_name(struct snd_pcm_substream *substream, char *buf, size_t size)
|
||||
{
|
||||
*buf = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* PCM library
|
||||
*/
|
||||
@ -749,17 +761,18 @@ static inline const struct snd_interval *hw_param_interval_c(const struct snd_pc
|
||||
return ¶ms->intervals[var - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL];
|
||||
}
|
||||
|
||||
#define params_access(p) ((__force snd_pcm_access_t)snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_ACCESS)))
|
||||
#define params_format(p) ((__force snd_pcm_format_t)snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_FORMAT)))
|
||||
#define params_subformat(p) snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_SUBFORMAT))
|
||||
#define params_channels(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_CHANNELS)->min
|
||||
#define params_rate(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_RATE)->min
|
||||
#define params_period_size(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_PERIOD_SIZE)->min
|
||||
#define params_period_bytes(p) ((params_period_size(p)*snd_pcm_format_physical_width(params_format(p))*params_channels(p))/8)
|
||||
#define params_periods(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_PERIODS)->min
|
||||
#define params_buffer_size(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_BUFFER_SIZE)->min
|
||||
#define params_buffer_bytes(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_BUFFER_BYTES)->min
|
||||
|
||||
#define params_channels(p) \
|
||||
(hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_CHANNELS)->min)
|
||||
#define params_rate(p) \
|
||||
(hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_RATE)->min)
|
||||
#define params_period_size(p) \
|
||||
(hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_PERIOD_SIZE)->min)
|
||||
#define params_periods(p) \
|
||||
(hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_PERIODS)->min)
|
||||
#define params_buffer_size(p) \
|
||||
(hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_BUFFER_SIZE)->min)
|
||||
#define params_buffer_bytes(p) \
|
||||
(hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_BUFFER_BYTES)->min)
|
||||
|
||||
int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v);
|
||||
void snd_interval_mul(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c);
|
||||
|
@ -337,5 +337,19 @@ static inline unsigned int sub(unsigned int a, unsigned int b)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __SOUND_PCM_PARAMS_H */
|
||||
#define params_access(p) ((__force snd_pcm_access_t)\
|
||||
snd_mask_min(hw_param_mask_c((p), SNDRV_PCM_HW_PARAM_ACCESS)))
|
||||
#define params_format(p) ((__force snd_pcm_format_t)\
|
||||
snd_mask_min(hw_param_mask_c((p), SNDRV_PCM_HW_PARAM_FORMAT)))
|
||||
#define params_subformat(p) \
|
||||
snd_mask_min(hw_param_mask_c((p), SNDRV_PCM_HW_PARAM_SUBFORMAT))
|
||||
|
||||
static inline unsigned int
|
||||
params_period_bytes(const struct snd_pcm_hw_params *p)
|
||||
{
|
||||
return (params_period_size(p) *
|
||||
snd_pcm_format_physical_width(params_format(p)) *
|
||||
params_channels(p)) / 8;
|
||||
}
|
||||
|
||||
#endif /* __SOUND_PCM_PARAMS_H */
|
||||
|
@ -266,6 +266,12 @@
|
||||
.get = snd_soc_dapm_get_enum_virt, \
|
||||
.put = snd_soc_dapm_put_enum_virt, \
|
||||
.private_value = (unsigned long)&xenum }
|
||||
#define SOC_DAPM_ENUM_EXT(xname, xenum, xget, xput) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_info_enum_double, \
|
||||
.get = xget, \
|
||||
.put = xput, \
|
||||
.private_value = (unsigned long)&xenum }
|
||||
#define SOC_DAPM_VALUE_ENUM(xname, xenum) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_info_enum_double, \
|
||||
|
@ -128,7 +128,8 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
|
||||
}
|
||||
}
|
||||
|
||||
static void pcm_debug_name(struct snd_pcm_substream *substream,
|
||||
#ifdef CONFIG_SND_DEBUG
|
||||
void snd_pcm_debug_name(struct snd_pcm_substream *substream,
|
||||
char *name, size_t len)
|
||||
{
|
||||
snprintf(name, len, "pcmC%dD%d%c:%d",
|
||||
@ -137,6 +138,8 @@ static void pcm_debug_name(struct snd_pcm_substream *substream,
|
||||
substream->stream ? 'c' : 'p',
|
||||
substream->number);
|
||||
}
|
||||
EXPORT_SYMBOL(snd_pcm_debug_name);
|
||||
#endif
|
||||
|
||||
#define XRUN_DEBUG_BASIC (1<<0)
|
||||
#define XRUN_DEBUG_STACK (1<<1) /* dump also stack */
|
||||
@ -168,7 +171,7 @@ static void xrun(struct snd_pcm_substream *substream)
|
||||
snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
|
||||
if (xrun_debug(substream, XRUN_DEBUG_BASIC)) {
|
||||
char name[16];
|
||||
pcm_debug_name(substream, name, sizeof(name));
|
||||
snd_pcm_debug_name(substream, name, sizeof(name));
|
||||
snd_printd(KERN_DEBUG "XRUN: %s\n", name);
|
||||
dump_stack_on_xrun(substream);
|
||||
}
|
||||
@ -243,7 +246,7 @@ static void xrun_log_show(struct snd_pcm_substream *substream)
|
||||
return;
|
||||
if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit)
|
||||
return;
|
||||
pcm_debug_name(substream, name, sizeof(name));
|
||||
snd_pcm_debug_name(substream, name, sizeof(name));
|
||||
for (cnt = 0, idx = log->idx; cnt < XRUN_LOG_CNT; cnt++) {
|
||||
entry = &log->entries[idx];
|
||||
if (entry->period_size == 0)
|
||||
@ -319,7 +322,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
|
||||
if (pos >= runtime->buffer_size) {
|
||||
if (printk_ratelimit()) {
|
||||
char name[16];
|
||||
pcm_debug_name(substream, name, sizeof(name));
|
||||
snd_pcm_debug_name(substream, name, sizeof(name));
|
||||
xrun_log_show(substream);
|
||||
snd_printd(KERN_ERR "BUG: %s, pos = %ld, "
|
||||
"buffer size = %ld, period size = %ld\n",
|
||||
@ -364,7 +367,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
|
||||
if (xrun_debug(substream, in_interrupt ?
|
||||
XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) {
|
||||
char name[16];
|
||||
pcm_debug_name(substream, name, sizeof(name));
|
||||
snd_pcm_debug_name(substream, name, sizeof(name));
|
||||
snd_printd("%s_update: %s: pos=%u/%u/%u, "
|
||||
"hwptr=%ld/%ld/%ld/%ld\n",
|
||||
in_interrupt ? "period" : "hwptr",
|
||||
|
@ -41,31 +41,10 @@
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/hwdep.h>
|
||||
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("AudioScience inc. <support@audioscience.com>");
|
||||
MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx");
|
||||
|
||||
#if defined CONFIG_SND_DEBUG
|
||||
/* copied from pcm_lib.c, hope later patch will make that version public
|
||||
and this copy can be removed */
|
||||
static inline void
|
||||
snd_pcm_debug_name(struct snd_pcm_substream *substream, char *buf, size_t size)
|
||||
{
|
||||
snprintf(buf, size, "pcmC%dD%d%c:%d",
|
||||
substream->pcm->card->number,
|
||||
substream->pcm->device,
|
||||
substream->stream ? 'c' : 'p',
|
||||
substream->number);
|
||||
}
|
||||
#else
|
||||
static inline void
|
||||
snd_pcm_debug_name(struct snd_pcm_substream *substream, char *buf, size_t size)
|
||||
{
|
||||
*buf = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined CONFIG_SND_DEBUG_VERBOSE
|
||||
/**
|
||||
* snd_printddd - very verbose debug printk
|
||||
|
@ -243,6 +243,7 @@ config SND_HDA_GENERIC
|
||||
|
||||
config SND_HDA_POWER_SAVE
|
||||
bool "Aggressive power-saving on HD-audio"
|
||||
depends on PM
|
||||
help
|
||||
Say Y here to enable more aggressive power-saving mode on
|
||||
HD-audio driver. The power-saving timeout can be configured
|
||||
|
@ -91,8 +91,10 @@ EXPORT_SYMBOL_HDA(snd_hda_delete_codec_preset);
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
static void hda_power_work(struct work_struct *work);
|
||||
static void hda_keep_power_on(struct hda_codec *codec);
|
||||
#define hda_codec_is_power_on(codec) ((codec)->power_on)
|
||||
#else
|
||||
static inline void hda_keep_power_on(struct hda_codec *codec) {}
|
||||
#define hda_codec_is_power_on(codec) 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -1101,7 +1103,7 @@ void snd_hda_shutup_pins(struct hda_codec *codec)
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_shutup_pins);
|
||||
|
||||
#ifdef SND_HDA_NEEDS_RESUME
|
||||
#ifdef CONFIG_PM
|
||||
/* Restore the pin controls cleared previously via snd_hda_shutup_pins() */
|
||||
static void restore_shutup_pins(struct hda_codec *codec)
|
||||
{
|
||||
@ -1499,7 +1501,7 @@ static void purify_inactive_streams(struct hda_codec *codec)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SND_HDA_NEEDS_RESUME
|
||||
#ifdef CONFIG_PM
|
||||
/* clean up all streams; called from suspend */
|
||||
static void hda_cleanup_all_streams(struct hda_codec *codec)
|
||||
{
|
||||
@ -1838,7 +1840,7 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_codec_amp_stereo);
|
||||
|
||||
#ifdef SND_HDA_NEEDS_RESUME
|
||||
#ifdef CONFIG_PM
|
||||
/**
|
||||
* snd_hda_codec_resume_amp - Resume all AMP commands from the cache
|
||||
* @codec: HD-audio codec
|
||||
@ -1868,7 +1870,7 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec)
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp);
|
||||
#endif /* SND_HDA_NEEDS_RESUME */
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir,
|
||||
unsigned int ofs)
|
||||
@ -3082,7 +3084,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls);
|
||||
|
||||
#ifdef SND_HDA_NEEDS_RESUME
|
||||
#ifdef CONFIG_PM
|
||||
/*
|
||||
* command cache
|
||||
*/
|
||||
@ -3199,53 +3201,32 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec,
|
||||
seq->param);
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_sequence_write_cache);
|
||||
#endif /* SND_HDA_NEEDS_RESUME */
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
/*
|
||||
* set power state of the codec
|
||||
*/
|
||||
static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
|
||||
unsigned int power_state)
|
||||
void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
|
||||
unsigned int power_state,
|
||||
bool eapd_workaround)
|
||||
{
|
||||
hda_nid_t nid;
|
||||
hda_nid_t nid = codec->start_nid;
|
||||
int i;
|
||||
|
||||
/* this delay seems necessary to avoid click noise at power-down */
|
||||
if (power_state == AC_PWRST_D3)
|
||||
msleep(100);
|
||||
snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
|
||||
power_state);
|
||||
/* partial workaround for "azx_get_response timeout" */
|
||||
if (power_state == AC_PWRST_D0 &&
|
||||
(codec->vendor_id & 0xffff0000) == 0x14f10000)
|
||||
msleep(10);
|
||||
|
||||
nid = codec->start_nid;
|
||||
for (i = 0; i < codec->num_nodes; i++, nid++) {
|
||||
unsigned int wcaps = get_wcaps(codec, nid);
|
||||
if (wcaps & AC_WCAP_POWER) {
|
||||
unsigned int wid_type = get_wcaps_type(wcaps);
|
||||
if (power_state == AC_PWRST_D3 &&
|
||||
wid_type == AC_WID_PIN) {
|
||||
unsigned int pincap;
|
||||
/*
|
||||
* don't power down the widget if it controls
|
||||
* eapd and EAPD_BTLENABLE is set.
|
||||
*/
|
||||
pincap = snd_hda_query_pin_caps(codec, nid);
|
||||
if (pincap & AC_PINCAP_EAPD) {
|
||||
int eapd = snd_hda_codec_read(codec,
|
||||
nid, 0,
|
||||
if (!(wcaps & AC_WCAP_POWER))
|
||||
continue;
|
||||
/* don't power down the widget if it controls eapd and
|
||||
* EAPD_BTLENABLE is set.
|
||||
*/
|
||||
if (eapd_workaround && power_state == AC_PWRST_D3 &&
|
||||
get_wcaps_type(wcaps) == AC_WID_PIN &&
|
||||
(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) {
|
||||
int eapd = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_EAPD_BTLENABLE, 0);
|
||||
eapd &= 0x02;
|
||||
if (eapd)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
snd_hda_codec_write(codec, nid, 0,
|
||||
AC_VERB_SET_POWER_STATE,
|
||||
power_state);
|
||||
if (eapd & 0x02)
|
||||
continue;
|
||||
}
|
||||
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE,
|
||||
power_state);
|
||||
}
|
||||
|
||||
if (power_state == AC_PWRST_D0) {
|
||||
@ -3262,6 +3243,26 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
|
||||
} while (time_after_eq(end_time, jiffies));
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_codec_set_power_to_all);
|
||||
|
||||
/*
|
||||
* set power state of the codec
|
||||
*/
|
||||
static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
|
||||
unsigned int power_state)
|
||||
{
|
||||
if (codec->patch_ops.set_power_state) {
|
||||
codec->patch_ops.set_power_state(codec, fg, power_state);
|
||||
return;
|
||||
}
|
||||
|
||||
/* this delay seems necessary to avoid click noise at power-down */
|
||||
if (power_state == AC_PWRST_D3)
|
||||
msleep(100);
|
||||
snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
|
||||
power_state);
|
||||
snd_hda_codec_set_power_to_all(codec, fg, power_state, true);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SND_HDA_HWDEP
|
||||
/* execute additional init verbs */
|
||||
@ -3274,7 +3275,7 @@ static void hda_exec_init_verbs(struct hda_codec *codec)
|
||||
static inline void hda_exec_init_verbs(struct hda_codec *codec) {}
|
||||
#endif
|
||||
|
||||
#ifdef SND_HDA_NEEDS_RESUME
|
||||
#ifdef CONFIG_PM
|
||||
/*
|
||||
* call suspend and power-down; used both from PM and power-save
|
||||
*/
|
||||
@ -3315,7 +3316,7 @@ static void hda_call_codec_resume(struct hda_codec *codec)
|
||||
snd_hda_codec_resume_cache(codec);
|
||||
}
|
||||
}
|
||||
#endif /* SND_HDA_NEEDS_RESUME */
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
|
||||
/**
|
||||
@ -4071,9 +4072,6 @@ int snd_hda_add_new_ctls(struct hda_codec *codec,
|
||||
EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls);
|
||||
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
|
||||
unsigned int power_state);
|
||||
|
||||
static void hda_power_work(struct work_struct *work)
|
||||
{
|
||||
struct hda_codec *codec =
|
||||
@ -4376,11 +4374,8 @@ void snd_hda_bus_reboot_notify(struct hda_bus *bus)
|
||||
if (!bus)
|
||||
return;
|
||||
list_for_each_entry(codec, &bus->codec_list, list) {
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
if (!codec->power_on)
|
||||
continue;
|
||||
#endif
|
||||
if (codec->patch_ops.reboot_notify)
|
||||
if (hda_codec_is_power_on(codec) &&
|
||||
codec->patch_ops.reboot_notify)
|
||||
codec->patch_ops.reboot_notify(codec);
|
||||
}
|
||||
}
|
||||
@ -5079,11 +5074,10 @@ int snd_hda_suspend(struct hda_bus *bus)
|
||||
struct hda_codec *codec;
|
||||
|
||||
list_for_each_entry(codec, &bus->codec_list, list) {
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
if (!codec->power_on)
|
||||
continue;
|
||||
#endif
|
||||
hda_call_codec_suspend(codec);
|
||||
if (hda_codec_is_power_on(codec))
|
||||
hda_call_codec_suspend(codec);
|
||||
if (codec->patch_ops.post_suspend)
|
||||
codec->patch_ops.post_suspend(codec);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -5103,6 +5097,8 @@ int snd_hda_resume(struct hda_bus *bus)
|
||||
struct hda_codec *codec;
|
||||
|
||||
list_for_each_entry(codec, &bus->codec_list, list) {
|
||||
if (codec->patch_ops.pre_resume)
|
||||
codec->patch_ops.pre_resume(codec);
|
||||
if (snd_hda_codec_needs_resume(codec))
|
||||
hda_call_codec_resume(codec);
|
||||
}
|
||||
|
@ -26,10 +26,6 @@
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/hwdep.h>
|
||||
|
||||
#if defined(CONFIG_PM) || defined(CONFIG_SND_HDA_POWER_SAVE)
|
||||
#define SND_HDA_NEEDS_RESUME /* resume control code is required */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* nodes
|
||||
*/
|
||||
@ -704,8 +700,12 @@ struct hda_codec_ops {
|
||||
int (*init)(struct hda_codec *codec);
|
||||
void (*free)(struct hda_codec *codec);
|
||||
void (*unsol_event)(struct hda_codec *codec, unsigned int res);
|
||||
#ifdef SND_HDA_NEEDS_RESUME
|
||||
void (*set_power_state)(struct hda_codec *codec, hda_nid_t fg,
|
||||
unsigned int power_state);
|
||||
#ifdef CONFIG_PM
|
||||
int (*suspend)(struct hda_codec *codec, pm_message_t state);
|
||||
int (*post_suspend)(struct hda_codec *codec);
|
||||
int (*pre_resume)(struct hda_codec *codec);
|
||||
int (*resume)(struct hda_codec *codec);
|
||||
#endif
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
@ -927,7 +927,7 @@ void snd_hda_sequence_write(struct hda_codec *codec,
|
||||
int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex);
|
||||
|
||||
/* cached write */
|
||||
#ifdef SND_HDA_NEEDS_RESUME
|
||||
#ifdef CONFIG_PM
|
||||
int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
|
||||
int direct, unsigned int verb, unsigned int parm);
|
||||
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,
|
||||
*/
|
||||
void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen);
|
||||
void snd_hda_bus_reboot_notify(struct hda_bus *bus);
|
||||
void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
|
||||
unsigned int power_state,
|
||||
bool eapd_workaround);
|
||||
|
||||
/*
|
||||
* power management
|
||||
|
@ -131,7 +131,7 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
|
||||
int direction, int idx, int mask, int val);
|
||||
int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
|
||||
int dir, int idx, int mask, int val);
|
||||
#ifdef SND_HDA_NEEDS_RESUME
|
||||
#ifdef CONFIG_PM
|
||||
void snd_hda_codec_resume_amp(struct hda_codec *codec);
|
||||
#endif
|
||||
|
||||
|
@ -563,7 +563,7 @@ static void ad198x_free(struct hda_codec *codec)
|
||||
snd_hda_detach_beep_device(codec);
|
||||
}
|
||||
|
||||
#ifdef SND_HDA_NEEDS_RESUME
|
||||
#ifdef CONFIG_PM
|
||||
static int ad198x_suspend(struct hda_codec *codec, pm_message_t state)
|
||||
{
|
||||
ad198x_shutup(codec);
|
||||
@ -579,7 +579,7 @@ static const struct hda_codec_ops ad198x_patch_ops = {
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
.check_power_status = ad198x_check_power_status,
|
||||
#endif
|
||||
#ifdef SND_HDA_NEEDS_RESUME
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ad198x_suspend,
|
||||
#endif
|
||||
.reboot_notify = ad198x_shutup,
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <sound/core.h>
|
||||
#include "hda_codec.h"
|
||||
#include "hda_local.h"
|
||||
#include <sound/tlv.h>
|
||||
|
||||
/*
|
||||
*/
|
||||
@ -61,9 +62,15 @@ struct cs_spec {
|
||||
|
||||
unsigned int hp_detect:1;
|
||||
unsigned int mic_detect:1;
|
||||
/* CS421x */
|
||||
unsigned int spdif_detect:1;
|
||||
unsigned int sense_b:1;
|
||||
hda_nid_t vendor_nid;
|
||||
struct hda_input_mux input_mux;
|
||||
unsigned int last_input;
|
||||
};
|
||||
|
||||
/* available models */
|
||||
/* available models with CS420x */
|
||||
enum {
|
||||
CS420X_MBP53,
|
||||
CS420X_MBP55,
|
||||
@ -72,6 +79,12 @@ enum {
|
||||
CS420X_MODELS
|
||||
};
|
||||
|
||||
/* CS421x boards */
|
||||
enum {
|
||||
CS421X_CDB4210,
|
||||
CS421X_MODELS
|
||||
};
|
||||
|
||||
/* Vendor-specific processing widget */
|
||||
#define CS420X_VENDOR_NID 0x11
|
||||
#define CS_DIG_OUT1_PIN_NID 0x10
|
||||
@ -111,21 +124,42 @@ enum {
|
||||
/* 0x0009 - 0x0014 -> 12 test regs */
|
||||
/* 0x0015 - visibility reg */
|
||||
|
||||
/*
|
||||
* Cirrus Logic CS4210
|
||||
*
|
||||
* 1 DAC => HP(sense) / Speakers,
|
||||
* 1 ADC <= LineIn(sense) / MicIn / DMicIn,
|
||||
* 1 SPDIF OUT => SPDIF Trasmitter(sense)
|
||||
*/
|
||||
#define CS4210_DAC_NID 0x02
|
||||
#define CS4210_ADC_NID 0x03
|
||||
#define CS421X_VENDOR_NID 0x0B
|
||||
#define CS421X_DMIC_PIN_NID 0x09 /* Port E */
|
||||
#define CS421X_SPDIF_PIN_NID 0x0A /* Port H */
|
||||
|
||||
#define CS421X_IDX_DEV_CFG 0x01
|
||||
#define CS421X_IDX_ADC_CFG 0x02
|
||||
#define CS421X_IDX_DAC_CFG 0x03
|
||||
#define CS421X_IDX_SPK_CTL 0x04
|
||||
|
||||
#define SPDIF_EVENT 0x04
|
||||
|
||||
static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx)
|
||||
{
|
||||
snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0,
|
||||
struct cs_spec *spec = codec->spec;
|
||||
snd_hda_codec_write(codec, spec->vendor_nid, 0,
|
||||
AC_VERB_SET_COEF_INDEX, idx);
|
||||
return snd_hda_codec_read(codec, CS420X_VENDOR_NID, 0,
|
||||
return snd_hda_codec_read(codec, spec->vendor_nid, 0,
|
||||
AC_VERB_GET_PROC_COEF, 0);
|
||||
}
|
||||
|
||||
static inline void cs_vendor_coef_set(struct hda_codec *codec, unsigned int idx,
|
||||
unsigned int coef)
|
||||
{
|
||||
snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0,
|
||||
struct cs_spec *spec = codec->spec;
|
||||
snd_hda_codec_write(codec, spec->vendor_nid, 0,
|
||||
AC_VERB_SET_COEF_INDEX, idx);
|
||||
snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0,
|
||||
snd_hda_codec_write(codec, spec->vendor_nid, 0,
|
||||
AC_VERB_SET_PROC_COEF, coef);
|
||||
}
|
||||
|
||||
@ -347,15 +381,12 @@ static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin,
|
||||
nid = codec->start_nid;
|
||||
for (i = 0; i < codec->num_nodes; i++, nid++) {
|
||||
unsigned int type;
|
||||
int idx;
|
||||
type = get_wcaps_type(get_wcaps(codec, nid));
|
||||
if (type != AC_WID_AUD_IN)
|
||||
continue;
|
||||
idx = snd_hda_get_conn_index(codec, nid, pin, 0);
|
||||
if (idx >= 0) {
|
||||
*idxp = idx;
|
||||
*idxp = snd_hda_get_conn_index(codec, nid, pin, false);
|
||||
if (*idxp >= 0)
|
||||
return nid;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -835,6 +866,8 @@ static int build_digital_input(struct hda_codec *codec)
|
||||
|
||||
/*
|
||||
* auto-mute and auto-mic switching
|
||||
* CS421x auto-output redirecting
|
||||
* HP/SPK/SPDIF
|
||||
*/
|
||||
|
||||
static void cs_automute(struct hda_codec *codec)
|
||||
@ -842,9 +875,25 @@ static void cs_automute(struct hda_codec *codec)
|
||||
struct cs_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
unsigned int hp_present;
|
||||
unsigned int spdif_present;
|
||||
hda_nid_t nid;
|
||||
int i;
|
||||
|
||||
spdif_present = 0;
|
||||
if (cfg->dig_outs) {
|
||||
nid = cfg->dig_out_pins[0];
|
||||
if (is_jack_detectable(codec, nid)) {
|
||||
/*
|
||||
TODO: SPDIF output redirect when SENSE_B is enabled.
|
||||
Shared (SENSE_A) jack (e.g HP/mini-TOSLINK)
|
||||
assumed.
|
||||
*/
|
||||
if (snd_hda_jack_detect(codec, nid)
|
||||
/* && spec->sense_b */)
|
||||
spdif_present = 1;
|
||||
}
|
||||
}
|
||||
|
||||
hp_present = 0;
|
||||
for (i = 0; i < cfg->hp_outs; i++) {
|
||||
nid = cfg->hp_pins[i];
|
||||
@ -854,11 +903,19 @@ static void cs_automute(struct hda_codec *codec)
|
||||
if (hp_present)
|
||||
break;
|
||||
}
|
||||
|
||||
/* mute speakers if spdif or hp jack is plugged in */
|
||||
for (i = 0; i < cfg->speaker_outs; i++) {
|
||||
nid = cfg->speaker_pins[i];
|
||||
snd_hda_codec_write(codec, nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
hp_present ? 0 : PIN_OUT);
|
||||
/* detect on spdif is specific to CS421x */
|
||||
if (spec->vendor_nid == CS421X_VENDOR_NID) {
|
||||
snd_hda_codec_write(codec, nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
spdif_present ? 0 : PIN_OUT);
|
||||
}
|
||||
}
|
||||
if (spec->board_config == CS420X_MBP53 ||
|
||||
spec->board_config == CS420X_MBP55 ||
|
||||
@ -867,21 +924,62 @@ static void cs_automute(struct hda_codec *codec)
|
||||
snd_hda_codec_write(codec, 0x01, 0,
|
||||
AC_VERB_SET_GPIO_DATA, gpio);
|
||||
}
|
||||
|
||||
/* specific to CS421x */
|
||||
if (spec->vendor_nid == CS421X_VENDOR_NID) {
|
||||
/* mute HPs if spdif jack (SENSE_B) is present */
|
||||
for (i = 0; i < cfg->hp_outs; i++) {
|
||||
nid = cfg->hp_pins[i];
|
||||
snd_hda_codec_write(codec, nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
(spdif_present && spec->sense_b) ? 0 : PIN_HP);
|
||||
}
|
||||
|
||||
/* SPDIF TX on/off */
|
||||
if (cfg->dig_outs) {
|
||||
nid = cfg->dig_out_pins[0];
|
||||
snd_hda_codec_write(codec, nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
spdif_present ? PIN_OUT : 0);
|
||||
|
||||
}
|
||||
/* Update board GPIOs if neccessary ... */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Auto-input redirect for CS421x
|
||||
* Switch max 3 inputs of a single ADC (nid 3)
|
||||
*/
|
||||
|
||||
static void cs_automic(struct hda_codec *codec)
|
||||
{
|
||||
struct cs_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
hda_nid_t nid;
|
||||
unsigned int present;
|
||||
|
||||
|
||||
nid = cfg->inputs[spec->automic_idx].pin;
|
||||
present = snd_hda_jack_detect(codec, nid);
|
||||
if (present)
|
||||
change_cur_input(codec, spec->automic_idx, 0);
|
||||
else
|
||||
change_cur_input(codec, !spec->automic_idx, 0);
|
||||
|
||||
/* specific to CS421x, single ADC */
|
||||
if (spec->vendor_nid == CS421X_VENDOR_NID) {
|
||||
if (present) {
|
||||
spec->last_input = spec->cur_input;
|
||||
spec->cur_input = spec->automic_idx;
|
||||
} else {
|
||||
spec->cur_input = spec->last_input;
|
||||
}
|
||||
|
||||
snd_hda_codec_write_cache(codec, spec->cur_adc, 0,
|
||||
AC_VERB_SET_CONNECT_SEL,
|
||||
spec->adc_idx[spec->cur_input]);
|
||||
} else {
|
||||
if (present)
|
||||
change_cur_input(codec, spec->automic_idx, 0);
|
||||
else
|
||||
change_cur_input(codec, !spec->automic_idx, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -911,23 +1009,28 @@ static void init_output(struct hda_codec *codec)
|
||||
for (i = 0; i < cfg->line_outs; i++)
|
||||
snd_hda_codec_write(codec, cfg->line_out_pins[i], 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
|
||||
/* HP */
|
||||
for (i = 0; i < cfg->hp_outs; i++) {
|
||||
hda_nid_t nid = cfg->hp_pins[i];
|
||||
snd_hda_codec_write(codec, nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
|
||||
if (!cfg->speaker_outs)
|
||||
continue;
|
||||
if (is_jack_detectable(codec, nid)) {
|
||||
if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
|
||||
snd_hda_codec_write(codec, nid, 0,
|
||||
AC_VERB_SET_UNSOLICITED_ENABLE,
|
||||
AC_USRSP_EN | HP_EVENT);
|
||||
spec->hp_detect = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Speaker */
|
||||
for (i = 0; i < cfg->speaker_outs; i++)
|
||||
snd_hda_codec_write(codec, cfg->speaker_pins[i], 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
|
||||
if (spec->hp_detect)
|
||||
|
||||
/* SPDIF is enabled on presence detect for CS421x */
|
||||
if (spec->hp_detect || spec->spdif_detect)
|
||||
cs_automute(codec);
|
||||
}
|
||||
|
||||
@ -961,19 +1064,31 @@ static void init_input(struct hda_codec *codec)
|
||||
AC_VERB_SET_UNSOLICITED_ENABLE,
|
||||
AC_USRSP_EN | MIC_EVENT);
|
||||
}
|
||||
change_cur_input(codec, spec->cur_input, 1);
|
||||
if (spec->mic_detect)
|
||||
cs_automic(codec);
|
||||
/* specific to CS421x */
|
||||
if (spec->vendor_nid == CS421X_VENDOR_NID) {
|
||||
if (spec->mic_detect)
|
||||
cs_automic(codec);
|
||||
else {
|
||||
spec->cur_adc = spec->adc_nid[spec->cur_input];
|
||||
snd_hda_codec_write(codec, spec->cur_adc, 0,
|
||||
AC_VERB_SET_CONNECT_SEL,
|
||||
spec->adc_idx[spec->cur_input]);
|
||||
}
|
||||
} else {
|
||||
change_cur_input(codec, spec->cur_input, 1);
|
||||
if (spec->mic_detect)
|
||||
cs_automic(codec);
|
||||
|
||||
coef = 0x000a; /* ADC1/2 - Digital and Analog Soft Ramp */
|
||||
if (is_active_pin(codec, CS_DMIC2_PIN_NID))
|
||||
coef |= 0x0500; /* DMIC2 enable 2 channels, disable GPIO1 */
|
||||
if (is_active_pin(codec, CS_DMIC1_PIN_NID))
|
||||
coef |= 0x1800; /* DMIC1 enable 2 channels, disable GPIO0
|
||||
* No effect if SPDIF_OUT2 is selected in
|
||||
* IDX_SPDIF_CTL.
|
||||
*/
|
||||
cs_vendor_coef_set(codec, IDX_ADC_CFG, coef);
|
||||
coef = 0x000a; /* ADC1/2 - Digital and Analog Soft Ramp */
|
||||
if (is_active_pin(codec, CS_DMIC2_PIN_NID))
|
||||
coef |= 0x0500; /* DMIC2 2 chan on, GPIO1 off */
|
||||
if (is_active_pin(codec, CS_DMIC1_PIN_NID))
|
||||
coef |= 0x1800; /* DMIC1 2 chan on, GPIO0 off
|
||||
* No effect if SPDIF_OUT2 is
|
||||
* selected in IDX_SPDIF_CTL.
|
||||
*/
|
||||
cs_vendor_coef_set(codec, IDX_ADC_CFG, coef);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct hda_verb cs_coef_init_verbs[] = {
|
||||
@ -1221,16 +1336,16 @@ static const struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = {
|
||||
[CS420X_IMAC27] = imac27_pincfgs,
|
||||
};
|
||||
|
||||
static void fix_pincfg(struct hda_codec *codec, int model)
|
||||
static void fix_pincfg(struct hda_codec *codec, int model,
|
||||
const struct cs_pincfg **pin_configs)
|
||||
{
|
||||
const struct cs_pincfg *cfg = cs_pincfgs[model];
|
||||
const struct cs_pincfg *cfg = pin_configs[model];
|
||||
if (!cfg)
|
||||
return;
|
||||
for (; cfg->nid; cfg++)
|
||||
snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
|
||||
}
|
||||
|
||||
|
||||
static int patch_cs420x(struct hda_codec *codec)
|
||||
{
|
||||
struct cs_spec *spec;
|
||||
@ -1241,11 +1356,13 @@ static int patch_cs420x(struct hda_codec *codec)
|
||||
return -ENOMEM;
|
||||
codec->spec = spec;
|
||||
|
||||
spec->vendor_nid = CS420X_VENDOR_NID;
|
||||
|
||||
spec->board_config =
|
||||
snd_hda_check_board_config(codec, CS420X_MODELS,
|
||||
cs420x_models, cs420x_cfg_tbl);
|
||||
if (spec->board_config >= 0)
|
||||
fix_pincfg(codec, spec->board_config);
|
||||
fix_pincfg(codec, spec->board_config, cs_pincfgs);
|
||||
|
||||
switch (spec->board_config) {
|
||||
case CS420X_IMAC27:
|
||||
@ -1272,6 +1389,562 @@ static int patch_cs420x(struct hda_codec *codec)
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cirrus Logic CS4210
|
||||
*
|
||||
* 1 DAC => HP(sense) / Speakers,
|
||||
* 1 ADC <= LineIn(sense) / MicIn / DMicIn,
|
||||
* 1 SPDIF OUT => SPDIF Trasmitter(sense)
|
||||
*/
|
||||
|
||||
/* CS4210 board names */
|
||||
static const char *cs421x_models[CS421X_MODELS] = {
|
||||
[CS421X_CDB4210] = "cdb4210",
|
||||
};
|
||||
|
||||
static const struct snd_pci_quirk cs421x_cfg_tbl[] = {
|
||||
/* Test Intel board + CDB2410 */
|
||||
SND_PCI_QUIRK(0x8086, 0x5001, "DP45SG/CDB4210", CS421X_CDB4210),
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
/* CS4210 board pinconfigs */
|
||||
/* Default CS4210 (CDB4210)*/
|
||||
static const struct cs_pincfg cdb4210_pincfgs[] = {
|
||||
{ 0x05, 0x0321401f },
|
||||
{ 0x06, 0x90170010 },
|
||||
{ 0x07, 0x03813031 },
|
||||
{ 0x08, 0xb7a70037 },
|
||||
{ 0x09, 0xb7a6003e },
|
||||
{ 0x0a, 0x034510f0 },
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
static const struct cs_pincfg *cs421x_pincfgs[CS421X_MODELS] = {
|
||||
[CS421X_CDB4210] = cdb4210_pincfgs,
|
||||
};
|
||||
|
||||
static const struct hda_verb cs421x_coef_init_verbs[] = {
|
||||
{0x0B, AC_VERB_SET_PROC_STATE, 1},
|
||||
{0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DEV_CFG},
|
||||
/*
|
||||
Disable Coefficient Index Auto-Increment(DAI)=1,
|
||||
PDREF=0
|
||||
*/
|
||||
{0x0B, AC_VERB_SET_PROC_COEF, 0x0001 },
|
||||
|
||||
{0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_ADC_CFG},
|
||||
/* ADC SZCMode = Digital Soft Ramp */
|
||||
{0x0B, AC_VERB_SET_PROC_COEF, 0x0002 },
|
||||
|
||||
{0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DAC_CFG},
|
||||
{0x0B, AC_VERB_SET_PROC_COEF,
|
||||
(0x0002 /* DAC SZCMode = Digital Soft Ramp */
|
||||
| 0x0004 /* Mute DAC on FIFO error */
|
||||
| 0x0008 /* Enable DAC High Pass Filter */
|
||||
)},
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
/* Errata: CS4210 rev A1 Silicon
|
||||
*
|
||||
* http://www.cirrus.com/en/pubs/errata/
|
||||
*
|
||||
* Description:
|
||||
* 1. Performance degredation is present in the ADC.
|
||||
* 2. Speaker output is not completely muted upon HP detect.
|
||||
* 3. Noise is present when clipping occurs on the amplified
|
||||
* speaker outputs.
|
||||
*
|
||||
* Workaround:
|
||||
* The following verb sequence written to the registers during
|
||||
* initialization will correct the issues listed above.
|
||||
*/
|
||||
|
||||
static const struct hda_verb cs421x_coef_init_verbs_A1_silicon_fixes[] = {
|
||||
{0x0B, AC_VERB_SET_PROC_STATE, 0x01}, /* VPW: processing on */
|
||||
|
||||
{0x0B, AC_VERB_SET_COEF_INDEX, 0x0006},
|
||||
{0x0B, AC_VERB_SET_PROC_COEF, 0x9999}, /* Test mode: on */
|
||||
|
||||
{0x0B, AC_VERB_SET_COEF_INDEX, 0x000A},
|
||||
{0x0B, AC_VERB_SET_PROC_COEF, 0x14CB}, /* Chop double */
|
||||
|
||||
{0x0B, AC_VERB_SET_COEF_INDEX, 0x0011},
|
||||
{0x0B, AC_VERB_SET_PROC_COEF, 0xA2D0}, /* Increase ADC current */
|
||||
|
||||
{0x0B, AC_VERB_SET_COEF_INDEX, 0x001A},
|
||||
{0x0B, AC_VERB_SET_PROC_COEF, 0x02A9}, /* Mute speaker */
|
||||
|
||||
{0x0B, AC_VERB_SET_COEF_INDEX, 0x001B},
|
||||
{0x0B, AC_VERB_SET_PROC_COEF, 0X1006}, /* Remove noise */
|
||||
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
/* Speaker Amp Gain is controlled by the vendor widget's coef 4 */
|
||||
static const DECLARE_TLV_DB_SCALE(cs421x_speaker_boost_db_scale, 900, 300, 0);
|
||||
|
||||
static int cs421x_boost_vol_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->count = 1;
|
||||
uinfo->value.integer.min = 0;
|
||||
uinfo->value.integer.max = 3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs421x_boost_vol_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
|
||||
ucontrol->value.integer.value[0] =
|
||||
cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL) & 0x0003;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs421x_boost_vol_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
|
||||
unsigned int vol = ucontrol->value.integer.value[0];
|
||||
unsigned int coef =
|
||||
cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL);
|
||||
unsigned int original_coef = coef;
|
||||
|
||||
coef &= ~0x0003;
|
||||
coef |= (vol & 0x0003);
|
||||
if (original_coef == coef)
|
||||
return 0;
|
||||
else {
|
||||
cs_vendor_coef_set(codec, CS421X_IDX_SPK_CTL, coef);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new cs421x_speaker_bost_ctl = {
|
||||
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||
.name = "Speaker Boost Playback Volume",
|
||||
.info = cs421x_boost_vol_info,
|
||||
.get = cs421x_boost_vol_get,
|
||||
.put = cs421x_boost_vol_put,
|
||||
.tlv = { .p = cs421x_speaker_boost_db_scale },
|
||||
};
|
||||
|
||||
static void cs421x_pinmux_init(struct hda_codec *codec)
|
||||
{
|
||||
struct cs_spec *spec = codec->spec;
|
||||
unsigned int def_conf, coef;
|
||||
|
||||
/* GPIO, DMIC_SCL, DMIC_SDA and SENSE_B are multiplexed */
|
||||
coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG);
|
||||
|
||||
if (spec->gpio_mask)
|
||||
coef |= 0x0008; /* B1,B2 are GPIOs */
|
||||
else
|
||||
coef &= ~0x0008;
|
||||
|
||||
if (spec->sense_b)
|
||||
coef |= 0x0010; /* B2 is SENSE_B, not inverted */
|
||||
else
|
||||
coef &= ~0x0010;
|
||||
|
||||
cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef);
|
||||
|
||||
if ((spec->gpio_mask || spec->sense_b) &&
|
||||
is_active_pin(codec, CS421X_DMIC_PIN_NID)) {
|
||||
|
||||
/*
|
||||
GPIO or SENSE_B forced - disconnect the DMIC pin.
|
||||
*/
|
||||
def_conf = snd_hda_codec_get_pincfg(codec, CS421X_DMIC_PIN_NID);
|
||||
def_conf &= ~AC_DEFCFG_PORT_CONN;
|
||||
def_conf |= (AC_JACK_PORT_NONE << AC_DEFCFG_PORT_CONN_SHIFT);
|
||||
snd_hda_codec_set_pincfg(codec, CS421X_DMIC_PIN_NID, def_conf);
|
||||
}
|
||||
}
|
||||
|
||||
static void init_cs421x_digital(struct hda_codec *codec)
|
||||
{
|
||||
struct cs_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
int i;
|
||||
|
||||
|
||||
for (i = 0; i < cfg->dig_outs; i++) {
|
||||
hda_nid_t nid = cfg->dig_out_pins[i];
|
||||
if (!cfg->speaker_outs)
|
||||
continue;
|
||||
if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
|
||||
|
||||
snd_hda_codec_write(codec, nid, 0,
|
||||
AC_VERB_SET_UNSOLICITED_ENABLE,
|
||||
AC_USRSP_EN | SPDIF_EVENT);
|
||||
spec->spdif_detect = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int cs421x_init(struct hda_codec *codec)
|
||||
{
|
||||
struct cs_spec *spec = codec->spec;
|
||||
|
||||
snd_hda_sequence_write(codec, cs421x_coef_init_verbs);
|
||||
snd_hda_sequence_write(codec, cs421x_coef_init_verbs_A1_silicon_fixes);
|
||||
|
||||
cs421x_pinmux_init(codec);
|
||||
|
||||
if (spec->gpio_mask) {
|
||||
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
|
||||
spec->gpio_mask);
|
||||
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
|
||||
spec->gpio_dir);
|
||||
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
|
||||
spec->gpio_data);
|
||||
}
|
||||
|
||||
init_output(codec);
|
||||
init_input(codec);
|
||||
init_cs421x_digital(codec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* CS4210 Input MUX (1 ADC)
|
||||
*/
|
||||
static int cs421x_mux_enum_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct cs_spec *spec = codec->spec;
|
||||
|
||||
return snd_hda_input_mux_info(&spec->input_mux, uinfo);
|
||||
}
|
||||
|
||||
static int cs421x_mux_enum_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct cs_spec *spec = codec->spec;
|
||||
|
||||
ucontrol->value.enumerated.item[0] = spec->cur_input;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs421x_mux_enum_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct cs_spec *spec = codec->spec;
|
||||
|
||||
return snd_hda_input_mux_put(codec, &spec->input_mux, ucontrol,
|
||||
spec->adc_nid[0], &spec->cur_input);
|
||||
|
||||
}
|
||||
|
||||
static struct snd_kcontrol_new cs421x_capture_source = {
|
||||
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Capture Source",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
|
||||
.info = cs421x_mux_enum_info,
|
||||
.get = cs421x_mux_enum_get,
|
||||
.put = cs421x_mux_enum_put,
|
||||
};
|
||||
|
||||
static int cs421x_add_input_volume_control(struct hda_codec *codec, int item)
|
||||
{
|
||||
struct cs_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
const struct hda_input_mux *imux = &spec->input_mux;
|
||||
hda_nid_t pin = cfg->inputs[item].pin;
|
||||
struct snd_kcontrol *kctl;
|
||||
u32 caps;
|
||||
|
||||
if (!(get_wcaps(codec, pin) & AC_WCAP_IN_AMP))
|
||||
return 0;
|
||||
|
||||
caps = query_amp_caps(codec, pin, HDA_INPUT);
|
||||
caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
|
||||
if (caps <= 1)
|
||||
return 0;
|
||||
|
||||
return add_volume(codec, imux->items[item].label, 0,
|
||||
HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT), 1, &kctl);
|
||||
}
|
||||
|
||||
/* add a (input-boost) volume control to the given input pin */
|
||||
static int build_cs421x_input(struct hda_codec *codec)
|
||||
{
|
||||
struct cs_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
struct hda_input_mux *imux = &spec->input_mux;
|
||||
int i, err, type_idx;
|
||||
const char *label;
|
||||
|
||||
if (!spec->num_inputs)
|
||||
return 0;
|
||||
|
||||
/* make bind-capture */
|
||||
spec->capture_bind[0] = make_bind_capture(codec, &snd_hda_bind_sw);
|
||||
spec->capture_bind[1] = make_bind_capture(codec, &snd_hda_bind_vol);
|
||||
for (i = 0; i < 2; i++) {
|
||||
struct snd_kcontrol *kctl;
|
||||
int n;
|
||||
if (!spec->capture_bind[i])
|
||||
return -ENOMEM;
|
||||
kctl = snd_ctl_new1(&cs_capture_ctls[i], codec);
|
||||
if (!kctl)
|
||||
return -ENOMEM;
|
||||
kctl->private_value = (long)spec->capture_bind[i];
|
||||
err = snd_hda_ctl_add(codec, 0, kctl);
|
||||
if (err < 0)
|
||||
return err;
|
||||
for (n = 0; n < AUTO_PIN_LAST; n++) {
|
||||
if (!spec->adc_nid[n])
|
||||
continue;
|
||||
err = snd_hda_add_nid(codec, kctl, 0, spec->adc_nid[n]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add Input MUX Items + Capture Volume/Switch */
|
||||
for (i = 0; i < spec->num_inputs; i++) {
|
||||
label = hda_get_autocfg_input_label(codec, cfg, i);
|
||||
snd_hda_add_imux_item(imux, label, spec->adc_idx[i], &type_idx);
|
||||
|
||||
err = cs421x_add_input_volume_control(codec, i);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
Add 'Capture Source' Switch if
|
||||
* 2 inputs and no mic detec
|
||||
* 3 inputs
|
||||
*/
|
||||
if ((spec->num_inputs == 2 && !spec->mic_detect) ||
|
||||
(spec->num_inputs == 3)) {
|
||||
|
||||
err = snd_hda_ctl_add(codec, spec->adc_nid[0],
|
||||
snd_ctl_new1(&cs421x_capture_source, codec));
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Single DAC (Mute/Gain) */
|
||||
static int build_cs421x_output(struct hda_codec *codec)
|
||||
{
|
||||
hda_nid_t dac = CS4210_DAC_NID;
|
||||
struct cs_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
struct snd_kcontrol *kctl;
|
||||
int err;
|
||||
char *name = "HP/Speakers";
|
||||
|
||||
fix_volume_caps(codec, dac);
|
||||
if (!spec->vmaster_sw) {
|
||||
err = add_vmaster(codec, dac);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = add_mute(codec, name, 0,
|
||||
HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_ctl_add_slave(spec->vmaster_sw, kctl);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = add_volume(codec, name, 0,
|
||||
HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_ctl_add_slave(spec->vmaster_vol, kctl);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (cfg->speaker_outs) {
|
||||
err = snd_hda_ctl_add(codec, 0,
|
||||
snd_ctl_new1(&cs421x_speaker_bost_ctl, codec));
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int cs421x_build_controls(struct hda_codec *codec)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = build_cs421x_output(codec);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = build_cs421x_input(codec);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = build_digital_output(codec);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return cs421x_init(codec);
|
||||
}
|
||||
|
||||
static void cs421x_unsol_event(struct hda_codec *codec, unsigned int res)
|
||||
{
|
||||
switch ((res >> 26) & 0x3f) {
|
||||
case HP_EVENT:
|
||||
case SPDIF_EVENT:
|
||||
cs_automute(codec);
|
||||
break;
|
||||
|
||||
case MIC_EVENT:
|
||||
cs_automic(codec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_cs421x_input(struct hda_codec *codec)
|
||||
{
|
||||
struct cs_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
hda_nid_t pin = cfg->inputs[i].pin;
|
||||
spec->adc_nid[i] = get_adc(codec, pin, &spec->adc_idx[i]);
|
||||
spec->cur_input = spec->last_input = i;
|
||||
spec->num_inputs++;
|
||||
|
||||
/* check whether the automatic mic switch is available */
|
||||
if (is_ext_mic(codec, i) && cfg->num_inputs >= 2) {
|
||||
spec->mic_detect = 1;
|
||||
spec->automic_idx = i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs421x_parse_auto_config(struct hda_codec *codec)
|
||||
{
|
||||
struct cs_spec *spec = codec->spec;
|
||||
int err;
|
||||
|
||||
err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = parse_output(codec);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = parse_cs421x_input(codec);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = parse_digital_output(codec);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
/*
|
||||
Manage PDREF, when transitioning to D3hot
|
||||
(DAC,ADC) -> D3, PDREF=1, AFG->D3
|
||||
*/
|
||||
static int cs421x_suspend(struct hda_codec *codec, pm_message_t state)
|
||||
{
|
||||
unsigned int coef;
|
||||
|
||||
snd_hda_shutup_pins(codec);
|
||||
|
||||
snd_hda_codec_write(codec, CS4210_DAC_NID, 0,
|
||||
AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
|
||||
snd_hda_codec_write(codec, CS4210_ADC_NID, 0,
|
||||
AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
|
||||
|
||||
coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG);
|
||||
coef |= 0x0004; /* PDREF */
|
||||
cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct hda_codec_ops cs4210_patch_ops = {
|
||||
.build_controls = cs421x_build_controls,
|
||||
.build_pcms = cs_build_pcms,
|
||||
.init = cs421x_init,
|
||||
.free = cs_free,
|
||||
.unsol_event = cs421x_unsol_event,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = cs421x_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int patch_cs421x(struct hda_codec *codec)
|
||||
{
|
||||
struct cs_spec *spec;
|
||||
int err;
|
||||
|
||||
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
||||
if (!spec)
|
||||
return -ENOMEM;
|
||||
codec->spec = spec;
|
||||
|
||||
spec->vendor_nid = CS421X_VENDOR_NID;
|
||||
|
||||
spec->board_config =
|
||||
snd_hda_check_board_config(codec, CS421X_MODELS,
|
||||
cs421x_models, cs421x_cfg_tbl);
|
||||
if (spec->board_config >= 0)
|
||||
fix_pincfg(codec, spec->board_config, cs421x_pincfgs);
|
||||
/*
|
||||
Setup GPIO/SENSE for each board (if used)
|
||||
*/
|
||||
switch (spec->board_config) {
|
||||
case CS421X_CDB4210:
|
||||
snd_printd("CS4210 board: %s\n",
|
||||
cs421x_models[spec->board_config]);
|
||||
/* spec->gpio_mask = 3;
|
||||
spec->gpio_dir = 3;
|
||||
spec->gpio_data = 3;
|
||||
*/
|
||||
spec->sense_b = 1;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
Update the GPIO/DMIC/SENSE_B pinmux before the configuration
|
||||
is auto-parsed. If GPIO or SENSE_B is forced, DMIC input
|
||||
is disabled.
|
||||
*/
|
||||
cs421x_pinmux_init(codec);
|
||||
|
||||
err = cs421x_parse_auto_config(codec);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
codec->patch_ops = cs4210_patch_ops;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
kfree(codec->spec);
|
||||
codec->spec = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* patch entries
|
||||
@ -1279,11 +1952,13 @@ static int patch_cs420x(struct hda_codec *codec)
|
||||
static const struct hda_codec_preset snd_hda_preset_cirrus[] = {
|
||||
{ .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x },
|
||||
{ .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x },
|
||||
{ .id = 0x10134210, .name = "CS4210", .patch = patch_cs421x },
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
MODULE_ALIAS("snd-hda-codec-id:10134206");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10134207");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10134210");
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Cirrus Logic HD-audio codec");
|
||||
|
@ -446,6 +446,19 @@ static int conexant_init_jacks(struct hda_codec *codec)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void conexant_set_power(struct hda_codec *codec, hda_nid_t fg,
|
||||
unsigned int power_state)
|
||||
{
|
||||
if (power_state == AC_PWRST_D3)
|
||||
msleep(100);
|
||||
snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
|
||||
power_state);
|
||||
/* partial workaround for "azx_get_response timeout" */
|
||||
if (power_state == AC_PWRST_D0)
|
||||
msleep(10);
|
||||
snd_hda_codec_set_power_to_all(codec, fg, power_state, true);
|
||||
}
|
||||
|
||||
static int conexant_init(struct hda_codec *codec)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
@ -588,6 +601,7 @@ static const struct hda_codec_ops conexant_patch_ops = {
|
||||
.build_pcms = conexant_build_pcms,
|
||||
.init = conexant_init,
|
||||
.free = conexant_free,
|
||||
.set_power_state = conexant_set_power,
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
.suspend = conexant_suspend,
|
||||
#endif
|
||||
|
@ -2386,7 +2386,7 @@ static int alc_suspend(struct hda_codec *codec, pm_message_t state)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SND_HDA_NEEDS_RESUME
|
||||
#ifdef CONFIG_PM
|
||||
static int alc_resume(struct hda_codec *codec)
|
||||
{
|
||||
msleep(150); /* to avoid pop noise */
|
||||
@ -2406,7 +2406,7 @@ static const struct hda_codec_ops alc_patch_ops = {
|
||||
.init = alc_init,
|
||||
.free = alc_free,
|
||||
.unsol_event = alc_unsol_event,
|
||||
#ifdef SND_HDA_NEEDS_RESUME
|
||||
#ifdef CONFIG_PM
|
||||
.resume = alc_resume,
|
||||
#endif
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
@ -2801,7 +2801,8 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec)
|
||||
int i;
|
||||
|
||||
again:
|
||||
spec->multiout.num_dacs = 0;
|
||||
/* set num_dacs once to full for alc_auto_look_for_dac() */
|
||||
spec->multiout.num_dacs = cfg->line_outs;
|
||||
spec->multiout.hp_nid = 0;
|
||||
spec->multiout.extra_out_nid[0] = 0;
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
/* re-count num_dacs and squash invalid entries */
|
||||
spec->multiout.num_dacs = 0;
|
||||
for (i = 0; i < cfg->line_outs; i++) {
|
||||
if (spec->private_dac_nids[i])
|
||||
spec->multiout.num_dacs++;
|
||||
@ -4410,7 +4413,7 @@ static void alc269_shutup(struct hda_codec *codec)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SND_HDA_NEEDS_RESUME
|
||||
#ifdef CONFIG_PM
|
||||
static int alc269_resume(struct hda_codec *codec)
|
||||
{
|
||||
if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
|
||||
@ -4433,7 +4436,7 @@ static int alc269_resume(struct hda_codec *codec)
|
||||
hda_call_check_power_status(codec, 0x01);
|
||||
return 0;
|
||||
}
|
||||
#endif /* SND_HDA_NEEDS_RESUME */
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static void alc269_fixup_hweq(struct hda_codec *codec,
|
||||
const struct alc_fixup *fix, int action)
|
||||
@ -4725,7 +4728,7 @@ static int patch_alc269(struct hda_codec *codec)
|
||||
spec->vmaster_nid = 0x02;
|
||||
|
||||
codec->patch_ops = alc_patch_ops;
|
||||
#ifdef SND_HDA_NEEDS_RESUME
|
||||
#ifdef CONFIG_PM
|
||||
codec->patch_ops.resume = alc269_resume;
|
||||
#endif
|
||||
if (board_config == ALC_MODEL_AUTO)
|
||||
|
@ -95,6 +95,7 @@ enum {
|
||||
STAC_92HD83XXX_PWR_REF,
|
||||
STAC_DELL_S14,
|
||||
STAC_92HD83XXX_HP,
|
||||
STAC_92HD83XXX_HP_cNB11_INTQUAD,
|
||||
STAC_HP_DV7_4000,
|
||||
STAC_92HD83XXX_MODELS
|
||||
};
|
||||
@ -1636,10 +1637,17 @@ static const unsigned int hp_dv7_4000_pin_configs[10] = {
|
||||
0x40f000f0, 0x40f000f0,
|
||||
};
|
||||
|
||||
static const unsigned int hp_cNB11_intquad_pin_configs[10] = {
|
||||
0x40f000f0, 0x0221101f, 0x02a11020, 0x92170110,
|
||||
0x40f000f0, 0x92170110, 0x40f000f0, 0xd5a30130,
|
||||
0x40f000f0, 0x40f000f0,
|
||||
};
|
||||
|
||||
static const unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
|
||||
[STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs,
|
||||
[STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs,
|
||||
[STAC_DELL_S14] = dell_s14_pin_configs,
|
||||
[STAC_92HD83XXX_HP_cNB11_INTQUAD] = hp_cNB11_intquad_pin_configs,
|
||||
[STAC_HP_DV7_4000] = hp_dv7_4000_pin_configs,
|
||||
};
|
||||
|
||||
@ -1649,6 +1657,7 @@ static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
|
||||
[STAC_92HD83XXX_PWR_REF] = "mic-ref",
|
||||
[STAC_DELL_S14] = "dell-s14",
|
||||
[STAC_92HD83XXX_HP] = "hp",
|
||||
[STAC_92HD83XXX_HP_cNB11_INTQUAD] = "hp_cNB11_intquad",
|
||||
[STAC_HP_DV7_4000] = "hp-dv7-4000",
|
||||
};
|
||||
|
||||
@ -1661,7 +1670,47 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ba,
|
||||
"unknown Dell", STAC_DELL_S14),
|
||||
SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x3600,
|
||||
"HP", STAC_92HD83XXX_HP),
|
||||
"HP", STAC_92HD83XXX_HP),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1656,
|
||||
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1657,
|
||||
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1658,
|
||||
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1659,
|
||||
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165A,
|
||||
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165B,
|
||||
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3388,
|
||||
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3389,
|
||||
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355B,
|
||||
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355C,
|
||||
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355D,
|
||||
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355E,
|
||||
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355F,
|
||||
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3560,
|
||||
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x358B,
|
||||
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x358C,
|
||||
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x358D,
|
||||
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3591,
|
||||
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3592,
|
||||
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
|
||||
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3593,
|
||||
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
@ -4885,7 +4934,18 @@ static void stac927x_proc_hook(struct snd_info_buffer *buffer,
|
||||
#define stac927x_proc_hook NULL
|
||||
#endif
|
||||
|
||||
#ifdef SND_HDA_NEEDS_RESUME
|
||||
#ifdef CONFIG_PM
|
||||
static int stac92xx_pre_resume(struct hda_codec *codec)
|
||||
{
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
|
||||
/* sync mute LED */
|
||||
if (spec->gpio_led)
|
||||
stac_gpio_set(codec, spec->gpio_mask,
|
||||
spec->gpio_dir, spec->gpio_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stac92xx_resume(struct hda_codec *codec)
|
||||
{
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
@ -4901,29 +4961,19 @@ static int stac92xx_resume(struct hda_codec *codec)
|
||||
stac_issue_unsol_event(codec,
|
||||
spec->autocfg.line_out_pins[0]);
|
||||
}
|
||||
/* sync mute LED */
|
||||
if (spec->gpio_led)
|
||||
hda_call_check_power_status(codec, 0x01);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* using power check for controlling mute led of HP notebooks
|
||||
* check for mute state only on Speakers (nid = 0x10)
|
||||
*
|
||||
* For this feature CONFIG_SND_HDA_POWER_SAVE is needed, otherwise
|
||||
* the LED is NOT working properly !
|
||||
*
|
||||
* Changed name to reflect that it now works for any designated
|
||||
* model, not just HP HDX.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
static int stac92xx_hp_check_power_status(struct hda_codec *codec,
|
||||
hda_nid_t nid)
|
||||
/*
|
||||
* For this feature CONFIG_SND_HDA_POWER_SAVE is needed
|
||||
* as mute LED state is updated in check_power_status hook
|
||||
*/
|
||||
static int stac92xx_update_led_status(struct hda_codec *codec)
|
||||
{
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
int i, muted = 1;
|
||||
int i, num_ext_dacs, muted = 1;
|
||||
hda_nid_t nid;
|
||||
|
||||
for (i = 0; i < spec->multiout.num_dacs; i++) {
|
||||
nid = spec->multiout.dac_nids[i];
|
||||
@ -4933,6 +4983,22 @@ static int stac92xx_hp_check_power_status(struct hda_codec *codec,
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (muted && spec->multiout.hp_nid)
|
||||
if (!(snd_hda_codec_amp_read(codec,
|
||||
spec->multiout.hp_nid, 0, HDA_OUTPUT, 0) &
|
||||
HDA_AMP_MUTE)) {
|
||||
muted = 0; /* HP is not muted */
|
||||
}
|
||||
num_ext_dacs = ARRAY_SIZE(spec->multiout.extra_out_nid);
|
||||
for (i = 0; muted && i < num_ext_dacs; i++) {
|
||||
nid = spec->multiout.extra_out_nid[i];
|
||||
if (nid == 0)
|
||||
break;
|
||||
if (!(snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) &
|
||||
HDA_AMP_MUTE)) {
|
||||
muted = 0; /* extra output is not muted */
|
||||
}
|
||||
}
|
||||
if (muted)
|
||||
spec->gpio_data &= ~spec->gpio_led; /* orange */
|
||||
else
|
||||
@ -4946,6 +5012,17 @@ static int stac92xx_hp_check_power_status(struct hda_codec *codec,
|
||||
stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* use power check for controlling mute led of HP notebooks
|
||||
*/
|
||||
static int stac92xx_check_power_status(struct hda_codec *codec,
|
||||
hda_nid_t nid)
|
||||
{
|
||||
stac92xx_update_led_status(codec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
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)
|
||||
stac92xx_shutup(codec);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static const struct hda_codec_ops stac92xx_patch_ops = {
|
||||
.build_controls = stac92xx_build_controls,
|
||||
@ -4961,9 +5038,10 @@ static const struct hda_codec_ops stac92xx_patch_ops = {
|
||||
.init = stac92xx_init,
|
||||
.free = stac92xx_free,
|
||||
.unsol_event = stac92xx_unsol_event,
|
||||
#ifdef SND_HDA_NEEDS_RESUME
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = stac92xx_suspend,
|
||||
.resume = stac92xx_resume,
|
||||
.pre_resume = stac92xx_pre_resume,
|
||||
#endif
|
||||
.reboot_notify = stac92xx_shutup,
|
||||
};
|
||||
@ -5482,7 +5560,7 @@ again:
|
||||
spec->gpio_data |= spec->gpio_led;
|
||||
/* register check_power_status callback. */
|
||||
codec->patch_ops.check_power_status =
|
||||
stac92xx_hp_check_power_status;
|
||||
stac92xx_check_power_status;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -5810,7 +5888,7 @@ again:
|
||||
spec->gpio_data |= spec->gpio_led;
|
||||
/* register check_power_status callback. */
|
||||
codec->patch_ops.check_power_status =
|
||||
stac92xx_hp_check_power_status;
|
||||
stac92xx_check_power_status;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1708,7 +1708,7 @@ static void via_unsol_event(struct hda_codec *codec,
|
||||
via_gpio_control(codec);
|
||||
}
|
||||
|
||||
#ifdef SND_HDA_NEEDS_RESUME
|
||||
#ifdef CONFIG_PM
|
||||
static int via_suspend(struct hda_codec *codec, pm_message_t state)
|
||||
{
|
||||
struct via_spec *spec = codec->spec;
|
||||
@ -1736,7 +1736,7 @@ static const struct hda_codec_ops via_patch_ops = {
|
||||
.init = via_init,
|
||||
.free = via_free,
|
||||
.unsol_event = via_unsol_event,
|
||||
#ifdef SND_HDA_NEEDS_RESUME
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = via_suspend,
|
||||
#endif
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
|
@ -907,6 +907,7 @@ static int ldo_regulator_register(struct snd_soc_codec *codec,
|
||||
struct regulator_init_data *init_data,
|
||||
int voltage)
|
||||
{
|
||||
dev_err(codec->dev, "this setup needs regulator support in the kernel\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -1218,6 +1219,34 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sgtl5000_replace_vddd_with_ldo(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
/* set internal ldo to 1.2v */
|
||||
ret = ldo_regulator_register(codec, &ldo_init_data, LDO_VOLTAGE);
|
||||
if (ret) {
|
||||
dev_err(codec->dev,
|
||||
"Failed to register vddd internal supplies: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
sgtl5000->supplies[VDDD].supply = LDO_CONSUMER_NAME;
|
||||
|
||||
ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies),
|
||||
sgtl5000->supplies);
|
||||
|
||||
if (ret) {
|
||||
ldo_regulator_remove(codec);
|
||||
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_info(codec->dev, "Using internal LDO instead of VDDD\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sgtl5000_enable_regulators(struct snd_soc_codec *codec)
|
||||
{
|
||||
u16 reg;
|
||||
@ -1235,30 +1264,9 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec)
|
||||
if (!ret)
|
||||
external_vddd = 1;
|
||||
else {
|
||||
/* set internal ldo to 1.2v */
|
||||
int voltage = LDO_VOLTAGE;
|
||||
|
||||
ret = ldo_regulator_register(codec, &ldo_init_data, voltage);
|
||||
if (ret) {
|
||||
dev_err(codec->dev,
|
||||
"Failed to register vddd internal supplies: %d\n",
|
||||
ret);
|
||||
ret = sgtl5000_replace_vddd_with_ldo(codec);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
sgtl5000->supplies[VDDD].supply = LDO_CONSUMER_NAME;
|
||||
|
||||
ret = regulator_bulk_get(codec->dev,
|
||||
ARRAY_SIZE(sgtl5000->supplies),
|
||||
sgtl5000->supplies);
|
||||
|
||||
if (ret) {
|
||||
ldo_regulator_remove(codec);
|
||||
dev_err(codec->dev,
|
||||
"Failed to request supplies: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies),
|
||||
@ -1287,7 +1295,6 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec)
|
||||
* roll back to use internal LDO
|
||||
*/
|
||||
if (external_vddd && rev >= 0x11) {
|
||||
int voltage = LDO_VOLTAGE;
|
||||
/* disable all regulator first */
|
||||
regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
|
||||
sgtl5000->supplies);
|
||||
@ -1295,23 +1302,10 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec)
|
||||
regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies),
|
||||
sgtl5000->supplies);
|
||||
|
||||
ret = ldo_regulator_register(codec, &ldo_init_data, voltage);
|
||||
ret = sgtl5000_replace_vddd_with_ldo(codec);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sgtl5000->supplies[VDDD].supply = LDO_CONSUMER_NAME;
|
||||
|
||||
ret = regulator_bulk_get(codec->dev,
|
||||
ARRAY_SIZE(sgtl5000->supplies),
|
||||
sgtl5000->supplies);
|
||||
if (ret) {
|
||||
ldo_regulator_remove(codec);
|
||||
dev_err(codec->dev,
|
||||
"Failed to request supplies: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies),
|
||||
sgtl5000->supplies);
|
||||
if (ret)
|
||||
|
@ -3409,6 +3409,9 @@ static irqreturn_t wm8962_irq(int irq, void *data)
|
||||
active = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2);
|
||||
active &= ~mask;
|
||||
|
||||
/* Acknowledge the interrupts */
|
||||
snd_soc_write(codec, WM8962_INTERRUPT_STATUS_2, active);
|
||||
|
||||
if (active & WM8962_FLL_LOCK_EINT) {
|
||||
dev_dbg(codec->dev, "FLL locked\n");
|
||||
complete(&wm8962->fll_lock);
|
||||
@ -3433,9 +3436,6 @@ static irqreturn_t wm8962_irq(int irq, void *data)
|
||||
msecs_to_jiffies(250));
|
||||
}
|
||||
|
||||
/* Acknowledge the interrupts */
|
||||
snd_soc_write(codec, WM8962_INTERRUPT_STATUS_2, active);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -62,9 +62,9 @@ static void davinci_vcif_start(struct snd_pcm_substream *substream)
|
||||
w = readl(davinci_vc->base + DAVINCI_VC_CTRL);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 1);
|
||||
MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 0);
|
||||
else
|
||||
MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 1);
|
||||
MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 0);
|
||||
|
||||
writel(w, davinci_vc->base + DAVINCI_VC_CTRL);
|
||||
}
|
||||
@ -80,9 +80,9 @@ static void davinci_vcif_stop(struct snd_pcm_substream *substream)
|
||||
/* Reset transmitter/receiver and sample rate/frame sync generators */
|
||||
w = readl(davinci_vc->base + DAVINCI_VC_CTRL);
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 0);
|
||||
MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 1);
|
||||
else
|
||||
MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 0);
|
||||
MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 1);
|
||||
|
||||
writel(w, davinci_vc->base + DAVINCI_VC_CTRL);
|
||||
}
|
||||
@ -159,6 +159,7 @@ static int davinci_vcif_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
davinci_vcif_start(substream);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <plat/audio.h>
|
||||
|
||||
#include "dma.h"
|
||||
#include "idma.h"
|
||||
#include "i2s.h"
|
||||
#include "i2s-regs.h"
|
||||
|
||||
@ -60,6 +61,7 @@ struct i2s_dai {
|
||||
/* DMA parameters */
|
||||
struct s3c_dma_params dma_playback;
|
||||
struct s3c_dma_params dma_capture;
|
||||
struct s3c_dma_params idma_playback;
|
||||
u32 quirks;
|
||||
u32 suspend_i2smod;
|
||||
u32 suspend_i2scon;
|
||||
@ -877,6 +879,10 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
|
||||
if (i2s->quirks & QUIRK_NEED_RSTCLR)
|
||||
writel(CON_RSTCLR, i2s->addr + I2SCON);
|
||||
|
||||
if (i2s->quirks & QUIRK_SEC_DAI)
|
||||
idma_reg_addr_init((void *)i2s->addr,
|
||||
i2s->sec_dai->idma_playback.dma_addr);
|
||||
|
||||
probe_exit:
|
||||
/* Reset any constraint on RFS and BFS */
|
||||
i2s->rfs = 0;
|
||||
@ -1077,6 +1083,7 @@ static __devinit int samsung_i2s_probe(struct platform_device *pdev)
|
||||
sec_dai->dma_playback.dma_size = 4;
|
||||
sec_dai->base = regs_base;
|
||||
sec_dai->quirks = quirks;
|
||||
sec_dai->idma_playback.dma_addr = i2s_cfg->idma_addr;
|
||||
sec_dai->pri_dai = pri_dai;
|
||||
pri_dai->sec_dai = sec_dai;
|
||||
}
|
||||
|
@ -577,6 +577,7 @@ int snd_soc_suspend(struct device *dev)
|
||||
case SND_SOC_BIAS_OFF:
|
||||
codec->driver->suspend(codec, PMSG_SUSPEND);
|
||||
codec->suspended = 1;
|
||||
codec->cache_sync = 1;
|
||||
break;
|
||||
default:
|
||||
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)
|
||||
}
|
||||
}
|
||||
cpu_dai->probed = 1;
|
||||
/* mark cpu_dai as probed and add to card cpu_dai list */
|
||||
/* mark cpu_dai as probed and add to card dai list */
|
||||
list_add(&cpu_dai->card_list, &card->dai_dev_list);
|
||||
}
|
||||
|
||||
@ -1171,7 +1172,7 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order)
|
||||
}
|
||||
}
|
||||
|
||||
/* mark cpu_dai as probed and add to card cpu_dai list */
|
||||
/* mark codec_dai as probed and add to card dai list */
|
||||
codec_dai->probed = 1;
|
||||
list_add(&codec_dai->card_list, &card->dai_dev_list);
|
||||
}
|
||||
|
@ -124,6 +124,36 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
|
||||
return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
|
||||
}
|
||||
|
||||
/* get snd_card from DAPM context */
|
||||
static inline struct snd_card *dapm_get_snd_card(
|
||||
struct snd_soc_dapm_context *dapm)
|
||||
{
|
||||
if (dapm->codec)
|
||||
return dapm->codec->card->snd_card;
|
||||
else if (dapm->platform)
|
||||
return dapm->platform->card->snd_card;
|
||||
else
|
||||
BUG();
|
||||
|
||||
/* unreachable */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* get soc_card from DAPM context */
|
||||
static inline struct snd_soc_card *dapm_get_soc_card(
|
||||
struct snd_soc_dapm_context *dapm)
|
||||
{
|
||||
if (dapm->codec)
|
||||
return dapm->codec->card;
|
||||
else if (dapm->platform)
|
||||
return dapm->platform->card;
|
||||
else
|
||||
BUG();
|
||||
|
||||
/* unreachable */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg)
|
||||
{
|
||||
if (w->codec)
|
||||
|
Loading…
Reference in New Issue
Block a user