Blame view

sound/ppc/awacs.c 32.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  /*
   * PMac AWACS lowlevel functions
   *
   * Copyright (c) by Takashi Iwai <tiwai@suse.de>
   * code based on dmasound.c.
   *
   *   This program is free software; you can redistribute it and/or modify
   *   it under the terms of the GNU General Public License as published by
   *   the Free Software Foundation; either version 2 of the License, or
   *   (at your option) any later version.
   *
   *   This program is distributed in the hope that it will be useful,
   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *   GNU General Public License for more details.
   *
   *   You should have received a copy of the GNU General Public License
   *   along with this program; if not, write to the Free Software
   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
23
24
25
26
27
28
29
30
31
32
33
34
  #include <asm/io.h>
  #include <asm/nvram.h>
  #include <linux/init.h>
  #include <linux/delay.h>
  #include <linux/slab.h>
  #include <sound/core.h>
  #include "pmac.h"
  
  
  #ifdef CONFIG_ADB_CUDA
  #define PMAC_AMP_AVAIL
  #endif
  
  #ifdef PMAC_AMP_AVAIL
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
35
  struct awacs_amp {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
38
  	unsigned char amp_master;
  	unsigned char amp_vol[2][2];
  	unsigned char amp_tone[2];
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
39
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
42
43
  
  #define CHECK_CUDA_AMP() (sys_ctrler == SYS_CTRLER_CUDA)
  
  #endif /* PMAC_AMP_AVAIL */
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
44
  static void snd_pmac_screamer_wait(struct snd_pmac *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
  {
  	long timeout = 2000;
  	while (!(in_le32(&chip->awacs->codec_stat) & MASK_VALID)) {
  		mdelay(1);
  		if (! --timeout) {
  			snd_printd("snd_pmac_screamer_wait timeout
  ");
  			break;
  		}
  	}
  }
  
  /*
   * write AWACS register
   */
  static void
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
61
  snd_pmac_awacs_write(struct snd_pmac *chip, int val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
  {
  	long timeout = 5000000;
  
  	if (chip->model == PMAC_SCREAMER)
  		snd_pmac_screamer_wait(chip);
  	out_le32(&chip->awacs->codec_ctrl, val | (chip->subframe << 22));
  	while (in_le32(&chip->awacs->codec_ctrl) & MASK_NEWECMD) {
  		if (! --timeout) {
  			snd_printd("snd_pmac_awacs_write timeout
  ");
  			break;
  		}
  	}
  }
  
  static void
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
78
  snd_pmac_awacs_write_reg(struct snd_pmac *chip, int reg, int val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
80
81
82
83
84
  {
  	snd_pmac_awacs_write(chip, val | (reg << 12));
  	chip->awacs_reg[reg] = val;
  }
  
  static void
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
85
  snd_pmac_awacs_write_noreg(struct snd_pmac *chip, int reg, int val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
88
  {
  	snd_pmac_awacs_write(chip, val | (reg << 12));
  }
8c8709334   Benjamin Herrenschmidt   [PATCH] ppc32: Re...
89
  #ifdef CONFIG_PM
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
  /* Recalibrate chip */
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
91
  static void screamer_recalibrate(struct snd_pmac *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
94
95
96
97
98
99
100
101
  {
  	if (chip->model != PMAC_SCREAMER)
  		return;
  
  	/* Sorry for the horrible delays... I hope to get that improved
  	 * by making the whole PM process asynchronous in a future version
  	 */
  	snd_pmac_awacs_write_noreg(chip, 1, chip->awacs_reg[1]);
  	if (chip->manufacturer == 0x1)
  		/* delay for broken crystal part */
989a0b248   Nishanth Aravamudan   [ALSA] Fix-up sle...
102
  		msleep(750);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
  	snd_pmac_awacs_write_noreg(chip, 1,
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
104
105
  				   chip->awacs_reg[1] | MASK_RECALIBRATE |
  				   MASK_CMUTE | MASK_AMUTE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
107
108
109
110
111
112
113
114
115
116
117
  	snd_pmac_awacs_write_noreg(chip, 1, chip->awacs_reg[1]);
  	snd_pmac_awacs_write_noreg(chip, 6, chip->awacs_reg[6]);
  }
  
  #else
  #define screamer_recalibrate(chip) /* NOP */
  #endif
  
  
  /*
   * additional callback to set the pcm format
   */
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
118
  static void snd_pmac_awacs_set_format(struct snd_pmac *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
120
121
122
123
124
125
126
127
128
129
130
131
  {
  	chip->awacs_reg[1] &= ~MASK_SAMPLERATE;
  	chip->awacs_reg[1] |= chip->rate_index << 3;
  	snd_pmac_awacs_write_reg(chip, 1, chip->awacs_reg[1]);
  }
  
  
  /*
   * AWACS volume callbacks
   */
  /*
   * volumes: 0-15 stereo
   */
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
132
133
  static int snd_pmac_awacs_info_volume(struct snd_kcontrol *kcontrol,
  				      struct snd_ctl_elem_info *uinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
135
136
137
138
139
140
  {
  	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  	uinfo->count = 2;
  	uinfo->value.integer.min = 0;
  	uinfo->value.integer.max = 15;
  	return 0;
  }
7ae44cfa7   Risto Suominen   [ALSA] snd-powerm...
141

65b29f503   Takashi Iwai   [ALSA] Remove xxx...
142
143
  static int snd_pmac_awacs_get_volume(struct snd_kcontrol *kcontrol,
  				     struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
145
  	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
  	int reg = kcontrol->private_value & 0xff;
  	int lshift = (kcontrol->private_value >> 8) & 0xff;
  	int inverted = (kcontrol->private_value >> 16) & 1;
  	unsigned long flags;
  	int vol[2];
  
  	spin_lock_irqsave(&chip->reg_lock, flags);
  	vol[0] = (chip->awacs_reg[reg] >> lshift) & 0xf;
  	vol[1] = chip->awacs_reg[reg] & 0xf;
  	spin_unlock_irqrestore(&chip->reg_lock, flags);
  	if (inverted) {
  		vol[0] = 0x0f - vol[0];
  		vol[1] = 0x0f - vol[1];
  	}
  	ucontrol->value.integer.value[0] = vol[0];
  	ucontrol->value.integer.value[1] = vol[1];
  	return 0;
  }
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
164
165
  static int snd_pmac_awacs_put_volume(struct snd_kcontrol *kcontrol,
  				     struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
167
  	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
169
170
171
172
  	int reg = kcontrol->private_value & 0xff;
  	int lshift = (kcontrol->private_value >> 8) & 0xff;
  	int inverted = (kcontrol->private_value >> 16) & 1;
  	int val, oldval;
  	unsigned long flags;
d4079ac49   Takashi Iwai   [ALSA] powermac -...
173
  	unsigned int vol[2];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
175
176
  
  	vol[0] = ucontrol->value.integer.value[0];
  	vol[1] = ucontrol->value.integer.value[1];
d4079ac49   Takashi Iwai   [ALSA] powermac -...
177
178
  	if (vol[0] > 0x0f || vol[1] > 0x0f)
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
  	if (inverted) {
  		vol[0] = 0x0f - vol[0];
  		vol[1] = 0x0f - vol[1];
  	}
  	vol[0] &= 0x0f;
  	vol[1] &= 0x0f;
  	spin_lock_irqsave(&chip->reg_lock, flags);
  	oldval = chip->awacs_reg[reg];
  	val = oldval & ~(0xf | (0xf << lshift));
  	val |= vol[0] << lshift;
  	val |= vol[1];
  	if (oldval != val)
  		snd_pmac_awacs_write_reg(chip, reg, val);
  	spin_unlock_irqrestore(&chip->reg_lock, flags);
  	return oldval != reg;
  }
  
  
  #define AWACS_VOLUME(xname, xreg, xshift, xinverted) \
  { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
    .info = snd_pmac_awacs_info_volume, \
    .get = snd_pmac_awacs_get_volume, \
    .put = snd_pmac_awacs_put_volume, \
    .private_value = (xreg) | ((xshift) << 8) | ((xinverted) << 16) }
  
  /*
   * mute master/ogain for AWACS: mono
   */
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
207
208
  static int snd_pmac_awacs_get_switch(struct snd_kcontrol *kcontrol,
  				     struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
210
  	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
212
213
214
215
216
217
218
219
220
221
222
223
224
  	int reg = kcontrol->private_value & 0xff;
  	int shift = (kcontrol->private_value >> 8) & 0xff;
  	int invert = (kcontrol->private_value >> 16) & 1;
  	int val;
  	unsigned long flags;
  
  	spin_lock_irqsave(&chip->reg_lock, flags);
  	val = (chip->awacs_reg[reg] >> shift) & 1;
  	spin_unlock_irqrestore(&chip->reg_lock, flags);
  	if (invert)
  		val = 1 - val;
  	ucontrol->value.integer.value[0] = val;
  	return 0;
  }
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
225
226
  static int snd_pmac_awacs_put_switch(struct snd_kcontrol *kcontrol,
  				     struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
228
  	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
  	int reg = kcontrol->private_value & 0xff;
  	int shift = (kcontrol->private_value >> 8) & 0xff;
  	int invert = (kcontrol->private_value >> 16) & 1;
  	int mask = 1 << shift;
  	int val, changed;
  	unsigned long flags;
  
  	spin_lock_irqsave(&chip->reg_lock, flags);
  	val = chip->awacs_reg[reg] & ~mask;
  	if (ucontrol->value.integer.value[0] != invert)
  		val |= mask;
  	changed = chip->awacs_reg[reg] != val;
  	if (changed)
  		snd_pmac_awacs_write_reg(chip, reg, val);
  	spin_unlock_irqrestore(&chip->reg_lock, flags);
  	return changed;
  }
  
  #define AWACS_SWITCH(xname, xreg, xshift, xinvert) \
  { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
    .info = snd_pmac_boolean_mono_info, \
    .get = snd_pmac_awacs_get_switch, \
    .put = snd_pmac_awacs_put_switch, \
    .private_value = (xreg) | ((xshift) << 8) | ((xinvert) << 16) }
  
  
  #ifdef PMAC_AMP_AVAIL
  /*
   * controls for perch/whisper extension cards, e.g. G3 desktop
   *
   * TDA7433 connected via i2c address 0x45 (= 0x8a),
   * accessed through cuda
   */
  static void awacs_set_cuda(int reg, int val)
  {
  	struct adb_request req;
7ae44cfa7   Risto Suominen   [ALSA] snd-powerm...
265
266
  	cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 0x8a,
  			reg, val);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
268
269
270
271
272
273
  	while (! req.complete)
  		cuda_poll();
  }
  
  /*
   * level = 0 - 14, 7 = 0 dB
   */
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
274
  static void awacs_amp_set_tone(struct awacs_amp *amp, int bass, int treble)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275
276
277
278
279
280
281
282
283
284
285
286
287
  {
  	amp->amp_tone[0] = bass;
  	amp->amp_tone[1] = treble;
  	if (bass > 7)
  		bass = (14 - bass) + 8;
  	if (treble > 7)
  		treble = (14 - treble) + 8;
  	awacs_set_cuda(2, (bass << 4) | treble);
  }
  
  /*
   * vol = 0 - 31 (attenuation), 32 = mute bit, stereo
   */
7ae44cfa7   Risto Suominen   [ALSA] snd-powerm...
288
289
  static int awacs_amp_set_vol(struct awacs_amp *amp, int index,
  			     int lvol, int rvol, int do_check)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
291
  {
  	if (do_check && amp->amp_vol[index][0] == lvol &&
7ae44cfa7   Risto Suominen   [ALSA] snd-powerm...
292
  			amp->amp_vol[index][1] == rvol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
294
295
296
297
298
299
300
301
302
303
  		return 0;
  	awacs_set_cuda(3 + index, lvol);
  	awacs_set_cuda(5 + index, rvol);
  	amp->amp_vol[index][0] = lvol;
  	amp->amp_vol[index][1] = rvol;
  	return 1;
  }
  
  /*
   * 0 = -79 dB, 79 = 0 dB, 99 = +20 dB
   */
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
304
  static void awacs_amp_set_master(struct awacs_amp *amp, int vol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
306
307
308
309
310
311
312
  {
  	amp->amp_master = vol;
  	if (vol <= 79)
  		vol = 32 + (79 - vol);
  	else
  		vol = 32 - (vol - 79);
  	awacs_set_cuda(1, vol);
  }
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
313
  static void awacs_amp_free(struct snd_pmac *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
315
  	struct awacs_amp *amp = chip->mixer_data;
5e246b850   Takashi Iwai   ALSA: Kill snd_as...
316
317
  	if (!amp)
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
319
320
321
322
323
324
325
326
  	kfree(amp);
  	chip->mixer_data = NULL;
  	chip->mixer_free = NULL;
  }
  
  
  /*
   * mixer controls
   */
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
327
328
  static int snd_pmac_awacs_info_volume_amp(struct snd_kcontrol *kcontrol,
  					  struct snd_ctl_elem_info *uinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
330
331
332
333
334
335
  {
  	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  	uinfo->count = 2;
  	uinfo->value.integer.min = 0;
  	uinfo->value.integer.max = 31;
  	return 0;
  }
7ae44cfa7   Risto Suominen   [ALSA] snd-powerm...
336

65b29f503   Takashi Iwai   [ALSA] Remove xxx...
337
338
  static int snd_pmac_awacs_get_volume_amp(struct snd_kcontrol *kcontrol,
  					 struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
340
  	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
  	int index = kcontrol->private_value;
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
342
  	struct awacs_amp *amp = chip->mixer_data;
5e246b850   Takashi Iwai   ALSA: Kill snd_as...
343

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
346
347
  	ucontrol->value.integer.value[0] = 31 - (amp->amp_vol[index][0] & 31);
  	ucontrol->value.integer.value[1] = 31 - (amp->amp_vol[index][1] & 31);
  	return 0;
  }
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
348
349
  static int snd_pmac_awacs_put_volume_amp(struct snd_kcontrol *kcontrol,
  					 struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
351
  	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
353
  	int index = kcontrol->private_value;
  	int vol[2];
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
354
  	struct awacs_amp *amp = chip->mixer_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355

7ae44cfa7   Risto Suominen   [ALSA] snd-powerm...
356
357
358
359
  	vol[0] = (31 - (ucontrol->value.integer.value[0] & 31))
  		| (amp->amp_vol[index][0] & 32);
  	vol[1] = (31 - (ucontrol->value.integer.value[1] & 31))
  		| (amp->amp_vol[index][1] & 32);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
361
  	return awacs_amp_set_vol(amp, index, vol[0], vol[1], 1);
  }
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
362
363
  static int snd_pmac_awacs_get_switch_amp(struct snd_kcontrol *kcontrol,
  					 struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
365
  	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
  	int index = kcontrol->private_value;
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
367
  	struct awacs_amp *amp = chip->mixer_data;
5e246b850   Takashi Iwai   ALSA: Kill snd_as...
368

7ae44cfa7   Risto Suominen   [ALSA] snd-powerm...
369
370
371
372
  	ucontrol->value.integer.value[0] = (amp->amp_vol[index][0] & 32)
  					? 0 : 1;
  	ucontrol->value.integer.value[1] = (amp->amp_vol[index][1] & 32)
  					? 0 : 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
374
  	return 0;
  }
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
375
376
  static int snd_pmac_awacs_put_switch_amp(struct snd_kcontrol *kcontrol,
  					 struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
378
  	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
380
  	int index = kcontrol->private_value;
  	int vol[2];
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
381
  	struct awacs_amp *amp = chip->mixer_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382

7ae44cfa7   Risto Suominen   [ALSA] snd-powerm...
383
384
385
386
  	vol[0] = (ucontrol->value.integer.value[0] ? 0 : 32)
  		| (amp->amp_vol[index][0] & 31);
  	vol[1] = (ucontrol->value.integer.value[1] ? 0 : 32)
  		| (amp->amp_vol[index][1] & 31);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
388
  	return awacs_amp_set_vol(amp, index, vol[0], vol[1], 1);
  }
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
389
390
  static int snd_pmac_awacs_info_tone_amp(struct snd_kcontrol *kcontrol,
  					struct snd_ctl_elem_info *uinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
392
393
394
395
396
397
  {
  	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  	uinfo->count = 1;
  	uinfo->value.integer.min = 0;
  	uinfo->value.integer.max = 14;
  	return 0;
  }
7ae44cfa7   Risto Suominen   [ALSA] snd-powerm...
398

65b29f503   Takashi Iwai   [ALSA] Remove xxx...
399
400
  static int snd_pmac_awacs_get_tone_amp(struct snd_kcontrol *kcontrol,
  				       struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
402
  	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
  	int index = kcontrol->private_value;
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
404
  	struct awacs_amp *amp = chip->mixer_data;
5e246b850   Takashi Iwai   ALSA: Kill snd_as...
405

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406
407
408
  	ucontrol->value.integer.value[0] = amp->amp_tone[index];
  	return 0;
  }
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
409
410
  static int snd_pmac_awacs_put_tone_amp(struct snd_kcontrol *kcontrol,
  				       struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
412
  	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
413
  	int index = kcontrol->private_value;
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
414
  	struct awacs_amp *amp = chip->mixer_data;
d4079ac49   Takashi Iwai   [ALSA] powermac -...
415
  	unsigned int val;
5e246b850   Takashi Iwai   ALSA: Kill snd_as...
416

d4079ac49   Takashi Iwai   [ALSA] powermac -...
417
418
419
420
421
  	val = ucontrol->value.integer.value[0];
  	if (val > 14)
  		return -EINVAL;
  	if (val != amp->amp_tone[index]) {
  		amp->amp_tone[index] = val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
423
424
425
426
  		awacs_amp_set_tone(amp, amp->amp_tone[0], amp->amp_tone[1]);
  		return 1;
  	}
  	return 0;
  }
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
427
428
  static int snd_pmac_awacs_info_master_amp(struct snd_kcontrol *kcontrol,
  					  struct snd_ctl_elem_info *uinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
430
431
432
433
434
435
  {
  	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  	uinfo->count = 1;
  	uinfo->value.integer.min = 0;
  	uinfo->value.integer.max = 99;
  	return 0;
  }
7ae44cfa7   Risto Suominen   [ALSA] snd-powerm...
436

65b29f503   Takashi Iwai   [ALSA] Remove xxx...
437
438
  static int snd_pmac_awacs_get_master_amp(struct snd_kcontrol *kcontrol,
  					 struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
440
441
  	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
  	struct awacs_amp *amp = chip->mixer_data;
5e246b850   Takashi Iwai   ALSA: Kill snd_as...
442

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
443
444
445
  	ucontrol->value.integer.value[0] = amp->amp_master;
  	return 0;
  }
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
446
447
  static int snd_pmac_awacs_put_master_amp(struct snd_kcontrol *kcontrol,
  					 struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
449
450
  	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
  	struct awacs_amp *amp = chip->mixer_data;
d4079ac49   Takashi Iwai   [ALSA] powermac -...
451
  	unsigned int val;
5e246b850   Takashi Iwai   ALSA: Kill snd_as...
452

d4079ac49   Takashi Iwai   [ALSA] powermac -...
453
454
455
456
457
  	val = ucontrol->value.integer.value[0];
  	if (val > 99)
  		return -EINVAL;
  	if (val != amp->amp_master) {
  		amp->amp_master = val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
459
460
461
462
463
464
465
  		awacs_amp_set_master(amp, amp->amp_master);
  		return 1;
  	}
  	return 0;
  }
  
  #define AMP_CH_SPK	0
  #define AMP_CH_HD	1
3e1e0a5dd   Takashi Iwai   ALSA: powermac - ...
466
  static struct snd_kcontrol_new snd_pmac_awacs_amp_vol[] __devinitdata = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
  	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
ad1cd7450   Jaroslav Kysela   ALSA: rename "PC ...
468
  	  .name = "Speaker Playback Volume",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
  	  .info = snd_pmac_awacs_info_volume_amp,
  	  .get = snd_pmac_awacs_get_volume_amp,
  	  .put = snd_pmac_awacs_put_volume_amp,
  	  .private_value = AMP_CH_SPK,
  	},
  	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  	  .name = "Headphone Playback Volume",
  	  .info = snd_pmac_awacs_info_volume_amp,
  	  .get = snd_pmac_awacs_get_volume_amp,
  	  .put = snd_pmac_awacs_put_volume_amp,
  	  .private_value = AMP_CH_HD,
  	},
  	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  	  .name = "Tone Control - Bass",
  	  .info = snd_pmac_awacs_info_tone_amp,
  	  .get = snd_pmac_awacs_get_tone_amp,
  	  .put = snd_pmac_awacs_put_tone_amp,
  	  .private_value = 0,
  	},
  	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  	  .name = "Tone Control - Treble",
  	  .info = snd_pmac_awacs_info_tone_amp,
  	  .get = snd_pmac_awacs_get_tone_amp,
  	  .put = snd_pmac_awacs_put_tone_amp,
  	  .private_value = 1,
  	},
  	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  	  .name = "Amp Master Playback Volume",
  	  .info = snd_pmac_awacs_info_master_amp,
  	  .get = snd_pmac_awacs_get_master_amp,
  	  .put = snd_pmac_awacs_put_master_amp,
  	},
  };
3e1e0a5dd   Takashi Iwai   ALSA: powermac - ...
502
  static struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw __devinitdata = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
504
505
506
507
508
509
  	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  	.name = "Headphone Playback Switch",
  	.info = snd_pmac_boolean_stereo_info,
  	.get = snd_pmac_awacs_get_switch_amp,
  	.put = snd_pmac_awacs_put_switch_amp,
  	.private_value = AMP_CH_HD,
  };
3e1e0a5dd   Takashi Iwai   ALSA: powermac - ...
510
  static struct snd_kcontrol_new snd_pmac_awacs_amp_spk_sw __devinitdata = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
  	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
ad1cd7450   Jaroslav Kysela   ALSA: rename "PC ...
512
  	.name = "Speaker Playback Switch",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
514
515
516
517
518
519
520
521
522
523
524
  	.info = snd_pmac_boolean_stereo_info,
  	.get = snd_pmac_awacs_get_switch_amp,
  	.put = snd_pmac_awacs_put_switch_amp,
  	.private_value = AMP_CH_SPK,
  };
  
  #endif /* PMAC_AMP_AVAIL */
  
  
  /*
   * mic boost for screamer
   */
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
525
526
  static int snd_pmac_screamer_mic_boost_info(struct snd_kcontrol *kcontrol,
  					    struct snd_ctl_elem_info *uinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527
528
529
530
  {
  	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  	uinfo->count = 1;
  	uinfo->value.integer.min = 0;
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
531
  	uinfo->value.integer.max = 3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
533
  	return 0;
  }
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
534
535
  static int snd_pmac_screamer_mic_boost_get(struct snd_kcontrol *kcontrol,
  					   struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
537
  	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
538
  	int val = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
540
541
542
  	unsigned long flags;
  
  	spin_lock_irqsave(&chip->reg_lock, flags);
  	if (chip->awacs_reg[6] & MASK_MIC_BOOST)
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
543
544
545
  		val |= 2;
  	if (chip->awacs_reg[0] & MASK_GAINLINE)
  		val |= 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
547
548
549
  	spin_unlock_irqrestore(&chip->reg_lock, flags);
  	ucontrol->value.integer.value[0] = val;
  	return 0;
  }
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
550
551
  static int snd_pmac_screamer_mic_boost_put(struct snd_kcontrol *kcontrol,
  					   struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
552
  {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
553
  	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
554
555
556
557
558
559
560
  	int changed = 0;
  	int val0, val6;
  	unsigned long flags;
  
  	spin_lock_irqsave(&chip->reg_lock, flags);
  	val0 = chip->awacs_reg[0] & ~MASK_GAINLINE;
  	val6 = chip->awacs_reg[6] & ~MASK_MIC_BOOST;
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
561
  	if (ucontrol->value.integer.value[0] & 1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562
  		val0 |= MASK_GAINLINE;
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
563
564
  	if (ucontrol->value.integer.value[0] & 2)
  		val6 |= MASK_MIC_BOOST;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
  	if (val0 != chip->awacs_reg[0]) {
  		snd_pmac_awacs_write_reg(chip, 0, val0);
  		changed = 1;
  	}
  	if (val6 != chip->awacs_reg[6]) {
  		snd_pmac_awacs_write_reg(chip, 6, val6);
  		changed = 1;
  	}
  	spin_unlock_irqrestore(&chip->reg_lock, flags);
  	return changed;
  }
  
  /*
   * lists of mixer elements
   */
3e1e0a5dd   Takashi Iwai   ALSA: powermac - ...
580
  static struct snd_kcontrol_new snd_pmac_awacs_mixers[] __devinitdata = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
581
  	AWACS_SWITCH("Master Capture Switch", 1, SHIFT_LOOPTHRU, 0),
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
582
583
584
  	AWACS_VOLUME("Master Capture Volume", 0, 4, 0),
  /*	AWACS_SWITCH("Unknown Playback Switch", 6, SHIFT_PAROUT0, 0), */
  };
3e1e0a5dd   Takashi Iwai   ALSA: powermac - ...
585
  static struct snd_kcontrol_new snd_pmac_screamer_mixers_beige[] __devinitdata = {
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
586
587
588
589
590
  	AWACS_VOLUME("Master Playback Volume", 2, 6, 1),
  	AWACS_VOLUME("Play-through Playback Volume", 5, 6, 1),
  	AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0),
  	AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_LINE, 0),
  };
3e1e0a5dd   Takashi Iwai   ALSA: powermac - ...
591
  static struct snd_kcontrol_new snd_pmac_screamer_mixers_lo[] __devinitdata = {
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
592
  	AWACS_VOLUME("Line out Playback Volume", 2, 6, 1),
dca7c7417   Risto Suominen   ALSA: Add vmaster...
593
  };
3e1e0a5dd   Takashi Iwai   ALSA: powermac - ...
594
  static struct snd_kcontrol_new snd_pmac_screamer_mixers_imac[] __devinitdata = {
dca7c7417   Risto Suominen   ALSA: Add vmaster...
595
  	AWACS_VOLUME("Play-through Playback Volume", 5, 6, 1),
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
596
597
  	AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
  };
3e1e0a5dd   Takashi Iwai   ALSA: powermac - ...
598
  static struct snd_kcontrol_new snd_pmac_screamer_mixers_g4agp[] __devinitdata = {
4dbf95ba6   Risto Suominen   ALSA: snd-powerma...
599
600
601
602
603
  	AWACS_VOLUME("Line out Playback Volume", 2, 6, 1),
  	AWACS_VOLUME("Master Playback Volume", 5, 6, 1),
  	AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
  	AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0),
  };
3e1e0a5dd   Takashi Iwai   ALSA: powermac - ...
604
  static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac7500[] __devinitdata = {
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
605
606
607
608
  	AWACS_VOLUME("Line out Playback Volume", 2, 6, 1),
  	AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
  	AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0),
  };
3e1e0a5dd   Takashi Iwai   ALSA: powermac - ...
609
  static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac5500[] __devinitdata = {
dca7c7417   Risto Suominen   ALSA: Add vmaster...
610
611
  	AWACS_VOLUME("Headphone Playback Volume", 2, 6, 1),
  };
3e1e0a5dd   Takashi Iwai   ALSA: powermac - ...
612
  static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac[] __devinitdata = {
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
613
  	AWACS_VOLUME("Master Playback Volume", 2, 6, 1),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
614
615
616
617
618
619
  	AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
  };
  
  /* FIXME: is this correct order?
   * screamer (powerbook G3 pismo) seems to have different bits...
   */
3e1e0a5dd   Takashi Iwai   ALSA: powermac - ...
620
  static struct snd_kcontrol_new snd_pmac_awacs_mixers2[] __devinitdata = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
622
623
  	AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_LINE, 0),
  	AWACS_SWITCH("Mic Capture Switch", 0, SHIFT_MUX_MIC, 0),
  };
3e1e0a5dd   Takashi Iwai   ALSA: powermac - ...
624
  static struct snd_kcontrol_new snd_pmac_screamer_mixers2[] __devinitdata = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
626
627
  	AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0),
  	AWACS_SWITCH("Mic Capture Switch", 0, SHIFT_MUX_LINE, 0),
  };
