Commit 62cbde18 authored by Takashi Iwai's avatar Takashi Iwai

ALSA: hda - Add mic-mute LED control for HP laptop

Some of new HP laptops have a LED for microphone (or recording) mute,
and it's controlled by GPIO pin 3.

Bind this with the capture switch to turn it on/off properly by the
mixer change.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent b35cc822
...@@ -103,6 +103,7 @@ enum { ...@@ -103,6 +103,7 @@ enum {
STAC_HP_ZEPHYR, STAC_HP_ZEPHYR,
STAC_92HD83XXX_HP_LED, STAC_92HD83XXX_HP_LED,
STAC_92HD83XXX_HP_INV_LED, STAC_92HD83XXX_HP_INV_LED,
STAC_92HD83XXX_HP_MIC_LED,
STAC_92HD83XXX_MODELS STAC_92HD83XXX_MODELS
}; };
...@@ -215,6 +216,9 @@ struct sigmatel_spec { ...@@ -215,6 +216,9 @@ struct sigmatel_spec {
unsigned int vref_mute_led_nid; /* pin NID for mute-LED vref control */ unsigned int vref_mute_led_nid; /* pin NID for mute-LED vref control */
unsigned int vref_led; unsigned int vref_led;
unsigned int mic_mute_led_gpio; /* capture mute LED GPIO */
bool mic_mute_led_on; /* current mic mute state */
/* stream */ /* stream */
unsigned int stream_delay; unsigned int stream_delay;
...@@ -1679,6 +1683,7 @@ static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { ...@@ -1679,6 +1683,7 @@ static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
[STAC_HP_ZEPHYR] = "hp-zephyr", [STAC_HP_ZEPHYR] = "hp-zephyr",
[STAC_92HD83XXX_HP_LED] = "hp-led", [STAC_92HD83XXX_HP_LED] = "hp-led",
[STAC_92HD83XXX_HP_INV_LED] = "hp-inv-led", [STAC_92HD83XXX_HP_INV_LED] = "hp-inv-led",
[STAC_92HD83XXX_HP_MIC_LED] = "hp-mic-led",
}; };
static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
...@@ -1703,6 +1708,8 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { ...@@ -1703,6 +1708,8 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165B, SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165B,
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18df,
"HP Folio", STAC_92HD83XXX_HP_MIC_LED),
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3388, SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3388,
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3389, SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3389,
...@@ -2791,7 +2798,8 @@ stac_control_new(struct sigmatel_spec *spec, ...@@ -2791,7 +2798,8 @@ stac_control_new(struct sigmatel_spec *spec,
return knew; return knew;
} }
static int stac92xx_add_control_temp(struct sigmatel_spec *spec, static struct snd_kcontrol_new *
add_control_temp(struct sigmatel_spec *spec,
const struct snd_kcontrol_new *ktemp, const struct snd_kcontrol_new *ktemp,
int idx, const char *name, int idx, const char *name,
unsigned long val) unsigned long val)
...@@ -2799,10 +2807,18 @@ static int stac92xx_add_control_temp(struct sigmatel_spec *spec, ...@@ -2799,10 +2807,18 @@ static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name, struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name,
HDA_SUBDEV_AMP_FLAG); HDA_SUBDEV_AMP_FLAG);
if (!knew) if (!knew)
return -ENOMEM; return NULL;
knew->index = idx; knew->index = idx;
knew->private_value = val; knew->private_value = val;
return 0; return knew;
}
static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
const struct snd_kcontrol_new *ktemp,
int idx, const char *name,
unsigned long val)
{
return add_control_temp(spec, ktemp, idx, name, val) ? 0 : -ENOMEM;
} }
static inline int stac92xx_add_control_idx(struct sigmatel_spec *spec, static inline int stac92xx_add_control_idx(struct sigmatel_spec *spec,
...@@ -3245,18 +3261,56 @@ static int create_multi_out_ctls(struct hda_codec *codec, int num_outs, ...@@ -3245,18 +3261,56 @@ static int create_multi_out_ctls(struct hda_codec *codec, int num_outs,
return 0; return 0;
} }
static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
unsigned int dir_mask, unsigned int data);
/* hook for controlling mic-mute LED GPIO */
static int stac92xx_capture_sw_put_led(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct sigmatel_spec *spec = codec->spec;
int err;
bool mute;
err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
if (err <= 0)
return err;
mute = !(ucontrol->value.integer.value[0] &&
ucontrol->value.integer.value[1]);
if (spec->mic_mute_led_on != mute) {
spec->mic_mute_led_on = mute;
if (mute)
spec->gpio_data |= spec->mic_mute_led_gpio;
else
spec->gpio_data &= ~spec->mic_mute_led_gpio;
stac_gpio_set(codec, spec->gpio_mask,
spec->gpio_dir, spec->gpio_data);
}
return err;
}
static int stac92xx_add_capvol_ctls(struct hda_codec *codec, unsigned long vol, static int stac92xx_add_capvol_ctls(struct hda_codec *codec, unsigned long vol,
unsigned long sw, int idx) unsigned long sw, int idx)
{ {
struct sigmatel_spec *spec = codec->spec;
struct snd_kcontrol_new *knew;
int err; int err;
err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx, err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx,
"Capture Volume", vol); "Capture Volume", vol);
if (err < 0) if (err < 0)
return err; return err;
err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_MUTE, idx,
"Capture Switch", sw); knew = add_control_temp(spec,
if (err < 0) &stac92xx_control_templates[STAC_CTL_WIDGET_MUTE],
return err; idx, "Capture Switch", sw);
if (!knew)
return -ENOMEM;
/* add a LED hook for some HP laptops */
if (spec->mic_mute_led_gpio)
knew->put = stac92xx_capture_sw_put_led;
return 0; return 0;
} }
...@@ -5579,6 +5633,9 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) ...@@ -5579,6 +5633,9 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
case STAC_92HD83XXX_HP_INV_LED: case STAC_92HD83XXX_HP_INV_LED:
default_polarity = 1; default_polarity = 1;
break; break;
case STAC_92HD83XXX_HP_MIC_LED:
spec->mic_mute_led_gpio = 0x08; /* GPIO3 */
break;
} }
if (find_mute_led_cfg(codec, default_polarity)) if (find_mute_led_cfg(codec, default_polarity))
...@@ -5597,6 +5654,13 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) ...@@ -5597,6 +5654,13 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
} }
} }
if (spec->mic_mute_led_gpio) {
spec->gpio_mask |= spec->mic_mute_led_gpio;
spec->gpio_dir |= spec->mic_mute_led_gpio;
spec->mic_mute_led_on = true;
spec->gpio_data |= spec->mic_mute_led_gpio;
}
err = stac92xx_parse_auto_config(codec); err = stac92xx_parse_auto_config(codec);
if (!err) { if (!err) {
if (spec->board_config < 0) { if (spec->board_config < 0) {
......
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