Commit 2faa3bf1 authored by Takashi Iwai's avatar Takashi Iwai

ALSA: hda - Rewrite the mute-LED hook with vmaster hook in patch_sigmatel.c

The mute-LED is controlled in patch_sigmatel.c by (ab-)using the
powersave hook.  This can be now rewritten with the vmaster hook
instead, which is much simpler and can work even without
CONFIG_SND_HDA_POWER_SAVE kconfig.

A drawback is that the mute-LED corresponds _only_ to the Master mixer
switch instead of checking the whole DACs.  But usually this shouldn't
be a big problem as PA enables the mixer elements accordingly.

Also, this patch changes the code to create vmaster always even on
STAC9200 and STAC925x.  The former "Master" on these chips are renamed
as "PCM" now.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 29e5853d
...@@ -310,6 +310,8 @@ struct sigmatel_spec { ...@@ -310,6 +310,8 @@ struct sigmatel_spec {
unsigned long auto_capvols[MAX_ADCS_NUM]; unsigned long auto_capvols[MAX_ADCS_NUM];
unsigned auto_dmic_cnt; unsigned auto_dmic_cnt;
hda_nid_t auto_dmic_nids[MAX_DMICS_NUM]; hda_nid_t auto_dmic_nids[MAX_DMICS_NUM];
struct snd_kcontrol *vmaster_sw_kctl;
}; };
static const hda_nid_t stac9200_adc_nids[1] = { static const hda_nid_t stac9200_adc_nids[1] = {
...@@ -1007,8 +1009,8 @@ static const struct hda_verb stac9205_core_init[] = { ...@@ -1007,8 +1009,8 @@ static const struct hda_verb stac9205_core_init[] = {
} }
static const struct snd_kcontrol_new stac9200_mixer[] = { static const struct snd_kcontrol_new stac9200_mixer[] = {
HDA_CODEC_VOLUME_MIN_MUTE("Master Playback Volume", 0xb, 0, HDA_OUTPUT), HDA_CODEC_VOLUME_MIN_MUTE("PCM Playback Volume", 0xb, 0, HDA_OUTPUT),
HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), HDA_CODEC_MUTE("PCM Playback Switch", 0xb, 0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
{ } /* end */ { } /* end */
...@@ -1035,8 +1037,8 @@ static const struct snd_kcontrol_new stac92hd71bxx_loopback[] = { ...@@ -1035,8 +1037,8 @@ static const struct snd_kcontrol_new stac92hd71bxx_loopback[] = {
}; };
static const struct snd_kcontrol_new stac925x_mixer[] = { static const struct snd_kcontrol_new stac925x_mixer[] = {
HDA_CODEC_VOLUME_MIN_MUTE("Master Playback Volume", 0xe, 0, HDA_OUTPUT), HDA_CODEC_VOLUME_MIN_MUTE("PCM Playback Volume", 0xe, 0, HDA_OUTPUT),
HDA_CODEC_MUTE("Master Playback Switch", 0x0e, 0, HDA_OUTPUT), HDA_CODEC_MUTE("PCM Playback Switch", 0x0e, 0, HDA_OUTPUT),
{ } /* end */ { } /* end */
}; };
...@@ -1074,11 +1076,19 @@ static const char * const slave_pfxs[] = { ...@@ -1074,11 +1076,19 @@ static const char * const slave_pfxs[] = {
NULL NULL
}; };
static void stac92xx_update_led_status(struct hda_codec *codec, int enabled);
static void stac92xx_vmaster_hook(void *private_data, int val)
{
stac92xx_update_led_status(private_data, val);
}
static void stac92xx_free_kctls(struct hda_codec *codec); static void stac92xx_free_kctls(struct hda_codec *codec);
static int stac92xx_build_controls(struct hda_codec *codec) static int stac92xx_build_controls(struct hda_codec *codec)
{ {
struct sigmatel_spec *spec = codec->spec; struct sigmatel_spec *spec = codec->spec;
unsigned int vmaster_tlv[4];
int err; int err;
int i; int i;
...@@ -1135,26 +1145,29 @@ static int stac92xx_build_controls(struct hda_codec *codec) ...@@ -1135,26 +1145,29 @@ static int stac92xx_build_controls(struct hda_codec *codec)
} }
/* if we have no master control, let's create it */ /* if we have no master control, let's create it */
if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
unsigned int vmaster_tlv[4]; HDA_OUTPUT, vmaster_tlv);
snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0], /* correct volume offset */
HDA_OUTPUT, vmaster_tlv); vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset;
/* correct volume offset */ /* minimum value is actually mute */
vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset; vmaster_tlv[3] |= TLV_DB_SCALE_MUTE;
/* minimum value is actually mute */ err = snd_hda_add_vmaster(codec, "Master Playback Volume",
vmaster_tlv[3] |= TLV_DB_SCALE_MUTE; vmaster_tlv, slave_pfxs,
err = snd_hda_add_vmaster(codec, "Master Playback Volume", "Playback Volume");
vmaster_tlv, slave_pfxs, if (err < 0)
"Playback Volume"); return err;
if (err < 0)
return err; err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
} NULL, slave_pfxs,
if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { "Playback Switch", true,
err = snd_hda_add_vmaster(codec, "Master Playback Switch", &spec->vmaster_sw_kctl);
NULL, slave_pfxs, if (err < 0)
"Playback Switch"); return err;
if (err < 0)
return err; if (spec->gpio_led) {
snd_ctl_add_vmaster_hook(spec->vmaster_sw_kctl,
stac92xx_vmaster_hook, codec);
snd_ctl_sync_vmaster_hook(spec->vmaster_sw_kctl);
} }
if (spec->aloopback_ctl && if (spec->aloopback_ctl &&
...@@ -4419,8 +4432,7 @@ static int stac92xx_init(struct hda_codec *codec) ...@@ -4419,8 +4432,7 @@ static int stac92xx_init(struct hda_codec *codec)
snd_hda_jack_report_sync(codec); snd_hda_jack_report_sync(codec);
/* sync mute LED */ /* sync mute LED */
if (spec->gpio_led) snd_ctl_sync_vmaster_hook(spec->vmaster_sw_kctl);
hda_call_check_power_status(codec, 0x01);
if (spec->dac_list) if (spec->dac_list)
stac92xx_power_down(codec); stac92xx_power_down(codec);
return 0; return 0;
...@@ -5033,83 +5045,37 @@ static void stac92xx_set_power_state(struct hda_codec *codec, hda_nid_t fg, ...@@ -5033,83 +5045,37 @@ static void stac92xx_set_power_state(struct hda_codec *codec, hda_nid_t fg,
afg_power_state); afg_power_state);
snd_hda_codec_set_power_to_all(codec, fg, power_state, true); snd_hda_codec_set_power_to_all(codec, fg, power_state, true);
} }
#endif /* CONFIG_SND_HDA_POWER_SAVE */
#endif /* CONFIG_PM */
/* /* update mute-LED accoring to the master switch */
* For this feature CONFIG_SND_HDA_POWER_SAVE is needed static void stac92xx_update_led_status(struct hda_codec *codec, int enabled)
* 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; struct sigmatel_spec *spec = codec->spec;
int i, num_ext_dacs, muted = 1; int muted = !enabled;
unsigned int muted_lvl, notmtd_lvl;
hda_nid_t nid;
if (!spec->gpio_led) if (!spec->gpio_led)
return 0; return;
/* LED state is inverted on these systems */
if (spec->gpio_led_polarity)
muted = !muted;
for (i = 0; i < spec->multiout.num_dacs; i++) {
nid = spec->multiout.dac_nids[i];
if (!(snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) &
HDA_AMP_MUTE)) {
muted = 0; /* something heard */
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 */
}
}
/*polarity defines *not* muted state level*/ /*polarity defines *not* muted state level*/
if (!spec->vref_mute_led_nid) { if (!spec->vref_mute_led_nid) {
if (muted) if (muted)
spec->gpio_data &= ~spec->gpio_led; /* orange */ spec->gpio_data &= ~spec->gpio_led; /* orange */
else else
spec->gpio_data |= spec->gpio_led; /* white */ spec->gpio_data |= spec->gpio_led; /* white */
if (!spec->gpio_led_polarity) {
/* LED state is inverted on these systems */
spec->gpio_data ^= spec->gpio_led;
}
stac_gpio_set(codec, spec->gpio_mask, stac_gpio_set(codec, spec->gpio_mask,
spec->gpio_dir, spec->gpio_data); spec->gpio_dir, spec->gpio_data);
} else { } else {
notmtd_lvl = spec->gpio_led_polarity ? spec->vref_led = muted ? AC_PINCTL_VREF_50 : AC_PINCTL_VREF_GRD;
AC_PINCTL_VREF_50 : AC_PINCTL_VREF_GRD;
muted_lvl = spec->gpio_led_polarity ?
AC_PINCTL_VREF_GRD : AC_PINCTL_VREF_50;
spec->vref_led = muted ? muted_lvl : notmtd_lvl;
stac_vrefout_set(codec, spec->vref_mute_led_nid, stac_vrefout_set(codec, spec->vref_mute_led_nid,
spec->vref_led); spec->vref_led);
} }
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 /* CONFIG_SND_HDA_POWER_SAVE */
#endif /* CONFIG_PM */
static const struct hda_codec_ops stac92xx_patch_ops = { static const struct hda_codec_ops stac92xx_patch_ops = {
.build_controls = stac92xx_build_controls, .build_controls = stac92xx_build_controls,
.build_pcms = stac92xx_build_pcms, .build_pcms = stac92xx_build_pcms,
...@@ -5627,8 +5593,6 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) ...@@ -5627,8 +5593,6 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
stac92xx_set_power_state; stac92xx_set_power_state;
} }
codec->patch_ops.pre_resume = stac92xx_pre_resume; codec->patch_ops.pre_resume = stac92xx_pre_resume;
codec->patch_ops.check_power_status =
stac92xx_check_power_status;
} }
#endif #endif
...@@ -5938,8 +5902,6 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) ...@@ -5938,8 +5902,6 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
stac92xx_set_power_state; stac92xx_set_power_state;
} }
codec->patch_ops.pre_resume = stac92xx_pre_resume; codec->patch_ops.pre_resume = stac92xx_pre_resume;
codec->patch_ops.check_power_status =
stac92xx_check_power_status;
} }
#endif #endif
......
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