3e1e0a5dd   Takashi Iwai   ALSA: powermac - ...
628
  static struct snd_kcontrol_new snd_pmac_awacs_mixers2_pmac5500[] __devinitdata = {
dca7c7417   Risto Suominen   ALSA: Add vmaster...
629
630
  	AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
  };
3e1e0a5dd   Takashi Iwai   ALSA: powermac - ...
631
  static struct snd_kcontrol_new snd_pmac_awacs_master_sw __devinitdata =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
632
  AWACS_SWITCH("Master Playback Switch", 1, SHIFT_HDMUTE, 1);
3e1e0a5dd   Takashi Iwai   ALSA: powermac - ...
633
  static struct snd_kcontrol_new snd_pmac_awacs_master_sw_imac __devinitdata =
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
634
  AWACS_SWITCH("Line out Playback Switch", 1, SHIFT_HDMUTE, 1);
3e1e0a5dd   Takashi Iwai   ALSA: powermac - ...
635
  static struct snd_kcontrol_new snd_pmac_awacs_master_sw_pmac5500 __devinitdata =
dca7c7417   Risto Suominen   ALSA: Add vmaster...
636
  AWACS_SWITCH("Headphone Playback Switch", 1, SHIFT_HDMUTE, 1);
3e1e0a5dd   Takashi Iwai   ALSA: powermac - ...
637
  static struct snd_kcontrol_new snd_pmac_awacs_mic_boost[] __devinitdata = {
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
638
  	AWACS_SWITCH("Mic Boost Capture Switch", 0, SHIFT_GAINLINE, 0),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
639
  };
