1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * PMac AWACS lowlevel functions |
4 | * |
5 | * Copyright (c) by Takashi Iwai <tiwai@suse.de> |
6 | * code based on dmasound.c. |
7 | */ |
8 | |
9 | |
10 | #include <linux/io.h> |
11 | #include <asm/nvram.h> |
12 | #include <linux/init.h> |
13 | #include <linux/delay.h> |
14 | #include <linux/of.h> |
15 | #include <linux/slab.h> |
16 | #include <sound/core.h> |
17 | #include "pmac.h" |
18 | |
19 | |
20 | #ifdef CONFIG_ADB_CUDA |
21 | #define PMAC_AMP_AVAIL |
22 | #endif |
23 | |
24 | #ifdef PMAC_AMP_AVAIL |
25 | struct awacs_amp { |
26 | unsigned char amp_master; |
27 | unsigned char amp_vol[2][2]; |
28 | unsigned char amp_tone[2]; |
29 | }; |
30 | |
31 | #define CHECK_CUDA_AMP() (sys_ctrler == SYS_CTRLER_CUDA) |
32 | |
33 | #endif /* PMAC_AMP_AVAIL */ |
34 | |
35 | |
36 | static void snd_pmac_screamer_wait(struct snd_pmac *chip) |
37 | { |
38 | long timeout = 2000; |
39 | while (!(in_le32(&chip->awacs->codec_stat) & MASK_VALID)) { |
40 | mdelay(1); |
41 | if (! --timeout) { |
42 | snd_printd("snd_pmac_screamer_wait timeout\n" ); |
43 | break; |
44 | } |
45 | } |
46 | } |
47 | |
48 | /* |
49 | * write AWACS register |
50 | */ |
51 | static void |
52 | snd_pmac_awacs_write(struct snd_pmac *chip, int val) |
53 | { |
54 | long timeout = 5000000; |
55 | |
56 | if (chip->model == PMAC_SCREAMER) |
57 | snd_pmac_screamer_wait(chip); |
58 | out_le32(&chip->awacs->codec_ctrl, val | (chip->subframe << 22)); |
59 | while (in_le32(&chip->awacs->codec_ctrl) & MASK_NEWECMD) { |
60 | if (! --timeout) { |
61 | snd_printd("snd_pmac_awacs_write timeout\n" ); |
62 | break; |
63 | } |
64 | } |
65 | } |
66 | |
67 | static void |
68 | snd_pmac_awacs_write_reg(struct snd_pmac *chip, int reg, int val) |
69 | { |
70 | snd_pmac_awacs_write(chip, val: val | (reg << 12)); |
71 | chip->awacs_reg[reg] = val; |
72 | } |
73 | |
74 | static void |
75 | snd_pmac_awacs_write_noreg(struct snd_pmac *chip, int reg, int val) |
76 | { |
77 | snd_pmac_awacs_write(chip, val: val | (reg << 12)); |
78 | } |
79 | |
80 | #ifdef CONFIG_PM |
81 | /* Recalibrate chip */ |
82 | static void screamer_recalibrate(struct snd_pmac *chip) |
83 | { |
84 | if (chip->model != PMAC_SCREAMER) |
85 | return; |
86 | |
87 | /* Sorry for the horrible delays... I hope to get that improved |
88 | * by making the whole PM process asynchronous in a future version |
89 | */ |
90 | snd_pmac_awacs_write_noreg(chip, reg: 1, val: chip->awacs_reg[1]); |
91 | if (chip->manufacturer == 0x1) |
92 | /* delay for broken crystal part */ |
93 | msleep(msecs: 750); |
94 | snd_pmac_awacs_write_noreg(chip, reg: 1, |
95 | val: chip->awacs_reg[1] | MASK_RECALIBRATE | |
96 | MASK_CMUTE | MASK_AMUTE); |
97 | snd_pmac_awacs_write_noreg(chip, reg: 1, val: chip->awacs_reg[1]); |
98 | snd_pmac_awacs_write_noreg(chip, reg: 6, val: chip->awacs_reg[6]); |
99 | } |
100 | |
101 | #else |
102 | #define screamer_recalibrate(chip) /* NOP */ |
103 | #endif |
104 | |
105 | |
106 | /* |
107 | * additional callback to set the pcm format |
108 | */ |
109 | static void snd_pmac_awacs_set_format(struct snd_pmac *chip) |
110 | { |
111 | chip->awacs_reg[1] &= ~MASK_SAMPLERATE; |
112 | chip->awacs_reg[1] |= chip->rate_index << 3; |
113 | snd_pmac_awacs_write_reg(chip, reg: 1, val: chip->awacs_reg[1]); |
114 | } |
115 | |
116 | |
117 | /* |
118 | * AWACS volume callbacks |
119 | */ |
120 | /* |
121 | * volumes: 0-15 stereo |
122 | */ |
123 | static int snd_pmac_awacs_info_volume(struct snd_kcontrol *kcontrol, |
124 | struct snd_ctl_elem_info *uinfo) |
125 | { |
126 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
127 | uinfo->count = 2; |
128 | uinfo->value.integer.min = 0; |
129 | uinfo->value.integer.max = 15; |
130 | return 0; |
131 | } |
132 | |
133 | static int snd_pmac_awacs_get_volume(struct snd_kcontrol *kcontrol, |
134 | struct snd_ctl_elem_value *ucontrol) |
135 | { |
136 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); |
137 | int reg = kcontrol->private_value & 0xff; |
138 | int lshift = (kcontrol->private_value >> 8) & 0xff; |
139 | int inverted = (kcontrol->private_value >> 16) & 1; |
140 | unsigned long flags; |
141 | int vol[2]; |
142 | |
143 | spin_lock_irqsave(&chip->reg_lock, flags); |
144 | vol[0] = (chip->awacs_reg[reg] >> lshift) & 0xf; |
145 | vol[1] = chip->awacs_reg[reg] & 0xf; |
146 | spin_unlock_irqrestore(lock: &chip->reg_lock, flags); |
147 | if (inverted) { |
148 | vol[0] = 0x0f - vol[0]; |
149 | vol[1] = 0x0f - vol[1]; |
150 | } |
151 | ucontrol->value.integer.value[0] = vol[0]; |
152 | ucontrol->value.integer.value[1] = vol[1]; |
153 | return 0; |
154 | } |
155 | |
156 | static int snd_pmac_awacs_put_volume(struct snd_kcontrol *kcontrol, |
157 | struct snd_ctl_elem_value *ucontrol) |
158 | { |
159 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); |
160 | int reg = kcontrol->private_value & 0xff; |
161 | int lshift = (kcontrol->private_value >> 8) & 0xff; |
162 | int inverted = (kcontrol->private_value >> 16) & 1; |
163 | int val, oldval; |
164 | unsigned long flags; |
165 | unsigned int vol[2]; |
166 | |
167 | vol[0] = ucontrol->value.integer.value[0]; |
168 | vol[1] = ucontrol->value.integer.value[1]; |
169 | if (vol[0] > 0x0f || vol[1] > 0x0f) |
170 | return -EINVAL; |
171 | if (inverted) { |
172 | vol[0] = 0x0f - vol[0]; |
173 | vol[1] = 0x0f - vol[1]; |
174 | } |
175 | vol[0] &= 0x0f; |
176 | vol[1] &= 0x0f; |
177 | spin_lock_irqsave(&chip->reg_lock, flags); |
178 | oldval = chip->awacs_reg[reg]; |
179 | val = oldval & ~(0xf | (0xf << lshift)); |
180 | val |= vol[0] << lshift; |
181 | val |= vol[1]; |
182 | if (oldval != val) |
183 | snd_pmac_awacs_write_reg(chip, reg, val); |
184 | spin_unlock_irqrestore(lock: &chip->reg_lock, flags); |
185 | return oldval != reg; |
186 | } |
187 | |
188 | |
189 | #define AWACS_VOLUME(xname, xreg, xshift, xinverted) \ |
190 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ |
191 | .info = snd_pmac_awacs_info_volume, \ |
192 | .get = snd_pmac_awacs_get_volume, \ |
193 | .put = snd_pmac_awacs_put_volume, \ |
194 | .private_value = (xreg) | ((xshift) << 8) | ((xinverted) << 16) } |
195 | |
196 | /* |
197 | * mute master/ogain for AWACS: mono |
198 | */ |
199 | static int snd_pmac_awacs_get_switch(struct snd_kcontrol *kcontrol, |
200 | struct snd_ctl_elem_value *ucontrol) |
201 | { |
202 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); |
203 | int reg = kcontrol->private_value & 0xff; |
204 | int shift = (kcontrol->private_value >> 8) & 0xff; |
205 | int invert = (kcontrol->private_value >> 16) & 1; |
206 | int val; |
207 | unsigned long flags; |
208 | |
209 | spin_lock_irqsave(&chip->reg_lock, flags); |
210 | val = (chip->awacs_reg[reg] >> shift) & 1; |
211 | spin_unlock_irqrestore(lock: &chip->reg_lock, flags); |
212 | if (invert) |
213 | val = 1 - val; |
214 | ucontrol->value.integer.value[0] = val; |
215 | return 0; |
216 | } |
217 | |
218 | static int snd_pmac_awacs_put_switch(struct snd_kcontrol *kcontrol, |
219 | struct snd_ctl_elem_value *ucontrol) |
220 | { |
221 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); |
222 | int reg = kcontrol->private_value & 0xff; |
223 | int shift = (kcontrol->private_value >> 8) & 0xff; |
224 | int invert = (kcontrol->private_value >> 16) & 1; |
225 | int mask = 1 << shift; |
226 | int val, changed; |
227 | unsigned long flags; |
228 | |
229 | spin_lock_irqsave(&chip->reg_lock, flags); |
230 | val = chip->awacs_reg[reg] & ~mask; |
231 | if (ucontrol->value.integer.value[0] != invert) |
232 | val |= mask; |
233 | changed = chip->awacs_reg[reg] != val; |
234 | if (changed) |
235 | snd_pmac_awacs_write_reg(chip, reg, val); |
236 | spin_unlock_irqrestore(lock: &chip->reg_lock, flags); |
237 | return changed; |
238 | } |
239 | |
240 | #define AWACS_SWITCH(xname, xreg, xshift, xinvert) \ |
241 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ |
242 | .info = snd_pmac_boolean_mono_info, \ |
243 | .get = snd_pmac_awacs_get_switch, \ |
244 | .put = snd_pmac_awacs_put_switch, \ |
245 | .private_value = (xreg) | ((xshift) << 8) | ((xinvert) << 16) } |
246 | |
247 | |
248 | #ifdef PMAC_AMP_AVAIL |
249 | /* |
250 | * controls for perch/whisper extension cards, e.g. G3 desktop |
251 | * |
252 | * TDA7433 connected via i2c address 0x45 (= 0x8a), |
253 | * accessed through cuda |
254 | */ |
255 | static void awacs_set_cuda(int reg, int val) |
256 | { |
257 | struct adb_request req; |
258 | cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 0x8a, |
259 | reg, val); |
260 | while (! req.complete) |
261 | cuda_poll(); |
262 | } |
263 | |
264 | /* |
265 | * level = 0 - 14, 7 = 0 dB |
266 | */ |
267 | static void awacs_amp_set_tone(struct awacs_amp *amp, int bass, int treble) |
268 | { |
269 | amp->amp_tone[0] = bass; |
270 | amp->amp_tone[1] = treble; |
271 | if (bass > 7) |
272 | bass = (14 - bass) + 8; |
273 | if (treble > 7) |
274 | treble = (14 - treble) + 8; |
275 | awacs_set_cuda(2, (bass << 4) | treble); |
276 | } |
277 | |
278 | /* |
279 | * vol = 0 - 31 (attenuation), 32 = mute bit, stereo |
280 | */ |
281 | static int awacs_amp_set_vol(struct awacs_amp *amp, int index, |
282 | int lvol, int rvol, int do_check) |
283 | { |
284 | if (do_check && amp->amp_vol[index][0] == lvol && |
285 | amp->amp_vol[index][1] == rvol) |
286 | return 0; |
287 | awacs_set_cuda(3 + index, lvol); |
288 | awacs_set_cuda(5 + index, rvol); |
289 | amp->amp_vol[index][0] = lvol; |
290 | amp->amp_vol[index][1] = rvol; |
291 | return 1; |
292 | } |
293 | |
294 | /* |
295 | * 0 = -79 dB, 79 = 0 dB, 99 = +20 dB |
296 | */ |
297 | static void awacs_amp_set_master(struct awacs_amp *amp, int vol) |
298 | { |
299 | amp->amp_master = vol; |
300 | if (vol <= 79) |
301 | vol = 32 + (79 - vol); |
302 | else |
303 | vol = 32 - (vol - 79); |
304 | awacs_set_cuda(1, vol); |
305 | } |
306 | |
307 | static void awacs_amp_free(struct snd_pmac *chip) |
308 | { |
309 | struct awacs_amp *amp = chip->mixer_data; |
310 | if (!amp) |
311 | return; |
312 | kfree(amp); |
313 | chip->mixer_data = NULL; |
314 | chip->mixer_free = NULL; |
315 | } |
316 | |
317 | |
318 | /* |
319 | * mixer controls |
320 | */ |
321 | static int snd_pmac_awacs_info_volume_amp(struct snd_kcontrol *kcontrol, |
322 | struct snd_ctl_elem_info *uinfo) |
323 | { |
324 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
325 | uinfo->count = 2; |
326 | uinfo->value.integer.min = 0; |
327 | uinfo->value.integer.max = 31; |
328 | return 0; |
329 | } |
330 | |
331 | static int snd_pmac_awacs_get_volume_amp(struct snd_kcontrol *kcontrol, |
332 | struct snd_ctl_elem_value *ucontrol) |
333 | { |
334 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); |
335 | int index = kcontrol->private_value; |
336 | struct awacs_amp *amp = chip->mixer_data; |
337 | |
338 | ucontrol->value.integer.value[0] = 31 - (amp->amp_vol[index][0] & 31); |
339 | ucontrol->value.integer.value[1] = 31 - (amp->amp_vol[index][1] & 31); |
340 | return 0; |
341 | } |
342 | |
343 | static int snd_pmac_awacs_put_volume_amp(struct snd_kcontrol *kcontrol, |
344 | struct snd_ctl_elem_value *ucontrol) |
345 | { |
346 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); |
347 | int index = kcontrol->private_value; |
348 | int vol[2]; |
349 | struct awacs_amp *amp = chip->mixer_data; |
350 | |
351 | vol[0] = (31 - (ucontrol->value.integer.value[0] & 31)) |
352 | | (amp->amp_vol[index][0] & 32); |
353 | vol[1] = (31 - (ucontrol->value.integer.value[1] & 31)) |
354 | | (amp->amp_vol[index][1] & 32); |
355 | return awacs_amp_set_vol(amp, index, vol[0], vol[1], 1); |
356 | } |
357 | |
358 | static int snd_pmac_awacs_get_switch_amp(struct snd_kcontrol *kcontrol, |
359 | struct snd_ctl_elem_value *ucontrol) |
360 | { |
361 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); |
362 | int index = kcontrol->private_value; |
363 | struct awacs_amp *amp = chip->mixer_data; |
364 | |
365 | ucontrol->value.integer.value[0] = (amp->amp_vol[index][0] & 32) |
366 | ? 0 : 1; |
367 | ucontrol->value.integer.value[1] = (amp->amp_vol[index][1] & 32) |
368 | ? 0 : 1; |
369 | return 0; |
370 | } |
371 | |
372 | static int snd_pmac_awacs_put_switch_amp(struct snd_kcontrol *kcontrol, |
373 | struct snd_ctl_elem_value *ucontrol) |
374 | { |
375 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); |
376 | int index = kcontrol->private_value; |
377 | int vol[2]; |
378 | struct awacs_amp *amp = chip->mixer_data; |
379 | |
380 | vol[0] = (ucontrol->value.integer.value[0] ? 0 : 32) |
381 | | (amp->amp_vol[index][0] & 31); |
382 | vol[1] = (ucontrol->value.integer.value[1] ? 0 : 32) |
383 | | (amp->amp_vol[index][1] & 31); |
384 | return awacs_amp_set_vol(amp, index, vol[0], vol[1], 1); |
385 | } |
386 | |
387 | static int snd_pmac_awacs_info_tone_amp(struct snd_kcontrol *kcontrol, |
388 | struct snd_ctl_elem_info *uinfo) |
389 | { |
390 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
391 | uinfo->count = 1; |
392 | uinfo->value.integer.min = 0; |
393 | uinfo->value.integer.max = 14; |
394 | return 0; |
395 | } |
396 | |
397 | static int snd_pmac_awacs_get_tone_amp(struct snd_kcontrol *kcontrol, |
398 | struct snd_ctl_elem_value *ucontrol) |
399 | { |
400 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); |
401 | int index = kcontrol->private_value; |
402 | struct awacs_amp *amp = chip->mixer_data; |
403 | |
404 | ucontrol->value.integer.value[0] = amp->amp_tone[index]; |
405 | return 0; |
406 | } |
407 | |
408 | static int snd_pmac_awacs_put_tone_amp(struct snd_kcontrol *kcontrol, |
409 | struct snd_ctl_elem_value *ucontrol) |
410 | { |
411 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); |
412 | int index = kcontrol->private_value; |
413 | struct awacs_amp *amp = chip->mixer_data; |
414 | unsigned int val; |
415 | |
416 | val = ucontrol->value.integer.value[0]; |
417 | if (val > 14) |
418 | return -EINVAL; |
419 | if (val != amp->amp_tone[index]) { |
420 | amp->amp_tone[index] = val; |
421 | awacs_amp_set_tone(amp, amp->amp_tone[0], amp->amp_tone[1]); |
422 | return 1; |
423 | } |
424 | return 0; |
425 | } |
426 | |
427 | static int snd_pmac_awacs_info_master_amp(struct snd_kcontrol *kcontrol, |
428 | struct snd_ctl_elem_info *uinfo) |
429 | { |
430 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
431 | uinfo->count = 1; |
432 | uinfo->value.integer.min = 0; |
433 | uinfo->value.integer.max = 99; |
434 | return 0; |
435 | } |
436 | |
437 | static int snd_pmac_awacs_get_master_amp(struct snd_kcontrol *kcontrol, |
438 | struct snd_ctl_elem_value *ucontrol) |
439 | { |
440 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); |
441 | struct awacs_amp *amp = chip->mixer_data; |
442 | |
443 | ucontrol->value.integer.value[0] = amp->amp_master; |
444 | return 0; |
445 | } |
446 | |
447 | static int snd_pmac_awacs_put_master_amp(struct snd_kcontrol *kcontrol, |
448 | struct snd_ctl_elem_value *ucontrol) |
449 | { |
450 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); |
451 | struct awacs_amp *amp = chip->mixer_data; |
452 | unsigned int val; |
453 | |
454 | val = ucontrol->value.integer.value[0]; |
455 | if (val > 99) |
456 | return -EINVAL; |
457 | if (val != amp->amp_master) { |
458 | amp->amp_master = val; |
459 | awacs_amp_set_master(amp, amp->amp_master); |
460 | return 1; |
461 | } |
462 | return 0; |
463 | } |
464 | |
465 | #define AMP_CH_SPK 0 |
466 | #define AMP_CH_HD 1 |
467 | |
468 | static const struct snd_kcontrol_new snd_pmac_awacs_amp_vol[] = { |
469 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
470 | .name = "Speaker Playback Volume" , |
471 | .info = snd_pmac_awacs_info_volume_amp, |
472 | .get = snd_pmac_awacs_get_volume_amp, |
473 | .put = snd_pmac_awacs_put_volume_amp, |
474 | .private_value = AMP_CH_SPK, |
475 | }, |
476 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
477 | .name = "Headphone Playback Volume" , |
478 | .info = snd_pmac_awacs_info_volume_amp, |
479 | .get = snd_pmac_awacs_get_volume_amp, |
480 | .put = snd_pmac_awacs_put_volume_amp, |
481 | .private_value = AMP_CH_HD, |
482 | }, |
483 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
484 | .name = "Tone Control - Bass" , |
485 | .info = snd_pmac_awacs_info_tone_amp, |
486 | .get = snd_pmac_awacs_get_tone_amp, |
487 | .put = snd_pmac_awacs_put_tone_amp, |
488 | .private_value = 0, |
489 | }, |
490 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
491 | .name = "Tone Control - Treble" , |
492 | .info = snd_pmac_awacs_info_tone_amp, |
493 | .get = snd_pmac_awacs_get_tone_amp, |
494 | .put = snd_pmac_awacs_put_tone_amp, |
495 | .private_value = 1, |
496 | }, |
497 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
498 | .name = "Amp Master Playback Volume" , |
499 | .info = snd_pmac_awacs_info_master_amp, |
500 | .get = snd_pmac_awacs_get_master_amp, |
501 | .put = snd_pmac_awacs_put_master_amp, |
502 | }, |
503 | }; |
504 | |
505 | static const struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw = { |
506 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
507 | .name = "Headphone Playback Switch" , |
508 | .info = snd_pmac_boolean_stereo_info, |
509 | .get = snd_pmac_awacs_get_switch_amp, |
510 | .put = snd_pmac_awacs_put_switch_amp, |
511 | .private_value = AMP_CH_HD, |
512 | }; |
513 | |
514 | static const struct snd_kcontrol_new snd_pmac_awacs_amp_spk_sw = { |
515 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
516 | .name = "Speaker Playback Switch" , |
517 | .info = snd_pmac_boolean_stereo_info, |
518 | .get = snd_pmac_awacs_get_switch_amp, |
519 | .put = snd_pmac_awacs_put_switch_amp, |
520 | .private_value = AMP_CH_SPK, |
521 | }; |
522 | |
523 | #endif /* PMAC_AMP_AVAIL */ |
524 | |
525 | |
526 | /* |
527 | * mic boost for screamer |
528 | */ |
529 | static int snd_pmac_screamer_mic_boost_info(struct snd_kcontrol *kcontrol, |
530 | struct snd_ctl_elem_info *uinfo) |
531 | { |
532 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
533 | uinfo->count = 1; |
534 | uinfo->value.integer.min = 0; |
535 | uinfo->value.integer.max = 3; |
536 | return 0; |
537 | } |
538 | |
539 | static int snd_pmac_screamer_mic_boost_get(struct snd_kcontrol *kcontrol, |
540 | struct snd_ctl_elem_value *ucontrol) |
541 | { |
542 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); |
543 | int val = 0; |
544 | unsigned long flags; |
545 | |
546 | spin_lock_irqsave(&chip->reg_lock, flags); |
547 | if (chip->awacs_reg[6] & MASK_MIC_BOOST) |
548 | val |= 2; |
549 | if (chip->awacs_reg[0] & MASK_GAINLINE) |
550 | val |= 1; |
551 | spin_unlock_irqrestore(lock: &chip->reg_lock, flags); |
552 | ucontrol->value.integer.value[0] = val; |
553 | return 0; |
554 | } |
555 | |
556 | static int snd_pmac_screamer_mic_boost_put(struct snd_kcontrol *kcontrol, |
557 | struct snd_ctl_elem_value *ucontrol) |
558 | { |
559 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); |
560 | int changed = 0; |
561 | int val0, val6; |
562 | unsigned long flags; |
563 | |
564 | spin_lock_irqsave(&chip->reg_lock, flags); |
565 | val0 = chip->awacs_reg[0] & ~MASK_GAINLINE; |
566 | val6 = chip->awacs_reg[6] & ~MASK_MIC_BOOST; |
567 | if (ucontrol->value.integer.value[0] & 1) |
568 | val0 |= MASK_GAINLINE; |
569 | if (ucontrol->value.integer.value[0] & 2) |
570 | val6 |= MASK_MIC_BOOST; |
571 | if (val0 != chip->awacs_reg[0]) { |
572 | snd_pmac_awacs_write_reg(chip, reg: 0, val: val0); |
573 | changed = 1; |
574 | } |
575 | if (val6 != chip->awacs_reg[6]) { |
576 | snd_pmac_awacs_write_reg(chip, reg: 6, val: val6); |
577 | changed = 1; |
578 | } |
579 | spin_unlock_irqrestore(lock: &chip->reg_lock, flags); |
580 | return changed; |
581 | } |
582 | |
583 | /* |
584 | * lists of mixer elements |
585 | */ |
586 | static const struct snd_kcontrol_new snd_pmac_awacs_mixers[] = { |
587 | AWACS_SWITCH("Master Capture Switch" , 1, SHIFT_LOOPTHRU, 0), |
588 | AWACS_VOLUME("Master Capture Volume" , 0, 4, 0), |
589 | /* AWACS_SWITCH("Unknown Playback Switch", 6, SHIFT_PAROUT0, 0), */ |
590 | }; |
591 | |
592 | static const struct snd_kcontrol_new snd_pmac_screamer_mixers_beige[] = { |
593 | AWACS_VOLUME("Master Playback Volume" , 2, 6, 1), |
594 | AWACS_VOLUME("Play-through Playback Volume" , 5, 6, 1), |
595 | AWACS_SWITCH("Line Capture Switch" , 0, SHIFT_MUX_MIC, 0), |
596 | AWACS_SWITCH("CD Capture Switch" , 0, SHIFT_MUX_LINE, 0), |
597 | }; |
598 | |
599 | static const struct snd_kcontrol_new snd_pmac_screamer_mixers_lo[] = { |
600 | AWACS_VOLUME("Line out Playback Volume" , 2, 6, 1), |
601 | }; |
602 | |
603 | static const struct snd_kcontrol_new snd_pmac_screamer_mixers_imac[] = { |
604 | AWACS_VOLUME("Play-through Playback Volume" , 5, 6, 1), |
605 | AWACS_SWITCH("CD Capture Switch" , 0, SHIFT_MUX_CD, 0), |
606 | }; |
607 | |
608 | static const struct snd_kcontrol_new snd_pmac_screamer_mixers_g4agp[] = { |
609 | AWACS_VOLUME("Line out Playback Volume" , 2, 6, 1), |
610 | AWACS_VOLUME("Master Playback Volume" , 5, 6, 1), |
611 | AWACS_SWITCH("CD Capture Switch" , 0, SHIFT_MUX_CD, 0), |
612 | AWACS_SWITCH("Line Capture Switch" , 0, SHIFT_MUX_MIC, 0), |
613 | }; |
614 | |
615 | static const struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac7500[] = { |
616 | AWACS_VOLUME("Line out Playback Volume" , 2, 6, 1), |
617 | AWACS_SWITCH("CD Capture Switch" , 0, SHIFT_MUX_CD, 0), |
618 | AWACS_SWITCH("Line Capture Switch" , 0, SHIFT_MUX_MIC, 0), |
619 | }; |
620 | |
621 | static const struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac5500[] = { |
622 | AWACS_VOLUME("Headphone Playback Volume" , 2, 6, 1), |
623 | }; |
624 | |
625 | static const struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac[] = { |
626 | AWACS_VOLUME("Master Playback Volume" , 2, 6, 1), |
627 | AWACS_SWITCH("CD Capture Switch" , 0, SHIFT_MUX_CD, 0), |
628 | }; |
629 | |
630 | /* FIXME: is this correct order? |
631 | * screamer (powerbook G3 pismo) seems to have different bits... |
632 | */ |
633 | static const struct snd_kcontrol_new snd_pmac_awacs_mixers2[] = { |
634 | AWACS_SWITCH("Line Capture Switch" , 0, SHIFT_MUX_LINE, 0), |
635 | AWACS_SWITCH("Mic Capture Switch" , 0, SHIFT_MUX_MIC, 0), |
636 | }; |
637 | |
638 | static const struct snd_kcontrol_new snd_pmac_screamer_mixers2[] = { |
639 | AWACS_SWITCH("Line Capture Switch" , 0, SHIFT_MUX_MIC, 0), |
640 | AWACS_SWITCH("Mic Capture Switch" , 0, SHIFT_MUX_LINE, 0), |
641 | }; |
642 | |
643 | static const struct snd_kcontrol_new snd_pmac_awacs_mixers2_pmac5500[] = { |
644 | AWACS_SWITCH("CD Capture Switch" , 0, SHIFT_MUX_CD, 0), |
645 | }; |
646 | |
647 | static const struct snd_kcontrol_new snd_pmac_awacs_master_sw = |
648 | AWACS_SWITCH("Master Playback Switch" , 1, SHIFT_HDMUTE, 1); |
649 | |
650 | static const struct snd_kcontrol_new snd_pmac_awacs_master_sw_imac = |
651 | AWACS_SWITCH("Line out Playback Switch" , 1, SHIFT_HDMUTE, 1); |
652 | |
653 | static const struct snd_kcontrol_new snd_pmac_awacs_master_sw_pmac5500 = |
654 | AWACS_SWITCH("Headphone Playback Switch" , 1, SHIFT_HDMUTE, 1); |
655 | |
656 | static const struct snd_kcontrol_new snd_pmac_awacs_mic_boost[] = { |
657 | AWACS_SWITCH("Mic Boost Capture Switch" , 0, SHIFT_GAINLINE, 0), |
658 | }; |
659 | |
660 | static const struct snd_kcontrol_new snd_pmac_screamer_mic_boost[] = { |
661 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
662 | .name = "Mic Boost Capture Volume" , |
663 | .info = snd_pmac_screamer_mic_boost_info, |
664 | .get = snd_pmac_screamer_mic_boost_get, |
665 | .put = snd_pmac_screamer_mic_boost_put, |
666 | }, |
667 | }; |
668 | |
669 | static const struct snd_kcontrol_new snd_pmac_awacs_mic_boost_pmac7500[] = |
670 | { |
671 | AWACS_SWITCH("Line Boost Capture Switch" , 0, SHIFT_GAINLINE, 0), |
672 | }; |
673 | |
674 | static const struct snd_kcontrol_new snd_pmac_screamer_mic_boost_beige[] = |
675 | { |
676 | AWACS_SWITCH("Line Boost Capture Switch" , 0, SHIFT_GAINLINE, 0), |
677 | AWACS_SWITCH("CD Boost Capture Switch" , 6, SHIFT_MIC_BOOST, 0), |
678 | }; |
679 | |
680 | static const struct snd_kcontrol_new snd_pmac_screamer_mic_boost_imac[] = |
681 | { |
682 | AWACS_SWITCH("Line Boost Capture Switch" , 0, SHIFT_GAINLINE, 0), |
683 | AWACS_SWITCH("Mic Boost Capture Switch" , 6, SHIFT_MIC_BOOST, 0), |
684 | }; |
685 | |
686 | static const struct snd_kcontrol_new snd_pmac_awacs_speaker_vol[] = { |
687 | AWACS_VOLUME("Speaker Playback Volume" , 4, 6, 1), |
688 | }; |
689 | |
690 | static const struct snd_kcontrol_new snd_pmac_awacs_speaker_sw = |
691 | AWACS_SWITCH("Speaker Playback Switch" , 1, SHIFT_SPKMUTE, 1); |
692 | |
693 | static const struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac1 = |
694 | AWACS_SWITCH("Speaker Playback Switch" , 1, SHIFT_PAROUT1, 1); |
695 | |
696 | static const struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac2 = |
697 | AWACS_SWITCH("Speaker Playback Switch" , 1, SHIFT_PAROUT1, 0); |
698 | |
699 | |
700 | /* |
701 | * add new mixer elements to the card |
702 | */ |
703 | static int build_mixers(struct snd_pmac *chip, int nums, |
704 | const struct snd_kcontrol_new *mixers) |
705 | { |
706 | int i, err; |
707 | |
708 | for (i = 0; i < nums; i++) { |
709 | err = snd_ctl_add(card: chip->card, kcontrol: snd_ctl_new1(kcontrolnew: &mixers[i], private_data: chip)); |
710 | if (err < 0) |
711 | return err; |
712 | } |
713 | return 0; |
714 | } |
715 | |
716 | |
717 | /* |
718 | * restore all registers |
719 | */ |
720 | static void awacs_restore_all_regs(struct snd_pmac *chip) |
721 | { |
722 | snd_pmac_awacs_write_noreg(chip, reg: 0, val: chip->awacs_reg[0]); |
723 | snd_pmac_awacs_write_noreg(chip, reg: 1, val: chip->awacs_reg[1]); |
724 | snd_pmac_awacs_write_noreg(chip, reg: 2, val: chip->awacs_reg[2]); |
725 | snd_pmac_awacs_write_noreg(chip, reg: 4, val: chip->awacs_reg[4]); |
726 | if (chip->model == PMAC_SCREAMER) { |
727 | snd_pmac_awacs_write_noreg(chip, reg: 5, val: chip->awacs_reg[5]); |
728 | snd_pmac_awacs_write_noreg(chip, reg: 6, val: chip->awacs_reg[6]); |
729 | snd_pmac_awacs_write_noreg(chip, reg: 7, val: chip->awacs_reg[7]); |
730 | } |
731 | } |
732 | |
733 | #ifdef CONFIG_PM |
734 | static void snd_pmac_awacs_suspend(struct snd_pmac *chip) |
735 | { |
736 | snd_pmac_awacs_write_noreg(chip, reg: 1, val: (chip->awacs_reg[1] |
737 | | MASK_AMUTE | MASK_CMUTE)); |
738 | } |
739 | |
740 | static void snd_pmac_awacs_resume(struct snd_pmac *chip) |
741 | { |
742 | if (of_machine_is_compatible(compat: "PowerBook3,1" ) |
743 | || of_machine_is_compatible(compat: "PowerBook3,2" )) { |
744 | msleep(msecs: 100); |
745 | snd_pmac_awacs_write_reg(chip, reg: 1, |
746 | val: chip->awacs_reg[1] & ~MASK_PAROUT); |
747 | msleep(msecs: 300); |
748 | } |
749 | |
750 | awacs_restore_all_regs(chip); |
751 | if (chip->model == PMAC_SCREAMER) { |
752 | /* reset power bits in reg 6 */ |
753 | mdelay(5); |
754 | snd_pmac_awacs_write_noreg(chip, reg: 6, val: chip->awacs_reg[6]); |
755 | } |
756 | screamer_recalibrate(chip); |
757 | #ifdef PMAC_AMP_AVAIL |
758 | if (chip->mixer_data) { |
759 | struct awacs_amp *amp = chip->mixer_data; |
760 | awacs_amp_set_vol(amp, 0, |
761 | amp->amp_vol[0][0], amp->amp_vol[0][1], 0); |
762 | awacs_amp_set_vol(amp, 1, |
763 | amp->amp_vol[1][0], amp->amp_vol[1][1], 0); |
764 | awacs_amp_set_tone(amp, amp->amp_tone[0], amp->amp_tone[1]); |
765 | awacs_amp_set_master(amp, amp->amp_master); |
766 | } |
767 | #endif |
768 | } |
769 | #endif /* CONFIG_PM */ |
770 | |
771 | #define IS_PM7500 (of_machine_is_compatible("AAPL,7500") \ |
772 | || of_machine_is_compatible("AAPL,8500") \ |
773 | || of_machine_is_compatible("AAPL,9500")) |
774 | #define IS_PM5500 (of_machine_is_compatible("AAPL,e411")) |
775 | #define IS_BEIGE (of_machine_is_compatible("AAPL,Gossamer")) |
776 | #define IS_IMAC1 (of_machine_is_compatible("PowerMac2,1")) |
777 | #define IS_IMAC2 (of_machine_is_compatible("PowerMac2,2") \ |
778 | || of_machine_is_compatible("PowerMac4,1")) |
779 | #define IS_G4AGP (of_machine_is_compatible("PowerMac3,1")) |
780 | #define IS_LOMBARD (of_machine_is_compatible("PowerBook1,1")) |
781 | |
782 | static int imac1, imac2; |
783 | |
784 | #ifdef PMAC_SUPPORT_AUTOMUTE |
785 | /* |
786 | * auto-mute stuffs |
787 | */ |
788 | static int snd_pmac_awacs_detect_headphone(struct snd_pmac *chip) |
789 | { |
790 | return (in_le32(&chip->awacs->codec_stat) & chip->hp_stat_mask) ? 1 : 0; |
791 | } |
792 | |
793 | #ifdef PMAC_AMP_AVAIL |
794 | static int toggle_amp_mute(struct awacs_amp *amp, int index, int mute) |
795 | { |
796 | int vol[2]; |
797 | vol[0] = amp->amp_vol[index][0] & 31; |
798 | vol[1] = amp->amp_vol[index][1] & 31; |
799 | if (mute) { |
800 | vol[0] |= 32; |
801 | vol[1] |= 32; |
802 | } |
803 | return awacs_amp_set_vol(amp, index, vol[0], vol[1], 1); |
804 | } |
805 | #endif |
806 | |
807 | static void snd_pmac_awacs_update_automute(struct snd_pmac *chip, int do_notify) |
808 | { |
809 | if (chip->auto_mute) { |
810 | #ifdef PMAC_AMP_AVAIL |
811 | if (chip->mixer_data) { |
812 | struct awacs_amp *amp = chip->mixer_data; |
813 | int changed; |
814 | if (snd_pmac_awacs_detect_headphone(chip)) { |
815 | changed = toggle_amp_mute(amp, AMP_CH_HD, 0); |
816 | changed |= toggle_amp_mute(amp, AMP_CH_SPK, 1); |
817 | } else { |
818 | changed = toggle_amp_mute(amp, AMP_CH_HD, 1); |
819 | changed |= toggle_amp_mute(amp, AMP_CH_SPK, 0); |
820 | } |
821 | if (do_notify && ! changed) |
822 | return; |
823 | } else |
824 | #endif |
825 | { |
826 | int reg = chip->awacs_reg[1] |
827 | | (MASK_HDMUTE | MASK_SPKMUTE); |
828 | if (imac1) { |
829 | reg &= ~MASK_SPKMUTE; |
830 | reg |= MASK_PAROUT1; |
831 | } else if (imac2) { |
832 | reg &= ~MASK_SPKMUTE; |
833 | reg &= ~MASK_PAROUT1; |
834 | } |
835 | if (snd_pmac_awacs_detect_headphone(chip)) |
836 | reg &= ~MASK_HDMUTE; |
837 | else if (imac1) |
838 | reg &= ~MASK_PAROUT1; |
839 | else if (imac2) |
840 | reg |= MASK_PAROUT1; |
841 | else |
842 | reg &= ~MASK_SPKMUTE; |
843 | if (do_notify && reg == chip->awacs_reg[1]) |
844 | return; |
845 | snd_pmac_awacs_write_reg(chip, reg: 1, val: reg); |
846 | } |
847 | if (do_notify) { |
848 | snd_ctl_notify(card: chip->card, SNDRV_CTL_EVENT_MASK_VALUE, |
849 | id: &chip->master_sw_ctl->id); |
850 | snd_ctl_notify(card: chip->card, SNDRV_CTL_EVENT_MASK_VALUE, |
851 | id: &chip->speaker_sw_ctl->id); |
852 | snd_ctl_notify(card: chip->card, SNDRV_CTL_EVENT_MASK_VALUE, |
853 | id: &chip->hp_detect_ctl->id); |
854 | } |
855 | } |
856 | } |
857 | #endif /* PMAC_SUPPORT_AUTOMUTE */ |
858 | |
859 | |
860 | /* |
861 | * initialize chip |
862 | */ |
863 | int |
864 | snd_pmac_awacs_init(struct snd_pmac *chip) |
865 | { |
866 | int pm7500 = IS_PM7500; |
867 | int pm5500 = IS_PM5500; |
868 | int beige = IS_BEIGE; |
869 | int g4agp = IS_G4AGP; |
870 | int lombard = IS_LOMBARD; |
871 | int imac; |
872 | int err, vol; |
873 | struct snd_kcontrol *vmaster_sw, *vmaster_vol; |
874 | struct snd_kcontrol *master_vol, *speaker_vol; |
875 | |
876 | imac1 = IS_IMAC1; |
877 | imac2 = IS_IMAC2; |
878 | imac = imac1 || imac2; |
879 | /* looks like MASK_GAINLINE triggers something, so we set here |
880 | * as start-up |
881 | */ |
882 | chip->awacs_reg[0] = MASK_MUX_CD | 0xff | MASK_GAINLINE; |
883 | chip->awacs_reg[1] = MASK_CMUTE | MASK_AMUTE; |
884 | /* FIXME: Only machines with external SRS module need MASK_PAROUT */ |
885 | if (chip->has_iic || chip->device_id == 0x5 || |
886 | /* chip->_device_id == 0x8 || */ |
887 | chip->device_id == 0xb) |
888 | chip->awacs_reg[1] |= MASK_PAROUT; |
889 | /* get default volume from nvram */ |
890 | // vol = (~nvram_read_byte(0x1308) & 7) << 1; |
891 | // vol = ((pmac_xpram_read( 8 ) & 7 ) << 1 ); |
892 | vol = 0x0f; /* no, on alsa, muted as default */ |
893 | vol = vol + (vol << 6); |
894 | chip->awacs_reg[2] = vol; |
895 | chip->awacs_reg[4] = vol; |
896 | if (chip->model == PMAC_SCREAMER) { |
897 | /* FIXME: screamer has loopthru vol control */ |
898 | chip->awacs_reg[5] = vol; |
899 | /* FIXME: maybe should be vol << 3 for PCMCIA speaker */ |
900 | chip->awacs_reg[6] = MASK_MIC_BOOST; |
901 | chip->awacs_reg[7] = 0; |
902 | } |
903 | |
904 | awacs_restore_all_regs(chip); |
905 | chip->manufacturer = (in_le32(&chip->awacs->codec_stat) >> 8) & 0xf; |
906 | screamer_recalibrate(chip); |
907 | |
908 | chip->revision = (in_le32(&chip->awacs->codec_stat) >> 12) & 0xf; |
909 | #ifdef PMAC_AMP_AVAIL |
910 | if (chip->revision == 3 && chip->has_iic && CHECK_CUDA_AMP()) { |
911 | struct awacs_amp *amp = kzalloc(sizeof(*amp), GFP_KERNEL); |
912 | if (! amp) |
913 | return -ENOMEM; |
914 | chip->mixer_data = amp; |
915 | chip->mixer_free = awacs_amp_free; |
916 | /* mute and zero vol */ |
917 | awacs_amp_set_vol(amp, 0, 63, 63, 0); |
918 | awacs_amp_set_vol(amp, 1, 63, 63, 0); |
919 | awacs_amp_set_tone(amp, 7, 7); /* 0 dB */ |
920 | awacs_amp_set_master(amp, 79); /* 0 dB */ |
921 | } |
922 | #endif /* PMAC_AMP_AVAIL */ |
923 | |
924 | if (chip->hp_stat_mask == 0) { |
925 | /* set headphone-jack detection bit */ |
926 | switch (chip->model) { |
927 | case PMAC_AWACS: |
928 | chip->hp_stat_mask = pm7500 || pm5500 ? MASK_HDPCONN |
929 | : MASK_LOCONN; |
930 | break; |
931 | case PMAC_SCREAMER: |
932 | switch (chip->device_id) { |
933 | case 0x08: |
934 | case 0x0B: |
935 | chip->hp_stat_mask = imac |
936 | ? MASK_LOCONN_IMAC | |
937 | MASK_HDPLCONN_IMAC | |
938 | MASK_HDPRCONN_IMAC |
939 | : MASK_HDPCONN; |
940 | break; |
941 | case 0x00: |
942 | case 0x05: |
943 | chip->hp_stat_mask = MASK_LOCONN; |
944 | break; |
945 | default: |
946 | chip->hp_stat_mask = MASK_HDPCONN; |
947 | break; |
948 | } |
949 | break; |
950 | default: |
951 | snd_BUG(); |
952 | break; |
953 | } |
954 | } |
955 | |
956 | /* |
957 | * build mixers |
958 | */ |
959 | strcpy(p: chip->card->mixername, q: "PowerMac AWACS" ); |
960 | |
961 | err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mixers), |
962 | mixers: snd_pmac_awacs_mixers); |
963 | if (err < 0) |
964 | return err; |
965 | if (beige || g4agp) |
966 | ; |
967 | else if (chip->model == PMAC_SCREAMER || pm5500) |
968 | err = build_mixers(chip, ARRAY_SIZE(snd_pmac_screamer_mixers2), |
969 | mixers: snd_pmac_screamer_mixers2); |
970 | else if (!pm7500) |
971 | err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mixers2), |
972 | mixers: snd_pmac_awacs_mixers2); |
973 | if (err < 0) |
974 | return err; |
975 | if (pm5500) { |
976 | err = build_mixers(chip, |
977 | ARRAY_SIZE(snd_pmac_awacs_mixers2_pmac5500), |
978 | mixers: snd_pmac_awacs_mixers2_pmac5500); |
979 | if (err < 0) |
980 | return err; |
981 | } |
982 | master_vol = NULL; |
983 | if (pm7500) |
984 | err = build_mixers(chip, |
985 | ARRAY_SIZE(snd_pmac_awacs_mixers_pmac7500), |
986 | mixers: snd_pmac_awacs_mixers_pmac7500); |
987 | else if (pm5500) |
988 | err = snd_ctl_add(card: chip->card, |
989 | kcontrol: (master_vol = snd_ctl_new1(kcontrolnew: snd_pmac_awacs_mixers_pmac5500, |
990 | private_data: chip))); |
991 | else if (beige) |
992 | err = build_mixers(chip, |
993 | ARRAY_SIZE(snd_pmac_screamer_mixers_beige), |
994 | mixers: snd_pmac_screamer_mixers_beige); |
995 | else if (imac || lombard) { |
996 | err = snd_ctl_add(card: chip->card, |
997 | kcontrol: (master_vol = snd_ctl_new1(kcontrolnew: snd_pmac_screamer_mixers_lo, |
998 | private_data: chip))); |
999 | if (err < 0) |
1000 | return err; |
1001 | err = build_mixers(chip, |
1002 | ARRAY_SIZE(snd_pmac_screamer_mixers_imac), |
1003 | mixers: snd_pmac_screamer_mixers_imac); |
1004 | } else if (g4agp) |
1005 | err = build_mixers(chip, |
1006 | ARRAY_SIZE(snd_pmac_screamer_mixers_g4agp), |
1007 | mixers: snd_pmac_screamer_mixers_g4agp); |
1008 | else |
1009 | err = build_mixers(chip, |
1010 | ARRAY_SIZE(snd_pmac_awacs_mixers_pmac), |
1011 | mixers: snd_pmac_awacs_mixers_pmac); |
1012 | if (err < 0) |
1013 | return err; |
1014 | chip->master_sw_ctl = snd_ctl_new1(kcontrolnew: (pm7500 || imac || g4agp || lombard) |
1015 | ? &snd_pmac_awacs_master_sw_imac |
1016 | : pm5500 |
1017 | ? &snd_pmac_awacs_master_sw_pmac5500 |
1018 | : &snd_pmac_awacs_master_sw, private_data: chip); |
1019 | err = snd_ctl_add(card: chip->card, kcontrol: chip->master_sw_ctl); |
1020 | if (err < 0) |
1021 | return err; |
1022 | #ifdef PMAC_AMP_AVAIL |
1023 | if (chip->mixer_data) { |
1024 | /* use amplifier. the signal is connected from route A |
1025 | * to the amp. the amp has its headphone and speaker |
1026 | * volumes and mute switches, so we use them instead of |
1027 | * screamer registers. |
1028 | * in this case, it seems the route C is not used. |
1029 | */ |
1030 | err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_amp_vol), |
1031 | snd_pmac_awacs_amp_vol); |
1032 | if (err < 0) |
1033 | return err; |
1034 | /* overwrite */ |
1035 | chip->master_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_amp_hp_sw, |
1036 | chip); |
1037 | err = snd_ctl_add(chip->card, chip->master_sw_ctl); |
1038 | if (err < 0) |
1039 | return err; |
1040 | chip->speaker_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_amp_spk_sw, |
1041 | chip); |
1042 | err = snd_ctl_add(chip->card, chip->speaker_sw_ctl); |
1043 | if (err < 0) |
1044 | return err; |
1045 | } else |
1046 | #endif /* PMAC_AMP_AVAIL */ |
1047 | { |
1048 | /* route A = headphone, route C = speaker */ |
1049 | err = snd_ctl_add(card: chip->card, |
1050 | kcontrol: (speaker_vol = snd_ctl_new1(kcontrolnew: snd_pmac_awacs_speaker_vol, |
1051 | private_data: chip))); |
1052 | if (err < 0) |
1053 | return err; |
1054 | chip->speaker_sw_ctl = snd_ctl_new1(kcontrolnew: imac1 |
1055 | ? &snd_pmac_awacs_speaker_sw_imac1 |
1056 | : imac2 |
1057 | ? &snd_pmac_awacs_speaker_sw_imac2 |
1058 | : &snd_pmac_awacs_speaker_sw, private_data: chip); |
1059 | err = snd_ctl_add(card: chip->card, kcontrol: chip->speaker_sw_ctl); |
1060 | if (err < 0) |
1061 | return err; |
1062 | } |
1063 | |
1064 | if (pm5500 || imac || lombard) { |
1065 | vmaster_sw = snd_ctl_make_virtual_master( |
1066 | name: "Master Playback Switch" , tlv: (unsigned int *) NULL); |
1067 | err = snd_ctl_add_follower_uncached(master: vmaster_sw, |
1068 | follower: chip->master_sw_ctl); |
1069 | if (err < 0) |
1070 | return err; |
1071 | err = snd_ctl_add_follower_uncached(master: vmaster_sw, |
1072 | follower: chip->speaker_sw_ctl); |
1073 | if (err < 0) |
1074 | return err; |
1075 | err = snd_ctl_add(card: chip->card, kcontrol: vmaster_sw); |
1076 | if (err < 0) |
1077 | return err; |
1078 | vmaster_vol = snd_ctl_make_virtual_master( |
1079 | name: "Master Playback Volume" , tlv: (unsigned int *) NULL); |
1080 | err = snd_ctl_add_follower(master: vmaster_vol, follower: master_vol); |
1081 | if (err < 0) |
1082 | return err; |
1083 | err = snd_ctl_add_follower(master: vmaster_vol, follower: speaker_vol); |
1084 | if (err < 0) |
1085 | return err; |
1086 | err = snd_ctl_add(card: chip->card, kcontrol: vmaster_vol); |
1087 | if (err < 0) |
1088 | return err; |
1089 | } |
1090 | |
1091 | if (beige || g4agp) |
1092 | err = build_mixers(chip, |
1093 | ARRAY_SIZE(snd_pmac_screamer_mic_boost_beige), |
1094 | mixers: snd_pmac_screamer_mic_boost_beige); |
1095 | else if (imac) |
1096 | err = build_mixers(chip, |
1097 | ARRAY_SIZE(snd_pmac_screamer_mic_boost_imac), |
1098 | mixers: snd_pmac_screamer_mic_boost_imac); |
1099 | else if (chip->model == PMAC_SCREAMER) |
1100 | err = build_mixers(chip, |
1101 | ARRAY_SIZE(snd_pmac_screamer_mic_boost), |
1102 | mixers: snd_pmac_screamer_mic_boost); |
1103 | else if (pm7500) |
1104 | err = build_mixers(chip, |
1105 | ARRAY_SIZE(snd_pmac_awacs_mic_boost_pmac7500), |
1106 | mixers: snd_pmac_awacs_mic_boost_pmac7500); |
1107 | else |
1108 | err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mic_boost), |
1109 | mixers: snd_pmac_awacs_mic_boost); |
1110 | if (err < 0) |
1111 | return err; |
1112 | |
1113 | /* |
1114 | * set lowlevel callbacks |
1115 | */ |
1116 | chip->set_format = snd_pmac_awacs_set_format; |
1117 | #ifdef CONFIG_PM |
1118 | chip->suspend = snd_pmac_awacs_suspend; |
1119 | chip->resume = snd_pmac_awacs_resume; |
1120 | #endif |
1121 | #ifdef PMAC_SUPPORT_AUTOMUTE |
1122 | err = snd_pmac_add_automute(chip); |
1123 | if (err < 0) |
1124 | return err; |
1125 | chip->detect_headphone = snd_pmac_awacs_detect_headphone; |
1126 | chip->update_automute = snd_pmac_awacs_update_automute; |
1127 | snd_pmac_awacs_update_automute(chip, do_notify: 0); /* update the status only */ |
1128 | #endif |
1129 | if (chip->model == PMAC_SCREAMER) { |
1130 | snd_pmac_awacs_write_noreg(chip, reg: 6, val: chip->awacs_reg[6]); |
1131 | snd_pmac_awacs_write_noreg(chip, reg: 0, val: chip->awacs_reg[0]); |
1132 | } |
1133 | |
1134 | return 0; |
1135 | } |
1136 | |