aboutsummaryrefslogtreecommitdiffstats
path: root/sound/ppc/burgundy.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/ppc/burgundy.c')
-rw-r--r--sound/ppc/burgundy.c465
1 files changed, 372 insertions, 93 deletions
diff --git a/sound/ppc/burgundy.c b/sound/ppc/burgundy.c
index 1a545ac0de04..f860d39af36b 100644
--- a/sound/ppc/burgundy.c
+++ b/sound/ppc/burgundy.c
@@ -102,7 +102,8 @@ snd_pmac_burgundy_rcw(struct snd_pmac *chip, unsigned addr)
102} 102}
103 103
104static void 104static void
105snd_pmac_burgundy_wcb(struct snd_pmac *chip, unsigned int addr, unsigned int val) 105snd_pmac_burgundy_wcb(struct snd_pmac *chip, unsigned int addr,
106 unsigned int val)
106{ 107{
107 out_le32(&chip->awacs->codec_ctrl, addr + 0x300000 + (val & 0xff)); 108 out_le32(&chip->awacs->codec_ctrl, addr + 0x300000 + (val & 0xff));
108 snd_pmac_burgundy_busy_wait(chip); 109 snd_pmac_burgundy_busy_wait(chip);
@@ -126,8 +127,11 @@ snd_pmac_burgundy_rcb(struct snd_pmac *chip, unsigned int addr)
126 return val; 127 return val;
127} 128}
128 129
130#define BASE2ADDR(base) ((base) << 12)
131#define ADDR2BASE(addr) ((addr) >> 12)
132
129/* 133/*
130 * Burgundy volume: 0 - 100, stereo 134 * Burgundy volume: 0 - 100, stereo, word reg
131 */ 135 */
132static void 136static void
133snd_pmac_burgundy_write_volume(struct snd_pmac *chip, unsigned int address, 137snd_pmac_burgundy_write_volume(struct snd_pmac *chip, unsigned int address,
@@ -168,13 +172,6 @@ snd_pmac_burgundy_read_volume(struct snd_pmac *chip, unsigned int address,
168 volume[1] = 0; 172 volume[1] = 0;
169} 173}
170 174
171
172/*
173 */
174
175#define BASE2ADDR(base) ((base) << 12)
176#define ADDR2BASE(addr) ((addr) >> 12)
177
178static int snd_pmac_burgundy_info_volume(struct snd_kcontrol *kcontrol, 175static int snd_pmac_burgundy_info_volume(struct snd_kcontrol *kcontrol,
179 struct snd_ctl_elem_info *uinfo) 176 struct snd_ctl_elem_info *uinfo)
180{ 177{
@@ -191,8 +188,8 @@ static int snd_pmac_burgundy_get_volume(struct snd_kcontrol *kcontrol,
191 struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); 188 struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
192 unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff); 189 unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
193 int shift = (kcontrol->private_value >> 8) & 0xff; 190 int shift = (kcontrol->private_value >> 8) & 0xff;
194 snd_pmac_burgundy_read_volume(chip, addr, ucontrol->value.integer.value, 191 snd_pmac_burgundy_read_volume(chip, addr,
195 shift); 192 ucontrol->value.integer.value, shift);
196 return 0; 193 return 0;
197} 194}
198 195
@@ -204,24 +201,163 @@ static int snd_pmac_burgundy_put_volume(struct snd_kcontrol *kcontrol,
204 int shift = (kcontrol->private_value >> 8) & 0xff; 201 int shift = (kcontrol->private_value >> 8) & 0xff;
205 long nvoices[2]; 202 long nvoices[2];
206 203
207 snd_pmac_burgundy_write_volume(chip, addr, ucontrol->value.integer.value, 204 snd_pmac_burgundy_write_volume(chip, addr,
208 shift); 205 ucontrol->value.integer.value, shift);
209 snd_pmac_burgundy_read_volume(chip, addr, nvoices, shift); 206 snd_pmac_burgundy_read_volume(chip, addr, nvoices, shift);
210 return (nvoices[0] != ucontrol->value.integer.value[0] || 207 return (nvoices[0] != ucontrol->value.integer.value[0] ||
211 nvoices[1] != ucontrol->value.integer.value[1]); 208 nvoices[1] != ucontrol->value.integer.value[1]);
212} 209}
213 210
214#define BURGUNDY_VOLUME(xname, xindex, addr, shift) \ 211#define BURGUNDY_VOLUME_W(xname, xindex, addr, shift) \
215{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\ 212{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
216 .info = snd_pmac_burgundy_info_volume,\ 213 .info = snd_pmac_burgundy_info_volume,\
217 .get = snd_pmac_burgundy_get_volume,\ 214 .get = snd_pmac_burgundy_get_volume,\
218 .put = snd_pmac_burgundy_put_volume,\ 215 .put = snd_pmac_burgundy_put_volume,\
219 .private_value = ((ADDR2BASE(addr) & 0xff) | ((shift) << 8)) } 216 .private_value = ((ADDR2BASE(addr) & 0xff) | ((shift) << 8)) }
220 217
221/* lineout/speaker */ 218/*
219 * Burgundy volume: 0 - 100, stereo, 2-byte reg
220 */
221static void
222snd_pmac_burgundy_write_volume_2b(struct snd_pmac *chip, unsigned int address,
223 long *volume, int off)
224{
225 int lvolume, rvolume;
222 226
223static int snd_pmac_burgundy_info_switch_out(struct snd_kcontrol *kcontrol, 227 off |= off << 2;
224 struct snd_ctl_elem_info *uinfo) 228 lvolume = volume[0] ? volume[0] + BURGUNDY_VOLUME_OFFSET : 0;
229 rvolume = volume[1] ? volume[1] + BURGUNDY_VOLUME_OFFSET : 0;
230
231 snd_pmac_burgundy_wcb(chip, address + off, lvolume);
232 snd_pmac_burgundy_wcb(chip, address + off + 0x500, rvolume);
233}
234
235static void
236snd_pmac_burgundy_read_volume_2b(struct snd_pmac *chip, unsigned int address,
237 long *volume, int off)
238{
239 volume[0] = snd_pmac_burgundy_rcb(chip, address + off);
240 if (volume[0] >= BURGUNDY_VOLUME_OFFSET)
241 volume[0] -= BURGUNDY_VOLUME_OFFSET;
242 else
243 volume[0] = 0;
244 volume[1] = snd_pmac_burgundy_rcb(chip, address + off + 0x100);
245 if (volume[1] >= BURGUNDY_VOLUME_OFFSET)
246 volume[1] -= BURGUNDY_VOLUME_OFFSET;
247 else
248 volume[1] = 0;
249}
250
251static int snd_pmac_burgundy_info_volume_2b(struct snd_kcontrol *kcontrol,
252 struct snd_ctl_elem_info *uinfo)
253{
254 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
255 uinfo->count = 2;
256 uinfo->value.integer.min = 0;
257 uinfo->value.integer.max = 100;
258 return 0;
259}
260
261static int snd_pmac_burgundy_get_volume_2b(struct snd_kcontrol *kcontrol,
262 struct snd_ctl_elem_value *ucontrol)
263{
264 struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
265 unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
266 int off = kcontrol->private_value & 0x300;
267 snd_pmac_burgundy_read_volume_2b(chip, addr,
268 ucontrol->value.integer.value, off);
269 return 0;
270}
271
272static int snd_pmac_burgundy_put_volume_2b(struct snd_kcontrol *kcontrol,
273 struct snd_ctl_elem_value *ucontrol)
274{
275 struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
276 unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
277 int off = kcontrol->private_value & 0x300;
278 long nvoices[2];
279
280 snd_pmac_burgundy_write_volume_2b(chip, addr,
281 ucontrol->value.integer.value, off);
282 snd_pmac_burgundy_read_volume_2b(chip, addr, nvoices, off);
283 return (nvoices[0] != ucontrol->value.integer.value[0] ||
284 nvoices[1] != ucontrol->value.integer.value[1]);
285}
286
287#define BURGUNDY_VOLUME_2B(xname, xindex, addr, off) \
288{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
289 .info = snd_pmac_burgundy_info_volume_2b,\
290 .get = snd_pmac_burgundy_get_volume_2b,\
291 .put = snd_pmac_burgundy_put_volume_2b,\
292 .private_value = ((ADDR2BASE(addr) & 0xff) | ((off) << 8)) }
293
294/*
295 * Burgundy gain/attenuation: 0 - 15, mono/stereo, byte reg
296 */
297static int snd_pmac_burgundy_info_gain(struct snd_kcontrol *kcontrol,
298 struct snd_ctl_elem_info *uinfo)
299{
300 int stereo = (kcontrol->private_value >> 24) & 1;
301 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
302 uinfo->count = stereo + 1;
303 uinfo->value.integer.min = 0;
304 uinfo->value.integer.max = 15;
305 return 0;
306}
307
308static int snd_pmac_burgundy_get_gain(struct snd_kcontrol *kcontrol,
309 struct snd_ctl_elem_value *ucontrol)
310{
311 struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
312 unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
313 int stereo = (kcontrol->private_value >> 24) & 1;
314 int atten = (kcontrol->private_value >> 25) & 1;
315 int oval;
316
317 oval = snd_pmac_burgundy_rcb(chip, addr);
318 if (atten)
319 oval = ~oval & 0xff;
320 ucontrol->value.integer.value[0] = oval & 0xf;
321 if (stereo)
322 ucontrol->value.integer.value[1] = (oval >> 4) & 0xf;
323 return 0;
324}
325
326static int snd_pmac_burgundy_put_gain(struct snd_kcontrol *kcontrol,
327 struct snd_ctl_elem_value *ucontrol)
328{
329 struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
330 unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
331 int stereo = (kcontrol->private_value >> 24) & 1;
332 int atten = (kcontrol->private_value >> 25) & 1;
333 int oval, val;
334
335 oval = snd_pmac_burgundy_rcb(chip, addr);
336 if (atten)
337 oval = ~oval & 0xff;
338 val = ucontrol->value.integer.value[0];
339 if (stereo)
340 val |= ucontrol->value.integer.value[1] << 4;
341 else
342 val |= ucontrol->value.integer.value[0] << 4;
343 if (atten)
344 val = ~val & 0xff;
345 snd_pmac_burgundy_wcb(chip, addr, val);
346 return val != oval;
347}
348
349#define BURGUNDY_VOLUME_B(xname, xindex, addr, stereo, atten) \
350{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
351 .info = snd_pmac_burgundy_info_gain,\
352 .get = snd_pmac_burgundy_get_gain,\
353 .put = snd_pmac_burgundy_put_gain,\
354 .private_value = (ADDR2BASE(addr) | ((stereo) << 24) | ((atten) << 25)) }
355
356/*
357 * Burgundy switch: 0/1, mono/stereo, word reg
358 */
359static int snd_pmac_burgundy_info_switch_w(struct snd_kcontrol *kcontrol,
360 struct snd_ctl_elem_info *uinfo)
225{ 361{
226 int stereo = (kcontrol->private_value >> 24) & 1; 362 int stereo = (kcontrol->private_value >> 24) & 1;
227 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 363 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
@@ -231,111 +367,207 @@ static int snd_pmac_burgundy_info_switch_out(struct snd_kcontrol *kcontrol,
231 return 0; 367 return 0;
232} 368}
233 369
234static int snd_pmac_burgundy_get_switch_out(struct snd_kcontrol *kcontrol, 370static int snd_pmac_burgundy_get_switch_w(struct snd_kcontrol *kcontrol,
235 struct snd_ctl_elem_value *ucontrol) 371 struct snd_ctl_elem_value *ucontrol)
236{ 372{
237 struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); 373 struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
238 int lmask = kcontrol->private_value & 0xff; 374 unsigned int addr = BASE2ADDR((kcontrol->private_value >> 16) & 0xff);
239 int rmask = (kcontrol->private_value >> 8) & 0xff; 375 int lmask = 1 << (kcontrol->private_value & 0xff);
376 int rmask = 1 << ((kcontrol->private_value >> 8) & 0xff);
240 int stereo = (kcontrol->private_value >> 24) & 1; 377 int stereo = (kcontrol->private_value >> 24) & 1;
241 int val = snd_pmac_burgundy_rcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES); 378 int val = snd_pmac_burgundy_rcw(chip, addr);
242 ucontrol->value.integer.value[0] = (val & lmask) ? 1 : 0; 379 ucontrol->value.integer.value[0] = (val & lmask) ? 1 : 0;
243 if (stereo) 380 if (stereo)
244 ucontrol->value.integer.value[1] = (val & rmask) ? 1 : 0; 381 ucontrol->value.integer.value[1] = (val & rmask) ? 1 : 0;
245 return 0; 382 return 0;
246} 383}
247 384
248static int snd_pmac_burgundy_put_switch_out(struct snd_kcontrol *kcontrol, 385static int snd_pmac_burgundy_put_switch_w(struct snd_kcontrol *kcontrol,
249 struct snd_ctl_elem_value *ucontrol) 386 struct snd_ctl_elem_value *ucontrol)
250{ 387{
251 struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); 388 struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
252 int lmask = kcontrol->private_value & 0xff; 389 unsigned int addr = BASE2ADDR((kcontrol->private_value >> 16) & 0xff);
253 int rmask = (kcontrol->private_value >> 8) & 0xff; 390 int lmask = 1 << (kcontrol->private_value & 0xff);
391 int rmask = 1 << ((kcontrol->private_value >> 8) & 0xff);
254 int stereo = (kcontrol->private_value >> 24) & 1; 392 int stereo = (kcontrol->private_value >> 24) & 1;
255 int val, oval; 393 int val, oval;
256 oval = snd_pmac_burgundy_rcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES); 394 oval = snd_pmac_burgundy_rcw(chip, addr);
257 val = oval & ~(lmask | rmask); 395 val = oval & ~(lmask | (stereo ? rmask : 0));
258 if (ucontrol->value.integer.value[0]) 396 if (ucontrol->value.integer.value[0])
259 val |= lmask; 397 val |= lmask;
260 if (stereo && ucontrol->value.integer.value[1]) 398 if (stereo && ucontrol->value.integer.value[1])
261 val |= rmask; 399 val |= rmask;
262 snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, val); 400 snd_pmac_burgundy_wcw(chip, addr, val);
263 return val != oval; 401 return val != oval;
264} 402}
265 403
266#define BURGUNDY_OUTPUT_SWITCH(xname, xindex, lmask, rmask, stereo) \ 404#define BURGUNDY_SWITCH_W(xname, xindex, addr, lbit, rbit, stereo) \
267{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\ 405{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
268 .info = snd_pmac_burgundy_info_switch_out,\ 406 .info = snd_pmac_burgundy_info_switch_w,\
269 .get = snd_pmac_burgundy_get_switch_out,\ 407 .get = snd_pmac_burgundy_get_switch_w,\
270 .put = snd_pmac_burgundy_put_switch_out,\ 408 .put = snd_pmac_burgundy_put_switch_w,\
271 .private_value = ((lmask) | ((rmask) << 8) | ((stereo) << 24)) } 409 .private_value = ((lbit) | ((rbit) << 8)\
272 410 | (ADDR2BASE(addr) << 16) | ((stereo) << 24)) }
273/* line/speaker output volume */ 411
274static int snd_pmac_burgundy_info_volume_out(struct snd_kcontrol *kcontrol, 412/*
275 struct snd_ctl_elem_info *uinfo) 413 * Burgundy switch: 0/1, mono/stereo, byte reg, bit mask
414 */
415static int snd_pmac_burgundy_info_switch_b(struct snd_kcontrol *kcontrol,
416 struct snd_ctl_elem_info *uinfo)
276{ 417{
277 int stereo = (kcontrol->private_value >> 24) & 1; 418 int stereo = (kcontrol->private_value >> 24) & 1;
278 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 419 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
279 uinfo->count = stereo + 1; 420 uinfo->count = stereo + 1;
280 uinfo->value.integer.min = 0; 421 uinfo->value.integer.min = 0;
281 uinfo->value.integer.max = 15; 422 uinfo->value.integer.max = 1;
282 return 0; 423 return 0;
283} 424}
284 425
285static int snd_pmac_burgundy_get_volume_out(struct snd_kcontrol *kcontrol, 426static int snd_pmac_burgundy_get_switch_b(struct snd_kcontrol *kcontrol,
286 struct snd_ctl_elem_value *ucontrol) 427 struct snd_ctl_elem_value *ucontrol)
287{ 428{
288 struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); 429 struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
289 unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff); 430 unsigned int addr = BASE2ADDR((kcontrol->private_value >> 16) & 0xff);
431 int lmask = kcontrol->private_value & 0xff;
432 int rmask = (kcontrol->private_value >> 8) & 0xff;
290 int stereo = (kcontrol->private_value >> 24) & 1; 433 int stereo = (kcontrol->private_value >> 24) & 1;
291 int oval; 434 int val = snd_pmac_burgundy_rcb(chip, addr);
292 435 ucontrol->value.integer.value[0] = (val & lmask) ? 1 : 0;
293 oval = ~snd_pmac_burgundy_rcb(chip, addr) & 0xff;
294 ucontrol->value.integer.value[0] = oval & 0xf;
295 if (stereo) 436 if (stereo)
296 ucontrol->value.integer.value[1] = (oval >> 4) & 0xf; 437 ucontrol->value.integer.value[1] = (val & rmask) ? 1 : 0;
297 return 0; 438 return 0;
298} 439}
299 440
300static int snd_pmac_burgundy_put_volume_out(struct snd_kcontrol *kcontrol, 441static int snd_pmac_burgundy_put_switch_b(struct snd_kcontrol *kcontrol,
301 struct snd_ctl_elem_value *ucontrol) 442 struct snd_ctl_elem_value *ucontrol)
302{ 443{
303 struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); 444 struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
304 unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff); 445 unsigned int addr = BASE2ADDR((kcontrol->private_value >> 16) & 0xff);
446 int lmask = kcontrol->private_value & 0xff;
447 int rmask = (kcontrol->private_value >> 8) & 0xff;
305 int stereo = (kcontrol->private_value >> 24) & 1; 448 int stereo = (kcontrol->private_value >> 24) & 1;
306 unsigned int oval, val; 449 int val, oval;
307 450 oval = snd_pmac_burgundy_rcb(chip, addr);
308 oval = ~snd_pmac_burgundy_rcb(chip, addr) & 0xff; 451 val = oval & ~(lmask | rmask);
309 val = ucontrol->value.integer.value[0] & 15; 452 if (ucontrol->value.integer.value[0])
310 if (stereo) 453 val |= lmask;
311 val |= (ucontrol->value.integer.value[1] & 15) << 4; 454 if (stereo && ucontrol->value.integer.value[1])
312 else 455 val |= rmask;
313 val |= val << 4;
314 val = ~val & 0xff;
315 snd_pmac_burgundy_wcb(chip, addr, val); 456 snd_pmac_burgundy_wcb(chip, addr, val);
316 return val != oval; 457 return val != oval;
317} 458}
318 459
319#define BURGUNDY_OUTPUT_VOLUME(xname, xindex, addr, stereo) \ 460#define BURGUNDY_SWITCH_B(xname, xindex, addr, lmask, rmask, stereo) \
320{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\ 461{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
321 .info = snd_pmac_burgundy_info_volume_out,\ 462 .info = snd_pmac_burgundy_info_switch_b,\
322 .get = snd_pmac_burgundy_get_volume_out,\ 463 .get = snd_pmac_burgundy_get_switch_b,\
323 .put = snd_pmac_burgundy_put_volume_out,\ 464 .put = snd_pmac_burgundy_put_switch_b,\
324 .private_value = (ADDR2BASE(addr) | ((stereo) << 24)) } 465 .private_value = ((lmask) | ((rmask) << 8)\
466 | (ADDR2BASE(addr) << 16) | ((stereo) << 24)) }
325 467
468/*
469 * Burgundy mixers
470 */
326static struct snd_kcontrol_new snd_pmac_burgundy_mixers[] __initdata = { 471static struct snd_kcontrol_new snd_pmac_burgundy_mixers[] __initdata = {
327 BURGUNDY_VOLUME("Master Playback Volume", 0, MASK_ADDR_BURGUNDY_MASTER_VOLUME, 8), 472 BURGUNDY_VOLUME_W("Master Playback Volume", 0,
328 BURGUNDY_VOLUME("Line Playback Volume", 0, MASK_ADDR_BURGUNDY_VOLLINE, 16), 473 MASK_ADDR_BURGUNDY_MASTER_VOLUME, 8),
329 BURGUNDY_VOLUME("CD Playback Volume", 0, MASK_ADDR_BURGUNDY_VOLCD, 16), 474 BURGUNDY_VOLUME_W("CD Capture Volume", 0,
330 BURGUNDY_VOLUME("Mic Playback Volume", 0, MASK_ADDR_BURGUNDY_VOLMIC, 16), 475 MASK_ADDR_BURGUNDY_VOLCD, 16),
331 BURGUNDY_OUTPUT_VOLUME("PC Speaker Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENHP, 0), 476 BURGUNDY_VOLUME_2B("Input Capture Volume", 0,
332 /*BURGUNDY_OUTPUT_VOLUME("PCM Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENLINEOUT, 1),*/ 477 MASK_ADDR_BURGUNDY_VOLMIX01, 2),
333 BURGUNDY_OUTPUT_VOLUME("Headphone Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENSPEAKER, 1), 478 BURGUNDY_VOLUME_2B("Mixer Playback Volume", 0,
334}; 479 MASK_ADDR_BURGUNDY_VOLMIX23, 0),
335static struct snd_kcontrol_new snd_pmac_burgundy_master_sw __initdata = 480 BURGUNDY_VOLUME_B("CD Gain Capture Volume", 0,
336BURGUNDY_OUTPUT_SWITCH("Headphone Playback Switch", 0, BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1); 481 MASK_ADDR_BURGUNDY_GAINCD, 1, 0),
337static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw __initdata = 482 BURGUNDY_SWITCH_W("Master Capture Switch", 0,
338BURGUNDY_OUTPUT_SWITCH("PC Speaker Playback Switch", 0, BURGUNDY_OUTPUT_INTERN, 0, 0); 483 MASK_ADDR_BURGUNDY_OUTPUTENABLES, 24, 0, 0),
484 BURGUNDY_SWITCH_W("CD Capture Switch", 0,
485 MASK_ADDR_BURGUNDY_CAPTURESELECTS, 0, 16, 1),
486 BURGUNDY_SWITCH_W("CD Playback Switch", 0,
487 MASK_ADDR_BURGUNDY_OUTPUTSELECTS, 0, 16, 1),
488/* BURGUNDY_SWITCH_W("Loop Capture Switch", 0,
489 * MASK_ADDR_BURGUNDY_CAPTURESELECTS, 8, 24, 1),
490 * BURGUNDY_SWITCH_B("Mixer out Capture Switch", 0,
491 * MASK_ADDR_BURGUNDY_HOSTIFAD, 0x02, 0, 0),
492 * BURGUNDY_SWITCH_B("Mixer Capture Switch", 0,
493 * MASK_ADDR_BURGUNDY_HOSTIFAD, 0x01, 0, 0),
494 * BURGUNDY_SWITCH_B("PCM out Capture Switch", 0,
495 * MASK_ADDR_BURGUNDY_HOSTIFEH, 0x02, 0, 0),
496 */ BURGUNDY_SWITCH_B("PCM Capture Switch", 0,
497 MASK_ADDR_BURGUNDY_HOSTIFEH, 0x01, 0, 0)
498};
499static struct snd_kcontrol_new snd_pmac_burgundy_mixers_imac[] __initdata = {
500 BURGUNDY_VOLUME_W("Line in Capture Volume", 0,
501 MASK_ADDR_BURGUNDY_VOLLINE, 16),
502 BURGUNDY_VOLUME_W("Mic Capture Volume", 0,
503 MASK_ADDR_BURGUNDY_VOLMIC, 16),
504 BURGUNDY_VOLUME_B("Line in Gain Capture Volume", 0,
505 MASK_ADDR_BURGUNDY_GAINLINE, 1, 0),
506 BURGUNDY_VOLUME_B("Mic Gain Capture Volume", 0,
507 MASK_ADDR_BURGUNDY_GAINMIC, 1, 0),
508 BURGUNDY_VOLUME_B("PC Speaker Playback Volume", 0,
509 MASK_ADDR_BURGUNDY_ATTENSPEAKER, 1, 1),
510 BURGUNDY_VOLUME_B("Line out Playback Volume", 0,
511 MASK_ADDR_BURGUNDY_ATTENLINEOUT, 1, 1),
512 BURGUNDY_VOLUME_B("Headphone Playback Volume", 0,
513 MASK_ADDR_BURGUNDY_ATTENHP, 1, 1),
514 BURGUNDY_SWITCH_W("Line in Capture Switch", 0,
515 MASK_ADDR_BURGUNDY_CAPTURESELECTS, 1, 17, 1),
516 BURGUNDY_SWITCH_W("Mic Capture Switch", 0,
517 MASK_ADDR_BURGUNDY_CAPTURESELECTS, 2, 18, 1),
518 BURGUNDY_SWITCH_W("Line in Playback Switch", 0,
519 MASK_ADDR_BURGUNDY_OUTPUTSELECTS, 1, 17, 1),
520 BURGUNDY_SWITCH_W("Mic Playback Switch", 0,
521 MASK_ADDR_BURGUNDY_OUTPUTSELECTS, 2, 18, 1),
522 BURGUNDY_SWITCH_B("Mic Boost Capture Switch", 0,
523 MASK_ADDR_BURGUNDY_INPBOOST, 0x40, 0x80, 1)
524};
525static struct snd_kcontrol_new snd_pmac_burgundy_mixers_pmac[] __initdata = {
526 BURGUNDY_VOLUME_W("Line in Capture Volume", 0,
527 MASK_ADDR_BURGUNDY_VOLMIC, 16),
528 BURGUNDY_VOLUME_B("Line in Gain Capture Volume", 0,
529 MASK_ADDR_BURGUNDY_GAINMIC, 1, 0),
530 BURGUNDY_VOLUME_B("PC Speaker Playback Volume", 0,
531 MASK_ADDR_BURGUNDY_ATTENMONO, 0, 1),
532 BURGUNDY_VOLUME_B("Line out Playback Volume", 0,
533 MASK_ADDR_BURGUNDY_ATTENSPEAKER, 1, 1),
534 BURGUNDY_SWITCH_W("Line in Capture Switch", 0,
535 MASK_ADDR_BURGUNDY_CAPTURESELECTS, 2, 18, 1),
536 BURGUNDY_SWITCH_W("Line in Playback Switch", 0,
537 MASK_ADDR_BURGUNDY_OUTPUTSELECTS, 2, 18, 1),
538/* BURGUNDY_SWITCH_B("Line in Boost Capture Switch", 0,
539 * MASK_ADDR_BURGUNDY_INPBOOST, 0x40, 0x80, 1) */
540};
541static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_imac __initdata =
542BURGUNDY_SWITCH_B("Master Playback Switch", 0,
543 MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
544 BURGUNDY_OUTPUT_LEFT | BURGUNDY_LINEOUT_LEFT | BURGUNDY_HP_LEFT,
545 BURGUNDY_OUTPUT_RIGHT | BURGUNDY_LINEOUT_RIGHT | BURGUNDY_HP_RIGHT, 1);
546static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_pmac __initdata =
547BURGUNDY_SWITCH_B("Master Playback Switch", 0,
548 MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
549 BURGUNDY_OUTPUT_INTERN
550 | BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1);
551static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_imac __initdata =
552BURGUNDY_SWITCH_B("PC Speaker Playback Switch", 0,
553 MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
554 BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1);
555static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_pmac __initdata =
556BURGUNDY_SWITCH_B("PC Speaker Playback Switch", 0,
557 MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
558 BURGUNDY_OUTPUT_INTERN, 0, 0);
559static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_imac __initdata =
560BURGUNDY_SWITCH_B("Line out Playback Switch", 0,
561 MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
562 BURGUNDY_LINEOUT_LEFT, BURGUNDY_LINEOUT_RIGHT, 1);
563static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_pmac __initdata =
564BURGUNDY_SWITCH_B("Line out Playback Switch", 0,
565 MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
566 BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1);
567static struct snd_kcontrol_new snd_pmac_burgundy_hp_sw_imac __initdata =
568BURGUNDY_SWITCH_B("Headphone Playback Switch", 0,
569 MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
570 BURGUNDY_HP_LEFT, BURGUNDY_HP_RIGHT, 1);
339 571
340 572
341#ifdef PMAC_SUPPORT_AUTOMUTE 573#ifdef PMAC_SUPPORT_AUTOMUTE
@@ -350,16 +582,26 @@ static int snd_pmac_burgundy_detect_headphone(struct snd_pmac *chip)
350static void snd_pmac_burgundy_update_automute(struct snd_pmac *chip, int do_notify) 582static void snd_pmac_burgundy_update_automute(struct snd_pmac *chip, int do_notify)
351{ 583{
352 if (chip->auto_mute) { 584 if (chip->auto_mute) {
585 int imac = machine_is_compatible("iMac");
353 int reg, oreg; 586 int reg, oreg;
354 reg = oreg = snd_pmac_burgundy_rcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES); 587 reg = oreg = snd_pmac_burgundy_rcb(chip,
355 reg &= ~(BURGUNDY_OUTPUT_LEFT | BURGUNDY_OUTPUT_RIGHT | BURGUNDY_OUTPUT_INTERN); 588 MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES);
589 reg &= imac ? ~(BURGUNDY_OUTPUT_LEFT | BURGUNDY_OUTPUT_RIGHT
590 | BURGUNDY_HP_LEFT | BURGUNDY_HP_RIGHT)
591 : ~(BURGUNDY_OUTPUT_LEFT | BURGUNDY_OUTPUT_RIGHT
592 | BURGUNDY_OUTPUT_INTERN);
356 if (snd_pmac_burgundy_detect_headphone(chip)) 593 if (snd_pmac_burgundy_detect_headphone(chip))
357 reg |= BURGUNDY_OUTPUT_LEFT | BURGUNDY_OUTPUT_RIGHT; 594 reg |= imac ? (BURGUNDY_HP_LEFT | BURGUNDY_HP_RIGHT)
595 : (BURGUNDY_OUTPUT_LEFT
596 | BURGUNDY_OUTPUT_RIGHT);
358 else 597 else
359 reg |= BURGUNDY_OUTPUT_INTERN; 598 reg |= imac ? (BURGUNDY_OUTPUT_LEFT
599 | BURGUNDY_OUTPUT_RIGHT)
600 : (BURGUNDY_OUTPUT_INTERN);
360 if (do_notify && reg == oreg) 601 if (do_notify && reg == oreg)
361 return; 602 return;
362 snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, reg); 603 snd_pmac_burgundy_wcb(chip,
604 MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, reg);
363 if (do_notify) { 605 if (do_notify) {
364 snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, 606 snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
365 &chip->master_sw_ctl->id); 607 &chip->master_sw_ctl->id);
@@ -378,6 +620,7 @@ static void snd_pmac_burgundy_update_automute(struct snd_pmac *chip, int do_noti
378 */ 620 */
379int __init snd_pmac_burgundy_init(struct snd_pmac *chip) 621int __init snd_pmac_burgundy_init(struct snd_pmac *chip)
380{ 622{
623 int imac = machine_is_compatible("iMac");
381 int i, err; 624 int i, err;
382 625
383 /* Checks to see the chip is alive and kicking */ 626 /* Checks to see the chip is alive and kicking */
@@ -386,7 +629,7 @@ int __init snd_pmac_burgundy_init(struct snd_pmac *chip)
386 return 1; 629 return 1;
387 } 630 }
388 631
389 snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_OUTPUTENABLES, 632 snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_OUTPUTENABLES,
390 DEF_BURGUNDY_OUTPUTENABLES); 633 DEF_BURGUNDY_OUTPUTENABLES);
391 snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, 634 snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
392 DEF_BURGUNDY_MORE_OUTPUTENABLES); 635 DEF_BURGUNDY_MORE_OUTPUTENABLES);
@@ -396,7 +639,8 @@ int __init snd_pmac_burgundy_init(struct snd_pmac *chip)
396 snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_INPSEL21, 639 snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_INPSEL21,
397 DEF_BURGUNDY_INPSEL21); 640 DEF_BURGUNDY_INPSEL21);
398 snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_INPSEL3, 641 snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_INPSEL3,
399 DEF_BURGUNDY_INPSEL3); 642 imac ? DEF_BURGUNDY_INPSEL3_IMAC
643 : DEF_BURGUNDY_INPSEL3_PMAC);
400 snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINCD, 644 snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINCD,
401 DEF_BURGUNDY_GAINCD); 645 DEF_BURGUNDY_GAINCD);
402 snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINLINE, 646 snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINLINE,
@@ -422,27 +666,62 @@ int __init snd_pmac_burgundy_init(struct snd_pmac *chip)
422 snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_VOLMIC, 666 snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_VOLMIC,
423 DEF_BURGUNDY_VOLMIC); 667 DEF_BURGUNDY_VOLMIC);
424 668
425 if (chip->hp_stat_mask == 0) 669 if (chip->hp_stat_mask == 0) {
426 /* set headphone-jack detection bit */ 670 /* set headphone-jack detection bit */
427 chip->hp_stat_mask = 0x04; 671 if (imac)
428 672 chip->hp_stat_mask = BURGUNDY_HPDETECT_IMAC_UPPER
673 | BURGUNDY_HPDETECT_IMAC_LOWER
674 | BURGUNDY_HPDETECT_IMAC_SIDE;
675 else
676 chip->hp_stat_mask = BURGUNDY_HPDETECT_PMAC_BACK;
677 }
429 /* 678 /*
430 * build burgundy mixers 679 * build burgundy mixers
431 */ 680 */
432 strcpy(chip->card->mixername, "PowerMac Burgundy"); 681 strcpy(chip->card->mixername, "PowerMac Burgundy");
433 682
434 for (i = 0; i < ARRAY_SIZE(snd_pmac_burgundy_mixers); i++) { 683 for (i = 0; i < ARRAY_SIZE(snd_pmac_burgundy_mixers); i++) {
435 if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_pmac_burgundy_mixers[i], chip))) < 0) 684 err = snd_ctl_add(chip->card,
685 snd_ctl_new1(&snd_pmac_burgundy_mixers[i], chip));
686 if (err < 0)
687 return err;
688 }
689 for (i = 0; i < (imac ? ARRAY_SIZE(snd_pmac_burgundy_mixers_imac)
690 : ARRAY_SIZE(snd_pmac_burgundy_mixers_pmac)); i++) {
691 err = snd_ctl_add(chip->card,
692 snd_ctl_new1(imac ? &snd_pmac_burgundy_mixers_imac[i]
693 : &snd_pmac_burgundy_mixers_pmac[i], chip));
694 if (err < 0)
436 return err; 695 return err;
437 } 696 }
438 chip->master_sw_ctl = snd_ctl_new1(&snd_pmac_burgundy_master_sw, chip); 697 chip->master_sw_ctl = snd_ctl_new1(imac
439 if ((err = snd_ctl_add(chip->card, chip->master_sw_ctl)) < 0) 698 ? &snd_pmac_burgundy_master_sw_imac
699 : &snd_pmac_burgundy_master_sw_pmac, chip);
700 err = snd_ctl_add(chip->card, chip->master_sw_ctl);
701 if (err < 0)
702 return err;
703 chip->master_sw_ctl = snd_ctl_new1(imac
704 ? &snd_pmac_burgundy_line_sw_imac
705 : &snd_pmac_burgundy_line_sw_pmac, chip);
706 err = snd_ctl_add(chip->card, chip->master_sw_ctl);
707 if (err < 0)
440 return err; 708 return err;
441 chip->speaker_sw_ctl = snd_ctl_new1(&snd_pmac_burgundy_speaker_sw, chip); 709 if (imac) {
442 if ((err = snd_ctl_add(chip->card, chip->speaker_sw_ctl)) < 0) 710 chip->master_sw_ctl = snd_ctl_new1(
711 &snd_pmac_burgundy_hp_sw_imac, chip);
712 err = snd_ctl_add(chip->card, chip->master_sw_ctl);
713 if (err < 0)
714 return err;
715 }
716 chip->speaker_sw_ctl = snd_ctl_new1(imac
717 ? &snd_pmac_burgundy_speaker_sw_imac
718 : &snd_pmac_burgundy_speaker_sw_pmac, chip);
719 err = snd_ctl_add(chip->card, chip->speaker_sw_ctl);
720 if (err < 0)
443 return err; 721 return err;
444#ifdef PMAC_SUPPORT_AUTOMUTE 722#ifdef PMAC_SUPPORT_AUTOMUTE
445 if ((err = snd_pmac_add_automute(chip)) < 0) 723 err = snd_pmac_add_automute(chip);
724 if (err < 0)
446 return err; 725 return err;
447 726
448 chip->detect_headphone = snd_pmac_burgundy_detect_headphone; 727 chip->detect_headphone = snd_pmac_burgundy_detect_headphone;