ALSA: hda - Fix IDT/STAC multiple HP detection

Due to the recent change for multiple HP as line-out switch, only
one of the multiple headphons (usually a wrong one) is toggled
and the other pins are still disabled. This causes the silent output
problem on some Dell laptops.

Also, the hp_switch check is screwed up when a line-in or a mic-in
jack exists. This is added as an additional output, but hp_switch
check doesn't take it into account.

This patch fixes these issues: simplify hp_switch check by using
the NID instead of bool, and clean up / fix the toggle of HP pins
in unsol event handler code.

Reference: Novell bnc#443267
https://bugzilla.novell.com/show_bug.cgi?id=443267

Signed-off-by: Takashi Iwai <tiwai@suse.de>

+45 -14
+45 -14
sound/pci/hda/patch_sigmatel.c
··· 212 212 /* i/o switches */ 213 213 unsigned int io_switch[2]; 214 214 unsigned int clfe_swap; 215 - unsigned int hp_switch; 215 + unsigned int hp_switch; /* NID of HP as line-out */ 216 216 unsigned int aloopback; 217 217 218 218 struct hda_pcm pcm_rec[2]; /* PCM information */ ··· 2443 2443 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2444 2444 struct sigmatel_spec *spec = codec->spec; 2445 2445 2446 - ucontrol->value.integer.value[0] = spec->hp_switch; 2446 + ucontrol->value.integer.value[0] = !!spec->hp_switch; 2447 2447 return 0; 2448 2448 } 2449 2449 ··· 2452 2452 { 2453 2453 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2454 2454 struct sigmatel_spec *spec = codec->spec; 2455 - 2456 - spec->hp_switch = ucontrol->value.integer.value[0]; 2455 + int nid = kcontrol->private_value; 2456 + 2457 + spec->hp_switch = ucontrol->value.integer.value[0] ? nid : 0; 2457 2458 2458 2459 /* check to be sure that the ports are upto date with 2459 2460 * switch changes ··· 2863 2862 if (cfg->hp_outs > 1) { 2864 2863 err = stac92xx_add_control(spec, 2865 2864 STAC_CTL_WIDGET_HP_SWITCH, 2866 - "Headphone as Line Out Switch", 0); 2865 + "Headphone as Line Out Switch", 2866 + cfg->hp_pins[cfg->hp_outs - 1]); 2867 2867 if (err < 0) 2868 2868 return err; 2869 2869 } ··· 3788 3786 return 0; 3789 3787 } 3790 3788 3789 + /* return non-zero if the hp-pin of the given array index isn't 3790 + * a jack-detection target 3791 + */ 3792 + static int no_hp_sensing(struct sigmatel_spec *spec, int i) 3793 + { 3794 + struct auto_pin_cfg *cfg = &spec->autocfg; 3795 + 3796 + /* ignore sensing of shared line and mic jacks */ 3797 + if (spec->line_switch && 3798 + cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_LINE]) 3799 + return 1; 3800 + if (spec->mic_switch && 3801 + cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_MIC]) 3802 + return 1; 3803 + /* ignore if the pin is set as line-out */ 3804 + if (cfg->hp_pins[i] == spec->hp_switch) 3805 + return 1; 3806 + return 0; 3807 + } 3808 + 3791 3809 static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) 3792 3810 { 3793 3811 struct sigmatel_spec *spec = codec->spec; 3794 3812 struct auto_pin_cfg *cfg = &spec->autocfg; 3795 - int nid = cfg->hp_pins[cfg->hp_outs - 1]; 3796 3813 int i, presence; 3797 3814 3798 3815 presence = 0; ··· 3822 3801 for (i = 0; i < cfg->hp_outs; i++) { 3823 3802 if (presence) 3824 3803 break; 3825 - if (spec->hp_switch && cfg->hp_pins[i] == nid) 3826 - break; 3804 + if (no_hp_sensing(spec, i)) 3805 + continue; 3827 3806 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]); 3828 3807 } 3829 3808 3830 3809 if (presence) { 3831 - /* disable lineouts, enable hp */ 3810 + /* disable lineouts */ 3832 3811 if (spec->hp_switch) 3833 - stac92xx_reset_pinctl(codec, nid, AC_PINCTL_OUT_EN); 3812 + stac92xx_reset_pinctl(codec, spec->hp_switch, 3813 + AC_PINCTL_OUT_EN); 3834 3814 for (i = 0; i < cfg->line_outs; i++) 3835 3815 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i], 3836 3816 AC_PINCTL_OUT_EN); ··· 3843 3821 spec->gpio_dir, spec->gpio_data & 3844 3822 ~spec->eapd_mask); 3845 3823 } else { 3846 - /* enable lineouts, disable hp */ 3824 + /* enable lineouts */ 3847 3825 if (spec->hp_switch) 3848 - stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); 3826 + stac92xx_set_pinctl(codec, spec->hp_switch, 3827 + AC_PINCTL_OUT_EN); 3849 3828 for (i = 0; i < cfg->line_outs; i++) 3850 3829 stac92xx_set_pinctl(codec, cfg->line_out_pins[i], 3851 3830 AC_PINCTL_OUT_EN); ··· 3858 3835 spec->gpio_dir, spec->gpio_data | 3859 3836 spec->eapd_mask); 3860 3837 } 3861 - if (!spec->hp_switch && cfg->hp_outs > 1 && presence) 3862 - stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); 3838 + /* toggle hp outs */ 3839 + for (i = 0; i < cfg->hp_outs; i++) { 3840 + unsigned int val = AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN; 3841 + if (no_hp_sensing(spec, i)) 3842 + continue; 3843 + if (presence) 3844 + stac92xx_set_pinctl(codec, cfg->hp_pins[i], val); 3845 + else 3846 + stac92xx_reset_pinctl(codec, cfg->hp_pins[i], val); 3847 + } 3863 3848 } 3864 3849 3865 3850 static void stac92xx_pin_sense(struct hda_codec *codec, int idx)