diff options
Diffstat (limited to 'sound/ppc/burgundy.c')
-rw-r--r-- | sound/ppc/burgundy.c | 465 |
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 | ||
104 | static void | 104 | static void |
105 | snd_pmac_burgundy_wcb(struct snd_pmac *chip, unsigned int addr, unsigned int val) | 105 | snd_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 | */ |
132 | static void | 136 | static void |
133 | snd_pmac_burgundy_write_volume(struct snd_pmac *chip, unsigned int address, | 137 | snd_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 | |||
178 | static int snd_pmac_burgundy_info_volume(struct snd_kcontrol *kcontrol, | 175 | static 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 | */ | ||
221 | static void | ||
222 | snd_pmac_burgundy_write_volume_2b(struct snd_pmac *chip, unsigned int address, | ||
223 | long *volume, int off) | ||
224 | { | ||
225 | int lvolume, rvolume; | ||
222 | 226 | ||
223 | static 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 | |||
235 | static void | ||
236 | snd_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 | |||
251 | static 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 | |||
261 | static 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 | |||
272 | static 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 | */ | ||
297 | static 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 | |||
308 | static 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 | |||
326 | static 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 | */ | ||
359 | static 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 | ||
234 | static int snd_pmac_burgundy_get_switch_out(struct snd_kcontrol *kcontrol, | 370 | static 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 | ||
248 | static int snd_pmac_burgundy_put_switch_out(struct snd_kcontrol *kcontrol, | 385 | static 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 | |
274 | static 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 | */ | ||
415 | static 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 | ||
285 | static int snd_pmac_burgundy_get_volume_out(struct snd_kcontrol *kcontrol, | 426 | static 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 | ||
300 | static int snd_pmac_burgundy_put_volume_out(struct snd_kcontrol *kcontrol, | 441 | static 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 | */ | ||
326 | static struct snd_kcontrol_new snd_pmac_burgundy_mixers[] __initdata = { | 471 | static 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), |
335 | static struct snd_kcontrol_new snd_pmac_burgundy_master_sw __initdata = | 480 | BURGUNDY_VOLUME_B("CD Gain Capture Volume", 0, |
336 | BURGUNDY_OUTPUT_SWITCH("Headphone Playback Switch", 0, BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1); | 481 | MASK_ADDR_BURGUNDY_GAINCD, 1, 0), |
337 | static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw __initdata = | 482 | BURGUNDY_SWITCH_W("Master Capture Switch", 0, |
338 | BURGUNDY_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 | }; | ||
499 | static 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 | }; | ||
525 | static 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 | }; | ||
541 | static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_imac __initdata = | ||
542 | BURGUNDY_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); | ||
546 | static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_pmac __initdata = | ||
547 | BURGUNDY_SWITCH_B("Master Playback Switch", 0, | ||
548 | MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, | ||
549 | BURGUNDY_OUTPUT_INTERN | ||
550 | | BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1); | ||
551 | static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_imac __initdata = | ||
552 | BURGUNDY_SWITCH_B("PC Speaker Playback Switch", 0, | ||
553 | MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, | ||
554 | BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1); | ||
555 | static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_pmac __initdata = | ||
556 | BURGUNDY_SWITCH_B("PC Speaker Playback Switch", 0, | ||
557 | MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, | ||
558 | BURGUNDY_OUTPUT_INTERN, 0, 0); | ||
559 | static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_imac __initdata = | ||
560 | BURGUNDY_SWITCH_B("Line out Playback Switch", 0, | ||
561 | MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, | ||
562 | BURGUNDY_LINEOUT_LEFT, BURGUNDY_LINEOUT_RIGHT, 1); | ||
563 | static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_pmac __initdata = | ||
564 | BURGUNDY_SWITCH_B("Line out Playback Switch", 0, | ||
565 | MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, | ||
566 | BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1); | ||
567 | static struct snd_kcontrol_new snd_pmac_burgundy_hp_sw_imac __initdata = | ||
568 | BURGUNDY_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) | |||
350 | static void snd_pmac_burgundy_update_automute(struct snd_pmac *chip, int do_notify) | 582 | static 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 | */ |
379 | int __init snd_pmac_burgundy_init(struct snd_pmac *chip) | 621 | int __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; |