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