blob: 6941d85dfec9d669c6da90db6fd6de45821f0d55 [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 */
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
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 Iwaiab0c7d72005-11-17 15:00:18 +0100624static int aureon_mono_bool_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625{
626 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
627 uinfo->count = 1;
628 uinfo->value.integer.min = 0;
629 uinfo->value.integer.max = 1;
630 return 0;
631}
632
633/*
634 * AC'97 master playback mute controls (Mute on WM8770 chip)
635 */
636#define aureon_ac97_mmute_info aureon_mono_bool_info
637
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100638static int aureon_ac97_mmute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100640 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641
Ingo Molnar62932df2006-01-16 16:34:20 +0100642 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643
644 ucontrol->value.integer.value[0] = (wm_get(ice, WM_OUT_MUX1) >> 1) & 0x01;
645
Ingo Molnar62932df2006-01-16 16:34:20 +0100646 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 return 0;
648}
649
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100650static int aureon_ac97_mmute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
651 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 unsigned short ovol, nvol;
653 int change;
654
655 snd_ice1712_save_gpio_status(ice);
656
657 ovol = wm_get(ice, WM_OUT_MUX1);
658 nvol = (ovol & ~0x02) | (ucontrol->value.integer.value[0] ? 0x02 : 0x00);
659 if ((change = (ovol != nvol)))
660 wm_put(ice, WM_OUT_MUX1, nvol);
661
662 snd_ice1712_restore_gpio_status(ice);
663
664 return change;
665}
666
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100667static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
668static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
669static const DECLARE_TLV_DB_SCALE(db_scale_wm_adc, -1200, 100, 0);
670static const DECLARE_TLV_DB_SCALE(db_scale_ac97_master, -4650, 150, 0);
671static const DECLARE_TLV_DB_SCALE(db_scale_ac97_gain, -3450, 150, 0);
Takashi Iwaif640c322006-08-30 16:57:37 +0200672
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673/*
674 * Logarithmic volume values for WM8770
675 * Computed as 20 * Log10(255 / x)
676 */
Takashi Iwai32b47da2007-01-29 15:26:36 +0100677static const unsigned char wm_vol[256] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23,
679 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17,
680 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13,
681 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11,
682 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8,
683 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,
684 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,
685 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,
686 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,
687 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,
688 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,
689 0, 0
690};
691
692#define WM_VOL_MAX (sizeof(wm_vol) - 1)
693#define WM_VOL_MUTE 0x8000
694
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100695static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, unsigned short vol, unsigned short master)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696{
697 unsigned char nvol;
698
699 if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))
700 nvol = 0;
701 else
702 nvol = 127 - wm_vol[(((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 127) & WM_VOL_MAX];
703
704 wm_put(ice, index, nvol);
705 wm_put_nocache(ice, index, 0x180 | nvol);
706}
707
708/*
709 * DAC mute control
710 */
711#define wm_pcm_mute_info aureon_mono_bool_info
712
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100713static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100715 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
Ingo Molnar62932df2006-01-16 16:34:20 +0100717 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1;
Ingo Molnar62932df2006-01-16 16:34:20 +0100719 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 return 0;
721}
722
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100723static int wm_pcm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100725 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 unsigned short nval, oval;
727 int change;
728
729 snd_ice1712_save_gpio_status(ice);
730 oval = wm_get(ice, WM_MUTE);
731 nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10);
732 if ((change = (nval != oval)))
733 wm_put(ice, WM_MUTE, nval);
734 snd_ice1712_restore_gpio_status(ice);
735
736 return change;
737}
738
739/*
740 * Master volume attenuation mixer control
741 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100742static int wm_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743{
744 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
745 uinfo->count = 2;
746 uinfo->value.integer.min = 0;
747 uinfo->value.integer.max = WM_VOL_MAX;
748 return 0;
749}
750
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100751static int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100753 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 int i;
755 for (i=0; i<2; i++)
756 ucontrol->value.integer.value[i] = ice->spec.aureon.master[i] & ~WM_VOL_MUTE;
757 return 0;
758}
759
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100760static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100762 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 int ch, change = 0;
764
765 snd_ice1712_save_gpio_status(ice);
766 for (ch = 0; ch < 2; ch++) {
767 if (ucontrol->value.integer.value[ch] != ice->spec.aureon.master[ch]) {
768 int dac;
769 ice->spec.aureon.master[ch] &= WM_VOL_MUTE;
770 ice->spec.aureon.master[ch] |= ucontrol->value.integer.value[ch];
771 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
772 wm_set_vol(ice, WM_DAC_ATTEN + dac + ch,
773 ice->spec.aureon.vol[dac + ch],
774 ice->spec.aureon.master[ch]);
775 change = 1;
776 }
777 }
778 snd_ice1712_restore_gpio_status(ice);
779 return change;
780}
781
782/*
783 * DAC volume attenuation mixer control
784 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100785static int wm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786{
787 int voices = kcontrol->private_value >> 8;
788 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
789 uinfo->count = voices;
790 uinfo->value.integer.min = 0; /* mute (-101dB) */
791 uinfo->value.integer.max = 0x7F; /* 0dB */
792 return 0;
793}
794
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100795static int wm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100797 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 int i, ofs, voices;
799
800 voices = kcontrol->private_value >> 8;
801 ofs = kcontrol->private_value & 0xff;
802 for (i = 0; i < voices; i++)
803 ucontrol->value.integer.value[i] = ice->spec.aureon.vol[ofs+i] & ~WM_VOL_MUTE;
804 return 0;
805}
806
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100807static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100809 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 int i, idx, ofs, voices;
811 int change = 0;
812
813 voices = kcontrol->private_value >> 8;
814 ofs = kcontrol->private_value & 0xff;
815 snd_ice1712_save_gpio_status(ice);
816 for (i = 0; i < voices; i++) {
817 idx = WM_DAC_ATTEN + ofs + i;
818 if (ucontrol->value.integer.value[i] != ice->spec.aureon.vol[ofs+i]) {
819 ice->spec.aureon.vol[ofs+i] &= WM_VOL_MUTE;
820 ice->spec.aureon.vol[ofs+i] |= ucontrol->value.integer.value[i];
821 wm_set_vol(ice, idx, ice->spec.aureon.vol[ofs+i],
822 ice->spec.aureon.master[i]);
823 change = 1;
824 }
825 }
826 snd_ice1712_restore_gpio_status(ice);
827 return change;
828}
829
830/*
831 * WM8770 mute control
832 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100833static int wm_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
835 uinfo->count = kcontrol->private_value >> 8;
836 uinfo->value.integer.min = 0;
837 uinfo->value.integer.max = 1;
838 return 0;
839}
840
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100841static int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100843 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 int voices, ofs, i;
845
846 voices = kcontrol->private_value >> 8;
847 ofs = kcontrol->private_value & 0xFF;
848
849 for (i = 0; i < voices; i++)
850 ucontrol->value.integer.value[i] = (ice->spec.aureon.vol[ofs+i] & WM_VOL_MUTE) ? 0 : 1;
851 return 0;
852}
853
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100854static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100856 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 int change = 0, voices, ofs, i;
858
859 voices = kcontrol->private_value >> 8;
860 ofs = kcontrol->private_value & 0xFF;
861
862 snd_ice1712_save_gpio_status(ice);
863 for (i = 0; i < voices; i++) {
864 int val = (ice->spec.aureon.vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
865 if (ucontrol->value.integer.value[i] != val) {
866 ice->spec.aureon.vol[ofs + i] &= ~WM_VOL_MUTE;
867 ice->spec.aureon.vol[ofs + i] |=
868 ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
869 wm_set_vol(ice, ofs + i, ice->spec.aureon.vol[ofs + i],
870 ice->spec.aureon.master[i]);
871 change = 1;
872 }
873 }
874 snd_ice1712_restore_gpio_status(ice);
875
876 return change;
877}
878
879/*
880 * WM8770 master mute control
881 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100882static int wm_master_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
884 uinfo->count = 2;
885 uinfo->value.integer.min = 0;
886 uinfo->value.integer.max = 1;
887 return 0;
888}
889
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100890static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100892 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893
894 ucontrol->value.integer.value[0] = (ice->spec.aureon.master[0] & WM_VOL_MUTE) ? 0 : 1;
895 ucontrol->value.integer.value[1] = (ice->spec.aureon.master[1] & WM_VOL_MUTE) ? 0 : 1;
896 return 0;
897}
898
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100899static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100901 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 int change = 0, i;
903
904 snd_ice1712_save_gpio_status(ice);
905 for (i = 0; i < 2; i++) {
906 int val = (ice->spec.aureon.master[i] & WM_VOL_MUTE) ? 0 : 1;
907 if (ucontrol->value.integer.value[i] != val) {
908 int dac;
909 ice->spec.aureon.master[i] &= ~WM_VOL_MUTE;
910 ice->spec.aureon.master[i] |=
911 ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
912 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
913 wm_set_vol(ice, WM_DAC_ATTEN + dac + i,
914 ice->spec.aureon.vol[dac + i],
915 ice->spec.aureon.master[i]);
916 change = 1;
917 }
918 }
919 snd_ice1712_restore_gpio_status(ice);
920
921 return change;
922}
923
924/* digital master volume */
925#define PCM_0dB 0xff
926#define PCM_RES 128 /* -64dB */
927#define PCM_MIN (PCM_0dB - PCM_RES)
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100928static int wm_pcm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929{
930 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
931 uinfo->count = 1;
932 uinfo->value.integer.min = 0; /* mute (-64dB) */
933 uinfo->value.integer.max = PCM_RES; /* 0dB */
934 return 0;
935}
936
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100937static int wm_pcm_vol_get(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 val;
941
Ingo Molnar62932df2006-01-16 16:34:20 +0100942 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
944 val = val > PCM_MIN ? (val - PCM_MIN) : 0;
945 ucontrol->value.integer.value[0] = val;
Ingo Molnar62932df2006-01-16 16:34:20 +0100946 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 return 0;
948}
949
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100950static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100952 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 unsigned short ovol, nvol;
954 int change = 0;
955
956 snd_ice1712_save_gpio_status(ice);
957 nvol = ucontrol->value.integer.value[0];
958 nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff;
959 ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
960 if (ovol != nvol) {
961 wm_put(ice, WM_DAC_DIG_MASTER_ATTEN, nvol); /* prelatch */
962 wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100); /* update */
963 change = 1;
964 }
965 snd_ice1712_restore_gpio_status(ice);
966 return change;
967}
968
969/*
970 * ADC mute control
971 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100972static int wm_adc_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973{
974 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
975 uinfo->count = 2;
976 uinfo->value.integer.min = 0;
977 uinfo->value.integer.max = 1;
978 return 0;
979}
980
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100981static int wm_adc_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100983 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 unsigned short val;
985 int i;
986
Ingo Molnar62932df2006-01-16 16:34:20 +0100987 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 for (i = 0; i < 2; i++) {
989 val = wm_get(ice, WM_ADC_GAIN + i);
990 ucontrol->value.integer.value[i] = ~val>>5 & 0x1;
991 }
Ingo Molnar62932df2006-01-16 16:34:20 +0100992 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 return 0;
994}
995
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100996static int wm_adc_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100998 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 unsigned short new, old;
1000 int i, change = 0;
1001
1002 snd_ice1712_save_gpio_status(ice);
1003 for (i = 0; i < 2; i++) {
1004 old = wm_get(ice, WM_ADC_GAIN + i);
1005 new = (~ucontrol->value.integer.value[i]<<5&0x20) | (old&~0x20);
1006 if (new != old) {
1007 wm_put(ice, WM_ADC_GAIN + i, new);
1008 change = 1;
1009 }
1010 }
1011 snd_ice1712_restore_gpio_status(ice);
1012
1013 return change;
1014}
1015
1016/*
1017 * ADC gain mixer control
1018 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001019static int wm_adc_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020{
1021 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1022 uinfo->count = 2;
1023 uinfo->value.integer.min = 0; /* -12dB */
1024 uinfo->value.integer.max = 0x1f; /* 19dB */
1025 return 0;
1026}
1027
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001028static int wm_adc_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001030 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 int i, idx;
1032 unsigned short vol;
1033
Ingo Molnar62932df2006-01-16 16:34:20 +01001034 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 for (i = 0; i < 2; i++) {
1036 idx = WM_ADC_GAIN + i;
1037 vol = wm_get(ice, idx) & 0x1f;
1038 ucontrol->value.integer.value[i] = vol;
1039 }
Ingo Molnar62932df2006-01-16 16:34:20 +01001040 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 return 0;
1042}
1043
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001044static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001046 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 int i, idx;
1048 unsigned short ovol, nvol;
1049 int change = 0;
1050
1051 snd_ice1712_save_gpio_status(ice);
1052 for (i = 0; i < 2; i++) {
1053 idx = WM_ADC_GAIN + i;
1054 nvol = ucontrol->value.integer.value[i];
1055 ovol = wm_get(ice, idx);
1056 if ((ovol & 0x1f) != nvol) {
1057 wm_put(ice, idx, nvol | (ovol & ~0x1f));
1058 change = 1;
1059 }
1060 }
1061 snd_ice1712_restore_gpio_status(ice);
1062 return change;
1063}
1064
1065/*
1066 * ADC input mux mixer control
1067 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001068static int wm_adc_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069{
Takashi Iwai32b47da2007-01-29 15:26:36 +01001070 static const char * const texts[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 "CD", //AIN1
1072 "Aux", //AIN2
1073 "Line", //AIN3
1074 "Mic", //AIN4
1075 "AC97" //AIN5
1076 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01001077 static const char * const universe_texts[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 "Aux1", //AIN1
1079 "CD", //AIN2
1080 "Phono", //AIN3
1081 "Line", //AIN4
1082 "Aux2", //AIN5
1083 "Mic", //AIN6
1084 "Aux3", //AIN7
1085 "AC97" //AIN8
1086 };
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001087 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088
1089 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1090 uinfo->count = 2;
1091 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) {
1092 uinfo->value.enumerated.items = 8;
1093 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1094 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1095 strcpy(uinfo->value.enumerated.name, universe_texts[uinfo->value.enumerated.item]);
1096 }
1097 else {
1098 uinfo->value.enumerated.items = 5;
1099 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1100 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1101 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1102 }
1103 return 0;
1104}
1105
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001106static int wm_adc_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001108 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 unsigned short val;
1110
Ingo Molnar62932df2006-01-16 16:34:20 +01001111 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 val = wm_get(ice, WM_ADC_MUX);
Takashi Iwai66820252006-03-20 18:31:57 +01001113 ucontrol->value.enumerated.item[0] = val & 7;
1114 ucontrol->value.enumerated.item[1] = (val >> 4) & 7;
Ingo Molnar62932df2006-01-16 16:34:20 +01001115 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 return 0;
1117}
1118
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001119static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001121 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 unsigned short oval, nval;
1123 int change;
1124
1125 snd_ice1712_save_gpio_status(ice);
1126 oval = wm_get(ice, WM_ADC_MUX);
1127 nval = oval & ~0x77;
Takashi Iwai66820252006-03-20 18:31:57 +01001128 nval |= ucontrol->value.enumerated.item[0] & 7;
1129 nval |= (ucontrol->value.enumerated.item[1] & 7) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 change = (oval != nval);
1131 if (change)
1132 wm_put(ice, WM_ADC_MUX, nval);
1133 snd_ice1712_restore_gpio_status(ice);
Takashi Iwai63786d02005-11-04 13:58:11 +01001134 return change;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135}
1136
1137/*
1138 * CS8415 Input mux
1139 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001140static int aureon_cs8415_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001142 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai32b47da2007-01-29 15:26:36 +01001143 static const char * const aureon_texts[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 "CD", //RXP0
1145 "Optical" //RXP1
1146 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01001147 static const char * const prodigy_texts[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 "CD",
1149 "Coax"
1150 };
1151 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1152 uinfo->count = 1;
1153 uinfo->value.enumerated.items = 2;
1154 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1155 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1156 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71)
1157 strcpy(uinfo->value.enumerated.name, prodigy_texts[uinfo->value.enumerated.item]);
1158 else
1159 strcpy(uinfo->value.enumerated.name, aureon_texts[uinfo->value.enumerated.item]);
1160 return 0;
1161}
1162
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001163static int aureon_cs8415_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001165 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166
1167 //snd_ice1712_save_gpio_status(ice);
1168 //val = aureon_cs8415_get(ice, CS8415_CTRL2);
Takashi Iwai66820252006-03-20 18:31:57 +01001169 ucontrol->value.enumerated.item[0] = ice->spec.aureon.cs8415_mux;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 //snd_ice1712_restore_gpio_status(ice);
1171 return 0;
1172}
1173
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001174static int aureon_cs8415_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001176 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 unsigned short oval, nval;
1178 int change;
1179
1180 snd_ice1712_save_gpio_status(ice);
1181 oval = aureon_cs8415_get(ice, CS8415_CTRL2);
1182 nval = oval & ~0x07;
Takashi Iwai66820252006-03-20 18:31:57 +01001183 nval |= ucontrol->value.enumerated.item[0] & 7;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 change = (oval != nval);
1185 if (change)
1186 aureon_cs8415_put(ice, CS8415_CTRL2, nval);
1187 snd_ice1712_restore_gpio_status(ice);
Takashi Iwai66820252006-03-20 18:31:57 +01001188 ice->spec.aureon.cs8415_mux = ucontrol->value.enumerated.item[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 return change;
1190}
1191
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001192static int aureon_cs8415_rate_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193{
1194 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1195 uinfo->count = 1;
1196 uinfo->value.integer.min = 0;
1197 uinfo->value.integer.max = 192000;
1198 return 0;
1199}
1200
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001201static int aureon_cs8415_rate_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001203 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 unsigned char ratio;
1205 ratio = aureon_cs8415_get(ice, CS8415_RATIO);
1206 ucontrol->value.integer.value[0] = (int)((unsigned int)ratio * 750);
1207 return 0;
1208}
1209
1210/*
1211 * CS8415A Mute
1212 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001213static int aureon_cs8415_mute_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214{
1215 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1216 uinfo->count = 1;
1217 return 0;
1218}
1219
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001220static int aureon_cs8415_mute_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001222 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 snd_ice1712_save_gpio_status(ice);
1224 ucontrol->value.integer.value[0] = (aureon_cs8415_get(ice, CS8415_CTRL1) & 0x20) ? 0 : 1;
1225 snd_ice1712_restore_gpio_status(ice);
1226 return 0;
1227}
1228
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001229static int aureon_cs8415_mute_put (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001231 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 unsigned char oval, nval;
1233 int change;
1234 snd_ice1712_save_gpio_status(ice);
1235 oval = aureon_cs8415_get(ice, CS8415_CTRL1);
1236 if (ucontrol->value.integer.value[0])
1237 nval = oval & ~0x20;
1238 else
1239 nval = oval | 0x20;
1240 if ((change = (oval != nval)))
1241 aureon_cs8415_put(ice, CS8415_CTRL1, nval);
1242 snd_ice1712_restore_gpio_status(ice);
1243 return change;
1244}
1245
1246/*
1247 * CS8415A Q-Sub info
1248 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001249static int aureon_cs8415_qsub_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
1251 uinfo->count = 10;
1252 return 0;
1253}
1254
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001255static int aureon_cs8415_qsub_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
1256 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257
1258 snd_ice1712_save_gpio_status(ice);
1259 aureon_cs8415_read(ice, CS8415_QSUB, ucontrol->value.bytes.data, 10);
1260 snd_ice1712_restore_gpio_status(ice);
1261
1262 return 0;
1263}
1264
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001265static int aureon_cs8415_spdif_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
1267 uinfo->count = 1;
1268 return 0;
1269}
1270
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001271static int aureon_cs8415_mask_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 memset(ucontrol->value.iec958.status, 0xFF, 24);
1273 return 0;
1274}
1275
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001276static int aureon_cs8415_spdif_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
1277 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278
1279 snd_ice1712_save_gpio_status(ice);
1280 aureon_cs8415_read(ice, CS8415_C_BUFFER, ucontrol->value.iec958.status, 24);
1281 snd_ice1712_restore_gpio_status(ice);
1282 return 0;
1283}
1284
1285/*
1286 * Headphone Amplifier
1287 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001288static int aureon_set_headphone_amp(struct snd_ice1712 *ice, int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289{
1290 unsigned int tmp, tmp2;
1291
1292 tmp2 = tmp = snd_ice1712_gpio_read(ice);
1293 if (enable)
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001294 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1295 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT)
Takashi Iwaic5130272006-05-23 15:46:10 +02001296 tmp |= AUREON_HP_SEL;
1297 else
1298 tmp |= PRODIGY_HP_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 else
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001300 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1301 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT)
Takashi Iwaic5130272006-05-23 15:46:10 +02001302 tmp &= ~ AUREON_HP_SEL;
1303 else
1304 tmp &= ~ PRODIGY_HP_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 if (tmp != tmp2) {
1306 snd_ice1712_gpio_write(ice, tmp);
1307 return 1;
1308 }
1309 return 0;
1310}
1311
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001312static int aureon_get_headphone_amp(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313{
1314 unsigned int tmp = snd_ice1712_gpio_read(ice);
1315
1316 return ( tmp & AUREON_HP_SEL )!= 0;
1317}
1318
1319#define aureon_hpamp_info aureon_mono_bool_info
1320
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001321static int aureon_hpamp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001323 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324
1325 ucontrol->value.integer.value[0] = aureon_get_headphone_amp(ice);
1326 return 0;
1327}
1328
1329
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001330static int aureon_hpamp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001332 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333
1334 return aureon_set_headphone_amp(ice,ucontrol->value.integer.value[0]);
1335}
1336
1337/*
1338 * Deemphasis
1339 */
1340
1341#define aureon_deemp_info aureon_mono_bool_info
1342
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001343static int aureon_deemp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001345 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 0xf;
1347 return 0;
1348}
1349
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001350static int aureon_deemp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001352 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 int temp, temp2;
1354 temp2 = temp = wm_get(ice, WM_DAC_CTRL2);
1355 if (ucontrol->value.integer.value[0])
1356 temp |= 0xf;
1357 else
1358 temp &= ~0xf;
1359 if (temp != temp2) {
1360 wm_put(ice, WM_DAC_CTRL2, temp);
1361 return 1;
1362 }
1363 return 0;
1364}
1365
1366/*
1367 * ADC Oversampling
1368 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001369static int aureon_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370{
Takashi Iwai32b47da2007-01-29 15:26:36 +01001371 static const char * const texts[2] = { "128x", "64x" };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372
1373 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1374 uinfo->count = 1;
1375 uinfo->value.enumerated.items = 2;
1376
1377 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1378 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1379 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1380
1381 return 0;
1382}
1383
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001384static int aureon_oversampling_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001386 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 0x8;
1388 return 0;
1389}
1390
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001391static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392{
1393 int temp, temp2;
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001394 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395
1396 temp2 = temp = wm_get(ice, WM_MASTER);
1397
1398 if (ucontrol->value.enumerated.item[0])
1399 temp |= 0x8;
1400 else
1401 temp &= ~0x8;
1402
1403 if (temp != temp2) {
1404 wm_put(ice, WM_MASTER, temp);
1405 return 1;
1406 }
1407 return 0;
1408}
1409
1410/*
1411 * mixers
1412 */
1413
Takashi Iwai32b47da2007-01-29 15:26:36 +01001414static const struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 {
1416 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1417 .name = "Master Playback Switch",
1418 .info = wm_master_mute_info,
1419 .get = wm_master_mute_get,
1420 .put = wm_master_mute_put
1421 },
1422 {
1423 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001424 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1425 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 .name = "Master Playback Volume",
1427 .info = wm_master_vol_info,
1428 .get = wm_master_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +02001429 .put = wm_master_vol_put,
1430 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 },
1432 {
1433 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1434 .name = "Front Playback Switch",
1435 .info = wm_mute_info,
1436 .get = wm_mute_get,
1437 .put = wm_mute_put,
1438 .private_value = (2 << 8) | 0
1439 },
1440 {
1441 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001442 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1443 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 .name = "Front Playback Volume",
1445 .info = wm_vol_info,
1446 .get = wm_vol_get,
1447 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001448 .private_value = (2 << 8) | 0,
1449 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 },
1451 {
1452 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1453 .name = "Rear Playback Switch",
1454 .info = wm_mute_info,
1455 .get = wm_mute_get,
1456 .put = wm_mute_put,
1457 .private_value = (2 << 8) | 2
1458 },
1459 {
1460 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001461 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1462 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 .name = "Rear Playback Volume",
1464 .info = wm_vol_info,
1465 .get = wm_vol_get,
1466 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001467 .private_value = (2 << 8) | 2,
1468 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 },
1470 {
1471 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1472 .name = "Center Playback Switch",
1473 .info = wm_mute_info,
1474 .get = wm_mute_get,
1475 .put = wm_mute_put,
1476 .private_value = (1 << 8) | 4
1477 },
1478 {
1479 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001480 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1481 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 .name = "Center Playback Volume",
1483 .info = wm_vol_info,
1484 .get = wm_vol_get,
1485 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001486 .private_value = (1 << 8) | 4,
1487 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 },
1489 {
1490 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1491 .name = "LFE Playback Switch",
1492 .info = wm_mute_info,
1493 .get = wm_mute_get,
1494 .put = wm_mute_put,
1495 .private_value = (1 << 8) | 5
1496 },
1497 {
1498 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001499 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1500 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 .name = "LFE Playback Volume",
1502 .info = wm_vol_info,
1503 .get = wm_vol_get,
1504 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001505 .private_value = (1 << 8) | 5,
1506 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 },
1508 {
1509 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1510 .name = "Side Playback Switch",
1511 .info = wm_mute_info,
1512 .get = wm_mute_get,
1513 .put = wm_mute_put,
1514 .private_value = (2 << 8) | 6
1515 },
1516 {
1517 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001518 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1519 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 .name = "Side Playback Volume",
1521 .info = wm_vol_info,
1522 .get = wm_vol_get,
1523 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001524 .private_value = (2 << 8) | 6,
1525 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 }
1527};
1528
Takashi Iwai32b47da2007-01-29 15:26:36 +01001529static const struct snd_kcontrol_new wm_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 {
1531 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1532 .name = "PCM Playback Switch",
1533 .info = wm_pcm_mute_info,
1534 .get = wm_pcm_mute_get,
1535 .put = wm_pcm_mute_put
1536 },
1537 {
1538 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001539 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1540 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 .name = "PCM Playback Volume",
1542 .info = wm_pcm_vol_info,
1543 .get = wm_pcm_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +02001544 .put = wm_pcm_vol_put,
1545 .tlv = { .p = db_scale_wm_pcm }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 },
1547 {
1548 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1549 .name = "Capture Switch",
1550 .info = wm_adc_mute_info,
1551 .get = wm_adc_mute_get,
1552 .put = wm_adc_mute_put,
1553 },
1554 {
1555 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001556 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1557 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 .name = "Capture Volume",
1559 .info = wm_adc_vol_info,
1560 .get = wm_adc_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +02001561 .put = wm_adc_vol_put,
1562 .tlv = { .p = db_scale_wm_adc }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 },
1564 {
1565 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1566 .name = "Capture Source",
1567 .info = wm_adc_mux_info,
1568 .get = wm_adc_mux_get,
1569 .put = wm_adc_mux_put,
1570 .private_value = 5
1571 },
1572 {
1573 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1574 .name = "External Amplifier",
1575 .info = aureon_hpamp_info,
1576 .get = aureon_hpamp_get,
1577 .put = aureon_hpamp_put
1578 },
1579 {
1580 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1581 .name = "DAC Deemphasis Switch",
1582 .info = aureon_deemp_info,
1583 .get = aureon_deemp_get,
1584 .put = aureon_deemp_put
1585 },
1586 {
1587 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1588 .name = "ADC Oversampling",
1589 .info = aureon_oversampling_info,
1590 .get = aureon_oversampling_get,
1591 .put = aureon_oversampling_put
1592 }
1593};
1594
Takashi Iwai32b47da2007-01-29 15:26:36 +01001595static const struct snd_kcontrol_new ac97_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 {
1597 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1598 .name = "AC97 Playback Switch",
1599 .info = aureon_ac97_mmute_info,
1600 .get = aureon_ac97_mmute_get,
1601 .put = aureon_ac97_mmute_put,
1602 .private_value = AC97_MASTER
1603 },
1604 {
1605 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001606 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1607 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 .name = "AC97 Playback Volume",
1609 .info = aureon_ac97_vol_info,
1610 .get = aureon_ac97_vol_get,
1611 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001612 .private_value = AC97_MASTER|AUREON_AC97_STEREO,
1613 .tlv = { .p = db_scale_ac97_master }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 },
1615 {
1616 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1617 .name = "CD Playback Switch",
1618 .info = aureon_ac97_mute_info,
1619 .get = aureon_ac97_mute_get,
1620 .put = aureon_ac97_mute_put,
1621 .private_value = AC97_CD
1622 },
1623 {
1624 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001625 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1626 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 .name = "CD Playback Volume",
1628 .info = aureon_ac97_vol_info,
1629 .get = aureon_ac97_vol_get,
1630 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001631 .private_value = AC97_CD|AUREON_AC97_STEREO,
1632 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 },
1634 {
1635 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1636 .name = "Aux Playback Switch",
1637 .info = aureon_ac97_mute_info,
1638 .get = aureon_ac97_mute_get,
1639 .put = aureon_ac97_mute_put,
1640 .private_value = AC97_AUX,
1641 },
1642 {
1643 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001644 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1645 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 .name = "Aux Playback Volume",
1647 .info = aureon_ac97_vol_info,
1648 .get = aureon_ac97_vol_get,
1649 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001650 .private_value = AC97_AUX|AUREON_AC97_STEREO,
1651 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 },
1653 {
1654 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1655 .name = "Line Playback Switch",
1656 .info = aureon_ac97_mute_info,
1657 .get = aureon_ac97_mute_get,
1658 .put = aureon_ac97_mute_put,
1659 .private_value = AC97_LINE
1660 },
1661 {
1662 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001663 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1664 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 .name = "Line Playback Volume",
1666 .info = aureon_ac97_vol_info,
1667 .get = aureon_ac97_vol_get,
1668 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001669 .private_value = AC97_LINE|AUREON_AC97_STEREO,
1670 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 },
1672 {
1673 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1674 .name = "Mic Playback Switch",
1675 .info = aureon_ac97_mute_info,
1676 .get = aureon_ac97_mute_get,
1677 .put = aureon_ac97_mute_put,
1678 .private_value = AC97_MIC
1679 },
1680 {
1681 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001682 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1683 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 .name = "Mic Playback Volume",
1685 .info = aureon_ac97_vol_info,
1686 .get = aureon_ac97_vol_get,
1687 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001688 .private_value = AC97_MIC,
1689 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 },
1691 {
1692 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1693 .name = "Mic Boost (+20dB)",
1694 .info = aureon_ac97_micboost_info,
1695 .get = aureon_ac97_micboost_get,
1696 .put = aureon_ac97_micboost_put
1697 }
1698};
1699
Takashi Iwai32b47da2007-01-29 15:26:36 +01001700static const struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 {
1702 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1703 .name = "AC97 Playback Switch",
1704 .info = aureon_ac97_mmute_info,
1705 .get = aureon_ac97_mmute_get,
1706 .put = aureon_ac97_mmute_put,
1707 .private_value = AC97_MASTER
1708 },
1709 {
1710 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001711 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1712 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 .name = "AC97 Playback Volume",
1714 .info = aureon_ac97_vol_info,
1715 .get = aureon_ac97_vol_get,
1716 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001717 .private_value = AC97_MASTER|AUREON_AC97_STEREO,
1718 .tlv = { .p = db_scale_ac97_master }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 },
1720 {
1721 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1722 .name = "CD Playback Switch",
1723 .info = aureon_ac97_mute_info,
1724 .get = aureon_ac97_mute_get,
1725 .put = aureon_ac97_mute_put,
1726 .private_value = AC97_AUX
1727 },
1728 {
1729 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001730 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1731 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 .name = "CD Playback Volume",
1733 .info = aureon_ac97_vol_info,
1734 .get = aureon_ac97_vol_get,
1735 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001736 .private_value = AC97_AUX|AUREON_AC97_STEREO,
1737 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 },
1739 {
1740 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1741 .name = "Phono Playback Switch",
1742 .info = aureon_ac97_mute_info,
1743 .get = aureon_ac97_mute_get,
1744 .put = aureon_ac97_mute_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001745 .private_value = AC97_CD
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 },
1747 {
1748 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001749 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1750 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 .name = "Phono Playback Volume",
1752 .info = aureon_ac97_vol_info,
1753 .get = aureon_ac97_vol_get,
1754 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001755 .private_value = AC97_CD|AUREON_AC97_STEREO,
1756 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 },
1758 {
1759 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1760 .name = "Line Playback Switch",
1761 .info = aureon_ac97_mute_info,
1762 .get = aureon_ac97_mute_get,
1763 .put = aureon_ac97_mute_put,
1764 .private_value = AC97_LINE
1765 },
1766 {
1767 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001768 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1769 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 .name = "Line Playback Volume",
1771 .info = aureon_ac97_vol_info,
1772 .get = aureon_ac97_vol_get,
1773 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001774 .private_value = AC97_LINE|AUREON_AC97_STEREO,
1775 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 },
1777 {
1778 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1779 .name = "Mic Playback Switch",
1780 .info = aureon_ac97_mute_info,
1781 .get = aureon_ac97_mute_get,
1782 .put = aureon_ac97_mute_put,
1783 .private_value = AC97_MIC
1784 },
1785 {
1786 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001787 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1788 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 .name = "Mic Playback Volume",
1790 .info = aureon_ac97_vol_info,
1791 .get = aureon_ac97_vol_get,
1792 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001793 .private_value = AC97_MIC,
1794 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 },
1796 {
1797 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1798 .name = "Mic Boost (+20dB)",
1799 .info = aureon_ac97_micboost_info,
1800 .get = aureon_ac97_micboost_get,
1801 .put = aureon_ac97_micboost_put
1802 },
1803 {
1804 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1805 .name = "Aux Playback Switch",
1806 .info = aureon_ac97_mute_info,
1807 .get = aureon_ac97_mute_get,
1808 .put = aureon_ac97_mute_put,
1809 .private_value = AC97_VIDEO,
1810 },
1811 {
1812 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001813 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1814 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 .name = "Aux Playback Volume",
1816 .info = aureon_ac97_vol_info,
1817 .get = aureon_ac97_vol_get,
1818 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001819 .private_value = AC97_VIDEO|AUREON_AC97_STEREO,
1820 .tlv = { .p = db_scale_ac97_gain }
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +02001821 },
1822 {
1823 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1824 .name = "Aux Source",
1825 .info = aureon_universe_inmux_info,
1826 .get = aureon_universe_inmux_get,
1827 .put = aureon_universe_inmux_put
1828 }
1829
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830};
1831
Takashi Iwai32b47da2007-01-29 15:26:36 +01001832static const struct snd_kcontrol_new cs8415_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 {
1834 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1835 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH),
1836 .info = aureon_cs8415_mute_info,
1837 .get = aureon_cs8415_mute_get,
1838 .put = aureon_cs8415_mute_put
1839 },
1840 {
1841 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1842 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Source",
1843 .info = aureon_cs8415_mux_info,
1844 .get = aureon_cs8415_mux_get,
1845 .put = aureon_cs8415_mux_put,
1846 },
1847 {
1848 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1849 .name = SNDRV_CTL_NAME_IEC958("Q-subcode ",CAPTURE,DEFAULT),
1850 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1851 .info = aureon_cs8415_qsub_info,
1852 .get = aureon_cs8415_qsub_get,
1853 },
1854 {
1855 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1856 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,MASK),
1857 .access = SNDRV_CTL_ELEM_ACCESS_READ,
1858 .info = aureon_cs8415_spdif_info,
1859 .get = aureon_cs8415_mask_get
1860 },
1861 {
1862 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1863 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT),
1864 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1865 .info = aureon_cs8415_spdif_info,
1866 .get = aureon_cs8415_spdif_get
1867 },
1868 {
1869 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1870 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Rate",
1871 .access =SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1872 .info = aureon_cs8415_rate_info,
1873 .get = aureon_cs8415_rate_get
1874 }
1875};
1876
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001877static int __devinit aureon_add_controls(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878{
1879 unsigned int i, counts;
1880 int err;
1881
1882 counts = ARRAY_SIZE(aureon_dac_controls);
1883 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY)
1884 counts -= 2; /* no side */
1885 for (i = 0; i < counts; i++) {
1886 err = snd_ctl_add(ice->card, snd_ctl_new1(&aureon_dac_controls[i], ice));
1887 if (err < 0)
1888 return err;
1889 }
1890
1891 for (i = 0; i < ARRAY_SIZE(wm_controls); i++) {
1892 err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice));
1893 if (err < 0)
1894 return err;
1895 }
1896
1897 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) {
1898 for (i = 0; i < ARRAY_SIZE(universe_ac97_controls); i++) {
1899 err = snd_ctl_add(ice->card, snd_ctl_new1(&universe_ac97_controls[i], ice));
1900 if (err < 0)
1901 return err;
1902 }
1903 }
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001904 else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1905 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 for (i = 0; i < ARRAY_SIZE(ac97_controls); i++) {
1907 err = snd_ctl_add(ice->card, snd_ctl_new1(&ac97_controls[i], ice));
1908 if (err < 0)
1909 return err;
1910 }
1911 }
1912
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001913 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1914 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 unsigned char id;
1916 snd_ice1712_save_gpio_status(ice);
1917 id = aureon_cs8415_get(ice, CS8415_ID);
1918 if (id != 0x41)
Takashi Iwai99b359b2005-10-20 18:26:44 +02001919 snd_printk(KERN_INFO "No CS8415 chip. Skipping CS8415 controls.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 else if ((id & 0x0F) != 0x01)
Takashi Iwai99b359b2005-10-20 18:26:44 +02001921 snd_printk(KERN_INFO "Detected unsupported CS8415 rev. (%c)\n", (char)((id & 0x0F) + 'A' - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 else {
1923 for (i = 0; i< ARRAY_SIZE(cs8415_controls); i++) {
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001924 struct snd_kcontrol *kctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 err = snd_ctl_add(ice->card, (kctl = snd_ctl_new1(&cs8415_controls[i], ice)));
1926 if (err < 0)
1927 return err;
1928 if (i > 1)
1929 kctl->id.device = ice->pcm->device;
1930 }
1931 }
1932 snd_ice1712_restore_gpio_status(ice);
1933 }
1934
1935 return 0;
1936}
1937
1938
1939/*
1940 * initialize the chip
1941 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001942static int __devinit aureon_init(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943{
Takashi Iwai32b47da2007-01-29 15:26:36 +01001944 static const unsigned short wm_inits_aureon[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 /* These come first to reduce init pop noise */
1946 0x1b, 0x044, /* ADC Mux (AC'97 source) */
1947 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
1948 0x1d, 0x009, /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */
1949
1950 0x18, 0x000, /* All power-up */
1951
1952 0x16, 0x122, /* I2S, normal polarity, 24bit */
1953 0x17, 0x022, /* 256fs, slave mode */
1954 0x00, 0, /* DAC1 analog mute */
1955 0x01, 0, /* DAC2 analog mute */
1956 0x02, 0, /* DAC3 analog mute */
1957 0x03, 0, /* DAC4 analog mute */
1958 0x04, 0, /* DAC5 analog mute */
1959 0x05, 0, /* DAC6 analog mute */
1960 0x06, 0, /* DAC7 analog mute */
1961 0x07, 0, /* DAC8 analog mute */
1962 0x08, 0x100, /* master analog mute */
1963 0x09, 0xff, /* DAC1 digital full */
1964 0x0a, 0xff, /* DAC2 digital full */
1965 0x0b, 0xff, /* DAC3 digital full */
1966 0x0c, 0xff, /* DAC4 digital full */
1967 0x0d, 0xff, /* DAC5 digital full */
1968 0x0e, 0xff, /* DAC6 digital full */
1969 0x0f, 0xff, /* DAC7 digital full */
1970 0x10, 0xff, /* DAC8 digital full */
1971 0x11, 0x1ff, /* master digital full */
1972 0x12, 0x000, /* phase normal */
1973 0x13, 0x090, /* unmute DAC L/R */
1974 0x14, 0x000, /* all unmute */
1975 0x15, 0x000, /* no deemphasis, no ZFLG */
1976 0x19, 0x000, /* -12dB ADC/L */
1977 0x1a, 0x000, /* -12dB ADC/R */
1978 (unsigned short)-1
1979 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01001980 static const unsigned short wm_inits_prodigy[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981
1982 /* These come first to reduce init pop noise */
1983 0x1b, 0x000, /* ADC Mux */
1984 0x1c, 0x009, /* Out Mux1 */
1985 0x1d, 0x009, /* Out Mux2 */
1986
1987 0x18, 0x000, /* All power-up */
1988
1989 0x16, 0x022, /* I2S, normal polarity, 24bit, high-pass on */
1990 0x17, 0x006, /* 128fs, slave mode */
1991
1992 0x00, 0, /* DAC1 analog mute */
1993 0x01, 0, /* DAC2 analog mute */
1994 0x02, 0, /* DAC3 analog mute */
1995 0x03, 0, /* DAC4 analog mute */
1996 0x04, 0, /* DAC5 analog mute */
1997 0x05, 0, /* DAC6 analog mute */
1998 0x06, 0, /* DAC7 analog mute */
1999 0x07, 0, /* DAC8 analog mute */
2000 0x08, 0x100, /* master analog mute */
2001
2002 0x09, 0x7f, /* DAC1 digital full */
2003 0x0a, 0x7f, /* DAC2 digital full */
2004 0x0b, 0x7f, /* DAC3 digital full */
2005 0x0c, 0x7f, /* DAC4 digital full */
2006 0x0d, 0x7f, /* DAC5 digital full */
2007 0x0e, 0x7f, /* DAC6 digital full */
2008 0x0f, 0x7f, /* DAC7 digital full */
2009 0x10, 0x7f, /* DAC8 digital full */
2010 0x11, 0x1FF, /* master digital full */
2011
2012 0x12, 0x000, /* phase normal */
2013 0x13, 0x090, /* unmute DAC L/R */
2014 0x14, 0x000, /* all unmute */
2015 0x15, 0x000, /* no deemphasis, no ZFLG */
2016
2017 0x19, 0x000, /* -12dB ADC/L */
2018 0x1a, 0x000, /* -12dB ADC/R */
2019 (unsigned short)-1
2020
2021 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01002022 static const unsigned short cs_inits[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 0x0441, /* RUN */
2024 0x0180, /* no mute, OMCK output on RMCK pin */
2025 0x0201, /* S/PDIF source on RXP1 */
2026 0x0605, /* slave, 24bit, MSB on second OSCLK, SDOUT for right channel when OLRCK is high */
2027 (unsigned short)-1
2028 };
2029 unsigned int tmp;
Takashi Iwai32b47da2007-01-29 15:26:36 +01002030 const unsigned short *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 int err, i;
2032
2033 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) {
2034 ice->num_total_dacs = 6;
2035 ice->num_total_adcs = 2;
2036 } else {
2037 /* aureon 7.1 and prodigy 7.1 */
2038 ice->num_total_dacs = 8;
2039 ice->num_total_adcs = 2;
2040 }
2041
2042 /* to remeber the register values of CS8415 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01002043 ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 if (! ice->akm)
2045 return -ENOMEM;
2046 ice->akm_codecs = 1;
2047
2048 if ((err = aureon_ac97_init(ice)) != 0)
2049 return err;
2050
2051 snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for the time being */
2052
2053 /* reset the wm codec as the SPI mode */
2054 snd_ice1712_save_gpio_status(ice);
2055 snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RESET|AUREON_WM_CS|AUREON_CS8415_CS|AUREON_HP_SEL));
2056
2057 tmp = snd_ice1712_gpio_read(ice);
2058 tmp &= ~AUREON_WM_RESET;
2059 snd_ice1712_gpio_write(ice, tmp);
2060 udelay(1);
2061 tmp |= AUREON_WM_CS | AUREON_CS8415_CS;
2062 snd_ice1712_gpio_write(ice, tmp);
2063 udelay(1);
2064 tmp |= AUREON_WM_RESET;
2065 snd_ice1712_gpio_write(ice, tmp);
2066 udelay(1);
2067
2068 /* initialize WM8770 codec */
Takashi Iwai45fe7222006-01-13 13:50:16 +01002069 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71 ||
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01002070 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
2071 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 p = wm_inits_prodigy;
2073 else
2074 p = wm_inits_aureon;
2075 for (; *p != (unsigned short)-1; p += 2)
2076 wm_put(ice, p[0], p[1]);
2077
2078 /* initialize CS8415A codec */
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01002079 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
2080 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
Takashi Iwai45fe7222006-01-13 13:50:16 +01002081 for (p = cs_inits; *p != (unsigned short)-1; p++)
2082 aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24);
2083 ice->spec.aureon.cs8415_mux = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084
Takashi Iwai45fe7222006-01-13 13:50:16 +01002085 aureon_set_headphone_amp(ice, 1);
2086 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087
2088 snd_ice1712_restore_gpio_status(ice);
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +02002089
2090 /* initialize PCA9554 pin directions & set default input*/
2091 aureon_pca9554_write(ice, PCA9554_DIR, 0x00);
2092 aureon_pca9554_write(ice, PCA9554_OUT, 0x00); /* internal AUX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093
2094 ice->spec.aureon.master[0] = WM_VOL_MUTE;
2095 ice->spec.aureon.master[1] = WM_VOL_MUTE;
2096 for (i = 0; i < ice->num_total_dacs; i++) {
2097 ice->spec.aureon.vol[i] = WM_VOL_MUTE;
2098 wm_set_vol(ice, i, ice->spec.aureon.vol[i], ice->spec.aureon.master[i % 2]);
2099 }
2100
2101 return 0;
2102}
2103
2104
2105/*
2106 * Aureon boards don't provide the EEPROM data except for the vendor IDs.
2107 * hence the driver needs to sets up it properly.
2108 */
2109
Takashi Iwai32b47da2007-01-29 15:26:36 +01002110static const unsigned char aureon51_eeprom[] __devinitdata = {
Takashi Iwai189bc172007-01-29 15:25:40 +01002111 [ICE_EEP2_SYSCONF] = 0x0a, /* clock 512, spdif-in/ADC, 3DACs */
2112 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
2113 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
2114 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
2115 [ICE_EEP2_GPIO_DIR] = 0xff,
2116 [ICE_EEP2_GPIO_DIR1] = 0xff,
2117 [ICE_EEP2_GPIO_DIR2] = 0x5f,
2118 [ICE_EEP2_GPIO_MASK] = 0x00,
2119 [ICE_EEP2_GPIO_MASK1] = 0x00,
2120 [ICE_EEP2_GPIO_MASK2] = 0x00,
2121 [ICE_EEP2_GPIO_STATE] = 0x00,
2122 [ICE_EEP2_GPIO_STATE1] = 0x00,
2123 [ICE_EEP2_GPIO_STATE2] = 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124};
2125
Takashi Iwai32b47da2007-01-29 15:26:36 +01002126static const unsigned char aureon71_eeprom[] __devinitdata = {
Takashi Iwai189bc172007-01-29 15:25:40 +01002127 [ICE_EEP2_SYSCONF] = 0x0b, /* clock 512, spdif-in/ADC, 4DACs */
2128 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
2129 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
2130 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
2131 [ICE_EEP2_GPIO_DIR] = 0xff,
2132 [ICE_EEP2_GPIO_DIR1] = 0xff,
2133 [ICE_EEP2_GPIO_DIR2] = 0x5f,
2134 [ICE_EEP2_GPIO_MASK] = 0x00,
2135 [ICE_EEP2_GPIO_MASK1] = 0x00,
2136 [ICE_EEP2_GPIO_MASK2] = 0x00,
2137 [ICE_EEP2_GPIO_STATE] = 0x00,
2138 [ICE_EEP2_GPIO_STATE1] = 0x00,
2139 [ICE_EEP2_GPIO_STATE2] = 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140};
Takashi Iwai189bc172007-01-29 15:25:40 +01002141#define prodigy71_eeprom aureon71_eeprom
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142
Takashi Iwai32b47da2007-01-29 15:26:36 +01002143static const unsigned char prodigy71lt_eeprom[] __devinitdata = {
Takashi Iwai189bc172007-01-29 15:25:40 +01002144 [ICE_EEP2_SYSCONF] = 0x4b, /* clock 384, spdif-in/ADC, 4DACs */
2145 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
2146 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
2147 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
2148 [ICE_EEP2_GPIO_DIR] = 0xff,
2149 [ICE_EEP2_GPIO_DIR1] = 0xff,
2150 [ICE_EEP2_GPIO_DIR2] = 0x5f,
2151 [ICE_EEP2_GPIO_MASK] = 0x00,
2152 [ICE_EEP2_GPIO_MASK1] = 0x00,
2153 [ICE_EEP2_GPIO_MASK2] = 0x00,
2154 [ICE_EEP2_GPIO_STATE] = 0x00,
2155 [ICE_EEP2_GPIO_STATE1] = 0x00,
2156 [ICE_EEP2_GPIO_STATE2] = 0x00,
Takashi Iwai45fe7222006-01-13 13:50:16 +01002157};
Takashi Iwai189bc172007-01-29 15:25:40 +01002158#define prodigy71xt_eeprom prodigy71lt_eeprom
Takashi Iwai45fe7222006-01-13 13:50:16 +01002159
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160/* entry point */
Takashi Iwai32b47da2007-01-29 15:26:36 +01002161const struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 {
2163 .subvendor = VT1724_SUBDEVICE_AUREON51_SKY,
2164 .name = "Terratec Aureon 5.1-Sky",
2165 .model = "aureon51",
2166 .chip_init = aureon_init,
2167 .build_controls = aureon_add_controls,
2168 .eeprom_size = sizeof(aureon51_eeprom),
2169 .eeprom_data = aureon51_eeprom,
2170 .driver = "Aureon51",
2171 },
2172 {
2173 .subvendor = VT1724_SUBDEVICE_AUREON71_SPACE,
2174 .name = "Terratec Aureon 7.1-Space",
2175 .model = "aureon71",
2176 .chip_init = aureon_init,
2177 .build_controls = aureon_add_controls,
2178 .eeprom_size = sizeof(aureon71_eeprom),
2179 .eeprom_data = aureon71_eeprom,
2180 .driver = "Aureon71",
2181 },
2182 {
2183 .subvendor = VT1724_SUBDEVICE_AUREON71_UNIVERSE,
2184 .name = "Terratec Aureon 7.1-Universe",
2185 .model = "universe",
2186 .chip_init = aureon_init,
2187 .build_controls = aureon_add_controls,
2188 .eeprom_size = sizeof(aureon71_eeprom),
2189 .eeprom_data = aureon71_eeprom,
Takashi Iwai9f37c5b2006-06-29 16:40:21 +02002190 .driver = "Aureon71Univ", /* keep in 15 letters */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191 },
2192 {
2193 .subvendor = VT1724_SUBDEVICE_PRODIGY71,
2194 .name = "Audiotrak Prodigy 7.1",
2195 .model = "prodigy71",
2196 .chip_init = aureon_init,
2197 .build_controls = aureon_add_controls,
2198 .eeprom_size = sizeof(prodigy71_eeprom),
2199 .eeprom_data = prodigy71_eeprom,
2200 .driver = "Prodigy71", /* should be identical with Aureon71 */
2201 },
Takashi Iwai45fe7222006-01-13 13:50:16 +01002202 {
2203 .subvendor = VT1724_SUBDEVICE_PRODIGY71LT,
2204 .name = "Audiotrak Prodigy 7.1 LT",
2205 .model = "prodigy71lt",
2206 .chip_init = aureon_init,
2207 .build_controls = aureon_add_controls,
2208 .eeprom_size = sizeof(prodigy71lt_eeprom),
2209 .eeprom_data = prodigy71lt_eeprom,
2210 .driver = "Prodigy71LT",
2211 },
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01002212 {
2213 .subvendor = VT1724_SUBDEVICE_PRODIGY71XT,
2214 .name = "Audiotrak Prodigy 7.1 XT",
2215 .model = "prodigy71xt",
2216 .chip_init = aureon_init,
2217 .build_controls = aureon_add_controls,
2218 .eeprom_size = sizeof(prodigy71xt_eeprom),
2219 .eeprom_data = prodigy71xt_eeprom,
2220 .driver = "Prodigy71LT",
2221 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 { } /* terminator */
2223};