aboutsummaryrefslogtreecommitdiffstats
path: root/sound/ppc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /sound/ppc
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'sound/ppc')
-rw-r--r--sound/ppc/Kconfig23
-rw-r--r--sound/ppc/Makefile9
-rw-r--r--sound/ppc/awacs.c903
-rw-r--r--sound/ppc/awacs.h192
-rw-r--r--sound/ppc/beep.c262
-rw-r--r--sound/ppc/burgundy.c439
-rw-r--r--sound/ppc/burgundy.h95
-rw-r--r--sound/ppc/daca.c283
-rw-r--r--sound/ppc/keywest.c143
-rw-r--r--sound/ppc/pmac.c1328
-rw-r--r--sound/ppc/pmac.h214
-rw-r--r--sound/ppc/powermac.c159
-rw-r--r--sound/ppc/tumbler.c1175
-rw-r--r--sound/ppc/tumbler_volume.h250
14 files changed, 5475 insertions, 0 deletions
diff --git a/sound/ppc/Kconfig b/sound/ppc/Kconfig
new file mode 100644
index 000000000000..b0a9ebf8bf3b
--- /dev/null
+++ b/sound/ppc/Kconfig
@@ -0,0 +1,23 @@
1# ALSA PowerMac drivers
2
3menu "ALSA PowerMac devices"
4 depends on SND!=n && PPC
5
6comment "ALSA PowerMac requires I2C"
7 depends on SND && I2C=n
8
9comment "ALSA PowerMac requires INPUT"
10 depends on SND && INPUT=n
11
12config SND_POWERMAC
13 tristate "PowerMac (AWACS, DACA, Burgundy, Tumbler, Keywest)"
14 depends on SND && I2C && INPUT
15 select SND_PCM
16 help
17 Say Y here to include support for the integrated sound device.
18
19 To compile this driver as a module, choose M here: the module
20 will be called snd-powermac.
21
22endmenu
23
diff --git a/sound/ppc/Makefile b/sound/ppc/Makefile
new file mode 100644
index 000000000000..4d95c652c8ca
--- /dev/null
+++ b/sound/ppc/Makefile
@@ -0,0 +1,9 @@
1#
2# Makefile for ALSA
3# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
4#
5
6snd-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o keywest.o beep.o
7
8# Toplevel Module Dependency
9obj-$(CONFIG_SND_POWERMAC) += snd-powermac.o
diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c
new file mode 100644
index 000000000000..e052bd071e5b
--- /dev/null
+++ b/sound/ppc/awacs.c
@@ -0,0 +1,903 @@
1/*
2 * PMac AWACS lowlevel functions
3 *
4 * Copyright (c) by Takashi Iwai <tiwai@suse.de>
5 * code based on dmasound.c.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22
23#include <sound/driver.h>
24#include <asm/io.h>
25#include <asm/nvram.h>
26#include <linux/init.h>
27#include <linux/delay.h>
28#include <linux/slab.h>
29#include <sound/core.h>
30#include "pmac.h"
31
32
33#ifdef CONFIG_ADB_CUDA
34#define PMAC_AMP_AVAIL
35#endif
36
37#ifdef PMAC_AMP_AVAIL
38typedef struct awacs_amp {
39 unsigned char amp_master;
40 unsigned char amp_vol[2][2];
41 unsigned char amp_tone[2];
42} awacs_amp_t;
43
44#define CHECK_CUDA_AMP() (sys_ctrler == SYS_CTRLER_CUDA)
45
46#endif /* PMAC_AMP_AVAIL */
47
48
49static void snd_pmac_screamer_wait(pmac_t *chip)
50{
51 long timeout = 2000;
52 while (!(in_le32(&chip->awacs->codec_stat) & MASK_VALID)) {
53 mdelay(1);
54 if (! --timeout) {
55 snd_printd("snd_pmac_screamer_wait timeout\n");
56 break;
57 }
58 }
59}
60
61/*
62 * write AWACS register
63 */
64static void
65snd_pmac_awacs_write(pmac_t *chip, int val)
66{
67 long timeout = 5000000;
68
69 if (chip->model == PMAC_SCREAMER)
70 snd_pmac_screamer_wait(chip);
71 out_le32(&chip->awacs->codec_ctrl, val | (chip->subframe << 22));
72 while (in_le32(&chip->awacs->codec_ctrl) & MASK_NEWECMD) {
73 if (! --timeout) {
74 snd_printd("snd_pmac_awacs_write timeout\n");
75 break;
76 }
77 }
78}
79
80static void
81snd_pmac_awacs_write_reg(pmac_t *chip, int reg, int val)
82{
83 snd_pmac_awacs_write(chip, val | (reg << 12));
84 chip->awacs_reg[reg] = val;
85}
86
87static void
88snd_pmac_awacs_write_noreg(pmac_t *chip, int reg, int val)
89{
90 snd_pmac_awacs_write(chip, val | (reg << 12));
91}
92
93#ifdef CONFIG_PMAC_PBOOK
94/* Recalibrate chip */
95static void screamer_recalibrate(pmac_t *chip)
96{
97 if (chip->model != PMAC_SCREAMER)
98 return;
99
100 /* Sorry for the horrible delays... I hope to get that improved
101 * by making the whole PM process asynchronous in a future version
102 */
103 snd_pmac_awacs_write_noreg(chip, 1, chip->awacs_reg[1]);
104 if (chip->manufacturer == 0x1)
105 /* delay for broken crystal part */
106 big_mdelay(750);
107 snd_pmac_awacs_write_noreg(chip, 1,
108 chip->awacs_reg[1] | MASK_RECALIBRATE | MASK_CMUTE | MASK_AMUTE);
109 snd_pmac_awacs_write_noreg(chip, 1, chip->awacs_reg[1]);
110 snd_pmac_awacs_write_noreg(chip, 6, chip->awacs_reg[6]);
111}
112
113#else
114#define screamer_recalibrate(chip) /* NOP */
115#endif
116
117
118/*
119 * additional callback to set the pcm format
120 */
121static void snd_pmac_awacs_set_format(pmac_t *chip)
122{
123 chip->awacs_reg[1] &= ~MASK_SAMPLERATE;
124 chip->awacs_reg[1] |= chip->rate_index << 3;
125 snd_pmac_awacs_write_reg(chip, 1, chip->awacs_reg[1]);
126}
127
128
129/*
130 * AWACS volume callbacks
131 */
132/*
133 * volumes: 0-15 stereo
134 */
135static int snd_pmac_awacs_info_volume(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
136{
137 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
138 uinfo->count = 2;
139 uinfo->value.integer.min = 0;
140 uinfo->value.integer.max = 15;
141 return 0;
142}
143
144static int snd_pmac_awacs_get_volume(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
145{
146 pmac_t *chip = snd_kcontrol_chip(kcontrol);
147 int reg = kcontrol->private_value & 0xff;
148 int lshift = (kcontrol->private_value >> 8) & 0xff;
149 int inverted = (kcontrol->private_value >> 16) & 1;
150 unsigned long flags;
151 int vol[2];
152
153 spin_lock_irqsave(&chip->reg_lock, flags);
154 vol[0] = (chip->awacs_reg[reg] >> lshift) & 0xf;
155 vol[1] = chip->awacs_reg[reg] & 0xf;
156 spin_unlock_irqrestore(&chip->reg_lock, flags);
157 if (inverted) {
158 vol[0] = 0x0f - vol[0];
159 vol[1] = 0x0f - vol[1];
160 }
161 ucontrol->value.integer.value[0] = vol[0];
162 ucontrol->value.integer.value[1] = vol[1];
163 return 0;
164}
165
166static int snd_pmac_awacs_put_volume(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
167{
168 pmac_t *chip = snd_kcontrol_chip(kcontrol);
169 int reg = kcontrol->private_value & 0xff;
170 int lshift = (kcontrol->private_value >> 8) & 0xff;
171 int inverted = (kcontrol->private_value >> 16) & 1;
172 int val, oldval;
173 unsigned long flags;
174 int vol[2];
175
176 vol[0] = ucontrol->value.integer.value[0];
177 vol[1] = ucontrol->value.integer.value[1];
178 if (inverted) {
179 vol[0] = 0x0f - vol[0];
180 vol[1] = 0x0f - vol[1];
181 }
182 vol[0] &= 0x0f;
183 vol[1] &= 0x0f;
184 spin_lock_irqsave(&chip->reg_lock, flags);
185 oldval = chip->awacs_reg[reg];
186 val = oldval & ~(0xf | (0xf << lshift));
187 val |= vol[0] << lshift;
188 val |= vol[1];
189 if (oldval != val)
190 snd_pmac_awacs_write_reg(chip, reg, val);
191 spin_unlock_irqrestore(&chip->reg_lock, flags);
192 return oldval != reg;
193}
194
195
196#define AWACS_VOLUME(xname, xreg, xshift, xinverted) \
197{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
198 .info = snd_pmac_awacs_info_volume, \
199 .get = snd_pmac_awacs_get_volume, \
200 .put = snd_pmac_awacs_put_volume, \
201 .private_value = (xreg) | ((xshift) << 8) | ((xinverted) << 16) }
202
203/*
204 * mute master/ogain for AWACS: mono
205 */
206static int snd_pmac_awacs_get_switch(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
207{
208 pmac_t *chip = snd_kcontrol_chip(kcontrol);
209 int reg = kcontrol->private_value & 0xff;
210 int shift = (kcontrol->private_value >> 8) & 0xff;
211 int invert = (kcontrol->private_value >> 16) & 1;
212 int val;
213 unsigned long flags;
214
215 spin_lock_irqsave(&chip->reg_lock, flags);
216 val = (chip->awacs_reg[reg] >> shift) & 1;
217 spin_unlock_irqrestore(&chip->reg_lock, flags);
218 if (invert)
219 val = 1 - val;
220 ucontrol->value.integer.value[0] = val;
221 return 0;
222}
223
224static int snd_pmac_awacs_put_switch(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
225{
226 pmac_t *chip = snd_kcontrol_chip(kcontrol);
227 int reg = kcontrol->private_value & 0xff;
228 int shift = (kcontrol->private_value >> 8) & 0xff;
229 int invert = (kcontrol->private_value >> 16) & 1;
230 int mask = 1 << shift;
231 int val, changed;
232 unsigned long flags;
233
234 spin_lock_irqsave(&chip->reg_lock, flags);
235 val = chip->awacs_reg[reg] & ~mask;
236 if (ucontrol->value.integer.value[0] != invert)
237 val |= mask;
238 changed = chip->awacs_reg[reg] != val;
239 if (changed)
240 snd_pmac_awacs_write_reg(chip, reg, val);
241 spin_unlock_irqrestore(&chip->reg_lock, flags);
242 return changed;
243}
244
245#define AWACS_SWITCH(xname, xreg, xshift, xinvert) \
246{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
247 .info = snd_pmac_boolean_mono_info, \
248 .get = snd_pmac_awacs_get_switch, \
249 .put = snd_pmac_awacs_put_switch, \
250 .private_value = (xreg) | ((xshift) << 8) | ((xinvert) << 16) }
251
252
253#ifdef PMAC_AMP_AVAIL
254/*
255 * controls for perch/whisper extension cards, e.g. G3 desktop
256 *
257 * TDA7433 connected via i2c address 0x45 (= 0x8a),
258 * accessed through cuda
259 */
260static void awacs_set_cuda(int reg, int val)
261{
262 struct adb_request req;
263 cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 0x8a, reg, val);
264 while (! req.complete)
265 cuda_poll();
266}
267
268/*
269 * level = 0 - 14, 7 = 0 dB
270 */
271static void awacs_amp_set_tone(awacs_amp_t *amp, int bass, int treble)
272{
273 amp->amp_tone[0] = bass;
274 amp->amp_tone[1] = treble;
275 if (bass > 7)
276 bass = (14 - bass) + 8;
277 if (treble > 7)
278 treble = (14 - treble) + 8;
279 awacs_set_cuda(2, (bass << 4) | treble);
280}
281
282/*
283 * vol = 0 - 31 (attenuation), 32 = mute bit, stereo
284 */
285static int awacs_amp_set_vol(awacs_amp_t *amp, int index, int lvol, int rvol, int do_check)
286{
287 if (do_check && amp->amp_vol[index][0] == lvol &&
288 amp->amp_vol[index][1] == rvol)
289 return 0;
290 awacs_set_cuda(3 + index, lvol);
291 awacs_set_cuda(5 + index, rvol);
292 amp->amp_vol[index][0] = lvol;
293 amp->amp_vol[index][1] = rvol;
294 return 1;
295}
296
297/*
298 * 0 = -79 dB, 79 = 0 dB, 99 = +20 dB
299 */
300static void awacs_amp_set_master(awacs_amp_t *amp, int vol)
301{
302 amp->amp_master = vol;
303 if (vol <= 79)
304 vol = 32 + (79 - vol);
305 else
306 vol = 32 - (vol - 79);
307 awacs_set_cuda(1, vol);
308}
309
310static void awacs_amp_free(pmac_t *chip)
311{
312 awacs_amp_t *amp = chip->mixer_data;
313 snd_assert(amp, return);
314 kfree(amp);
315 chip->mixer_data = NULL;
316 chip->mixer_free = NULL;
317}
318
319
320/*
321 * mixer controls
322 */
323static int snd_pmac_awacs_info_volume_amp(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
324{
325 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
326 uinfo->count = 2;
327 uinfo->value.integer.min = 0;
328 uinfo->value.integer.max = 31;
329 return 0;
330}
331
332static int snd_pmac_awacs_get_volume_amp(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
333{
334 pmac_t *chip = snd_kcontrol_chip(kcontrol);
335 int index = kcontrol->private_value;
336 awacs_amp_t *amp = chip->mixer_data;
337 snd_assert(amp, return -EINVAL);
338 snd_assert(index >= 0 && index <= 1, return -EINVAL);
339 ucontrol->value.integer.value[0] = 31 - (amp->amp_vol[index][0] & 31);
340 ucontrol->value.integer.value[1] = 31 - (amp->amp_vol[index][1] & 31);
341 return 0;
342}
343
344static int snd_pmac_awacs_put_volume_amp(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
345{
346 pmac_t *chip = snd_kcontrol_chip(kcontrol);
347 int index = kcontrol->private_value;
348 int vol[2];
349 awacs_amp_t *amp = chip->mixer_data;
350 snd_assert(amp, return -EINVAL);
351 snd_assert(index >= 0 && index <= 1, return -EINVAL);
352
353 vol[0] = (31 - (ucontrol->value.integer.value[0] & 31)) | (amp->amp_vol[index][0] & 32);
354 vol[1] = (31 - (ucontrol->value.integer.value[1] & 31)) | (amp->amp_vol[index][1] & 32);
355 return awacs_amp_set_vol(amp, index, vol[0], vol[1], 1);
356}
357
358static int snd_pmac_awacs_get_switch_amp(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
359{
360 pmac_t *chip = snd_kcontrol_chip(kcontrol);
361 int index = kcontrol->private_value;
362 awacs_amp_t *amp = chip->mixer_data;
363 snd_assert(amp, return -EINVAL);
364 snd_assert(index >= 0 && index <= 1, return -EINVAL);
365 ucontrol->value.integer.value[0] = (amp->amp_vol[index][0] & 32) ? 0 : 1;
366 ucontrol->value.integer.value[1] = (amp->amp_vol[index][1] & 32) ? 0 : 1;
367 return 0;
368}
369
370static int snd_pmac_awacs_put_switch_amp(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
371{
372 pmac_t *chip = snd_kcontrol_chip(kcontrol);
373 int index = kcontrol->private_value;
374 int vol[2];
375 awacs_amp_t *amp = chip->mixer_data;
376 snd_assert(amp, return -EINVAL);
377 snd_assert(index >= 0 && index <= 1, return -EINVAL);
378
379 vol[0] = (ucontrol->value.integer.value[0] ? 0 : 32) | (amp->amp_vol[index][0] & 31);
380 vol[1] = (ucontrol->value.integer.value[1] ? 0 : 32) | (amp->amp_vol[index][1] & 31);
381 return awacs_amp_set_vol(amp, index, vol[0], vol[1], 1);
382}
383
384static int snd_pmac_awacs_info_tone_amp(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
385{
386 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
387 uinfo->count = 1;
388 uinfo->value.integer.min = 0;
389 uinfo->value.integer.max = 14;
390 return 0;
391}
392
393static int snd_pmac_awacs_get_tone_amp(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
394{
395 pmac_t *chip = snd_kcontrol_chip(kcontrol);
396 int index = kcontrol->private_value;
397 awacs_amp_t *amp = chip->mixer_data;
398 snd_assert(amp, return -EINVAL);
399 snd_assert(index >= 0 && index <= 1, return -EINVAL);
400 ucontrol->value.integer.value[0] = amp->amp_tone[index];
401 return 0;
402}
403
404static int snd_pmac_awacs_put_tone_amp(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
405{
406 pmac_t *chip = snd_kcontrol_chip(kcontrol);
407 int index = kcontrol->private_value;
408 awacs_amp_t *amp = chip->mixer_data;
409 snd_assert(amp, return -EINVAL);
410 snd_assert(index >= 0 && index <= 1, return -EINVAL);
411 if (ucontrol->value.integer.value[0] != amp->amp_tone[index]) {
412 amp->amp_tone[index] = ucontrol->value.integer.value[0];
413 awacs_amp_set_tone(amp, amp->amp_tone[0], amp->amp_tone[1]);
414 return 1;
415 }
416 return 0;
417}
418
419static int snd_pmac_awacs_info_master_amp(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
420{
421 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
422 uinfo->count = 1;
423 uinfo->value.integer.min = 0;
424 uinfo->value.integer.max = 99;
425 return 0;
426}
427
428static int snd_pmac_awacs_get_master_amp(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
429{
430 pmac_t *chip = snd_kcontrol_chip(kcontrol);
431 awacs_amp_t *amp = chip->mixer_data;
432 snd_assert(amp, return -EINVAL);
433 ucontrol->value.integer.value[0] = amp->amp_master;
434 return 0;
435}
436
437static int snd_pmac_awacs_put_master_amp(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
438{
439 pmac_t *chip = snd_kcontrol_chip(kcontrol);
440 awacs_amp_t *amp = chip->mixer_data;
441 snd_assert(amp, return -EINVAL);
442 if (ucontrol->value.integer.value[0] != amp->amp_master) {
443 amp->amp_master = ucontrol->value.integer.value[0];
444 awacs_amp_set_master(amp, amp->amp_master);
445 return 1;
446 }
447 return 0;
448}
449
450#define AMP_CH_SPK 0
451#define AMP_CH_HD 1
452
453static snd_kcontrol_new_t snd_pmac_awacs_amp_vol[] __initdata = {
454 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
455 .name = "PC Speaker Playback Volume",
456 .info = snd_pmac_awacs_info_volume_amp,
457 .get = snd_pmac_awacs_get_volume_amp,
458 .put = snd_pmac_awacs_put_volume_amp,
459 .private_value = AMP_CH_SPK,
460 },
461 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
462 .name = "Headphone Playback Volume",
463 .info = snd_pmac_awacs_info_volume_amp,
464 .get = snd_pmac_awacs_get_volume_amp,
465 .put = snd_pmac_awacs_put_volume_amp,
466 .private_value = AMP_CH_HD,
467 },
468 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
469 .name = "Tone Control - Bass",
470 .info = snd_pmac_awacs_info_tone_amp,
471 .get = snd_pmac_awacs_get_tone_amp,
472 .put = snd_pmac_awacs_put_tone_amp,
473 .private_value = 0,
474 },
475 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
476 .name = "Tone Control - Treble",
477 .info = snd_pmac_awacs_info_tone_amp,
478 .get = snd_pmac_awacs_get_tone_amp,
479 .put = snd_pmac_awacs_put_tone_amp,
480 .private_value = 1,
481 },
482 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
483 .name = "Amp Master Playback Volume",
484 .info = snd_pmac_awacs_info_master_amp,
485 .get = snd_pmac_awacs_get_master_amp,
486 .put = snd_pmac_awacs_put_master_amp,
487 },
488};
489
490static snd_kcontrol_new_t snd_pmac_awacs_amp_hp_sw __initdata = {
491 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
492 .name = "Headphone Playback Switch",
493 .info = snd_pmac_boolean_stereo_info,
494 .get = snd_pmac_awacs_get_switch_amp,
495 .put = snd_pmac_awacs_put_switch_amp,
496 .private_value = AMP_CH_HD,
497};
498
499static snd_kcontrol_new_t snd_pmac_awacs_amp_spk_sw __initdata = {
500 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
501 .name = "PC Speaker Playback Switch",
502 .info = snd_pmac_boolean_stereo_info,
503 .get = snd_pmac_awacs_get_switch_amp,
504 .put = snd_pmac_awacs_put_switch_amp,
505 .private_value = AMP_CH_SPK,
506};
507
508#endif /* PMAC_AMP_AVAIL */
509
510
511/*
512 * mic boost for screamer
513 */
514static int snd_pmac_screamer_mic_boost_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
515{
516 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
517 uinfo->count = 1;
518 uinfo->value.integer.min = 0;
519 uinfo->value.integer.max = 2;
520 return 0;
521}
522
523static int snd_pmac_screamer_mic_boost_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
524{
525 pmac_t *chip = snd_kcontrol_chip(kcontrol);
526 int val;
527 unsigned long flags;
528
529 spin_lock_irqsave(&chip->reg_lock, flags);
530 if (chip->awacs_reg[6] & MASK_MIC_BOOST)
531 val = 2;
532 else if (chip->awacs_reg[0] & MASK_GAINLINE)
533 val = 1;
534 else
535 val = 0;
536 spin_unlock_irqrestore(&chip->reg_lock, flags);
537 ucontrol->value.integer.value[0] = val;
538 return 0;
539}
540
541static int snd_pmac_screamer_mic_boost_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
542{
543 pmac_t *chip = snd_kcontrol_chip(kcontrol);
544 int changed = 0;
545 int val0, val6;
546 unsigned long flags;
547
548 spin_lock_irqsave(&chip->reg_lock, flags);
549 val0 = chip->awacs_reg[0] & ~MASK_GAINLINE;
550 val6 = chip->awacs_reg[6] & ~MASK_MIC_BOOST;
551 if (ucontrol->value.integer.value[0] > 0) {
552 val0 |= MASK_GAINLINE;
553 if (ucontrol->value.integer.value[0] > 1)
554 val6 |= MASK_MIC_BOOST;
555 }
556 if (val0 != chip->awacs_reg[0]) {
557 snd_pmac_awacs_write_reg(chip, 0, val0);
558 changed = 1;
559 }
560 if (val6 != chip->awacs_reg[6]) {
561 snd_pmac_awacs_write_reg(chip, 6, val6);
562 changed = 1;
563 }
564 spin_unlock_irqrestore(&chip->reg_lock, flags);
565 return changed;
566}
567
568/*
569 * lists of mixer elements
570 */
571static snd_kcontrol_new_t snd_pmac_awacs_mixers[] __initdata = {
572 AWACS_VOLUME("Master Playback Volume", 2, 6, 1),
573 AWACS_SWITCH("Master Capture Switch", 1, SHIFT_LOOPTHRU, 0),
574 AWACS_VOLUME("Capture Volume", 0, 4, 0),
575 AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
576};
577
578/* FIXME: is this correct order?
579 * screamer (powerbook G3 pismo) seems to have different bits...
580 */
581static snd_kcontrol_new_t snd_pmac_awacs_mixers2[] __initdata = {
582 AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_LINE, 0),
583 AWACS_SWITCH("Mic Capture Switch", 0, SHIFT_MUX_MIC, 0),
584};
585
586static snd_kcontrol_new_t snd_pmac_screamer_mixers2[] __initdata = {
587 AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0),
588 AWACS_SWITCH("Mic Capture Switch", 0, SHIFT_MUX_LINE, 0),
589};
590
591static snd_kcontrol_new_t snd_pmac_awacs_master_sw __initdata =
592AWACS_SWITCH("Master Playback Switch", 1, SHIFT_HDMUTE, 1);
593
594static snd_kcontrol_new_t snd_pmac_awacs_mic_boost[] __initdata = {
595 AWACS_SWITCH("Mic Boost", 0, SHIFT_GAINLINE, 0),
596};
597
598static snd_kcontrol_new_t snd_pmac_screamer_mic_boost[] __initdata = {
599 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
600 .name = "Mic Boost",
601 .info = snd_pmac_screamer_mic_boost_info,
602 .get = snd_pmac_screamer_mic_boost_get,
603 .put = snd_pmac_screamer_mic_boost_put,
604 },
605};
606
607static snd_kcontrol_new_t snd_pmac_awacs_speaker_vol[] __initdata = {
608 AWACS_VOLUME("PC Speaker Playback Volume", 4, 6, 1),
609};
610static snd_kcontrol_new_t snd_pmac_awacs_speaker_sw __initdata =
611AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_SPKMUTE, 1);
612
613
614/*
615 * add new mixer elements to the card
616 */
617static int build_mixers(pmac_t *chip, int nums, snd_kcontrol_new_t *mixers)
618{
619 int i, err;
620
621 for (i = 0; i < nums; i++) {
622 if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&mixers[i], chip))) < 0)
623 return err;
624 }
625 return 0;
626}
627
628
629/*
630 * restore all registers
631 */
632static void awacs_restore_all_regs(pmac_t *chip)
633{
634 snd_pmac_awacs_write_noreg(chip, 0, chip->awacs_reg[0]);
635 snd_pmac_awacs_write_noreg(chip, 1, chip->awacs_reg[1]);
636 snd_pmac_awacs_write_noreg(chip, 2, chip->awacs_reg[2]);
637 snd_pmac_awacs_write_noreg(chip, 4, chip->awacs_reg[4]);
638 if (chip->model == PMAC_SCREAMER) {
639 snd_pmac_awacs_write_noreg(chip, 5, chip->awacs_reg[5]);
640 snd_pmac_awacs_write_noreg(chip, 6, chip->awacs_reg[6]);
641 snd_pmac_awacs_write_noreg(chip, 7, chip->awacs_reg[7]);
642 }
643}
644
645#ifdef CONFIG_PMAC_PBOOK
646static void snd_pmac_awacs_suspend(pmac_t *chip)
647{
648 snd_pmac_awacs_write_noreg(chip, 1, (chip->awacs_reg[1]
649 | MASK_AMUTE | MASK_CMUTE));
650}
651
652static void snd_pmac_awacs_resume(pmac_t *chip)
653{
654 if (machine_is_compatible("PowerBook3,1")
655 || machine_is_compatible("PowerBook3,2")) {
656 big_mdelay(100);
657 snd_pmac_awacs_write_reg(chip, 1,
658 chip->awacs_reg[1] & ~MASK_PAROUT);
659 big_mdelay(300);
660 }
661
662 awacs_restore_all_regs(chip);
663 if (chip->model == PMAC_SCREAMER) {
664 /* reset power bits in reg 6 */
665 mdelay(5);
666 snd_pmac_awacs_write_noreg(chip, 6, chip->awacs_reg[6]);
667 }
668 screamer_recalibrate(chip);
669#ifdef PMAC_AMP_AVAIL
670 if (chip->mixer_data) {
671 awacs_amp_t *amp = chip->mixer_data;
672 awacs_amp_set_vol(amp, 0, amp->amp_vol[0][0], amp->amp_vol[0][1], 0);
673 awacs_amp_set_vol(amp, 1, amp->amp_vol[1][0], amp->amp_vol[1][1], 0);
674 awacs_amp_set_tone(amp, amp->amp_tone[0], amp->amp_tone[1]);
675 awacs_amp_set_master(amp, amp->amp_master);
676 }
677#endif
678}
679#endif /* CONFIG_PMAC_PBOOK */
680
681#ifdef PMAC_SUPPORT_AUTOMUTE
682/*
683 * auto-mute stuffs
684 */
685static int snd_pmac_awacs_detect_headphone(pmac_t *chip)
686{
687 return (in_le32(&chip->awacs->codec_stat) & chip->hp_stat_mask) ? 1 : 0;
688}
689
690#ifdef PMAC_AMP_AVAIL
691static int toggle_amp_mute(awacs_amp_t *amp, int index, int mute)
692{
693 int vol[2];
694 vol[0] = amp->amp_vol[index][0] & 31;
695 vol[1] = amp->amp_vol[index][1] & 31;
696 if (mute) {
697 vol[0] |= 32;
698 vol[1] |= 32;
699 }
700 return awacs_amp_set_vol(amp, index, vol[0], vol[1], 1);
701}
702#endif
703
704static void snd_pmac_awacs_update_automute(pmac_t *chip, int do_notify)
705{
706 if (chip->auto_mute) {
707#ifdef PMAC_AMP_AVAIL
708 if (chip->mixer_data) {
709 awacs_amp_t *amp = chip->mixer_data;
710 int changed;
711 if (snd_pmac_awacs_detect_headphone(chip)) {
712 changed = toggle_amp_mute(amp, AMP_CH_HD, 0);
713 changed |= toggle_amp_mute(amp, AMP_CH_SPK, 1);
714 } else {
715 changed = toggle_amp_mute(amp, AMP_CH_HD, 1);
716 changed |= toggle_amp_mute(amp, AMP_CH_SPK, 0);
717 }
718 if (do_notify && ! changed)
719 return;
720 } else
721#endif
722 {
723 int reg = chip->awacs_reg[1] | (MASK_HDMUTE|MASK_SPKMUTE);
724 if (snd_pmac_awacs_detect_headphone(chip))
725 reg &= ~MASK_HDMUTE;
726 else
727 reg &= ~MASK_SPKMUTE;
728 if (do_notify && reg == chip->awacs_reg[1])
729 return;
730 snd_pmac_awacs_write_reg(chip, 1, reg);
731 }
732 if (do_notify) {
733 snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
734 &chip->master_sw_ctl->id);
735 snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
736 &chip->speaker_sw_ctl->id);
737 snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
738 &chip->hp_detect_ctl->id);
739 }
740 }
741}
742#endif /* PMAC_SUPPORT_AUTOMUTE */
743
744
745/*
746 * initialize chip
747 */
748int __init
749snd_pmac_awacs_init(pmac_t *chip)
750{
751 int err, vol;
752
753 /* looks like MASK_GAINLINE triggers something, so we set here
754 * as start-up
755 */
756 chip->awacs_reg[0] = MASK_MUX_CD | 0xff | MASK_GAINLINE;
757 chip->awacs_reg[1] = MASK_CMUTE | MASK_AMUTE;
758 /* FIXME: Only machines with external SRS module need MASK_PAROUT */
759 if (chip->has_iic || chip->device_id == 0x5 ||
760 /*chip->_device_id == 0x8 || */
761 chip->device_id == 0xb)
762 chip->awacs_reg[1] |= MASK_PAROUT;
763 /* get default volume from nvram */
764 // vol = (~nvram_read_byte(0x1308) & 7) << 1;
765 // vol = ((pmac_xpram_read( 8 ) & 7 ) << 1 );
766 vol = 0x0f; /* no, on alsa, muted as default */
767 vol = vol + (vol << 6);
768 chip->awacs_reg[2] = vol;
769 chip->awacs_reg[4] = vol;
770 if (chip->model == PMAC_SCREAMER) {
771 chip->awacs_reg[5] = vol; /* FIXME: screamer has loopthru vol control */
772 chip->awacs_reg[6] = MASK_MIC_BOOST; /* FIXME: maybe should be vol << 3 for PCMCIA speaker */
773 chip->awacs_reg[7] = 0;
774 }
775
776 awacs_restore_all_regs(chip);
777 chip->manufacturer = (in_le32(&chip->awacs->codec_stat) >> 8) & 0xf;
778 screamer_recalibrate(chip);
779
780 chip->revision = (in_le32(&chip->awacs->codec_stat) >> 12) & 0xf;
781#ifdef PMAC_AMP_AVAIL
782 if (chip->revision == 3 && chip->has_iic && CHECK_CUDA_AMP()) {
783 awacs_amp_t *amp = kmalloc(sizeof(*amp), GFP_KERNEL);
784 if (! amp)
785 return -ENOMEM;
786 chip->mixer_data = amp;
787 memset(amp, 0, sizeof(*amp));
788 chip->mixer_free = awacs_amp_free;
789 awacs_amp_set_vol(amp, 0, 63, 63, 0); /* mute and zero vol */
790 awacs_amp_set_vol(amp, 1, 63, 63, 0);
791 awacs_amp_set_tone(amp, 7, 7); /* 0 dB */
792 awacs_amp_set_master(amp, 79); /* 0 dB */
793 }
794#endif /* PMAC_AMP_AVAIL */
795
796 if (chip->hp_stat_mask == 0) {
797 /* set headphone-jack detection bit */
798 switch (chip->model) {
799 case PMAC_AWACS:
800 chip->hp_stat_mask = 0x04;
801 break;
802 case PMAC_SCREAMER:
803 switch (chip->device_id) {
804 case 0x08:
805 /* 1 = side jack, 2 = front jack */
806 chip->hp_stat_mask = 0x03;
807 break;
808 case 0x00:
809 case 0x05:
810 chip->hp_stat_mask = 0x04;
811 break;
812 default:
813 chip->hp_stat_mask = 0x08;
814 break;
815 }
816 break;
817 default:
818 snd_BUG();
819 break;
820 }
821 }
822
823 /*
824 * build mixers
825 */
826 strcpy(chip->card->mixername, "PowerMac AWACS");
827
828 if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mixers),
829 snd_pmac_awacs_mixers)) < 0)
830 return err;
831 if (chip->model == PMAC_SCREAMER)
832 err = build_mixers(chip, ARRAY_SIZE(snd_pmac_screamer_mixers2),
833 snd_pmac_screamer_mixers2);
834 else
835 err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mixers2),
836 snd_pmac_awacs_mixers2);
837 if (err < 0)
838 return err;
839 chip->master_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_master_sw, chip);
840 if ((err = snd_ctl_add(chip->card, chip->master_sw_ctl)) < 0)
841 return err;
842#ifdef PMAC_AMP_AVAIL
843 if (chip->mixer_data) {
844 /* use amplifier. the signal is connected from route A
845 * to the amp. the amp has its headphone and speaker
846 * volumes and mute switches, so we use them instead of
847 * screamer registers.
848 * in this case, it seems the route C is not used.
849 */
850 if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_amp_vol),
851 snd_pmac_awacs_amp_vol)) < 0)
852 return err;
853 /* overwrite */
854 chip->master_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_amp_hp_sw, chip);
855 if ((err = snd_ctl_add(chip->card, chip->master_sw_ctl)) < 0)
856 return err;
857 chip->speaker_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_amp_spk_sw, chip);
858 if ((err = snd_ctl_add(chip->card, chip->speaker_sw_ctl)) < 0)
859 return err;
860 } else
861#endif /* PMAC_AMP_AVAIL */
862 {
863 /* route A = headphone, route C = speaker */
864 if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_speaker_vol),
865 snd_pmac_awacs_speaker_vol)) < 0)
866 return err;
867 chip->speaker_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_speaker_sw, chip);
868 if ((err = snd_ctl_add(chip->card, chip->speaker_sw_ctl)) < 0)
869 return err;
870 }
871
872 if (chip->model == PMAC_SCREAMER) {
873 if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_screamer_mic_boost),
874 snd_pmac_screamer_mic_boost)) < 0)
875 return err;
876 } else {
877 if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mic_boost),
878 snd_pmac_awacs_mic_boost)) < 0)
879 return err;
880 }
881
882 /*
883 * set lowlevel callbacks
884 */
885 chip->set_format = snd_pmac_awacs_set_format;
886#ifdef CONFIG_PMAC_PBOOK
887 chip->suspend = snd_pmac_awacs_suspend;
888 chip->resume = snd_pmac_awacs_resume;
889#endif
890#ifdef PMAC_SUPPORT_AUTOMUTE
891 if ((err = snd_pmac_add_automute(chip)) < 0)
892 return err;
893 chip->detect_headphone = snd_pmac_awacs_detect_headphone;
894 chip->update_automute = snd_pmac_awacs_update_automute;
895 snd_pmac_awacs_update_automute(chip, 0); /* update the status only */
896#endif
897 if (chip->model == PMAC_SCREAMER) {
898 snd_pmac_awacs_write_noreg(chip, 6, chip->awacs_reg[6]);
899 snd_pmac_awacs_write_noreg(chip, 0, chip->awacs_reg[0]);
900 }
901
902 return 0;
903}
diff --git a/sound/ppc/awacs.h b/sound/ppc/awacs.h
new file mode 100644
index 000000000000..1b2cc44eda57
--- /dev/null
+++ b/sound/ppc/awacs.h
@@ -0,0 +1,192 @@
1/*
2 * Driver for PowerMac AWACS onboard soundchips
3 * Copyright (c) 2001 by Takashi Iwai <tiwai@suse.de>
4 * based on dmasound.c.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21
22#ifndef __AWACS_H
23#define __AWACS_H
24
25/*******************************/
26/* AWACs Audio Register Layout */
27/*******************************/
28
29struct awacs_regs {
30 unsigned control; /* Audio control register */
31 unsigned pad0[3];
32 unsigned codec_ctrl; /* Codec control register */
33 unsigned pad1[3];
34 unsigned codec_stat; /* Codec status register */
35 unsigned pad2[3];
36 unsigned clip_count; /* Clipping count register */
37 unsigned pad3[3];
38 unsigned byteswap; /* Data is little-endian if 1 */
39};
40
41/*******************/
42/* Audio Bit Masks */
43/*******************/
44
45/* Audio Control Reg Bit Masks */
46/* ----- ------- --- --- ----- */
47#define MASK_ISFSEL (0xf) /* Input SubFrame Select */
48#define MASK_OSFSEL (0xf << 4) /* Output SubFrame Select */
49#define MASK_RATE (0x7 << 8) /* Sound Rate */
50#define MASK_CNTLERR (0x1 << 11) /* Error */
51#define MASK_PORTCHG (0x1 << 12) /* Port Change */
52#define MASK_IEE (0x1 << 13) /* Enable Interrupt on Error */
53#define MASK_IEPC (0x1 << 14) /* Enable Interrupt on Port Change */
54#define MASK_SSFSEL (0x3 << 15) /* Status SubFrame Select */
55
56/* Audio Codec Control Reg Bit Masks */
57/* ----- ----- ------- --- --- ----- */
58#define MASK_NEWECMD (0x1 << 24) /* Lock: don't write to reg when 1 */
59#define MASK_EMODESEL (0x3 << 22) /* Send info out on which frame? */
60#define MASK_EXMODEADDR (0x3ff << 12) /* Extended Mode Address -- 10 bits */
61#define MASK_EXMODEDATA (0xfff) /* Extended Mode Data -- 12 bits */
62
63/* Audio Codec Control Address Values / Masks */
64/* ----- ----- ------- ------- ------ - ----- */
65#define MASK_ADDR0 (0x0 << 12) /* Expanded Data Mode Address 0 */
66#define MASK_ADDR_MUX MASK_ADDR0 /* Mux Control */
67#define MASK_ADDR_GAIN MASK_ADDR0
68
69#define MASK_ADDR1 (0x1 << 12) /* Expanded Data Mode Address 1 */
70#define MASK_ADDR_MUTE MASK_ADDR1
71#define MASK_ADDR_RATE MASK_ADDR1
72
73#define MASK_ADDR2 (0x2 << 12) /* Expanded Data Mode Address 2 */
74#define MASK_ADDR_VOLA MASK_ADDR2 /* Volume Control A -- Headphones */
75#define MASK_ADDR_VOLHD MASK_ADDR2
76
77#define MASK_ADDR4 (0x4 << 12) /* Expanded Data Mode Address 4 */
78#define MASK_ADDR_VOLC MASK_ADDR4 /* Volume Control C -- Speaker */
79#define MASK_ADDR_VOLSPK MASK_ADDR4
80
81/* additional registers of screamer */
82#define MASK_ADDR5 (0x5 << 12) /* Expanded Data Mode Address 5 */
83#define MASK_ADDR6 (0x6 << 12) /* Expanded Data Mode Address 6 */
84#define MASK_ADDR7 (0x7 << 12) /* Expanded Data Mode Address 7 */
85
86/* Address 0 Bit Masks & Macros */
87/* ------- - --- ----- - ------ */
88#define MASK_GAINRIGHT (0xf) /* Gain Right Mask */
89#define MASK_GAINLEFT (0xf << 4) /* Gain Left Mask */
90#define MASK_GAINLINE (0x1 << 8) /* Disable Mic preamp */
91#define MASK_GAINMIC (0x0 << 8) /* Enable Mic preamp */
92#define MASK_MUX_CD (0x1 << 9) /* Select CD in MUX */
93#define MASK_MUX_MIC (0x1 << 10) /* Select Mic in MUX */
94#define MASK_MUX_AUDIN (0x1 << 11) /* Select Audio In in MUX */
95#define MASK_MUX_LINE MASK_MUX_AUDIN
96#define SHIFT_GAINLINE 8
97#define SHIFT_MUX_CD 9
98#define SHIFT_MUX_MIC 10
99#define SHIFT_MUX_LINE 11
100
101#define GAINRIGHT(x) ((x) & MASK_GAINRIGHT)
102#define GAINLEFT(x) (((x) << 4) & MASK_GAINLEFT)
103
104/* Address 1 Bit Masks */
105/* ------- - --- ----- */
106#define MASK_ADDR1RES1 (0x3) /* Reserved */
107#define MASK_RECALIBRATE (0x1 << 2) /* Recalibrate */
108#define MASK_SAMPLERATE (0x7 << 3) /* Sample Rate: */
109#define MASK_LOOPTHRU (0x1 << 6) /* Loopthrough Enable */
110#define SHIFT_LOOPTHRU 6
111#define MASK_CMUTE (0x1 << 7) /* Output C (Speaker) Mute when 1 */
112#define MASK_SPKMUTE MASK_CMUTE
113#define SHIFT_SPKMUTE 7
114#define MASK_ADDR1RES2 (0x1 << 8) /* Reserved */
115#define MASK_AMUTE (0x1 << 9) /* Output A (Headphone) Mute when 1 */
116#define MASK_HDMUTE MASK_AMUTE
117#define SHIFT_HDMUTE 9
118#define MASK_PAROUT (0x3 << 10) /* Parallel Out (???) */
119
120#define SAMPLERATE_48000 (0x0 << 3) /* 48 or 44.1 kHz */
121#define SAMPLERATE_32000 (0x1 << 3) /* 32 or 29.4 kHz */
122#define SAMPLERATE_24000 (0x2 << 3) /* 24 or 22.05 kHz */
123#define SAMPLERATE_19200 (0x3 << 3) /* 19.2 or 17.64 kHz */
124#define SAMPLERATE_16000 (0x4 << 3) /* 16 or 14.7 kHz */
125#define SAMPLERATE_12000 (0x5 << 3) /* 12 or 11.025 kHz */
126#define SAMPLERATE_9600 (0x6 << 3) /* 9.6 or 8.82 kHz */
127#define SAMPLERATE_8000 (0x7 << 3) /* 8 or 7.35 kHz */
128
129/* Address 2 & 4 Bit Masks & Macros */
130/* ------- - - - --- ----- - ------ */
131#define MASK_OUTVOLRIGHT (0xf) /* Output Right Volume */
132#define MASK_ADDR2RES1 (0x2 << 4) /* Reserved */
133#define MASK_ADDR4RES1 MASK_ADDR2RES1
134#define MASK_OUTVOLLEFT (0xf << 6) /* Output Left Volume */
135#define MASK_ADDR2RES2 (0x2 << 10) /* Reserved */
136#define MASK_ADDR4RES2 MASK_ADDR2RES2
137
138#define VOLRIGHT(x) (((~(x)) & MASK_OUTVOLRIGHT))
139#define VOLLEFT(x) (((~(x)) << 6) & MASK_OUTVOLLEFT)
140
141/* address 6 */
142#define MASK_MIC_BOOST (0x4) /* screamer mic boost */
143#define SHIFT_MIC_BOOST 2
144
145/* Audio Codec Status Reg Bit Masks */
146/* ----- ----- ------ --- --- ----- */
147#define MASK_EXTEND (0x1 << 23) /* Extend */
148#define MASK_VALID (0x1 << 22) /* Valid Data? */
149#define MASK_OFLEFT (0x1 << 21) /* Overflow Left */
150#define MASK_OFRIGHT (0x1 << 20) /* Overflow Right */
151#define MASK_ERRCODE (0xf << 16) /* Error Code */
152#define MASK_REVISION (0xf << 12) /* Revision Number */
153#define MASK_MFGID (0xf << 8) /* Mfg. ID */
154#define MASK_CODSTATRES (0xf << 4) /* bits 4 - 7 reserved */
155#define MASK_INPPORT (0xf) /* Input Port */
156#define MASK_HDPCONN 8 /* headphone plugged in */
157
158/* Clipping Count Reg Bit Masks */
159/* -------- ----- --- --- ----- */
160#define MASK_CLIPLEFT (0xff << 7) /* Clipping Count, Left Channel */
161#define MASK_CLIPRIGHT (0xff) /* Clipping Count, Right Channel */
162
163/* DBDMA ChannelStatus Bit Masks */
164/* ----- ------------- --- ----- */
165#define MASK_CSERR (0x1 << 7) /* Error */
166#define MASK_EOI (0x1 << 6) /* End of Input -- only for Input Channel */
167#define MASK_CSUNUSED (0x1f << 1) /* bits 1-5 not used */
168#define MASK_WAIT (0x1) /* Wait */
169
170/* Various Rates */
171/* ------- ----- */
172#define RATE_48000 (0x0 << 8) /* 48 kHz */
173#define RATE_44100 (0x0 << 8) /* 44.1 kHz */
174#define RATE_32000 (0x1 << 8) /* 32 kHz */
175#define RATE_29400 (0x1 << 8) /* 29.4 kHz */
176#define RATE_24000 (0x2 << 8) /* 24 kHz */
177#define RATE_22050 (0x2 << 8) /* 22.05 kHz */
178#define RATE_19200 (0x3 << 8) /* 19.2 kHz */
179#define RATE_17640 (0x3 << 8) /* 17.64 kHz */
180#define RATE_16000 (0x4 << 8) /* 16 kHz */
181#define RATE_14700 (0x4 << 8) /* 14.7 kHz */
182#define RATE_12000 (0x5 << 8) /* 12 kHz */
183#define RATE_11025 (0x5 << 8) /* 11.025 kHz */
184#define RATE_9600 (0x6 << 8) /* 9.6 kHz */
185#define RATE_8820 (0x6 << 8) /* 8.82 kHz */
186#define RATE_8000 (0x7 << 8) /* 8 kHz */
187#define RATE_7350 (0x7 << 8) /* 7.35 kHz */
188
189#define RATE_LOW 1 /* HIGH = 48kHz, etc; LOW = 44.1kHz, etc. */
190
191
192#endif /* __AWACS_H */
diff --git a/sound/ppc/beep.c b/sound/ppc/beep.c
new file mode 100644
index 000000000000..c23f601a37f9
--- /dev/null
+++ b/sound/ppc/beep.c
@@ -0,0 +1,262 @@
1/*
2 * Beep using pcm
3 *
4 * Copyright (c) by Takashi Iwai <tiwai@suse.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include <sound/driver.h>
22#include <asm/io.h>
23#include <asm/irq.h>
24#include <linux/init.h>
25#include <linux/slab.h>
26#include <linux/input.h>
27#include <sound/core.h>
28#include <sound/control.h>
29#include "pmac.h"
30
31struct snd_pmac_beep {
32 int running; /* boolean */
33 int volume; /* mixer volume: 0-100 */
34 int volume_play; /* currently playing volume */
35 int hz;
36 int nsamples;
37 short *buf; /* allocated wave buffer */
38 unsigned long addr; /* physical address of buffer */
39 struct input_dev dev;
40};
41
42/*
43 * stop beep if running
44 */
45void snd_pmac_beep_stop(pmac_t *chip)
46{
47 pmac_beep_t *beep = chip->beep;
48 if (beep && beep->running) {
49 beep->running = 0;
50 snd_pmac_beep_dma_stop(chip);
51 }
52}
53
54/*
55 * Stuff for outputting a beep. The values range from -327 to +327
56 * so we can multiply by an amplitude in the range 0..100 to get a
57 * signed short value to put in the output buffer.
58 */
59static short beep_wform[256] = {
60 0, 40, 79, 117, 153, 187, 218, 245,
61 269, 288, 304, 316, 323, 327, 327, 324,
62 318, 310, 299, 288, 275, 262, 249, 236,
63 224, 213, 204, 196, 190, 186, 183, 182,
64 182, 183, 186, 189, 192, 196, 200, 203,
65 206, 208, 209, 209, 209, 207, 204, 201,
66 197, 193, 188, 183, 179, 174, 170, 166,
67 163, 161, 160, 159, 159, 160, 161, 162,
68 164, 166, 168, 169, 171, 171, 171, 170,
69 169, 167, 163, 159, 155, 150, 144, 139,
70 133, 128, 122, 117, 113, 110, 107, 105,
71 103, 103, 103, 103, 104, 104, 105, 105,
72 105, 103, 101, 97, 92, 86, 78, 68,
73 58, 45, 32, 18, 3, -11, -26, -41,
74 -55, -68, -79, -88, -95, -100, -102, -102,
75 -99, -93, -85, -75, -62, -48, -33, -16,
76 0, 16, 33, 48, 62, 75, 85, 93,
77 99, 102, 102, 100, 95, 88, 79, 68,
78 55, 41, 26, 11, -3, -18, -32, -45,
79 -58, -68, -78, -86, -92, -97, -101, -103,
80 -105, -105, -105, -104, -104, -103, -103, -103,
81 -103, -105, -107, -110, -113, -117, -122, -128,
82 -133, -139, -144, -150, -155, -159, -163, -167,
83 -169, -170, -171, -171, -171, -169, -168, -166,
84 -164, -162, -161, -160, -159, -159, -160, -161,
85 -163, -166, -170, -174, -179, -183, -188, -193,
86 -197, -201, -204, -207, -209, -209, -209, -208,
87 -206, -203, -200, -196, -192, -189, -186, -183,
88 -182, -182, -183, -186, -190, -196, -204, -213,
89 -224, -236, -249, -262, -275, -288, -299, -310,
90 -318, -324, -327, -327, -323, -316, -304, -288,
91 -269, -245, -218, -187, -153, -117, -79, -40,
92};
93
94#define BEEP_SRATE 22050 /* 22050 Hz sample rate */
95#define BEEP_BUFLEN 512
96#define BEEP_VOLUME 15 /* 0 - 100 */
97
98static int snd_pmac_beep_event(struct input_dev *dev, unsigned int type, unsigned int code, int hz)
99{
100 pmac_t *chip;
101 pmac_beep_t *beep;
102 unsigned long flags;
103 int beep_speed = 0;
104 int srate;
105 int period, ncycles, nsamples;
106 int i, j, f;
107 short *p;
108
109 if (type != EV_SND)
110 return -1;
111
112 switch (code) {
113 case SND_BELL: if (hz) hz = 1000;
114 case SND_TONE: break;
115 default: return -1;
116 }
117
118 chip = dev->private;
119 if (! chip || (beep = chip->beep) == NULL)
120 return -1;
121
122 if (! hz) {
123 spin_lock_irqsave(&chip->reg_lock, flags);
124 if (beep->running)
125 snd_pmac_beep_stop(chip);
126 spin_unlock_irqrestore(&chip->reg_lock, flags);
127 return 0;
128 }
129
130 beep_speed = snd_pmac_rate_index(chip, &chip->playback, BEEP_SRATE);
131 srate = chip->freq_table[beep_speed];
132
133 if (hz <= srate / BEEP_BUFLEN || hz > srate / 2)
134 hz = 1000;
135
136 spin_lock_irqsave(&chip->reg_lock, flags);
137 if (chip->playback.running || chip->capture.running || beep->running) {
138 spin_unlock_irqrestore(&chip->reg_lock, flags);
139 return 0;
140 }
141 beep->running = 1;
142 spin_unlock_irqrestore(&chip->reg_lock, flags);
143
144 if (hz == beep->hz && beep->volume == beep->volume_play) {
145 nsamples = beep->nsamples;
146 } else {
147 period = srate * 256 / hz; /* fixed point */
148 ncycles = BEEP_BUFLEN * 256 / period;
149 nsamples = (period * ncycles) >> 8;
150 f = ncycles * 65536 / nsamples;
151 j = 0;
152 p = beep->buf;
153 for (i = 0; i < nsamples; ++i, p += 2) {
154 p[0] = p[1] = beep_wform[j >> 8] * beep->volume;
155 j = (j + f) & 0xffff;
156 }
157 beep->hz = hz;
158 beep->volume_play = beep->volume;
159 beep->nsamples = nsamples;
160 }
161
162 spin_lock_irqsave(&chip->reg_lock, flags);
163 snd_pmac_beep_dma_start(chip, beep->nsamples * 4, beep->addr, beep_speed);
164 spin_unlock_irqrestore(&chip->reg_lock, flags);
165 return 0;
166}
167
168/*
169 * beep volume mixer
170 */
171
172#define chip_t pmac_t
173
174static int snd_pmac_info_beep(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
175{
176 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
177 uinfo->count = 1;
178 uinfo->value.integer.min = 0;
179 uinfo->value.integer.max = 100;
180 return 0;
181}
182
183static int snd_pmac_get_beep(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
184{
185 pmac_t *chip = snd_kcontrol_chip(kcontrol);
186 snd_assert(chip->beep, return -ENXIO);
187 ucontrol->value.integer.value[0] = chip->beep->volume;
188 return 0;
189}
190
191static int snd_pmac_put_beep(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
192{
193 pmac_t *chip = snd_kcontrol_chip(kcontrol);
194 int oval;
195 snd_assert(chip->beep, return -ENXIO);
196 oval = chip->beep->volume;
197 chip->beep->volume = ucontrol->value.integer.value[0];
198 return oval != chip->beep->volume;
199}
200
201static snd_kcontrol_new_t snd_pmac_beep_mixer = {
202 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
203 .name = "Beep Playback Volume",
204 .info = snd_pmac_info_beep,
205 .get = snd_pmac_get_beep,
206 .put = snd_pmac_put_beep,
207};
208
209/* Initialize beep stuff */
210int __init snd_pmac_attach_beep(pmac_t *chip)
211{
212 pmac_beep_t *beep;
213 int err;
214
215 beep = kmalloc(sizeof(*beep), GFP_KERNEL);
216 if (! beep)
217 return -ENOMEM;
218
219 memset(beep, 0, sizeof(*beep));
220 beep->buf = (short *) kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL);
221 if (! beep->buf) {
222 kfree(beep);
223 return -ENOMEM;
224 }
225 beep->addr = virt_to_bus(beep->buf);
226
227 beep->dev.evbit[0] = BIT(EV_SND);
228 beep->dev.sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
229 beep->dev.event = snd_pmac_beep_event;
230 beep->dev.private = chip;
231
232 /* FIXME: set more better values */
233 beep->dev.name = "PowerMac Beep";
234 beep->dev.phys = "powermac/beep";
235 beep->dev.id.bustype = BUS_ADB;
236 beep->dev.id.vendor = 0x001f;
237 beep->dev.id.product = 0x0001;
238 beep->dev.id.version = 0x0100;
239
240 beep->volume = BEEP_VOLUME;
241 beep->running = 0;
242 if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_pmac_beep_mixer, chip))) < 0) {
243 kfree(beep->buf);
244 kfree(beep);
245 return err;
246 }
247
248 chip->beep = beep;
249 input_register_device(&beep->dev);
250
251 return 0;
252}
253
254void snd_pmac_detach_beep(pmac_t *chip)
255{
256 if (chip->beep) {
257 input_unregister_device(&chip->beep->dev);
258 kfree(chip->beep->buf);
259 kfree(chip->beep);
260 chip->beep = NULL;
261 }
262}
diff --git a/sound/ppc/burgundy.c b/sound/ppc/burgundy.c
new file mode 100644
index 000000000000..3f837d9f3eb1
--- /dev/null
+++ b/sound/ppc/burgundy.c
@@ -0,0 +1,439 @@
1/*
2 * PMac Burgundy lowlevel functions
3 *
4 * Copyright (c) by Takashi Iwai <tiwai@suse.de>
5 * code based on dmasound.c.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#include <sound/driver.h>
23#include <asm/io.h>
24#include <linux/init.h>
25#include <linux/slab.h>
26#include <linux/delay.h>
27#include <sound/core.h>
28#include "pmac.h"
29#include "burgundy.h"
30
31
32/* Waits for busy flag to clear */
33inline static void
34snd_pmac_burgundy_busy_wait(pmac_t *chip)
35{
36 int timeout = 50;
37 while ((in_le32(&chip->awacs->codec_ctrl) & MASK_NEWECMD) && timeout--)
38 udelay(1);
39 if (! timeout)
40 printk(KERN_DEBUG "burgundy_busy_wait: timeout\n");
41}
42
43inline static void
44snd_pmac_burgundy_extend_wait(pmac_t *chip)
45{
46 int timeout;
47 timeout = 50;
48 while (!(in_le32(&chip->awacs->codec_stat) & MASK_EXTEND) && timeout--)
49 udelay(1);
50 if (! timeout)
51 printk(KERN_DEBUG "burgundy_extend_wait: timeout #1\n");
52 timeout = 50;
53 while ((in_le32(&chip->awacs->codec_stat) & MASK_EXTEND) && timeout--)
54 udelay(1);
55 if (! timeout)
56 printk(KERN_DEBUG "burgundy_extend_wait: timeout #2\n");
57}
58
59static void
60snd_pmac_burgundy_wcw(pmac_t *chip, unsigned addr, unsigned val)
61{
62 out_le32(&chip->awacs->codec_ctrl, addr + 0x200c00 + (val & 0xff));
63 snd_pmac_burgundy_busy_wait(chip);
64 out_le32(&chip->awacs->codec_ctrl, addr + 0x200d00 +((val>>8) & 0xff));
65 snd_pmac_burgundy_busy_wait(chip);
66 out_le32(&chip->awacs->codec_ctrl, addr + 0x200e00 +((val>>16) & 0xff));
67 snd_pmac_burgundy_busy_wait(chip);
68 out_le32(&chip->awacs->codec_ctrl, addr + 0x200f00 +((val>>24) & 0xff));
69 snd_pmac_burgundy_busy_wait(chip);
70}
71
72static unsigned
73snd_pmac_burgundy_rcw(pmac_t *chip, unsigned addr)
74{
75 unsigned val = 0;
76 unsigned long flags;
77
78 spin_lock_irqsave(&chip->reg_lock, flags);
79
80 out_le32(&chip->awacs->codec_ctrl, addr + 0x100000);
81 snd_pmac_burgundy_busy_wait(chip);
82 snd_pmac_burgundy_extend_wait(chip);
83 val += (in_le32(&chip->awacs->codec_stat) >> 4) & 0xff;
84
85 out_le32(&chip->awacs->codec_ctrl, addr + 0x100100);
86 snd_pmac_burgundy_busy_wait(chip);
87 snd_pmac_burgundy_extend_wait(chip);
88 val += ((in_le32(&chip->awacs->codec_stat)>>4) & 0xff) <<8;
89
90 out_le32(&chip->awacs->codec_ctrl, addr + 0x100200);
91 snd_pmac_burgundy_busy_wait(chip);
92 snd_pmac_burgundy_extend_wait(chip);
93 val += ((in_le32(&chip->awacs->codec_stat)>>4) & 0xff) <<16;
94
95 out_le32(&chip->awacs->codec_ctrl, addr + 0x100300);
96 snd_pmac_burgundy_busy_wait(chip);
97 snd_pmac_burgundy_extend_wait(chip);
98 val += ((in_le32(&chip->awacs->codec_stat)>>4) & 0xff) <<24;
99
100 spin_unlock_irqrestore(&chip->reg_lock, flags);
101
102 return val;
103}
104
105static void
106snd_pmac_burgundy_wcb(pmac_t *chip, unsigned int addr, unsigned int val)
107{
108 out_le32(&chip->awacs->codec_ctrl, addr + 0x300000 + (val & 0xff));
109 snd_pmac_burgundy_busy_wait(chip);
110}
111
112static unsigned
113snd_pmac_burgundy_rcb(pmac_t *chip, unsigned int addr)
114{
115 unsigned val = 0;
116 unsigned long flags;
117
118 spin_lock_irqsave(&chip->reg_lock, flags);
119
120 out_le32(&chip->awacs->codec_ctrl, addr + 0x100000);
121 snd_pmac_burgundy_busy_wait(chip);
122 snd_pmac_burgundy_extend_wait(chip);
123 val += (in_le32(&chip->awacs->codec_stat) >> 4) & 0xff;
124
125 spin_unlock_irqrestore(&chip->reg_lock, flags);
126
127 return val;
128}
129
130/*
131 * Burgundy volume: 0 - 100, stereo
132 */
133static void
134snd_pmac_burgundy_write_volume(pmac_t *chip, unsigned int address, long *volume, int shift)
135{
136 int hardvolume, lvolume, rvolume;
137
138 lvolume = volume[0] ? volume[0] + BURGUNDY_VOLUME_OFFSET : 0;
139 rvolume = volume[1] ? volume[1] + BURGUNDY_VOLUME_OFFSET : 0;
140
141 hardvolume = lvolume + (rvolume << shift);
142 if (shift == 8)
143 hardvolume |= hardvolume << 16;
144
145 snd_pmac_burgundy_wcw(chip, address, hardvolume);
146}
147
148static void
149snd_pmac_burgundy_read_volume(pmac_t *chip, unsigned int address, long *volume, int shift)
150{
151 int wvolume;
152
153 wvolume = snd_pmac_burgundy_rcw(chip, address);
154
155 volume[0] = wvolume & 0xff;
156 if (volume[0] >= BURGUNDY_VOLUME_OFFSET)
157 volume[0] -= BURGUNDY_VOLUME_OFFSET;
158 else
159 volume[0] = 0;
160 volume[1] = (wvolume >> shift) & 0xff;
161 if (volume[1] >= BURGUNDY_VOLUME_OFFSET)
162 volume[1] -= BURGUNDY_VOLUME_OFFSET;
163 else
164 volume[1] = 0;
165}
166
167
168/*
169 */
170
171#define BASE2ADDR(base) ((base) << 12)
172#define ADDR2BASE(addr) ((addr) >> 12)
173
174static int snd_pmac_burgundy_info_volume(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
175{
176 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
177 uinfo->count = 2;
178 uinfo->value.integer.min = 0;
179 uinfo->value.integer.max = 100;
180 return 0;
181}
182
183static int snd_pmac_burgundy_get_volume(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
184{
185 pmac_t *chip = snd_kcontrol_chip(kcontrol);
186 unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
187 int shift = (kcontrol->private_value >> 8) & 0xff;
188 snd_pmac_burgundy_read_volume(chip, addr, ucontrol->value.integer.value, shift);
189 return 0;
190}
191
192static int snd_pmac_burgundy_put_volume(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
193{
194 pmac_t *chip = snd_kcontrol_chip(kcontrol);
195 unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
196 int shift = (kcontrol->private_value >> 8) & 0xff;
197 long nvoices[2];
198
199 snd_pmac_burgundy_write_volume(chip, addr, ucontrol->value.integer.value, shift);
200 snd_pmac_burgundy_read_volume(chip, addr, nvoices, shift);
201 return (nvoices[0] != ucontrol->value.integer.value[0] ||
202 nvoices[1] != ucontrol->value.integer.value[1]);
203}
204
205#define BURGUNDY_VOLUME(xname, xindex, addr, shift) \
206{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
207 .info = snd_pmac_burgundy_info_volume,\
208 .get = snd_pmac_burgundy_get_volume,\
209 .put = snd_pmac_burgundy_put_volume,\
210 .private_value = ((ADDR2BASE(addr) & 0xff) | ((shift) << 8)) }
211
212/* lineout/speaker */
213
214static int snd_pmac_burgundy_info_switch_out(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
215{
216 int stereo = (kcontrol->private_value >> 24) & 1;
217 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
218 uinfo->count = stereo + 1;
219 uinfo->value.integer.min = 0;
220 uinfo->value.integer.max = 1;
221 return 0;
222}
223
224static int snd_pmac_burgundy_get_switch_out(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
225{
226 pmac_t *chip = snd_kcontrol_chip(kcontrol);
227 int lmask = kcontrol->private_value & 0xff;
228 int rmask = (kcontrol->private_value >> 8) & 0xff;
229 int stereo = (kcontrol->private_value >> 24) & 1;
230 int val = snd_pmac_burgundy_rcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES);
231 ucontrol->value.integer.value[0] = (val & lmask) ? 1 : 0;
232 if (stereo)
233 ucontrol->value.integer.value[1] = (val & rmask) ? 1 : 0;
234 return 0;
235}
236
237static int snd_pmac_burgundy_put_switch_out(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
238{
239 pmac_t *chip = snd_kcontrol_chip(kcontrol);
240 int lmask = kcontrol->private_value & 0xff;
241 int rmask = (kcontrol->private_value >> 8) & 0xff;
242 int stereo = (kcontrol->private_value >> 24) & 1;
243 int val, oval;
244 oval = snd_pmac_burgundy_rcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES);
245 val = oval & ~(lmask | rmask);
246 if (ucontrol->value.integer.value[0])
247 val |= lmask;
248 if (stereo && ucontrol->value.integer.value[1])
249 val |= rmask;
250 snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, val);
251 return val != oval;
252}
253
254#define BURGUNDY_OUTPUT_SWITCH(xname, xindex, lmask, rmask, stereo) \
255{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
256 .info = snd_pmac_burgundy_info_switch_out,\
257 .get = snd_pmac_burgundy_get_switch_out,\
258 .put = snd_pmac_burgundy_put_switch_out,\
259 .private_value = ((lmask) | ((rmask) << 8) | ((stereo) << 24)) }
260
261/* line/speaker output volume */
262static int snd_pmac_burgundy_info_volume_out(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
263{
264 int stereo = (kcontrol->private_value >> 24) & 1;
265 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
266 uinfo->count = stereo + 1;
267 uinfo->value.integer.min = 0;
268 uinfo->value.integer.max = 15;
269 return 0;
270}
271
272static int snd_pmac_burgundy_get_volume_out(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
273{
274 pmac_t *chip = snd_kcontrol_chip(kcontrol);
275 unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
276 int stereo = (kcontrol->private_value >> 24) & 1;
277 int oval;
278
279 oval = ~snd_pmac_burgundy_rcb(chip, addr) & 0xff;
280 ucontrol->value.integer.value[0] = oval & 0xf;
281 if (stereo)
282 ucontrol->value.integer.value[1] = (oval >> 4) & 0xf;
283 return 0;
284}
285
286static int snd_pmac_burgundy_put_volume_out(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
287{
288 pmac_t *chip = snd_kcontrol_chip(kcontrol);
289 unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
290 int stereo = (kcontrol->private_value >> 24) & 1;
291 int oval, val;
292
293 oval = ~snd_pmac_burgundy_rcb(chip, addr) & 0xff;
294 val = ucontrol->value.integer.value[0];
295 if (stereo)
296 val |= ucontrol->value.integer.value[1] << 4;
297 else
298 val |= ucontrol->value.integer.value[0] << 4;
299 val = ~val & 0xff;
300 snd_pmac_burgundy_wcb(chip, addr, val);
301 return val != oval;
302}
303
304#define BURGUNDY_OUTPUT_VOLUME(xname, xindex, addr, stereo) \
305{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
306 .info = snd_pmac_burgundy_info_volume_out,\
307 .get = snd_pmac_burgundy_get_volume_out,\
308 .put = snd_pmac_burgundy_put_volume_out,\
309 .private_value = (ADDR2BASE(addr) | ((stereo) << 24)) }
310
311static snd_kcontrol_new_t snd_pmac_burgundy_mixers[] __initdata = {
312 BURGUNDY_VOLUME("Master Playback Volume", 0, MASK_ADDR_BURGUNDY_MASTER_VOLUME, 8),
313 BURGUNDY_VOLUME("Line Playback Volume", 0, MASK_ADDR_BURGUNDY_VOLLINE, 16),
314 BURGUNDY_VOLUME("CD Playback Volume", 0, MASK_ADDR_BURGUNDY_VOLCD, 16),
315 BURGUNDY_VOLUME("Mic Playback Volume", 0, MASK_ADDR_BURGUNDY_VOLMIC, 16),
316 BURGUNDY_OUTPUT_VOLUME("PC Speaker Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENHP, 0),
317 /*BURGUNDY_OUTPUT_VOLUME("PCM Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENLINEOUT, 1),*/
318 BURGUNDY_OUTPUT_VOLUME("Headphone Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENSPEAKER, 1),
319};
320static snd_kcontrol_new_t snd_pmac_burgundy_master_sw __initdata =
321BURGUNDY_OUTPUT_SWITCH("Headphone Playback Switch", 0, BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1);
322static snd_kcontrol_new_t snd_pmac_burgundy_speaker_sw __initdata =
323BURGUNDY_OUTPUT_SWITCH("PC Speaker Playback Switch", 0, BURGUNDY_OUTPUT_INTERN, 0, 0);
324
325
326#ifdef PMAC_SUPPORT_AUTOMUTE
327/*
328 * auto-mute stuffs
329 */
330static int snd_pmac_burgundy_detect_headphone(pmac_t *chip)
331{
332 return (in_le32(&chip->awacs->codec_stat) & chip->hp_stat_mask) ? 1 : 0;
333}
334
335static void snd_pmac_burgundy_update_automute(pmac_t *chip, int do_notify)
336{
337 if (chip->auto_mute) {
338 int reg, oreg;
339 reg = oreg = snd_pmac_burgundy_rcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES);
340 reg &= ~(BURGUNDY_OUTPUT_LEFT | BURGUNDY_OUTPUT_RIGHT | BURGUNDY_OUTPUT_INTERN);
341 if (snd_pmac_burgundy_detect_headphone(chip))
342 reg |= BURGUNDY_OUTPUT_LEFT | BURGUNDY_OUTPUT_RIGHT;
343 else
344 reg |= BURGUNDY_OUTPUT_INTERN;
345 if (do_notify && reg == oreg)
346 return;
347 snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, reg);
348 if (do_notify) {
349 snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
350 &chip->master_sw_ctl->id);
351 snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
352 &chip->speaker_sw_ctl->id);
353 snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
354 &chip->hp_detect_ctl->id);
355 }
356 }
357}
358#endif /* PMAC_SUPPORT_AUTOMUTE */
359
360
361/*
362 * initialize burgundy
363 */
364int __init snd_pmac_burgundy_init(pmac_t *chip)
365{
366 int i, err;
367
368 /* Checks to see the chip is alive and kicking */
369 if ((in_le32(&chip->awacs->codec_ctrl) & MASK_ERRCODE) == 0xf0000) {
370 printk(KERN_WARNING "pmac burgundy: disabled by MacOS :-(\n");
371 return 1;
372 }
373
374 snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_OUTPUTENABLES,
375 DEF_BURGUNDY_OUTPUTENABLES);
376 snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
377 DEF_BURGUNDY_MORE_OUTPUTENABLES);
378 snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_OUTPUTSELECTS,
379 DEF_BURGUNDY_OUTPUTSELECTS);
380
381 snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_INPSEL21,
382 DEF_BURGUNDY_INPSEL21);
383 snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_INPSEL3,
384 DEF_BURGUNDY_INPSEL3);
385 snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINCD,
386 DEF_BURGUNDY_GAINCD);
387 snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINLINE,
388 DEF_BURGUNDY_GAINLINE);
389 snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINMIC,
390 DEF_BURGUNDY_GAINMIC);
391 snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINMODEM,
392 DEF_BURGUNDY_GAINMODEM);
393
394 snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_ATTENSPEAKER,
395 DEF_BURGUNDY_ATTENSPEAKER);
396 snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_ATTENLINEOUT,
397 DEF_BURGUNDY_ATTENLINEOUT);
398 snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_ATTENHP,
399 DEF_BURGUNDY_ATTENHP);
400
401 snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_MASTER_VOLUME,
402 DEF_BURGUNDY_MASTER_VOLUME);
403 snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_VOLCD,
404 DEF_BURGUNDY_VOLCD);
405 snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_VOLLINE,
406 DEF_BURGUNDY_VOLLINE);
407 snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_VOLMIC,
408 DEF_BURGUNDY_VOLMIC);
409
410 if (chip->hp_stat_mask == 0)
411 /* set headphone-jack detection bit */
412 chip->hp_stat_mask = 0x04;
413
414 /*
415 * build burgundy mixers
416 */
417 strcpy(chip->card->mixername, "PowerMac Burgundy");
418
419 for (i = 0; i < ARRAY_SIZE(snd_pmac_burgundy_mixers); i++) {
420 if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_pmac_burgundy_mixers[i], chip))) < 0)
421 return err;
422 }
423 chip->master_sw_ctl = snd_ctl_new1(&snd_pmac_burgundy_master_sw, chip);
424 if ((err = snd_ctl_add(chip->card, chip->master_sw_ctl)) < 0)
425 return err;
426 chip->speaker_sw_ctl = snd_ctl_new1(&snd_pmac_burgundy_speaker_sw, chip);
427 if ((err = snd_ctl_add(chip->card, chip->speaker_sw_ctl)) < 0)
428 return err;
429#ifdef PMAC_SUPPORT_AUTOMUTE
430 if ((err = snd_pmac_add_automute(chip)) < 0)
431 return err;
432
433 chip->detect_headphone = snd_pmac_burgundy_detect_headphone;
434 chip->update_automute = snd_pmac_burgundy_update_automute;
435 snd_pmac_burgundy_update_automute(chip, 0); /* update the status only */
436#endif
437
438 return 0;
439}
diff --git a/sound/ppc/burgundy.h b/sound/ppc/burgundy.h
new file mode 100644
index 000000000000..ebb457a8342c
--- /dev/null
+++ b/sound/ppc/burgundy.h
@@ -0,0 +1,95 @@
1/*
2 * Driver for PowerMac Burgundy onboard soundchips
3 * Copyright (c) 2001 by Takashi Iwai <tiwai@suse.de>
4 * based on dmasound.c.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21
22#ifndef __BURGUNDY_H
23#define __BURGUNDY_H
24
25#define MASK_ADDR_BURGUNDY_INPSEL21 (0x11 << 12)
26#define MASK_ADDR_BURGUNDY_INPSEL3 (0x12 << 12)
27
28#define MASK_ADDR_BURGUNDY_GAINCH1 (0x13 << 12)
29#define MASK_ADDR_BURGUNDY_GAINCH2 (0x14 << 12)
30#define MASK_ADDR_BURGUNDY_GAINCH3 (0x15 << 12)
31#define MASK_ADDR_BURGUNDY_GAINCH4 (0x16 << 12)
32
33#define MASK_ADDR_BURGUNDY_VOLCH1 (0x20 << 12)
34#define MASK_ADDR_BURGUNDY_VOLCH2 (0x21 << 12)
35#define MASK_ADDR_BURGUNDY_VOLCH3 (0x22 << 12)
36#define MASK_ADDR_BURGUNDY_VOLCH4 (0x23 << 12)
37
38#define MASK_ADDR_BURGUNDY_OUTPUTSELECTS (0x2B << 12)
39#define MASK_ADDR_BURGUNDY_OUTPUTENABLES (0x2F << 12)
40
41#define MASK_ADDR_BURGUNDY_MASTER_VOLUME (0x30 << 12)
42
43#define MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES (0x60 << 12)
44
45#define MASK_ADDR_BURGUNDY_ATTENSPEAKER (0x62 << 12)
46#define MASK_ADDR_BURGUNDY_ATTENLINEOUT (0x63 << 12)
47#define MASK_ADDR_BURGUNDY_ATTENHP (0x64 << 12)
48
49#define MASK_ADDR_BURGUNDY_VOLCD (MASK_ADDR_BURGUNDY_VOLCH1)
50#define MASK_ADDR_BURGUNDY_VOLLINE (MASK_ADDR_BURGUNDY_VOLCH2)
51#define MASK_ADDR_BURGUNDY_VOLMIC (MASK_ADDR_BURGUNDY_VOLCH3)
52#define MASK_ADDR_BURGUNDY_VOLMODEM (MASK_ADDR_BURGUNDY_VOLCH4)
53
54#define MASK_ADDR_BURGUNDY_GAINCD (MASK_ADDR_BURGUNDY_GAINCH1)
55#define MASK_ADDR_BURGUNDY_GAINLINE (MASK_ADDR_BURGUNDY_GAINCH2)
56#define MASK_ADDR_BURGUNDY_GAINMIC (MASK_ADDR_BURGUNDY_GAINCH3)
57#define MASK_ADDR_BURGUNDY_GAINMODEM (MASK_ADDR_BURGUNDY_VOLCH4)
58
59
60/* These are all default values for the burgundy */
61#define DEF_BURGUNDY_INPSEL21 (0xAA)
62#define DEF_BURGUNDY_INPSEL3 (0x0A)
63
64#define DEF_BURGUNDY_GAINCD (0x33)
65#define DEF_BURGUNDY_GAINLINE (0x44)
66#define DEF_BURGUNDY_GAINMIC (0x44)
67#define DEF_BURGUNDY_GAINMODEM (0x06)
68
69/* Remember: lowest volume here is 0x9b */
70#define DEF_BURGUNDY_VOLCD (0xCCCCCCCC)
71#define DEF_BURGUNDY_VOLLINE (0x00000000)
72#define DEF_BURGUNDY_VOLMIC (0x00000000)
73#define DEF_BURGUNDY_VOLMODEM (0xCCCCCCCC)
74
75#define DEF_BURGUNDY_OUTPUTSELECTS (0x010f010f)
76#define DEF_BURGUNDY_OUTPUTENABLES (0x0A)
77
78/* #define DEF_BURGUNDY_MASTER_VOLUME (0xFFFFFFFF) */ /* too loud */
79#define DEF_BURGUNDY_MASTER_VOLUME (0xDDDDDDDD)
80
81#define DEF_BURGUNDY_MORE_OUTPUTENABLES (0x7E)
82
83#define DEF_BURGUNDY_ATTENSPEAKER (0x44)
84#define DEF_BURGUNDY_ATTENLINEOUT (0xCC)
85#define DEF_BURGUNDY_ATTENHP (0xCC)
86
87/* OUTPUTENABLES bits */
88#define BURGUNDY_OUTPUT_LEFT 0x02
89#define BURGUNDY_OUTPUT_RIGHT 0x04
90#define BURGUNDY_OUTPUT_INTERN 0x80
91
92/* volume offset */
93#define BURGUNDY_VOLUME_OFFSET 155
94
95#endif /* __BURGUNDY_H */
diff --git a/sound/ppc/daca.c b/sound/ppc/daca.c
new file mode 100644
index 000000000000..f24a91693616
--- /dev/null
+++ b/sound/ppc/daca.c
@@ -0,0 +1,283 @@
1/*
2 * PMac DACA lowlevel functions
3 *
4 * Copyright (c) by Takashi Iwai <tiwai@suse.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21
22#include <sound/driver.h>
23#include <linux/init.h>
24#include <linux/i2c.h>
25#include <linux/i2c-dev.h>
26#include <linux/kmod.h>
27#include <linux/slab.h>
28#include <sound/core.h>
29#include "pmac.h"
30
31/* i2c address */
32#define DACA_I2C_ADDR 0x4d
33
34/* registers */
35#define DACA_REG_SR 0x01
36#define DACA_REG_AVOL 0x02
37#define DACA_REG_GCFG 0x03
38
39/* maximum volume value */
40#define DACA_VOL_MAX 0x38
41
42
43typedef struct pmac_daca_t {
44 pmac_keywest_t i2c;
45 int left_vol, right_vol;
46 unsigned int deemphasis : 1;
47 unsigned int amp_on : 1;
48} pmac_daca_t;
49
50
51/*
52 * initialize / detect DACA
53 */
54static int daca_init_client(pmac_keywest_t *i2c)
55{
56 unsigned short wdata = 0x00;
57 /* SR: no swap, 1bit delay, 32-48kHz */
58 /* GCFG: power amp inverted, DAC on */
59 if (i2c_smbus_write_byte_data(i2c->client, DACA_REG_SR, 0x08) < 0 ||
60 i2c_smbus_write_byte_data(i2c->client, DACA_REG_GCFG, 0x05) < 0)
61 return -EINVAL;
62 return i2c_smbus_write_block_data(i2c->client, DACA_REG_AVOL,
63 2, (unsigned char*)&wdata);
64}
65
66/*
67 * update volume
68 */
69static int daca_set_volume(pmac_daca_t *mix)
70{
71 unsigned char data[2];
72
73 if (! mix->i2c.client)
74 return -ENODEV;
75
76 if (mix->left_vol > DACA_VOL_MAX)
77 data[0] = DACA_VOL_MAX;
78 else
79 data[0] = mix->left_vol;
80 if (mix->right_vol > DACA_VOL_MAX)
81 data[1] = DACA_VOL_MAX;
82 else
83 data[1] = mix->right_vol;
84 data[1] |= mix->deemphasis ? 0x40 : 0;
85 if (i2c_smbus_write_block_data(mix->i2c.client, DACA_REG_AVOL,
86 2, data) < 0) {
87 snd_printk("failed to set volume \n");
88 return -EINVAL;
89 }
90 return 0;
91}
92
93
94/* deemphasis switch */
95static int daca_info_deemphasis(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
96{
97 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
98 uinfo->count = 1;
99 uinfo->value.integer.min = 0;
100 uinfo->value.integer.max = 1;
101 return 0;
102}
103
104static int daca_get_deemphasis(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
105{
106 pmac_t *chip = snd_kcontrol_chip(kcontrol);
107 pmac_daca_t *mix;
108 if (! (mix = chip->mixer_data))
109 return -ENODEV;
110 ucontrol->value.integer.value[0] = mix->deemphasis ? 1 : 0;
111 return 0;
112}
113
114static int daca_put_deemphasis(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
115{
116 pmac_t *chip = snd_kcontrol_chip(kcontrol);
117 pmac_daca_t *mix;
118 int change;
119
120 if (! (mix = chip->mixer_data))
121 return -ENODEV;
122 change = mix->deemphasis != ucontrol->value.integer.value[0];
123 if (change) {
124 mix->deemphasis = ucontrol->value.integer.value[0];
125 daca_set_volume(mix);
126 }
127 return change;
128}
129
130/* output volume */
131static int daca_info_volume(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
132{
133 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
134 uinfo->count = 2;
135 uinfo->value.integer.min = 0;
136 uinfo->value.integer.max = DACA_VOL_MAX;
137 return 0;
138}
139
140static int daca_get_volume(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
141{
142 pmac_t *chip = snd_kcontrol_chip(kcontrol);
143 pmac_daca_t *mix;
144 if (! (mix = chip->mixer_data))
145 return -ENODEV;
146 ucontrol->value.integer.value[0] = mix->left_vol;
147 ucontrol->value.integer.value[1] = mix->right_vol;
148 return 0;
149}
150
151static int daca_put_volume(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
152{
153 pmac_t *chip = snd_kcontrol_chip(kcontrol);
154 pmac_daca_t *mix;
155 int change;
156
157 if (! (mix = chip->mixer_data))
158 return -ENODEV;
159 change = mix->left_vol != ucontrol->value.integer.value[0] ||
160 mix->right_vol != ucontrol->value.integer.value[1];
161 if (change) {
162 mix->left_vol = ucontrol->value.integer.value[0];
163 mix->right_vol = ucontrol->value.integer.value[1];
164 daca_set_volume(mix);
165 }
166 return change;
167}
168
169/* amplifier switch */
170#define daca_info_amp daca_info_deemphasis
171
172static int daca_get_amp(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
173{
174 pmac_t *chip = snd_kcontrol_chip(kcontrol);
175 pmac_daca_t *mix;
176 if (! (mix = chip->mixer_data))
177 return -ENODEV;
178 ucontrol->value.integer.value[0] = mix->amp_on ? 1 : 0;
179 return 0;
180}
181
182static int daca_put_amp(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
183{
184 pmac_t *chip = snd_kcontrol_chip(kcontrol);
185 pmac_daca_t *mix;
186 int change;
187
188 if (! (mix = chip->mixer_data))
189 return -ENODEV;
190 change = mix->amp_on != ucontrol->value.integer.value[0];
191 if (change) {
192 mix->amp_on = ucontrol->value.integer.value[0];
193 i2c_smbus_write_byte_data(mix->i2c.client, DACA_REG_GCFG,
194 mix->amp_on ? 0x05 : 0x04);
195 }
196 return change;
197}
198
199static snd_kcontrol_new_t daca_mixers[] = {
200 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
201 .name = "Deemphasis Switch",
202 .info = daca_info_deemphasis,
203 .get = daca_get_deemphasis,
204 .put = daca_put_deemphasis
205 },
206 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
207 .name = "Master Playback Volume",
208 .info = daca_info_volume,
209 .get = daca_get_volume,
210 .put = daca_put_volume
211 },
212 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
213 .name = "Power Amplifier Switch",
214 .info = daca_info_amp,
215 .get = daca_get_amp,
216 .put = daca_put_amp
217 },
218};
219
220
221#ifdef CONFIG_PMAC_PBOOK
222static void daca_resume(pmac_t *chip)
223{
224 pmac_daca_t *mix = chip->mixer_data;
225 i2c_smbus_write_byte_data(mix->i2c.client, DACA_REG_SR, 0x08);
226 i2c_smbus_write_byte_data(mix->i2c.client, DACA_REG_GCFG,
227 mix->amp_on ? 0x05 : 0x04);
228 daca_set_volume(mix);
229}
230#endif /* CONFIG_PMAC_PBOOK */
231
232
233static void daca_cleanup(pmac_t *chip)
234{
235 pmac_daca_t *mix = chip->mixer_data;
236 if (! mix)
237 return;
238 snd_pmac_keywest_cleanup(&mix->i2c);
239 kfree(mix);
240 chip->mixer_data = NULL;
241}
242
243/* exported */
244int __init snd_pmac_daca_init(pmac_t *chip)
245{
246 int i, err;
247 pmac_daca_t *mix;
248
249#ifdef CONFIG_KMOD
250 if (current->fs->root)
251 request_module("i2c-keywest");
252#endif /* CONFIG_KMOD */
253
254 mix = kmalloc(sizeof(*mix), GFP_KERNEL);
255 if (! mix)
256 return -ENOMEM;
257 memset(mix, 0, sizeof(*mix));
258 chip->mixer_data = mix;
259 chip->mixer_free = daca_cleanup;
260 mix->amp_on = 1; /* default on */
261
262 mix->i2c.addr = DACA_I2C_ADDR;
263 mix->i2c.init_client = daca_init_client;
264 mix->i2c.name = "DACA";
265 if ((err = snd_pmac_keywest_init(&mix->i2c)) < 0)
266 return err;
267
268 /*
269 * build mixers
270 */
271 strcpy(chip->card->mixername, "PowerMac DACA");
272
273 for (i = 0; i < ARRAY_SIZE(daca_mixers); i++) {
274 if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&daca_mixers[i], chip))) < 0)
275 return err;
276 }
277
278#ifdef CONFIG_PMAC_PBOOK
279 chip->resume = daca_resume;
280#endif
281
282 return 0;
283}
diff --git a/sound/ppc/keywest.c b/sound/ppc/keywest.c
new file mode 100644
index 000000000000..df073a05b5d7
--- /dev/null
+++ b/sound/ppc/keywest.c
@@ -0,0 +1,143 @@
1/*
2 * common keywest i2c layer
3 *
4 * Copyright (c) by Takashi Iwai <tiwai@suse.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21
22#include <sound/driver.h>
23#include <linux/init.h>
24#include <linux/i2c.h>
25#include <linux/delay.h>
26#include <linux/i2c-dev.h>
27#include <linux/slab.h>
28#include <sound/core.h>
29#include "pmac.h"
30
31/*
32 * we have to keep a static variable here since i2c attach_adapter
33 * callback cannot pass a private data.
34 */
35static pmac_keywest_t *keywest_ctx;
36
37
38#define I2C_DRIVERID_KEYWEST 0xFEBA
39
40static int keywest_attach_adapter(struct i2c_adapter *adapter);
41static int keywest_detach_client(struct i2c_client *client);
42
43struct i2c_driver keywest_driver = {
44 .name = "PMac Keywest Audio",
45 .id = I2C_DRIVERID_KEYWEST,
46 .flags = I2C_DF_NOTIFY,
47 .attach_adapter = &keywest_attach_adapter,
48 .detach_client = &keywest_detach_client,
49};
50
51
52#ifndef i2c_device_name
53#define i2c_device_name(x) ((x)->name)
54#endif
55
56static int keywest_attach_adapter(struct i2c_adapter *adapter)
57{
58 int err;
59 struct i2c_client *new_client;
60
61 if (! keywest_ctx)
62 return -EINVAL;
63
64 if (strncmp(i2c_device_name(adapter), "mac-io", 6))
65 return 0; /* ignored */
66
67 new_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
68 if (! new_client)
69 return -ENOMEM;
70
71 memset(new_client, 0, sizeof(*new_client));
72 new_client->addr = keywest_ctx->addr;
73 i2c_set_clientdata(new_client, keywest_ctx);
74 new_client->adapter = adapter;
75 new_client->driver = &keywest_driver;
76 new_client->flags = 0;
77
78 strcpy(i2c_device_name(new_client), keywest_ctx->name);
79 keywest_ctx->client = new_client;
80
81 /* Tell the i2c layer a new client has arrived */
82 if (i2c_attach_client(new_client)) {
83 snd_printk(KERN_ERR "tumbler: cannot attach i2c client\n");
84 err = -ENODEV;
85 goto __err;
86 }
87
88 return 0;
89
90 __err:
91 kfree(new_client);
92 keywest_ctx->client = NULL;
93 return err;
94}
95
96static int keywest_detach_client(struct i2c_client *client)
97{
98 if (! keywest_ctx)
99 return 0;
100 if (client == keywest_ctx->client)
101 keywest_ctx->client = NULL;
102
103 i2c_detach_client(client);
104 kfree(client);
105 return 0;
106}
107
108/* exported */
109void snd_pmac_keywest_cleanup(pmac_keywest_t *i2c)
110{
111 if (keywest_ctx && keywest_ctx == i2c) {
112 i2c_del_driver(&keywest_driver);
113 keywest_ctx = NULL;
114 }
115}
116
117int __init snd_pmac_tumbler_post_init(void)
118{
119 int err;
120
121 if ((err = keywest_ctx->init_client(keywest_ctx)) < 0) {
122 snd_printk(KERN_ERR "tumbler: %i :cannot initialize the MCS\n", err);
123 return err;
124 }
125 return 0;
126}
127
128/* exported */
129int __init snd_pmac_keywest_init(pmac_keywest_t *i2c)
130{
131 int err;
132
133 if (keywest_ctx)
134 return -EBUSY;
135
136 keywest_ctx = i2c;
137
138 if ((err = i2c_add_driver(&keywest_driver))) {
139 snd_printk(KERN_ERR "cannot register keywest i2c driver\n");
140 return err;
141 }
142 return 0;
143}
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c
new file mode 100644
index 000000000000..6c4ed90f490e
--- /dev/null
+++ b/sound/ppc/pmac.c
@@ -0,0 +1,1328 @@
1/*
2 * PMac DBDMA lowlevel functions
3 *
4 * Copyright (c) by Takashi Iwai <tiwai@suse.de>
5 * code based on dmasound.c.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22
23#include <sound/driver.h>
24#include <asm/io.h>
25#include <asm/irq.h>
26#include <linux/init.h>
27#include <linux/delay.h>
28#include <linux/slab.h>
29#include <linux/interrupt.h>
30#include <sound/core.h>
31#include "pmac.h"
32#include <sound/pcm_params.h>
33#ifdef CONFIG_PPC_HAS_FEATURE_CALLS
34#include <asm/pmac_feature.h>
35#else
36#include <asm/feature.h>
37#endif
38
39
40#if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK)
41static int snd_pmac_register_sleep_notifier(pmac_t *chip);
42static int snd_pmac_unregister_sleep_notifier(pmac_t *chip);
43static int snd_pmac_suspend(snd_card_t *card, pm_message_t state);
44static int snd_pmac_resume(snd_card_t *card);
45#endif
46
47
48/* fixed frequency table for awacs, screamer, burgundy, DACA (44100 max) */
49static int awacs_freqs[8] = {
50 44100, 29400, 22050, 17640, 14700, 11025, 8820, 7350
51};
52/* fixed frequency table for tumbler */
53static int tumbler_freqs[1] = {
54 44100
55};
56
57/*
58 * allocate DBDMA command arrays
59 */
60static int snd_pmac_dbdma_alloc(pmac_dbdma_t *rec, int size)
61{
62 rec->space = kmalloc(sizeof(struct dbdma_cmd) * (size + 1), GFP_KERNEL);
63 if (rec->space == NULL)
64 return -ENOMEM;
65 rec->size = size;
66 memset(rec->space, 0, sizeof(struct dbdma_cmd) * (size + 1));
67 rec->cmds = (void __iomem *)DBDMA_ALIGN(rec->space);
68 rec->addr = virt_to_bus(rec->cmds);
69 return 0;
70}
71
72static void snd_pmac_dbdma_free(pmac_dbdma_t *rec)
73{
74 if (rec)
75 kfree(rec->space);
76}
77
78
79/*
80 * pcm stuff
81 */
82
83/*
84 * look up frequency table
85 */
86
87unsigned int snd_pmac_rate_index(pmac_t *chip, pmac_stream_t *rec, unsigned int rate)
88{
89 int i, ok, found;
90
91 ok = rec->cur_freqs;
92 if (rate > chip->freq_table[0])
93 return 0;
94 found = 0;
95 for (i = 0; i < chip->num_freqs; i++, ok >>= 1) {
96 if (! (ok & 1)) continue;
97 found = i;
98 if (rate >= chip->freq_table[i])
99 break;
100 }
101 return found;
102}
103
104/*
105 * check whether another stream is active
106 */
107static inline int another_stream(int stream)
108{
109 return (stream == SNDRV_PCM_STREAM_PLAYBACK) ?
110 SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
111}
112
113/*
114 * allocate buffers
115 */
116static int snd_pmac_pcm_hw_params(snd_pcm_substream_t *subs,
117 snd_pcm_hw_params_t *hw_params)
118{
119 return snd_pcm_lib_malloc_pages(subs, params_buffer_bytes(hw_params));
120}
121
122/*
123 * release buffers
124 */
125static int snd_pmac_pcm_hw_free(snd_pcm_substream_t *subs)
126{
127 snd_pcm_lib_free_pages(subs);
128 return 0;
129}
130
131/*
132 * get a stream of the opposite direction
133 */
134static pmac_stream_t *snd_pmac_get_stream(pmac_t *chip, int stream)
135{
136 switch (stream) {
137 case SNDRV_PCM_STREAM_PLAYBACK:
138 return &chip->playback;
139 case SNDRV_PCM_STREAM_CAPTURE:
140 return &chip->capture;
141 default:
142 snd_BUG();
143 return NULL;
144 }
145}
146
147/*
148 * wait while run status is on
149 */
150inline static void
151snd_pmac_wait_ack(pmac_stream_t *rec)
152{
153 int timeout = 50000;
154 while ((in_le32(&rec->dma->status) & RUN) && timeout-- > 0)
155 udelay(1);
156}
157
158/*
159 * set the format and rate to the chip.
160 * call the lowlevel function if defined (e.g. for AWACS).
161 */
162static void snd_pmac_pcm_set_format(pmac_t *chip)
163{
164 /* set up frequency and format */
165 out_le32(&chip->awacs->control, chip->control_mask | (chip->rate_index << 8));
166 out_le32(&chip->awacs->byteswap, chip->format == SNDRV_PCM_FORMAT_S16_LE ? 1 : 0);
167 if (chip->set_format)
168 chip->set_format(chip);
169}
170
171/*
172 * stop the DMA transfer
173 */
174inline static void snd_pmac_dma_stop(pmac_stream_t *rec)
175{
176 out_le32(&rec->dma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
177 snd_pmac_wait_ack(rec);
178}
179
180/*
181 * set the command pointer address
182 */
183inline static void snd_pmac_dma_set_command(pmac_stream_t *rec, pmac_dbdma_t *cmd)
184{
185 out_le32(&rec->dma->cmdptr, cmd->addr);
186}
187
188/*
189 * start the DMA
190 */
191inline static void snd_pmac_dma_run(pmac_stream_t *rec, int status)
192{
193 out_le32(&rec->dma->control, status | (status << 16));
194}
195
196
197/*
198 * prepare playback/capture stream
199 */
200static int snd_pmac_pcm_prepare(pmac_t *chip, pmac_stream_t *rec, snd_pcm_substream_t *subs)
201{
202 int i;
203 volatile struct dbdma_cmd __iomem *cp;
204 snd_pcm_runtime_t *runtime = subs->runtime;
205 int rate_index;
206 long offset;
207 pmac_stream_t *astr;
208
209 rec->dma_size = snd_pcm_lib_buffer_bytes(subs);
210 rec->period_size = snd_pcm_lib_period_bytes(subs);
211 rec->nperiods = rec->dma_size / rec->period_size;
212 rec->cur_period = 0;
213 rate_index = snd_pmac_rate_index(chip, rec, runtime->rate);
214
215 /* set up constraints */
216 astr = snd_pmac_get_stream(chip, another_stream(rec->stream));
217 snd_runtime_check(astr, return -EINVAL);
218 astr->cur_freqs = 1 << rate_index;
219 astr->cur_formats = 1 << runtime->format;
220 chip->rate_index = rate_index;
221 chip->format = runtime->format;
222
223 /* We really want to execute a DMA stop command, after the AWACS
224 * is initialized.
225 * For reasons I don't understand, it stops the hissing noise
226 * common to many PowerBook G3 systems and random noise otherwise
227 * captured on iBook2's about every third time. -ReneR
228 */
229 spin_lock_irq(&chip->reg_lock);
230 snd_pmac_dma_stop(rec);
231 st_le16(&chip->extra_dma.cmds->command, DBDMA_STOP);
232 snd_pmac_dma_set_command(rec, &chip->extra_dma);
233 snd_pmac_dma_run(rec, RUN);
234 spin_unlock_irq(&chip->reg_lock);
235 mdelay(5);
236 spin_lock_irq(&chip->reg_lock);
237 /* continuous DMA memory type doesn't provide the physical address,
238 * so we need to resolve the address here...
239 */
240 offset = virt_to_bus(runtime->dma_area);
241 for (i = 0, cp = rec->cmd.cmds; i < rec->nperiods; i++, cp++) {
242 st_le32(&cp->phy_addr, offset);
243 st_le16(&cp->req_count, rec->period_size);
244 /*st_le16(&cp->res_count, 0);*/
245 st_le16(&cp->xfer_status, 0);
246 offset += rec->period_size;
247 }
248 /* make loop */
249 st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
250 st_le32(&cp->cmd_dep, rec->cmd.addr);
251
252 snd_pmac_dma_stop(rec);
253 snd_pmac_dma_set_command(rec, &rec->cmd);
254 spin_unlock_irq(&chip->reg_lock);
255
256 return 0;
257}
258
259
260/*
261 * PCM trigger/stop
262 */
263static int snd_pmac_pcm_trigger(pmac_t *chip, pmac_stream_t *rec,
264 snd_pcm_substream_t *subs, int cmd)
265{
266 volatile struct dbdma_cmd __iomem *cp;
267 int i, command;
268
269 switch (cmd) {
270 case SNDRV_PCM_TRIGGER_START:
271 case SNDRV_PCM_TRIGGER_RESUME:
272 if (rec->running)
273 return -EBUSY;
274 command = (subs->stream == SNDRV_PCM_STREAM_PLAYBACK ?
275 OUTPUT_MORE : INPUT_MORE) + INTR_ALWAYS;
276 spin_lock(&chip->reg_lock);
277 snd_pmac_beep_stop(chip);
278 snd_pmac_pcm_set_format(chip);
279 for (i = 0, cp = rec->cmd.cmds; i < rec->nperiods; i++, cp++)
280 out_le16(&cp->command, command);
281 snd_pmac_dma_set_command(rec, &rec->cmd);
282 (void)in_le32(&rec->dma->status);
283 snd_pmac_dma_run(rec, RUN|WAKE);
284 rec->running = 1;
285 spin_unlock(&chip->reg_lock);
286 break;
287
288 case SNDRV_PCM_TRIGGER_STOP:
289 case SNDRV_PCM_TRIGGER_SUSPEND:
290 spin_lock(&chip->reg_lock);
291 rec->running = 0;
292 /*printk("stopped!!\n");*/
293 snd_pmac_dma_stop(rec);
294 for (i = 0, cp = rec->cmd.cmds; i < rec->nperiods; i++, cp++)
295 out_le16(&cp->command, DBDMA_STOP);
296 spin_unlock(&chip->reg_lock);
297 break;
298
299 default:
300 return -EINVAL;
301 }
302
303 return 0;
304}
305
306/*
307 * return the current pointer
308 */
309inline
310static snd_pcm_uframes_t snd_pmac_pcm_pointer(pmac_t *chip, pmac_stream_t *rec,
311 snd_pcm_substream_t *subs)
312{
313 int count = 0;
314
315#if 1 /* hmm.. how can we get the current dma pointer?? */
316 int stat;
317 volatile struct dbdma_cmd __iomem *cp = &rec->cmd.cmds[rec->cur_period];
318 stat = ld_le16(&cp->xfer_status);
319 if (stat & (ACTIVE|DEAD)) {
320 count = in_le16(&cp->res_count);
321 if (count)
322 count = rec->period_size - count;
323 }
324#endif
325 count += rec->cur_period * rec->period_size;
326 /*printk("pointer=%d\n", count);*/
327 return bytes_to_frames(subs->runtime, count);
328}
329
330/*
331 * playback
332 */
333
334static int snd_pmac_playback_prepare(snd_pcm_substream_t *subs)
335{
336 pmac_t *chip = snd_pcm_substream_chip(subs);
337 return snd_pmac_pcm_prepare(chip, &chip->playback, subs);
338}
339
340static int snd_pmac_playback_trigger(snd_pcm_substream_t *subs,
341 int cmd)
342{
343 pmac_t *chip = snd_pcm_substream_chip(subs);
344 return snd_pmac_pcm_trigger(chip, &chip->playback, subs, cmd);
345}
346
347static snd_pcm_uframes_t snd_pmac_playback_pointer(snd_pcm_substream_t *subs)
348{
349 pmac_t *chip = snd_pcm_substream_chip(subs);
350 return snd_pmac_pcm_pointer(chip, &chip->playback, subs);
351}
352
353
354/*
355 * capture
356 */
357
358static int snd_pmac_capture_prepare(snd_pcm_substream_t *subs)
359{
360 pmac_t *chip = snd_pcm_substream_chip(subs);
361 return snd_pmac_pcm_prepare(chip, &chip->capture, subs);
362}
363
364static int snd_pmac_capture_trigger(snd_pcm_substream_t *subs,
365 int cmd)
366{
367 pmac_t *chip = snd_pcm_substream_chip(subs);
368 return snd_pmac_pcm_trigger(chip, &chip->capture, subs, cmd);
369}
370
371static snd_pcm_uframes_t snd_pmac_capture_pointer(snd_pcm_substream_t *subs)
372{
373 pmac_t *chip = snd_pcm_substream_chip(subs);
374 return snd_pmac_pcm_pointer(chip, &chip->capture, subs);
375}
376
377
378/*
379 * update playback/capture pointer from interrupts
380 */
381static void snd_pmac_pcm_update(pmac_t *chip, pmac_stream_t *rec)
382{
383 volatile struct dbdma_cmd __iomem *cp;
384 int c;
385 int stat;
386
387 spin_lock(&chip->reg_lock);
388 if (rec->running) {
389 cp = &rec->cmd.cmds[rec->cur_period];
390 for (c = 0; c < rec->nperiods; c++) { /* at most all fragments */
391 stat = ld_le16(&cp->xfer_status);
392 if (! (stat & ACTIVE))
393 break;
394 /*printk("update frag %d\n", rec->cur_period);*/
395 st_le16(&cp->xfer_status, 0);
396 st_le16(&cp->req_count, rec->period_size);
397 /*st_le16(&cp->res_count, 0);*/
398 rec->cur_period++;
399 if (rec->cur_period >= rec->nperiods) {
400 rec->cur_period = 0;
401 cp = rec->cmd.cmds;
402 } else
403 cp++;
404 spin_unlock(&chip->reg_lock);
405 snd_pcm_period_elapsed(rec->substream);
406 spin_lock(&chip->reg_lock);
407 }
408 }
409 spin_unlock(&chip->reg_lock);
410}
411
412
413/*
414 * hw info
415 */
416
417static snd_pcm_hardware_t snd_pmac_playback =
418{
419 .info = (SNDRV_PCM_INFO_INTERLEAVED |
420 SNDRV_PCM_INFO_MMAP |
421 SNDRV_PCM_INFO_MMAP_VALID |
422 SNDRV_PCM_INFO_RESUME),
423 .formats = SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S16_LE,
424 .rates = SNDRV_PCM_RATE_8000_44100,
425 .rate_min = 7350,
426 .rate_max = 44100,
427 .channels_min = 2,
428 .channels_max = 2,
429 .buffer_bytes_max = 131072,
430 .period_bytes_min = 256,
431 .period_bytes_max = 16384,
432 .periods_min = 3,
433 .periods_max = PMAC_MAX_FRAGS,
434};
435
436static snd_pcm_hardware_t snd_pmac_capture =
437{
438 .info = (SNDRV_PCM_INFO_INTERLEAVED |
439 SNDRV_PCM_INFO_MMAP |
440 SNDRV_PCM_INFO_MMAP_VALID |
441 SNDRV_PCM_INFO_RESUME),
442 .formats = SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S16_LE,
443 .rates = SNDRV_PCM_RATE_8000_44100,
444 .rate_min = 7350,
445 .rate_max = 44100,
446 .channels_min = 2,
447 .channels_max = 2,
448 .buffer_bytes_max = 131072,
449 .period_bytes_min = 256,
450 .period_bytes_max = 16384,
451 .periods_min = 3,
452 .periods_max = PMAC_MAX_FRAGS,
453};
454
455
456#if 0 // NYI
457static int snd_pmac_hw_rule_rate(snd_pcm_hw_params_t *params,
458 snd_pcm_hw_rule_t *rule)
459{
460 pmac_t *chip = rule->private;
461 pmac_stream_t *rec = snd_pmac_get_stream(chip, rule->deps[0]);
462 int i, freq_table[8], num_freqs;
463
464 snd_runtime_check(rec, return -EINVAL);
465 num_freqs = 0;
466 for (i = chip->num_freqs - 1; i >= 0; i--) {
467 if (rec->cur_freqs & (1 << i))
468 freq_table[num_freqs++] = chip->freq_table[i];
469 }
470
471 return snd_interval_list(hw_param_interval(params, rule->var),
472 num_freqs, freq_table, 0);
473}
474
475static int snd_pmac_hw_rule_format(snd_pcm_hw_params_t *params,
476 snd_pcm_hw_rule_t *rule)
477{
478 pmac_t *chip = rule->private;
479 pmac_stream_t *rec = snd_pmac_get_stream(chip, rule->deps[0]);
480
481 snd_runtime_check(rec, return -EINVAL);
482 return snd_mask_refine_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
483 rec->cur_formats);
484}
485#endif // NYI
486
487static int snd_pmac_pcm_open(pmac_t *chip, pmac_stream_t *rec, snd_pcm_substream_t *subs)
488{
489 snd_pcm_runtime_t *runtime = subs->runtime;
490 int i, j, fflags;
491 static int typical_freqs[] = {
492 44100,
493 22050,
494 11025,
495 0,
496 };
497 static int typical_freq_flags[] = {
498 SNDRV_PCM_RATE_44100,
499 SNDRV_PCM_RATE_22050,
500 SNDRV_PCM_RATE_11025,
501 0,
502 };
503
504 /* look up frequency table and fill bit mask */
505 runtime->hw.rates = 0;
506 fflags = chip->freqs_ok;
507 for (i = 0; typical_freqs[i]; i++) {
508 for (j = 0; j < chip->num_freqs; j++) {
509 if ((chip->freqs_ok & (1 << j)) &&
510 chip->freq_table[j] == typical_freqs[i]) {
511 runtime->hw.rates |= typical_freq_flags[i];
512 fflags &= ~(1 << j);
513 break;
514 }
515 }
516 }
517 if (fflags) /* rest */
518 runtime->hw.rates |= SNDRV_PCM_RATE_KNOT;
519
520 /* check for minimum and maximum rates */
521 for (i = 0; i < chip->num_freqs; i++) {
522 if (chip->freqs_ok & (1 << i)) {
523 runtime->hw.rate_max = chip->freq_table[i];
524 break;
525 }
526 }
527 for (i = chip->num_freqs - 1; i >= 0; i--) {
528 if (chip->freqs_ok & (1 << i)) {
529 runtime->hw.rate_min = chip->freq_table[i];
530 break;
531 }
532 }
533 runtime->hw.formats = chip->formats_ok;
534 if (chip->can_capture) {
535 if (! chip->can_duplex)
536 runtime->hw.info |= SNDRV_PCM_INFO_HALF_DUPLEX;
537 runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
538 }
539 runtime->private_data = rec;
540 rec->substream = subs;
541
542#if 0 /* FIXME: still under development.. */
543 snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
544 snd_pmac_hw_rule_rate, chip, rec->stream, -1);
545 snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
546 snd_pmac_hw_rule_format, chip, rec->stream, -1);
547#endif
548
549 runtime->hw.periods_max = rec->cmd.size - 1;
550
551 if (chip->can_duplex)
552 snd_pcm_set_sync(subs);
553
554 /* constraints to fix choppy sound */
555 snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
556 return 0;
557}
558
559static int snd_pmac_pcm_close(pmac_t *chip, pmac_stream_t *rec, snd_pcm_substream_t *subs)
560{
561 pmac_stream_t *astr;
562
563 snd_pmac_dma_stop(rec);
564
565 astr = snd_pmac_get_stream(chip, another_stream(rec->stream));
566 snd_runtime_check(astr, return -EINVAL);
567
568 /* reset constraints */
569 astr->cur_freqs = chip->freqs_ok;
570 astr->cur_formats = chip->formats_ok;
571
572 return 0;
573}
574
575static int snd_pmac_playback_open(snd_pcm_substream_t *subs)
576{
577 pmac_t *chip = snd_pcm_substream_chip(subs);
578
579 subs->runtime->hw = snd_pmac_playback;
580 return snd_pmac_pcm_open(chip, &chip->playback, subs);
581}
582
583static int snd_pmac_capture_open(snd_pcm_substream_t *subs)
584{
585 pmac_t *chip = snd_pcm_substream_chip(subs);
586
587 subs->runtime->hw = snd_pmac_capture;
588 return snd_pmac_pcm_open(chip, &chip->capture, subs);
589}
590
591static int snd_pmac_playback_close(snd_pcm_substream_t *subs)
592{
593 pmac_t *chip = snd_pcm_substream_chip(subs);
594
595 return snd_pmac_pcm_close(chip, &chip->playback, subs);
596}
597
598static int snd_pmac_capture_close(snd_pcm_substream_t *subs)
599{
600 pmac_t *chip = snd_pcm_substream_chip(subs);
601
602 return snd_pmac_pcm_close(chip, &chip->capture, subs);
603}
604
605/*
606 */
607
608static snd_pcm_ops_t snd_pmac_playback_ops = {
609 .open = snd_pmac_playback_open,
610 .close = snd_pmac_playback_close,
611 .ioctl = snd_pcm_lib_ioctl,
612 .hw_params = snd_pmac_pcm_hw_params,
613 .hw_free = snd_pmac_pcm_hw_free,
614 .prepare = snd_pmac_playback_prepare,
615 .trigger = snd_pmac_playback_trigger,
616 .pointer = snd_pmac_playback_pointer,
617};
618
619static snd_pcm_ops_t snd_pmac_capture_ops = {
620 .open = snd_pmac_capture_open,
621 .close = snd_pmac_capture_close,
622 .ioctl = snd_pcm_lib_ioctl,
623 .hw_params = snd_pmac_pcm_hw_params,
624 .hw_free = snd_pmac_pcm_hw_free,
625 .prepare = snd_pmac_capture_prepare,
626 .trigger = snd_pmac_capture_trigger,
627 .pointer = snd_pmac_capture_pointer,
628};
629
630static void pmac_pcm_free(snd_pcm_t *pcm)
631{
632 snd_pcm_lib_preallocate_free_for_all(pcm);
633}
634
635int __init snd_pmac_pcm_new(pmac_t *chip)
636{
637 snd_pcm_t *pcm;
638 int err;
639 int num_captures = 1;
640
641 if (! chip->can_capture)
642 num_captures = 0;
643 err = snd_pcm_new(chip->card, chip->card->driver, 0, 1, num_captures, &pcm);
644 if (err < 0)
645 return err;
646
647 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_pmac_playback_ops);
648 if (chip->can_capture)
649 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_pmac_capture_ops);
650
651 pcm->private_data = chip;
652 pcm->private_free = pmac_pcm_free;
653 pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
654 strcpy(pcm->name, chip->card->shortname);
655 chip->pcm = pcm;
656
657 chip->formats_ok = SNDRV_PCM_FMTBIT_S16_BE;
658 if (chip->can_byte_swap)
659 chip->formats_ok |= SNDRV_PCM_FMTBIT_S16_LE;
660
661 chip->playback.cur_formats = chip->formats_ok;
662 chip->capture.cur_formats = chip->formats_ok;
663 chip->playback.cur_freqs = chip->freqs_ok;
664 chip->capture.cur_freqs = chip->freqs_ok;
665
666 /* preallocate 64k buffer */
667 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
668 snd_dma_continuous_data(GFP_KERNEL),
669 64 * 1024, 64 * 1024);
670
671 return 0;
672}
673
674
675static void snd_pmac_dbdma_reset(pmac_t *chip)
676{
677 out_le32(&chip->playback.dma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16);
678 snd_pmac_wait_ack(&chip->playback);
679 out_le32(&chip->capture.dma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16);
680 snd_pmac_wait_ack(&chip->capture);
681}
682
683
684/*
685 * handling beep
686 */
687void snd_pmac_beep_dma_start(pmac_t *chip, int bytes, unsigned long addr, int speed)
688{
689 pmac_stream_t *rec = &chip->playback;
690
691 snd_pmac_dma_stop(rec);
692 st_le16(&chip->extra_dma.cmds->req_count, bytes);
693 st_le16(&chip->extra_dma.cmds->xfer_status, 0);
694 st_le32(&chip->extra_dma.cmds->cmd_dep, chip->extra_dma.addr);
695 st_le32(&chip->extra_dma.cmds->phy_addr, addr);
696 st_le16(&chip->extra_dma.cmds->command, OUTPUT_MORE + BR_ALWAYS);
697 out_le32(&chip->awacs->control,
698 (in_le32(&chip->awacs->control) & ~0x1f00)
699 | (speed << 8));
700 out_le32(&chip->awacs->byteswap, 0);
701 snd_pmac_dma_set_command(rec, &chip->extra_dma);
702 snd_pmac_dma_run(rec, RUN);
703}
704
705void snd_pmac_beep_dma_stop(pmac_t *chip)
706{
707 snd_pmac_dma_stop(&chip->playback);
708 st_le16(&chip->extra_dma.cmds->command, DBDMA_STOP);
709 snd_pmac_pcm_set_format(chip); /* reset format */
710}
711
712
713/*
714 * interrupt handlers
715 */
716static irqreturn_t
717snd_pmac_tx_intr(int irq, void *devid, struct pt_regs *regs)
718{
719 pmac_t *chip = devid;
720 snd_pmac_pcm_update(chip, &chip->playback);
721 return IRQ_HANDLED;
722}
723
724
725static irqreturn_t
726snd_pmac_rx_intr(int irq, void *devid, struct pt_regs *regs)
727{
728 pmac_t *chip = devid;
729 snd_pmac_pcm_update(chip, &chip->capture);
730 return IRQ_HANDLED;
731}
732
733
734static irqreturn_t
735snd_pmac_ctrl_intr(int irq, void *devid, struct pt_regs *regs)
736{
737 pmac_t *chip = devid;
738 int ctrl = in_le32(&chip->awacs->control);
739
740 /*printk("pmac: control interrupt.. 0x%x\n", ctrl);*/
741 if (ctrl & MASK_PORTCHG) {
742 /* do something when headphone is plugged/unplugged? */
743 if (chip->update_automute)
744 chip->update_automute(chip, 1);
745 }
746 if (ctrl & MASK_CNTLERR) {
747 int err = (in_le32(&chip->awacs->codec_stat) & MASK_ERRCODE) >> 16;
748 if (err && chip->model <= PMAC_SCREAMER)
749 snd_printk(KERN_DEBUG "error %x\n", err);
750 }
751 /* Writing 1s to the CNTLERR and PORTCHG bits clears them... */
752 out_le32(&chip->awacs->control, ctrl);
753 return IRQ_HANDLED;
754}
755
756
757/*
758 * a wrapper to feature call for compatibility
759 */
760#if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK)
761static void snd_pmac_sound_feature(pmac_t *chip, int enable)
762{
763#ifdef CONFIG_PPC_HAS_FEATURE_CALLS
764 ppc_md.feature_call(PMAC_FTR_SOUND_CHIP_ENABLE, chip->node, 0, enable);
765#else
766 if (chip->is_pbook_G3) {
767 pmu_suspend();
768 feature_clear(chip->node, FEATURE_Sound_power);
769 feature_clear(chip->node, FEATURE_Sound_CLK_enable);
770 big_mdelay(1000); /* XXX */
771 pmu_resume();
772 }
773 if (chip->is_pbook_3400) {
774 feature_set(chip->node, FEATURE_IOBUS_enable);
775 udelay(10);
776 }
777#endif
778}
779#else /* CONFIG_PM && CONFIG_PMAC_PBOOK */
780#define snd_pmac_sound_feature(chip,enable) /**/
781#endif /* CONFIG_PM && CONFIG_PMAC_PBOOK */
782
783/*
784 * release resources
785 */
786
787static int snd_pmac_free(pmac_t *chip)
788{
789 int i;
790
791 /* stop sounds */
792 if (chip->initialized) {
793 snd_pmac_dbdma_reset(chip);
794 /* disable interrupts from awacs interface */
795 out_le32(&chip->awacs->control, in_le32(&chip->awacs->control) & 0xfff);
796 }
797
798 snd_pmac_sound_feature(chip, 0);
799#if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK)
800 snd_pmac_unregister_sleep_notifier(chip);
801#endif
802
803 /* clean up mixer if any */
804 if (chip->mixer_free)
805 chip->mixer_free(chip);
806
807 snd_pmac_detach_beep(chip);
808
809 /* release resources */
810 if (chip->irq >= 0)
811 free_irq(chip->irq, (void*)chip);
812 if (chip->tx_irq >= 0)
813 free_irq(chip->tx_irq, (void*)chip);
814 if (chip->rx_irq >= 0)
815 free_irq(chip->rx_irq, (void*)chip);
816 snd_pmac_dbdma_free(&chip->playback.cmd);
817 snd_pmac_dbdma_free(&chip->capture.cmd);
818 snd_pmac_dbdma_free(&chip->extra_dma);
819 if (chip->macio_base)
820 iounmap(chip->macio_base);
821 if (chip->latch_base)
822 iounmap(chip->latch_base);
823 if (chip->awacs)
824 iounmap(chip->awacs);
825 if (chip->playback.dma)
826 iounmap(chip->playback.dma);
827 if (chip->capture.dma)
828 iounmap(chip->capture.dma);
829 if (chip->node) {
830 for (i = 0; i < 3; i++) {
831 if (chip->of_requested & (1 << i))
832 release_OF_resource(chip->node, i);
833 }
834 }
835 kfree(chip);
836 return 0;
837}
838
839
840/*
841 * free the device
842 */
843static int snd_pmac_dev_free(snd_device_t *device)
844{
845 pmac_t *chip = device->device_data;
846 return snd_pmac_free(chip);
847}
848
849
850/*
851 * check the machine support byteswap (little-endian)
852 */
853
854static void __init detect_byte_swap(pmac_t *chip)
855{
856 struct device_node *mio;
857
858 /* if seems that Keylargo can't byte-swap */
859 for (mio = chip->node->parent; mio; mio = mio->parent) {
860 if (strcmp(mio->name, "mac-io") == 0) {
861 if (device_is_compatible(mio, "Keylargo"))
862 chip->can_byte_swap = 0;
863 break;
864 }
865 }
866
867 /* it seems the Pismo & iBook can't byte-swap in hardware. */
868 if (machine_is_compatible("PowerBook3,1") ||
869 machine_is_compatible("PowerBook2,1"))
870 chip->can_byte_swap = 0 ;
871
872 if (machine_is_compatible("PowerBook2,1"))
873 chip->can_duplex = 0;
874}
875
876
877/*
878 * detect a sound chip
879 */
880static int __init snd_pmac_detect(pmac_t *chip)
881{
882 struct device_node *sound;
883 unsigned int *prop, l;
884
885 if (_machine != _MACH_Pmac)
886 return -ENODEV;
887
888 chip->subframe = 0;
889 chip->revision = 0;
890 chip->freqs_ok = 0xff; /* all ok */
891 chip->model = PMAC_AWACS;
892 chip->can_byte_swap = 1;
893 chip->can_duplex = 1;
894 chip->can_capture = 1;
895 chip->num_freqs = ARRAY_SIZE(awacs_freqs);
896 chip->freq_table = awacs_freqs;
897
898 chip->control_mask = MASK_IEPC | MASK_IEE | 0x11; /* default */
899
900 /* check machine type */
901 if (machine_is_compatible("AAPL,3400/2400")
902 || machine_is_compatible("AAPL,3500"))
903 chip->is_pbook_3400 = 1;
904 else if (machine_is_compatible("PowerBook1,1")
905 || machine_is_compatible("AAPL,PowerBook1998"))
906 chip->is_pbook_G3 = 1;
907 chip->node = find_devices("awacs");
908 if (chip->node)
909 return 0; /* ok */
910
911 /*
912 * powermac G3 models have a node called "davbus"
913 * with a child called "sound".
914 */
915 chip->node = find_devices("davbus");
916 /*
917 * if we didn't find a davbus device, try 'i2s-a' since
918 * this seems to be what iBooks have
919 */
920 if (! chip->node)
921 chip->node = find_devices("i2s-a");
922 if (! chip->node)
923 return -ENODEV;
924 sound = find_devices("sound");
925 while (sound && sound->parent != chip->node)
926 sound = sound->next;
927 if (! sound)
928 return -ENODEV;
929 prop = (unsigned int *) get_property(sound, "sub-frame", NULL);
930 if (prop && *prop < 16)
931 chip->subframe = *prop;
932 /* This should be verified on older screamers */
933 if (device_is_compatible(sound, "screamer")) {
934 chip->model = PMAC_SCREAMER;
935 // chip->can_byte_swap = 0; /* FIXME: check this */
936 }
937 if (device_is_compatible(sound, "burgundy")) {
938 chip->model = PMAC_BURGUNDY;
939 chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */
940 }
941 if (device_is_compatible(sound, "daca")) {
942 chip->model = PMAC_DACA;
943 chip->can_capture = 0; /* no capture */
944 chip->can_duplex = 0;
945 // chip->can_byte_swap = 0; /* FIXME: check this */
946 chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */
947 }
948 if (device_is_compatible(sound, "tumbler")) {
949 chip->model = PMAC_TUMBLER;
950 chip->can_capture = 0; /* no capture */
951 chip->can_duplex = 0;
952 // chip->can_byte_swap = 0; /* FIXME: check this */
953 chip->num_freqs = ARRAY_SIZE(tumbler_freqs);
954 chip->freq_table = tumbler_freqs;
955 chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */
956 }
957 if (device_is_compatible(sound, "snapper")) {
958 chip->model = PMAC_SNAPPER;
959 // chip->can_byte_swap = 0; /* FIXME: check this */
960 chip->num_freqs = ARRAY_SIZE(tumbler_freqs);
961 chip->freq_table = tumbler_freqs;
962 chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */
963 }
964 if (device_is_compatible(sound, "AOAKeylargo")) {
965 /* Seems to support the stock AWACS frequencies, but has
966 a snapper mixer */
967 chip->model = PMAC_SNAPPER;
968 // chip->can_byte_swap = 0; /* FIXME: check this */
969 chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */
970 }
971 prop = (unsigned int *)get_property(sound, "device-id", NULL);
972 if (prop)
973 chip->device_id = *prop;
974 chip->has_iic = (find_devices("perch") != NULL);
975
976 detect_byte_swap(chip);
977
978 /* look for a property saying what sample rates
979 are available */
980 prop = (unsigned int *) get_property(sound, "sample-rates", &l);
981 if (! prop)
982 prop = (unsigned int *) get_property(sound, "output-frame-rates", &l);
983 if (prop) {
984 int i;
985 chip->freqs_ok = 0;
986 for (l /= sizeof(int); l > 0; --l) {
987 unsigned int r = *prop++;
988 /* Apple 'Fixed' format */
989 if (r >= 0x10000)
990 r >>= 16;
991 for (i = 0; i < chip->num_freqs; ++i) {
992 if (r == chip->freq_table[i]) {
993 chip->freqs_ok |= (1 << i);
994 break;
995 }
996 }
997 }
998 } else {
999 /* assume only 44.1khz */
1000 chip->freqs_ok = 1;
1001 }
1002
1003 return 0;
1004}
1005
1006/*
1007 * exported - boolean info callbacks for ease of programming
1008 */
1009int snd_pmac_boolean_stereo_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
1010{
1011 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1012 uinfo->count = 2;
1013 uinfo->value.integer.min = 0;
1014 uinfo->value.integer.max = 1;
1015 return 0;
1016}
1017
1018int snd_pmac_boolean_mono_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
1019{
1020 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1021 uinfo->count = 1;
1022 uinfo->value.integer.min = 0;
1023 uinfo->value.integer.max = 1;
1024 return 0;
1025}
1026
1027#ifdef PMAC_SUPPORT_AUTOMUTE
1028/*
1029 * auto-mute
1030 */
1031static int pmac_auto_mute_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
1032{
1033 pmac_t *chip = snd_kcontrol_chip(kcontrol);
1034 ucontrol->value.integer.value[0] = chip->auto_mute;
1035 return 0;
1036}
1037
1038static int pmac_auto_mute_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
1039{
1040 pmac_t *chip = snd_kcontrol_chip(kcontrol);
1041 if (ucontrol->value.integer.value[0] != chip->auto_mute) {
1042 chip->auto_mute = ucontrol->value.integer.value[0];
1043 if (chip->update_automute)
1044 chip->update_automute(chip, 1);
1045 return 1;
1046 }
1047 return 0;
1048}
1049
1050static int pmac_hp_detect_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
1051{
1052 pmac_t *chip = snd_kcontrol_chip(kcontrol);
1053 if (chip->detect_headphone)
1054 ucontrol->value.integer.value[0] = chip->detect_headphone(chip);
1055 else
1056 ucontrol->value.integer.value[0] = 0;
1057 return 0;
1058}
1059
1060static snd_kcontrol_new_t auto_mute_controls[] __initdata = {
1061 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1062 .name = "Auto Mute Switch",
1063 .info = snd_pmac_boolean_mono_info,
1064 .get = pmac_auto_mute_get,
1065 .put = pmac_auto_mute_put,
1066 },
1067 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1068 .name = "Headphone Detection",
1069 .access = SNDRV_CTL_ELEM_ACCESS_READ,
1070 .info = snd_pmac_boolean_mono_info,
1071 .get = pmac_hp_detect_get,
1072 },
1073};
1074
1075int __init snd_pmac_add_automute(pmac_t *chip)
1076{
1077 int err;
1078 chip->auto_mute = 1;
1079 err = snd_ctl_add(chip->card, snd_ctl_new1(&auto_mute_controls[0], chip));
1080 if (err < 0)
1081 return err;
1082 chip->hp_detect_ctl = snd_ctl_new1(&auto_mute_controls[1], chip);
1083 return snd_ctl_add(chip->card, chip->hp_detect_ctl);
1084}
1085#endif /* PMAC_SUPPORT_AUTOMUTE */
1086
1087/*
1088 * create and detect a pmac chip record
1089 */
1090int __init snd_pmac_new(snd_card_t *card, pmac_t **chip_return)
1091{
1092 pmac_t *chip;
1093 struct device_node *np;
1094 int i, err;
1095 static snd_device_ops_t ops = {
1096 .dev_free = snd_pmac_dev_free,
1097 };
1098
1099 snd_runtime_check(chip_return, return -EINVAL);
1100 *chip_return = NULL;
1101
1102 chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
1103 if (chip == NULL)
1104 return -ENOMEM;
1105 chip->card = card;
1106
1107 spin_lock_init(&chip->reg_lock);
1108 chip->irq = chip->tx_irq = chip->rx_irq = -1;
1109
1110 chip->playback.stream = SNDRV_PCM_STREAM_PLAYBACK;
1111 chip->capture.stream = SNDRV_PCM_STREAM_CAPTURE;
1112
1113 if ((err = snd_pmac_detect(chip)) < 0)
1114 goto __error;
1115
1116 if (snd_pmac_dbdma_alloc(&chip->playback.cmd, PMAC_MAX_FRAGS + 1) < 0 ||
1117 snd_pmac_dbdma_alloc(&chip->capture.cmd, PMAC_MAX_FRAGS + 1) < 0 ||
1118 snd_pmac_dbdma_alloc(&chip->extra_dma, 2) < 0) {
1119 err = -ENOMEM;
1120 goto __error;
1121 }
1122
1123 np = chip->node;
1124 if (np->n_addrs < 3 || np->n_intrs < 3) {
1125 err = -ENODEV;
1126 goto __error;
1127 }
1128
1129 for (i = 0; i < 3; i++) {
1130 static char *name[3] = { NULL, "- Tx DMA", "- Rx DMA" };
1131 if (! request_OF_resource(np, i, name[i])) {
1132 snd_printk(KERN_ERR "pmac: can't request resource %d!\n", i);
1133 err = -ENODEV;
1134 goto __error;
1135 }
1136 chip->of_requested |= (1 << i);
1137 }
1138
1139 chip->awacs = ioremap(np->addrs[0].address, 0x1000);
1140 chip->playback.dma = ioremap(np->addrs[1].address, 0x100);
1141 chip->capture.dma = ioremap(np->addrs[2].address, 0x100);
1142 if (chip->model <= PMAC_BURGUNDY) {
1143 if (request_irq(np->intrs[0].line, snd_pmac_ctrl_intr, 0,
1144 "PMac", (void*)chip)) {
1145 snd_printk(KERN_ERR "pmac: unable to grab IRQ %d\n", np->intrs[0].line);
1146 err = -EBUSY;
1147 goto __error;
1148 }
1149 chip->irq = np->intrs[0].line;
1150 }
1151 if (request_irq(np->intrs[1].line, snd_pmac_tx_intr, 0,
1152 "PMac Output", (void*)chip)) {
1153 snd_printk(KERN_ERR "pmac: unable to grab IRQ %d\n", np->intrs[1].line);
1154 err = -EBUSY;
1155 goto __error;
1156 }
1157 chip->tx_irq = np->intrs[1].line;
1158 if (request_irq(np->intrs[2].line, snd_pmac_rx_intr, 0,
1159 "PMac Input", (void*)chip)) {
1160 snd_printk(KERN_ERR "pmac: unable to grab IRQ %d\n", np->intrs[2].line);
1161 err = -EBUSY;
1162 goto __error;
1163 }
1164 chip->rx_irq = np->intrs[2].line;
1165
1166 snd_pmac_sound_feature(chip, 1);
1167
1168 /* reset */
1169 out_le32(&chip->awacs->control, 0x11);
1170
1171 /* Powerbooks have odd ways of enabling inputs such as
1172 an expansion-bay CD or sound from an internal modem
1173 or a PC-card modem. */
1174 if (chip->is_pbook_3400) {
1175 /* Enable CD and PC-card sound inputs. */
1176 /* This is done by reading from address
1177 * f301a000, + 0x10 to enable the expansion-bay
1178 * CD sound input, + 0x80 to enable the PC-card
1179 * sound input. The 0x100 enables the SCSI bus
1180 * terminator power.
1181 */
1182 chip->latch_base = ioremap (0xf301a000, 0x1000);
1183 in_8(chip->latch_base + 0x190);
1184 } else if (chip->is_pbook_G3) {
1185 struct device_node* mio;
1186 for (mio = chip->node->parent; mio; mio = mio->parent) {
1187 if (strcmp(mio->name, "mac-io") == 0
1188 && mio->n_addrs > 0) {
1189 chip->macio_base = ioremap(mio->addrs[0].address, 0x40);
1190 break;
1191 }
1192 }
1193 /* Enable CD sound input. */
1194 /* The relevant bits for writing to this byte are 0x8f.
1195 * I haven't found out what the 0x80 bit does.
1196 * For the 0xf bits, writing 3 or 7 enables the CD
1197 * input, any other value disables it. Values
1198 * 1, 3, 5, 7 enable the microphone. Values 0, 2,
1199 * 4, 6, 8 - f enable the input from the modem.
1200 */
1201 if (chip->macio_base)
1202 out_8(chip->macio_base + 0x37, 3);
1203 }
1204
1205 /* Reset dbdma channels */
1206 snd_pmac_dbdma_reset(chip);
1207
1208#if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK)
1209 /* add sleep notifier */
1210 if (! snd_pmac_register_sleep_notifier(chip))
1211 snd_card_set_pm_callback(chip->card, snd_pmac_suspend, snd_pmac_resume, chip);
1212#endif
1213
1214 if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0)
1215 goto __error;
1216
1217 *chip_return = chip;
1218 return 0;
1219
1220 __error:
1221 snd_pmac_free(chip);
1222 return err;
1223}
1224
1225
1226/*
1227 * sleep notify for powerbook
1228 */
1229
1230#if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK)
1231
1232/*
1233 * Save state when going to sleep, restore it afterwards.
1234 */
1235
1236static int snd_pmac_suspend(snd_card_t *card, pm_message_t state)
1237{
1238 pmac_t *chip = card->pm_private_data;
1239 unsigned long flags;
1240
1241 if (chip->suspend)
1242 chip->suspend(chip);
1243 snd_pcm_suspend_all(chip->pcm);
1244 spin_lock_irqsave(&chip->reg_lock, flags);
1245 snd_pmac_beep_stop(chip);
1246 spin_unlock_irqrestore(&chip->reg_lock, flags);
1247 if (chip->irq >= 0)
1248 disable_irq(chip->irq);
1249 if (chip->tx_irq >= 0)
1250 disable_irq(chip->tx_irq);
1251 if (chip->rx_irq >= 0)
1252 disable_irq(chip->rx_irq);
1253 snd_pmac_sound_feature(chip, 0);
1254 return 0;
1255}
1256
1257static int snd_pmac_resume(snd_card_t *card)
1258{
1259 pmac_t *chip = card->pm_private_data;
1260
1261 snd_pmac_sound_feature(chip, 1);
1262 if (chip->resume)
1263 chip->resume(chip);
1264 /* enable CD sound input */
1265 if (chip->macio_base && chip->is_pbook_G3) {
1266 out_8(chip->macio_base + 0x37, 3);
1267 } else if (chip->is_pbook_3400) {
1268 in_8(chip->latch_base + 0x190);
1269 }
1270
1271 snd_pmac_pcm_set_format(chip);
1272
1273 if (chip->irq >= 0)
1274 enable_irq(chip->irq);
1275 if (chip->tx_irq >= 0)
1276 enable_irq(chip->tx_irq);
1277 if (chip->rx_irq >= 0)
1278 enable_irq(chip->rx_irq);
1279
1280 return 0;
1281}
1282
1283/* the chip is stored statically by snd_pmac_register_sleep_notifier
1284 * because we can't have any private data for notify callback.
1285 */
1286static pmac_t *sleeping_pmac = NULL;
1287
1288static int snd_pmac_sleep_notify(struct pmu_sleep_notifier *self, int when)
1289{
1290 pmac_t *chip;
1291
1292 chip = sleeping_pmac;
1293 snd_runtime_check(chip, return 0);
1294
1295 switch (when) {
1296 case PBOOK_SLEEP_NOW:
1297 snd_pmac_suspend(chip->card, PMSG_SUSPEND);
1298 break;
1299 case PBOOK_WAKE:
1300 snd_pmac_resume(chip->card);
1301 break;
1302 }
1303 return PBOOK_SLEEP_OK;
1304}
1305
1306static struct pmu_sleep_notifier snd_pmac_sleep_notifier = {
1307 snd_pmac_sleep_notify, SLEEP_LEVEL_SOUND,
1308};
1309
1310static int __init snd_pmac_register_sleep_notifier(pmac_t *chip)
1311{
1312 /* should be protected here.. */
1313 snd_assert(! sleeping_pmac, return -EBUSY);
1314 sleeping_pmac = chip;
1315 pmu_register_sleep_notifier(&snd_pmac_sleep_notifier);
1316 return 0;
1317}
1318
1319static int snd_pmac_unregister_sleep_notifier(pmac_t *chip)
1320{
1321 /* should be protected here.. */
1322 snd_assert(sleeping_pmac == chip, return -ENODEV);
1323 pmu_unregister_sleep_notifier(&snd_pmac_sleep_notifier);
1324 sleeping_pmac = NULL;
1325 return 0;
1326}
1327
1328#endif /* CONFIG_PM && CONFIG_PMAC_PBOOK */
diff --git a/sound/ppc/pmac.h b/sound/ppc/pmac.h
new file mode 100644
index 000000000000..a699b01210ee
--- /dev/null
+++ b/sound/ppc/pmac.h
@@ -0,0 +1,214 @@
1/*
2 * Driver for PowerMac onboard soundchips
3 * Copyright (c) 2001 by Takashi Iwai <tiwai@suse.de>
4 * based on dmasound.c.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21
22#ifndef __PMAC_H
23#define __PMAC_H
24
25#include <linux/version.h>
26#include <sound/control.h>
27#include <sound/pcm.h>
28#include "awacs.h"
29
30#include <linux/adb.h>
31#ifdef CONFIG_ADB_CUDA
32#include <linux/cuda.h>
33#endif
34#ifdef CONFIG_ADB_PMU
35#include <linux/pmu.h>
36#endif
37#include <linux/nvram.h>
38#include <linux/tty.h>
39#include <linux/vt_kern.h>
40#include <asm/dbdma.h>
41#include <asm/prom.h>
42#include <asm/machdep.h>
43
44/* maximum number of fragments */
45#define PMAC_MAX_FRAGS 32
46
47
48#define PMAC_SUPPORT_AUTOMUTE
49
50/*
51 * typedefs
52 */
53typedef struct snd_pmac pmac_t;
54typedef struct snd_pmac_stream pmac_stream_t;
55typedef struct snd_pmac_beep pmac_beep_t;
56typedef struct snd_pmac_dbdma pmac_dbdma_t;
57
58
59/*
60 * DBDMA space
61 */
62struct snd_pmac_dbdma {
63 unsigned long addr;
64 struct dbdma_cmd __iomem *cmds;
65 void *space;
66 int size;
67};
68
69/*
70 * playback/capture stream
71 */
72struct snd_pmac_stream {
73 int running; /* boolean */
74
75 int stream; /* PLAYBACK/CAPTURE */
76
77 int dma_size; /* in bytes */
78 int period_size; /* in bytes */
79 int buffer_size; /* in kbytes */
80 int nperiods, cur_period;
81
82 pmac_dbdma_t cmd;
83 volatile struct dbdma_regs __iomem *dma;
84
85 snd_pcm_substream_t *substream;
86
87 unsigned int cur_freqs; /* currently available frequencies */
88 unsigned int cur_formats; /* currently available formats */
89};
90
91
92/*
93 */
94
95enum snd_pmac_model {
96 PMAC_AWACS, PMAC_SCREAMER, PMAC_BURGUNDY, PMAC_DACA, PMAC_TUMBLER, PMAC_SNAPPER
97};
98
99struct snd_pmac {
100 snd_card_t *card;
101
102 /* h/w info */
103 struct device_node *node;
104 unsigned int revision;
105 unsigned int manufacturer;
106 unsigned int subframe;
107 unsigned int device_id;
108 enum snd_pmac_model model;
109
110 unsigned int has_iic : 1;
111 unsigned int is_pbook_3400 : 1;
112 unsigned int is_pbook_G3 : 1;
113
114 unsigned int can_byte_swap : 1;
115 unsigned int can_duplex : 1;
116 unsigned int can_capture : 1;
117
118 unsigned int auto_mute : 1;
119 unsigned int initialized : 1;
120 unsigned int feature_is_set : 1;
121
122 unsigned int of_requested;
123
124 int num_freqs;
125 int *freq_table;
126 unsigned int freqs_ok; /* bit flags */
127 unsigned int formats_ok; /* pcm hwinfo */
128 int active;
129 int rate_index;
130 int format; /* current format */
131
132 spinlock_t reg_lock;
133 volatile struct awacs_regs __iomem *awacs;
134 int awacs_reg[8]; /* register cache */
135 unsigned int hp_stat_mask;
136
137 unsigned char __iomem *latch_base;
138 unsigned char __iomem *macio_base;
139
140 pmac_stream_t playback;
141 pmac_stream_t capture;
142
143 pmac_dbdma_t extra_dma;
144
145 int irq, tx_irq, rx_irq;
146
147 snd_pcm_t *pcm;
148
149 pmac_beep_t *beep;
150
151 unsigned int control_mask; /* control mask */
152
153 /* mixer stuffs */
154 void *mixer_data;
155 void (*mixer_free)(pmac_t *);
156 snd_kcontrol_t *master_sw_ctl;
157 snd_kcontrol_t *speaker_sw_ctl;
158 snd_kcontrol_t *drc_sw_ctl; /* only used for tumbler -ReneR */
159 snd_kcontrol_t *hp_detect_ctl;
160
161 /* lowlevel callbacks */
162 void (*set_format)(pmac_t *chip);
163 void (*update_automute)(pmac_t *chip, int do_notify);
164 int (*detect_headphone)(pmac_t *chip);
165#ifdef CONFIG_PMAC_PBOOK
166 void (*suspend)(pmac_t *chip);
167 void (*resume)(pmac_t *chip);
168#endif
169
170};
171
172
173/* exported functions */
174int snd_pmac_new(snd_card_t *card, pmac_t **chip_return);
175int snd_pmac_pcm_new(pmac_t *chip);
176int snd_pmac_attach_beep(pmac_t *chip);
177void snd_pmac_detach_beep(pmac_t *chip);
178void snd_pmac_beep_stop(pmac_t *chip);
179unsigned int snd_pmac_rate_index(pmac_t *chip, pmac_stream_t *rec, unsigned int rate);
180
181void snd_pmac_beep_dma_start(pmac_t *chip, int bytes, unsigned long addr, int speed);
182void snd_pmac_beep_dma_stop(pmac_t *chip);
183
184/* initialize mixer */
185int snd_pmac_awacs_init(pmac_t *chip);
186int snd_pmac_burgundy_init(pmac_t *chip);
187int snd_pmac_daca_init(pmac_t *chip);
188int snd_pmac_tumbler_init(pmac_t *chip);
189int snd_pmac_tumbler_post_init(void);
190
191/* i2c functions */
192typedef struct snd_pmac_keywest {
193 int addr;
194 struct i2c_client *client;
195 int id;
196 int (*init_client)(struct snd_pmac_keywest *i2c);
197 char *name;
198} pmac_keywest_t;
199
200int snd_pmac_keywest_init(pmac_keywest_t *i2c);
201void snd_pmac_keywest_cleanup(pmac_keywest_t *i2c);
202
203/* misc */
204int snd_pmac_boolean_stereo_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo);
205int snd_pmac_boolean_mono_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo);
206
207int snd_pmac_add_automute(pmac_t *chip);
208
209#define big_mdelay(msec) do {\
210 set_current_state(TASK_UNINTERRUPTIBLE);\
211 schedule_timeout(((msec) * HZ + 999) / 1000);\
212} while (0)
213
214#endif /* __PMAC_H */
diff --git a/sound/ppc/powermac.c b/sound/ppc/powermac.c
new file mode 100644
index 000000000000..8f1953a8e290
--- /dev/null
+++ b/sound/ppc/powermac.c
@@ -0,0 +1,159 @@
1/*
2 * Driver for PowerMac AWACS
3 * Copyright (c) 2001 by Takashi Iwai <tiwai@suse.de>
4 * based on dmasound.c.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include <sound/driver.h>
22#include <linux/init.h>
23#include <linux/moduleparam.h>
24#include <sound/core.h>
25#include <sound/initval.h>
26#include "pmac.h"
27#include "awacs.h"
28#include "burgundy.h"
29
30#define CHIP_NAME "PMac"
31
32MODULE_DESCRIPTION("PowerMac");
33MODULE_SUPPORTED_DEVICE("{{Apple,PowerMac}}");
34MODULE_LICENSE("GPL");
35
36static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
37static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */
38static int enable_beep = 1;
39
40module_param(index, int, 0444);
41MODULE_PARM_DESC(index, "Index value for " CHIP_NAME " soundchip.");
42module_param(id, charp, 0444);
43MODULE_PARM_DESC(id, "ID string for " CHIP_NAME " soundchip.");
44module_param(enable_beep, bool, 0444);
45MODULE_PARM_DESC(enable_beep, "Enable beep using PCM.");
46
47
48/*
49 * card entry
50 */
51
52static snd_card_t *snd_pmac_card = NULL;
53
54/*
55 */
56
57static int __init snd_pmac_probe(void)
58{
59 snd_card_t *card;
60 pmac_t *chip;
61 char *name_ext;
62 int err;
63
64 card = snd_card_new(index, id, THIS_MODULE, 0);
65 if (card == NULL)
66 return -ENOMEM;
67
68 if ((err = snd_pmac_new(card, &chip)) < 0)
69 goto __error;
70
71 switch (chip->model) {
72 case PMAC_BURGUNDY:
73 strcpy(card->driver, "PMac Burgundy");
74 strcpy(card->shortname, "PowerMac Burgundy");
75 sprintf(card->longname, "%s (Dev %d) Sub-frame %d",
76 card->shortname, chip->device_id, chip->subframe);
77 if ((err = snd_pmac_burgundy_init(chip)) < 0)
78 goto __error;
79 break;
80 case PMAC_DACA:
81 strcpy(card->driver, "PMac DACA");
82 strcpy(card->shortname, "PowerMac DACA");
83 sprintf(card->longname, "%s (Dev %d) Sub-frame %d",
84 card->shortname, chip->device_id, chip->subframe);
85 if ((err = snd_pmac_daca_init(chip)) < 0)
86 goto __error;
87 break;
88 case PMAC_TUMBLER:
89 case PMAC_SNAPPER:
90 name_ext = chip->model == PMAC_TUMBLER ? "Tumbler" : "Snapper";
91 sprintf(card->driver, "PMac %s", name_ext);
92 sprintf(card->shortname, "PowerMac %s", name_ext);
93 sprintf(card->longname, "%s (Dev %d) Sub-frame %d",
94 card->shortname, chip->device_id, chip->subframe);
95 if ( snd_pmac_tumbler_init(chip) < 0 || snd_pmac_tumbler_post_init() < 0)
96 goto __error;
97 break;
98 case PMAC_AWACS:
99 case PMAC_SCREAMER:
100 name_ext = chip->model == PMAC_SCREAMER ? "Screamer" : "AWACS";
101 sprintf(card->driver, "PMac %s", name_ext);
102 sprintf(card->shortname, "PowerMac %s", name_ext);
103 if (chip->is_pbook_3400)
104 name_ext = " [PB3400]";
105 else if (chip->is_pbook_G3)
106 name_ext = " [PBG3]";
107 else
108 name_ext = "";
109 sprintf(card->longname, "%s%s Rev %d",
110 card->shortname, name_ext, chip->revision);
111 if ((err = snd_pmac_awacs_init(chip)) < 0)
112 goto __error;
113 break;
114 default:
115 snd_printk("unsupported hardware %d\n", chip->model);
116 err = -EINVAL;
117 goto __error;
118 }
119
120 if ((err = snd_pmac_pcm_new(chip)) < 0)
121 goto __error;
122
123 chip->initialized = 1;
124 if (enable_beep)
125 snd_pmac_attach_beep(chip);
126
127 if ((err = snd_card_register(card)) < 0)
128 goto __error;
129
130 snd_pmac_card = card;
131 return 0;
132
133__error:
134 snd_card_free(card);
135 return err;
136}
137
138
139/*
140 * MODULE stuff
141 */
142
143static int __init alsa_card_pmac_init(void)
144{
145 int err;
146 if ((err = snd_pmac_probe()) < 0)
147 return err;
148 return 0;
149
150}
151
152static void __exit alsa_card_pmac_exit(void)
153{
154 if (snd_pmac_card)
155 snd_card_free(snd_pmac_card);
156}
157
158module_init(alsa_card_pmac_init)
159module_exit(alsa_card_pmac_exit)
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
new file mode 100644
index 000000000000..7d10385f0a76
--- /dev/null
+++ b/sound/ppc/tumbler.c
@@ -0,0 +1,1175 @@
1/*
2 * PMac Tumbler/Snapper lowlevel functions
3 *
4 * Copyright (c) by Takashi Iwai <tiwai@suse.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 * Rene Rebe <rene.rebe@gmx.net>:
21 * * update from shadow registers on wakeup and headphone plug
22 * * automatically toggle DRC on headphone plug
23 *
24 */
25
26
27#include <sound/driver.h>
28#include <linux/init.h>
29#include <linux/delay.h>
30#include <linux/i2c.h>
31#include <linux/i2c-dev.h>
32#include <linux/kmod.h>
33#include <linux/slab.h>
34#include <linux/interrupt.h>
35#include <sound/core.h>
36#include <asm/io.h>
37#include <asm/irq.h>
38#ifdef CONFIG_PPC_HAS_FEATURE_CALLS
39#include <asm/pmac_feature.h>
40#endif
41#include "pmac.h"
42#include "tumbler_volume.h"
43
44/* i2c address for tumbler */
45#define TAS_I2C_ADDR 0x34
46
47/* registers */
48#define TAS_REG_MCS 0x01 /* main control */
49#define TAS_REG_DRC 0x02
50#define TAS_REG_VOL 0x04
51#define TAS_REG_TREBLE 0x05
52#define TAS_REG_BASS 0x06
53#define TAS_REG_INPUT1 0x07
54#define TAS_REG_INPUT2 0x08
55
56/* tas3001c */
57#define TAS_REG_PCM TAS_REG_INPUT1
58
59/* tas3004 */
60#define TAS_REG_LMIX TAS_REG_INPUT1
61#define TAS_REG_RMIX TAS_REG_INPUT2
62#define TAS_REG_MCS2 0x43 /* main control 2 */
63#define TAS_REG_ACS 0x40 /* analog control */
64
65/* mono volumes for tas3001c/tas3004 */
66enum {
67 VOL_IDX_PCM_MONO, /* tas3001c only */
68 VOL_IDX_BASS, VOL_IDX_TREBLE,
69 VOL_IDX_LAST_MONO
70};
71
72/* stereo volumes for tas3004 */
73enum {
74 VOL_IDX_PCM, VOL_IDX_PCM2, VOL_IDX_ADC,
75 VOL_IDX_LAST_MIX
76};
77
78typedef struct pmac_gpio {
79#ifdef CONFIG_PPC_HAS_FEATURE_CALLS
80 unsigned int addr;
81#else
82 void __iomem *addr;
83#endif
84 int active_state;
85} pmac_gpio_t;
86
87typedef struct pmac_tumbler_t {
88 pmac_keywest_t i2c;
89 pmac_gpio_t audio_reset;
90 pmac_gpio_t amp_mute;
91 pmac_gpio_t hp_mute;
92 pmac_gpio_t hp_detect;
93 int headphone_irq;
94 unsigned int master_vol[2];
95 unsigned int master_switch[2];
96 unsigned int mono_vol[VOL_IDX_LAST_MONO];
97 unsigned int mix_vol[VOL_IDX_LAST_MIX][2]; /* stereo volumes for tas3004 */
98 int drc_range;
99 int drc_enable;
100 int capture_source;
101} pmac_tumbler_t;
102
103
104/*
105 */
106
107static int send_init_client(pmac_keywest_t *i2c, unsigned int *regs)
108{
109 while (*regs > 0) {
110 int err, count = 10;
111 do {
112 err = i2c_smbus_write_byte_data(i2c->client,
113 regs[0], regs[1]);
114 if (err >= 0)
115 break;
116 mdelay(10);
117 } while (count--);
118 if (err < 0)
119 return -ENXIO;
120 regs += 2;
121 }
122 return 0;
123}
124
125
126static int tumbler_init_client(pmac_keywest_t *i2c)
127{
128 static unsigned int regs[] = {
129 /* normal operation, SCLK=64fps, i2s output, i2s input, 16bit width */
130 TAS_REG_MCS, (1<<6)|(2<<4)|(2<<2)|0,
131 0, /* terminator */
132 };
133 return send_init_client(i2c, regs);
134}
135
136static int snapper_init_client(pmac_keywest_t *i2c)
137{
138 static unsigned int regs[] = {
139 /* normal operation, SCLK=64fps, i2s output, 16bit width */
140 TAS_REG_MCS, (1<<6)|(2<<4)|0,
141 /* normal operation, all-pass mode */
142 TAS_REG_MCS2, (1<<1),
143 /* normal output, no deemphasis, A input, power-up, line-in */
144 TAS_REG_ACS, 0,
145 0, /* terminator */
146 };
147 return send_init_client(i2c, regs);
148}
149
150/*
151 * gpio access
152 */
153#ifdef CONFIG_PPC_HAS_FEATURE_CALLS
154#define do_gpio_write(gp, val) \
155 pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, (gp)->addr, val)
156#define do_gpio_read(gp) \
157 pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, (gp)->addr, 0)
158#define tumbler_gpio_free(gp) /* NOP */
159#else
160#define do_gpio_write(gp, val) writeb(val, (gp)->addr)
161#define do_gpio_read(gp) readb((gp)->addr)
162static inline void tumbler_gpio_free(pmac_gpio_t *gp)
163{
164 if (gp->addr) {
165 iounmap(gp->addr);
166 gp->addr = NULL;
167 }
168}
169#endif /* CONFIG_PPC_HAS_FEATURE_CALLS */
170
171static void write_audio_gpio(pmac_gpio_t *gp, int active)
172{
173 if (! gp->addr)
174 return;
175 active = active ? gp->active_state : !gp->active_state;
176 do_gpio_write(gp, active ? 0x05 : 0x04);
177}
178
179static int read_audio_gpio(pmac_gpio_t *gp)
180{
181 int ret;
182 if (! gp->addr)
183 return 0;
184 ret = ((do_gpio_read(gp) & 0x02) !=0);
185 return ret == gp->active_state;
186}
187
188/*
189 * update master volume
190 */
191static int tumbler_set_master_volume(pmac_tumbler_t *mix)
192{
193 unsigned char block[6];
194 unsigned int left_vol, right_vol;
195
196 if (! mix->i2c.client)
197 return -ENODEV;
198
199 if (! mix->master_switch[0])
200 left_vol = 0;
201 else {
202 left_vol = mix->master_vol[0];
203 if (left_vol >= ARRAY_SIZE(master_volume_table))
204 left_vol = ARRAY_SIZE(master_volume_table) - 1;
205 left_vol = master_volume_table[left_vol];
206 }
207 if (! mix->master_switch[1])
208 right_vol = 0;
209 else {
210 right_vol = mix->master_vol[1];
211 if (right_vol >= ARRAY_SIZE(master_volume_table))
212 right_vol = ARRAY_SIZE(master_volume_table) - 1;
213 right_vol = master_volume_table[right_vol];
214 }
215
216 block[0] = (left_vol >> 16) & 0xff;
217 block[1] = (left_vol >> 8) & 0xff;
218 block[2] = (left_vol >> 0) & 0xff;
219
220 block[3] = (right_vol >> 16) & 0xff;
221 block[4] = (right_vol >> 8) & 0xff;
222 block[5] = (right_vol >> 0) & 0xff;
223
224 if (i2c_smbus_write_block_data(mix->i2c.client, TAS_REG_VOL,
225 6, block) < 0) {
226 snd_printk("failed to set volume \n");
227 return -EINVAL;
228 }
229 return 0;
230}
231
232
233/* output volume */
234static int tumbler_info_master_volume(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
235{
236 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
237 uinfo->count = 2;
238 uinfo->value.integer.min = 0;
239 uinfo->value.integer.max = ARRAY_SIZE(master_volume_table) - 1;
240 return 0;
241}
242
243static int tumbler_get_master_volume(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
244{
245 pmac_t *chip = snd_kcontrol_chip(kcontrol);
246 pmac_tumbler_t *mix = chip->mixer_data;
247 snd_assert(mix, return -ENODEV);
248 ucontrol->value.integer.value[0] = mix->master_vol[0];
249 ucontrol->value.integer.value[1] = mix->master_vol[1];
250 return 0;
251}
252
253static int tumbler_put_master_volume(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
254{
255 pmac_t *chip = snd_kcontrol_chip(kcontrol);
256 pmac_tumbler_t *mix = chip->mixer_data;
257 int change;
258
259 snd_assert(mix, return -ENODEV);
260 change = mix->master_vol[0] != ucontrol->value.integer.value[0] ||
261 mix->master_vol[1] != ucontrol->value.integer.value[1];
262 if (change) {
263 mix->master_vol[0] = ucontrol->value.integer.value[0];
264 mix->master_vol[1] = ucontrol->value.integer.value[1];
265 tumbler_set_master_volume(mix);
266 }
267 return change;
268}
269
270/* output switch */
271static int tumbler_get_master_switch(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
272{
273 pmac_t *chip = snd_kcontrol_chip(kcontrol);
274 pmac_tumbler_t *mix = chip->mixer_data;
275 snd_assert(mix, return -ENODEV);
276 ucontrol->value.integer.value[0] = mix->master_switch[0];
277 ucontrol->value.integer.value[1] = mix->master_switch[1];
278 return 0;
279}
280
281static int tumbler_put_master_switch(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
282{
283 pmac_t *chip = snd_kcontrol_chip(kcontrol);
284 pmac_tumbler_t *mix = chip->mixer_data;
285 int change;
286
287 snd_assert(mix, return -ENODEV);
288 change = mix->master_switch[0] != ucontrol->value.integer.value[0] ||
289 mix->master_switch[1] != ucontrol->value.integer.value[1];
290 if (change) {
291 mix->master_switch[0] = !!ucontrol->value.integer.value[0];
292 mix->master_switch[1] = !!ucontrol->value.integer.value[1];
293 tumbler_set_master_volume(mix);
294 }
295 return change;
296}
297
298
299/*
300 * TAS3001c dynamic range compression
301 */
302
303#define TAS3001_DRC_MAX 0x5f
304
305static int tumbler_set_drc(pmac_tumbler_t *mix)
306{
307 unsigned char val[2];
308
309 if (! mix->i2c.client)
310 return -ENODEV;
311
312 if (mix->drc_enable) {
313 val[0] = 0xc1; /* enable, 3:1 compression */
314 if (mix->drc_range > TAS3001_DRC_MAX)
315 val[1] = 0xf0;
316 else if (mix->drc_range < 0)
317 val[1] = 0x91;
318 else
319 val[1] = mix->drc_range + 0x91;
320 } else {
321 val[0] = 0;
322 val[1] = 0;
323 }
324
325 if (i2c_smbus_write_block_data(mix->i2c.client, TAS_REG_DRC,
326 2, val) < 0) {
327 snd_printk("failed to set DRC\n");
328 return -EINVAL;
329 }
330 return 0;
331}
332
333/*
334 * TAS3004
335 */
336
337#define TAS3004_DRC_MAX 0xef
338
339static int snapper_set_drc(pmac_tumbler_t *mix)
340{
341 unsigned char val[6];
342
343 if (! mix->i2c.client)
344 return -ENODEV;
345
346 if (mix->drc_enable)
347 val[0] = 0x50; /* 3:1 above threshold */
348 else
349 val[0] = 0x51; /* disabled */
350 val[1] = 0x02; /* 1:1 below threshold */
351 if (mix->drc_range > 0xef)
352 val[2] = 0xef;
353 else if (mix->drc_range < 0)
354 val[2] = 0x00;
355 else
356 val[2] = mix->drc_range;
357 val[3] = 0xb0;
358 val[4] = 0x60;
359 val[5] = 0xa0;
360
361 if (i2c_smbus_write_block_data(mix->i2c.client, TAS_REG_DRC,
362 6, val) < 0) {
363 snd_printk("failed to set DRC\n");
364 return -EINVAL;
365 }
366 return 0;
367}
368
369static int tumbler_info_drc_value(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
370{
371 pmac_t *chip = snd_kcontrol_chip(kcontrol);
372 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
373 uinfo->count = 1;
374 uinfo->value.integer.min = 0;
375 uinfo->value.integer.max =
376 chip->model == PMAC_TUMBLER ? TAS3001_DRC_MAX : TAS3004_DRC_MAX;
377 return 0;
378}
379
380static int tumbler_get_drc_value(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
381{
382 pmac_t *chip = snd_kcontrol_chip(kcontrol);
383 pmac_tumbler_t *mix;
384 if (! (mix = chip->mixer_data))
385 return -ENODEV;
386 ucontrol->value.integer.value[0] = mix->drc_range;
387 return 0;
388}
389
390static int tumbler_put_drc_value(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
391{
392 pmac_t *chip = snd_kcontrol_chip(kcontrol);
393 pmac_tumbler_t *mix;
394 int change;
395
396 if (! (mix = chip->mixer_data))
397 return -ENODEV;
398 change = mix->drc_range != ucontrol->value.integer.value[0];
399 if (change) {
400 mix->drc_range = ucontrol->value.integer.value[0];
401 if (chip->model == PMAC_TUMBLER)
402 tumbler_set_drc(mix);
403 else
404 snapper_set_drc(mix);
405 }
406 return change;
407}
408
409static int tumbler_get_drc_switch(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
410{
411 pmac_t *chip = snd_kcontrol_chip(kcontrol);
412 pmac_tumbler_t *mix;
413 if (! (mix = chip->mixer_data))
414 return -ENODEV;
415 ucontrol->value.integer.value[0] = mix->drc_enable;
416 return 0;
417}
418
419static int tumbler_put_drc_switch(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
420{
421 pmac_t *chip = snd_kcontrol_chip(kcontrol);
422 pmac_tumbler_t *mix;
423 int change;
424
425 if (! (mix = chip->mixer_data))
426 return -ENODEV;
427 change = mix->drc_enable != ucontrol->value.integer.value[0];
428 if (change) {
429 mix->drc_enable = !!ucontrol->value.integer.value[0];
430 if (chip->model == PMAC_TUMBLER)
431 tumbler_set_drc(mix);
432 else
433 snapper_set_drc(mix);
434 }
435 return change;
436}
437
438
439/*
440 * mono volumes
441 */
442
443struct tumbler_mono_vol {
444 int index;
445 int reg;
446 int bytes;
447 unsigned int max;
448 unsigned int *table;
449};
450
451static int tumbler_set_mono_volume(pmac_tumbler_t *mix, struct tumbler_mono_vol *info)
452{
453 unsigned char block[4];
454 unsigned int vol;
455 int i;
456
457 if (! mix->i2c.client)
458 return -ENODEV;
459
460 vol = mix->mono_vol[info->index];
461 if (vol >= info->max)
462 vol = info->max - 1;
463 vol = info->table[vol];
464 for (i = 0; i < info->bytes; i++)
465 block[i] = (vol >> ((info->bytes - i - 1) * 8)) & 0xff;
466 if (i2c_smbus_write_block_data(mix->i2c.client, info->reg,
467 info->bytes, block) < 0) {
468 snd_printk("failed to set mono volume %d\n", info->index);
469 return -EINVAL;
470 }
471 return 0;
472}
473
474static int tumbler_info_mono(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
475{
476 struct tumbler_mono_vol *info = (struct tumbler_mono_vol *)kcontrol->private_value;
477
478 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
479 uinfo->count = 1;
480 uinfo->value.integer.min = 0;
481 uinfo->value.integer.max = info->max - 1;
482 return 0;
483}
484
485static int tumbler_get_mono(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
486{
487 struct tumbler_mono_vol *info = (struct tumbler_mono_vol *)kcontrol->private_value;
488 pmac_t *chip = snd_kcontrol_chip(kcontrol);
489 pmac_tumbler_t *mix;
490 if (! (mix = chip->mixer_data))
491 return -ENODEV;
492 ucontrol->value.integer.value[0] = mix->mono_vol[info->index];
493 return 0;
494}
495
496static int tumbler_put_mono(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
497{
498 struct tumbler_mono_vol *info = (struct tumbler_mono_vol *)kcontrol->private_value;
499 pmac_t *chip = snd_kcontrol_chip(kcontrol);
500 pmac_tumbler_t *mix;
501 int change;
502
503 if (! (mix = chip->mixer_data))
504 return -ENODEV;
505 change = mix->mono_vol[info->index] != ucontrol->value.integer.value[0];
506 if (change) {
507 mix->mono_vol[info->index] = ucontrol->value.integer.value[0];
508 tumbler_set_mono_volume(mix, info);
509 }
510 return change;
511}
512
513/* TAS3001c mono volumes */
514static struct tumbler_mono_vol tumbler_pcm_vol_info = {
515 .index = VOL_IDX_PCM_MONO,
516 .reg = TAS_REG_PCM,
517 .bytes = 3,
518 .max = ARRAY_SIZE(mixer_volume_table),
519 .table = mixer_volume_table,
520};
521
522static struct tumbler_mono_vol tumbler_bass_vol_info = {
523 .index = VOL_IDX_BASS,
524 .reg = TAS_REG_BASS,
525 .bytes = 1,
526 .max = ARRAY_SIZE(bass_volume_table),
527 .table = bass_volume_table,
528};
529
530static struct tumbler_mono_vol tumbler_treble_vol_info = {
531 .index = VOL_IDX_TREBLE,
532 .reg = TAS_REG_TREBLE,
533 .bytes = 1,
534 .max = ARRAY_SIZE(treble_volume_table),
535 .table = treble_volume_table,
536};
537
538/* TAS3004 mono volumes */
539static struct tumbler_mono_vol snapper_bass_vol_info = {
540 .index = VOL_IDX_BASS,
541 .reg = TAS_REG_BASS,
542 .bytes = 1,
543 .max = ARRAY_SIZE(snapper_bass_volume_table),
544 .table = snapper_bass_volume_table,
545};
546
547static struct tumbler_mono_vol snapper_treble_vol_info = {
548 .index = VOL_IDX_TREBLE,
549 .reg = TAS_REG_TREBLE,
550 .bytes = 1,
551 .max = ARRAY_SIZE(snapper_treble_volume_table),
552 .table = snapper_treble_volume_table,
553};
554
555
556#define DEFINE_MONO(xname,type) { \
557 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,\
558 .name = xname, \
559 .info = tumbler_info_mono, \
560 .get = tumbler_get_mono, \
561 .put = tumbler_put_mono, \
562 .private_value = (unsigned long)(&tumbler_##type##_vol_info), \
563}
564
565#define DEFINE_SNAPPER_MONO(xname,type) { \
566 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,\
567 .name = xname, \
568 .info = tumbler_info_mono, \
569 .get = tumbler_get_mono, \
570 .put = tumbler_put_mono, \
571 .private_value = (unsigned long)(&snapper_##type##_vol_info), \
572}
573
574
575/*
576 * snapper mixer volumes
577 */
578
579static int snapper_set_mix_vol1(pmac_tumbler_t *mix, int idx, int ch, int reg)
580{
581 int i, j, vol;
582 unsigned char block[9];
583
584 vol = mix->mix_vol[idx][ch];
585 if (vol >= ARRAY_SIZE(mixer_volume_table)) {
586 vol = ARRAY_SIZE(mixer_volume_table) - 1;
587 mix->mix_vol[idx][ch] = vol;
588 }
589
590 for (i = 0; i < 3; i++) {
591 vol = mix->mix_vol[i][ch];
592 vol = mixer_volume_table[vol];
593 for (j = 0; j < 3; j++)
594 block[i * 3 + j] = (vol >> ((2 - j) * 8)) & 0xff;
595 }
596 if (i2c_smbus_write_block_data(mix->i2c.client, reg, 9, block) < 0) {
597 snd_printk("failed to set mono volume %d\n", reg);
598 return -EINVAL;
599 }
600 return 0;
601}
602
603static int snapper_set_mix_vol(pmac_tumbler_t *mix, int idx)
604{
605 if (! mix->i2c.client)
606 return -ENODEV;
607 if (snapper_set_mix_vol1(mix, idx, 0, TAS_REG_LMIX) < 0 ||
608 snapper_set_mix_vol1(mix, idx, 1, TAS_REG_RMIX) < 0)
609 return -EINVAL;
610 return 0;
611}
612
613static int snapper_info_mix(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
614{
615 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
616 uinfo->count = 2;
617 uinfo->value.integer.min = 0;
618 uinfo->value.integer.max = ARRAY_SIZE(mixer_volume_table) - 1;
619 return 0;
620}
621
622static int snapper_get_mix(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
623{
624 int idx = (int)kcontrol->private_value;
625 pmac_t *chip = snd_kcontrol_chip(kcontrol);
626 pmac_tumbler_t *mix;
627 if (! (mix = chip->mixer_data))
628 return -ENODEV;
629 ucontrol->value.integer.value[0] = mix->mix_vol[idx][0];
630 ucontrol->value.integer.value[1] = mix->mix_vol[idx][1];
631 return 0;
632}
633
634static int snapper_put_mix(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
635{
636 int idx = (int)kcontrol->private_value;
637 pmac_t *chip = snd_kcontrol_chip(kcontrol);
638 pmac_tumbler_t *mix;
639 int change;
640
641 if (! (mix = chip->mixer_data))
642 return -ENODEV;
643 change = mix->mix_vol[idx][0] != ucontrol->value.integer.value[0] ||
644 mix->mix_vol[idx][1] != ucontrol->value.integer.value[1];
645 if (change) {
646 mix->mix_vol[idx][0] = ucontrol->value.integer.value[0];
647 mix->mix_vol[idx][1] = ucontrol->value.integer.value[1];
648 snapper_set_mix_vol(mix, idx);
649 }
650 return change;
651}
652
653
654/*
655 * mute switches
656 */
657
658enum { TUMBLER_MUTE_HP, TUMBLER_MUTE_AMP };
659
660static int tumbler_get_mute_switch(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
661{
662 pmac_t *chip = snd_kcontrol_chip(kcontrol);
663 pmac_tumbler_t *mix;
664 pmac_gpio_t *gp;
665 if (! (mix = chip->mixer_data))
666 return -ENODEV;
667 gp = (kcontrol->private_value == TUMBLER_MUTE_HP) ? &mix->hp_mute : &mix->amp_mute;
668 ucontrol->value.integer.value[0] = ! read_audio_gpio(gp);
669 return 0;
670}
671
672static int tumbler_put_mute_switch(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
673{
674 pmac_t *chip = snd_kcontrol_chip(kcontrol);
675 pmac_tumbler_t *mix;
676 pmac_gpio_t *gp;
677 int val;
678#ifdef PMAC_SUPPORT_AUTOMUTE
679 if (chip->update_automute && chip->auto_mute)
680 return 0; /* don't touch in the auto-mute mode */
681#endif
682 if (! (mix = chip->mixer_data))
683 return -ENODEV;
684 gp = (kcontrol->private_value == TUMBLER_MUTE_HP) ? &mix->hp_mute : &mix->amp_mute;
685 val = ! read_audio_gpio(gp);
686 if (val != ucontrol->value.integer.value[0]) {
687 write_audio_gpio(gp, ! ucontrol->value.integer.value[0]);
688 return 1;
689 }
690 return 0;
691}
692
693static int snapper_set_capture_source(pmac_tumbler_t *mix)
694{
695 if (! mix->i2c.client)
696 return -ENODEV;
697 return i2c_smbus_write_byte_data(mix->i2c.client, TAS_REG_ACS,
698 mix->capture_source ? 2 : 0);
699}
700
701static int snapper_info_capture_source(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
702{
703 static char *texts[2] = {
704 "Line", "Mic"
705 };
706 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
707 uinfo->count = 1;
708 uinfo->value.enumerated.items = 2;
709 if (uinfo->value.enumerated.item > 1)
710 uinfo->value.enumerated.item = 1;
711 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
712 return 0;
713}
714
715static int snapper_get_capture_source(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
716{
717 pmac_t *chip = snd_kcontrol_chip(kcontrol);
718 pmac_tumbler_t *mix = chip->mixer_data;
719
720 snd_assert(mix, return -ENODEV);
721 ucontrol->value.integer.value[0] = mix->capture_source;
722 return 0;
723}
724
725static int snapper_put_capture_source(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
726{
727 pmac_t *chip = snd_kcontrol_chip(kcontrol);
728 pmac_tumbler_t *mix = chip->mixer_data;
729 int change;
730
731 snd_assert(mix, return -ENODEV);
732 change = ucontrol->value.integer.value[0] != mix->capture_source;
733 if (change) {
734 mix->capture_source = !!ucontrol->value.integer.value[0];
735 snapper_set_capture_source(mix);
736 }
737 return change;
738}
739
740#define DEFINE_SNAPPER_MIX(xname,idx,ofs) { \
741 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,\
742 .name = xname, \
743 .info = snapper_info_mix, \
744 .get = snapper_get_mix, \
745 .put = snapper_put_mix, \
746 .index = idx,\
747 .private_value = ofs, \
748}
749
750
751/*
752 */
753static snd_kcontrol_new_t tumbler_mixers[] __initdata = {
754 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
755 .name = "Master Playback Volume",
756 .info = tumbler_info_master_volume,
757 .get = tumbler_get_master_volume,
758 .put = tumbler_put_master_volume
759 },
760 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
761 .name = "Master Playback Switch",
762 .info = snd_pmac_boolean_stereo_info,
763 .get = tumbler_get_master_switch,
764 .put = tumbler_put_master_switch
765 },
766 DEFINE_MONO("Tone Control - Bass", bass),
767 DEFINE_MONO("Tone Control - Treble", treble),
768 DEFINE_MONO("PCM Playback Volume", pcm),
769 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
770 .name = "DRC Range",
771 .info = tumbler_info_drc_value,
772 .get = tumbler_get_drc_value,
773 .put = tumbler_put_drc_value
774 },
775};
776
777static snd_kcontrol_new_t snapper_mixers[] __initdata = {
778 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
779 .name = "Master Playback Volume",
780 .info = tumbler_info_master_volume,
781 .get = tumbler_get_master_volume,
782 .put = tumbler_put_master_volume
783 },
784 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
785 .name = "Master Playback Switch",
786 .info = snd_pmac_boolean_stereo_info,
787 .get = tumbler_get_master_switch,
788 .put = tumbler_put_master_switch
789 },
790 DEFINE_SNAPPER_MIX("PCM Playback Volume", 0, VOL_IDX_PCM),
791 DEFINE_SNAPPER_MIX("PCM Playback Volume", 1, VOL_IDX_PCM2),
792 DEFINE_SNAPPER_MIX("Monitor Mix Volume", 0, VOL_IDX_ADC),
793 DEFINE_SNAPPER_MONO("Tone Control - Bass", bass),
794 DEFINE_SNAPPER_MONO("Tone Control - Treble", treble),
795 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
796 .name = "DRC Range",
797 .info = tumbler_info_drc_value,
798 .get = tumbler_get_drc_value,
799 .put = tumbler_put_drc_value
800 },
801 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
802 .name = "Input Source", /* FIXME: "Capture Source" doesn't work properly */
803 .info = snapper_info_capture_source,
804 .get = snapper_get_capture_source,
805 .put = snapper_put_capture_source
806 },
807};
808
809static snd_kcontrol_new_t tumbler_hp_sw __initdata = {
810 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
811 .name = "Headphone Playback Switch",
812 .info = snd_pmac_boolean_mono_info,
813 .get = tumbler_get_mute_switch,
814 .put = tumbler_put_mute_switch,
815 .private_value = TUMBLER_MUTE_HP,
816};
817static snd_kcontrol_new_t tumbler_speaker_sw __initdata = {
818 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
819 .name = "PC Speaker Playback Switch",
820 .info = snd_pmac_boolean_mono_info,
821 .get = tumbler_get_mute_switch,
822 .put = tumbler_put_mute_switch,
823 .private_value = TUMBLER_MUTE_AMP,
824};
825static snd_kcontrol_new_t tumbler_drc_sw __initdata = {
826 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
827 .name = "DRC Switch",
828 .info = snd_pmac_boolean_mono_info,
829 .get = tumbler_get_drc_switch,
830 .put = tumbler_put_drc_switch
831};
832
833
834#ifdef PMAC_SUPPORT_AUTOMUTE
835/*
836 * auto-mute stuffs
837 */
838static int tumbler_detect_headphone(pmac_t *chip)
839{
840 pmac_tumbler_t *mix = chip->mixer_data;
841 return read_audio_gpio(&mix->hp_detect);
842}
843
844static void check_mute(pmac_t *chip, pmac_gpio_t *gp, int val, int do_notify, snd_kcontrol_t *sw)
845{
846 //pmac_tumbler_t *mix = chip->mixer_data;
847 if (val != read_audio_gpio(gp)) {
848 write_audio_gpio(gp, val);
849 if (do_notify)
850 snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &sw->id);
851 }
852}
853
854static struct work_struct device_change;
855
856static void
857device_change_handler(void *self)
858{
859 pmac_t *chip = (pmac_t*) self;
860 pmac_tumbler_t *mix;
861
862 if (!chip)
863 return;
864
865 mix = chip->mixer_data;
866
867 /* first set the DRC so the speaker do not explode -ReneR */
868 if (chip->model == PMAC_TUMBLER)
869 tumbler_set_drc(mix);
870 else
871 snapper_set_drc(mix);
872
873 /* reset the master volume so the correct amplification is applied */
874 tumbler_set_master_volume(mix);
875}
876
877static void tumbler_update_automute(pmac_t *chip, int do_notify)
878{
879 if (chip->auto_mute) {
880 pmac_tumbler_t *mix = chip->mixer_data;
881 snd_assert(mix, return);
882 if (tumbler_detect_headphone(chip)) {
883 /* mute speaker */
884 check_mute(chip, &mix->amp_mute, 1, do_notify, chip->speaker_sw_ctl);
885 check_mute(chip, &mix->hp_mute, 0, do_notify, chip->master_sw_ctl);
886 mix->drc_enable = 0;
887
888 } else {
889 /* unmute speaker */
890 check_mute(chip, &mix->amp_mute, 0, do_notify, chip->speaker_sw_ctl);
891 check_mute(chip, &mix->hp_mute, 1, do_notify, chip->master_sw_ctl);
892 mix->drc_enable = 1;
893 }
894 if (do_notify) {
895 snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
896 &chip->hp_detect_ctl->id);
897 snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
898 &chip->drc_sw_ctl->id);
899 }
900
901 /* finally we need to schedule an update of the mixer values
902 (master and DRC are enough for now) -ReneR */
903 schedule_work(&device_change);
904
905 }
906}
907#endif /* PMAC_SUPPORT_AUTOMUTE */
908
909
910/* interrupt - headphone plug changed */
911static irqreturn_t headphone_intr(int irq, void *devid, struct pt_regs *regs)
912{
913 pmac_t *chip = devid;
914 if (chip->update_automute && chip->initialized) {
915 chip->update_automute(chip, 1);
916 return IRQ_HANDLED;
917 }
918 return IRQ_NONE;
919}
920
921/* look for audio-gpio device */
922static struct device_node *find_audio_device(const char *name)
923{
924 struct device_node *np;
925
926 if (! (np = find_devices("gpio")))
927 return NULL;
928
929 for (np = np->child; np; np = np->sibling) {
930 char *property = get_property(np, "audio-gpio", NULL);
931 if (property && strcmp(property, name) == 0)
932 return np;
933 }
934 return NULL;
935}
936
937/* look for audio-gpio device */
938static struct device_node *find_compatible_audio_device(const char *name)
939{
940 struct device_node *np;
941
942 if (! (np = find_devices("gpio")))
943 return NULL;
944
945 for (np = np->child; np; np = np->sibling) {
946 if (device_is_compatible(np, name))
947 return np;
948 }
949 return NULL;
950}
951
952/* find an audio device and get its address */
953static unsigned long tumbler_find_device(const char *device, pmac_gpio_t *gp, int is_compatible)
954{
955 struct device_node *node;
956 u32 *base;
957
958 if (is_compatible)
959 node = find_compatible_audio_device(device);
960 else
961 node = find_audio_device(device);
962 if (! node) {
963 snd_printdd("cannot find device %s\n", device);
964 return -ENODEV;
965 }
966
967 base = (u32 *)get_property(node, "AAPL,address", NULL);
968 if (! base) {
969 snd_printd("cannot find address for device %s\n", device);
970 return -ENODEV;
971 }
972
973#ifdef CONFIG_PPC_HAS_FEATURE_CALLS
974 gp->addr = (*base) & 0x0000ffff;
975#else
976 gp->addr = ioremap((unsigned long)(*base), 1);
977#endif
978 base = (u32 *)get_property(node, "audio-gpio-active-state", NULL);
979 if (base)
980 gp->active_state = *base;
981 else
982 gp->active_state = 1;
983
984
985 return (node->n_intrs > 0) ? node->intrs[0].line : 0;
986}
987
988/* reset audio */
989static void tumbler_reset_audio(pmac_t *chip)
990{
991 pmac_tumbler_t *mix = chip->mixer_data;
992
993 write_audio_gpio(&mix->audio_reset, 0);
994 big_mdelay(200);
995 write_audio_gpio(&mix->audio_reset, 1);
996 big_mdelay(100);
997 write_audio_gpio(&mix->audio_reset, 0);
998 big_mdelay(100);
999}
1000
1001#ifdef CONFIG_PMAC_PBOOK
1002/* resume mixer */
1003static void tumbler_resume(pmac_t *chip)
1004{
1005 pmac_tumbler_t *mix = chip->mixer_data;
1006
1007 snd_assert(mix, return);
1008
1009 tumbler_reset_audio(chip);
1010 if (mix->i2c.client && mix->i2c.init_client) {
1011 if (mix->i2c.init_client(&mix->i2c) < 0)
1012 printk(KERN_ERR "tumbler_init_client error\n");
1013 } else
1014 printk(KERN_ERR "tumbler: i2c is not initialized\n");
1015 if (chip->model == PMAC_TUMBLER) {
1016 tumbler_set_mono_volume(mix, &tumbler_pcm_vol_info);
1017 tumbler_set_mono_volume(mix, &tumbler_bass_vol_info);
1018 tumbler_set_mono_volume(mix, &tumbler_treble_vol_info);
1019 tumbler_set_drc(mix);
1020 } else {
1021 snapper_set_mix_vol(mix, VOL_IDX_PCM);
1022 snapper_set_mix_vol(mix, VOL_IDX_PCM2);
1023 snapper_set_mix_vol(mix, VOL_IDX_ADC);
1024 tumbler_set_mono_volume(mix, &snapper_bass_vol_info);
1025 tumbler_set_mono_volume(mix, &snapper_treble_vol_info);
1026 snapper_set_drc(mix);
1027 snapper_set_capture_source(mix);
1028 }
1029 tumbler_set_master_volume(mix);
1030 if (chip->update_automute)
1031 chip->update_automute(chip, 0);
1032}
1033#endif
1034
1035/* initialize tumbler */
1036static int __init tumbler_init(pmac_t *chip)
1037{
1038 int irq, err;
1039 pmac_tumbler_t *mix = chip->mixer_data;
1040 snd_assert(mix, return -EINVAL);
1041
1042 tumbler_find_device("audio-hw-reset", &mix->audio_reset, 0);
1043 tumbler_find_device("amp-mute", &mix->amp_mute, 0);
1044 tumbler_find_device("headphone-mute", &mix->hp_mute, 0);
1045 irq = tumbler_find_device("headphone-detect", &mix->hp_detect, 0);
1046 if (irq < 0)
1047 irq = tumbler_find_device("keywest-gpio15", &mix->hp_detect, 1);
1048
1049 tumbler_reset_audio(chip);
1050
1051 /* activate headphone status interrupts */
1052 if (irq >= 0) {
1053 unsigned char val;
1054 if ((err = request_irq(irq, headphone_intr, 0,
1055 "Tumbler Headphone Detection", chip)) < 0)
1056 return err;
1057 /* activate headphone status interrupts */
1058 val = do_gpio_read(&mix->hp_detect);
1059 do_gpio_write(&mix->hp_detect, val | 0x80);
1060 }
1061 mix->headphone_irq = irq;
1062
1063 return 0;
1064}
1065
1066static void tumbler_cleanup(pmac_t *chip)
1067{
1068 pmac_tumbler_t *mix = chip->mixer_data;
1069 if (! mix)
1070 return;
1071
1072 if (mix->headphone_irq >= 0)
1073 free_irq(mix->headphone_irq, chip);
1074 tumbler_gpio_free(&mix->audio_reset);
1075 tumbler_gpio_free(&mix->amp_mute);
1076 tumbler_gpio_free(&mix->hp_mute);
1077 tumbler_gpio_free(&mix->hp_detect);
1078 snd_pmac_keywest_cleanup(&mix->i2c);
1079 kfree(mix);
1080 chip->mixer_data = NULL;
1081}
1082
1083/* exported */
1084int __init snd_pmac_tumbler_init(pmac_t *chip)
1085{
1086 int i, err;
1087 pmac_tumbler_t *mix;
1088 u32 *paddr;
1089 struct device_node *tas_node;
1090 char *chipname;
1091
1092#ifdef CONFIG_KMOD
1093 if (current->fs->root)
1094 request_module("i2c-keywest");
1095#endif /* CONFIG_KMOD */
1096
1097 mix = kmalloc(sizeof(*mix), GFP_KERNEL);
1098 if (! mix)
1099 return -ENOMEM;
1100 memset(mix, 0, sizeof(*mix));
1101 mix->headphone_irq = -1;
1102
1103 chip->mixer_data = mix;
1104 chip->mixer_free = tumbler_cleanup;
1105
1106 if ((err = tumbler_init(chip)) < 0)
1107 return err;
1108
1109 /* set up TAS */
1110 tas_node = find_devices("deq");
1111 if (tas_node == NULL)
1112 return -ENODEV;
1113
1114 paddr = (u32 *)get_property(tas_node, "i2c-address", NULL);
1115 if (paddr)
1116 mix->i2c.addr = (*paddr) >> 1;
1117 else
1118 mix->i2c.addr = TAS_I2C_ADDR;
1119
1120 if (chip->model == PMAC_TUMBLER) {
1121 mix->i2c.init_client = tumbler_init_client;
1122 mix->i2c.name = "TAS3001c";
1123 chipname = "Tumbler";
1124 } else {
1125 mix->i2c.init_client = snapper_init_client;
1126 mix->i2c.name = "TAS3004";
1127 chipname = "Snapper";
1128 }
1129
1130 if ((err = snd_pmac_keywest_init(&mix->i2c)) < 0)
1131 return err;
1132
1133 /*
1134 * build mixers
1135 */
1136 sprintf(chip->card->mixername, "PowerMac %s", chipname);
1137
1138 if (chip->model == PMAC_TUMBLER) {
1139 for (i = 0; i < ARRAY_SIZE(tumbler_mixers); i++) {
1140 if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&tumbler_mixers[i], chip))) < 0)
1141 return err;
1142 }
1143 } else {
1144 for (i = 0; i < ARRAY_SIZE(snapper_mixers); i++) {
1145 if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snapper_mixers[i], chip))) < 0)
1146 return err;
1147 }
1148 }
1149 chip->master_sw_ctl = snd_ctl_new1(&tumbler_hp_sw, chip);
1150 if ((err = snd_ctl_add(chip->card, chip->master_sw_ctl)) < 0)
1151 return err;
1152 chip->speaker_sw_ctl = snd_ctl_new1(&tumbler_speaker_sw, chip);
1153 if ((err = snd_ctl_add(chip->card, chip->speaker_sw_ctl)) < 0)
1154 return err;
1155 chip->drc_sw_ctl = snd_ctl_new1(&tumbler_drc_sw, chip);
1156 if ((err = snd_ctl_add(chip->card, chip->drc_sw_ctl)) < 0)
1157 return err;
1158
1159
1160#ifdef CONFIG_PMAC_PBOOK
1161 chip->resume = tumbler_resume;
1162#endif
1163
1164 INIT_WORK(&device_change, device_change_handler, (void *)chip);
1165
1166#ifdef PMAC_SUPPORT_AUTOMUTE
1167 if (mix->headphone_irq >=0 && (err = snd_pmac_add_automute(chip)) < 0)
1168 return err;
1169 chip->detect_headphone = tumbler_detect_headphone;
1170 chip->update_automute = tumbler_update_automute;
1171 tumbler_update_automute(chip, 0); /* update the status only */
1172#endif
1173
1174 return 0;
1175}
diff --git a/sound/ppc/tumbler_volume.h b/sound/ppc/tumbler_volume.h
new file mode 100644
index 000000000000..ef8d85d58b02
--- /dev/null
+++ b/sound/ppc/tumbler_volume.h
@@ -0,0 +1,250 @@
1/* volume tables, taken from TAS3001c data manual */
2/* volume gain values */
3/* 0 = -70 dB, 175 = 18.0 dB in 0.5 dB step */
4static unsigned int master_volume_table[] = {
5 0x00000015, 0x00000016, 0x00000017,
6 0x00000019, 0x0000001a, 0x0000001c,
7 0x0000001d, 0x0000001f, 0x00000021,
8 0x00000023, 0x00000025, 0x00000027,
9 0x00000029, 0x0000002c, 0x0000002e,
10 0x00000031, 0x00000034, 0x00000037,
11 0x0000003a, 0x0000003e, 0x00000042,
12 0x00000045, 0x0000004a, 0x0000004e,
13 0x00000053, 0x00000057, 0x0000005d,
14 0x00000062, 0x00000068, 0x0000006e,
15 0x00000075, 0x0000007b, 0x00000083,
16 0x0000008b, 0x00000093, 0x0000009b,
17 0x000000a5, 0x000000ae, 0x000000b9,
18 0x000000c4, 0x000000cf, 0x000000dc,
19 0x000000e9, 0x000000f6, 0x00000105,
20 0x00000114, 0x00000125, 0x00000136,
21 0x00000148, 0x0000015c, 0x00000171,
22 0x00000186, 0x0000019e, 0x000001b6,
23 0x000001d0, 0x000001eb, 0x00000209,
24 0x00000227, 0x00000248, 0x0000026b,
25 0x0000028f, 0x000002b6, 0x000002df,
26 0x0000030b, 0x00000339, 0x0000036a,
27 0x0000039e, 0x000003d5, 0x0000040f,
28 0x0000044c, 0x0000048d, 0x000004d2,
29 0x0000051c, 0x00000569, 0x000005bb,
30 0x00000612, 0x0000066e, 0x000006d0,
31 0x00000737, 0x000007a5, 0x00000818,
32 0x00000893, 0x00000915, 0x0000099f,
33 0x00000a31, 0x00000acc, 0x00000b6f,
34 0x00000c1d, 0x00000cd5, 0x00000d97,
35 0x00000e65, 0x00000f40, 0x00001027,
36 0x0000111c, 0x00001220, 0x00001333,
37 0x00001456, 0x0000158a, 0x000016d1,
38 0x0000182b, 0x0000199a, 0x00001b1e,
39 0x00001cb9, 0x00001e6d, 0x0000203a,
40 0x00002223, 0x00002429, 0x0000264e,
41 0x00002893, 0x00002afa, 0x00002d86,
42 0x00003039, 0x00003314, 0x0000361b,
43 0x00003950, 0x00003cb5, 0x0000404e,
44 0x0000441d, 0x00004827, 0x00004c6d,
45 0x000050f4, 0x000055c0, 0x00005ad5,
46 0x00006037, 0x000065ea, 0x00006bf4,
47 0x0000725a, 0x00007920, 0x0000804e,
48 0x000087e8, 0x00008ff6, 0x0000987d,
49 0x0000a186, 0x0000ab19, 0x0000b53c,
50 0x0000bff9, 0x0000cb59, 0x0000d766,
51 0x0000e429, 0x0000f1ae, 0x00010000,
52 0x00010f2b, 0x00011f3d, 0x00013042,
53 0x00014249, 0x00015562, 0x0001699c,
54 0x00017f09, 0x000195bc, 0x0001adc6,
55 0x0001c73d, 0x0001e237, 0x0001feca,
56 0x00021d0e, 0x00023d1d, 0x00025f12,
57 0x0002830b, 0x0002a925, 0x0002d182,
58 0x0002fc42, 0x0003298b, 0x00035983,
59 0x00038c53, 0x0003c225, 0x0003fb28,
60 0x0004378b, 0x00047783, 0x0004bb44,
61 0x0005030a, 0x00054f10, 0x00059f98,
62 0x0005f4e5, 0x00064f40, 0x0006aef6,
63 0x00071457, 0x00077fbb, 0x0007f17b,
64};
65
66/* treble table for TAS3001c */
67/* 0 = -18 dB, 72 = 18 dB in 0.5 dB step */
68static unsigned int treble_volume_table[] = {
69 0x96, 0x95, 0x94,
70 0x93, 0x92, 0x91,
71 0x90, 0x8f, 0x8e,
72 0x8d, 0x8c, 0x8b,
73 0x8a, 0x89, 0x88,
74 0x87, 0x86, 0x85,
75 0x84, 0x83, 0x82,
76 0x81, 0x80, 0x7f,
77 0x7e, 0x7d, 0x7c,
78 0x7b, 0x7a, 0x79,
79 0x78, 0x77, 0x76,
80 0x75, 0x74, 0x73,
81 0x72, 0x71, 0x70,
82 0x6e, 0x6d, 0x6c,
83 0x6b, 0x69, 0x68,
84 0x66, 0x65, 0x63,
85 0x62, 0x60, 0x5e,
86 0x5c, 0x5a, 0x57,
87 0x55, 0x52, 0x4f,
88 0x4c, 0x49, 0x45,
89 0x42, 0x3e, 0x3a,
90 0x36, 0x32, 0x2d,
91 0x28, 0x22, 0x1c,
92 0x16, 0x10, 0x09,
93 0x01,
94};
95
96/* bass table for TAS3001c */
97/* 0 = -18 dB, 72 = 18 dB in 0.5 dB step */
98static unsigned int bass_volume_table[] = {
99 0x86, 0x82, 0x7f,
100 0x7d, 0x7a, 0x78,
101 0x76, 0x74, 0x72,
102 0x70, 0x6e, 0x6d,
103 0x6b, 0x69, 0x66,
104 0x64, 0x61, 0x5f,
105 0x5d, 0x5c, 0x5a,
106 0x59, 0x58, 0x56,
107 0x55, 0x54, 0x53,
108 0x51, 0x4f, 0x4d,
109 0x4b, 0x49, 0x46,
110 0x44, 0x42, 0x40,
111 0x3e, 0x3c, 0x3b,
112 0x39, 0x38, 0x36,
113 0x35, 0x33, 0x31,
114 0x30, 0x2e, 0x2c,
115 0x2b, 0x29, 0x28,
116 0x26, 0x25, 0x23,
117 0x21, 0x1f, 0x1c,
118 0x19, 0x18, 0x17,
119 0x16, 0x14, 0x13,
120 0x12, 0x10, 0x0f,
121 0x0d, 0x0b, 0x0a,
122 0x08, 0x06, 0x03,
123 0x01,
124};
125
126/* mixer (pcm) volume table */
127/* 0 = -70 dB, 175 = 18.0 dB in 0.5 dB step */
128static unsigned int mixer_volume_table[] = {
129 0x00014b, 0x00015f, 0x000174,
130 0x00018a, 0x0001a1, 0x0001ba,
131 0x0001d4, 0x0001f0, 0x00020d,
132 0x00022c, 0x00024d, 0x000270,
133 0x000295, 0x0002bc, 0x0002e6,
134 0x000312, 0x000340, 0x000372,
135 0x0003a6, 0x0003dd, 0x000418,
136 0x000456, 0x000498, 0x0004de,
137 0x000528, 0x000576, 0x0005c9,
138 0x000620, 0x00067d, 0x0006e0,
139 0x000748, 0x0007b7, 0x00082c,
140 0x0008a8, 0x00092b, 0x0009b6,
141 0x000a49, 0x000ae5, 0x000b8b,
142 0x000c3a, 0x000cf3, 0x000db8,
143 0x000e88, 0x000f64, 0x00104e,
144 0x001145, 0x00124b, 0x001361,
145 0x001487, 0x0015be, 0x001708,
146 0x001865, 0x0019d8, 0x001b60,
147 0x001cff, 0x001eb7, 0x002089,
148 0x002276, 0x002481, 0x0026ab,
149 0x0028f5, 0x002b63, 0x002df5,
150 0x0030ae, 0x003390, 0x00369e,
151 0x0039db, 0x003d49, 0x0040ea,
152 0x0044c3, 0x0048d6, 0x004d27,
153 0x0051b9, 0x005691, 0x005bb2,
154 0x006121, 0x0066e3, 0x006cfb,
155 0x007370, 0x007a48, 0x008186,
156 0x008933, 0x009154, 0x0099f1,
157 0x00a310, 0x00acba, 0x00b6f6,
158 0x00c1cd, 0x00cd49, 0x00d973,
159 0x00e655, 0x00f3fb, 0x010270,
160 0x0111c0, 0x0121f9, 0x013328,
161 0x01455b, 0x0158a2, 0x016d0e,
162 0x0182af, 0x019999, 0x01b1de,
163 0x01cb94, 0x01e6cf, 0x0203a7,
164 0x022235, 0x024293, 0x0264db,
165 0x02892c, 0x02afa3, 0x02d862,
166 0x03038a, 0x033142, 0x0361af,
167 0x0394fa, 0x03cb50, 0x0404de,
168 0x0441d5, 0x048268, 0x04c6d0,
169 0x050f44, 0x055c04, 0x05ad50,
170 0x06036e, 0x065ea5, 0x06bf44,
171 0x07259d, 0x079207, 0x0804dc,
172 0x087e80, 0x08ff59, 0x0987d5,
173 0x0a1866, 0x0ab189, 0x0b53be,
174 0x0bff91, 0x0cb591, 0x0d765a,
175 0x0e4290, 0x0f1adf, 0x100000,
176 0x10f2b4, 0x11f3c9, 0x13041a,
177 0x14248e, 0x15561a, 0x1699c0,
178 0x17f094, 0x195bb8, 0x1adc61,
179 0x1c73d5, 0x1e236d, 0x1fec98,
180 0x21d0d9, 0x23d1cd, 0x25f125,
181 0x2830af, 0x2a9254, 0x2d1818,
182 0x2fc420, 0x3298b0, 0x35982f,
183 0x38c528, 0x3c224c, 0x3fb278,
184 0x437880, 0x477828, 0x4bb446,
185 0x5030a1, 0x54f106, 0x59f980,
186 0x5f4e52, 0x64f403, 0x6aef5d,
187 0x714575, 0x77fbaa, 0x7f17af,
188};
189
190
191/* treble table for TAS3004 */
192/* 0 = -18 dB, 72 = 18 dB in 0.5 dB step */
193static unsigned int snapper_treble_volume_table[] = {
194 0x96, 0x95, 0x94,
195 0x93, 0x92, 0x91,
196 0x90, 0x8f, 0x8e,
197 0x8d, 0x8c, 0x8b,
198 0x8a, 0x89, 0x88,
199 0x87, 0x86, 0x85,
200 0x84, 0x83, 0x82,
201 0x81, 0x80, 0x7f,
202 0x7e, 0x7d, 0x7c,
203 0x7b, 0x7a, 0x79,
204 0x78, 0x77, 0x76,
205 0x75, 0x74, 0x73,
206 0x72, 0x71, 0x70,
207 0x6f, 0x6d, 0x6c,
208 0x6b, 0x69, 0x68,
209 0x67, 0x65, 0x63,
210 0x62, 0x60, 0x5d,
211 0x5b, 0x59, 0x56,
212 0x53, 0x51, 0x4d,
213 0x4a, 0x47, 0x43,
214 0x3f, 0x3b, 0x36,
215 0x31, 0x2c, 0x26,
216 0x20, 0x1a, 0x13,
217 0x08, 0x04, 0x01,
218 0x01,
219};
220
221/* bass table for TAS3004 */
222/* 0 = -18 dB, 72 = 18 dB in 0.5 dB step */
223static unsigned int snapper_bass_volume_table[] = {
224 0x96, 0x95, 0x94,
225 0x93, 0x92, 0x91,
226 0x90, 0x8f, 0x8e,
227 0x8d, 0x8c, 0x8b,
228 0x8a, 0x89, 0x88,
229 0x87, 0x86, 0x85,
230 0x84, 0x83, 0x82,
231 0x81, 0x80, 0x7f,
232 0x7e, 0x7d, 0x7c,
233 0x7b, 0x7a, 0x79,
234 0x78, 0x77, 0x76,
235 0x75, 0x74, 0x73,
236 0x72, 0x71, 0x6f,
237 0x6e, 0x6d, 0x6b,
238 0x6a, 0x69, 0x67,
239 0x66, 0x65, 0x63,
240 0x62, 0x61, 0x5f,
241 0x5d, 0x5b, 0x58,
242 0x55, 0x52, 0x4f,
243 0x4c, 0x49, 0x46,
244 0x43, 0x3f, 0x3b,
245 0x37, 0x33, 0x2e,
246 0x29, 0x24, 0x1e,
247 0x18, 0x11, 0x0a,
248 0x01,
249};
250