3e1e0a5dd   Takashi Iwai   ALSA: powermac - ...
640
  static struct snd_kcontrol_new snd_pmac_screamer_mic_boost[] __devinitdata = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
  	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
642
  	  .name = "Mic Boost Capture Volume",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
643
644
645
646
647
  	  .info = snd_pmac_screamer_mic_boost_info,
  	  .get = snd_pmac_screamer_mic_boost_get,
  	  .put = snd_pmac_screamer_mic_boost_put,
  	},
  };
3e1e0a5dd   Takashi Iwai   ALSA: powermac - ...
648
  static struct snd_kcontrol_new snd_pmac_awacs_mic_boost_pmac7500[] __devinitdata =
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
649
650
651
  {
  	AWACS_SWITCH("Line Boost Capture Switch", 0, SHIFT_GAINLINE, 0),
  };
3e1e0a5dd   Takashi Iwai   ALSA: powermac - ...
652
  static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_beige[] __devinitdata =
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
653
654
655
656
  {
  	AWACS_SWITCH("Line Boost Capture Switch", 0, SHIFT_GAINLINE, 0),
  	AWACS_SWITCH("CD Boost Capture Switch", 6, SHIFT_MIC_BOOST, 0),
  };
3e1e0a5dd   Takashi Iwai   ALSA: powermac - ...
657
  static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_imac[] __devinitdata =
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
658
659
660
661
  {
  	AWACS_SWITCH("Line Boost Capture Switch", 0, SHIFT_GAINLINE, 0),
  	AWACS_SWITCH("Mic Boost Capture Switch", 6, SHIFT_MIC_BOOST, 0),
  };
