blob: 9e76cebd2d228c1680465e40757ad2cca4063153 [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;
297 static unsigned short ac97_defaults[] = {
298 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 */
397#define aureon_ac97_mute_info aureon_mono_bool_info
398
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 */
433#define aureon_ac97_micboost_info aureon_mono_bool_info
434
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
Takashi Iwai45fe7222006-01-13 13:50:16 +0100477 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT) {
478 snd_ice1712_gpio_set_mask(ice, ~(PRODIGY_SPI_MOSI|PRODIGY_SPI_CLK|PRODIGY_WM_CS));
479 mosi = PRODIGY_SPI_MOSI;
480 clk = PRODIGY_SPI_CLK;
481 }
482 else {
483 snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RW|AUREON_SPI_MOSI|AUREON_SPI_CLK|
484 AUREON_WM_CS|AUREON_CS8415_CS));
485 mosi = AUREON_SPI_MOSI;
486 clk = AUREON_SPI_CLK;
487
488 tmp |= AUREON_WM_RW;
489 }
490
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 tmp &= ~cs;
492 snd_ice1712_gpio_write(ice, tmp);
493 udelay(1);
494
495 for (i = bits - 1; i >= 0; i--) {
Takashi Iwai45fe7222006-01-13 13:50:16 +0100496 tmp &= ~clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 snd_ice1712_gpio_write(ice, tmp);
498 udelay(1);
499 if (data & (1 << i))
Takashi Iwai45fe7222006-01-13 13:50:16 +0100500 tmp |= mosi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 else
Takashi Iwai45fe7222006-01-13 13:50:16 +0100502 tmp &= ~mosi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 snd_ice1712_gpio_write(ice, tmp);
504 udelay(1);
Takashi Iwai45fe7222006-01-13 13:50:16 +0100505 tmp |= clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 snd_ice1712_gpio_write(ice, tmp);
507 udelay(1);
508 }
509
Takashi Iwai45fe7222006-01-13 13:50:16 +0100510 tmp &= ~clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 tmp |= cs;
512 snd_ice1712_gpio_write(ice, tmp);
513 udelay(1);
Takashi Iwai45fe7222006-01-13 13:50:16 +0100514 tmp |= clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 snd_ice1712_gpio_write(ice, tmp);
516 udelay(1);
517}
518
519/*
520 * Read data in SPI mode
521 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100522static 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 -0700523 int i, j;
524 unsigned int tmp;
525
526 tmp = (snd_ice1712_gpio_read(ice) & ~AUREON_SPI_CLK) | AUREON_CS8415_CS|AUREON_WM_CS;
527 snd_ice1712_gpio_write(ice, tmp);
528 tmp &= ~cs;
529 snd_ice1712_gpio_write(ice, tmp);
530 udelay(1);
531
532 for (i=bits-1; i>=0; i--) {
533 if (data & (1 << i))
534 tmp |= AUREON_SPI_MOSI;
535 else
536 tmp &= ~AUREON_SPI_MOSI;
537 snd_ice1712_gpio_write(ice, tmp);
538 udelay(1);
539
540 tmp |= AUREON_SPI_CLK;
541 snd_ice1712_gpio_write(ice, tmp);
542 udelay(1);
543
544 tmp &= ~AUREON_SPI_CLK;
545 snd_ice1712_gpio_write(ice, tmp);
546 udelay(1);
547 }
548
549 for (j=0; j<size; j++) {
550 unsigned char outdata = 0;
551 for (i=7; i>=0; i--) {
552 tmp = snd_ice1712_gpio_read(ice);
553 outdata <<= 1;
554 outdata |= (tmp & AUREON_SPI_MISO) ? 1 : 0;
555 udelay(1);
556
557 tmp |= AUREON_SPI_CLK;
558 snd_ice1712_gpio_write(ice, tmp);
559 udelay(1);
560
561 tmp &= ~AUREON_SPI_CLK;
562 snd_ice1712_gpio_write(ice, tmp);
563 udelay(1);
564 }
565 buffer[j] = outdata;
566 }
567
568 tmp |= cs;
569 snd_ice1712_gpio_write(ice, tmp);
570}
571
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100572static unsigned char aureon_cs8415_get(struct snd_ice1712 *ice, int reg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 unsigned char val;
574 aureon_spi_write(ice, AUREON_CS8415_CS, 0x2000 | reg, 16);
575 aureon_spi_read(ice, AUREON_CS8415_CS, 0x21, 8, &val, 1);
576 return val;
577}
578
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100579static void aureon_cs8415_read(struct snd_ice1712 *ice, int reg, unsigned char *buffer, int size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 aureon_spi_write(ice, AUREON_CS8415_CS, 0x2000 | reg, 16);
581 aureon_spi_read(ice, AUREON_CS8415_CS, 0x21, 8, buffer, size);
582}
583
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100584static void aureon_cs8415_put(struct snd_ice1712 *ice, int reg, unsigned char val) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 aureon_spi_write(ice, AUREON_CS8415_CS, 0x200000 | (reg << 8) | val, 24);
586}
587
588/*
589 * get the current register value of WM codec
590 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100591static unsigned short wm_get(struct snd_ice1712 *ice, int reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592{
593 reg <<= 1;
594 return ((unsigned short)ice->akm[0].images[reg] << 8) |
595 ice->akm[0].images[reg + 1];
596}
597
598/*
599 * set the register value of WM codec
600 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100601static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602{
Takashi Iwai45fe7222006-01-13 13:50:16 +0100603 aureon_spi_write(ice,
604 (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ? PRODIGY_WM_CS : AUREON_WM_CS),
605 (reg << 9) | (val & 0x1ff), 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606}
607
608/*
609 * set the register value of WM codec and remember it
610 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100611static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612{
613 wm_put_nocache(ice, reg, val);
614 reg <<= 1;
615 ice->akm[0].images[reg] = val >> 8;
616 ice->akm[0].images[reg + 1] = val;
617}
618
619/*
620 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100621static int aureon_mono_bool_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622{
623 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
624 uinfo->count = 1;
625 uinfo->value.integer.min = 0;
626 uinfo->value.integer.max = 1;
627 return 0;
628}
629
630/*
631 * AC'97 master playback mute controls (Mute on WM8770 chip)
632 */
633#define aureon_ac97_mmute_info aureon_mono_bool_info
634
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100635static int aureon_ac97_mmute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100637 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
Ingo Molnar62932df2006-01-16 16:34:20 +0100639 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640
641 ucontrol->value.integer.value[0] = (wm_get(ice, WM_OUT_MUX1) >> 1) & 0x01;
642
Ingo Molnar62932df2006-01-16 16:34:20 +0100643 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 return 0;
645}
646
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100647static int aureon_ac97_mmute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
648 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 unsigned short ovol, nvol;
650 int change;
651
652 snd_ice1712_save_gpio_status(ice);
653
654 ovol = wm_get(ice, WM_OUT_MUX1);
655 nvol = (ovol & ~0x02) | (ucontrol->value.integer.value[0] ? 0x02 : 0x00);
656 if ((change = (ovol != nvol)))
657 wm_put(ice, WM_OUT_MUX1, nvol);
658
659 snd_ice1712_restore_gpio_status(ice);
660
661 return change;
662}
663
Takashi Iwaif640c322006-08-30 16:57:37 +0200664static DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
665static DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
666static DECLARE_TLV_DB_SCALE(db_scale_wm_adc, -1200, 100, 0);
667static DECLARE_TLV_DB_SCALE(db_scale_ac97_master, -4650, 150, 0);
668static DECLARE_TLV_DB_SCALE(db_scale_ac97_gain, -3450, 150, 0);
669
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670/*
671 * Logarithmic volume values for WM8770
672 * Computed as 20 * Log10(255 / x)
673 */
674static unsigned char wm_vol[256] = {
675 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23,
676 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17,
677 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13,
678 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11,
679 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8,
680 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,
681 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,
682 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,
683 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,
684 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,
685 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,
686 0, 0
687};
688
689#define WM_VOL_MAX (sizeof(wm_vol) - 1)
690#define WM_VOL_MUTE 0x8000
691
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100692static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, unsigned short vol, unsigned short master)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693{
694 unsigned char nvol;
695
696 if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))
697 nvol = 0;
698 else
699 nvol = 127 - wm_vol[(((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 127) & WM_VOL_MAX];
700
701 wm_put(ice, index, nvol);
702 wm_put_nocache(ice, index, 0x180 | nvol);
703}
704
705/*
706 * DAC mute control
707 */
708#define wm_pcm_mute_info aureon_mono_bool_info
709
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100710static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100712 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713
Ingo Molnar62932df2006-01-16 16:34:20 +0100714 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1;
Ingo Molnar62932df2006-01-16 16:34:20 +0100716 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 return 0;
718}
719
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100720static int wm_pcm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100722 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 unsigned short nval, oval;
724 int change;
725
726 snd_ice1712_save_gpio_status(ice);
727 oval = wm_get(ice, WM_MUTE);
728 nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10);
729 if ((change = (nval != oval)))
730 wm_put(ice, WM_MUTE, nval);
731 snd_ice1712_restore_gpio_status(ice);
732
733 return change;
734}
735
736/*
737 * Master volume attenuation mixer control
738 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100739static int wm_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740{
741 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
742 uinfo->count = 2;
743 uinfo->value.integer.min = 0;
744 uinfo->value.integer.max = WM_VOL_MAX;
745 return 0;
746}
747
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100748static int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100750 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 int i;
752 for (i=0; i<2; i++)
753 ucontrol->value.integer.value[i] = ice->spec.aureon.master[i] & ~WM_VOL_MUTE;
754 return 0;
755}
756
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100757static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100759 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 int ch, change = 0;
761
762 snd_ice1712_save_gpio_status(ice);
763 for (ch = 0; ch < 2; ch++) {
764 if (ucontrol->value.integer.value[ch] != ice->spec.aureon.master[ch]) {
765 int dac;
766 ice->spec.aureon.master[ch] &= WM_VOL_MUTE;
767 ice->spec.aureon.master[ch] |= ucontrol->value.integer.value[ch];
768 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
769 wm_set_vol(ice, WM_DAC_ATTEN + dac + ch,
770 ice->spec.aureon.vol[dac + ch],
771 ice->spec.aureon.master[ch]);
772 change = 1;
773 }
774 }
775 snd_ice1712_restore_gpio_status(ice);
776 return change;
777}
778
779/*
780 * DAC volume attenuation mixer control
781 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100782static int wm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783{
784 int voices = kcontrol->private_value >> 8;
785 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
786 uinfo->count = voices;
787 uinfo->value.integer.min = 0; /* mute (-101dB) */
788 uinfo->value.integer.max = 0x7F; /* 0dB */
789 return 0;
790}
791
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100792static int wm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100794 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 int i, ofs, voices;
796
797 voices = kcontrol->private_value >> 8;
798 ofs = kcontrol->private_value & 0xff;
799 for (i = 0; i < voices; i++)
800 ucontrol->value.integer.value[i] = ice->spec.aureon.vol[ofs+i] & ~WM_VOL_MUTE;
801 return 0;
802}
803
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100804static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100806 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 int i, idx, ofs, voices;
808 int change = 0;
809
810 voices = kcontrol->private_value >> 8;
811 ofs = kcontrol->private_value & 0xff;
812 snd_ice1712_save_gpio_status(ice);
813 for (i = 0; i < voices; i++) {
814 idx = WM_DAC_ATTEN + ofs + i;
815 if (ucontrol->value.integer.value[i] != ice->spec.aureon.vol[ofs+i]) {
816 ice->spec.aureon.vol[ofs+i] &= WM_VOL_MUTE;
817 ice->spec.aureon.vol[ofs+i] |= ucontrol->value.integer.value[i];
818 wm_set_vol(ice, idx, ice->spec.aureon.vol[ofs+i],
819 ice->spec.aureon.master[i]);
820 change = 1;
821 }
822 }
823 snd_ice1712_restore_gpio_status(ice);
824 return change;
825}
826
827/*
828 * WM8770 mute control
829 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100830static int wm_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
832 uinfo->count = kcontrol->private_value >> 8;
833 uinfo->value.integer.min = 0;
834 uinfo->value.integer.max = 1;
835 return 0;
836}
837
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100838static int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100840 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 int voices, ofs, i;
842
843 voices = kcontrol->private_value >> 8;
844 ofs = kcontrol->private_value & 0xFF;
845
846 for (i = 0; i < voices; i++)
847 ucontrol->value.integer.value[i] = (ice->spec.aureon.vol[ofs+i] & WM_VOL_MUTE) ? 0 : 1;
848 return 0;
849}
850
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100851static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100853 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 int change = 0, voices, ofs, i;
855
856 voices = kcontrol->private_value >> 8;
857 ofs = kcontrol->private_value & 0xFF;
858
859 snd_ice1712_save_gpio_status(ice);
860 for (i = 0; i < voices; i++) {
861 int val = (ice->spec.aureon.vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
862 if (ucontrol->value.integer.value[i] != val) {
863 ice->spec.aureon.vol[ofs + i] &= ~WM_VOL_MUTE;
864 ice->spec.aureon.vol[ofs + i] |=
865 ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
866 wm_set_vol(ice, ofs + i, ice->spec.aureon.vol[ofs + i],
867 ice->spec.aureon.master[i]);
868 change = 1;
869 }
870 }
871 snd_ice1712_restore_gpio_status(ice);
872
873 return change;
874}
875
876/*
877 * WM8770 master mute control
878 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100879static int wm_master_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
881 uinfo->count = 2;
882 uinfo->value.integer.min = 0;
883 uinfo->value.integer.max = 1;
884 return 0;
885}
886
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100887static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100889 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890
891 ucontrol->value.integer.value[0] = (ice->spec.aureon.master[0] & WM_VOL_MUTE) ? 0 : 1;
892 ucontrol->value.integer.value[1] = (ice->spec.aureon.master[1] & WM_VOL_MUTE) ? 0 : 1;
893 return 0;
894}
895
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100896static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100898 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 int change = 0, i;
900
901 snd_ice1712_save_gpio_status(ice);
902 for (i = 0; i < 2; i++) {
903 int val = (ice->spec.aureon.master[i] & WM_VOL_MUTE) ? 0 : 1;
904 if (ucontrol->value.integer.value[i] != val) {
905 int dac;
906 ice->spec.aureon.master[i] &= ~WM_VOL_MUTE;
907 ice->spec.aureon.master[i] |=
908 ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
909 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
910 wm_set_vol(ice, WM_DAC_ATTEN + dac + i,
911 ice->spec.aureon.vol[dac + i],
912 ice->spec.aureon.master[i]);
913 change = 1;
914 }
915 }
916 snd_ice1712_restore_gpio_status(ice);
917
918 return change;
919}
920
921/* digital master volume */
922#define PCM_0dB 0xff
923#define PCM_RES 128 /* -64dB */
924#define PCM_MIN (PCM_0dB - PCM_RES)
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100925static int wm_pcm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926{
927 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
928 uinfo->count = 1;
929 uinfo->value.integer.min = 0; /* mute (-64dB) */
930 uinfo->value.integer.max = PCM_RES; /* 0dB */
931 return 0;
932}
933
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100934static int wm_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100936 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 unsigned short val;
938
Ingo Molnar62932df2006-01-16 16:34:20 +0100939 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
941 val = val > PCM_MIN ? (val - PCM_MIN) : 0;
942 ucontrol->value.integer.value[0] = val;
Ingo Molnar62932df2006-01-16 16:34:20 +0100943 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 return 0;
945}
946
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100947static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100949 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 unsigned short ovol, nvol;
951 int change = 0;
952
953 snd_ice1712_save_gpio_status(ice);
954 nvol = ucontrol->value.integer.value[0];
955 nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff;
956 ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
957 if (ovol != nvol) {
958 wm_put(ice, WM_DAC_DIG_MASTER_ATTEN, nvol); /* prelatch */
959 wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100); /* update */
960 change = 1;
961 }
962 snd_ice1712_restore_gpio_status(ice);
963 return change;
964}
965
966/*
967 * ADC mute control
968 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100969static int wm_adc_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970{
971 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
972 uinfo->count = 2;
973 uinfo->value.integer.min = 0;
974 uinfo->value.integer.max = 1;
975 return 0;
976}
977
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100978static int wm_adc_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100980 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 unsigned short val;
982 int i;
983
Ingo Molnar62932df2006-01-16 16:34:20 +0100984 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 for (i = 0; i < 2; i++) {
986 val = wm_get(ice, WM_ADC_GAIN + i);
987 ucontrol->value.integer.value[i] = ~val>>5 & 0x1;
988 }
Ingo Molnar62932df2006-01-16 16:34:20 +0100989 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 return 0;
991}
992
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100993static int wm_adc_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100995 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 unsigned short new, old;
997 int i, change = 0;
998
999 snd_ice1712_save_gpio_status(ice);
1000 for (i = 0; i < 2; i++) {
1001 old = wm_get(ice, WM_ADC_GAIN + i);
1002 new = (~ucontrol->value.integer.value[i]<<5&0x20) | (old&~0x20);
1003 if (new != old) {
1004 wm_put(ice, WM_ADC_GAIN + i, new);
1005 change = 1;
1006 }
1007 }
1008 snd_ice1712_restore_gpio_status(ice);
1009
1010 return change;
1011}
1012
1013/*
1014 * ADC gain mixer control
1015 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001016static int wm_adc_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017{
1018 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1019 uinfo->count = 2;
1020 uinfo->value.integer.min = 0; /* -12dB */
1021 uinfo->value.integer.max = 0x1f; /* 19dB */
1022 return 0;
1023}
1024
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001025static int wm_adc_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001027 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 int i, idx;
1029 unsigned short vol;
1030
Ingo Molnar62932df2006-01-16 16:34:20 +01001031 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 for (i = 0; i < 2; i++) {
1033 idx = WM_ADC_GAIN + i;
1034 vol = wm_get(ice, idx) & 0x1f;
1035 ucontrol->value.integer.value[i] = vol;
1036 }
Ingo Molnar62932df2006-01-16 16:34:20 +01001037 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 return 0;
1039}
1040
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001041static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001043 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 int i, idx;
1045 unsigned short ovol, nvol;
1046 int change = 0;
1047
1048 snd_ice1712_save_gpio_status(ice);
1049 for (i = 0; i < 2; i++) {
1050 idx = WM_ADC_GAIN + i;
1051 nvol = ucontrol->value.integer.value[i];
1052 ovol = wm_get(ice, idx);
1053 if ((ovol & 0x1f) != nvol) {
1054 wm_put(ice, idx, nvol | (ovol & ~0x1f));
1055 change = 1;
1056 }
1057 }
1058 snd_ice1712_restore_gpio_status(ice);
1059 return change;
1060}
1061
1062/*
1063 * ADC input mux mixer control
1064 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001065static int wm_adc_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066{
1067 static char *texts[] = {
1068 "CD", //AIN1
1069 "Aux", //AIN2
1070 "Line", //AIN3
1071 "Mic", //AIN4
1072 "AC97" //AIN5
1073 };
1074 static char *universe_texts[] = {
1075 "Aux1", //AIN1
1076 "CD", //AIN2
1077 "Phono", //AIN3
1078 "Line", //AIN4
1079 "Aux2", //AIN5
1080 "Mic", //AIN6
1081 "Aux3", //AIN7
1082 "AC97" //AIN8
1083 };
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001084 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085
1086 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1087 uinfo->count = 2;
1088 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) {
1089 uinfo->value.enumerated.items = 8;
1090 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1091 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1092 strcpy(uinfo->value.enumerated.name, universe_texts[uinfo->value.enumerated.item]);
1093 }
1094 else {
1095 uinfo->value.enumerated.items = 5;
1096 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1097 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1098 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1099 }
1100 return 0;
1101}
1102
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001103static int wm_adc_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001105 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 unsigned short val;
1107
Ingo Molnar62932df2006-01-16 16:34:20 +01001108 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 val = wm_get(ice, WM_ADC_MUX);
Takashi Iwai66820252006-03-20 18:31:57 +01001110 ucontrol->value.enumerated.item[0] = val & 7;
1111 ucontrol->value.enumerated.item[1] = (val >> 4) & 7;
Ingo Molnar62932df2006-01-16 16:34:20 +01001112 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 return 0;
1114}
1115
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001116static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001118 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 unsigned short oval, nval;
1120 int change;
1121
1122 snd_ice1712_save_gpio_status(ice);
1123 oval = wm_get(ice, WM_ADC_MUX);
1124 nval = oval & ~0x77;
Takashi Iwai66820252006-03-20 18:31:57 +01001125 nval |= ucontrol->value.enumerated.item[0] & 7;
1126 nval |= (ucontrol->value.enumerated.item[1] & 7) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 change = (oval != nval);
1128 if (change)
1129 wm_put(ice, WM_ADC_MUX, nval);
1130 snd_ice1712_restore_gpio_status(ice);
Takashi Iwai63786d02005-11-04 13:58:11 +01001131 return change;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132}
1133
1134/*
1135 * CS8415 Input mux
1136 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001137static int aureon_cs8415_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001139 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 static char *aureon_texts[] = {
1141 "CD", //RXP0
1142 "Optical" //RXP1
1143 };
1144 static char *prodigy_texts[] = {
1145 "CD",
1146 "Coax"
1147 };
1148 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1149 uinfo->count = 1;
1150 uinfo->value.enumerated.items = 2;
1151 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1152 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1153 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71)
1154 strcpy(uinfo->value.enumerated.name, prodigy_texts[uinfo->value.enumerated.item]);
1155 else
1156 strcpy(uinfo->value.enumerated.name, aureon_texts[uinfo->value.enumerated.item]);
1157 return 0;
1158}
1159
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001160static int aureon_cs8415_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001162 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163
1164 //snd_ice1712_save_gpio_status(ice);
1165 //val = aureon_cs8415_get(ice, CS8415_CTRL2);
Takashi Iwai66820252006-03-20 18:31:57 +01001166 ucontrol->value.enumerated.item[0] = ice->spec.aureon.cs8415_mux;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 //snd_ice1712_restore_gpio_status(ice);
1168 return 0;
1169}
1170
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001171static int aureon_cs8415_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001173 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 unsigned short oval, nval;
1175 int change;
1176
1177 snd_ice1712_save_gpio_status(ice);
1178 oval = aureon_cs8415_get(ice, CS8415_CTRL2);
1179 nval = oval & ~0x07;
Takashi Iwai66820252006-03-20 18:31:57 +01001180 nval |= ucontrol->value.enumerated.item[0] & 7;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 change = (oval != nval);
1182 if (change)
1183 aureon_cs8415_put(ice, CS8415_CTRL2, nval);
1184 snd_ice1712_restore_gpio_status(ice);
Takashi Iwai66820252006-03-20 18:31:57 +01001185 ice->spec.aureon.cs8415_mux = ucontrol->value.enumerated.item[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 return change;
1187}
1188
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001189static int aureon_cs8415_rate_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190{
1191 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1192 uinfo->count = 1;
1193 uinfo->value.integer.min = 0;
1194 uinfo->value.integer.max = 192000;
1195 return 0;
1196}
1197
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001198static int aureon_cs8415_rate_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001200 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 unsigned char ratio;
1202 ratio = aureon_cs8415_get(ice, CS8415_RATIO);
1203 ucontrol->value.integer.value[0] = (int)((unsigned int)ratio * 750);
1204 return 0;
1205}
1206
1207/*
1208 * CS8415A Mute
1209 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001210static int aureon_cs8415_mute_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211{
1212 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1213 uinfo->count = 1;
1214 return 0;
1215}
1216
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001217static int aureon_cs8415_mute_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001219 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 snd_ice1712_save_gpio_status(ice);
1221 ucontrol->value.integer.value[0] = (aureon_cs8415_get(ice, CS8415_CTRL1) & 0x20) ? 0 : 1;
1222 snd_ice1712_restore_gpio_status(ice);
1223 return 0;
1224}
1225
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001226static int aureon_cs8415_mute_put (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001228 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 unsigned char oval, nval;
1230 int change;
1231 snd_ice1712_save_gpio_status(ice);
1232 oval = aureon_cs8415_get(ice, CS8415_CTRL1);
1233 if (ucontrol->value.integer.value[0])
1234 nval = oval & ~0x20;
1235 else
1236 nval = oval | 0x20;
1237 if ((change = (oval != nval)))
1238 aureon_cs8415_put(ice, CS8415_CTRL1, nval);
1239 snd_ice1712_restore_gpio_status(ice);
1240 return change;
1241}
1242
1243/*
1244 * CS8415A Q-Sub info
1245 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001246static int aureon_cs8415_qsub_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
1248 uinfo->count = 10;
1249 return 0;
1250}
1251
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001252static int aureon_cs8415_qsub_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
1253 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254
1255 snd_ice1712_save_gpio_status(ice);
1256 aureon_cs8415_read(ice, CS8415_QSUB, ucontrol->value.bytes.data, 10);
1257 snd_ice1712_restore_gpio_status(ice);
1258
1259 return 0;
1260}
1261
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001262static int aureon_cs8415_spdif_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
1264 uinfo->count = 1;
1265 return 0;
1266}
1267
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001268static int aureon_cs8415_mask_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 memset(ucontrol->value.iec958.status, 0xFF, 24);
1270 return 0;
1271}
1272
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001273static int aureon_cs8415_spdif_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
1274 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275
1276 snd_ice1712_save_gpio_status(ice);
1277 aureon_cs8415_read(ice, CS8415_C_BUFFER, ucontrol->value.iec958.status, 24);
1278 snd_ice1712_restore_gpio_status(ice);
1279 return 0;
1280}
1281
1282/*
1283 * Headphone Amplifier
1284 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001285static int aureon_set_headphone_amp(struct snd_ice1712 *ice, int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286{
1287 unsigned int tmp, tmp2;
1288
1289 tmp2 = tmp = snd_ice1712_gpio_read(ice);
1290 if (enable)
Takashi Iwaic5130272006-05-23 15:46:10 +02001291 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT)
1292 tmp |= AUREON_HP_SEL;
1293 else
1294 tmp |= PRODIGY_HP_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 else
Takashi Iwaic5130272006-05-23 15:46:10 +02001296 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT)
1297 tmp &= ~ AUREON_HP_SEL;
1298 else
1299 tmp &= ~ PRODIGY_HP_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 if (tmp != tmp2) {
1301 snd_ice1712_gpio_write(ice, tmp);
1302 return 1;
1303 }
1304 return 0;
1305}
1306
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001307static int aureon_get_headphone_amp(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308{
1309 unsigned int tmp = snd_ice1712_gpio_read(ice);
1310
1311 return ( tmp & AUREON_HP_SEL )!= 0;
1312}
1313
1314#define aureon_hpamp_info aureon_mono_bool_info
1315
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001316static int aureon_hpamp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001318 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319
1320 ucontrol->value.integer.value[0] = aureon_get_headphone_amp(ice);
1321 return 0;
1322}
1323
1324
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001325static int aureon_hpamp_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
1329 return aureon_set_headphone_amp(ice,ucontrol->value.integer.value[0]);
1330}
1331
1332/*
1333 * Deemphasis
1334 */
1335
1336#define aureon_deemp_info aureon_mono_bool_info
1337
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001338static int aureon_deemp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001340 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 0xf;
1342 return 0;
1343}
1344
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001345static int aureon_deemp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001347 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 int temp, temp2;
1349 temp2 = temp = wm_get(ice, WM_DAC_CTRL2);
1350 if (ucontrol->value.integer.value[0])
1351 temp |= 0xf;
1352 else
1353 temp &= ~0xf;
1354 if (temp != temp2) {
1355 wm_put(ice, WM_DAC_CTRL2, temp);
1356 return 1;
1357 }
1358 return 0;
1359}
1360
1361/*
1362 * ADC Oversampling
1363 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001364static int aureon_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365{
1366 static char *texts[2] = { "128x", "64x" };
1367
1368 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1369 uinfo->count = 1;
1370 uinfo->value.enumerated.items = 2;
1371
1372 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1373 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1374 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1375
1376 return 0;
1377}
1378
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001379static int aureon_oversampling_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001381 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 0x8;
1383 return 0;
1384}
1385
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001386static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387{
1388 int temp, temp2;
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001389 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390
1391 temp2 = temp = wm_get(ice, WM_MASTER);
1392
1393 if (ucontrol->value.enumerated.item[0])
1394 temp |= 0x8;
1395 else
1396 temp &= ~0x8;
1397
1398 if (temp != temp2) {
1399 wm_put(ice, WM_MASTER, temp);
1400 return 1;
1401 }
1402 return 0;
1403}
1404
1405/*
1406 * mixers
1407 */
1408
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001409static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 {
1411 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1412 .name = "Master Playback Switch",
1413 .info = wm_master_mute_info,
1414 .get = wm_master_mute_get,
1415 .put = wm_master_mute_put
1416 },
1417 {
1418 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001419 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1420 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 .name = "Master Playback Volume",
1422 .info = wm_master_vol_info,
1423 .get = wm_master_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +02001424 .put = wm_master_vol_put,
1425 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 },
1427 {
1428 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1429 .name = "Front Playback Switch",
1430 .info = wm_mute_info,
1431 .get = wm_mute_get,
1432 .put = wm_mute_put,
1433 .private_value = (2 << 8) | 0
1434 },
1435 {
1436 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001437 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1438 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 .name = "Front Playback Volume",
1440 .info = wm_vol_info,
1441 .get = wm_vol_get,
1442 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001443 .private_value = (2 << 8) | 0,
1444 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 },
1446 {
1447 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1448 .name = "Rear Playback Switch",
1449 .info = wm_mute_info,
1450 .get = wm_mute_get,
1451 .put = wm_mute_put,
1452 .private_value = (2 << 8) | 2
1453 },
1454 {
1455 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001456 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1457 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 .name = "Rear Playback Volume",
1459 .info = wm_vol_info,
1460 .get = wm_vol_get,
1461 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001462 .private_value = (2 << 8) | 2,
1463 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 },
1465 {
1466 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1467 .name = "Center Playback Switch",
1468 .info = wm_mute_info,
1469 .get = wm_mute_get,
1470 .put = wm_mute_put,
1471 .private_value = (1 << 8) | 4
1472 },
1473 {
1474 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001475 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1476 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 .name = "Center Playback Volume",
1478 .info = wm_vol_info,
1479 .get = wm_vol_get,
1480 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001481 .private_value = (1 << 8) | 4,
1482 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 },
1484 {
1485 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1486 .name = "LFE Playback Switch",
1487 .info = wm_mute_info,
1488 .get = wm_mute_get,
1489 .put = wm_mute_put,
1490 .private_value = (1 << 8) | 5
1491 },
1492 {
1493 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001494 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1495 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 .name = "LFE Playback Volume",
1497 .info = wm_vol_info,
1498 .get = wm_vol_get,
1499 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001500 .private_value = (1 << 8) | 5,
1501 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 },
1503 {
1504 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1505 .name = "Side Playback Switch",
1506 .info = wm_mute_info,
1507 .get = wm_mute_get,
1508 .put = wm_mute_put,
1509 .private_value = (2 << 8) | 6
1510 },
1511 {
1512 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001513 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1514 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 .name = "Side Playback Volume",
1516 .info = wm_vol_info,
1517 .get = wm_vol_get,
1518 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001519 .private_value = (2 << 8) | 6,
1520 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 }
1522};
1523
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001524static struct snd_kcontrol_new wm_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 {
1526 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1527 .name = "PCM Playback Switch",
1528 .info = wm_pcm_mute_info,
1529 .get = wm_pcm_mute_get,
1530 .put = wm_pcm_mute_put
1531 },
1532 {
1533 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001534 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1535 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 .name = "PCM Playback Volume",
1537 .info = wm_pcm_vol_info,
1538 .get = wm_pcm_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +02001539 .put = wm_pcm_vol_put,
1540 .tlv = { .p = db_scale_wm_pcm }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 },
1542 {
1543 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1544 .name = "Capture Switch",
1545 .info = wm_adc_mute_info,
1546 .get = wm_adc_mute_get,
1547 .put = wm_adc_mute_put,
1548 },
1549 {
1550 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001551 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1552 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 .name = "Capture Volume",
1554 .info = wm_adc_vol_info,
1555 .get = wm_adc_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +02001556 .put = wm_adc_vol_put,
1557 .tlv = { .p = db_scale_wm_adc }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 },
1559 {
1560 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1561 .name = "Capture Source",
1562 .info = wm_adc_mux_info,
1563 .get = wm_adc_mux_get,
1564 .put = wm_adc_mux_put,
1565 .private_value = 5
1566 },
1567 {
1568 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1569 .name = "External Amplifier",
1570 .info = aureon_hpamp_info,
1571 .get = aureon_hpamp_get,
1572 .put = aureon_hpamp_put
1573 },
1574 {
1575 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1576 .name = "DAC Deemphasis Switch",
1577 .info = aureon_deemp_info,
1578 .get = aureon_deemp_get,
1579 .put = aureon_deemp_put
1580 },
1581 {
1582 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1583 .name = "ADC Oversampling",
1584 .info = aureon_oversampling_info,
1585 .get = aureon_oversampling_get,
1586 .put = aureon_oversampling_put
1587 }
1588};
1589
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001590static struct snd_kcontrol_new ac97_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 {
1592 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1593 .name = "AC97 Playback Switch",
1594 .info = aureon_ac97_mmute_info,
1595 .get = aureon_ac97_mmute_get,
1596 .put = aureon_ac97_mmute_put,
1597 .private_value = AC97_MASTER
1598 },
1599 {
1600 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001601 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1602 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 .name = "AC97 Playback Volume",
1604 .info = aureon_ac97_vol_info,
1605 .get = aureon_ac97_vol_get,
1606 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001607 .private_value = AC97_MASTER|AUREON_AC97_STEREO,
1608 .tlv = { .p = db_scale_ac97_master }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 },
1610 {
1611 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1612 .name = "CD Playback Switch",
1613 .info = aureon_ac97_mute_info,
1614 .get = aureon_ac97_mute_get,
1615 .put = aureon_ac97_mute_put,
1616 .private_value = AC97_CD
1617 },
1618 {
1619 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001620 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1621 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 .name = "CD Playback Volume",
1623 .info = aureon_ac97_vol_info,
1624 .get = aureon_ac97_vol_get,
1625 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001626 .private_value = AC97_CD|AUREON_AC97_STEREO,
1627 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 },
1629 {
1630 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1631 .name = "Aux Playback Switch",
1632 .info = aureon_ac97_mute_info,
1633 .get = aureon_ac97_mute_get,
1634 .put = aureon_ac97_mute_put,
1635 .private_value = AC97_AUX,
1636 },
1637 {
1638 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001639 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1640 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 .name = "Aux Playback Volume",
1642 .info = aureon_ac97_vol_info,
1643 .get = aureon_ac97_vol_get,
1644 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001645 .private_value = AC97_AUX|AUREON_AC97_STEREO,
1646 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 },
1648 {
1649 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1650 .name = "Line Playback Switch",
1651 .info = aureon_ac97_mute_info,
1652 .get = aureon_ac97_mute_get,
1653 .put = aureon_ac97_mute_put,
1654 .private_value = AC97_LINE
1655 },
1656 {
1657 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001658 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1659 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 .name = "Line Playback Volume",
1661 .info = aureon_ac97_vol_info,
1662 .get = aureon_ac97_vol_get,
1663 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001664 .private_value = AC97_LINE|AUREON_AC97_STEREO,
1665 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 },
1667 {
1668 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1669 .name = "Mic Playback Switch",
1670 .info = aureon_ac97_mute_info,
1671 .get = aureon_ac97_mute_get,
1672 .put = aureon_ac97_mute_put,
1673 .private_value = AC97_MIC
1674 },
1675 {
1676 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001677 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1678 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 .name = "Mic Playback Volume",
1680 .info = aureon_ac97_vol_info,
1681 .get = aureon_ac97_vol_get,
1682 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001683 .private_value = AC97_MIC,
1684 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 },
1686 {
1687 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1688 .name = "Mic Boost (+20dB)",
1689 .info = aureon_ac97_micboost_info,
1690 .get = aureon_ac97_micboost_get,
1691 .put = aureon_ac97_micboost_put
1692 }
1693};
1694
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001695static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 {
1697 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1698 .name = "AC97 Playback Switch",
1699 .info = aureon_ac97_mmute_info,
1700 .get = aureon_ac97_mmute_get,
1701 .put = aureon_ac97_mmute_put,
1702 .private_value = AC97_MASTER
1703 },
1704 {
1705 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001706 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1707 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 .name = "AC97 Playback Volume",
1709 .info = aureon_ac97_vol_info,
1710 .get = aureon_ac97_vol_get,
1711 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001712 .private_value = AC97_MASTER|AUREON_AC97_STEREO,
1713 .tlv = { .p = db_scale_ac97_master }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 },
1715 {
1716 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1717 .name = "CD Playback Switch",
1718 .info = aureon_ac97_mute_info,
1719 .get = aureon_ac97_mute_get,
1720 .put = aureon_ac97_mute_put,
1721 .private_value = AC97_AUX
1722 },
1723 {
1724 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001725 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1726 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 .name = "CD Playback Volume",
1728 .info = aureon_ac97_vol_info,
1729 .get = aureon_ac97_vol_get,
1730 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001731 .private_value = AC97_AUX|AUREON_AC97_STEREO,
1732 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 },
1734 {
1735 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1736 .name = "Phono Playback Switch",
1737 .info = aureon_ac97_mute_info,
1738 .get = aureon_ac97_mute_get,
1739 .put = aureon_ac97_mute_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001740 .private_value = AC97_CD
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 },
1742 {
1743 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001744 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1745 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 .name = "Phono Playback Volume",
1747 .info = aureon_ac97_vol_info,
1748 .get = aureon_ac97_vol_get,
1749 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001750 .private_value = AC97_CD|AUREON_AC97_STEREO,
1751 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 },
1753 {
1754 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1755 .name = "Line Playback Switch",
1756 .info = aureon_ac97_mute_info,
1757 .get = aureon_ac97_mute_get,
1758 .put = aureon_ac97_mute_put,
1759 .private_value = AC97_LINE
1760 },
1761 {
1762 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001763 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1764 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 .name = "Line Playback Volume",
1766 .info = aureon_ac97_vol_info,
1767 .get = aureon_ac97_vol_get,
1768 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001769 .private_value = AC97_LINE|AUREON_AC97_STEREO,
1770 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 },
1772 {
1773 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1774 .name = "Mic Playback Switch",
1775 .info = aureon_ac97_mute_info,
1776 .get = aureon_ac97_mute_get,
1777 .put = aureon_ac97_mute_put,
1778 .private_value = AC97_MIC
1779 },
1780 {
1781 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001782 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1783 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 .name = "Mic Playback Volume",
1785 .info = aureon_ac97_vol_info,
1786 .get = aureon_ac97_vol_get,
1787 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001788 .private_value = AC97_MIC,
1789 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 },
1791 {
1792 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1793 .name = "Mic Boost (+20dB)",
1794 .info = aureon_ac97_micboost_info,
1795 .get = aureon_ac97_micboost_get,
1796 .put = aureon_ac97_micboost_put
1797 },
1798 {
1799 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1800 .name = "Aux Playback Switch",
1801 .info = aureon_ac97_mute_info,
1802 .get = aureon_ac97_mute_get,
1803 .put = aureon_ac97_mute_put,
1804 .private_value = AC97_VIDEO,
1805 },
1806 {
1807 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001808 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1809 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 .name = "Aux Playback Volume",
1811 .info = aureon_ac97_vol_info,
1812 .get = aureon_ac97_vol_get,
1813 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001814 .private_value = AC97_VIDEO|AUREON_AC97_STEREO,
1815 .tlv = { .p = db_scale_ac97_gain }
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +02001816 },
1817 {
1818 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1819 .name = "Aux Source",
1820 .info = aureon_universe_inmux_info,
1821 .get = aureon_universe_inmux_get,
1822 .put = aureon_universe_inmux_put
1823 }
1824
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825};
1826
1827
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001828static struct snd_kcontrol_new cs8415_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 {
1830 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1831 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH),
1832 .info = aureon_cs8415_mute_info,
1833 .get = aureon_cs8415_mute_get,
1834 .put = aureon_cs8415_mute_put
1835 },
1836 {
1837 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1838 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Source",
1839 .info = aureon_cs8415_mux_info,
1840 .get = aureon_cs8415_mux_get,
1841 .put = aureon_cs8415_mux_put,
1842 },
1843 {
1844 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1845 .name = SNDRV_CTL_NAME_IEC958("Q-subcode ",CAPTURE,DEFAULT),
1846 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1847 .info = aureon_cs8415_qsub_info,
1848 .get = aureon_cs8415_qsub_get,
1849 },
1850 {
1851 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1852 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,MASK),
1853 .access = SNDRV_CTL_ELEM_ACCESS_READ,
1854 .info = aureon_cs8415_spdif_info,
1855 .get = aureon_cs8415_mask_get
1856 },
1857 {
1858 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1859 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT),
1860 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1861 .info = aureon_cs8415_spdif_info,
1862 .get = aureon_cs8415_spdif_get
1863 },
1864 {
1865 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1866 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Rate",
1867 .access =SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1868 .info = aureon_cs8415_rate_info,
1869 .get = aureon_cs8415_rate_get
1870 }
1871};
1872
1873
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001874static int __devinit aureon_add_controls(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875{
1876 unsigned int i, counts;
1877 int err;
1878
1879 counts = ARRAY_SIZE(aureon_dac_controls);
1880 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY)
1881 counts -= 2; /* no side */
1882 for (i = 0; i < counts; i++) {
1883 err = snd_ctl_add(ice->card, snd_ctl_new1(&aureon_dac_controls[i], ice));
1884 if (err < 0)
1885 return err;
1886 }
1887
1888 for (i = 0; i < ARRAY_SIZE(wm_controls); i++) {
1889 err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice));
1890 if (err < 0)
1891 return err;
1892 }
1893
1894 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) {
1895 for (i = 0; i < ARRAY_SIZE(universe_ac97_controls); i++) {
1896 err = snd_ctl_add(ice->card, snd_ctl_new1(&universe_ac97_controls[i], ice));
1897 if (err < 0)
1898 return err;
1899 }
1900 }
Takashi Iwai45fe7222006-01-13 13:50:16 +01001901 else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 for (i = 0; i < ARRAY_SIZE(ac97_controls); i++) {
1903 err = snd_ctl_add(ice->card, snd_ctl_new1(&ac97_controls[i], ice));
1904 if (err < 0)
1905 return err;
1906 }
1907 }
1908
Takashi Iwai45fe7222006-01-13 13:50:16 +01001909 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 unsigned char id;
1911 snd_ice1712_save_gpio_status(ice);
1912 id = aureon_cs8415_get(ice, CS8415_ID);
1913 if (id != 0x41)
Takashi Iwai99b359b2005-10-20 18:26:44 +02001914 snd_printk(KERN_INFO "No CS8415 chip. Skipping CS8415 controls.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 else if ((id & 0x0F) != 0x01)
Takashi Iwai99b359b2005-10-20 18:26:44 +02001916 snd_printk(KERN_INFO "Detected unsupported CS8415 rev. (%c)\n", (char)((id & 0x0F) + 'A' - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 else {
1918 for (i = 0; i< ARRAY_SIZE(cs8415_controls); i++) {
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001919 struct snd_kcontrol *kctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 err = snd_ctl_add(ice->card, (kctl = snd_ctl_new1(&cs8415_controls[i], ice)));
1921 if (err < 0)
1922 return err;
1923 if (i > 1)
1924 kctl->id.device = ice->pcm->device;
1925 }
1926 }
1927 snd_ice1712_restore_gpio_status(ice);
1928 }
1929
1930 return 0;
1931}
1932
1933
1934/*
1935 * initialize the chip
1936 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001937static int __devinit aureon_init(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938{
1939 static unsigned short wm_inits_aureon[] = {
1940 /* These come first to reduce init pop noise */
1941 0x1b, 0x044, /* ADC Mux (AC'97 source) */
1942 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
1943 0x1d, 0x009, /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */
1944
1945 0x18, 0x000, /* All power-up */
1946
1947 0x16, 0x122, /* I2S, normal polarity, 24bit */
1948 0x17, 0x022, /* 256fs, slave mode */
1949 0x00, 0, /* DAC1 analog mute */
1950 0x01, 0, /* DAC2 analog mute */
1951 0x02, 0, /* DAC3 analog mute */
1952 0x03, 0, /* DAC4 analog mute */
1953 0x04, 0, /* DAC5 analog mute */
1954 0x05, 0, /* DAC6 analog mute */
1955 0x06, 0, /* DAC7 analog mute */
1956 0x07, 0, /* DAC8 analog mute */
1957 0x08, 0x100, /* master analog mute */
1958 0x09, 0xff, /* DAC1 digital full */
1959 0x0a, 0xff, /* DAC2 digital full */
1960 0x0b, 0xff, /* DAC3 digital full */
1961 0x0c, 0xff, /* DAC4 digital full */
1962 0x0d, 0xff, /* DAC5 digital full */
1963 0x0e, 0xff, /* DAC6 digital full */
1964 0x0f, 0xff, /* DAC7 digital full */
1965 0x10, 0xff, /* DAC8 digital full */
1966 0x11, 0x1ff, /* master digital full */
1967 0x12, 0x000, /* phase normal */
1968 0x13, 0x090, /* unmute DAC L/R */
1969 0x14, 0x000, /* all unmute */
1970 0x15, 0x000, /* no deemphasis, no ZFLG */
1971 0x19, 0x000, /* -12dB ADC/L */
1972 0x1a, 0x000, /* -12dB ADC/R */
1973 (unsigned short)-1
1974 };
1975 static unsigned short wm_inits_prodigy[] = {
1976
1977 /* These come first to reduce init pop noise */
1978 0x1b, 0x000, /* ADC Mux */
1979 0x1c, 0x009, /* Out Mux1 */
1980 0x1d, 0x009, /* Out Mux2 */
1981
1982 0x18, 0x000, /* All power-up */
1983
1984 0x16, 0x022, /* I2S, normal polarity, 24bit, high-pass on */
1985 0x17, 0x006, /* 128fs, slave mode */
1986
1987 0x00, 0, /* DAC1 analog mute */
1988 0x01, 0, /* DAC2 analog mute */
1989 0x02, 0, /* DAC3 analog mute */
1990 0x03, 0, /* DAC4 analog mute */
1991 0x04, 0, /* DAC5 analog mute */
1992 0x05, 0, /* DAC6 analog mute */
1993 0x06, 0, /* DAC7 analog mute */
1994 0x07, 0, /* DAC8 analog mute */
1995 0x08, 0x100, /* master analog mute */
1996
1997 0x09, 0x7f, /* DAC1 digital full */
1998 0x0a, 0x7f, /* DAC2 digital full */
1999 0x0b, 0x7f, /* DAC3 digital full */
2000 0x0c, 0x7f, /* DAC4 digital full */
2001 0x0d, 0x7f, /* DAC5 digital full */
2002 0x0e, 0x7f, /* DAC6 digital full */
2003 0x0f, 0x7f, /* DAC7 digital full */
2004 0x10, 0x7f, /* DAC8 digital full */
2005 0x11, 0x1FF, /* master digital full */
2006
2007 0x12, 0x000, /* phase normal */
2008 0x13, 0x090, /* unmute DAC L/R */
2009 0x14, 0x000, /* all unmute */
2010 0x15, 0x000, /* no deemphasis, no ZFLG */
2011
2012 0x19, 0x000, /* -12dB ADC/L */
2013 0x1a, 0x000, /* -12dB ADC/R */
2014 (unsigned short)-1
2015
2016 };
2017 static unsigned short cs_inits[] = {
2018 0x0441, /* RUN */
2019 0x0180, /* no mute, OMCK output on RMCK pin */
2020 0x0201, /* S/PDIF source on RXP1 */
2021 0x0605, /* slave, 24bit, MSB on second OSCLK, SDOUT for right channel when OLRCK is high */
2022 (unsigned short)-1
2023 };
2024 unsigned int tmp;
2025 unsigned short *p;
2026 int err, i;
2027
2028 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) {
2029 ice->num_total_dacs = 6;
2030 ice->num_total_adcs = 2;
2031 } else {
2032 /* aureon 7.1 and prodigy 7.1 */
2033 ice->num_total_dacs = 8;
2034 ice->num_total_adcs = 2;
2035 }
2036
2037 /* to remeber the register values of CS8415 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01002038 ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 if (! ice->akm)
2040 return -ENOMEM;
2041 ice->akm_codecs = 1;
2042
2043 if ((err = aureon_ac97_init(ice)) != 0)
2044 return err;
2045
2046 snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for the time being */
2047
2048 /* reset the wm codec as the SPI mode */
2049 snd_ice1712_save_gpio_status(ice);
2050 snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RESET|AUREON_WM_CS|AUREON_CS8415_CS|AUREON_HP_SEL));
2051
2052 tmp = snd_ice1712_gpio_read(ice);
2053 tmp &= ~AUREON_WM_RESET;
2054 snd_ice1712_gpio_write(ice, tmp);
2055 udelay(1);
2056 tmp |= AUREON_WM_CS | AUREON_CS8415_CS;
2057 snd_ice1712_gpio_write(ice, tmp);
2058 udelay(1);
2059 tmp |= AUREON_WM_RESET;
2060 snd_ice1712_gpio_write(ice, tmp);
2061 udelay(1);
2062
2063 /* initialize WM8770 codec */
Takashi Iwai45fe7222006-01-13 13:50:16 +01002064 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71 ||
2065 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 p = wm_inits_prodigy;
2067 else
2068 p = wm_inits_aureon;
2069 for (; *p != (unsigned short)-1; p += 2)
2070 wm_put(ice, p[0], p[1]);
2071
2072 /* initialize CS8415A codec */
Takashi Iwai45fe7222006-01-13 13:50:16 +01002073 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) {
2074 for (p = cs_inits; *p != (unsigned short)-1; p++)
2075 aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24);
2076 ice->spec.aureon.cs8415_mux = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077
Takashi Iwai45fe7222006-01-13 13:50:16 +01002078 aureon_set_headphone_amp(ice, 1);
2079 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080
2081 snd_ice1712_restore_gpio_status(ice);
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +02002082
2083 /* initialize PCA9554 pin directions & set default input*/
2084 aureon_pca9554_write(ice, PCA9554_DIR, 0x00);
2085 aureon_pca9554_write(ice, PCA9554_OUT, 0x00); /* internal AUX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086
2087 ice->spec.aureon.master[0] = WM_VOL_MUTE;
2088 ice->spec.aureon.master[1] = WM_VOL_MUTE;
2089 for (i = 0; i < ice->num_total_dacs; i++) {
2090 ice->spec.aureon.vol[i] = WM_VOL_MUTE;
2091 wm_set_vol(ice, i, ice->spec.aureon.vol[i], ice->spec.aureon.master[i % 2]);
2092 }
2093
2094 return 0;
2095}
2096
2097
2098/*
2099 * Aureon boards don't provide the EEPROM data except for the vendor IDs.
2100 * hence the driver needs to sets up it properly.
2101 */
2102
2103static unsigned char aureon51_eeprom[] __devinitdata = {
2104 0x0a, /* SYSCONF: clock 512, spdif-in/ADC, 3DACs */
2105 0x80, /* ACLINK: I2S */
2106 0xfc, /* I2S: vol, 96k, 24bit, 192k */
2107 0xc3, /* SPDIF: out-en, out-int, spdif-in */
2108 0xff, /* GPIO_DIR */
2109 0xff, /* GPIO_DIR1 */
2110 0x5f, /* GPIO_DIR2 */
2111 0x00, /* GPIO_MASK */
2112 0x00, /* GPIO_MASK1 */
2113 0x00, /* GPIO_MASK2 */
2114 0x00, /* GPIO_STATE */
2115 0x00, /* GPIO_STATE1 */
2116 0x00, /* GPIO_STATE2 */
2117};
2118
2119static unsigned char aureon71_eeprom[] __devinitdata = {
2120 0x0b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */
2121 0x80, /* ACLINK: I2S */
2122 0xfc, /* I2S: vol, 96k, 24bit, 192k */
2123 0xc3, /* SPDIF: out-en, out-int, spdif-in */
2124 0xff, /* GPIO_DIR */
2125 0xff, /* GPIO_DIR1 */
2126 0x5f, /* GPIO_DIR2 */
2127 0x00, /* GPIO_MASK */
2128 0x00, /* GPIO_MASK1 */
2129 0x00, /* GPIO_MASK2 */
2130 0x00, /* GPIO_STATE */
2131 0x00, /* GPIO_STATE1 */
2132 0x00, /* GPIO_STATE2 */
2133};
2134
2135static unsigned char prodigy71_eeprom[] __devinitdata = {
2136 0x0b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */
2137 0x80, /* ACLINK: I2S */
2138 0xfc, /* I2S: vol, 96k, 24bit, 192k */
2139 0xc3, /* SPDIF: out-en, out-int, spdif-in */
2140 0xff, /* GPIO_DIR */
2141 0xff, /* GPIO_DIR1 */
2142 0x5f, /* GPIO_DIR2 */
2143 0x00, /* GPIO_MASK */
2144 0x00, /* GPIO_MASK1 */
2145 0x00, /* GPIO_MASK2 */
2146 0x00, /* GPIO_STATE */
2147 0x00, /* GPIO_STATE1 */
2148 0x00, /* GPIO_STATE2 */
2149};
2150
Takashi Iwai45fe7222006-01-13 13:50:16 +01002151static unsigned char prodigy71lt_eeprom[] __devinitdata = {
Takashi Iwaic5130272006-05-23 15:46:10 +02002152 0x4b, /* SYSCINF: clock 512, spdif-in/ADC, 4DACs */
Takashi Iwai45fe7222006-01-13 13:50:16 +01002153 0x80, /* ACLINK: I2S */
2154 0xfc, /* I2S: vol, 96k, 24bit, 192k */
Takashi Iwaic5130272006-05-23 15:46:10 +02002155 0xc3, /* SPDIF: out-en, out-int, spdif-in */
2156 0xff, /* GPIO_DIR */
2157 0xff, /* GPIO_DIR1 */
2158 0x5f, /* GPIO_DIR2 */
2159 0x00, /* GPIO_MASK */
2160 0x00, /* GPIO_MASK1 */
2161 0x00, /* GPIO_MASK2 */
Takashi Iwai45fe7222006-01-13 13:50:16 +01002162 0x00, /* GPIO_STATE */
2163 0x00, /* GPIO_STATE1 */
2164 0x00, /* GPIO_STATE2 */
2165};
2166
2167
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168/* entry point */
2169struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = {
2170 {
2171 .subvendor = VT1724_SUBDEVICE_AUREON51_SKY,
2172 .name = "Terratec Aureon 5.1-Sky",
2173 .model = "aureon51",
2174 .chip_init = aureon_init,
2175 .build_controls = aureon_add_controls,
2176 .eeprom_size = sizeof(aureon51_eeprom),
2177 .eeprom_data = aureon51_eeprom,
2178 .driver = "Aureon51",
2179 },
2180 {
2181 .subvendor = VT1724_SUBDEVICE_AUREON71_SPACE,
2182 .name = "Terratec Aureon 7.1-Space",
2183 .model = "aureon71",
2184 .chip_init = aureon_init,
2185 .build_controls = aureon_add_controls,
2186 .eeprom_size = sizeof(aureon71_eeprom),
2187 .eeprom_data = aureon71_eeprom,
2188 .driver = "Aureon71",
2189 },
2190 {
2191 .subvendor = VT1724_SUBDEVICE_AUREON71_UNIVERSE,
2192 .name = "Terratec Aureon 7.1-Universe",
2193 .model = "universe",
2194 .chip_init = aureon_init,
2195 .build_controls = aureon_add_controls,
2196 .eeprom_size = sizeof(aureon71_eeprom),
2197 .eeprom_data = aureon71_eeprom,
Takashi Iwai9f37c5b2006-06-29 16:40:21 +02002198 .driver = "Aureon71Univ", /* keep in 15 letters */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 },
2200 {
2201 .subvendor = VT1724_SUBDEVICE_PRODIGY71,
2202 .name = "Audiotrak Prodigy 7.1",
2203 .model = "prodigy71",
2204 .chip_init = aureon_init,
2205 .build_controls = aureon_add_controls,
2206 .eeprom_size = sizeof(prodigy71_eeprom),
2207 .eeprom_data = prodigy71_eeprom,
2208 .driver = "Prodigy71", /* should be identical with Aureon71 */
2209 },
Takashi Iwai45fe7222006-01-13 13:50:16 +01002210 {
2211 .subvendor = VT1724_SUBDEVICE_PRODIGY71LT,
2212 .name = "Audiotrak Prodigy 7.1 LT",
2213 .model = "prodigy71lt",
2214 .chip_init = aureon_init,
2215 .build_controls = aureon_add_controls,
2216 .eeprom_size = sizeof(prodigy71lt_eeprom),
2217 .eeprom_data = prodigy71lt_eeprom,
2218 .driver = "Prodigy71LT",
2219 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 { } /* terminator */
2221};