]> git.ipfire.org Git - ipfire-2.x.git/blame - 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
CommitLineData
82094b55
AF
1From: Takashi Iwai <tiwai@suse.de>
2Subject: Fix / improve HP 2530p docking station support
3Patch-mainline:
4References: bnc#531437, bnc#535409
5
6Update AD codec support code to fix / improve AD1984A laptop model
7for supporting the docking station.
8
9Also sync quirk entries with the upstream, which fixes the missing
10entriy for bug #531437.
11
12Signed-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 */