diff options
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 85 |
1 files changed, 63 insertions, 22 deletions
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index e6085915d86d..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 | } |
@@ -3530,6 +3532,12 @@ static int stac9200_parse_auto_config(struct hda_codec *codec) | |||
3530 | if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0) | 3532 | if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0) |
3531 | return err; | 3533 | return err; |
3532 | 3534 | ||
3535 | if (spec->num_muxes > 0) { | ||
3536 | err = stac92xx_auto_create_mux_input_ctls(codec); | ||
3537 | if (err < 0) | ||
3538 | return err; | ||
3539 | } | ||
3540 | |||
3533 | if (spec->autocfg.dig_out_pin) | 3541 | if (spec->autocfg.dig_out_pin) |
3534 | spec->multiout.dig_out_nid = 0x05; | 3542 | spec->multiout.dig_out_nid = 0x05; |
3535 | if (spec->autocfg.dig_in_pin) | 3543 | if (spec->autocfg.dig_in_pin) |
@@ -3647,14 +3655,18 @@ static int stac92xx_init(struct hda_codec *codec) | |||
3647 | for (i = 0; i < AUTO_PIN_LAST; i++) { | 3655 | for (i = 0; i < AUTO_PIN_LAST; i++) { |
3648 | hda_nid_t nid = cfg->input_pins[i]; | 3656 | hda_nid_t nid = cfg->input_pins[i]; |
3649 | if (nid) { | 3657 | if (nid) { |
3650 | unsigned int pinctl = snd_hda_codec_read(codec, nid, | 3658 | unsigned int pinctl; |
3651 | 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | 3659 | if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) { |
3652 | /* if PINCTL already set then skip */ | 3660 | /* for mic pins, force to initialize */ |
3653 | if (pinctl & AC_PINCAP_IN) | 3661 | pinctl = stac92xx_get_vref(codec, nid); |
3654 | continue; | 3662 | } else { |
3655 | pinctl = AC_PINCTL_IN_EN; | 3663 | pinctl = snd_hda_codec_read(codec, nid, 0, |
3656 | if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) | 3664 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); |
3657 | pinctl |= stac92xx_get_vref(codec, nid); | 3665 | /* if PINCTL already set then skip */ |
3666 | if (pinctl & AC_PINCTL_IN_EN) | ||
3667 | continue; | ||
3668 | } | ||
3669 | pinctl |= AC_PINCTL_IN_EN; | ||
3658 | stac92xx_auto_set_pinctl(codec, nid, pinctl); | 3670 | stac92xx_auto_set_pinctl(codec, nid, pinctl); |
3659 | } | 3671 | } |
3660 | } | 3672 | } |
@@ -3776,11 +3788,30 @@ static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid) | |||
3776 | return 0; | 3788 | return 0; |
3777 | } | 3789 | } |
3778 | 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 | |||
3779 | 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) |
3780 | { | 3812 | { |
3781 | struct sigmatel_spec *spec = codec->spec; | 3813 | struct sigmatel_spec *spec = codec->spec; |
3782 | struct auto_pin_cfg *cfg = &spec->autocfg; | 3814 | struct auto_pin_cfg *cfg = &spec->autocfg; |
3783 | int nid = cfg->hp_pins[cfg->hp_outs - 1]; | ||
3784 | int i, presence; | 3815 | int i, presence; |
3785 | 3816 | ||
3786 | presence = 0; | 3817 | presence = 0; |
@@ -3791,15 +3822,16 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) | |||
3791 | for (i = 0; i < cfg->hp_outs; i++) { | 3822 | for (i = 0; i < cfg->hp_outs; i++) { |
3792 | if (presence) | 3823 | if (presence) |
3793 | break; | 3824 | break; |
3794 | if (spec->hp_switch && cfg->hp_pins[i] == nid) | 3825 | if (no_hp_sensing(spec, i)) |
3795 | break; | 3826 | continue; |
3796 | presence = get_hp_pin_presence(codec, cfg->hp_pins[i]); | 3827 | presence = get_hp_pin_presence(codec, cfg->hp_pins[i]); |
3797 | } | 3828 | } |
3798 | 3829 | ||
3799 | if (presence) { | 3830 | if (presence) { |
3800 | /* disable lineouts, enable hp */ | 3831 | /* disable lineouts */ |
3801 | if (spec->hp_switch) | 3832 | if (spec->hp_switch) |
3802 | stac92xx_reset_pinctl(codec, nid, AC_PINCTL_OUT_EN); | 3833 | stac92xx_reset_pinctl(codec, spec->hp_switch, |
3834 | AC_PINCTL_OUT_EN); | ||
3803 | for (i = 0; i < cfg->line_outs; i++) | 3835 | for (i = 0; i < cfg->line_outs; i++) |
3804 | stac92xx_reset_pinctl(codec, cfg->line_out_pins[i], | 3836 | stac92xx_reset_pinctl(codec, cfg->line_out_pins[i], |
3805 | AC_PINCTL_OUT_EN); | 3837 | AC_PINCTL_OUT_EN); |
@@ -3811,9 +3843,10 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) | |||
3811 | spec->gpio_dir, spec->gpio_data & | 3843 | spec->gpio_dir, spec->gpio_data & |
3812 | ~spec->eapd_mask); | 3844 | ~spec->eapd_mask); |
3813 | } else { | 3845 | } else { |
3814 | /* enable lineouts, disable hp */ | 3846 | /* enable lineouts */ |
3815 | if (spec->hp_switch) | 3847 | if (spec->hp_switch) |
3816 | stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); | 3848 | stac92xx_set_pinctl(codec, spec->hp_switch, |
3849 | AC_PINCTL_OUT_EN); | ||
3817 | for (i = 0; i < cfg->line_outs; i++) | 3850 | for (i = 0; i < cfg->line_outs; i++) |
3818 | stac92xx_set_pinctl(codec, cfg->line_out_pins[i], | 3851 | stac92xx_set_pinctl(codec, cfg->line_out_pins[i], |
3819 | AC_PINCTL_OUT_EN); | 3852 | AC_PINCTL_OUT_EN); |
@@ -3825,8 +3858,16 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) | |||
3825 | spec->gpio_dir, spec->gpio_data | | 3858 | spec->gpio_dir, spec->gpio_data | |
3826 | spec->eapd_mask); | 3859 | spec->eapd_mask); |
3827 | } | 3860 | } |
3828 | if (!spec->hp_switch && cfg->hp_outs > 1 && presence) | 3861 | /* toggle hp outs */ |
3829 | 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 | } | ||
3830 | } | 3871 | } |
3831 | 3872 | ||
3832 | static void stac92xx_pin_sense(struct hda_codec *codec, int idx) | 3873 | static void stac92xx_pin_sense(struct hda_codec *codec, int idx) |