blob: ec0699c89952f9c0d5b9ecc62163afd6483a39eb [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * ALSA driver for ICEnsemble VT1724 (Envy24HT)
3 *
4 * Lowlevel functions for Terratec Aureon cards
5 *
6 * Copyright (c) 2003 Takashi Iwai <tiwai@suse.de>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 *
23 * NOTES:
24 *
Takashi Iwaiab0c7d72005-11-17 15:00:18 +010025 * - we reuse the struct snd_akm4xxx record for storing the wm8770 codec data.
Linus Torvalds1da177e2005-04-16 15:20:36 -070026 * both wm and akm codecs are pretty similar, so we can integrate
27 * both controls in the future, once if wm codecs are reused in
28 * many boards.
29 *
30 * - DAC digital volumes are not implemented in the mixer.
31 * if they show better response than DAC analog volumes, we can use them
32 * instead.
33 *
34 * Lowlevel functions for AudioTrak Prodigy 7.1 (and possibly 192) cards
35 * Copyright (c) 2003 Dimitromanolakis Apostolos <apostol@cs.utoronto.ca>
36 *
37 * version 0.82: Stable / not all features work yet (no communication with AC97 secondary)
38 * added 64x/128x oversampling switch (should be 64x only for 96khz)
39 * fixed some recording labels (still need to check the rest)
40 * recording is working probably thanks to correct wm8770 initialization
41 *
42 * version 0.5: Initial release:
43 * working: analog output, mixer, headphone amplifier switch
44 * not working: prety much everything else, at least i could verify that
45 * we have no digital output, no capture, pretty bad clicks and poops
46 * on mixer switch and other coll stuff.
47 *
48 */
49
50#include <sound/driver.h>
51#include <asm/io.h>
52#include <linux/delay.h>
53#include <linux/interrupt.h>
54#include <linux/init.h>
55#include <linux/slab.h>
Ingo Molnar62932df2006-01-16 16:34:20 +010056#include <linux/mutex.h>
57
Linus Torvalds1da177e2005-04-16 15:20:36 -070058#include <sound/core.h>
59
60#include "ice1712.h"
61#include "envy24ht.h"
62#include "aureon.h"
Takashi Iwaif640c322006-08-30 16:57:37 +020063#include <sound/tlv.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
65/* WM8770 registers */
66#define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */
67#define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */
68#define WM_DAC_DIG_ATTEN 0x09 /* DAC1-8 digital attenuation */
69#define WM_DAC_DIG_MASTER_ATTEN 0x11 /* DAC master digital attenuation */
70#define WM_PHASE_SWAP 0x12 /* DAC phase */
71#define WM_DAC_CTRL1 0x13 /* DAC control bits */
72#define WM_MUTE 0x14 /* mute controls */
73#define WM_DAC_CTRL2 0x15 /* de-emphasis and zefo-flag */
74#define WM_INT_CTRL 0x16 /* interface control */
75#define WM_MASTER 0x17 /* master clock and mode */
76#define WM_POWERDOWN 0x18 /* power-down controls */
77#define WM_ADC_GAIN 0x19 /* ADC gain L(19)/R(1a) */
78#define WM_ADC_MUX 0x1b /* input MUX */
79#define WM_OUT_MUX1 0x1c /* output MUX */
80#define WM_OUT_MUX2 0x1e /* output MUX */
81#define WM_RESET 0x1f /* software reset */
82
83/* CS8415A registers */
84#define CS8415_CTRL1 0x01
85#define CS8415_CTRL2 0x02
86#define CS8415_QSUB 0x14
87#define CS8415_RATIO 0x1E
88#define CS8415_C_BUFFER 0x20
89#define CS8415_ID 0x7F
90
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +020091/* PCA9554 registers */
92#define PCA9554_DEV 0x40 /* I2C device address */
93#define PCA9554_IN 0x00 /* input port */
94#define PCA9554_OUT 0x01 /* output port */
95#define PCA9554_INVERT 0x02 /* input invert */
96#define PCA9554_DIR 0x03 /* port directions */
97
98/*
99 * Aureon Universe additional controls using PCA9554
100 */
101
102/*
103 * Send data to pca9554
104 */
105static void aureon_pca9554_write(struct snd_ice1712 *ice, unsigned char reg,
106 unsigned char data)
107{
108 unsigned int tmp;
109 int i, j;
110 unsigned char dev = PCA9554_DEV; /* ID 0100000, write */
111 unsigned char val = 0;
112
113 tmp = snd_ice1712_gpio_read(ice);
114
115 snd_ice1712_gpio_set_mask(ice, ~(AUREON_SPI_MOSI|AUREON_SPI_CLK|
116 AUREON_WM_RW|AUREON_WM_CS|
117 AUREON_CS8415_CS));
118 tmp |= AUREON_WM_RW;
119 tmp |= AUREON_CS8415_CS | AUREON_WM_CS; /* disable SPI devices */
120
121 tmp &= ~AUREON_SPI_MOSI;
122 tmp &= ~AUREON_SPI_CLK;
123 snd_ice1712_gpio_write(ice, tmp);
124 udelay(50);
125
126 /*
127 * send i2c stop condition and start condition
128 * to obtain sane state
129 */
130 tmp |= AUREON_SPI_CLK;
131 snd_ice1712_gpio_write(ice, tmp);
132 udelay(50);
133 tmp |= AUREON_SPI_MOSI;
134 snd_ice1712_gpio_write(ice, tmp);
135 udelay(100);
136 tmp &= ~AUREON_SPI_MOSI;
137 snd_ice1712_gpio_write(ice, tmp);
138 udelay(50);
139 tmp &= ~AUREON_SPI_CLK;
140 snd_ice1712_gpio_write(ice, tmp);
141 udelay(100);
142 /*
143 * send device address, command and value,
144 * skipping ack cycles inbetween
145 */
146 for (j = 0; j < 3; j++) {
147 switch(j) {
148 case 0: val = dev; break;
149 case 1: val = reg; break;
150 case 2: val = data; break;
151 }
152 for (i = 7; i >= 0; i--) {
153 tmp &= ~AUREON_SPI_CLK;
154 snd_ice1712_gpio_write(ice, tmp);
155 udelay(40);
156 if (val & (1 << i))
157 tmp |= AUREON_SPI_MOSI;
158 else
159 tmp &= ~AUREON_SPI_MOSI;
160 snd_ice1712_gpio_write(ice, tmp);
161 udelay(40);
162 tmp |= AUREON_SPI_CLK;
163 snd_ice1712_gpio_write(ice, tmp);
164 udelay(40);
165 }
166 tmp &= ~AUREON_SPI_CLK;
167 snd_ice1712_gpio_write(ice, tmp);
168 udelay(40);
169 tmp |= AUREON_SPI_CLK;
170 snd_ice1712_gpio_write(ice, tmp);
171 udelay(40);
172 tmp &= ~AUREON_SPI_CLK;
173 snd_ice1712_gpio_write(ice, tmp);
174 udelay(40);
175 }
176 tmp &= ~AUREON_SPI_CLK;
177 snd_ice1712_gpio_write(ice, tmp);
178 udelay(40);
179 tmp &= ~AUREON_SPI_MOSI;
180 snd_ice1712_gpio_write(ice, tmp);
181 udelay(40);
182 tmp |= AUREON_SPI_CLK;
183 snd_ice1712_gpio_write(ice, tmp);
184 udelay(50);
185 tmp |= AUREON_SPI_MOSI;
186 snd_ice1712_gpio_write(ice, tmp);
187 udelay(100);
188}
189
190static int aureon_universe_inmux_info(struct snd_kcontrol *kcontrol,
191 struct snd_ctl_elem_info *uinfo)
192{
193 char *texts[3] = {"Internal Aux", "Wavetable", "Rear Line-In"};
194
195 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
196 uinfo->count = 1;
197 uinfo->value.enumerated.items = 3;
198 if(uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
199 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
200 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
201 return 0;
202}
203
204static int aureon_universe_inmux_get(struct snd_kcontrol *kcontrol,
205 struct snd_ctl_elem_value *ucontrol)
206{
207 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
208 ucontrol->value.integer.value[0] = ice->spec.aureon.pca9554_out;
209 return 0;
210}
211
212static int aureon_universe_inmux_put(struct snd_kcontrol *kcontrol,
213 struct snd_ctl_elem_value *ucontrol)
214{
215 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
216 unsigned char oval, nval;
217 int change;
218
219 snd_ice1712_save_gpio_status(ice);
220
221 oval = ice->spec.aureon.pca9554_out;
222 nval = ucontrol->value.integer.value[0];
223 if ((change = (oval != nval))) {
224 aureon_pca9554_write(ice, PCA9554_OUT, nval);
225 ice->spec.aureon.pca9554_out = nval;
226 }
227 snd_ice1712_restore_gpio_status(ice);
228
229 return change;
230}
231
232
233static void aureon_ac97_write(struct snd_ice1712 *ice, unsigned short reg,
234 unsigned short val)
235{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 unsigned int tmp;
237
238 /* Send address to XILINX chip */
239 tmp = (snd_ice1712_gpio_read(ice) & ~0xFF) | (reg & 0x7F);
240 snd_ice1712_gpio_write(ice, tmp);
241 udelay(10);
242 tmp |= AUREON_AC97_ADDR;
243 snd_ice1712_gpio_write(ice, tmp);
244 udelay(10);
245 tmp &= ~AUREON_AC97_ADDR;
246 snd_ice1712_gpio_write(ice, tmp);
247 udelay(10);
248
249 /* Send low-order byte to XILINX chip */
250 tmp &= ~AUREON_AC97_DATA_MASK;
251 tmp |= val & AUREON_AC97_DATA_MASK;
252 snd_ice1712_gpio_write(ice, tmp);
253 udelay(10);
254 tmp |= AUREON_AC97_DATA_LOW;
255 snd_ice1712_gpio_write(ice, tmp);
256 udelay(10);
257 tmp &= ~AUREON_AC97_DATA_LOW;
258 snd_ice1712_gpio_write(ice, tmp);
259 udelay(10);
260
261 /* Send high-order byte to XILINX chip */
262 tmp &= ~AUREON_AC97_DATA_MASK;
263 tmp |= (val >> 8) & AUREON_AC97_DATA_MASK;
264
265 snd_ice1712_gpio_write(ice, tmp);
266 udelay(10);
267 tmp |= AUREON_AC97_DATA_HIGH;
268 snd_ice1712_gpio_write(ice, tmp);
269 udelay(10);
270 tmp &= ~AUREON_AC97_DATA_HIGH;
271 snd_ice1712_gpio_write(ice, tmp);
272 udelay(10);
273
274 /* Instruct XILINX chip to parse the data to the STAC9744 chip */
275 tmp |= AUREON_AC97_COMMIT;
276 snd_ice1712_gpio_write(ice, tmp);
277 udelay(10);
278 tmp &= ~AUREON_AC97_COMMIT;
279 snd_ice1712_gpio_write(ice, tmp);
280 udelay(10);
281
282 /* Store the data in out private buffer */
283 ice->spec.aureon.stac9744[(reg & 0x7F) >> 1] = val;
284}
285
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100286static unsigned short aureon_ac97_read(struct snd_ice1712 *ice, unsigned short reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287{
288 return ice->spec.aureon.stac9744[(reg & 0x7F) >> 1];
289}
290
291/*
292 * Initialize STAC9744 chip
293 */
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200294static int aureon_ac97_init (struct snd_ice1712 *ice)
295{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 int i;
Takashi Iwai32b47da2007-01-29 15:26:36 +0100297 static const unsigned short ac97_defaults[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 0x00, 0x9640,
299 0x02, 0x8000,
300 0x04, 0x8000,
301 0x06, 0x8000,
302 0x0C, 0x8008,
303 0x0E, 0x8008,
304 0x10, 0x8808,
305 0x12, 0x8808,
306 0x14, 0x8808,
307 0x16, 0x8808,
308 0x18, 0x8808,
309 0x1C, 0x8000,
310 0x26, 0x000F,
311 0x28, 0x0201,
312 0x2C, 0xBB80,
313 0x32, 0xBB80,
314 0x7C, 0x8384,
315 0x7E, 0x7644,
316 (unsigned short)-1
317 };
318 unsigned int tmp;
319
320 /* Cold reset */
321 tmp = (snd_ice1712_gpio_read(ice) | AUREON_AC97_RESET) & ~AUREON_AC97_DATA_MASK;
322 snd_ice1712_gpio_write(ice, tmp);
323 udelay(3);
324
325 tmp &= ~AUREON_AC97_RESET;
326 snd_ice1712_gpio_write(ice, tmp);
327 udelay(3);
328
329 tmp |= AUREON_AC97_RESET;
330 snd_ice1712_gpio_write(ice, tmp);
331 udelay(3);
332
333 memset(&ice->spec.aureon.stac9744, 0, sizeof(ice->spec.aureon.stac9744));
334 for (i=0; ac97_defaults[i] != (unsigned short)-1; i+=2)
335 ice->spec.aureon.stac9744[(ac97_defaults[i]) >> 1] = ac97_defaults[i+1];
336
337 aureon_ac97_write(ice, AC97_MASTER, 0x0000); // Unmute AC'97 master volume permanently - muting is done by WM8770
338
339 return 0;
340}
341
342#define AUREON_AC97_STEREO 0x80
343
344/*
345 * AC'97 volume controls
346 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100347static int aureon_ac97_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348{
349 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
350 uinfo->count = kcontrol->private_value & AUREON_AC97_STEREO ? 2 : 1;
351 uinfo->value.integer.min = 0;
352 uinfo->value.integer.max = 31;
353 return 0;
354}
355
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100356static int aureon_ac97_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100358 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 unsigned short vol;
360
Ingo Molnar62932df2006-01-16 16:34:20 +0100361 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362
363 vol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
364 ucontrol->value.integer.value[0] = 0x1F - (vol & 0x1F);
365 if (kcontrol->private_value & AUREON_AC97_STEREO)
366 ucontrol->value.integer.value[1] = 0x1F - ((vol >> 8) & 0x1F);
367
Ingo Molnar62932df2006-01-16 16:34:20 +0100368 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 return 0;
370}
371
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100372static int aureon_ac97_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100374 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 unsigned short ovol, nvol;
376 int change;
377
378 snd_ice1712_save_gpio_status(ice);
379
380 ovol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
381 nvol = (0x1F - ucontrol->value.integer.value[0]) & 0x001F;
382 if (kcontrol->private_value & AUREON_AC97_STEREO)
383 nvol |= ((0x1F - ucontrol->value.integer.value[1]) << 8) & 0x1F00;
384 nvol |= ovol & ~0x1F1F;
385
386 if ((change = (ovol != nvol)))
387 aureon_ac97_write(ice, kcontrol->private_value & 0x7F, nvol);
388
389 snd_ice1712_restore_gpio_status(ice);
390
391 return change;
392}
393
394/*
395 * AC'97 mute controls
396 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200397#define aureon_ac97_mute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100399static int aureon_ac97_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100401 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402
Ingo Molnar62932df2006-01-16 16:34:20 +0100403 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404
405 ucontrol->value.integer.value[0] = aureon_ac97_read(ice, kcontrol->private_value & 0x7F) & 0x8000 ? 0 : 1;
406
Ingo Molnar62932df2006-01-16 16:34:20 +0100407 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 return 0;
409}
410
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100411static int aureon_ac97_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100413 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 unsigned short ovol, nvol;
415 int change;
416
417 snd_ice1712_save_gpio_status(ice);
418
419 ovol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
420 nvol = (ucontrol->value.integer.value[0] ? 0x0000 : 0x8000) | (ovol & ~ 0x8000);
421
422 if ((change = (ovol != nvol)))
423 aureon_ac97_write(ice, kcontrol->private_value & 0x7F, nvol);
424
425 snd_ice1712_restore_gpio_status(ice);
426
427 return change;
428}
429
430/*
431 * AC'97 mute controls
432 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200433#define aureon_ac97_micboost_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100435static int aureon_ac97_micboost_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100437 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438
Ingo Molnar62932df2006-01-16 16:34:20 +0100439 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440
441 ucontrol->value.integer.value[0] = aureon_ac97_read(ice, AC97_MIC) & 0x0020 ? 0 : 1;
442
Ingo Molnar62932df2006-01-16 16:34:20 +0100443 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 return 0;
445}
446
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100447static int aureon_ac97_micboost_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100449 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 unsigned short ovol, nvol;
451 int change;
452
453 snd_ice1712_save_gpio_status(ice);
454
455 ovol = aureon_ac97_read(ice, AC97_MIC);
456 nvol = (ucontrol->value.integer.value[0] ? 0x0000 : 0x0020) | (ovol & ~0x0020);
457
458 if ((change = (ovol != nvol)))
459 aureon_ac97_write(ice, AC97_MIC, nvol);
460
461 snd_ice1712_restore_gpio_status(ice);
462
463 return change;
464}
465
466/*
467 * write data in the SPI mode
468 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100469static void aureon_spi_write(struct snd_ice1712 *ice, unsigned int cs, unsigned int data, int bits)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470{
471 unsigned int tmp;
472 int i;
Takashi Iwai45fe7222006-01-13 13:50:16 +0100473 unsigned int mosi, clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474
475 tmp = snd_ice1712_gpio_read(ice);
476
Toshimune Konnocdf88ef2006-12-18 13:12:18 +0100477 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
478 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) {
Takashi Iwai45fe7222006-01-13 13:50:16 +0100479 snd_ice1712_gpio_set_mask(ice, ~(PRODIGY_SPI_MOSI|PRODIGY_SPI_CLK|PRODIGY_WM_CS));
480 mosi = PRODIGY_SPI_MOSI;
481 clk = PRODIGY_SPI_CLK;
482 }
483 else {
484 snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RW|AUREON_SPI_MOSI|AUREON_SPI_CLK|
485 AUREON_WM_CS|AUREON_CS8415_CS));
486 mosi = AUREON_SPI_MOSI;
487 clk = AUREON_SPI_CLK;
488
489 tmp |= AUREON_WM_RW;
490 }
491
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 tmp &= ~cs;
493 snd_ice1712_gpio_write(ice, tmp);
494 udelay(1);
495
496 for (i = bits - 1; i >= 0; i--) {
Takashi Iwai45fe7222006-01-13 13:50:16 +0100497 tmp &= ~clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 snd_ice1712_gpio_write(ice, tmp);
499 udelay(1);
500 if (data & (1 << i))
Takashi Iwai45fe7222006-01-13 13:50:16 +0100501 tmp |= mosi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 else
Takashi Iwai45fe7222006-01-13 13:50:16 +0100503 tmp &= ~mosi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 snd_ice1712_gpio_write(ice, tmp);
505 udelay(1);
Takashi Iwai45fe7222006-01-13 13:50:16 +0100506 tmp |= clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 snd_ice1712_gpio_write(ice, tmp);
508 udelay(1);
509 }
510
Takashi Iwai45fe7222006-01-13 13:50:16 +0100511 tmp &= ~clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 tmp |= cs;
513 snd_ice1712_gpio_write(ice, tmp);
514 udelay(1);
Takashi Iwai45fe7222006-01-13 13:50:16 +0100515 tmp |= clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 snd_ice1712_gpio_write(ice, tmp);
517 udelay(1);
518}
519
520/*
521 * Read data in SPI mode
522 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100523static void aureon_spi_read(struct snd_ice1712 *ice, unsigned int cs, unsigned int data, int bits, unsigned char *buffer, int size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 int i, j;
525 unsigned int tmp;
526
527 tmp = (snd_ice1712_gpio_read(ice) & ~AUREON_SPI_CLK) | AUREON_CS8415_CS|AUREON_WM_CS;
528 snd_ice1712_gpio_write(ice, tmp);
529 tmp &= ~cs;
530 snd_ice1712_gpio_write(ice, tmp);
531 udelay(1);
532
533 for (i=bits-1; i>=0; i--) {
534 if (data & (1 << i))
535 tmp |= AUREON_SPI_MOSI;
536 else
537 tmp &= ~AUREON_SPI_MOSI;
538 snd_ice1712_gpio_write(ice, tmp);
539 udelay(1);
540
541 tmp |= AUREON_SPI_CLK;
542 snd_ice1712_gpio_write(ice, tmp);
543 udelay(1);
544
545 tmp &= ~AUREON_SPI_CLK;
546 snd_ice1712_gpio_write(ice, tmp);
547 udelay(1);
548 }
549
550 for (j=0; j<size; j++) {
551 unsigned char outdata = 0;
552 for (i=7; i>=0; i--) {
553 tmp = snd_ice1712_gpio_read(ice);
554 outdata <<= 1;
555 outdata |= (tmp & AUREON_SPI_MISO) ? 1 : 0;
556 udelay(1);
557
558 tmp |= AUREON_SPI_CLK;
559 snd_ice1712_gpio_write(ice, tmp);
560 udelay(1);
561
562 tmp &= ~AUREON_SPI_CLK;
563 snd_ice1712_gpio_write(ice, tmp);
564 udelay(1);
565 }
566 buffer[j] = outdata;
567 }
568
569 tmp |= cs;
570 snd_ice1712_gpio_write(ice, tmp);
571}
572
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100573static unsigned char aureon_cs8415_get(struct snd_ice1712 *ice, int reg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 unsigned char val;
575 aureon_spi_write(ice, AUREON_CS8415_CS, 0x2000 | reg, 16);
576 aureon_spi_read(ice, AUREON_CS8415_CS, 0x21, 8, &val, 1);
577 return val;
578}
579
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100580static void aureon_cs8415_read(struct snd_ice1712 *ice, int reg, unsigned char *buffer, int size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 aureon_spi_write(ice, AUREON_CS8415_CS, 0x2000 | reg, 16);
582 aureon_spi_read(ice, AUREON_CS8415_CS, 0x21, 8, buffer, size);
583}
584
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100585static void aureon_cs8415_put(struct snd_ice1712 *ice, int reg, unsigned char val) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 aureon_spi_write(ice, AUREON_CS8415_CS, 0x200000 | (reg << 8) | val, 24);
587}
588
589/*
590 * get the current register value of WM codec
591 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100592static unsigned short wm_get(struct snd_ice1712 *ice, int reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593{
594 reg <<= 1;
595 return ((unsigned short)ice->akm[0].images[reg] << 8) |
596 ice->akm[0].images[reg + 1];
597}
598
599/*
600 * set the register value of WM codec
601 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100602static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603{
Takashi Iwai45fe7222006-01-13 13:50:16 +0100604 aureon_spi_write(ice,
Toshimune Konnocdf88ef2006-12-18 13:12:18 +0100605 ((ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
606 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) ?
607 PRODIGY_WM_CS : AUREON_WM_CS),
Takashi Iwai45fe7222006-01-13 13:50:16 +0100608 (reg << 9) | (val & 0x1ff), 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609}
610
611/*
612 * set the register value of WM codec and remember it
613 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100614static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615{
616 wm_put_nocache(ice, reg, val);
617 reg <<= 1;
618 ice->akm[0].images[reg] = val >> 8;
619 ice->akm[0].images[reg + 1] = val;
620}
621
622/*
623 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200624#define aureon_mono_bool_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
626/*
627 * AC'97 master playback mute controls (Mute on WM8770 chip)
628 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200629#define aureon_ac97_mmute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100631static int aureon_ac97_mmute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100633 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634
Ingo Molnar62932df2006-01-16 16:34:20 +0100635 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636
637 ucontrol->value.integer.value[0] = (wm_get(ice, WM_OUT_MUX1) >> 1) & 0x01;
638
Ingo Molnar62932df2006-01-16 16:34:20 +0100639 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 return 0;
641}
642
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100643static int aureon_ac97_mmute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
644 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 unsigned short ovol, nvol;
646 int change;
647
648 snd_ice1712_save_gpio_status(ice);
649
650 ovol = wm_get(ice, WM_OUT_MUX1);
651 nvol = (ovol & ~0x02) | (ucontrol->value.integer.value[0] ? 0x02 : 0x00);
652 if ((change = (ovol != nvol)))
653 wm_put(ice, WM_OUT_MUX1, nvol);
654
655 snd_ice1712_restore_gpio_status(ice);
656
657 return change;
658}
659
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100660static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
661static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
662static const DECLARE_TLV_DB_SCALE(db_scale_wm_adc, -1200, 100, 0);
663static const DECLARE_TLV_DB_SCALE(db_scale_ac97_master, -4650, 150, 0);
664static const DECLARE_TLV_DB_SCALE(db_scale_ac97_gain, -3450, 150, 0);
Takashi Iwaif640c322006-08-30 16:57:37 +0200665
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666/*
667 * Logarithmic volume values for WM8770
668 * Computed as 20 * Log10(255 / x)
669 */
Takashi Iwai32b47da2007-01-29 15:26:36 +0100670static const unsigned char wm_vol[256] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23,
672 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17,
673 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13,
674 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11,
675 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8,
676 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6,
677 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
678 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3,
679 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
680 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
681 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
682 0, 0
683};
684
685#define WM_VOL_MAX (sizeof(wm_vol) - 1)
686#define WM_VOL_MUTE 0x8000
687
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100688static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, unsigned short vol, unsigned short master)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689{
690 unsigned char nvol;
691
692 if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))
693 nvol = 0;
694 else
695 nvol = 127 - wm_vol[(((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 127) & WM_VOL_MAX];
696
697 wm_put(ice, index, nvol);
698 wm_put_nocache(ice, index, 0x180 | nvol);
699}
700
701/*
702 * DAC mute control
703 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200704#define wm_pcm_mute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100706static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100708 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
Ingo Molnar62932df2006-01-16 16:34:20 +0100710 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1;
Ingo Molnar62932df2006-01-16 16:34:20 +0100712 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 return 0;
714}
715
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100716static int wm_pcm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100718 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 unsigned short nval, oval;
720 int change;
721
722 snd_ice1712_save_gpio_status(ice);
723 oval = wm_get(ice, WM_MUTE);
724 nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10);
725 if ((change = (nval != oval)))
726 wm_put(ice, WM_MUTE, nval);
727 snd_ice1712_restore_gpio_status(ice);
728
729 return change;
730}
731
732/*
733 * Master volume attenuation mixer control
734 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100735static int wm_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736{
737 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
738 uinfo->count = 2;
739 uinfo->value.integer.min = 0;
740 uinfo->value.integer.max = WM_VOL_MAX;
741 return 0;
742}
743
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100744static int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100746 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 int i;
748 for (i=0; i<2; i++)
749 ucontrol->value.integer.value[i] = ice->spec.aureon.master[i] & ~WM_VOL_MUTE;
750 return 0;
751}
752
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100753static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100755 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 int ch, change = 0;
757
758 snd_ice1712_save_gpio_status(ice);
759 for (ch = 0; ch < 2; ch++) {
760 if (ucontrol->value.integer.value[ch] != ice->spec.aureon.master[ch]) {
761 int dac;
762 ice->spec.aureon.master[ch] &= WM_VOL_MUTE;
763 ice->spec.aureon.master[ch] |= ucontrol->value.integer.value[ch];
764 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
765 wm_set_vol(ice, WM_DAC_ATTEN + dac + ch,
766 ice->spec.aureon.vol[dac + ch],
767 ice->spec.aureon.master[ch]);
768 change = 1;
769 }
770 }
771 snd_ice1712_restore_gpio_status(ice);
772 return change;
773}
774
775/*
776 * DAC volume attenuation mixer control
777 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100778static int wm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779{
780 int voices = kcontrol->private_value >> 8;
781 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
782 uinfo->count = voices;
783 uinfo->value.integer.min = 0; /* mute (-101dB) */
784 uinfo->value.integer.max = 0x7F; /* 0dB */
785 return 0;
786}
787
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100788static int wm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100790 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 int i, ofs, voices;
792
793 voices = kcontrol->private_value >> 8;
794 ofs = kcontrol->private_value & 0xff;
795 for (i = 0; i < voices; i++)
796 ucontrol->value.integer.value[i] = ice->spec.aureon.vol[ofs+i] & ~WM_VOL_MUTE;
797 return 0;
798}
799
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100800static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100802 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 int i, idx, ofs, voices;
804 int change = 0;
805
806 voices = kcontrol->private_value >> 8;
807 ofs = kcontrol->private_value & 0xff;
808 snd_ice1712_save_gpio_status(ice);
809 for (i = 0; i < voices; i++) {
810 idx = WM_DAC_ATTEN + ofs + i;
811 if (ucontrol->value.integer.value[i] != ice->spec.aureon.vol[ofs+i]) {
812 ice->spec.aureon.vol[ofs+i] &= WM_VOL_MUTE;
813 ice->spec.aureon.vol[ofs+i] |= ucontrol->value.integer.value[i];
814 wm_set_vol(ice, idx, ice->spec.aureon.vol[ofs+i],
815 ice->spec.aureon.master[i]);
816 change = 1;
817 }
818 }
819 snd_ice1712_restore_gpio_status(ice);
820 return change;
821}
822
823/*
824 * WM8770 mute control
825 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100826static int wm_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
828 uinfo->count = kcontrol->private_value >> 8;
829 uinfo->value.integer.min = 0;
830 uinfo->value.integer.max = 1;
831 return 0;
832}
833
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100834static int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100836 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 int voices, ofs, i;
838
839 voices = kcontrol->private_value >> 8;
840 ofs = kcontrol->private_value & 0xFF;
841
842 for (i = 0; i < voices; i++)
843 ucontrol->value.integer.value[i] = (ice->spec.aureon.vol[ofs+i] & WM_VOL_MUTE) ? 0 : 1;
844 return 0;
845}
846
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100847static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100849 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 int change = 0, voices, ofs, i;
851
852 voices = kcontrol->private_value >> 8;
853 ofs = kcontrol->private_value & 0xFF;
854
855 snd_ice1712_save_gpio_status(ice);
856 for (i = 0; i < voices; i++) {
857 int val = (ice->spec.aureon.vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
858 if (ucontrol->value.integer.value[i] != val) {
859 ice->spec.aureon.vol[ofs + i] &= ~WM_VOL_MUTE;
860 ice->spec.aureon.vol[ofs + i] |=
861 ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
862 wm_set_vol(ice, ofs + i, ice->spec.aureon.vol[ofs + i],
863 ice->spec.aureon.master[i]);
864 change = 1;
865 }
866 }
867 snd_ice1712_restore_gpio_status(ice);
868
869 return change;
870}
871
872/*
873 * WM8770 master mute control
874 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200875#define wm_master_mute_info snd_ctl_boolean_stereo_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100877static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100879 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880
881 ucontrol->value.integer.value[0] = (ice->spec.aureon.master[0] & WM_VOL_MUTE) ? 0 : 1;
882 ucontrol->value.integer.value[1] = (ice->spec.aureon.master[1] & WM_VOL_MUTE) ? 0 : 1;
883 return 0;
884}
885
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100886static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100888 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 int change = 0, i;
890
891 snd_ice1712_save_gpio_status(ice);
892 for (i = 0; i < 2; i++) {
893 int val = (ice->spec.aureon.master[i] & WM_VOL_MUTE) ? 0 : 1;
894 if (ucontrol->value.integer.value[i] != val) {
895 int dac;
896 ice->spec.aureon.master[i] &= ~WM_VOL_MUTE;
897 ice->spec.aureon.master[i] |=
898 ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
899 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
900 wm_set_vol(ice, WM_DAC_ATTEN + dac + i,
901 ice->spec.aureon.vol[dac + i],
902 ice->spec.aureon.master[i]);
903 change = 1;
904 }
905 }
906 snd_ice1712_restore_gpio_status(ice);
907
908 return change;
909}
910
911/* digital master volume */
912#define PCM_0dB 0xff
913#define PCM_RES 128 /* -64dB */
914#define PCM_MIN (PCM_0dB - PCM_RES)
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100915static int wm_pcm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916{
917 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
918 uinfo->count = 1;
919 uinfo->value.integer.min = 0; /* mute (-64dB) */
920 uinfo->value.integer.max = PCM_RES; /* 0dB */
921 return 0;
922}
923
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100924static int wm_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100926 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 unsigned short val;
928
Ingo Molnar62932df2006-01-16 16:34:20 +0100929 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
931 val = val > PCM_MIN ? (val - PCM_MIN) : 0;
932 ucontrol->value.integer.value[0] = val;
Ingo Molnar62932df2006-01-16 16:34:20 +0100933 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 return 0;
935}
936
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100937static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100939 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 unsigned short ovol, nvol;
941 int change = 0;
942
943 snd_ice1712_save_gpio_status(ice);
944 nvol = ucontrol->value.integer.value[0];
945 nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff;
946 ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
947 if (ovol != nvol) {
948 wm_put(ice, WM_DAC_DIG_MASTER_ATTEN, nvol); /* prelatch */
949 wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100); /* update */
950 change = 1;
951 }
952 snd_ice1712_restore_gpio_status(ice);
953 return change;
954}
955
956/*
957 * ADC mute control
958 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200959#define wm_adc_mute_info snd_ctl_boolean_stereo_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100961static int wm_adc_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100963 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 unsigned short val;
965 int i;
966
Ingo Molnar62932df2006-01-16 16:34:20 +0100967 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 for (i = 0; i < 2; i++) {
969 val = wm_get(ice, WM_ADC_GAIN + i);
970 ucontrol->value.integer.value[i] = ~val>>5 & 0x1;
971 }
Ingo Molnar62932df2006-01-16 16:34:20 +0100972 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 return 0;
974}
975
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100976static int wm_adc_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100978 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 unsigned short new, old;
980 int i, change = 0;
981
982 snd_ice1712_save_gpio_status(ice);
983 for (i = 0; i < 2; i++) {
984 old = wm_get(ice, WM_ADC_GAIN + i);
985 new = (~ucontrol->value.integer.value[i]<<5&0x20) | (old&~0x20);
986 if (new != old) {
987 wm_put(ice, WM_ADC_GAIN + i, new);
988 change = 1;
989 }
990 }
991 snd_ice1712_restore_gpio_status(ice);
992
993 return change;
994}
995
996/*
997 * ADC gain mixer control
998 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100999static int wm_adc_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000{
1001 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1002 uinfo->count = 2;
1003 uinfo->value.integer.min = 0; /* -12dB */
1004 uinfo->value.integer.max = 0x1f; /* 19dB */
1005 return 0;
1006}
1007
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001008static int wm_adc_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001010 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 int i, idx;
1012 unsigned short vol;
1013
Ingo Molnar62932df2006-01-16 16:34:20 +01001014 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 for (i = 0; i < 2; i++) {
1016 idx = WM_ADC_GAIN + i;
1017 vol = wm_get(ice, idx) & 0x1f;
1018 ucontrol->value.integer.value[i] = vol;
1019 }
Ingo Molnar62932df2006-01-16 16:34:20 +01001020 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 return 0;
1022}
1023
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001024static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001026 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 int i, idx;
1028 unsigned short ovol, nvol;
1029 int change = 0;
1030
1031 snd_ice1712_save_gpio_status(ice);
1032 for (i = 0; i < 2; i++) {
1033 idx = WM_ADC_GAIN + i;
1034 nvol = ucontrol->value.integer.value[i];
1035 ovol = wm_get(ice, idx);
1036 if ((ovol & 0x1f) != nvol) {
1037 wm_put(ice, idx, nvol | (ovol & ~0x1f));
1038 change = 1;
1039 }
1040 }
1041 snd_ice1712_restore_gpio_status(ice);
1042 return change;
1043}
1044
1045/*
1046 * ADC input mux mixer control
1047 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001048static int wm_adc_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049{
Takashi Iwai32b47da2007-01-29 15:26:36 +01001050 static const char * const texts[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 "CD", //AIN1
1052 "Aux", //AIN2
1053 "Line", //AIN3
1054 "Mic", //AIN4
1055 "AC97" //AIN5
1056 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01001057 static const char * const universe_texts[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 "Aux1", //AIN1
1059 "CD", //AIN2
1060 "Phono", //AIN3
1061 "Line", //AIN4
1062 "Aux2", //AIN5
1063 "Mic", //AIN6
1064 "Aux3", //AIN7
1065 "AC97" //AIN8
1066 };
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001067 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068
1069 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1070 uinfo->count = 2;
1071 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) {
1072 uinfo->value.enumerated.items = 8;
1073 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1074 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1075 strcpy(uinfo->value.enumerated.name, universe_texts[uinfo->value.enumerated.item]);
1076 }
1077 else {
1078 uinfo->value.enumerated.items = 5;
1079 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1080 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1081 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1082 }
1083 return 0;
1084}
1085
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001086static int wm_adc_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001088 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 unsigned short val;
1090
Ingo Molnar62932df2006-01-16 16:34:20 +01001091 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 val = wm_get(ice, WM_ADC_MUX);
Takashi Iwai66820252006-03-20 18:31:57 +01001093 ucontrol->value.enumerated.item[0] = val & 7;
1094 ucontrol->value.enumerated.item[1] = (val >> 4) & 7;
Ingo Molnar62932df2006-01-16 16:34:20 +01001095 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 return 0;
1097}
1098
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001099static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001101 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 unsigned short oval, nval;
1103 int change;
1104
1105 snd_ice1712_save_gpio_status(ice);
1106 oval = wm_get(ice, WM_ADC_MUX);
1107 nval = oval & ~0x77;
Takashi Iwai66820252006-03-20 18:31:57 +01001108 nval |= ucontrol->value.enumerated.item[0] & 7;
1109 nval |= (ucontrol->value.enumerated.item[1] & 7) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 change = (oval != nval);
1111 if (change)
1112 wm_put(ice, WM_ADC_MUX, nval);
1113 snd_ice1712_restore_gpio_status(ice);
Takashi Iwai63786d02005-11-04 13:58:11 +01001114 return change;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115}
1116
1117/*
1118 * CS8415 Input mux
1119 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001120static int aureon_cs8415_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001122 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai32b47da2007-01-29 15:26:36 +01001123 static const char * const aureon_texts[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 "CD", //RXP0
1125 "Optical" //RXP1
1126 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01001127 static const char * const prodigy_texts[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 "CD",
1129 "Coax"
1130 };
1131 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1132 uinfo->count = 1;
1133 uinfo->value.enumerated.items = 2;
1134 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1135 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1136 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71)
1137 strcpy(uinfo->value.enumerated.name, prodigy_texts[uinfo->value.enumerated.item]);
1138 else
1139 strcpy(uinfo->value.enumerated.name, aureon_texts[uinfo->value.enumerated.item]);
1140 return 0;
1141}
1142
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001143static int aureon_cs8415_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001145 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146
1147 //snd_ice1712_save_gpio_status(ice);
1148 //val = aureon_cs8415_get(ice, CS8415_CTRL2);
Takashi Iwai66820252006-03-20 18:31:57 +01001149 ucontrol->value.enumerated.item[0] = ice->spec.aureon.cs8415_mux;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 //snd_ice1712_restore_gpio_status(ice);
1151 return 0;
1152}
1153
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001154static int aureon_cs8415_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001156 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 unsigned short oval, nval;
1158 int change;
1159
1160 snd_ice1712_save_gpio_status(ice);
1161 oval = aureon_cs8415_get(ice, CS8415_CTRL2);
1162 nval = oval & ~0x07;
Takashi Iwai66820252006-03-20 18:31:57 +01001163 nval |= ucontrol->value.enumerated.item[0] & 7;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 change = (oval != nval);
1165 if (change)
1166 aureon_cs8415_put(ice, CS8415_CTRL2, nval);
1167 snd_ice1712_restore_gpio_status(ice);
Takashi Iwai66820252006-03-20 18:31:57 +01001168 ice->spec.aureon.cs8415_mux = ucontrol->value.enumerated.item[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 return change;
1170}
1171
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001172static int aureon_cs8415_rate_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173{
1174 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1175 uinfo->count = 1;
1176 uinfo->value.integer.min = 0;
1177 uinfo->value.integer.max = 192000;
1178 return 0;
1179}
1180
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001181static int aureon_cs8415_rate_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001183 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 unsigned char ratio;
1185 ratio = aureon_cs8415_get(ice, CS8415_RATIO);
1186 ucontrol->value.integer.value[0] = (int)((unsigned int)ratio * 750);
1187 return 0;
1188}
1189
1190/*
1191 * CS8415A Mute
1192 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001193#define aureon_cs8415_mute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001195static int aureon_cs8415_mute_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001197 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 snd_ice1712_save_gpio_status(ice);
1199 ucontrol->value.integer.value[0] = (aureon_cs8415_get(ice, CS8415_CTRL1) & 0x20) ? 0 : 1;
1200 snd_ice1712_restore_gpio_status(ice);
1201 return 0;
1202}
1203
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001204static int aureon_cs8415_mute_put (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001206 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 unsigned char oval, nval;
1208 int change;
1209 snd_ice1712_save_gpio_status(ice);
1210 oval = aureon_cs8415_get(ice, CS8415_CTRL1);
1211 if (ucontrol->value.integer.value[0])
1212 nval = oval & ~0x20;
1213 else
1214 nval = oval | 0x20;
1215 if ((change = (oval != nval)))
1216 aureon_cs8415_put(ice, CS8415_CTRL1, nval);
1217 snd_ice1712_restore_gpio_status(ice);
1218 return change;
1219}
1220
1221/*
1222 * CS8415A Q-Sub info
1223 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001224static int aureon_cs8415_qsub_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
1226 uinfo->count = 10;
1227 return 0;
1228}
1229
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001230static int aureon_cs8415_qsub_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
1231 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232
1233 snd_ice1712_save_gpio_status(ice);
1234 aureon_cs8415_read(ice, CS8415_QSUB, ucontrol->value.bytes.data, 10);
1235 snd_ice1712_restore_gpio_status(ice);
1236
1237 return 0;
1238}
1239
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001240static int aureon_cs8415_spdif_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
1242 uinfo->count = 1;
1243 return 0;
1244}
1245
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001246static int aureon_cs8415_mask_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 memset(ucontrol->value.iec958.status, 0xFF, 24);
1248 return 0;
1249}
1250
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001251static int aureon_cs8415_spdif_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
1252 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253
1254 snd_ice1712_save_gpio_status(ice);
1255 aureon_cs8415_read(ice, CS8415_C_BUFFER, ucontrol->value.iec958.status, 24);
1256 snd_ice1712_restore_gpio_status(ice);
1257 return 0;
1258}
1259
1260/*
1261 * Headphone Amplifier
1262 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001263static int aureon_set_headphone_amp(struct snd_ice1712 *ice, int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264{
1265 unsigned int tmp, tmp2;
1266
1267 tmp2 = tmp = snd_ice1712_gpio_read(ice);
1268 if (enable)
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001269 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1270 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT)
Takashi Iwaic5130272006-05-23 15:46:10 +02001271 tmp |= AUREON_HP_SEL;
1272 else
1273 tmp |= PRODIGY_HP_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 else
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001275 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1276 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT)
Takashi Iwaic5130272006-05-23 15:46:10 +02001277 tmp &= ~ AUREON_HP_SEL;
1278 else
1279 tmp &= ~ PRODIGY_HP_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 if (tmp != tmp2) {
1281 snd_ice1712_gpio_write(ice, tmp);
1282 return 1;
1283 }
1284 return 0;
1285}
1286
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001287static int aureon_get_headphone_amp(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288{
1289 unsigned int tmp = snd_ice1712_gpio_read(ice);
1290
1291 return ( tmp & AUREON_HP_SEL )!= 0;
1292}
1293
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001294#define aureon_hpamp_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001296static int aureon_hpamp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001298 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299
1300 ucontrol->value.integer.value[0] = aureon_get_headphone_amp(ice);
1301 return 0;
1302}
1303
1304
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001305static int aureon_hpamp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001307 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308
1309 return aureon_set_headphone_amp(ice,ucontrol->value.integer.value[0]);
1310}
1311
1312/*
1313 * Deemphasis
1314 */
1315
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001316#define aureon_deemp_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001318static int aureon_deemp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001320 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 0xf;
1322 return 0;
1323}
1324
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001325static int aureon_deemp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001327 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 int temp, temp2;
1329 temp2 = temp = wm_get(ice, WM_DAC_CTRL2);
1330 if (ucontrol->value.integer.value[0])
1331 temp |= 0xf;
1332 else
1333 temp &= ~0xf;
1334 if (temp != temp2) {
1335 wm_put(ice, WM_DAC_CTRL2, temp);
1336 return 1;
1337 }
1338 return 0;
1339}
1340
1341/*
1342 * ADC Oversampling
1343 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001344static int aureon_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345{
Takashi Iwai32b47da2007-01-29 15:26:36 +01001346 static const char * const texts[2] = { "128x", "64x" };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347
1348 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1349 uinfo->count = 1;
1350 uinfo->value.enumerated.items = 2;
1351
1352 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1353 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1354 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1355
1356 return 0;
1357}
1358
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001359static int aureon_oversampling_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001361 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 0x8;
1363 return 0;
1364}
1365
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001366static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367{
1368 int temp, temp2;
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001369 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370
1371 temp2 = temp = wm_get(ice, WM_MASTER);
1372
1373 if (ucontrol->value.enumerated.item[0])
1374 temp |= 0x8;
1375 else
1376 temp &= ~0x8;
1377
1378 if (temp != temp2) {
1379 wm_put(ice, WM_MASTER, temp);
1380 return 1;
1381 }
1382 return 0;
1383}
1384
1385/*
1386 * mixers
1387 */
1388
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01001389static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 {
1391 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1392 .name = "Master Playback Switch",
1393 .info = wm_master_mute_info,
1394 .get = wm_master_mute_get,
1395 .put = wm_master_mute_put
1396 },
1397 {
1398 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001399 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1400 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 .name = "Master Playback Volume",
1402 .info = wm_master_vol_info,
1403 .get = wm_master_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +02001404 .put = wm_master_vol_put,
1405 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 },
1407 {
1408 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1409 .name = "Front Playback Switch",
1410 .info = wm_mute_info,
1411 .get = wm_mute_get,
1412 .put = wm_mute_put,
1413 .private_value = (2 << 8) | 0
1414 },
1415 {
1416 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001417 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1418 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 .name = "Front Playback Volume",
1420 .info = wm_vol_info,
1421 .get = wm_vol_get,
1422 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001423 .private_value = (2 << 8) | 0,
1424 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 },
1426 {
1427 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1428 .name = "Rear Playback Switch",
1429 .info = wm_mute_info,
1430 .get = wm_mute_get,
1431 .put = wm_mute_put,
1432 .private_value = (2 << 8) | 2
1433 },
1434 {
1435 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001436 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1437 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 .name = "Rear Playback Volume",
1439 .info = wm_vol_info,
1440 .get = wm_vol_get,
1441 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001442 .private_value = (2 << 8) | 2,
1443 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 },
1445 {
1446 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1447 .name = "Center Playback Switch",
1448 .info = wm_mute_info,
1449 .get = wm_mute_get,
1450 .put = wm_mute_put,
1451 .private_value = (1 << 8) | 4
1452 },
1453 {
1454 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001455 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1456 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 .name = "Center Playback Volume",
1458 .info = wm_vol_info,
1459 .get = wm_vol_get,
1460 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001461 .private_value = (1 << 8) | 4,
1462 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 },
1464 {
1465 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1466 .name = "LFE Playback Switch",
1467 .info = wm_mute_info,
1468 .get = wm_mute_get,
1469 .put = wm_mute_put,
1470 .private_value = (1 << 8) | 5
1471 },
1472 {
1473 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001474 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1475 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 .name = "LFE Playback Volume",
1477 .info = wm_vol_info,
1478 .get = wm_vol_get,
1479 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001480 .private_value = (1 << 8) | 5,
1481 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 },
1483 {
1484 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1485 .name = "Side Playback Switch",
1486 .info = wm_mute_info,
1487 .get = wm_mute_get,
1488 .put = wm_mute_put,
1489 .private_value = (2 << 8) | 6
1490 },
1491 {
1492 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001493 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1494 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 .name = "Side Playback Volume",
1496 .info = wm_vol_info,
1497 .get = wm_vol_get,
1498 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001499 .private_value = (2 << 8) | 6,
1500 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 }
1502};
1503
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01001504static struct snd_kcontrol_new wm_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 {
1506 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1507 .name = "PCM Playback Switch",
1508 .info = wm_pcm_mute_info,
1509 .get = wm_pcm_mute_get,
1510 .put = wm_pcm_mute_put
1511 },
1512 {
1513 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001514 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1515 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 .name = "PCM Playback Volume",
1517 .info = wm_pcm_vol_info,
1518 .get = wm_pcm_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +02001519 .put = wm_pcm_vol_put,
1520 .tlv = { .p = db_scale_wm_pcm }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 },
1522 {
1523 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1524 .name = "Capture Switch",
1525 .info = wm_adc_mute_info,
1526 .get = wm_adc_mute_get,
1527 .put = wm_adc_mute_put,
1528 },
1529 {
1530 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001531 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1532 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 .name = "Capture Volume",
1534 .info = wm_adc_vol_info,
1535 .get = wm_adc_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +02001536 .put = wm_adc_vol_put,
1537 .tlv = { .p = db_scale_wm_adc }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 },
1539 {
1540 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1541 .name = "Capture Source",
1542 .info = wm_adc_mux_info,
1543 .get = wm_adc_mux_get,
1544 .put = wm_adc_mux_put,
1545 .private_value = 5
1546 },
1547 {
1548 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1549 .name = "External Amplifier",
1550 .info = aureon_hpamp_info,
1551 .get = aureon_hpamp_get,
1552 .put = aureon_hpamp_put
1553 },
1554 {
1555 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1556 .name = "DAC Deemphasis Switch",
1557 .info = aureon_deemp_info,
1558 .get = aureon_deemp_get,
1559 .put = aureon_deemp_put
1560 },
1561 {
1562 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1563 .name = "ADC Oversampling",
1564 .info = aureon_oversampling_info,
1565 .get = aureon_oversampling_get,
1566 .put = aureon_oversampling_put
1567 }
1568};
1569
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01001570static struct snd_kcontrol_new ac97_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 {
1572 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1573 .name = "AC97 Playback Switch",
1574 .info = aureon_ac97_mmute_info,
1575 .get = aureon_ac97_mmute_get,
1576 .put = aureon_ac97_mmute_put,
1577 .private_value = AC97_MASTER
1578 },
1579 {
1580 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001581 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1582 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 .name = "AC97 Playback Volume",
1584 .info = aureon_ac97_vol_info,
1585 .get = aureon_ac97_vol_get,
1586 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001587 .private_value = AC97_MASTER|AUREON_AC97_STEREO,
1588 .tlv = { .p = db_scale_ac97_master }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 },
1590 {
1591 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1592 .name = "CD Playback Switch",
1593 .info = aureon_ac97_mute_info,
1594 .get = aureon_ac97_mute_get,
1595 .put = aureon_ac97_mute_put,
1596 .private_value = AC97_CD
1597 },
1598 {
1599 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001600 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1601 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 .name = "CD Playback Volume",
1603 .info = aureon_ac97_vol_info,
1604 .get = aureon_ac97_vol_get,
1605 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001606 .private_value = AC97_CD|AUREON_AC97_STEREO,
1607 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 },
1609 {
1610 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1611 .name = "Aux Playback Switch",
1612 .info = aureon_ac97_mute_info,
1613 .get = aureon_ac97_mute_get,
1614 .put = aureon_ac97_mute_put,
1615 .private_value = AC97_AUX,
1616 },
1617 {
1618 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001619 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1620 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 .name = "Aux Playback Volume",
1622 .info = aureon_ac97_vol_info,
1623 .get = aureon_ac97_vol_get,
1624 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001625 .private_value = AC97_AUX|AUREON_AC97_STEREO,
1626 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 },
1628 {
1629 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1630 .name = "Line Playback Switch",
1631 .info = aureon_ac97_mute_info,
1632 .get = aureon_ac97_mute_get,
1633 .put = aureon_ac97_mute_put,
1634 .private_value = AC97_LINE
1635 },
1636 {
1637 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001638 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1639 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 .name = "Line Playback Volume",
1641 .info = aureon_ac97_vol_info,
1642 .get = aureon_ac97_vol_get,
1643 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001644 .private_value = AC97_LINE|AUREON_AC97_STEREO,
1645 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 },
1647 {
1648 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1649 .name = "Mic Playback Switch",
1650 .info = aureon_ac97_mute_info,
1651 .get = aureon_ac97_mute_get,
1652 .put = aureon_ac97_mute_put,
1653 .private_value = AC97_MIC
1654 },
1655 {
1656 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001657 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1658 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 .name = "Mic Playback Volume",
1660 .info = aureon_ac97_vol_info,
1661 .get = aureon_ac97_vol_get,
1662 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001663 .private_value = AC97_MIC,
1664 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 },
1666 {
1667 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1668 .name = "Mic Boost (+20dB)",
1669 .info = aureon_ac97_micboost_info,
1670 .get = aureon_ac97_micboost_get,
1671 .put = aureon_ac97_micboost_put
1672 }
1673};
1674
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01001675static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 {
1677 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1678 .name = "AC97 Playback Switch",
1679 .info = aureon_ac97_mmute_info,
1680 .get = aureon_ac97_mmute_get,
1681 .put = aureon_ac97_mmute_put,
1682 .private_value = AC97_MASTER
1683 },
1684 {
1685 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001686 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1687 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 .name = "AC97 Playback Volume",
1689 .info = aureon_ac97_vol_info,
1690 .get = aureon_ac97_vol_get,
1691 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001692 .private_value = AC97_MASTER|AUREON_AC97_STEREO,
1693 .tlv = { .p = db_scale_ac97_master }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 },
1695 {
1696 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1697 .name = "CD Playback Switch",
1698 .info = aureon_ac97_mute_info,
1699 .get = aureon_ac97_mute_get,
1700 .put = aureon_ac97_mute_put,
1701 .private_value = AC97_AUX
1702 },
1703 {
1704 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001705 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1706 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 .name = "CD Playback Volume",
1708 .info = aureon_ac97_vol_info,
1709 .get = aureon_ac97_vol_get,
1710 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001711 .private_value = AC97_AUX|AUREON_AC97_STEREO,
1712 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 },
1714 {
1715 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1716 .name = "Phono Playback Switch",
1717 .info = aureon_ac97_mute_info,
1718 .get = aureon_ac97_mute_get,
1719 .put = aureon_ac97_mute_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001720 .private_value = AC97_CD
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 },
1722 {
1723 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001724 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1725 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 .name = "Phono Playback Volume",
1727 .info = aureon_ac97_vol_info,
1728 .get = aureon_ac97_vol_get,
1729 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001730 .private_value = AC97_CD|AUREON_AC97_STEREO,
1731 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 },
1733 {
1734 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1735 .name = "Line Playback Switch",
1736 .info = aureon_ac97_mute_info,
1737 .get = aureon_ac97_mute_get,
1738 .put = aureon_ac97_mute_put,
1739 .private_value = AC97_LINE
1740 },
1741 {
1742 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001743 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1744 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 .name = "Line Playback Volume",
1746 .info = aureon_ac97_vol_info,
1747 .get = aureon_ac97_vol_get,
1748 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001749 .private_value = AC97_LINE|AUREON_AC97_STEREO,
1750 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 },
1752 {
1753 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1754 .name = "Mic Playback Switch",
1755 .info = aureon_ac97_mute_info,
1756 .get = aureon_ac97_mute_get,
1757 .put = aureon_ac97_mute_put,
1758 .private_value = AC97_MIC
1759 },
1760 {
1761 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001762 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1763 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 .name = "Mic Playback Volume",
1765 .info = aureon_ac97_vol_info,
1766 .get = aureon_ac97_vol_get,
1767 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001768 .private_value = AC97_MIC,
1769 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 },
1771 {
1772 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1773 .name = "Mic Boost (+20dB)",
1774 .info = aureon_ac97_micboost_info,
1775 .get = aureon_ac97_micboost_get,
1776 .put = aureon_ac97_micboost_put
1777 },
1778 {
1779 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1780 .name = "Aux Playback Switch",
1781 .info = aureon_ac97_mute_info,
1782 .get = aureon_ac97_mute_get,
1783 .put = aureon_ac97_mute_put,
1784 .private_value = AC97_VIDEO,
1785 },
1786 {
1787 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001788 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1789 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 .name = "Aux Playback Volume",
1791 .info = aureon_ac97_vol_info,
1792 .get = aureon_ac97_vol_get,
1793 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001794 .private_value = AC97_VIDEO|AUREON_AC97_STEREO,
1795 .tlv = { .p = db_scale_ac97_gain }
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +02001796 },
1797 {
1798 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1799 .name = "Aux Source",
1800 .info = aureon_universe_inmux_info,
1801 .get = aureon_universe_inmux_get,
1802 .put = aureon_universe_inmux_put
1803 }
1804
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805};
1806
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01001807static struct snd_kcontrol_new cs8415_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 {
1809 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1810 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH),
1811 .info = aureon_cs8415_mute_info,
1812 .get = aureon_cs8415_mute_get,
1813 .put = aureon_cs8415_mute_put
1814 },
1815 {
1816 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1817 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Source",
1818 .info = aureon_cs8415_mux_info,
1819 .get = aureon_cs8415_mux_get,
1820 .put = aureon_cs8415_mux_put,
1821 },
1822 {
1823 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1824 .name = SNDRV_CTL_NAME_IEC958("Q-subcode ",CAPTURE,DEFAULT),
1825 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1826 .info = aureon_cs8415_qsub_info,
1827 .get = aureon_cs8415_qsub_get,
1828 },
1829 {
1830 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1831 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,MASK),
1832 .access = SNDRV_CTL_ELEM_ACCESS_READ,
1833 .info = aureon_cs8415_spdif_info,
1834 .get = aureon_cs8415_mask_get
1835 },
1836 {
1837 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1838 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT),
1839 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1840 .info = aureon_cs8415_spdif_info,
1841 .get = aureon_cs8415_spdif_get
1842 },
1843 {
1844 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1845 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Rate",
1846 .access =SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1847 .info = aureon_cs8415_rate_info,
1848 .get = aureon_cs8415_rate_get
1849 }
1850};
1851
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001852static int __devinit aureon_add_controls(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853{
1854 unsigned int i, counts;
1855 int err;
1856
1857 counts = ARRAY_SIZE(aureon_dac_controls);
1858 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY)
1859 counts -= 2; /* no side */
1860 for (i = 0; i < counts; i++) {
1861 err = snd_ctl_add(ice->card, snd_ctl_new1(&aureon_dac_controls[i], ice));
1862 if (err < 0)
1863 return err;
1864 }
1865
1866 for (i = 0; i < ARRAY_SIZE(wm_controls); i++) {
1867 err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice));
1868 if (err < 0)
1869 return err;
1870 }
1871
1872 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) {
1873 for (i = 0; i < ARRAY_SIZE(universe_ac97_controls); i++) {
1874 err = snd_ctl_add(ice->card, snd_ctl_new1(&universe_ac97_controls[i], ice));
1875 if (err < 0)
1876 return err;
1877 }
1878 }
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001879 else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1880 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 for (i = 0; i < ARRAY_SIZE(ac97_controls); i++) {
1882 err = snd_ctl_add(ice->card, snd_ctl_new1(&ac97_controls[i], ice));
1883 if (err < 0)
1884 return err;
1885 }
1886 }
1887
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001888 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1889 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 unsigned char id;
1891 snd_ice1712_save_gpio_status(ice);
1892 id = aureon_cs8415_get(ice, CS8415_ID);
1893 if (id != 0x41)
Takashi Iwai99b359b2005-10-20 18:26:44 +02001894 snd_printk(KERN_INFO "No CS8415 chip. Skipping CS8415 controls.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 else if ((id & 0x0F) != 0x01)
Takashi Iwai99b359b2005-10-20 18:26:44 +02001896 snd_printk(KERN_INFO "Detected unsupported CS8415 rev. (%c)\n", (char)((id & 0x0F) + 'A' - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 else {
1898 for (i = 0; i< ARRAY_SIZE(cs8415_controls); i++) {
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001899 struct snd_kcontrol *kctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 err = snd_ctl_add(ice->card, (kctl = snd_ctl_new1(&cs8415_controls[i], ice)));
1901 if (err < 0)
1902 return err;
1903 if (i > 1)
1904 kctl->id.device = ice->pcm->device;
1905 }
1906 }
1907 snd_ice1712_restore_gpio_status(ice);
1908 }
1909
1910 return 0;
1911}
1912
1913
1914/*
1915 * initialize the chip
1916 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001917static int __devinit aureon_init(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918{
Takashi Iwai32b47da2007-01-29 15:26:36 +01001919 static const unsigned short wm_inits_aureon[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 /* These come first to reduce init pop noise */
1921 0x1b, 0x044, /* ADC Mux (AC'97 source) */
1922 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
1923 0x1d, 0x009, /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */
1924
1925 0x18, 0x000, /* All power-up */
1926
1927 0x16, 0x122, /* I2S, normal polarity, 24bit */
1928 0x17, 0x022, /* 256fs, slave mode */
1929 0x00, 0, /* DAC1 analog mute */
1930 0x01, 0, /* DAC2 analog mute */
1931 0x02, 0, /* DAC3 analog mute */
1932 0x03, 0, /* DAC4 analog mute */
1933 0x04, 0, /* DAC5 analog mute */
1934 0x05, 0, /* DAC6 analog mute */
1935 0x06, 0, /* DAC7 analog mute */
1936 0x07, 0, /* DAC8 analog mute */
1937 0x08, 0x100, /* master analog mute */
1938 0x09, 0xff, /* DAC1 digital full */
1939 0x0a, 0xff, /* DAC2 digital full */
1940 0x0b, 0xff, /* DAC3 digital full */
1941 0x0c, 0xff, /* DAC4 digital full */
1942 0x0d, 0xff, /* DAC5 digital full */
1943 0x0e, 0xff, /* DAC6 digital full */
1944 0x0f, 0xff, /* DAC7 digital full */
1945 0x10, 0xff, /* DAC8 digital full */
1946 0x11, 0x1ff, /* master digital full */
1947 0x12, 0x000, /* phase normal */
1948 0x13, 0x090, /* unmute DAC L/R */
1949 0x14, 0x000, /* all unmute */
1950 0x15, 0x000, /* no deemphasis, no ZFLG */
1951 0x19, 0x000, /* -12dB ADC/L */
1952 0x1a, 0x000, /* -12dB ADC/R */
1953 (unsigned short)-1
1954 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01001955 static const unsigned short wm_inits_prodigy[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956
1957 /* These come first to reduce init pop noise */
1958 0x1b, 0x000, /* ADC Mux */
1959 0x1c, 0x009, /* Out Mux1 */
1960 0x1d, 0x009, /* Out Mux2 */
1961
1962 0x18, 0x000, /* All power-up */
1963
1964 0x16, 0x022, /* I2S, normal polarity, 24bit, high-pass on */
1965 0x17, 0x006, /* 128fs, slave mode */
1966
1967 0x00, 0, /* DAC1 analog mute */
1968 0x01, 0, /* DAC2 analog mute */
1969 0x02, 0, /* DAC3 analog mute */
1970 0x03, 0, /* DAC4 analog mute */
1971 0x04, 0, /* DAC5 analog mute */
1972 0x05, 0, /* DAC6 analog mute */
1973 0x06, 0, /* DAC7 analog mute */
1974 0x07, 0, /* DAC8 analog mute */
1975 0x08, 0x100, /* master analog mute */
1976
1977 0x09, 0x7f, /* DAC1 digital full */
1978 0x0a, 0x7f, /* DAC2 digital full */
1979 0x0b, 0x7f, /* DAC3 digital full */
1980 0x0c, 0x7f, /* DAC4 digital full */
1981 0x0d, 0x7f, /* DAC5 digital full */
1982 0x0e, 0x7f, /* DAC6 digital full */
1983 0x0f, 0x7f, /* DAC7 digital full */
1984 0x10, 0x7f, /* DAC8 digital full */
1985 0x11, 0x1FF, /* master digital full */
1986
1987 0x12, 0x000, /* phase normal */
1988 0x13, 0x090, /* unmute DAC L/R */
1989 0x14, 0x000, /* all unmute */
1990 0x15, 0x000, /* no deemphasis, no ZFLG */
1991
1992 0x19, 0x000, /* -12dB ADC/L */
1993 0x1a, 0x000, /* -12dB ADC/R */
1994 (unsigned short)-1
1995
1996 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01001997 static const unsigned short cs_inits[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 0x0441, /* RUN */
1999 0x0180, /* no mute, OMCK output on RMCK pin */
2000 0x0201, /* S/PDIF source on RXP1 */
2001 0x0605, /* slave, 24bit, MSB on second OSCLK, SDOUT for right channel when OLRCK is high */
2002 (unsigned short)-1
2003 };
2004 unsigned int tmp;
Takashi Iwai32b47da2007-01-29 15:26:36 +01002005 const unsigned short *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 int err, i;
2007
2008 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) {
2009 ice->num_total_dacs = 6;
2010 ice->num_total_adcs = 2;
2011 } else {
2012 /* aureon 7.1 and prodigy 7.1 */
2013 ice->num_total_dacs = 8;
2014 ice->num_total_adcs = 2;
2015 }
2016
2017 /* to remeber the register values of CS8415 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01002018 ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 if (! ice->akm)
2020 return -ENOMEM;
2021 ice->akm_codecs = 1;
2022
2023 if ((err = aureon_ac97_init(ice)) != 0)
2024 return err;
2025
2026 snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for the time being */
2027
2028 /* reset the wm codec as the SPI mode */
2029 snd_ice1712_save_gpio_status(ice);
2030 snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RESET|AUREON_WM_CS|AUREON_CS8415_CS|AUREON_HP_SEL));
2031
2032 tmp = snd_ice1712_gpio_read(ice);
2033 tmp &= ~AUREON_WM_RESET;
2034 snd_ice1712_gpio_write(ice, tmp);
2035 udelay(1);
2036 tmp |= AUREON_WM_CS | AUREON_CS8415_CS;
2037 snd_ice1712_gpio_write(ice, tmp);
2038 udelay(1);
2039 tmp |= AUREON_WM_RESET;
2040 snd_ice1712_gpio_write(ice, tmp);
2041 udelay(1);
2042
2043 /* initialize WM8770 codec */
Takashi Iwai45fe7222006-01-13 13:50:16 +01002044 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71 ||
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01002045 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
2046 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 p = wm_inits_prodigy;
2048 else
2049 p = wm_inits_aureon;
2050 for (; *p != (unsigned short)-1; p += 2)
2051 wm_put(ice, p[0], p[1]);
2052
2053 /* initialize CS8415A codec */
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01002054 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
2055 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
Takashi Iwai45fe7222006-01-13 13:50:16 +01002056 for (p = cs_inits; *p != (unsigned short)-1; p++)
2057 aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24);
2058 ice->spec.aureon.cs8415_mux = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059
Takashi Iwai45fe7222006-01-13 13:50:16 +01002060 aureon_set_headphone_amp(ice, 1);
2061 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062
2063 snd_ice1712_restore_gpio_status(ice);
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +02002064
2065 /* initialize PCA9554 pin directions & set default input*/
2066 aureon_pca9554_write(ice, PCA9554_DIR, 0x00);
2067 aureon_pca9554_write(ice, PCA9554_OUT, 0x00); /* internal AUX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068
2069 ice->spec.aureon.master[0] = WM_VOL_MUTE;
2070 ice->spec.aureon.master[1] = WM_VOL_MUTE;
2071 for (i = 0; i < ice->num_total_dacs; i++) {
2072 ice->spec.aureon.vol[i] = WM_VOL_MUTE;
2073 wm_set_vol(ice, i, ice->spec.aureon.vol[i], ice->spec.aureon.master[i % 2]);
2074 }
2075
2076 return 0;
2077}
2078
2079
2080/*
2081 * Aureon boards don't provide the EEPROM data except for the vendor IDs.
2082 * hence the driver needs to sets up it properly.
2083 */
2084
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01002085static unsigned char aureon51_eeprom[] __devinitdata = {
Takashi Iwai189bc172007-01-29 15:25:40 +01002086 [ICE_EEP2_SYSCONF] = 0x0a, /* clock 512, spdif-in/ADC, 3DACs */
2087 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
2088 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
2089 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
2090 [ICE_EEP2_GPIO_DIR] = 0xff,
2091 [ICE_EEP2_GPIO_DIR1] = 0xff,
2092 [ICE_EEP2_GPIO_DIR2] = 0x5f,
2093 [ICE_EEP2_GPIO_MASK] = 0x00,
2094 [ICE_EEP2_GPIO_MASK1] = 0x00,
2095 [ICE_EEP2_GPIO_MASK2] = 0x00,
2096 [ICE_EEP2_GPIO_STATE] = 0x00,
2097 [ICE_EEP2_GPIO_STATE1] = 0x00,
2098 [ICE_EEP2_GPIO_STATE2] = 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099};
2100
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01002101static unsigned char aureon71_eeprom[] __devinitdata = {
Takashi Iwai189bc172007-01-29 15:25:40 +01002102 [ICE_EEP2_SYSCONF] = 0x0b, /* clock 512, spdif-in/ADC, 4DACs */
2103 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
2104 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
2105 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
2106 [ICE_EEP2_GPIO_DIR] = 0xff,
2107 [ICE_EEP2_GPIO_DIR1] = 0xff,
2108 [ICE_EEP2_GPIO_DIR2] = 0x5f,
2109 [ICE_EEP2_GPIO_MASK] = 0x00,
2110 [ICE_EEP2_GPIO_MASK1] = 0x00,
2111 [ICE_EEP2_GPIO_MASK2] = 0x00,
2112 [ICE_EEP2_GPIO_STATE] = 0x00,
2113 [ICE_EEP2_GPIO_STATE1] = 0x00,
2114 [ICE_EEP2_GPIO_STATE2] = 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115};
Takashi Iwai189bc172007-01-29 15:25:40 +01002116#define prodigy71_eeprom aureon71_eeprom
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01002118static unsigned char prodigy71lt_eeprom[] __devinitdata = {
Takashi Iwai189bc172007-01-29 15:25:40 +01002119 [ICE_EEP2_SYSCONF] = 0x4b, /* clock 384, spdif-in/ADC, 4DACs */
2120 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
2121 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
2122 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
2123 [ICE_EEP2_GPIO_DIR] = 0xff,
2124 [ICE_EEP2_GPIO_DIR1] = 0xff,
2125 [ICE_EEP2_GPIO_DIR2] = 0x5f,
2126 [ICE_EEP2_GPIO_MASK] = 0x00,
2127 [ICE_EEP2_GPIO_MASK1] = 0x00,
2128 [ICE_EEP2_GPIO_MASK2] = 0x00,
2129 [ICE_EEP2_GPIO_STATE] = 0x00,
2130 [ICE_EEP2_GPIO_STATE1] = 0x00,
2131 [ICE_EEP2_GPIO_STATE2] = 0x00,
Takashi Iwai45fe7222006-01-13 13:50:16 +01002132};
Takashi Iwai189bc172007-01-29 15:25:40 +01002133#define prodigy71xt_eeprom prodigy71lt_eeprom
Takashi Iwai45fe7222006-01-13 13:50:16 +01002134
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135/* entry point */
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01002136struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 {
2138 .subvendor = VT1724_SUBDEVICE_AUREON51_SKY,
2139 .name = "Terratec Aureon 5.1-Sky",
2140 .model = "aureon51",
2141 .chip_init = aureon_init,
2142 .build_controls = aureon_add_controls,
2143 .eeprom_size = sizeof(aureon51_eeprom),
2144 .eeprom_data = aureon51_eeprom,
2145 .driver = "Aureon51",
2146 },
2147 {
2148 .subvendor = VT1724_SUBDEVICE_AUREON71_SPACE,
2149 .name = "Terratec Aureon 7.1-Space",
2150 .model = "aureon71",
2151 .chip_init = aureon_init,
2152 .build_controls = aureon_add_controls,
2153 .eeprom_size = sizeof(aureon71_eeprom),
2154 .eeprom_data = aureon71_eeprom,
2155 .driver = "Aureon71",
2156 },
2157 {
2158 .subvendor = VT1724_SUBDEVICE_AUREON71_UNIVERSE,
2159 .name = "Terratec Aureon 7.1-Universe",
2160 .model = "universe",
2161 .chip_init = aureon_init,
2162 .build_controls = aureon_add_controls,
2163 .eeprom_size = sizeof(aureon71_eeprom),
2164 .eeprom_data = aureon71_eeprom,
Takashi Iwai9f37c5b2006-06-29 16:40:21 +02002165 .driver = "Aureon71Univ", /* keep in 15 letters */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 },
2167 {
2168 .subvendor = VT1724_SUBDEVICE_PRODIGY71,
2169 .name = "Audiotrak Prodigy 7.1",
2170 .model = "prodigy71",
2171 .chip_init = aureon_init,
2172 .build_controls = aureon_add_controls,
2173 .eeprom_size = sizeof(prodigy71_eeprom),
2174 .eeprom_data = prodigy71_eeprom,
2175 .driver = "Prodigy71", /* should be identical with Aureon71 */
2176 },
Takashi Iwai45fe7222006-01-13 13:50:16 +01002177 {
2178 .subvendor = VT1724_SUBDEVICE_PRODIGY71LT,
2179 .name = "Audiotrak Prodigy 7.1 LT",
2180 .model = "prodigy71lt",
2181 .chip_init = aureon_init,
2182 .build_controls = aureon_add_controls,
2183 .eeprom_size = sizeof(prodigy71lt_eeprom),
2184 .eeprom_data = prodigy71lt_eeprom,
2185 .driver = "Prodigy71LT",
2186 },
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01002187 {
2188 .subvendor = VT1724_SUBDEVICE_PRODIGY71XT,
2189 .name = "Audiotrak Prodigy 7.1 XT",
2190 .model = "prodigy71xt",
2191 .chip_init = aureon_init,
2192 .build_controls = aureon_add_controls,
2193 .eeprom_size = sizeof(prodigy71xt_eeprom),
2194 .eeprom_data = prodigy71xt_eeprom,
2195 .driver = "Prodigy71LT",
2196 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 { } /* terminator */
2198};