diff options
Diffstat (limited to 'sound/ppc/burgundy.c')
-rw-r--r-- | sound/ppc/burgundy.c | 439 |
1 files changed, 439 insertions, 0 deletions
diff --git a/sound/ppc/burgundy.c b/sound/ppc/burgundy.c new file mode 100644 index 000000000000..3f837d9f3eb1 --- /dev/null +++ b/sound/ppc/burgundy.c | |||
@@ -0,0 +1,439 @@ | |||
1 | /* | ||
2 | * PMac Burgundy lowlevel functions | ||
3 | * | ||
4 | * Copyright (c) by Takashi Iwai <tiwai@suse.de> | ||
5 | * code based on dmasound.c. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #include <sound/driver.h> | ||
23 | #include <asm/io.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <sound/core.h> | ||
28 | #include "pmac.h" | ||
29 | #include "burgundy.h" | ||
30 | |||
31 | |||
32 | /* Waits for busy flag to clear */ | ||
33 | inline static void | ||
34 | snd_pmac_burgundy_busy_wait(pmac_t *chip) | ||
35 | { | ||
36 | int timeout = 50; | ||
37 | while ((in_le32(&chip->awacs->codec_ctrl) & MASK_NEWECMD) && timeout--) | ||
38 | udelay(1); | ||
39 | if (! timeout) | ||
40 | printk(KERN_DEBUG "burgundy_busy_wait: timeout\n"); | ||
41 | } | ||
42 | |||
43 | inline static void | ||
44 | snd_pmac_burgundy_extend_wait(pmac_t *chip) | ||
45 | { | ||
46 | int timeout; | ||
47 | timeout = 50; | ||
48 | while (!(in_le32(&chip->awacs->codec_stat) & MASK_EXTEND) && timeout--) | ||
49 | udelay(1); | ||
50 | if (! timeout) | ||
51 | printk(KERN_DEBUG "burgundy_extend_wait: timeout #1\n"); | ||
52 | timeout = 50; | ||
53 | while ((in_le32(&chip->awacs->codec_stat) & MASK_EXTEND) && timeout--) | ||
54 | udelay(1); | ||
55 | if (! timeout) | ||
56 | printk(KERN_DEBUG "burgundy_extend_wait: timeout #2\n"); | ||
57 | } | ||
58 | |||
59 | static void | ||
60 | snd_pmac_burgundy_wcw(pmac_t *chip, unsigned addr, unsigned val) | ||
61 | { | ||
62 | out_le32(&chip->awacs->codec_ctrl, addr + 0x200c00 + (val & 0xff)); | ||
63 | snd_pmac_burgundy_busy_wait(chip); | ||
64 | out_le32(&chip->awacs->codec_ctrl, addr + 0x200d00 +((val>>8) & 0xff)); | ||
65 | snd_pmac_burgundy_busy_wait(chip); | ||
66 | out_le32(&chip->awacs->codec_ctrl, addr + 0x200e00 +((val>>16) & 0xff)); | ||
67 | snd_pmac_burgundy_busy_wait(chip); | ||
68 | out_le32(&chip->awacs->codec_ctrl, addr + 0x200f00 +((val>>24) & 0xff)); | ||
69 | snd_pmac_burgundy_busy_wait(chip); | ||
70 | } | ||
71 | |||
72 | static unsigned | ||
73 | snd_pmac_burgundy_rcw(pmac_t *chip, unsigned addr) | ||
74 | { | ||
75 | unsigned val = 0; | ||
76 | unsigned long flags; | ||
77 | |||
78 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
79 | |||
80 | out_le32(&chip->awacs->codec_ctrl, addr + 0x100000); | ||
81 | snd_pmac_burgundy_busy_wait(chip); | ||
82 | snd_pmac_burgundy_extend_wait(chip); | ||
83 | val += (in_le32(&chip->awacs->codec_stat) >> 4) & 0xff; | ||
84 | |||
85 | out_le32(&chip->awacs->codec_ctrl, addr + 0x100100); | ||
86 | snd_pmac_burgundy_busy_wait(chip); | ||
87 | snd_pmac_burgundy_extend_wait(chip); | ||
88 | val += ((in_le32(&chip->awacs->codec_stat)>>4) & 0xff) <<8; | ||
89 | |||
90 | out_le32(&chip->awacs->codec_ctrl, addr + 0x100200); | ||
91 | snd_pmac_burgundy_busy_wait(chip); | ||
92 | snd_pmac_burgundy_extend_wait(chip); | ||
93 | val += ((in_le32(&chip->awacs->codec_stat)>>4) & 0xff) <<16; | ||
94 | |||
95 | out_le32(&chip->awacs->codec_ctrl, addr + 0x100300); | ||
96 | snd_pmac_burgundy_busy_wait(chip); | ||
97 | snd_pmac_burgundy_extend_wait(chip); | ||
98 | val += ((in_le32(&chip->awacs->codec_stat)>>4) & 0xff) <<24; | ||
99 | |||
100 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
101 | |||
102 | return val; | ||
103 | } | ||
104 | |||
105 | static void | ||
106 | snd_pmac_burgundy_wcb(pmac_t *chip, unsigned int addr, unsigned int val) | ||
107 | { | ||
108 | out_le32(&chip->awacs->codec_ctrl, addr + 0x300000 + (val & 0xff)); | ||
109 | snd_pmac_burgundy_busy_wait(chip); | ||
110 | } | ||
111 | |||
112 | static unsigned | ||
113 | snd_pmac_burgundy_rcb(pmac_t *chip, unsigned int addr) | ||
114 | { | ||
115 | unsigned val = 0; | ||
116 | unsigned long flags; | ||
117 | |||
118 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
119 | |||
120 | out_le32(&chip->awacs->codec_ctrl, addr + 0x100000); | ||
121 | snd_pmac_burgundy_busy_wait(chip); | ||
122 | snd_pmac_burgundy_extend_wait(chip); | ||
123 | val += (in_le32(&chip->awacs->codec_stat) >> 4) & 0xff; | ||
124 | |||
125 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
126 | |||
127 | return val; | ||
128 | } | ||
129 | |||
130 | /* | ||
131 | * Burgundy volume: 0 - 100, stereo | ||
132 | */ | ||
133 | static void | ||
134 | snd_pmac_burgundy_write_volume(pmac_t *chip, unsigned int address, long *volume, int shift) | ||
135 | { | ||
136 | int hardvolume, lvolume, rvolume; | ||
137 | |||
138 | lvolume = volume[0] ? volume[0] + BURGUNDY_VOLUME_OFFSET : 0; | ||
139 | rvolume = volume[1] ? volume[1] + BURGUNDY_VOLUME_OFFSET : 0; | ||
140 | |||
141 | hardvolume = lvolume + (rvolume << shift); | ||
142 | if (shift == 8) | ||
143 | hardvolume |= hardvolume << 16; | ||
144 | |||
145 | snd_pmac_burgundy_wcw(chip, address, hardvolume); | ||
146 | } | ||
147 | |||
148 | static void | ||
149 | snd_pmac_burgundy_read_volume(pmac_t *chip, unsigned int address, long *volume, int shift) | ||
150 | { | ||
151 | int wvolume; | ||
152 | |||
153 | wvolume = snd_pmac_burgundy_rcw(chip, address); | ||
154 | |||
155 | volume[0] = wvolume & 0xff; | ||
156 | if (volume[0] >= BURGUNDY_VOLUME_OFFSET) | ||
157 | volume[0] -= BURGUNDY_VOLUME_OFFSET; | ||
158 | else | ||
159 | volume[0] = 0; | ||
160 | volume[1] = (wvolume >> shift) & 0xff; | ||
161 | if (volume[1] >= BURGUNDY_VOLUME_OFFSET) | ||
162 | volume[1] -= BURGUNDY_VOLUME_OFFSET; | ||
163 | else | ||
164 | volume[1] = 0; | ||
165 | } | ||
166 | |||
167 | |||
168 | /* | ||
169 | */ | ||
170 | |||
171 | #define BASE2ADDR(base) ((base) << 12) | ||
172 | #define ADDR2BASE(addr) ((addr) >> 12) | ||
173 | |||
174 | static int snd_pmac_burgundy_info_volume(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
175 | { | ||
176 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
177 | uinfo->count = 2; | ||
178 | uinfo->value.integer.min = 0; | ||
179 | uinfo->value.integer.max = 100; | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | static int snd_pmac_burgundy_get_volume(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
184 | { | ||
185 | pmac_t *chip = snd_kcontrol_chip(kcontrol); | ||
186 | unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff); | ||
187 | int shift = (kcontrol->private_value >> 8) & 0xff; | ||
188 | snd_pmac_burgundy_read_volume(chip, addr, ucontrol->value.integer.value, shift); | ||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | static int snd_pmac_burgundy_put_volume(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
193 | { | ||
194 | pmac_t *chip = snd_kcontrol_chip(kcontrol); | ||
195 | unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff); | ||
196 | int shift = (kcontrol->private_value >> 8) & 0xff; | ||
197 | long nvoices[2]; | ||
198 | |||
199 | snd_pmac_burgundy_write_volume(chip, addr, ucontrol->value.integer.value, shift); | ||
200 | snd_pmac_burgundy_read_volume(chip, addr, nvoices, shift); | ||
201 | return (nvoices[0] != ucontrol->value.integer.value[0] || | ||
202 | nvoices[1] != ucontrol->value.integer.value[1]); | ||
203 | } | ||
204 | |||
205 | #define BURGUNDY_VOLUME(xname, xindex, addr, shift) \ | ||
206 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\ | ||
207 | .info = snd_pmac_burgundy_info_volume,\ | ||
208 | .get = snd_pmac_burgundy_get_volume,\ | ||
209 | .put = snd_pmac_burgundy_put_volume,\ | ||
210 | .private_value = ((ADDR2BASE(addr) & 0xff) | ((shift) << 8)) } | ||
211 | |||
212 | /* lineout/speaker */ | ||
213 | |||
214 | static int snd_pmac_burgundy_info_switch_out(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
215 | { | ||
216 | int stereo = (kcontrol->private_value >> 24) & 1; | ||
217 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
218 | uinfo->count = stereo + 1; | ||
219 | uinfo->value.integer.min = 0; | ||
220 | uinfo->value.integer.max = 1; | ||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | static int snd_pmac_burgundy_get_switch_out(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
225 | { | ||
226 | pmac_t *chip = snd_kcontrol_chip(kcontrol); | ||
227 | int lmask = kcontrol->private_value & 0xff; | ||
228 | int rmask = (kcontrol->private_value >> 8) & 0xff; | ||
229 | int stereo = (kcontrol->private_value >> 24) & 1; | ||
230 | int val = snd_pmac_burgundy_rcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES); | ||
231 | ucontrol->value.integer.value[0] = (val & lmask) ? 1 : 0; | ||
232 | if (stereo) | ||
233 | ucontrol->value.integer.value[1] = (val & rmask) ? 1 : 0; | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static int snd_pmac_burgundy_put_switch_out(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
238 | { | ||
239 | pmac_t *chip = snd_kcontrol_chip(kcontrol); | ||
240 | int lmask = kcontrol->private_value & 0xff; | ||
241 | int rmask = (kcontrol->private_value >> 8) & 0xff; | ||
242 | int stereo = (kcontrol->private_value >> 24) & 1; | ||
243 | int val, oval; | ||
244 | oval = snd_pmac_burgundy_rcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES); | ||
245 | val = oval & ~(lmask | rmask); | ||
246 | if (ucontrol->value.integer.value[0]) | ||
247 | val |= lmask; | ||
248 | if (stereo && ucontrol->value.integer.value[1]) | ||
249 | val |= rmask; | ||
250 | snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, val); | ||
251 | return val != oval; | ||
252 | } | ||
253 | |||
254 | #define BURGUNDY_OUTPUT_SWITCH(xname, xindex, lmask, rmask, stereo) \ | ||
255 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\ | ||
256 | .info = snd_pmac_burgundy_info_switch_out,\ | ||
257 | .get = snd_pmac_burgundy_get_switch_out,\ | ||
258 | .put = snd_pmac_burgundy_put_switch_out,\ | ||
259 | .private_value = ((lmask) | ((rmask) << 8) | ((stereo) << 24)) } | ||
260 | |||
261 | /* line/speaker output volume */ | ||
262 | static int snd_pmac_burgundy_info_volume_out(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
263 | { | ||
264 | int stereo = (kcontrol->private_value >> 24) & 1; | ||
265 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
266 | uinfo->count = stereo + 1; | ||
267 | uinfo->value.integer.min = 0; | ||
268 | uinfo->value.integer.max = 15; | ||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | static int snd_pmac_burgundy_get_volume_out(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
273 | { | ||
274 | pmac_t *chip = snd_kcontrol_chip(kcontrol); | ||
275 | unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff); | ||
276 | int stereo = (kcontrol->private_value >> 24) & 1; | ||
277 | int oval; | ||
278 | |||
279 | oval = ~snd_pmac_burgundy_rcb(chip, addr) & 0xff; | ||
280 | ucontrol->value.integer.value[0] = oval & 0xf; | ||
281 | if (stereo) | ||
282 | ucontrol->value.integer.value[1] = (oval >> 4) & 0xf; | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | static int snd_pmac_burgundy_put_volume_out(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
287 | { | ||
288 | pmac_t *chip = snd_kcontrol_chip(kcontrol); | ||
289 | unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff); | ||
290 | int stereo = (kcontrol->private_value >> 24) & 1; | ||
291 | int oval, val; | ||
292 | |||
293 | oval = ~snd_pmac_burgundy_rcb(chip, addr) & 0xff; | ||
294 | val = ucontrol->value.integer.value[0]; | ||
295 | if (stereo) | ||
296 | val |= ucontrol->value.integer.value[1] << 4; | ||
297 | else | ||
298 | val |= ucontrol->value.integer.value[0] << 4; | ||
299 | val = ~val & 0xff; | ||
300 | snd_pmac_burgundy_wcb(chip, addr, val); | ||
301 | return val != oval; | ||
302 | } | ||
303 | |||
304 | #define BURGUNDY_OUTPUT_VOLUME(xname, xindex, addr, stereo) \ | ||
305 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\ | ||
306 | .info = snd_pmac_burgundy_info_volume_out,\ | ||
307 | .get = snd_pmac_burgundy_get_volume_out,\ | ||
308 | .put = snd_pmac_burgundy_put_volume_out,\ | ||
309 | .private_value = (ADDR2BASE(addr) | ((stereo) << 24)) } | ||
310 | |||
311 | static snd_kcontrol_new_t snd_pmac_burgundy_mixers[] __initdata = { | ||
312 | BURGUNDY_VOLUME("Master Playback Volume", 0, MASK_ADDR_BURGUNDY_MASTER_VOLUME, 8), | ||
313 | BURGUNDY_VOLUME("Line Playback Volume", 0, MASK_ADDR_BURGUNDY_VOLLINE, 16), | ||
314 | BURGUNDY_VOLUME("CD Playback Volume", 0, MASK_ADDR_BURGUNDY_VOLCD, 16), | ||
315 | BURGUNDY_VOLUME("Mic Playback Volume", 0, MASK_ADDR_BURGUNDY_VOLMIC, 16), | ||
316 | BURGUNDY_OUTPUT_VOLUME("PC Speaker Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENHP, 0), | ||
317 | /*BURGUNDY_OUTPUT_VOLUME("PCM Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENLINEOUT, 1),*/ | ||
318 | BURGUNDY_OUTPUT_VOLUME("Headphone Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENSPEAKER, 1), | ||
319 | }; | ||
320 | static snd_kcontrol_new_t snd_pmac_burgundy_master_sw __initdata = | ||
321 | BURGUNDY_OUTPUT_SWITCH("Headphone Playback Switch", 0, BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1); | ||
322 | static snd_kcontrol_new_t snd_pmac_burgundy_speaker_sw __initdata = | ||
323 | BURGUNDY_OUTPUT_SWITCH("PC Speaker Playback Switch", 0, BURGUNDY_OUTPUT_INTERN, 0, 0); | ||
324 | |||
325 | |||
326 | #ifdef PMAC_SUPPORT_AUTOMUTE | ||
327 | /* | ||
328 | * auto-mute stuffs | ||
329 | */ | ||
330 | static int snd_pmac_burgundy_detect_headphone(pmac_t *chip) | ||
331 | { | ||
332 | return (in_le32(&chip->awacs->codec_stat) & chip->hp_stat_mask) ? 1 : 0; | ||
333 | } | ||
334 | |||
335 | static void snd_pmac_burgundy_update_automute(pmac_t *chip, int do_notify) | ||
336 | { | ||
337 | if (chip->auto_mute) { | ||
338 | int reg, oreg; | ||
339 | reg = oreg = snd_pmac_burgundy_rcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES); | ||
340 | reg &= ~(BURGUNDY_OUTPUT_LEFT | BURGUNDY_OUTPUT_RIGHT | BURGUNDY_OUTPUT_INTERN); | ||
341 | if (snd_pmac_burgundy_detect_headphone(chip)) | ||
342 | reg |= BURGUNDY_OUTPUT_LEFT | BURGUNDY_OUTPUT_RIGHT; | ||
343 | else | ||
344 | reg |= BURGUNDY_OUTPUT_INTERN; | ||
345 | if (do_notify && reg == oreg) | ||
346 | return; | ||
347 | snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, reg); | ||
348 | if (do_notify) { | ||
349 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
350 | &chip->master_sw_ctl->id); | ||
351 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
352 | &chip->speaker_sw_ctl->id); | ||
353 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
354 | &chip->hp_detect_ctl->id); | ||
355 | } | ||
356 | } | ||
357 | } | ||
358 | #endif /* PMAC_SUPPORT_AUTOMUTE */ | ||
359 | |||
360 | |||
361 | /* | ||
362 | * initialize burgundy | ||
363 | */ | ||
364 | int __init snd_pmac_burgundy_init(pmac_t *chip) | ||
365 | { | ||
366 | int i, err; | ||
367 | |||
368 | /* Checks to see the chip is alive and kicking */ | ||
369 | if ((in_le32(&chip->awacs->codec_ctrl) & MASK_ERRCODE) == 0xf0000) { | ||
370 | printk(KERN_WARNING "pmac burgundy: disabled by MacOS :-(\n"); | ||
371 | return 1; | ||
372 | } | ||
373 | |||
374 | snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_OUTPUTENABLES, | ||
375 | DEF_BURGUNDY_OUTPUTENABLES); | ||
376 | snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, | ||
377 | DEF_BURGUNDY_MORE_OUTPUTENABLES); | ||
378 | snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_OUTPUTSELECTS, | ||
379 | DEF_BURGUNDY_OUTPUTSELECTS); | ||
380 | |||
381 | snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_INPSEL21, | ||
382 | DEF_BURGUNDY_INPSEL21); | ||
383 | snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_INPSEL3, | ||
384 | DEF_BURGUNDY_INPSEL3); | ||
385 | snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINCD, | ||
386 | DEF_BURGUNDY_GAINCD); | ||
387 | snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINLINE, | ||
388 | DEF_BURGUNDY_GAINLINE); | ||
389 | snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINMIC, | ||
390 | DEF_BURGUNDY_GAINMIC); | ||
391 | snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINMODEM, | ||
392 | DEF_BURGUNDY_GAINMODEM); | ||
393 | |||
394 | snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_ATTENSPEAKER, | ||
395 | DEF_BURGUNDY_ATTENSPEAKER); | ||
396 | snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_ATTENLINEOUT, | ||
397 | DEF_BURGUNDY_ATTENLINEOUT); | ||
398 | snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_ATTENHP, | ||
399 | DEF_BURGUNDY_ATTENHP); | ||
400 | |||
401 | snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_MASTER_VOLUME, | ||
402 | DEF_BURGUNDY_MASTER_VOLUME); | ||
403 | snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_VOLCD, | ||
404 | DEF_BURGUNDY_VOLCD); | ||
405 | snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_VOLLINE, | ||
406 | DEF_BURGUNDY_VOLLINE); | ||
407 | snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_VOLMIC, | ||
408 | DEF_BURGUNDY_VOLMIC); | ||
409 | |||
410 | if (chip->hp_stat_mask == 0) | ||
411 | /* set headphone-jack detection bit */ | ||
412 | chip->hp_stat_mask = 0x04; | ||
413 | |||
414 | /* | ||
415 | * build burgundy mixers | ||
416 | */ | ||
417 | strcpy(chip->card->mixername, "PowerMac Burgundy"); | ||
418 | |||
419 | for (i = 0; i < ARRAY_SIZE(snd_pmac_burgundy_mixers); i++) { | ||
420 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_pmac_burgundy_mixers[i], chip))) < 0) | ||
421 | return err; | ||
422 | } | ||
423 | chip->master_sw_ctl = snd_ctl_new1(&snd_pmac_burgundy_master_sw, chip); | ||
424 | if ((err = snd_ctl_add(chip->card, chip->master_sw_ctl)) < 0) | ||
425 | return err; | ||
426 | chip->speaker_sw_ctl = snd_ctl_new1(&snd_pmac_burgundy_speaker_sw, chip); | ||
427 | if ((err = snd_ctl_add(chip->card, chip->speaker_sw_ctl)) < 0) | ||
428 | return err; | ||
429 | #ifdef PMAC_SUPPORT_AUTOMUTE | ||
430 | if ((err = snd_pmac_add_automute(chip)) < 0) | ||
431 | return err; | ||
432 | |||
433 | chip->detect_headphone = snd_pmac_burgundy_detect_headphone; | ||
434 | chip->update_automute = snd_pmac_burgundy_update_automute; | ||
435 | snd_pmac_burgundy_update_automute(chip, 0); /* update the status only */ | ||
436 | #endif | ||
437 | |||
438 | return 0; | ||
439 | } | ||