diff options
author | Takashi Iwai <tiwai@suse.de> | 2012-09-14 05:58:54 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2012-09-14 06:23:50 -0400 |
commit | 62cbde1868b16e7cf1ed115cdfb9cbe82e230f0a (patch) | |
tree | 3350de8dc4a167f91bd27f0f93a02aa6a911a63b /sound/pci | |
parent | b35cc8225845112a616e3a2266d2fde5ab13d3ab (diff) |
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: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 84 |
1 files changed, 74 insertions, 10 deletions
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index eef9c6cad25d..bb6c50e7b5da 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -103,6 +103,7 @@ enum { | |||
103 | STAC_HP_ZEPHYR, | 103 | STAC_HP_ZEPHYR, |
104 | STAC_92HD83XXX_HP_LED, | 104 | STAC_92HD83XXX_HP_LED, |
105 | STAC_92HD83XXX_HP_INV_LED, | 105 | STAC_92HD83XXX_HP_INV_LED, |
106 | STAC_92HD83XXX_HP_MIC_LED, | ||
106 | STAC_92HD83XXX_MODELS | 107 | STAC_92HD83XXX_MODELS |
107 | }; | 108 | }; |
108 | 109 | ||
@@ -215,6 +216,9 @@ struct sigmatel_spec { | |||
215 | unsigned int vref_mute_led_nid; /* pin NID for mute-LED vref control */ | 216 | unsigned int vref_mute_led_nid; /* pin NID for mute-LED vref control */ |
216 | unsigned int vref_led; | 217 | unsigned int vref_led; |
217 | 218 | ||
219 | unsigned int mic_mute_led_gpio; /* capture mute LED GPIO */ | ||
220 | bool mic_mute_led_on; /* current mic mute state */ | ||
221 | |||
218 | /* stream */ | 222 | /* stream */ |
219 | unsigned int stream_delay; | 223 | unsigned int stream_delay; |
220 | 224 | ||
@@ -1679,6 +1683,7 @@ static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { | |||
1679 | [STAC_HP_ZEPHYR] = "hp-zephyr", | 1683 | [STAC_HP_ZEPHYR] = "hp-zephyr", |
1680 | [STAC_92HD83XXX_HP_LED] = "hp-led", | 1684 | [STAC_92HD83XXX_HP_LED] = "hp-led", |
1681 | [STAC_92HD83XXX_HP_INV_LED] = "hp-inv-led", | 1685 | [STAC_92HD83XXX_HP_INV_LED] = "hp-inv-led", |
1686 | [STAC_92HD83XXX_HP_MIC_LED] = "hp-mic-led", | ||
1682 | }; | 1687 | }; |
1683 | 1688 | ||
1684 | static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { | 1689 | static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { |
@@ -1703,6 +1708,8 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { | |||
1703 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), | 1708 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), |
1704 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165B, | 1709 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165B, |
1705 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), | 1710 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), |
1711 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18df, | ||
1712 | "HP Folio", STAC_92HD83XXX_HP_MIC_LED), | ||
1706 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3388, | 1713 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3388, |
1707 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), | 1714 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), |
1708 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3389, | 1715 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3389, |
@@ -2791,18 +2798,27 @@ stac_control_new(struct sigmatel_spec *spec, | |||
2791 | return knew; | 2798 | return knew; |
2792 | } | 2799 | } |
2793 | 2800 | ||
2794 | static int stac92xx_add_control_temp(struct sigmatel_spec *spec, | 2801 | static struct snd_kcontrol_new * |
2795 | const struct snd_kcontrol_new *ktemp, | 2802 | add_control_temp(struct sigmatel_spec *spec, |
2796 | int idx, const char *name, | 2803 | const struct snd_kcontrol_new *ktemp, |
2797 | unsigned long val) | 2804 | int idx, const char *name, |
2805 | unsigned long val) | ||
2798 | { | 2806 | { |
2799 | struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name, | 2807 | struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name, |
2800 | HDA_SUBDEV_AMP_FLAG); | 2808 | HDA_SUBDEV_AMP_FLAG); |
2801 | if (!knew) | 2809 | if (!knew) |
2802 | return -ENOMEM; | 2810 | return NULL; |
2803 | knew->index = idx; | 2811 | knew->index = idx; |
2804 | knew->private_value = val; | 2812 | knew->private_value = val; |
2805 | return 0; | 2813 | return knew; |
2814 | } | ||
2815 | |||
2816 | static int stac92xx_add_control_temp(struct sigmatel_spec *spec, | ||
2817 | const struct snd_kcontrol_new *ktemp, | ||
2818 | int idx, const char *name, | ||
2819 | unsigned long val) | ||
2820 | { | ||
2821 | return add_control_temp(spec, ktemp, idx, name, val) ? 0 : -ENOMEM; | ||
2806 | } | 2822 | } |
2807 | 2823 | ||
2808 | static inline int stac92xx_add_control_idx(struct sigmatel_spec *spec, | 2824 | 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 | return 0; | 3261 | return 0; |
3246 | } | 3262 | } |
3247 | 3263 | ||
3264 | static void stac_gpio_set(struct hda_codec *codec, unsigned int mask, | ||
3265 | unsigned int dir_mask, unsigned int data); | ||
3266 | |||
3267 | /* hook for controlling mic-mute LED GPIO */ | ||
3268 | static int stac92xx_capture_sw_put_led(struct snd_kcontrol *kcontrol, | ||
3269 | struct snd_ctl_elem_value *ucontrol) | ||
3270 | { | ||
3271 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
3272 | struct sigmatel_spec *spec = codec->spec; | ||
3273 | int err; | ||
3274 | bool mute; | ||
3275 | |||
3276 | err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); | ||
3277 | if (err <= 0) | ||
3278 | return err; | ||
3279 | mute = !(ucontrol->value.integer.value[0] && | ||
3280 | ucontrol->value.integer.value[1]); | ||
3281 | if (spec->mic_mute_led_on != mute) { | ||
3282 | spec->mic_mute_led_on = mute; | ||
3283 | if (mute) | ||
3284 | spec->gpio_data |= spec->mic_mute_led_gpio; | ||
3285 | else | ||
3286 | spec->gpio_data &= ~spec->mic_mute_led_gpio; | ||
3287 | stac_gpio_set(codec, spec->gpio_mask, | ||
3288 | spec->gpio_dir, spec->gpio_data); | ||
3289 | } | ||
3290 | return err; | ||
3291 | } | ||
3292 | |||
3248 | static int stac92xx_add_capvol_ctls(struct hda_codec *codec, unsigned long vol, | 3293 | static int stac92xx_add_capvol_ctls(struct hda_codec *codec, unsigned long vol, |
3249 | unsigned long sw, int idx) | 3294 | unsigned long sw, int idx) |
3250 | { | 3295 | { |
3296 | struct sigmatel_spec *spec = codec->spec; | ||
3297 | struct snd_kcontrol_new *knew; | ||
3251 | int err; | 3298 | int err; |
3299 | |||
3252 | err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx, | 3300 | err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx, |
3253 | "Capture Volume", vol); | 3301 | "Capture Volume", vol); |
3254 | if (err < 0) | 3302 | if (err < 0) |
3255 | return err; | 3303 | return err; |
3256 | err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_MUTE, idx, | 3304 | |
3257 | "Capture Switch", sw); | 3305 | knew = add_control_temp(spec, |
3258 | if (err < 0) | 3306 | &stac92xx_control_templates[STAC_CTL_WIDGET_MUTE], |
3259 | return err; | 3307 | idx, "Capture Switch", sw); |
3308 | if (!knew) | ||
3309 | return -ENOMEM; | ||
3310 | /* add a LED hook for some HP laptops */ | ||
3311 | if (spec->mic_mute_led_gpio) | ||
3312 | knew->put = stac92xx_capture_sw_put_led; | ||
3313 | |||
3260 | return 0; | 3314 | return 0; |
3261 | } | 3315 | } |
3262 | 3316 | ||
@@ -5579,6 +5633,9 @@ again: | |||
5579 | case STAC_92HD83XXX_HP_INV_LED: | 5633 | case STAC_92HD83XXX_HP_INV_LED: |
5580 | default_polarity = 1; | 5634 | default_polarity = 1; |
5581 | break; | 5635 | break; |
5636 | case STAC_92HD83XXX_HP_MIC_LED: | ||
5637 | spec->mic_mute_led_gpio = 0x08; /* GPIO3 */ | ||
5638 | break; | ||
5582 | } | 5639 | } |
5583 | 5640 | ||
5584 | if (find_mute_led_cfg(codec, default_polarity)) | 5641 | if (find_mute_led_cfg(codec, default_polarity)) |
@@ -5597,6 +5654,13 @@ again: | |||
5597 | } | 5654 | } |
5598 | } | 5655 | } |
5599 | 5656 | ||
5657 | if (spec->mic_mute_led_gpio) { | ||
5658 | spec->gpio_mask |= spec->mic_mute_led_gpio; | ||
5659 | spec->gpio_dir |= spec->mic_mute_led_gpio; | ||
5660 | spec->mic_mute_led_on = true; | ||
5661 | spec->gpio_data |= spec->mic_mute_led_gpio; | ||
5662 | } | ||
5663 | |||
5600 | err = stac92xx_parse_auto_config(codec); | 5664 | err = stac92xx_parse_auto_config(codec); |
5601 | if (!err) { | 5665 | if (!err) { |
5602 | if (spec->board_config < 0) { | 5666 | if (spec->board_config < 0) { |