3e1e0a5dd   Takashi Iwai   ALSA: powermac - ...
662
  static struct snd_kcontrol_new snd_pmac_awacs_speaker_vol[] __devinitdata = {
ad1cd7450   Jaroslav Kysela   ALSA: rename "PC ...
663
  	AWACS_VOLUME("Speaker Playback Volume", 4, 6, 1),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
  };
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
665

3e1e0a5dd   Takashi Iwai   ALSA: powermac - ...
666
  static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw __devinitdata =
ad1cd7450   Jaroslav Kysela   ALSA: rename "PC ...
667
  AWACS_SWITCH("Speaker Playback Switch", 1, SHIFT_SPKMUTE, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668

3e1e0a5dd   Takashi Iwai   ALSA: powermac - ...
669
  static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac1 __devinitdata =
ad1cd7450   Jaroslav Kysela   ALSA: rename "PC ...
670
  AWACS_SWITCH("Speaker Playback Switch", 1, SHIFT_PAROUT1, 1);
030b655b0   Risto Suominen   ALSA: snd-powerma...
671

3e1e0a5dd   Takashi Iwai   ALSA: powermac - ...
672
  static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac2 __devinitdata =
ad1cd7450   Jaroslav Kysela   ALSA: rename "PC ...
673
  AWACS_SWITCH("Speaker Playback Switch", 1, SHIFT_PAROUT1, 0);
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
674

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
675
676
677
678
  
  /*
   * add new mixer elements to the card
   */
7ae44cfa7   Risto Suominen   [ALSA] snd-powerm...
679
680
  static int build_mixers(struct snd_pmac *chip, int nums,
  			struct snd_kcontrol_new *mixers)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
682
683
684
  {
  	int i, err;
  
  	for (i = 0; i < nums; i++) {
7ae44cfa7   Risto Suominen   [ALSA] snd-powerm...
685
686
  		err = snd_ctl_add(chip->card, snd_ctl_new1(&mixers[i], chip));
  		if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
687
688
689
690
691
692
693
694
695
  			return err;
  	}
  	return 0;
  }
  
  
  /*
   * restore all registers
   */
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
696
  static void awacs_restore_all_regs(struct snd_pmac *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
698
699
700
701
702
703
704
705
706
707
  {
  	snd_pmac_awacs_write_noreg(chip, 0, chip->awacs_reg[0]);
  	snd_pmac_awacs_write_noreg(chip, 1, chip->awacs_reg[1]);
  	snd_pmac_awacs_write_noreg(chip, 2, chip->awacs_reg[2]);
  	snd_pmac_awacs_write_noreg(chip, 4, chip->awacs_reg[4]);
  	if (chip->model == PMAC_SCREAMER) {
  		snd_pmac_awacs_write_noreg(chip, 5, chip->awacs_reg[5]);
  		snd_pmac_awacs_write_noreg(chip, 6, chip->awacs_reg[6]);
  		snd_pmac_awacs_write_noreg(chip, 7, chip->awacs_reg[7]);
  	}
  }
8c8709334   Benjamin Herrenschmidt   [PATCH] ppc32: Re...
708
  #ifdef CONFIG_PM
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
709
  static void snd_pmac_awacs_suspend(struct snd_pmac *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
710
711
712
713
  {
  	snd_pmac_awacs_write_noreg(chip, 1, (chip->awacs_reg[1]
  					     | MASK_AMUTE | MASK_CMUTE));
  }
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
714
  static void snd_pmac_awacs_resume(struct snd_pmac *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
715
  {
71a157e8e   Grant Likely   of: add 'of_' pre...
716
717
  	if (of_machine_is_compatible("PowerBook3,1")
  	    || of_machine_is_compatible("PowerBook3,2")) {
989a0b248   Nishanth Aravamudan   [ALSA] Fix-up sle...
718
  		msleep(100);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719
720
  		snd_pmac_awacs_write_reg(chip, 1,
  			chip->awacs_reg[1] & ~MASK_PAROUT);
989a0b248   Nishanth Aravamudan   [ALSA] Fix-up sle...
721
  		msleep(300);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
723
724
725
726
727
728
729
730
731
732
  	}
  
  	awacs_restore_all_regs(chip);
  	if (chip->model == PMAC_SCREAMER) {
  		/* reset power bits in reg 6 */
  		mdelay(5);
  		snd_pmac_awacs_write_noreg(chip, 6, chip->awacs_reg[6]);
  	}
  	screamer_recalibrate(chip);
  #ifdef PMAC_AMP_AVAIL
  	if (chip->mixer_data) {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
733
  		struct awacs_amp *amp = chip->mixer_data;
7ae44cfa7   Risto Suominen   [ALSA] snd-powerm...
734
735
736
737
  		awacs_amp_set_vol(amp, 0,
  				  amp->amp_vol[0][0], amp->amp_vol[0][1], 0);
  		awacs_amp_set_vol(amp, 1,
  				  amp->amp_vol[1][0], amp->amp_vol[1][1], 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
738
739
740
741
742
  		awacs_amp_set_tone(amp, amp->amp_tone[0], amp->amp_tone[1]);
  		awacs_amp_set_master(amp, amp->amp_master);
  	}
  #endif
  }
8c8709334   Benjamin Herrenschmidt   [PATCH] ppc32: Re...
743
  #endif /* CONFIG_PM */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
744

71a157e8e   Grant Likely   of: add 'of_' pre...
745
746
747
748
749
750
751
752
753
754
  #define IS_PM7500 (of_machine_is_compatible("AAPL,7500") \
  		|| of_machine_is_compatible("AAPL,8500") \
  		|| of_machine_is_compatible("AAPL,9500"))
  #define IS_PM5500 (of_machine_is_compatible("AAPL,e411"))
  #define IS_BEIGE (of_machine_is_compatible("AAPL,Gossamer"))
  #define IS_IMAC1 (of_machine_is_compatible("PowerMac2,1"))
  #define IS_IMAC2 (of_machine_is_compatible("PowerMac2,2") \
  		|| of_machine_is_compatible("PowerMac4,1"))
  #define IS_G4AGP (of_machine_is_compatible("PowerMac3,1"))
  #define IS_LOMBARD (of_machine_is_compatible("PowerBook1,1"))
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
755

030b655b0   Risto Suominen   ALSA: snd-powerma...
756
  static int imac1, imac2;
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
757

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
758
759
760
761
  #ifdef PMAC_SUPPORT_AUTOMUTE
  /*
   * auto-mute stuffs
   */
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
762
  static int snd_pmac_awacs_detect_headphone(struct snd_pmac *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
763
764
765
766
767
  {
  	return (in_le32(&chip->awacs->codec_stat) & chip->hp_stat_mask) ? 1 : 0;
  }
  
  #ifdef PMAC_AMP_AVAIL
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
768
  static int toggle_amp_mute(struct awacs_amp *amp, int index, int mute)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769
770
771
772
773
774
775
776
777
778
779
  {
  	int vol[2];
  	vol[0] = amp->amp_vol[index][0] & 31;
  	vol[1] = amp->amp_vol[index][1] & 31;
  	if (mute) {
  		vol[0] |= 32;
  		vol[1] |= 32;
  	}
  	return awacs_amp_set_vol(amp, index, vol[0], vol[1], 1);
  }
  #endif
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
780
  static void snd_pmac_awacs_update_automute(struct snd_pmac *chip, int do_notify)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
782
783
784
  {
  	if (chip->auto_mute) {
  #ifdef PMAC_AMP_AVAIL
  		if (chip->mixer_data) {
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
785
  			struct awacs_amp *amp = chip->mixer_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786
787
788
789
790
791
792
793
794
795
796
797
798
  			int changed;
  			if (snd_pmac_awacs_detect_headphone(chip)) {
  				changed = toggle_amp_mute(amp, AMP_CH_HD, 0);
  				changed |= toggle_amp_mute(amp, AMP_CH_SPK, 1);
  			} else {
  				changed = toggle_amp_mute(amp, AMP_CH_HD, 1);
  				changed |= toggle_amp_mute(amp, AMP_CH_SPK, 0);
  			}
  			if (do_notify && ! changed)
  				return;
  		} else
  #endif
  		{
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
799
800
  			int reg = chip->awacs_reg[1]
  				| (MASK_HDMUTE | MASK_SPKMUTE);
030b655b0   Risto Suominen   ALSA: snd-powerma...
801
802
803
804
  			if (imac1) {
  				reg &= ~MASK_SPKMUTE;
  				reg |= MASK_PAROUT1;
  			} else if (imac2) {
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
805
806
807
  				reg &= ~MASK_SPKMUTE;
  				reg &= ~MASK_PAROUT1;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
809
  			if (snd_pmac_awacs_detect_headphone(chip))
  				reg &= ~MASK_HDMUTE;
030b655b0   Risto Suominen   ALSA: snd-powerma...
810
811
812
  			else if (imac1)
  				reg &= ~MASK_PAROUT1;
  			else if (imac2)
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
813
  				reg |= MASK_PAROUT1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
  			else
  				reg &= ~MASK_SPKMUTE;
  			if (do_notify && reg == chip->awacs_reg[1])
  				return;
  			snd_pmac_awacs_write_reg(chip, 1, reg);
  		}
  		if (do_notify) {
  			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
  				       &chip->master_sw_ctl->id);
  			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
  				       &chip->speaker_sw_ctl->id);
  			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
  				       &chip->hp_detect_ctl->id);
  		}
  	}
  }
  #endif /* PMAC_SUPPORT_AUTOMUTE */
  
  
  /*
   * initialize chip
   */
5c9b6e9e6   Stephen Rothwell   ALSA: sound/ppc: ...
836
  int __devinit
65b29f503   Takashi Iwai   [ALSA] Remove xxx...
837
  snd_pmac_awacs_init(struct snd_pmac *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
838
  {
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
839
  	int pm7500 = IS_PM7500;
b0a8a8fd1   Risto Suominen   ALSA: powermac - ...
840
  	int pm5500 = IS_PM5500;
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
841
  	int beige = IS_BEIGE;
4dbf95ba6   Risto Suominen   ALSA: snd-powerma...
842
  	int g4agp = IS_G4AGP;
573934bc0   Risto Suominen   ALSA: powermac - ...
843
  	int lombard = IS_LOMBARD;
030b655b0   Risto Suominen   ALSA: snd-powerma...
844
  	int imac;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
845
  	int err, vol;
dca7c7417   Risto Suominen   ALSA: Add vmaster...
846
847
  	struct snd_kcontrol *vmaster_sw, *vmaster_vol;
  	struct snd_kcontrol *master_vol, *speaker_vol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848

030b655b0   Risto Suominen   ALSA: snd-powerma...
849
850
851
  	imac1 = IS_IMAC1;
  	imac2 = IS_IMAC2;
  	imac = imac1 || imac2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
852
853
854
855
856
857
858
  	/* looks like MASK_GAINLINE triggers something, so we set here
  	 * as start-up
  	 */
  	chip->awacs_reg[0] = MASK_MUX_CD | 0xff | MASK_GAINLINE;
  	chip->awacs_reg[1] = MASK_CMUTE | MASK_AMUTE;
  	/* FIXME: Only machines with external SRS module need MASK_PAROUT */
  	if (chip->has_iic || chip->device_id == 0x5 ||
7ae44cfa7   Risto Suominen   [ALSA] snd-powerm...
859
  	    /* chip->_device_id == 0x8 || */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
860
861
862
863
864
865
866
867
868
869
  	    chip->device_id == 0xb)
  		chip->awacs_reg[1] |= MASK_PAROUT;
  	/* get default volume from nvram */
  	// vol = (~nvram_read_byte(0x1308) & 7) << 1;
  	// vol = ((pmac_xpram_read( 8 ) & 7 ) << 1 );
  	vol = 0x0f; /* no, on alsa, muted as default */
  	vol = vol + (vol << 6);
  	chip->awacs_reg[2] = vol;
  	chip->awacs_reg[4] = vol;
  	if (chip->model == PMAC_SCREAMER) {
7ae44cfa7   Risto Suominen   [ALSA] snd-powerm...
870
871
872
873
  		/* FIXME: screamer has loopthru vol control */
  		chip->awacs_reg[5] = vol;
  		/* FIXME: maybe should be vol << 3 for PCMCIA speaker */
  		chip->awacs_reg[6] = MASK_MIC_BOOST;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
874
875
876
877
878
879
880
881
882
883
  		chip->awacs_reg[7] = 0;
  	}
  
  	awacs_restore_all_regs(chip);
  	chip->manufacturer = (in_le32(&chip->awacs->codec_stat) >> 8) & 0xf;
  	screamer_recalibrate(chip);
  
  	chip->revision = (in_le32(&chip->awacs->codec_stat) >> 12) & 0xf;
  #ifdef PMAC_AMP_AVAIL
  	if (chip->revision == 3 && chip->has_iic && CHECK_CUDA_AMP()) {
59feddb25   Panagiotis Issaris   [ALSA] Conversion...
884
  		struct awacs_amp *amp = kzalloc(sizeof(*amp), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
885
886
887
  		if (! amp)
  			return -ENOMEM;
  		chip->mixer_data = amp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
888
  		chip->mixer_free = awacs_amp_free;
7ae44cfa7   Risto Suominen   [ALSA] snd-powerm...
889
890
  		/* mute and zero vol */
  		awacs_amp_set_vol(amp, 0, 63, 63, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
891
892
893
894
895
896
897
898
899
900
  		awacs_amp_set_vol(amp, 1, 63, 63, 0);
  		awacs_amp_set_tone(amp, 7, 7); /* 0 dB */
  		awacs_amp_set_master(amp, 79); /* 0 dB */
  	}
  #endif /* PMAC_AMP_AVAIL */
  
  	if (chip->hp_stat_mask == 0) {
  		/* set headphone-jack detection bit */
  		switch (chip->model) {
  		case PMAC_AWACS:
b0a8a8fd1   Risto Suominen   ALSA: powermac - ...
901
  			chip->hp_stat_mask = pm7500 || pm5500 ? MASK_HDPCONN
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
902
  				: MASK_LOCONN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903
904
905
906
  			break;
  		case PMAC_SCREAMER:
  			switch (chip->device_id) {
  			case 0x08:
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
907
908
909
910
911
912
  			case 0x0B:
  				chip->hp_stat_mask = imac
  					? MASK_LOCONN_IMAC |
  					MASK_HDPLCONN_IMAC |
  					MASK_HDPRCONN_IMAC
  					: MASK_HDPCONN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
913
914
915
  				break;
  			case 0x00:
  			case 0x05:
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
916
  				chip->hp_stat_mask = MASK_LOCONN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917
918
  				break;
  			default:
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
919
  				chip->hp_stat_mask = MASK_HDPCONN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
920
921
922
923
924
925
926
927
928
929
930
931
932
  				break;
  			}
  			break;
  		default:
  			snd_BUG();
  			break;
  		}
  	}
  
  	/*
  	 * build mixers
  	 */
  	strcpy(chip->card->mixername, "PowerMac AWACS");
7ae44cfa7   Risto Suominen   [ALSA] snd-powerm...
933
934
935
  	err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mixers),
  				snd_pmac_awacs_mixers);
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
936
  		return err;
4dbf95ba6   Risto Suominen   ALSA: snd-powerma...
937
  	if (beige || g4agp)
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
938
  		;
b0a8a8fd1   Risto Suominen   ALSA: powermac - ...
939
  	else if (chip->model == PMAC_SCREAMER || pm5500)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
940
941
  		err = build_mixers(chip, ARRAY_SIZE(snd_pmac_screamer_mixers2),
  				   snd_pmac_screamer_mixers2);
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
942
  	else if (!pm7500)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
943
944
945
946
  		err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mixers2),
  				   snd_pmac_awacs_mixers2);
  	if (err < 0)
  		return err;
dca7c7417   Risto Suominen   ALSA: Add vmaster...
947
948
949
950
951
952
953
  	if (pm5500) {
  		err = build_mixers(chip,
  				   ARRAY_SIZE(snd_pmac_awacs_mixers2_pmac5500),
  				   snd_pmac_awacs_mixers2_pmac5500);
  		if (err < 0)
  			return err;
  	}
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
954
955
956
957
  	if (pm7500)
  		err = build_mixers(chip,
  				   ARRAY_SIZE(snd_pmac_awacs_mixers_pmac7500),
  				   snd_pmac_awacs_mixers_pmac7500);
dca7c7417   Risto Suominen   ALSA: Add vmaster...
958
959
960
961
  	else if (pm5500)
  		err = snd_ctl_add(chip->card,
  		    (master_vol = snd_ctl_new1(snd_pmac_awacs_mixers_pmac5500,
  						chip)));
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
962
963
964
965
  	else if (beige)
  		err = build_mixers(chip,
  				   ARRAY_SIZE(snd_pmac_screamer_mixers_beige),
  				   snd_pmac_screamer_mixers_beige);
dca7c7417   Risto Suominen   ALSA: Add vmaster...
966
967
968
969
970
971
  	else if (imac || lombard) {
  		err = snd_ctl_add(chip->card,
  		    (master_vol = snd_ctl_new1(snd_pmac_screamer_mixers_lo,
  						chip)));
  		if (err < 0)
  			return err;
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
972
973
974
  		err = build_mixers(chip,
  				   ARRAY_SIZE(snd_pmac_screamer_mixers_imac),
  				   snd_pmac_screamer_mixers_imac);
dca7c7417   Risto Suominen   ALSA: Add vmaster...
975
  	} else if (g4agp)
4dbf95ba6   Risto Suominen   ALSA: snd-powerma...
976
977
978
  		err = build_mixers(chip,
  				   ARRAY_SIZE(snd_pmac_screamer_mixers_g4agp),
  				   snd_pmac_screamer_mixers_g4agp);
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
979
980
981
982
983
984
  	else
  		err = build_mixers(chip,
  				   ARRAY_SIZE(snd_pmac_awacs_mixers_pmac),
  				   snd_pmac_awacs_mixers_pmac);
  	if (err < 0)
  		return err;
573934bc0   Risto Suominen   ALSA: powermac - ...
985
  	chip->master_sw_ctl = snd_ctl_new1((pm7500 || imac || g4agp || lombard)
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
986
  			? &snd_pmac_awacs_master_sw_imac
dca7c7417   Risto Suominen   ALSA: Add vmaster...
987
988
  			: pm5500
  			? &snd_pmac_awacs_master_sw_pmac5500
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
989
  			: &snd_pmac_awacs_master_sw, chip);
7ae44cfa7   Risto Suominen   [ALSA] snd-powerm...
990
991
  	err = snd_ctl_add(chip->card, chip->master_sw_ctl);
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
992
993
994
995
996
997
998
999
1000
  		return err;
  #ifdef PMAC_AMP_AVAIL
  	if (chip->mixer_data) {
  		/* use amplifier.  the signal is connected from route A
  		 * to the amp.  the amp has its headphone and speaker
  		 * volumes and mute switches, so we use them instead of
  		 * screamer registers.
  		 * in this case, it seems the route C is not used.
  		 */
7ae44cfa7   Risto Suominen   [ALSA] snd-powerm...
1001
1002
1003
  		err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_amp_vol),
  					snd_pmac_awacs_amp_vol);
  		if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1004
1005
  			return err;
  		/* overwrite */
7ae44cfa7   Risto Suominen   [ALSA] snd-powerm...
1006
1007
1008
1009
  		chip->master_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_amp_hp_sw,
  							chip);
  		err = snd_ctl_add(chip->card, chip->master_sw_ctl);
  		if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1010
  			return err;
