]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From: Takashi Iwai <tiwai@suse.de> |
2 | Subject: ALSA: hda - Fix IDT/STAC multiple HP detection | |
3 | Patch-mainline: | |
4 | References: bnc#443267 | |
5 | ||
6 | Due to the recent change for multiple HP as line-out switch, only | |
7 | one of the multiple headphons (usually a wrong one) is toggled | |
8 | and the other pins are still disabled. This causes the silent output | |
9 | problem on some Dell laptops. | |
10 | ||
11 | Also, the hp_switch check is screwed up when a line-in or a mic-in | |
12 | jack exists. This is added as an additional output, but hp_switch | |
13 | check doesn't take it into account. | |
14 | ||
15 | This patch fixes these issues: simplify hp_switch check by using | |
16 | the NID instead of bool, and clean up / fix the toggle of HP pins | |
17 | in unsol event handler code. | |
18 | ||
19 | Reference: Novell bnc#443267 | |
20 | https://bugzilla.novell.com/show_bug.cgi?id=443267 | |
21 | ||
22 | Signed-off-by: Takashi Iwai <tiwai@suse.de> | |
23 | ||
24 | --- | |
25 | sound/pci/hda/patch_sigmatel.c | 57 +++++++++++++++++++++++++++++++---------- | |
26 | 1 file changed, 44 insertions(+), 13 deletions(-) | |
27 | ||
28 | --- a/sound/pci/hda/patch_sigmatel.c | |
29 | +++ b/sound/pci/hda/patch_sigmatel.c | |
30 | @@ -212,7 +212,7 @@ struct sigmatel_spec { | |
31 | /* i/o switches */ | |
32 | unsigned int io_switch[2]; | |
33 | unsigned int clfe_swap; | |
34 | - unsigned int hp_switch; | |
35 | + unsigned int hp_switch; /* NID of HP as line-out */ | |
36 | unsigned int aloopback; | |
37 | ||
38 | struct hda_pcm pcm_rec[2]; /* PCM information */ | |
39 | @@ -2448,7 +2448,7 @@ static int stac92xx_hp_switch_get(struct | |
40 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | |
41 | struct sigmatel_spec *spec = codec->spec; | |
42 | ||
43 | - ucontrol->value.integer.value[0] = spec->hp_switch; | |
44 | + ucontrol->value.integer.value[0] = !!spec->hp_switch; | |
45 | return 0; | |
46 | } | |
47 | ||
48 | @@ -2457,8 +2457,9 @@ static int stac92xx_hp_switch_put(struct | |
49 | { | |
50 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | |
51 | struct sigmatel_spec *spec = codec->spec; | |
52 | + int nid = kcontrol->private_value; | |
53 | ||
54 | - spec->hp_switch = ucontrol->value.integer.value[0]; | |
55 | + spec->hp_switch = ucontrol->value.integer.value[0] ? nid : 0; | |
56 | ||
57 | /* check to be sure that the ports are upto date with | |
58 | * switch changes | |
59 | @@ -2867,7 +2868,8 @@ static int stac92xx_auto_create_multi_ou | |
60 | if (cfg->hp_outs > 1 && cfg->line_out_type == AUTO_PIN_LINE_OUT) { | |
61 | err = stac92xx_add_control(spec, | |
62 | STAC_CTL_WIDGET_HP_SWITCH, | |
63 | - "Headphone as Line Out Switch", 0); | |
64 | + "Headphone as Line Out Switch", | |
65 | + cfg->hp_pins[cfg->hp_outs - 1]); | |
66 | if (err < 0) | |
67 | return err; | |
68 | } | |
69 | @@ -3791,11 +3793,30 @@ static int get_hp_pin_presence(struct hd | |
70 | return 0; | |
71 | } | |
72 | ||
73 | +/* return non-zero if the hp-pin of the given array index isn't | |
74 | + * a jack-detection target | |
75 | + */ | |
76 | +static int no_hp_sensing(struct sigmatel_spec *spec, int i) | |
77 | +{ | |
78 | + struct auto_pin_cfg *cfg = &spec->autocfg; | |
79 | + | |
80 | + /* ignore sensing of shared line and mic jacks */ | |
81 | + if (spec->line_switch && | |
82 | + cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_LINE]) | |
83 | + return 1; | |
84 | + if (spec->mic_switch && | |
85 | + cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_MIC]) | |
86 | + return 1; | |
87 | + /* ignore if the pin is set as line-out */ | |
88 | + if (cfg->hp_pins[i] == spec->hp_switch) | |
89 | + return 1; | |
90 | + return 0; | |
91 | +} | |
92 | + | |
93 | static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) | |
94 | { | |
95 | struct sigmatel_spec *spec = codec->spec; | |
96 | struct auto_pin_cfg *cfg = &spec->autocfg; | |
97 | - int nid = cfg->hp_pins[cfg->hp_outs - 1]; | |
98 | int i, presence; | |
99 | ||
100 | presence = 0; | |
101 | @@ -3806,15 +3827,16 @@ static void stac92xx_hp_detect(struct hd | |
102 | for (i = 0; i < cfg->hp_outs; i++) { | |
103 | if (presence) | |
104 | break; | |
105 | - if (spec->hp_switch && cfg->hp_pins[i] == nid) | |
106 | - break; | |
107 | + if (no_hp_sensing(spec, i)) | |
108 | + continue; | |
109 | presence = get_hp_pin_presence(codec, cfg->hp_pins[i]); | |
110 | } | |
111 | ||
112 | if (presence) { | |
113 | - /* disable lineouts, enable hp */ | |
114 | + /* disable lineouts */ | |
115 | if (spec->hp_switch) | |
116 | - stac92xx_reset_pinctl(codec, nid, AC_PINCTL_OUT_EN); | |
117 | + stac92xx_reset_pinctl(codec, spec->hp_switch, | |
118 | + AC_PINCTL_OUT_EN); | |
119 | for (i = 0; i < cfg->line_outs; i++) | |
120 | stac92xx_reset_pinctl(codec, cfg->line_out_pins[i], | |
121 | AC_PINCTL_OUT_EN); | |
122 | @@ -3826,9 +3848,10 @@ static void stac92xx_hp_detect(struct hd | |
123 | spec->gpio_dir, spec->gpio_data & | |
124 | ~spec->eapd_mask); | |
125 | } else { | |
126 | - /* enable lineouts, disable hp */ | |
127 | + /* enable lineouts */ | |
128 | if (spec->hp_switch) | |
129 | - stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); | |
130 | + stac92xx_set_pinctl(codec, spec->hp_switch, | |
131 | + AC_PINCTL_OUT_EN); | |
132 | for (i = 0; i < cfg->line_outs; i++) | |
133 | stac92xx_set_pinctl(codec, cfg->line_out_pins[i], | |
134 | AC_PINCTL_OUT_EN); | |
135 | @@ -3840,8 +3863,16 @@ static void stac92xx_hp_detect(struct hd | |
136 | spec->gpio_dir, spec->gpio_data | | |
137 | spec->eapd_mask); | |
138 | } | |
139 | - if (!spec->hp_switch && cfg->hp_outs > 1 && presence) | |
140 | - stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); | |
141 | + /* toggle hp outs */ | |
142 | + for (i = 0; i < cfg->hp_outs; i++) { | |
143 | + unsigned int val = AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN; | |
144 | + if (no_hp_sensing(spec, i)) | |
145 | + continue; | |
146 | + if (presence) | |
147 | + stac92xx_set_pinctl(codec, cfg->hp_pins[i], val); | |
148 | + else | |
149 | + stac92xx_reset_pinctl(codec, cfg->hp_pins[i], val); | |
150 | + } | |
151 | } | |
152 | ||
153 | static void stac92xx_pin_sense(struct hda_codec *codec, int idx) |