]> git.ipfire.org Git - ipfire-2.x.git/blob - src/patches/suse-2.6.27.39/patches.drivers/alsa-post-ga-hda-analog-updates
Fix oinkmaster patch.
[ipfire-2.x.git] / src / patches / suse-2.6.27.39 / patches.drivers / alsa-post-ga-hda-analog-updates
1 From: Takashi Iwai <tiwai@suse.de>
2 Subject: Fix / improve HP 2530p docking station support
3 Patch-mainline:
4 References: bnc#531437, bnc#535409
5
6 Update AD codec support code to fix / improve AD1984A laptop model
7 for supporting the docking station.
8
9 Also sync quirk entries with the upstream, which fixes the missing
10 entriy for bug #531437.
11
12 Signed-off-by: Takashi Iwai <tiwai@suse.de>
13
14 ---
15 sound/pci/hda/patch_analog.c | 189 ++++++++++++++++++++++++-------------------
16 1 file changed, 108 insertions(+), 81 deletions(-)
17
18 --- a/sound/pci/hda/patch_analog.c
19 +++ b/sound/pci/hda/patch_analog.c
20 @@ -1395,8 +1395,8 @@
21 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
22 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
23 /* Mic boost: 0dB */
24 - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
25 - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
26 + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
27 + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
28 /* Record selector: Front mic */
29 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
30 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
31 @@ -1661,10 +1661,10 @@
32 SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
33 SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD),
34 /* All HP models */
35 - SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP),
36 + SND_PCI_QUIRK_VENDOR(0x103c, "HP nx", AD1981_HP),
37 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA),
38 /* Lenovo Thinkpad T60/X60/Z6xx */
39 - SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1981_THINKPAD),
40 + SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1981_THINKPAD),
41 /* HP nx6320 (reversed SSID, H/W bug) */
42 SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP),
43 {}
44 @@ -1873,8 +1873,8 @@
45 #define AD1988_SPDIF_OUT_HDMI 0x0b
46 #define AD1988_SPDIF_IN 0x07
47
48 -static hda_nid_t ad1989b_slave_dig_outs[2] = {
49 - AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI
50 +static hda_nid_t ad1989b_slave_dig_outs[] = {
51 + AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI, 0
52 };
53
54 static struct hda_input_mux ad1988_6stack_capture_source = {
55 @@ -2276,10 +2276,6 @@
56 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
57 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
58 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
59 - /* ADCs; muted */
60 - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
61 - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
62 - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
63
64 { }
65 };
66 @@ -2387,10 +2383,6 @@
67 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
68 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
69 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
70 - /* ADCs; muted */
71 - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
72 - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
73 - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
74 /* Analog Mix output amp */
75 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
76 { }
77 @@ -2462,10 +2454,6 @@
78 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
79 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
80 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
81 - /* ADCs; muted */
82 - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
83 - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
84 - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
85 /* Analog Mix output amp */
86 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
87 { }
88 @@ -3198,10 +3186,10 @@
89 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
90 /* Port-B (front mic) pin */
91 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
92 - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
93 + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
94 /* Port-C (rear mic) pin */
95 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
96 - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
97 + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
98 /* Analog mixer; mute as default */
99 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
100 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
101 @@ -3352,7 +3340,7 @@
102 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
103 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
104 /* docking mic boost */
105 - {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
106 + {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
107 /* Analog mixer - docking mic; mute as default */
108 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
109 /* enable EAPD bit */
110 @@ -3462,7 +3450,7 @@
111
112 static struct snd_pci_quirk ad1984_cfg_tbl[] = {
113 /* Lenovo Thinkpad T61/X61 */
114 - SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1984_THINKPAD),
115 + SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD),
116 SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP),
117 {}
118 };
119 @@ -3616,10 +3604,10 @@
120 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
121 /* Port-B (front mic) pin */
122 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
123 - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
124 + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
125 /* Port-C (rear line-in) pin */
126 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
127 - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
128 + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
129 /* Port-E (rear mic) pin */
130 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
131 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
132 @@ -3667,19 +3655,29 @@
133 * Port F: Internal speakers
134 */
135
136 -static struct hda_input_mux ad1884a_laptop_capture_source = {
137 - .num_items = 4,
138 - .items = {
139 - { "Mic", 0x0 }, /* port-B */
140 - { "Internal Mic", 0x1 }, /* port-C */
141 - { "Dock Mic", 0x4 }, /* port-E */
142 - { "Mix", 0x3 },
143 - },
144 -};
145 +static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol,
146 + struct snd_ctl_elem_value *ucontrol)
147 +{
148 + struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
149 + int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
150 + int mute = (!ucontrol->value.integer.value[0] &&
151 + !ucontrol->value.integer.value[1]);
152 + /* toggle GPIO1 according to the mute state */
153 + snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
154 + mute ? 0x02 : 0x0);
155 + return ret;
156 +}
157
158 static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
159 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
160 - HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
161 + {
162 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
163 + .name = "Master Playback Switch",
164 + .info = snd_hda_mixer_amp_switch_info,
165 + .get = snd_hda_mixer_amp_switch_get,
166 + .put = ad1884a_mobile_master_sw_put,
167 + .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
168 + },
169 HDA_CODEC_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT),
170 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
171 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
172 @@ -3696,36 +3694,9 @@
173 HDA_CODEC_VOLUME("Dock Mic Boost", 0x25, 0x0, HDA_OUTPUT),
174 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
175 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
176 - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
177 - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
178 - {
179 - .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
180 - /* The multiple "Capture Source" controls confuse alsamixer
181 - * So call somewhat different..
182 - */
183 - /* .name = "Capture Source", */
184 - .name = "Input Source",
185 - .count = 2,
186 - .info = ad198x_mux_enum_info,
187 - .get = ad198x_mux_enum_get,
188 - .put = ad198x_mux_enum_put,
189 - },
190 { } /* end */
191 };
192
193 -static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol,
194 - struct snd_ctl_elem_value *ucontrol)
195 -{
196 - struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
197 - int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
198 - int mute = (!ucontrol->value.integer.value[0] &&
199 - !ucontrol->value.integer.value[1]);
200 - /* toggle GPIO1 according to the mute state */
201 - snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
202 - mute ? 0x02 : 0x0);
203 - return ret;
204 -}
205 -
206 static struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
207 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
208 /*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
209 @@ -3797,6 +3768,63 @@
210 return 0;
211 }
212
213 +/* mute internal speaker if HP or docking HP is plugged */
214 +static void ad1884a_laptop_automute(struct hda_codec *codec)
215 +{
216 + unsigned int present;
217 +
218 + present = snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0);
219 + present &= AC_PINSENSE_PRESENCE;
220 + if (!present) {
221 + present = snd_hda_codec_read(codec, 0x12, 0,
222 + AC_VERB_GET_PIN_SENSE, 0);
223 + present &= AC_PINSENSE_PRESENCE;
224 + }
225 + snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
226 + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
227 + snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
228 + present ? 0x00 : 0x02);
229 +}
230 +
231 +/* switch to external mic if plugged */
232 +static void ad1884a_laptop_automic(struct hda_codec *codec)
233 +{
234 + unsigned int idx;
235 +
236 + if (snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) &
237 + AC_PINSENSE_PRESENCE)
238 + idx = 0;
239 + else if (snd_hda_codec_read(codec, 0x1c, 0, AC_VERB_GET_PIN_SENSE, 0) &
240 + AC_PINSENSE_PRESENCE)
241 + idx = 4;
242 + else
243 + idx = 1;
244 + snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, idx);
245 +}
246 +
247 +/* unsolicited event for HP jack sensing */
248 +static void ad1884a_laptop_unsol_event(struct hda_codec *codec,
249 + unsigned int res)
250 +{
251 + switch (res >> 26) {
252 + case AD1884A_HP_EVENT:
253 + ad1884a_laptop_automute(codec);
254 + break;
255 + case AD1884A_MIC_EVENT:
256 + ad1884a_laptop_automic(codec);
257 + break;
258 + }
259 +}
260 +
261 +/* initialize jack-sensing, too */
262 +static int ad1884a_laptop_init(struct hda_codec *codec)
263 +{
264 + ad198x_init(codec);
265 + ad1884a_laptop_automute(codec);
266 + ad1884a_laptop_automic(codec);
267 + return 0;
268 +}
269 +
270 /* additional verbs for laptop model */
271 static struct hda_verb ad1884a_laptop_verbs[] = {
272 /* Port-A (HP) pin - always unmuted */
273 @@ -3804,18 +3832,28 @@
274 /* Port-F (int speaker) mixer - route only from analog mixer */
275 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
276 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
277 - /* Port-F pin */
278 - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
279 + /* Port-F (int speaker) pin */
280 + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
281 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
282 + /* required for compaq 6530s/6531s speaker output */
283 + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
284 /* Port-C pin - internal mic-in */
285 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
286 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
287 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
288 + /* Port-D (docking line-out) pin - default unmuted */
289 + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
290 /* analog mix */
291 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
292 /* unsolicited event for pin-sense */
293 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
294 + {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
295 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
296 + {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
297 + /* allow to touch GPIO1 (for mute control) */
298 + {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
299 + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
300 + {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
301 { } /* end */
302 };
303
304 @@ -3973,21 +4011,11 @@
305 SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE),
306 SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP),
307 SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE),
308 - SND_PCI_QUIRK(0x103c, 0x3072, "HP", AD1884A_MOBILE),
309 - SND_PCI_QUIRK(0x103c, 0x3073, "HP", AD1884A_MOBILE),
310 - SND_PCI_QUIRK(0x103c, 0x3074, "HP", AD1884A_MOBILE),
311 - SND_PCI_QUIRK(0x103c, 0x3075, "HP", AD1884A_MOBILE),
312 - SND_PCI_QUIRK(0x103c, 0x3076, "HP", AD1884A_MOBILE),
313 - SND_PCI_QUIRK(0x103c, 0x3077, "HP", AD1884A_MOBILE),
314 - SND_PCI_QUIRK(0x103c, 0x3078, "HP", AD1884A_MOBILE),
315 - SND_PCI_QUIRK(0x103c, 0x3079, "HP", AD1884A_MOBILE),
316 - SND_PCI_QUIRK(0x103c, 0x307a, "HP", AD1884A_MOBILE),
317 - SND_PCI_QUIRK(0x103c, 0x30e1, "HP 2530p", AD1884A_LAPTOP),
318 - SND_PCI_QUIRK(0x103c, 0x30e6, "HP 6730b", AD1884A_LAPTOP),
319 - SND_PCI_QUIRK(0x103c, 0x30e7, "HP EliteBook 8530p", AD1884A_LAPTOP),
320 - SND_PCI_QUIRK(0x103c, 0x360d, "HP 6530b", AD1884A_LAPTOP),
321 - SND_PCI_QUIRK(0x103c, 0x3614, "HP 6730s", AD1884A_LAPTOP),
322 - SND_PCI_QUIRK(0x103c, 0x3632, "HP", AD1884A_MOBILE),
323 + SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x3070, "HP", AD1884A_MOBILE),
324 + SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30d0, "HP laptop", AD1884A_LAPTOP),
325 + SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP),
326 + SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP),
327 + SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x7010, "HP laptop", AD1884A_MOBILE),
328 SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
329 {}
330 };
331 @@ -4030,9 +4058,8 @@
332 spec->mixers[0] = ad1884a_laptop_mixers;
333 spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs;
334 spec->multiout.dig_out_nid = 0;
335 - spec->input_mux = &ad1884a_laptop_capture_source;
336 - codec->patch_ops.unsol_event = ad1884a_hp_unsol_event;
337 - codec->patch_ops.init = ad1884a_hp_init;
338 + codec->patch_ops.unsol_event = ad1884a_laptop_unsol_event;
339 + codec->patch_ops.init = ad1884a_laptop_init;
340 /* set the upper-limit for mixer amp to 0dB for avoiding the
341 * possible damage by overloading
342 */