7ae44cfa7   Risto Suominen   [ALSA] snd-powerm...
1011
1012
1013
1014
  		chip->speaker_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_amp_spk_sw,
  							chip);
  		err = snd_ctl_add(chip->card, chip->speaker_sw_ctl);
  		if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1015
1016
1017
1018
1019
  			return err;
  	} else
  #endif /* PMAC_AMP_AVAIL */
  	{
  		/* route A = headphone, route C = speaker */
dca7c7417   Risto Suominen   ALSA: Add vmaster...
1020
1021
1022
  		err = snd_ctl_add(chip->card,
  		    (speaker_vol = snd_ctl_new1(snd_pmac_awacs_speaker_vol,
  						chip)));
7ae44cfa7   Risto Suominen   [ALSA] snd-powerm...
1023
  		if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1024
  			return err;
030b655b0   Risto Suominen   ALSA: snd-powerma...
1025
1026
1027
1028
  		chip->speaker_sw_ctl = snd_ctl_new1(imac1
  				? &snd_pmac_awacs_speaker_sw_imac1
  				: imac2
  				? &snd_pmac_awacs_speaker_sw_imac2
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
1029
  				: &snd_pmac_awacs_speaker_sw, chip);
7ae44cfa7   Risto Suominen   [ALSA] snd-powerm...
1030
1031
  		err = snd_ctl_add(chip->card, chip->speaker_sw_ctl);
  		if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1032
1033
  			return err;
  	}
