Commit 82beb8fd authored by Takashi Iwai's avatar Takashi Iwai Committed by Jaroslav Kysela

[ALSA] hda-codec - optimize resume using caches

So far, the driver looked the table of snd_kcontrol_new used for creating
mixer elements and forces to call each of its put callbacks in PM resume
code.  This is too ugly and hackish.
Now, the resume is simplified using the codec amp and command register
caches.  The driver simply restores the values that have been written
in the cache table.  With this simplification, most codec support codes
don't require any special resume callback.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarJaroslav Kysela <perex@suse.cz>
parent b3ac5636
...@@ -836,12 +836,13 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, ...@@ -836,12 +836,13 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
return 0; return 0;
val &= mask; val &= mask;
val |= get_vol_mute(codec, info, nid, ch, direction, idx) & ~mask; val |= get_vol_mute(codec, info, nid, ch, direction, idx) & ~mask;
if (info->vol[ch] == val && !codec->in_resume) if (info->vol[ch] == val)
return 0; return 0;
put_vol_mute(codec, info, nid, ch, direction, idx, val); put_vol_mute(codec, info, nid, ch, direction, idx, val);
return 1; return 1;
} }
#ifdef CONFIG_PM
/* resume the all amp commands from the cache */ /* resume the all amp commands from the cache */
void snd_hda_codec_resume_amp(struct hda_codec *codec) void snd_hda_codec_resume_amp(struct hda_codec *codec)
{ {
...@@ -865,6 +866,7 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec) ...@@ -865,6 +866,7 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec)
} }
} }
} }
#endif /* CONFIG_PM */
/* /*
* AMP control callbacks * AMP control callbacks
...@@ -1272,11 +1274,13 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol, ...@@ -1272,11 +1274,13 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
change = codec->spdif_ctls != val; change = codec->spdif_ctls != val;
codec->spdif_ctls = val; codec->spdif_ctls = val;
if (change || codec->in_resume) { if (change) {
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, snd_hda_codec_write_cache(codec, nid, 0,
val & 0xff); AC_VERB_SET_DIGI_CONVERT_1,
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_2, val & 0xff);
val >> 8); snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_DIGI_CONVERT_2,
val >> 8);
} }
mutex_unlock(&codec->spdif_mutex); mutex_unlock(&codec->spdif_mutex);
...@@ -1307,17 +1311,19 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol, ...@@ -1307,17 +1311,19 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol,
if (ucontrol->value.integer.value[0]) if (ucontrol->value.integer.value[0])
val |= AC_DIG1_ENABLE; val |= AC_DIG1_ENABLE;
change = codec->spdif_ctls != val; change = codec->spdif_ctls != val;
if (change || codec->in_resume) { if (change) {
codec->spdif_ctls = val; codec->spdif_ctls = val;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, snd_hda_codec_write_cache(codec, nid, 0,
val & 0xff); AC_VERB_SET_DIGI_CONVERT_1,
val & 0xff);
/* unmute amp switch (if any) */ /* unmute amp switch (if any) */
if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) && if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) &&
(val & AC_DIG1_ENABLE)) (val & AC_DIG1_ENABLE)) {
snd_hda_codec_write(codec, nid, 0, snd_hda_codec_amp_update(codec, nid, 0, HDA_OUTPUT, 0,
AC_VERB_SET_AMP_GAIN_MUTE, 0x80, 0x00);
AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | snd_hda_codec_amp_update(codec, nid, 1, HDA_OUTPUT, 0,
AC_AMP_SET_OUTPUT); 0x80, 0x00);
}
} }
mutex_unlock(&codec->spdif_mutex); mutex_unlock(&codec->spdif_mutex);
return change; return change;
...@@ -1409,10 +1415,10 @@ static int snd_hda_spdif_in_switch_put(struct snd_kcontrol *kcontrol, ...@@ -1409,10 +1415,10 @@ static int snd_hda_spdif_in_switch_put(struct snd_kcontrol *kcontrol,
mutex_lock(&codec->spdif_mutex); mutex_lock(&codec->spdif_mutex);
change = codec->spdif_in_enable != val; change = codec->spdif_in_enable != val;
if (change || codec->in_resume) { if (change) {
codec->spdif_in_enable = val; codec->spdif_in_enable = val;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, snd_hda_codec_write_cache(codec, nid, 0,
val); AC_VERB_SET_DIGI_CONVERT_1, val);
} }
mutex_unlock(&codec->spdif_mutex); mutex_unlock(&codec->spdif_mutex);
return change; return change;
...@@ -1482,6 +1488,10 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) ...@@ -1482,6 +1488,10 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
return 0; return 0;
} }
#ifdef CONFIG_PM
/*
* command cache
*/
/* build a 32bit cache key with the widget id and the command parameter */ /* build a 32bit cache key with the widget id and the command parameter */
#define build_cmd_cache_key(nid, verb) ((verb << 8) | nid) #define build_cmd_cache_key(nid, verb) ((verb << 8) | nid)
...@@ -1548,6 +1558,7 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec, ...@@ -1548,6 +1558,7 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec,
snd_hda_codec_write_cache(codec, seq->nid, 0, seq->verb, snd_hda_codec_write_cache(codec, seq->nid, 0, seq->verb,
seq->param); seq->param);
} }
#endif /* CONFIG_PM */
/* /*
* set power state of the codec * set power state of the codec
...@@ -2122,12 +2133,12 @@ int snd_hda_ch_mode_put(struct hda_codec *codec, ...@@ -2122,12 +2133,12 @@ int snd_hda_ch_mode_put(struct hda_codec *codec,
mode = ucontrol->value.enumerated.item[0]; mode = ucontrol->value.enumerated.item[0];
snd_assert(mode < num_chmodes, return -EINVAL); snd_assert(mode < num_chmodes, return -EINVAL);
if (*max_channelsp == chmode[mode].channels && !codec->in_resume) if (*max_channelsp == chmode[mode].channels)
return 0; return 0;
/* change the current channel setting */ /* change the current channel setting */
*max_channelsp = chmode[mode].channels; *max_channelsp = chmode[mode].channels;
if (chmode[mode].sequence) if (chmode[mode].sequence)
snd_hda_sequence_write(codec, chmode[mode].sequence); snd_hda_sequence_write_cache(codec, chmode[mode].sequence);
return 1; return 1;
} }
...@@ -2160,10 +2171,10 @@ int snd_hda_input_mux_put(struct hda_codec *codec, ...@@ -2160,10 +2171,10 @@ int snd_hda_input_mux_put(struct hda_codec *codec,
idx = ucontrol->value.enumerated.item[0]; idx = ucontrol->value.enumerated.item[0];
if (idx >= imux->num_items) if (idx >= imux->num_items)
idx = imux->num_items - 1; idx = imux->num_items - 1;
if (*cur_val == idx && !codec->in_resume) if (*cur_val == idx)
return 0; return 0;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_CONNECT_SEL,
imux->items[idx].index); imux->items[idx].index);
*cur_val = idx; *cur_val = idx;
return 1; return 1;
} }
...@@ -2608,65 +2619,13 @@ int snd_hda_resume(struct hda_bus *bus) ...@@ -2608,65 +2619,13 @@ int snd_hda_resume(struct hda_bus *bus)
AC_PWRST_D0); AC_PWRST_D0);
if (codec->patch_ops.resume) if (codec->patch_ops.resume)
codec->patch_ops.resume(codec); codec->patch_ops.resume(codec);
} else {
return 0; codec->patch_ops.init(codec);
} snd_hda_codec_resume_amp(codec);
snd_hda_codec_resume_cache(codec);
/**
* snd_hda_resume_ctls - resume controls in the new control list
* @codec: the HDA codec
* @knew: the array of struct snd_kcontrol_new
*
* This function resumes the mixer controls in the struct snd_kcontrol_new array,
* originally for snd_hda_add_new_ctls().
* The array must be terminated with an empty entry as terminator.
*/
int snd_hda_resume_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
{
struct snd_ctl_elem_value *val;
val = kmalloc(sizeof(*val), GFP_KERNEL);
if (!val)
return -ENOMEM;
codec->in_resume = 1;
for (; knew->name; knew++) {
int i, count;
count = knew->count ? knew->count : 1;
for (i = 0; i < count; i++) {
memset(val, 0, sizeof(*val));
val->id.iface = knew->iface;
val->id.device = knew->device;
val->id.subdevice = knew->subdevice;
strcpy(val->id.name, knew->name);
val->id.index = knew->index ? knew->index : i;
/* Assume that get callback reads only from cache,
* not accessing to the real hardware
*/
if (snd_ctl_elem_read(codec->bus->card, val) < 0)
continue;
snd_ctl_elem_write(codec->bus->card, NULL, val);
} }
} }
codec->in_resume = 0;
kfree(val);
return 0; return 0;
} }
/**
* snd_hda_resume_spdif_out - resume the digital out
* @codec: the HDA codec
*/
int snd_hda_resume_spdif_out(struct hda_codec *codec)
{
return snd_hda_resume_ctls(codec, dig_mixes);
}
/**
* snd_hda_resume_spdif_in - resume the digital in
* @codec: the HDA codec
*/
int snd_hda_resume_spdif_in(struct hda_codec *codec)
{
return snd_hda_resume_ctls(codec, dig_in_ctls);
}
#endif #endif
...@@ -552,11 +552,6 @@ struct hda_codec { ...@@ -552,11 +552,6 @@ struct hda_codec {
/* set by patch */ /* set by patch */
struct hda_codec_ops patch_ops; struct hda_codec_ops patch_ops;
/* resume phase - all controls should update even if
* the values are not changed
*/
unsigned int in_resume;
/* PCM to create, set by patch_ops.build_pcms callback */ /* PCM to create, set by patch_ops.build_pcms callback */
unsigned int num_pcms; unsigned int num_pcms;
struct hda_pcm *pcm_info; struct hda_pcm *pcm_info;
...@@ -622,11 +617,16 @@ void snd_hda_sequence_write(struct hda_codec *codec, ...@@ -622,11 +617,16 @@ void snd_hda_sequence_write(struct hda_codec *codec,
int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex); int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex);
/* cached write */ /* cached write */
#ifdef CONFIG_PM
int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
int direct, unsigned int verb, unsigned int parm); int direct, unsigned int verb, unsigned int parm);
void snd_hda_sequence_write_cache(struct hda_codec *codec, void snd_hda_sequence_write_cache(struct hda_codec *codec,
const struct hda_verb *seq); const struct hda_verb *seq);
void snd_hda_codec_resume_cache(struct hda_codec *codec); void snd_hda_codec_resume_cache(struct hda_codec *codec);
#else
#define snd_hda_codec_write_cache snd_hda_codec_write
#define snd_hda_sequence_write_cache snd_hda_sequence_write
#endif
/* /*
* Mixer * Mixer
......
...@@ -218,9 +218,9 @@ static int unmute_output(struct hda_codec *codec, struct hda_gnode *node) ...@@ -218,9 +218,9 @@ static int unmute_output(struct hda_codec *codec, struct hda_gnode *node)
ofs = (node->amp_out_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; ofs = (node->amp_out_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT;
if (val >= ofs) if (val >= ofs)
val -= ofs; val -= ofs;
val |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT; snd_hda_codec_amp_update(codec, node->nid, 0, HDA_OUTPUT, 0, 0xff, val);
val |= AC_AMP_SET_OUTPUT; snd_hda_codec_amp_update(codec, node->nid, 0, HDA_OUTPUT, 1, 0xff, val);
return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, val); return 0;
} }
/* /*
...@@ -234,11 +234,11 @@ static int unmute_input(struct hda_codec *codec, struct hda_gnode *node, unsigne ...@@ -234,11 +234,11 @@ static int unmute_input(struct hda_codec *codec, struct hda_gnode *node, unsigne
ofs = (node->amp_in_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; ofs = (node->amp_in_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT;
if (val >= ofs) if (val >= ofs)
val -= ofs; val -= ofs;
val |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT; snd_hda_codec_amp_update(codec, node->nid, 0, HDA_INPUT, index,
val |= AC_AMP_SET_INPUT; 0xff, val);
// awk added - fixed to allow unmuting of indexed amps snd_hda_codec_amp_update(codec, node->nid, 1, HDA_INPUT, index,
val |= index << AC_AMP_SET_INDEX_SHIFT; 0xff, val);
return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, val); return 0;
} }
/* /*
...@@ -248,7 +248,8 @@ static int select_input_connection(struct hda_codec *codec, struct hda_gnode *no ...@@ -248,7 +248,8 @@ static int select_input_connection(struct hda_codec *codec, struct hda_gnode *no
unsigned int index) unsigned int index)
{ {
snd_printdd("CONNECT: NID=0x%x IDX=0x%x\n", node->nid, index); snd_printdd("CONNECT: NID=0x%x IDX=0x%x\n", node->nid, index);
return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_CONNECT_SEL, index); return snd_hda_codec_write_cache(codec, node->nid, 0,
AC_VERB_SET_CONNECT_SEL, index);
} }
/* /*
...@@ -379,7 +380,7 @@ static struct hda_gnode *parse_output_jack(struct hda_codec *codec, ...@@ -379,7 +380,7 @@ static struct hda_gnode *parse_output_jack(struct hda_codec *codec,
/* unmute the PIN output */ /* unmute the PIN output */
unmute_output(codec, node); unmute_output(codec, node);
/* set PIN-Out enable */ /* set PIN-Out enable */
snd_hda_codec_write(codec, node->nid, 0, snd_hda_codec_write_cache(codec, node->nid, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, AC_VERB_SET_PIN_WIDGET_CONTROL,
AC_PINCTL_OUT_EN | AC_PINCTL_OUT_EN |
((node->pin_caps & AC_PINCAP_HP_DRV) ? ((node->pin_caps & AC_PINCAP_HP_DRV) ?
...@@ -570,7 +571,8 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec, ...@@ -570,7 +571,8 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
/* unmute the PIN external input */ /* unmute the PIN external input */
unmute_input(codec, node, 0); /* index = 0? */ unmute_input(codec, node, 0); /* index = 0? */
/* set PIN-In enable */ /* set PIN-In enable */
snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); snd_hda_codec_write_cache(codec, node->nid, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl);
return 1; /* found */ return 1; /* found */
} }
......
...@@ -84,7 +84,9 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, ...@@ -84,7 +84,9 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch,
int direction, int index); int direction, int index);
int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, 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 direction, int idx, int mask, int val);
#ifdef CONFIG_PM
void snd_hda_codec_resume_amp(struct hda_codec *codec); void snd_hda_codec_resume_amp(struct hda_codec *codec);
#endif
/* mono switch binding multiple inputs */ /* mono switch binding multiple inputs */
#define HDA_BIND_MUTE_MONO(xname, nid, channel, indices, direction) \ #define HDA_BIND_MUTE_MONO(xname, nid, channel, indices, direction) \
...@@ -256,15 +258,6 @@ int snd_hda_check_board_config(struct hda_codec *codec, int num_configs, ...@@ -256,15 +258,6 @@ int snd_hda_check_board_config(struct hda_codec *codec, int num_configs,
int snd_hda_add_new_ctls(struct hda_codec *codec, int snd_hda_add_new_ctls(struct hda_codec *codec,
struct snd_kcontrol_new *knew); struct snd_kcontrol_new *knew);
/*
* power management
*/
#ifdef CONFIG_PM
int snd_hda_resume_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew);
int snd_hda_resume_spdif_out(struct hda_codec *codec);
int snd_hda_resume_spdif_in(struct hda_codec *codec);
#endif
/* /*
* unsolicited event handler * unsolicited event handler
*/ */
......
...@@ -318,31 +318,11 @@ static void ad198x_free(struct hda_codec *codec) ...@@ -318,31 +318,11 @@ static void ad198x_free(struct hda_codec *codec)
kfree(codec->spec); kfree(codec->spec);
} }
#ifdef CONFIG_PM
static int ad198x_resume(struct hda_codec *codec)
{
struct ad198x_spec *spec = codec->spec;
int i;
codec->patch_ops.init(codec);
for (i = 0; i < spec->num_mixers; i++)
snd_hda_resume_ctls(codec, spec->mixers[i]);
if (spec->multiout.dig_out_nid)
snd_hda_resume_spdif_out(codec);
if (spec->dig_in_nid)
snd_hda_resume_spdif_in(codec);
return 0;
}
#endif
static struct hda_codec_ops ad198x_patch_ops = { static struct hda_codec_ops ad198x_patch_ops = {
.build_controls = ad198x_build_controls, .build_controls = ad198x_build_controls,
.build_pcms = ad198x_build_pcms, .build_pcms = ad198x_build_pcms,
.init = ad198x_init, .init = ad198x_init,
.free = ad198x_free, .free = ad198x_free,
#ifdef CONFIG_PM
.resume = ad198x_resume,
#endif
}; };
...@@ -376,12 +356,12 @@ static int ad198x_eapd_put(struct snd_kcontrol *kcontrol, ...@@ -376,12 +356,12 @@ static int ad198x_eapd_put(struct snd_kcontrol *kcontrol,
eapd = ucontrol->value.integer.value[0]; eapd = ucontrol->value.integer.value[0];
if (invert) if (invert)
eapd = !eapd; eapd = !eapd;
if (eapd == spec->cur_eapd && ! codec->in_resume) if (eapd == spec->cur_eapd)
return 0; return 0;
spec->cur_eapd = eapd; spec->cur_eapd = eapd;
snd_hda_codec_write(codec, nid, snd_hda_codec_write_cache(codec, nid,
0, AC_VERB_SET_EAPD_BTLENABLE, 0, AC_VERB_SET_EAPD_BTLENABLE,
eapd ? 0x02 : 0x00); eapd ? 0x02 : 0x00);
return 1; return 1;
} }
...@@ -882,8 +862,9 @@ static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ ...@@ -882,8 +862,9 @@ static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
if (spec->spdif_route != ucontrol->value.enumerated.item[0]) { if (spec->spdif_route != ucontrol->value.enumerated.item[0]) {
spec->spdif_route = ucontrol->value.enumerated.item[0]; spec->spdif_route = ucontrol->value.enumerated.item[0];
snd_hda_codec_write(codec, spec->multiout.dig_out_nid, 0, snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0,
AC_VERB_SET_CONNECT_SEL, spec->spdif_route); AC_VERB_SET_CONNECT_SEL,
spec->spdif_route);
return 1; return 1;
} }
return 0; return 0;
...@@ -1824,33 +1805,34 @@ static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol, ...@@ -1824,33 +1805,34 @@ static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol,
AC_VERB_GET_AMP_GAIN_MUTE, AC_VERB_GET_AMP_GAIN_MUTE,
AC_AMP_GET_INPUT); AC_AMP_GET_INPUT);
change = sel & 0x80; change = sel & 0x80;
if (change || codec->in_resume) { if (change) {
snd_hda_codec_write(codec, 0x1d, 0, snd_hda_codec_write_cache(codec, 0x1d, 0,
AC_VERB_SET_AMP_GAIN_MUTE, AC_VERB_SET_AMP_GAIN_MUTE,
AMP_IN_UNMUTE(0)); AMP_IN_UNMUTE(0));
snd_hda_codec_write(codec, 0x1d, 0, snd_hda_codec_write_cache(codec, 0x1d, 0,
AC_VERB_SET_AMP_GAIN_MUTE, AC_VERB_SET_AMP_GAIN_MUTE,
AMP_IN_MUTE(1)); AMP_IN_MUTE(1));
} }
} else { } else {
sel = snd_hda_codec_read(codec, 0x1d, 0, sel = snd_hda_codec_read(codec, 0x1d, 0,
AC_VERB_GET_AMP_GAIN_MUTE, AC_VERB_GET_AMP_GAIN_MUTE,
AC_AMP_GET_INPUT | 0x01); AC_AMP_GET_INPUT | 0x01);
change = sel & 0x80; change = sel & 0x80;
if (change || codec->in_resume) { if (change) {
snd_hda_codec_write(codec, 0x1d, 0, snd_hda_codec_write_cache(codec, 0x1d, 0,
AC_VERB_SET_AMP_GAIN_MUTE, AC_VERB_SET_AMP_GAIN_MUTE,
AMP_IN_MUTE(0)); AMP_IN_MUTE(0));
snd_hda_codec_write(codec, 0x1d, 0, snd_hda_codec_write_cache(codec, 0x1d, 0,
AC_VERB_SET_AMP_GAIN_MUTE, AC_VERB_SET_AMP_GAIN_MUTE,
AMP_IN_UNMUTE(1)); AMP_IN_UNMUTE(1));
} }
sel = snd_hda_codec_read(codec, 0x0b, 0, sel = snd_hda_codec_read(codec, 0x0b, 0,
AC_VERB_GET_CONNECT_SEL, 0) + 1; AC_VERB_GET_CONNECT_SEL, 0) + 1;
change |= sel != val; change |= sel != val;
if (change || codec->in_resume) if (change)
snd_hda_codec_write(codec, 0x0b, 0, snd_hda_codec_write_cache(codec, 0x0b, 0,
AC_VERB_SET_CONNECT_SEL, val - 1); AC_VERB_SET_CONNECT_SEL,
val - 1);
} }
return change; return change;
} }
......
...@@ -62,19 +62,6 @@ static int atihdmi_init(struct hda_codec *codec) ...@@ -62,19 +62,6 @@ static int atihdmi_init(struct hda_codec *codec)
return 0; return 0;
} }
#ifdef CONFIG_PM
/*
* resume
*/
static int atihdmi_resume(struct hda_codec *codec)
{
atihdmi_init(codec);
snd_hda_resume_spdif_out(codec);
return 0;
}
#endif
/* /*
* Digital out * Digital out
*/ */
...@@ -141,9 +128,6 @@ static struct hda_codec_ops atihdmi_patch_ops = { ...@@ -141,9 +128,6 @@ static struct hda_codec_ops atihdmi_patch_ops = {
.build_pcms = atihdmi_build_pcms, .build_pcms = atihdmi_build_pcms,
.init = atihdmi_init, .init = atihdmi_init,
.free = atihdmi_free, .free = atihdmi_free,
#ifdef CONFIG_PM
.resume = atihdmi_resume,
#endif
}; };
static int patch_atihdmi(struct hda_codec *codec) static int patch_atihdmi(struct hda_codec *codec)
......
...@@ -427,27 +427,6 @@ static int cmi9880_init(struct hda_codec *codec) ...@@ -427,27 +427,6 @@ static int cmi9880_init(struct hda_codec *codec)
return 0; return 0;
} }
#ifdef CONFIG_PM
/*
* resume
*/
static int cmi9880_resume(struct hda_codec *codec)
{
struct cmi_spec *spec = codec->spec;
cmi9880_init(codec);
snd_hda_resume_ctls(codec, cmi9880_basic_mixer);
if (spec->channel_modes)
snd_hda_resume_ctls(codec, cmi9880_ch_mode_mixer);
if (spec->multiout.dig_out_nid)
snd_hda_resume_spdif_out(codec);
if (spec->dig_in_nid)
snd_hda_resume_spdif_in(codec);
return 0;
}
#endif
/* /*
* Analog playback callbacks * Analog playback callbacks
*/ */
...@@ -635,9 +614,6 @@ static struct hda_codec_ops cmi9880_patch_ops = { ...@@ -635,9 +614,6 @@ static struct hda_codec_ops cmi9880_patch_ops = {
.build_pcms = cmi9880_build_pcms, .build_pcms = cmi9880_build_pcms,
.init = cmi9880_init, .init = cmi9880_init,
.free = cmi9880_free, .free = cmi9880_free,
#ifdef CONFIG_PM
.resume = cmi9880_resume,
#endif
}; };
static int patch_cmi9880(struct hda_codec *codec) static int patch_cmi9880(struct hda_codec *codec)
......
...@@ -311,23 +311,6 @@ static void conexant_free(struct hda_codec *codec) ...@@ -311,23 +311,6 @@ static void conexant_free(struct hda_codec *codec)
kfree(codec->spec); kfree(codec->spec);
} }
#ifdef CONFIG_PM
static int conexant_resume(struct hda_codec *codec)
{
struct conexant_spec *spec = codec->spec;
int i;
codec->patch_ops.init(codec);
for (i = 0; i < spec->num_mixers; i++)
snd_hda_resume_ctls(codec, spec->mixers[i]);
if (spec->multiout.dig_out_nid)
snd_hda_resume_spdif_out(codec);
if (spec->dig_in_nid)
snd_hda_resume_spdif_in(codec);
return 0;
}
#endif
static int conexant_build_controls(struct hda_codec *codec) static int conexant_build_controls(struct hda_codec *codec)
{ {
struct conexant_spec *spec = codec->spec; struct conexant_spec *spec = codec->spec;
...@@ -358,9 +341,6 @@ static struct hda_codec_ops conexant_patch_ops = { ...@@ -358,9 +341,6 @@ static struct hda_codec_ops conexant_patch_ops = {
.build_pcms = conexant_build_pcms, .build_pcms = conexant_build_pcms,
.init = conexant_init, .init = conexant_init,
.free = conexant_free, .free = conexant_free,
#ifdef CONFIG_PM
.resume = conexant_resume,
#endif
}; };
/* /*
...@@ -396,13 +376,13 @@ static int cxt_eapd_put(struct snd_kcontrol *kcontrol, ...@@ -396,13 +376,13 @@ static int cxt_eapd_put(struct snd_kcontrol *kcontrol,
eapd = ucontrol->value.integer.value[0]; eapd = ucontrol->value.integer.value[0];
if (invert) if (invert)
eapd = !eapd; eapd = !eapd;
if (eapd == spec->cur_eapd && !codec->in_resume) if (eapd == spec->cur_eapd)
return 0; return 0;
spec->cur_eapd = eapd; spec->cur_eapd = eapd;
snd_hda_codec_write(codec, nid, snd_hda_codec_write_cache(codec, nid,
0, AC_VERB_SET_EAPD_BTLENABLE, 0, AC_VERB_SET_EAPD_BTLENABLE,
eapd ? 0x02 : 0x00); eapd ? 0x02 : 0x00);
return 1; return 1;
} }
......
This diff is collapsed.
...@@ -78,6 +78,8 @@ ...@@ -78,6 +78,8 @@
/* si3054 codec registers (nodes) access macros */ /* si3054 codec registers (nodes) access macros */
#define GET_REG(codec,reg) (snd_hda_codec_read(codec,reg,0,SI3054_VERB_READ_NODE,0)) #define GET_REG(codec,reg) (snd_hda_codec_read(codec,reg,0,SI3054_VERB_READ_NODE,0))
#define SET_REG(codec,reg,val) (snd_hda_codec_write(codec,reg,0,SI3054_VERB_WRITE_NODE,val)) #define SET_REG(codec,reg,val) (snd_hda_codec_write(codec,reg,0,SI3054_VERB_WRITE_NODE,val))
#define SET_REG_CACHE(codec,reg,val) \
snd_hda_codec_write_cache(codec,reg,0,SI3054_VERB_WRITE_NODE,val)
struct si3054_spec { struct si3054_spec {
...@@ -113,9 +115,9 @@ static int si3054_switch_put(struct snd_kcontrol *kcontrol, ...@@ -113,9 +115,9 @@ static int si3054_switch_put(struct snd_kcontrol *kcontrol,
u16 reg = PRIVATE_REG(kcontrol->private_value); u16 reg = PRIVATE_REG(kcontrol->private_value);
u16 mask = PRIVATE_MASK(kcontrol->private_value); u16 mask = PRIVATE_MASK(kcontrol->private_value);
if (uvalue->value.integer.value[0]) if (uvalue->value.integer.value[0])
SET_REG(codec, reg, (GET_REG(codec, reg)) | mask); SET_REG_CACHE(codec, reg, (GET_REG(codec, reg)) | mask);
else else
SET_REG(codec, reg, (GET_REG(codec, reg)) & ~mask); SET_REG_CACHE(codec, reg, (GET_REG(codec, reg)) & ~mask);
return 0; return 0;
} }
...@@ -267,10 +269,6 @@ static struct hda_codec_ops si3054_patch_ops = { ...@@ -267,10 +269,6 @@ static struct hda_codec_ops si3054_patch_ops = {
.build_pcms = si3054_build_pcms, .build_pcms = si3054_build_pcms,
.init = si3054_init, .init = si3054_init,
.free = si3054_free, .free = si3054_free,
#ifdef CONFIG_PM
//.suspend = si3054_suspend,
.resume = si3054_init,
#endif
}; };
static int patch_si3054(struct hda_codec *codec) static int patch_si3054(struct hda_codec *codec)
......
...@@ -874,16 +874,16 @@ static void stac92xx_enable_gpio_mask(struct hda_codec *codec) ...@@ -874,16 +874,16 @@ static void stac92xx_enable_gpio_mask(struct hda_codec *codec)
{ {
struct sigmatel_spec *spec = codec->spec; struct sigmatel_spec *spec = codec->spec;
/* Configure GPIOx as output */ /* Configure GPIOx as output */
snd_hda_codec_write(codec, codec->afg, 0, snd_hda_codec_write_cache(codec, codec->afg, 0,
AC_VERB_SET_GPIO_DIRECTION, spec->gpio_mask); AC_VERB_SET_GPIO_DIRECTION, spec->gpio_mask);
/* Configure GPIOx as CMOS */ /* Configure GPIOx as CMOS */
snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0x00000000); snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7e7, 0x00000000);
/* Assert GPIOx */ /* Assert GPIOx */
snd_hda_codec_write(codec, codec->afg, 0, snd_hda_codec_write_cache(codec, codec->afg, 0,
AC_VERB_SET_GPIO_DATA, spec->gpio_data); AC_VERB_SET_GPIO_DATA, spec->gpio_data);
/* Enable GPIOx */ /* Enable GPIOx */
snd_hda_codec_write(codec, codec->afg, 0, snd_hda_codec_write_cache(codec, codec->afg, 0,
AC_VERB_SET_GPIO_MASK, spec->gpio_mask); AC_VERB_SET_GPIO_MASK, spec->gpio_mask);
} }
/* /*
...@@ -1082,7 +1082,8 @@ static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid) ...@@ -1082,7 +1082,8 @@ static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type) static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
{ {
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
} }
#define stac92xx_io_switch_info snd_ctl_boolean_mono_info #define stac92xx_io_switch_info snd_ctl_boolean_mono_info
...@@ -1291,8 +1292,8 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, ...@@ -1291,8 +1292,8 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
spec->multiout.num_dacs++; spec->multiout.num_dacs++;
if (conn_len > 1) { if (conn_len > 1) {
/* select this DAC in the pin's input mux */ /* select this DAC in the pin's input mux */
snd_hda_codec_write(codec, nid, 0, snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_CONNECT_SEL, j); AC_VERB_SET_CONNECT_SEL, j);
} }
} }
...@@ -1545,9 +1546,9 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const ...@@ -1545,9 +1546,9 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const
* NID lists. Hopefully this won't get confused. * NID lists. Hopefully this won't get confused.
*/ */
for (i = 0; i < spec->num_muxes; i++) { for (i = 0; i < spec->num_muxes; i++) {
snd_hda_codec_write(codec, spec->mux_nids[i], 0, snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
AC_VERB_SET_CONNECT_SEL, AC_VERB_SET_CONNECT_SEL,
imux->items[0].index); imux->items[0].index);
} }
} }
...@@ -1879,7 +1880,7 @@ static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid, ...@@ -1879,7 +1880,7 @@ static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN)) if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN); pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
snd_hda_codec_write(codec, nid, 0, snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, AC_VERB_SET_PIN_WIDGET_CONTROL,
pin_ctl | flag); pin_ctl | flag);
} }
...@@ -1889,7 +1890,7 @@ static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid, ...@@ -1889,7 +1890,7 @@ static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
{ {
unsigned int pin_ctl = snd_hda_codec_read(codec, nid, unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00); 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
snd_hda_codec_write(codec, nid, 0, snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, AC_VERB_SET_PIN_WIDGET_CONTROL,
pin_ctl & ~flag); pin_ctl & ~flag);
} }
...@@ -1948,21 +1949,10 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) ...@@ -1948,21 +1949,10 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int stac92xx_resume(struct hda_codec *codec) static int stac92xx_resume(struct hda_codec *codec)
{ {
struct sigmatel_spec *spec = codec->spec;
int i;
stac92xx_set_config_regs(codec); stac92xx_set_config_regs(codec);
if (spec->gpio_mask && spec->gpio_data)
stac92xx_enable_gpio_mask(codec);
stac92xx_init(codec); stac92xx_init(codec);
snd_hda_resume_ctls(codec, spec->mixer); snd_hda_codec_resume_amp(codec);
for (i = 0; i < spec->num_mixers; i++) snd_hda_codec_resume_cache(codec);
snd_hda_resume_ctls(codec, spec->mixers[i]);
if (spec->multiout.dig_out_nid)
snd_hda_resume_spdif_out(codec);
if (spec->dig_in_nid)
snd_hda_resume_spdif_in(codec);
return 0; return 0;
} }
#endif #endif
......
...@@ -543,27 +543,6 @@ static int via_init(struct hda_codec *codec) ...@@ -543,27 +543,6 @@ static int via_init(struct hda_codec *codec)
return 0; return 0;
} }
#ifdef CONFIG_PM
/*
* resume
*/
static int via_resume(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
int i;
via_init(codec);
for (i = 0; i < spec->num_mixers; i++)
snd_hda_resume_ctls(codec, spec->mixers[i]);
if (spec->multiout.dig_out_nid)
snd_hda_resume_spdif_out(codec);
if (spec->dig_in_nid)
snd_hda_resume_spdif_in(codec);
return 0;
}
#endif
/* /*
*/ */
static struct hda_codec_ops via_patch_ops = { static struct hda_codec_ops via_patch_ops = {
...@@ -571,9 +550,6 @@ static struct hda_codec_ops via_patch_ops = { ...@@ -571,9 +550,6 @@ static struct hda_codec_ops via_patch_ops = {
.build_pcms = via_build_pcms, .build_pcms = via_build_pcms,
.init = via_init, .init = via_init,
.free = via_free, .free = via_free,
#ifdef CONFIG_PM
.resume = via_resume,
#endif
}; };
/* fill in the dac_nids table from the parsed pin configuration */ /* fill in the dac_nids table from the parsed pin configuration */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment