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,
return 0;
val &= 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;
put_vol_mute(codec, info, nid, ch, direction, idx, val);
return 1;
}
#ifdef CONFIG_PM
/* resume the all amp commands from the cache */
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
......@@ -1272,10 +1274,12 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
change = codec->spdif_ctls != val;
codec->spdif_ctls = val;
if (change || codec->in_resume) {
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
if (change) {
snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_DIGI_CONVERT_1,
val & 0xff);
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_2,
snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_DIGI_CONVERT_2,
val >> 8);
}
......@@ -1307,17 +1311,19 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol,
if (ucontrol->value.integer.value[0])
val |= AC_DIG1_ENABLE;
change = codec->spdif_ctls != val;
if (change || codec->in_resume) {
if (change) {
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,
AC_VERB_SET_DIGI_CONVERT_1,
val & 0xff);
/* unmute amp switch (if any) */
if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) &&
(val & AC_DIG1_ENABLE))
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE,
AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT |
AC_AMP_SET_OUTPUT);
(val & AC_DIG1_ENABLE)) {
snd_hda_codec_amp_update(codec, nid, 0, HDA_OUTPUT, 0,
0x80, 0x00);
snd_hda_codec_amp_update(codec, nid, 1, HDA_OUTPUT, 0,
0x80, 0x00);
}
}
mutex_unlock(&codec->spdif_mutex);
return change;
......@@ -1409,10 +1415,10 @@ static int snd_hda_spdif_in_switch_put(struct snd_kcontrol *kcontrol,
mutex_lock(&codec->spdif_mutex);
change = codec->spdif_in_enable != val;
if (change || codec->in_resume) {
if (change) {
codec->spdif_in_enable = val;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
val);
snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_DIGI_CONVERT_1, val);
}
mutex_unlock(&codec->spdif_mutex);
return change;
......@@ -1482,6 +1488,10 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
return 0;
}
#ifdef CONFIG_PM
/*
* command cache
*/
/* build a 32bit cache key with the widget id and the command parameter */
#define build_cmd_cache_key(nid, verb) ((verb << 8) | nid)
......@@ -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,
seq->param);
}
#endif /* CONFIG_PM */
/*
* set power state of the codec
......@@ -2122,12 +2133,12 @@ int snd_hda_ch_mode_put(struct hda_codec *codec,
mode = ucontrol->value.enumerated.item[0];
snd_assert(mode < num_chmodes, return -EINVAL);
if (*max_channelsp == chmode[mode].channels && !codec->in_resume)
if (*max_channelsp == chmode[mode].channels)
return 0;
/* change the current channel setting */
*max_channelsp = chmode[mode].channels;
if (chmode[mode].sequence)
snd_hda_sequence_write(codec, chmode[mode].sequence);
snd_hda_sequence_write_cache(codec, chmode[mode].sequence);
return 1;
}
......@@ -2160,9 +2171,9 @@ int snd_hda_input_mux_put(struct hda_codec *codec,
idx = ucontrol->value.enumerated.item[0];
if (idx >= imux->num_items)
idx = imux->num_items - 1;
if (*cur_val == idx && !codec->in_resume)
if (*cur_val == idx)
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);
*cur_val = idx;
return 1;
......@@ -2608,65 +2619,13 @@ int snd_hda_resume(struct hda_bus *bus)
AC_PWRST_D0);
if (codec->patch_ops.resume)
codec->patch_ops.resume(codec);
}
return 0;
}
/**
* 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);
else {
codec->patch_ops.init(codec);
snd_hda_codec_resume_amp(codec);
snd_hda_codec_resume_cache(codec);
}
}
codec->in_resume = 0;
kfree(val);
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
......@@ -552,11 +552,6 @@ struct hda_codec {
/* set by patch */
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 */
unsigned int num_pcms;
struct hda_pcm *pcm_info;
......@@ -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);
/* cached write */
#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,
const struct hda_verb *seq);
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
......
......@@ -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;
if (val >= ofs)
val -= ofs;
val |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT;
val |= AC_AMP_SET_OUTPUT;
return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, val);
snd_hda_codec_amp_update(codec, node->nid, 0, HDA_OUTPUT, 0, 0xff, val);
snd_hda_codec_amp_update(codec, node->nid, 0, HDA_OUTPUT, 1, 0xff, val);
return 0;
}
/*
......@@ -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;
if (val >= ofs)
val -= ofs;
val |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT;
val |= AC_AMP_SET_INPUT;
// awk added - fixed to allow unmuting of indexed amps
val |= index << AC_AMP_SET_INDEX_SHIFT;
return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, val);
snd_hda_codec_amp_update(codec, node->nid, 0, HDA_INPUT, index,
0xff, val);
snd_hda_codec_amp_update(codec, node->nid, 1, HDA_INPUT, index,
0xff, val);
return 0;
}
/*
......@@ -248,7 +248,8 @@ static int select_input_connection(struct hda_codec *codec, struct hda_gnode *no
unsigned int 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,
/* unmute the PIN output */
unmute_output(codec, node);
/* 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_PINCTL_OUT_EN |
((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,
/* unmute the PIN external input */
unmute_input(codec, node, 0); /* index = 0? */
/* 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 */
}
......
......@@ -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 snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
int direction, int idx, int mask, int val);
#ifdef CONFIG_PM
void snd_hda_codec_resume_amp(struct hda_codec *codec);
#endif
/* mono switch binding multiple inputs */
#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,
int snd_hda_add_new_ctls(struct hda_codec *codec,
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
*/
......
......@@ -318,31 +318,11 @@ static void ad198x_free(struct hda_codec *codec)
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 = {
.build_controls = ad198x_build_controls,
.build_pcms = ad198x_build_pcms,
.init = ad198x_init,
.free = ad198x_free,
#ifdef CONFIG_PM
.resume = ad198x_resume,
#endif
};
......@@ -376,10 +356,10 @@ static int ad198x_eapd_put(struct snd_kcontrol *kcontrol,
eapd = ucontrol->value.integer.value[0];
if (invert)
eapd = !eapd;
if (eapd == spec->cur_eapd && ! codec->in_resume)
if (eapd == spec->cur_eapd)
return 0;
spec->cur_eapd = eapd;
snd_hda_codec_write(codec, nid,
snd_hda_codec_write_cache(codec, nid,
0, AC_VERB_SET_EAPD_BTLENABLE,
eapd ? 0x02 : 0x00);
return 1;
......@@ -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]) {
spec->spdif_route = ucontrol->value.enumerated.item[0];
snd_hda_codec_write(codec, spec->multiout.dig_out_nid, 0,
AC_VERB_SET_CONNECT_SEL, spec->spdif_route);
snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0,
AC_VERB_SET_CONNECT_SEL,
spec->spdif_route);
return 1;
}
return 0;
......@@ -1824,11 +1805,11 @@ static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol,
AC_VERB_GET_AMP_GAIN_MUTE,
AC_AMP_GET_INPUT);
change = sel & 0x80;
if (change || codec->in_resume) {
snd_hda_codec_write(codec, 0x1d, 0,
if (change) {
snd_hda_codec_write_cache(codec, 0x1d, 0,
AC_VERB_SET_AMP_GAIN_MUTE,
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,
AMP_IN_MUTE(1));
}
......@@ -1837,20 +1818,21 @@ static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol,
AC_VERB_GET_AMP_GAIN_MUTE,
AC_AMP_GET_INPUT | 0x01);
change = sel & 0x80;
if (change || codec->in_resume) {
snd_hda_codec_write(codec, 0x1d, 0,
if (change) {
snd_hda_codec_write_cache(codec, 0x1d, 0,
AC_VERB_SET_AMP_GAIN_MUTE,
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,
AMP_IN_UNMUTE(1));
}
sel = snd_hda_codec_read(codec, 0x0b, 0,
AC_VERB_GET_CONNECT_SEL, 0) + 1;
change |= sel != val;
if (change || codec->in_resume)
snd_hda_codec_write(codec, 0x0b, 0,
AC_VERB_SET_CONNECT_SEL, val - 1);
if (change)
snd_hda_codec_write_cache(codec, 0x0b, 0,
AC_VERB_SET_CONNECT_SEL,
val - 1);
}
return change;
}
......
......@@ -62,19 +62,6 @@ static int atihdmi_init(struct hda_codec *codec)
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
*/
......@@ -141,9 +128,6 @@ static struct hda_codec_ops atihdmi_patch_ops = {
.build_pcms = atihdmi_build_pcms,
.init = atihdmi_init,
.free = atihdmi_free,
#ifdef CONFIG_PM
.resume = atihdmi_resume,
#endif
};
static int patch_atihdmi(struct hda_codec *codec)
......
......@@ -427,27 +427,6 @@ static int cmi9880_init(struct hda_codec *codec)
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
*/
......@@ -635,9 +614,6 @@ static struct hda_codec_ops cmi9880_patch_ops = {
.build_pcms = cmi9880_build_pcms,
.init = cmi9880_init,
.free = cmi9880_free,
#ifdef CONFIG_PM
.resume = cmi9880_resume,
#endif
};
static int patch_cmi9880(struct hda_codec *codec)
......
......@@ -311,23 +311,6 @@ static void conexant_free(struct hda_codec *codec)
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)
{
struct conexant_spec *spec = codec->spec;
......@@ -358,9 +341,6 @@ static struct hda_codec_ops conexant_patch_ops = {
.build_pcms = conexant_build_pcms,
.init = conexant_init,
.free = conexant_free,
#ifdef CONFIG_PM
.resume = conexant_resume,
#endif
};
/*
......@@ -396,11 +376,11 @@ static int cxt_eapd_put(struct snd_kcontrol *kcontrol,
eapd = ucontrol->value.integer.value[0];
if (invert)
eapd = !eapd;
if (eapd == spec->cur_eapd && !codec->in_resume)
if (eapd == spec->cur_eapd)
return 0;
spec->cur_eapd = eapd;
snd_hda_codec_write(codec, nid,
snd_hda_codec_write_cache(codec, nid,
0, AC_VERB_SET_EAPD_BTLENABLE,
eapd ? 0x02 : 0x00);
return 1;
......
......@@ -442,7 +442,8 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
change = pinctl != alc_pin_mode_values[val];
if (change) {
/* Set pin mode to that requested */
snd_hda_codec_write(codec,nid,0,AC_VERB_SET_PIN_WIDGET_CONTROL,
snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL,
alc_pin_mode_values[val]);
/* Also enable the retasking pin's input/output as required
......@@ -456,19 +457,23 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
* this turns out to be necessary in the future.
*/
if (val <= 2) {
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE,
AMP_OUT_MUTE);
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE,
AMP_IN_UNMUTE(0));
snd_hda_codec_amp_update(codec, nid, 0, HDA_OUTPUT, 0,
0x80, 0x80);
snd_hda_codec_amp_update(codec, nid, 1, HDA_OUTPUT, 0,
0x80, 0x80);
snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT, 0,
0x80, 0x00);
snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT, 0,
0x80, 0x00);
} else {
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE,
AMP_IN_MUTE(0));
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE,
AMP_OUT_UNMUTE);
snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT, 0,
0x80, 0x80);
snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT, 0,
0x80, 0x80);
snd_hda_codec_amp_update(codec, nid, 0, HDA_OUTPUT, 0,
0x80, 0x00);
snd_hda_codec_amp_update(codec, nid, 1, HDA_OUTPUT, 0,
0x80, 0x00);
}
}
return change;
......@@ -520,7 +525,8 @@ static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
gpio_data &= ~mask;
else
gpio_data |= mask;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_GPIO_DATA, gpio_data);
snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_GPIO_DATA, gpio_data);
return change;
}
......@@ -573,7 +579,7 @@ static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
ctrl_data &= ~mask;
else
ctrl_data |= mask;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
ctrl_data);
return change;
......@@ -2026,27 +2032,6 @@ static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
spec->unsol_event(codec, res);
}
#ifdef CONFIG_PM
/*
* resume
*/
static int alc_resume(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
int i;
alc_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
/*
* Analog playback callbacks
*/
......@@ -2278,9 +2263,6 @@ static struct hda_codec_ops alc_patch_ops = {
.init = alc_init,
.free = alc_free,
.unsol_event = alc_unsol_event,
#ifdef CONFIG_PM
.resume = alc_resume,
#endif
};
......@@ -2377,11 +2359,15 @@ static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
new_ctl = ctls[ucontrol->value.enumerated.item[0]];
if (old_ctl != new_ctl) {
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, new_ctl);
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
(ucontrol->value.enumerated.item[0] >= 3 ?
0xb080 : 0xb000));
int val;
snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL,
new_ctl);
val = ucontrol->value.enumerated.item[0] >= 3 ? 0x80 : 0x00;
snd_hda_codec_amp_update(codec, nid, 0, HDA_OUTPUT, 0,
0x80, val);
snd_hda_codec_amp_update(codec, nid, 1, HDA_OUTPUT, 0,
0x80, val);
return 1;
}
return 0;
......@@ -2424,7 +2410,8 @@ static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
if (ucontrol->value.enumerated.item[0] != sel) {
sel = ucontrol->value.enumerated.item[0] & 3;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, sel);
snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_CONNECT_SEL, sel);
return 1;
}
return 0;
......@@ -4054,13 +4041,17 @@ static void alc260_replacer_672v_automute(struct hda_codec *codec)
present = snd_hda_codec_read(codec, 0x0f, 0,
AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
if (present) {
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 1);
snd_hda_codec_write(codec, 0x0f, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
snd_hda_codec_write_cache(codec, 0x01, 0,
AC_VERB_SET_GPIO_DATA, 1);
snd_hda_codec_write_cache(codec, 0x0f, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL,
PIN_HP);
} else {
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
snd_hda_codec_write(codec, 0x0f, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
snd_hda_codec_write_cache(codec, 0x01, 0,
AC_VERB_SET_GPIO_DATA, 0);
snd_hda_codec_write_cache(codec, 0x0f, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL,
PIN_OUT);
}
}
......@@ -4797,12 +4788,16 @@ static int alc882_mux_enum_put(struct snd_kcontrol *kcontrol,
idx = ucontrol->value.enumerated.item[0];
if (idx >= imux->num_items)
idx = imux->num_items - 1;
if (*cur_val == idx && !codec->in_resume)
if (*cur_val == idx)
return 0;
for (i = 0; i < imux->num_items; i++) {
unsigned int v = (i == idx) ? 0x7000 : 0x7080;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
v | (imux->items[i].index << 8));
unsigned int v = (i == idx) ? 0x00 : 0x80;
snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT,
imux->items[i].index,
0x80, v);
snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT,
imux->items[i].index,
0x80, v);
}
*cur_val = idx;
return 1;
......@@ -5187,7 +5182,8 @@ static void alc882_targa_automute(struct hda_codec *codec)
0x80, present ? 0x80 : 0);
snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0,
0x80, present ? 0x80 : 0);
snd_hda_codec_write(codec, 1, 0, AC_VERB_SET_GPIO_DATA, present ? 1 : 3);
snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
present ? 1 : 3);
}
static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
......@@ -5777,12 +5773,16 @@ static int alc883_mux_enum_put(struct snd_kcontrol *kcontrol,
idx = ucontrol->value.enumerated.item[0];
if (idx >= imux->num_items)
idx = imux->num_items - 1;
if (*cur_val == idx && !codec->in_resume)
if (*cur_val == idx)
return 0;
for (i = 0; i < imux->num_items; i++) {
unsigned int v = (i == idx) ? 0x7000 : 0x7080;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
v | (imux->items[i].index << 8));
unsigned int v = (i == idx) ? 0x00 : 0x80;
snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT,
imux->items[i].index,
0x80, v);
snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT,
imux->items[i].index,
0x80, v);
}
*cur_val = idx;
return 1;
......@@ -6509,7 +6509,7 @@ static void alc883_tagra_automute(struct hda_codec *codec)
0x80, bits);
snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0,
0x80, bits);
snd_hda_codec_write(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
present ? 1 : 3);
}
......@@ -7510,8 +7510,8 @@ static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
0x80, valp[0] ? 0 : 0x80);
change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
0x80, valp[1] ? 0 : 0x80);
if (change || codec->in_resume)
alc262_fujitsu_automute(codec, codec->in_resume);
if (change)
alc262_fujitsu_automute(codec, 0);
return change;
}
......@@ -8328,13 +8328,16 @@ static int alc268_mux_enum_put(struct snd_kcontrol *kcontrol,
idx = ucontrol->value.enumerated.item[0];
if (idx >= imux->num_items)
idx = imux->num_items - 1;
if (*cur_val == idx && !codec->in_resume)
if (*cur_val == idx)
return 0;
for (i = 0; i < imux->num_items; i++) {
unsigned int v = (i == idx) ? 0x7000 : 0x7080;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
v | (imux->items[i].index << 8));
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL,
unsigned int v = (i == idx) ? 0x00 : 0x80;
snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT,
imux->items[i].index, 0x80, v);
snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT,
imux->items[i].index, 0x80, v);
snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_CONNECT_SEL,
idx );
}
*cur_val = idx;
......@@ -9916,12 +9919,14 @@ static int alc861vd_mux_enum_put(struct snd_kcontrol *kcontrol,
idx = ucontrol->value.enumerated.item[0];
if (idx >= imux->num_items)
idx = imux->num_items - 1;
if (*cur_val == idx && !codec->in_resume)
if (*cur_val == idx)
return 0;
for (i = 0; i < imux->num_items; i++) {
unsigned int v = (i == idx) ? 0x7000 : 0x7080;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
v | (imux->items[i].index << 8));
unsigned int v = (i == idx) ? 0x00 : 0x80;
snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT,
imux->items[i].index, 0x80, v);
snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT,
imux->items[i].index, 0x80, v);
}
*cur_val = idx;
return 1;
......@@ -10847,12 +10852,14 @@ static int alc662_mux_enum_put(struct snd_kcontrol *kcontrol,
idx = ucontrol->value.enumerated.item[0];
if (idx >= imux->num_items)
idx = imux->num_items - 1;
if (*cur_val == idx && !codec->in_resume)
if (*cur_val == idx)
return 0;
for (i = 0; i < imux->num_items; i++) {
unsigned int v = (i == idx) ? 0x7000 : 0x7080;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
v | (imux->items[i].index << 8));
unsigned int v = (i == idx) ? 0x00 : 0x80;
snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT,
imux->items[i].index, 0x80, v);
snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT,
imux->items[i].index, 0x80, v);
}
*cur_val = idx;
return 1;
......
......@@ -78,6 +78,8 @@
/* si3054 codec registers (nodes) access macros */
#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_CACHE(codec,reg,val) \
snd_hda_codec_write_cache(codec,reg,0,SI3054_VERB_WRITE_NODE,val)
struct si3054_spec {
......@@ -113,9 +115,9 @@ static int si3054_switch_put(struct snd_kcontrol *kcontrol,
u16 reg = PRIVATE_REG(kcontrol->private_value);
u16 mask = PRIVATE_MASK(kcontrol->private_value);
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
SET_REG(codec, reg, (GET_REG(codec, reg)) & ~mask);
SET_REG_CACHE(codec, reg, (GET_REG(codec, reg)) & ~mask);
return 0;
}
......@@ -267,10 +269,6 @@ static struct hda_codec_ops si3054_patch_ops = {
.build_pcms = si3054_build_pcms,
.init = si3054_init,
.free = si3054_free,
#ifdef CONFIG_PM
//.suspend = si3054_suspend,
.resume = si3054_init,
#endif
};
static int patch_si3054(struct hda_codec *codec)
......
......@@ -874,15 +874,15 @@ static void stac92xx_enable_gpio_mask(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
/* 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);
/* 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 */
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);
/* 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);
}
......@@ -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)
{
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
......@@ -1291,7 +1292,7 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
spec->multiout.num_dacs++;
if (conn_len > 1) {
/* 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);
}
......@@ -1545,7 +1546,7 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const
* NID lists. Hopefully this won't get confused.
*/
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,
imux->items[0].index);
}
......@@ -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))
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,
pin_ctl | flag);
}
......@@ -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,
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,
pin_ctl & ~flag);
}
......@@ -1948,21 +1949,10 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
#ifdef CONFIG_PM
static int stac92xx_resume(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
int i;
stac92xx_set_config_regs(codec);
if (spec->gpio_mask && spec->gpio_data)
stac92xx_enable_gpio_mask(codec);
stac92xx_init(codec);
snd_hda_resume_ctls(codec, spec->mixer);
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);
snd_hda_codec_resume_amp(codec);
snd_hda_codec_resume_cache(codec);
return 0;
}
#endif
......
......@@ -543,27 +543,6 @@ static int via_init(struct hda_codec *codec)
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 = {
......@@ -571,9 +550,6 @@ static struct hda_codec_ops via_patch_ops = {
.build_pcms = via_build_pcms,
.init = via_init,
.free = via_free,
#ifdef CONFIG_PM
.resume = via_resume,
#endif
};
/* 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