diff options
author | Takashi Iwai <tiwai@suse.de> | 2008-11-12 03:48:04 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2008-11-12 04:00:56 -0500 |
commit | d7a8943635485597ae7c6d554a8ccf3ce5a42d2d (patch) | |
tree | ceb41ca8ba7f143d2c9d63dec0fe60abc7d59a20 | |
parent | 4f1e6bc3646ab50b8181555ab7e6eeab68b8632a (diff) |
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>
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 59 |
1 files changed, 45 insertions, 14 deletions
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index a51160106df3..4300a679cd86 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -212,7 +212,7 @@ struct sigmatel_spec { | |||
212 | /* i/o switches */ | 212 | /* i/o switches */ |
213 | unsigned int io_switch[2]; | 213 | unsigned int io_switch[2]; |
214 | unsigned int clfe_swap; | 214 | unsigned int clfe_swap; |
215 | unsigned int hp_switch; | 215 | unsigned int hp_switch; /* NID of HP as line-out */ |
216 | unsigned int aloopback; | 216 | unsigned int aloopback; |
217 | 217 | ||
218 | struct hda_pcm pcm_rec[2]; /* PCM information */ | 218 | struct hda_pcm pcm_rec[2]; /* PCM information */ |
@@ -2443,7 +2443,7 @@ static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol, | |||
2443 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 2443 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
2444 | struct sigmatel_spec *spec = codec->spec; | 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 | return 0; | 2447 | return 0; |
2448 | } | 2448 | } |
2449 | 2449 | ||
@@ -2452,8 +2452,9 @@ static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol, | |||
2452 | { | 2452 | { |
2453 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 2453 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
2454 | struct sigmatel_spec *spec = codec->spec; | 2454 | struct sigmatel_spec *spec = codec->spec; |
2455 | 2455 | int nid = kcontrol->private_value; | |
2456 | spec->hp_switch = ucontrol->value.integer.value[0]; | 2456 | |
2457 | spec->hp_switch = ucontrol->value.integer.value[0] ? nid : 0; | ||
2457 | 2458 | ||
2458 | /* check to be sure that the ports are upto date with | 2459 | /* check to be sure that the ports are upto date with |
2459 | * switch changes | 2460 | * switch changes |
@@ -2862,7 +2863,8 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, | |||
2862 | if (cfg->hp_outs > 1) { | 2863 | if (cfg->hp_outs > 1) { |
2863 | err = stac92xx_add_control(spec, | 2864 | err = stac92xx_add_control(spec, |
2864 | STAC_CTL_WIDGET_HP_SWITCH, | 2865 | STAC_CTL_WIDGET_HP_SWITCH, |
2865 | "Headphone as Line Out Switch", 0); | 2866 | "Headphone as Line Out Switch", |
2867 | cfg->hp_pins[cfg->hp_outs - 1]); | ||
2866 | if (err < 0) | 2868 | if (err < 0) |
2867 | return err; | 2869 | return err; |
2868 | } | 2870 | } |
@@ -3786,11 +3788,30 @@ static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid) | |||
3786 | return 0; | 3788 | return 0; |
3787 | } | 3789 | } |
3788 | 3790 | ||
3791 | /* return non-zero if the hp-pin of the given array index isn't | ||
3792 | * a jack-detection target | ||
3793 | */ | ||
3794 | static int no_hp_sensing(struct sigmatel_spec *spec, int i) | ||
3795 | { | ||
3796 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
3797 | |||
3798 | /* ignore sensing of shared line and mic jacks */ | ||
3799 | if (spec->line_switch && | ||
3800 | cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_LINE]) | ||
3801 | return 1; | ||
3802 | if (spec->mic_switch && | ||
3803 | cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_MIC]) | ||
3804 | return 1; | ||
3805 | /* ignore if the pin is set as line-out */ | ||
3806 | if (cfg->hp_pins[i] == spec->hp_switch) | ||
3807 | return 1; | ||
3808 | return 0; | ||
3809 | } | ||
3810 | |||
3789 | static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) | 3811 | static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) |
3790 | { | 3812 | { |
3791 | struct sigmatel_spec *spec = codec->spec; | 3813 | struct sigmatel_spec *spec = codec->spec; |
3792 | struct auto_pin_cfg *cfg = &spec->autocfg; | 3814 | struct auto_pin_cfg *cfg = &spec->autocfg; |
3793 | int nid = cfg->hp_pins[cfg->hp_outs - 1]; | ||
3794 | int i, presence; | 3815 | int i, presence; |
3795 | 3816 | ||
3796 | presence = 0; | 3817 | presence = 0; |
@@ -3801,15 +3822,16 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) | |||
3801 | for (i = 0; i < cfg->hp_outs; i++) { | 3822 | for (i = 0; i < cfg->hp_outs; i++) { |
3802 | if (presence) | 3823 | if (presence) |
3803 | break; | 3824 | break; |
3804 | if (spec->hp_switch && cfg->hp_pins[i] == nid) | 3825 | if (no_hp_sensing(spec, i)) |
3805 | break; | 3826 | continue; |
3806 | presence = get_hp_pin_presence(codec, cfg->hp_pins[i]); | 3827 | presence = get_hp_pin_presence(codec, cfg->hp_pins[i]); |
3807 | } | 3828 | } |
3808 | 3829 | ||
3809 | if (presence) { | 3830 | if (presence) { |
3810 | /* disable lineouts, enable hp */ | 3831 | /* disable lineouts */ |
3811 | if (spec->hp_switch) | 3832 | if (spec->hp_switch) |
3812 | stac92xx_reset_pinctl(codec, nid, AC_PINCTL_OUT_EN); | 3833 | stac92xx_reset_pinctl(codec, spec->hp_switch, |
3834 | AC_PINCTL_OUT_EN); | ||
3813 | for (i = 0; i < cfg->line_outs; i++) | 3835 | for (i = 0; i < cfg->line_outs; i++) |
3814 | stac92xx_reset_pinctl(codec, cfg->line_out_pins[i], | 3836 | stac92xx_reset_pinctl(codec, cfg->line_out_pins[i], |
3815 | AC_PINCTL_OUT_EN); | 3837 | AC_PINCTL_OUT_EN); |
@@ -3821,9 +3843,10 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) | |||
3821 | spec->gpio_dir, spec->gpio_data & | 3843 | spec->gpio_dir, spec->gpio_data & |
3822 | ~spec->eapd_mask); | 3844 | ~spec->eapd_mask); |
3823 | } else { | 3845 | } else { |
3824 | /* enable lineouts, disable hp */ | 3846 | /* enable lineouts */ |
3825 | if (spec->hp_switch) | 3847 | if (spec->hp_switch) |
3826 | stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); | 3848 | stac92xx_set_pinctl(codec, spec->hp_switch, |
3849 | AC_PINCTL_OUT_EN); | ||
3827 | for (i = 0; i < cfg->line_outs; i++) | 3850 | for (i = 0; i < cfg->line_outs; i++) |
3828 | stac92xx_set_pinctl(codec, cfg->line_out_pins[i], | 3851 | stac92xx_set_pinctl(codec, cfg->line_out_pins[i], |
3829 | AC_PINCTL_OUT_EN); | 3852 | AC_PINCTL_OUT_EN); |
@@ -3835,8 +3858,16 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) | |||
3835 | spec->gpio_dir, spec->gpio_data | | 3858 | spec->gpio_dir, spec->gpio_data | |
3836 | spec->eapd_mask); | 3859 | spec->eapd_mask); |
3837 | } | 3860 | } |
3838 | if (!spec->hp_switch && cfg->hp_outs > 1 && presence) | 3861 | /* toggle hp outs */ |
3839 | stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); | 3862 | for (i = 0; i < cfg->hp_outs; i++) { |
3863 | unsigned int val = AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN; | ||
3864 | if (no_hp_sensing(spec, i)) | ||
3865 | continue; | ||
3866 | if (presence) | ||
3867 | stac92xx_set_pinctl(codec, cfg->hp_pins[i], val); | ||
3868 | else | ||
3869 | stac92xx_reset_pinctl(codec, cfg->hp_pins[i], val); | ||
3870 | } | ||
3840 | } | 3871 | } |
3841 | 3872 | ||
3842 | static void stac92xx_pin_sense(struct hda_codec *codec, int idx) | 3873 | static void stac92xx_pin_sense(struct hda_codec *codec, int idx) |