dca7c7417   Risto Suominen   ALSA: Add vmaster...
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
  	if (pm5500 || imac || lombard) {
  		vmaster_sw = snd_ctl_make_virtual_master(
  			"Master Playback Switch", (unsigned int *) NULL);
  		err = snd_ctl_add_slave_uncached(vmaster_sw,
  						 chip->master_sw_ctl);
  		if (err < 0)
  			return err;
  		err = snd_ctl_add_slave_uncached(vmaster_sw,
  						  chip->speaker_sw_ctl);
  		if (err < 0)
  			return err;
  		err = snd_ctl_add(chip->card, vmaster_sw);
  		if (err < 0)
  			return err;
  		vmaster_vol = snd_ctl_make_virtual_master(
  			"Master Playback Volume", (unsigned int *) NULL);
  		err = snd_ctl_add_slave(vmaster_vol, master_vol);
  		if (err < 0)
  			return err;
  		err = snd_ctl_add_slave(vmaster_vol, speaker_vol);
  		if (err < 0)
  			return err;
  		err = snd_ctl_add(chip->card, vmaster_vol);
  		if (err < 0)
  			return err;
  	}
4dbf95ba6   Risto Suominen   ALSA: snd-powerma...
1060
  	if (beige || g4agp)
a8c2a6bf4   Risto Suominen   [ALSA] snd-powerm...
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
  		err = build_mixers(chip,
  				ARRAY_SIZE(snd_pmac_screamer_mic_boost_beige),
  				snd_pmac_screamer_mic_boost_beige);
  	else if (imac)
  		err = build_mixers(chip,
  				ARRAY_SIZE(snd_pmac_screamer_mic_boost_imac),
  				snd_pmac_screamer_mic_boost_imac);
  	else if (chip->model == PMAC_SCREAMER)
  		err = build_mixers(chip,
  				ARRAY_SIZE(snd_pmac_screamer_mic_boost),
  				snd_pmac_screamer_mic_boost);
  	else if (pm7500)
  		err = build_mixers(chip,
  				ARRAY_SIZE(snd_pmac_awacs_mic_boost_pmac7500),
  				snd_pmac_awacs_mic_boost_pmac7500);
  	else
  		err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mic_boost),
  				snd_pmac_awacs_mic_boost);
  	if (err < 0)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1081
1082
1083
1084
1085
  
  	/*
  	 * set lowlevel callbacks
  	 */
  	chip->set_format = snd_pmac_awacs_set_format;
8c8709334   Benjamin Herrenschmidt   [PATCH] ppc32: Re...
1086
  #ifdef CONFIG_PM
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1087
1088
1089
1090
  	chip->suspend = snd_pmac_awacs_suspend;
  	chip->resume = snd_pmac_awacs_resume;
  #endif
  #ifdef PMAC_SUPPORT_AUTOMUTE
7ae44cfa7   Risto Suominen   [ALSA] snd-powerm...
1091
1092
  	err = snd_pmac_add_automute(chip);
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
  		return err;
  	chip->detect_headphone = snd_pmac_awacs_detect_headphone;
  	chip->update_automute = snd_pmac_awacs_update_automute;
  	snd_pmac_awacs_update_automute(chip, 0); /* update the status only */
  #endif
  	if (chip->model == PMAC_SCREAMER) {
  		snd_pmac_awacs_write_noreg(chip, 6, chip->awacs_reg[6]);
  		snd_pmac_awacs_write_noreg(chip, 0, chip->awacs_reg[0]);
  	}
  
  	return 0;
  }