aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_sigmatel.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2012-09-14 05:58:54 -0400
committerTakashi Iwai <tiwai@suse.de>2012-09-14 06:23:50 -0400
commit62cbde1868b16e7cf1ed115cdfb9cbe82e230f0a (patch)
tree3350de8dc4a167f91bd27f0f93a02aa6a911a63b /sound/pci/hda/patch_sigmatel.c
parentb35cc8225845112a616e3a2266d2fde5ab13d3ab (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/hda/patch_sigmatel.c')
-rw-r--r--sound/pci/hda/patch_sigmatel.c84
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
1684static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { 1689static 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
2794static int stac92xx_add_control_temp(struct sigmatel_spec *spec, 2801static struct snd_kcontrol_new *
2795 const struct snd_kcontrol_new *ktemp, 2802add_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
2816static 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
2808static inline int stac92xx_add_control_idx(struct sigmatel_spec *spec, 2824static 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
3264static 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 */
3268static 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
3248static int stac92xx_add_capvol_ctls(struct hda_codec *codec, unsigned long vol, 3293static 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) {