blob: f83ec2f565cf3714d91fc9d5cb6c8439cd4d779e [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);
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100208 ucontrol->value.enumerated.item[0] = ice->spec.aureon.pca9554_out;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200209 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
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100219 nval = ucontrol->value.enumerated.item[0];
220 if (nval >= 3)
221 return -EINVAL;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200222 snd_ice1712_save_gpio_status(ice);
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200223 oval = ice->spec.aureon.pca9554_out;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200224 if ((change = (oval != nval))) {
225 aureon_pca9554_write(ice, PCA9554_OUT, nval);
226 ice->spec.aureon.pca9554_out = nval;
227 }
228 snd_ice1712_restore_gpio_status(ice);
229
230 return change;
231}
232
233
234static void aureon_ac97_write(struct snd_ice1712 *ice, unsigned short reg,
235 unsigned short val)
236{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 unsigned int tmp;
238
239 /* Send address to XILINX chip */
240 tmp = (snd_ice1712_gpio_read(ice) & ~0xFF) | (reg & 0x7F);
241 snd_ice1712_gpio_write(ice, tmp);
242 udelay(10);
243 tmp |= AUREON_AC97_ADDR;
244 snd_ice1712_gpio_write(ice, tmp);
245 udelay(10);
246 tmp &= ~AUREON_AC97_ADDR;
247 snd_ice1712_gpio_write(ice, tmp);
248 udelay(10);
249
250 /* Send low-order byte to XILINX chip */
251 tmp &= ~AUREON_AC97_DATA_MASK;
252 tmp |= val & AUREON_AC97_DATA_MASK;
253 snd_ice1712_gpio_write(ice, tmp);
254 udelay(10);
255 tmp |= AUREON_AC97_DATA_LOW;
256 snd_ice1712_gpio_write(ice, tmp);
257 udelay(10);
258 tmp &= ~AUREON_AC97_DATA_LOW;
259 snd_ice1712_gpio_write(ice, tmp);
260 udelay(10);
261
262 /* Send high-order byte to XILINX chip */
263 tmp &= ~AUREON_AC97_DATA_MASK;
264 tmp |= (val >> 8) & AUREON_AC97_DATA_MASK;
265
266 snd_ice1712_gpio_write(ice, tmp);
267 udelay(10);
268 tmp |= AUREON_AC97_DATA_HIGH;
269 snd_ice1712_gpio_write(ice, tmp);
270 udelay(10);
271 tmp &= ~AUREON_AC97_DATA_HIGH;
272 snd_ice1712_gpio_write(ice, tmp);
273 udelay(10);
274
275 /* Instruct XILINX chip to parse the data to the STAC9744 chip */
276 tmp |= AUREON_AC97_COMMIT;
277 snd_ice1712_gpio_write(ice, tmp);
278 udelay(10);
279 tmp &= ~AUREON_AC97_COMMIT;
280 snd_ice1712_gpio_write(ice, tmp);
281 udelay(10);
282
283 /* Store the data in out private buffer */
284 ice->spec.aureon.stac9744[(reg & 0x7F) >> 1] = val;
285}
286
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100287static unsigned short aureon_ac97_read(struct snd_ice1712 *ice, unsigned short reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288{
289 return ice->spec.aureon.stac9744[(reg & 0x7F) >> 1];
290}
291
292/*
293 * Initialize STAC9744 chip
294 */
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200295static int aureon_ac97_init (struct snd_ice1712 *ice)
296{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 int i;
Takashi Iwai32b47da2007-01-29 15:26:36 +0100298 static const unsigned short ac97_defaults[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 0x00, 0x9640,
300 0x02, 0x8000,
301 0x04, 0x8000,
302 0x06, 0x8000,
303 0x0C, 0x8008,
304 0x0E, 0x8008,
305 0x10, 0x8808,
306 0x12, 0x8808,
307 0x14, 0x8808,
308 0x16, 0x8808,
309 0x18, 0x8808,
310 0x1C, 0x8000,
311 0x26, 0x000F,
312 0x28, 0x0201,
313 0x2C, 0xBB80,
314 0x32, 0xBB80,
315 0x7C, 0x8384,
316 0x7E, 0x7644,
317 (unsigned short)-1
318 };
319 unsigned int tmp;
320
321 /* Cold reset */
322 tmp = (snd_ice1712_gpio_read(ice) | AUREON_AC97_RESET) & ~AUREON_AC97_DATA_MASK;
323 snd_ice1712_gpio_write(ice, tmp);
324 udelay(3);
325
326 tmp &= ~AUREON_AC97_RESET;
327 snd_ice1712_gpio_write(ice, tmp);
328 udelay(3);
329
330 tmp |= AUREON_AC97_RESET;
331 snd_ice1712_gpio_write(ice, tmp);
332 udelay(3);
333
334 memset(&ice->spec.aureon.stac9744, 0, sizeof(ice->spec.aureon.stac9744));
335 for (i=0; ac97_defaults[i] != (unsigned short)-1; i+=2)
336 ice->spec.aureon.stac9744[(ac97_defaults[i]) >> 1] = ac97_defaults[i+1];
337
338 aureon_ac97_write(ice, AC97_MASTER, 0x0000); // Unmute AC'97 master volume permanently - muting is done by WM8770
339
340 return 0;
341}
342
343#define AUREON_AC97_STEREO 0x80
344
345/*
346 * AC'97 volume controls
347 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100348static int aureon_ac97_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349{
350 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
351 uinfo->count = kcontrol->private_value & AUREON_AC97_STEREO ? 2 : 1;
352 uinfo->value.integer.min = 0;
353 uinfo->value.integer.max = 31;
354 return 0;
355}
356
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100357static int aureon_ac97_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100359 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 unsigned short vol;
361
Ingo Molnar62932df2006-01-16 16:34:20 +0100362 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363
364 vol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
365 ucontrol->value.integer.value[0] = 0x1F - (vol & 0x1F);
366 if (kcontrol->private_value & AUREON_AC97_STEREO)
367 ucontrol->value.integer.value[1] = 0x1F - ((vol >> 8) & 0x1F);
368
Ingo Molnar62932df2006-01-16 16:34:20 +0100369 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 return 0;
371}
372
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100373static int aureon_ac97_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100375 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 unsigned short ovol, nvol;
377 int change;
378
379 snd_ice1712_save_gpio_status(ice);
380
381 ovol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
382 nvol = (0x1F - ucontrol->value.integer.value[0]) & 0x001F;
383 if (kcontrol->private_value & AUREON_AC97_STEREO)
384 nvol |= ((0x1F - ucontrol->value.integer.value[1]) << 8) & 0x1F00;
385 nvol |= ovol & ~0x1F1F;
386
387 if ((change = (ovol != nvol)))
388 aureon_ac97_write(ice, kcontrol->private_value & 0x7F, nvol);
389
390 snd_ice1712_restore_gpio_status(ice);
391
392 return change;
393}
394
395/*
396 * AC'97 mute controls
397 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200398#define aureon_ac97_mute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100400static int aureon_ac97_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100402 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
Ingo Molnar62932df2006-01-16 16:34:20 +0100404 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
406 ucontrol->value.integer.value[0] = aureon_ac97_read(ice, kcontrol->private_value & 0x7F) & 0x8000 ? 0 : 1;
407
Ingo Molnar62932df2006-01-16 16:34:20 +0100408 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 return 0;
410}
411
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100412static int aureon_ac97_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100414 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 unsigned short ovol, nvol;
416 int change;
417
418 snd_ice1712_save_gpio_status(ice);
419
420 ovol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
421 nvol = (ucontrol->value.integer.value[0] ? 0x0000 : 0x8000) | (ovol & ~ 0x8000);
422
423 if ((change = (ovol != nvol)))
424 aureon_ac97_write(ice, kcontrol->private_value & 0x7F, nvol);
425
426 snd_ice1712_restore_gpio_status(ice);
427
428 return change;
429}
430
431/*
432 * AC'97 mute controls
433 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200434#define aureon_ac97_micboost_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100436static int aureon_ac97_micboost_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100438 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439
Ingo Molnar62932df2006-01-16 16:34:20 +0100440 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441
442 ucontrol->value.integer.value[0] = aureon_ac97_read(ice, AC97_MIC) & 0x0020 ? 0 : 1;
443
Ingo Molnar62932df2006-01-16 16:34:20 +0100444 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 return 0;
446}
447
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100448static int aureon_ac97_micboost_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100450 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 unsigned short ovol, nvol;
452 int change;
453
454 snd_ice1712_save_gpio_status(ice);
455
456 ovol = aureon_ac97_read(ice, AC97_MIC);
457 nvol = (ucontrol->value.integer.value[0] ? 0x0000 : 0x0020) | (ovol & ~0x0020);
458
459 if ((change = (ovol != nvol)))
460 aureon_ac97_write(ice, AC97_MIC, nvol);
461
462 snd_ice1712_restore_gpio_status(ice);
463
464 return change;
465}
466
467/*
468 * write data in the SPI mode
469 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100470static void aureon_spi_write(struct snd_ice1712 *ice, unsigned int cs, unsigned int data, int bits)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471{
472 unsigned int tmp;
473 int i;
Takashi Iwai45fe7222006-01-13 13:50:16 +0100474 unsigned int mosi, clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475
476 tmp = snd_ice1712_gpio_read(ice);
477
Toshimune Konnocdf88ef2006-12-18 13:12:18 +0100478 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
479 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) {
Takashi Iwai45fe7222006-01-13 13:50:16 +0100480 snd_ice1712_gpio_set_mask(ice, ~(PRODIGY_SPI_MOSI|PRODIGY_SPI_CLK|PRODIGY_WM_CS));
481 mosi = PRODIGY_SPI_MOSI;
482 clk = PRODIGY_SPI_CLK;
483 }
484 else {
485 snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RW|AUREON_SPI_MOSI|AUREON_SPI_CLK|
486 AUREON_WM_CS|AUREON_CS8415_CS));
487 mosi = AUREON_SPI_MOSI;
488 clk = AUREON_SPI_CLK;
489
490 tmp |= AUREON_WM_RW;
491 }
492
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 tmp &= ~cs;
494 snd_ice1712_gpio_write(ice, tmp);
495 udelay(1);
496
497 for (i = bits - 1; i >= 0; i--) {
Takashi Iwai45fe7222006-01-13 13:50:16 +0100498 tmp &= ~clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 snd_ice1712_gpio_write(ice, tmp);
500 udelay(1);
501 if (data & (1 << i))
Takashi Iwai45fe7222006-01-13 13:50:16 +0100502 tmp |= mosi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 else
Takashi Iwai45fe7222006-01-13 13:50:16 +0100504 tmp &= ~mosi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 snd_ice1712_gpio_write(ice, tmp);
506 udelay(1);
Takashi Iwai45fe7222006-01-13 13:50:16 +0100507 tmp |= clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 snd_ice1712_gpio_write(ice, tmp);
509 udelay(1);
510 }
511
Takashi Iwai45fe7222006-01-13 13:50:16 +0100512 tmp &= ~clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 tmp |= cs;
514 snd_ice1712_gpio_write(ice, tmp);
515 udelay(1);
Takashi Iwai45fe7222006-01-13 13:50:16 +0100516 tmp |= clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 snd_ice1712_gpio_write(ice, tmp);
518 udelay(1);
519}
520
521/*
522 * Read data in SPI mode
523 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100524static 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 -0700525 int i, j;
526 unsigned int tmp;
527
528 tmp = (snd_ice1712_gpio_read(ice) & ~AUREON_SPI_CLK) | AUREON_CS8415_CS|AUREON_WM_CS;
529 snd_ice1712_gpio_write(ice, tmp);
530 tmp &= ~cs;
531 snd_ice1712_gpio_write(ice, tmp);
532 udelay(1);
533
534 for (i=bits-1; i>=0; i--) {
535 if (data & (1 << i))
536 tmp |= AUREON_SPI_MOSI;
537 else
538 tmp &= ~AUREON_SPI_MOSI;
539 snd_ice1712_gpio_write(ice, tmp);
540 udelay(1);
541
542 tmp |= AUREON_SPI_CLK;
543 snd_ice1712_gpio_write(ice, tmp);
544 udelay(1);
545
546 tmp &= ~AUREON_SPI_CLK;
547 snd_ice1712_gpio_write(ice, tmp);
548 udelay(1);
549 }
550
551 for (j=0; j<size; j++) {
552 unsigned char outdata = 0;
553 for (i=7; i>=0; i--) {
554 tmp = snd_ice1712_gpio_read(ice);
555 outdata <<= 1;
556 outdata |= (tmp & AUREON_SPI_MISO) ? 1 : 0;
557 udelay(1);
558
559 tmp |= AUREON_SPI_CLK;
560 snd_ice1712_gpio_write(ice, tmp);
561 udelay(1);
562
563 tmp &= ~AUREON_SPI_CLK;
564 snd_ice1712_gpio_write(ice, tmp);
565 udelay(1);
566 }
567 buffer[j] = outdata;
568 }
569
570 tmp |= cs;
571 snd_ice1712_gpio_write(ice, tmp);
572}
573
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100574static unsigned char aureon_cs8415_get(struct snd_ice1712 *ice, int reg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 unsigned char val;
576 aureon_spi_write(ice, AUREON_CS8415_CS, 0x2000 | reg, 16);
577 aureon_spi_read(ice, AUREON_CS8415_CS, 0x21, 8, &val, 1);
578 return val;
579}
580
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100581static void aureon_cs8415_read(struct snd_ice1712 *ice, int reg, unsigned char *buffer, int size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 aureon_spi_write(ice, AUREON_CS8415_CS, 0x2000 | reg, 16);
583 aureon_spi_read(ice, AUREON_CS8415_CS, 0x21, 8, buffer, size);
584}
585
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100586static void aureon_cs8415_put(struct snd_ice1712 *ice, int reg, unsigned char val) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 aureon_spi_write(ice, AUREON_CS8415_CS, 0x200000 | (reg << 8) | val, 24);
588}
589
590/*
591 * get the current register value of WM codec
592 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100593static unsigned short wm_get(struct snd_ice1712 *ice, int reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594{
595 reg <<= 1;
596 return ((unsigned short)ice->akm[0].images[reg] << 8) |
597 ice->akm[0].images[reg + 1];
598}
599
600/*
601 * set the register value of WM codec
602 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100603static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604{
Takashi Iwai45fe7222006-01-13 13:50:16 +0100605 aureon_spi_write(ice,
Toshimune Konnocdf88ef2006-12-18 13:12:18 +0100606 ((ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
607 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) ?
608 PRODIGY_WM_CS : AUREON_WM_CS),
Takashi Iwai45fe7222006-01-13 13:50:16 +0100609 (reg << 9) | (val & 0x1ff), 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610}
611
612/*
613 * set the register value of WM codec and remember it
614 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100615static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616{
617 wm_put_nocache(ice, reg, val);
618 reg <<= 1;
619 ice->akm[0].images[reg] = val >> 8;
620 ice->akm[0].images[reg + 1] = val;
621}
622
623/*
624 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200625#define aureon_mono_bool_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626
627/*
628 * AC'97 master playback mute controls (Mute on WM8770 chip)
629 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200630#define aureon_ac97_mmute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100632static int aureon_ac97_mmute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100634 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
Ingo Molnar62932df2006-01-16 16:34:20 +0100636 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
638 ucontrol->value.integer.value[0] = (wm_get(ice, WM_OUT_MUX1) >> 1) & 0x01;
639
Ingo Molnar62932df2006-01-16 16:34:20 +0100640 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 return 0;
642}
643
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100644static int aureon_ac97_mmute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
645 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 unsigned short ovol, nvol;
647 int change;
648
649 snd_ice1712_save_gpio_status(ice);
650
651 ovol = wm_get(ice, WM_OUT_MUX1);
652 nvol = (ovol & ~0x02) | (ucontrol->value.integer.value[0] ? 0x02 : 0x00);
653 if ((change = (ovol != nvol)))
654 wm_put(ice, WM_OUT_MUX1, nvol);
655
656 snd_ice1712_restore_gpio_status(ice);
657
658 return change;
659}
660
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100661static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
662static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
663static const DECLARE_TLV_DB_SCALE(db_scale_wm_adc, -1200, 100, 0);
664static const DECLARE_TLV_DB_SCALE(db_scale_ac97_master, -4650, 150, 0);
665static const DECLARE_TLV_DB_SCALE(db_scale_ac97_gain, -3450, 150, 0);
Takashi Iwaif640c322006-08-30 16:57:37 +0200666
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667/*
668 * Logarithmic volume values for WM8770
669 * Computed as 20 * Log10(255 / x)
670 */
Takashi Iwai32b47da2007-01-29 15:26:36 +0100671static const unsigned char wm_vol[256] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23,
673 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17,
674 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13,
675 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11,
676 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8,
677 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,
678 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,
679 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,
680 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,
681 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,
682 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,
683 0, 0
684};
685
686#define WM_VOL_MAX (sizeof(wm_vol) - 1)
687#define WM_VOL_MUTE 0x8000
688
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100689static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, unsigned short vol, unsigned short master)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690{
691 unsigned char nvol;
692
693 if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))
694 nvol = 0;
695 else
696 nvol = 127 - wm_vol[(((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 127) & WM_VOL_MAX];
697
698 wm_put(ice, index, nvol);
699 wm_put_nocache(ice, index, 0x180 | nvol);
700}
701
702/*
703 * DAC mute control
704 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200705#define wm_pcm_mute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100707static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100709 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
Ingo Molnar62932df2006-01-16 16:34:20 +0100711 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1;
Ingo Molnar62932df2006-01-16 16:34:20 +0100713 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 return 0;
715}
716
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100717static int wm_pcm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100719 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 unsigned short nval, oval;
721 int change;
722
723 snd_ice1712_save_gpio_status(ice);
724 oval = wm_get(ice, WM_MUTE);
725 nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10);
726 if ((change = (nval != oval)))
727 wm_put(ice, WM_MUTE, nval);
728 snd_ice1712_restore_gpio_status(ice);
729
730 return change;
731}
732
733/*
734 * Master volume attenuation mixer control
735 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100736static int wm_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737{
738 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
739 uinfo->count = 2;
740 uinfo->value.integer.min = 0;
741 uinfo->value.integer.max = WM_VOL_MAX;
742 return 0;
743}
744
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100745static int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100747 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 int i;
749 for (i=0; i<2; i++)
750 ucontrol->value.integer.value[i] = ice->spec.aureon.master[i] & ~WM_VOL_MUTE;
751 return 0;
752}
753
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100754static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100756 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 int ch, change = 0;
758
759 snd_ice1712_save_gpio_status(ice);
760 for (ch = 0; ch < 2; ch++) {
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100761 unsigned int vol = ucontrol->value.integer.value[ch];
762 if (vol > WM_VOL_MAX)
763 continue;
764 vol |= ice->spec.aureon.master[ch] & WM_VOL_MUTE;
765 if (vol != ice->spec.aureon.master[ch]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 int dac;
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100767 ice->spec.aureon.master[ch] = vol;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 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++) {
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100814 unsigned int vol = ucontrol->value.integer.value[i];
815 if (vol > 0x7f)
816 continue;
817 vol |= ice->spec.aureon.vol[ofs+i];
818 if (vol != ice->spec.aureon.vol[ofs+i]) {
819 ice->spec.aureon.vol[ofs+i] = vol;
820 idx = WM_DAC_ATTEN + ofs + i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 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 Iwaia5ce8892007-07-23 15:42:26 +0200882#define wm_master_mute_info snd_ctl_boolean_stereo_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100884static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100886 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887
888 ucontrol->value.integer.value[0] = (ice->spec.aureon.master[0] & WM_VOL_MUTE) ? 0 : 1;
889 ucontrol->value.integer.value[1] = (ice->spec.aureon.master[1] & WM_VOL_MUTE) ? 0 : 1;
890 return 0;
891}
892
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100893static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100895 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 int change = 0, i;
897
898 snd_ice1712_save_gpio_status(ice);
899 for (i = 0; i < 2; i++) {
900 int val = (ice->spec.aureon.master[i] & WM_VOL_MUTE) ? 0 : 1;
901 if (ucontrol->value.integer.value[i] != val) {
902 int dac;
903 ice->spec.aureon.master[i] &= ~WM_VOL_MUTE;
904 ice->spec.aureon.master[i] |=
905 ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
906 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
907 wm_set_vol(ice, WM_DAC_ATTEN + dac + i,
908 ice->spec.aureon.vol[dac + i],
909 ice->spec.aureon.master[i]);
910 change = 1;
911 }
912 }
913 snd_ice1712_restore_gpio_status(ice);
914
915 return change;
916}
917
918/* digital master volume */
919#define PCM_0dB 0xff
920#define PCM_RES 128 /* -64dB */
921#define PCM_MIN (PCM_0dB - PCM_RES)
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100922static int wm_pcm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923{
924 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
925 uinfo->count = 1;
926 uinfo->value.integer.min = 0; /* mute (-64dB) */
927 uinfo->value.integer.max = PCM_RES; /* 0dB */
928 return 0;
929}
930
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100931static int wm_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100933 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 unsigned short val;
935
Ingo Molnar62932df2006-01-16 16:34:20 +0100936 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
938 val = val > PCM_MIN ? (val - PCM_MIN) : 0;
939 ucontrol->value.integer.value[0] = val;
Ingo Molnar62932df2006-01-16 16:34:20 +0100940 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 return 0;
942}
943
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100944static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100946 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 unsigned short ovol, nvol;
948 int change = 0;
949
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 nvol = ucontrol->value.integer.value[0];
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100951 if (nvol > PCM_RES)
952 return -EINVAL;
953 snd_ice1712_save_gpio_status(ice);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff;
955 ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
956 if (ovol != nvol) {
957 wm_put(ice, WM_DAC_DIG_MASTER_ATTEN, nvol); /* prelatch */
958 wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100); /* update */
959 change = 1;
960 }
961 snd_ice1712_restore_gpio_status(ice);
962 return change;
963}
964
965/*
966 * ADC mute control
967 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200968#define wm_adc_mute_info snd_ctl_boolean_stereo_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100970static int wm_adc_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100972 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 unsigned short val;
974 int i;
975
Ingo Molnar62932df2006-01-16 16:34:20 +0100976 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 for (i = 0; i < 2; i++) {
978 val = wm_get(ice, WM_ADC_GAIN + i);
979 ucontrol->value.integer.value[i] = ~val>>5 & 0x1;
980 }
Ingo Molnar62932df2006-01-16 16:34:20 +0100981 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 return 0;
983}
984
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100985static int wm_adc_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100987 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 unsigned short new, old;
989 int i, change = 0;
990
991 snd_ice1712_save_gpio_status(ice);
992 for (i = 0; i < 2; i++) {
993 old = wm_get(ice, WM_ADC_GAIN + i);
994 new = (~ucontrol->value.integer.value[i]<<5&0x20) | (old&~0x20);
995 if (new != old) {
996 wm_put(ice, WM_ADC_GAIN + i, new);
997 change = 1;
998 }
999 }
1000 snd_ice1712_restore_gpio_status(ice);
1001
1002 return change;
1003}
1004
1005/*
1006 * ADC gain mixer control
1007 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001008static int wm_adc_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009{
1010 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1011 uinfo->count = 2;
1012 uinfo->value.integer.min = 0; /* -12dB */
1013 uinfo->value.integer.max = 0x1f; /* 19dB */
1014 return 0;
1015}
1016
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001017static int wm_adc_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001019 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 int i, idx;
1021 unsigned short vol;
1022
Ingo Molnar62932df2006-01-16 16:34:20 +01001023 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 for (i = 0; i < 2; i++) {
1025 idx = WM_ADC_GAIN + i;
1026 vol = wm_get(ice, idx) & 0x1f;
1027 ucontrol->value.integer.value[i] = vol;
1028 }
Ingo Molnar62932df2006-01-16 16:34:20 +01001029 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 return 0;
1031}
1032
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001033static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001035 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 int i, idx;
1037 unsigned short ovol, nvol;
1038 int change = 0;
1039
1040 snd_ice1712_save_gpio_status(ice);
1041 for (i = 0; i < 2; i++) {
1042 idx = WM_ADC_GAIN + i;
Takashi Iwai9cd17cd2007-11-15 15:56:07 +01001043 nvol = ucontrol->value.integer.value[i] & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 ovol = wm_get(ice, idx);
1045 if ((ovol & 0x1f) != nvol) {
1046 wm_put(ice, idx, nvol | (ovol & ~0x1f));
1047 change = 1;
1048 }
1049 }
1050 snd_ice1712_restore_gpio_status(ice);
1051 return change;
1052}
1053
1054/*
1055 * ADC input mux mixer control
1056 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001057static int wm_adc_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058{
Takashi Iwai32b47da2007-01-29 15:26:36 +01001059 static const char * const texts[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 "CD", //AIN1
1061 "Aux", //AIN2
1062 "Line", //AIN3
1063 "Mic", //AIN4
1064 "AC97" //AIN5
1065 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01001066 static const char * const universe_texts[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 "Aux1", //AIN1
1068 "CD", //AIN2
1069 "Phono", //AIN3
1070 "Line", //AIN4
1071 "Aux2", //AIN5
1072 "Mic", //AIN6
1073 "Aux3", //AIN7
1074 "AC97" //AIN8
1075 };
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001076 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077
1078 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1079 uinfo->count = 2;
1080 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) {
1081 uinfo->value.enumerated.items = 8;
1082 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1083 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1084 strcpy(uinfo->value.enumerated.name, universe_texts[uinfo->value.enumerated.item]);
1085 }
1086 else {
1087 uinfo->value.enumerated.items = 5;
1088 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1089 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1090 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1091 }
1092 return 0;
1093}
1094
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001095static int wm_adc_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001097 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 unsigned short val;
1099
Ingo Molnar62932df2006-01-16 16:34:20 +01001100 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 val = wm_get(ice, WM_ADC_MUX);
Takashi Iwai66820252006-03-20 18:31:57 +01001102 ucontrol->value.enumerated.item[0] = val & 7;
1103 ucontrol->value.enumerated.item[1] = (val >> 4) & 7;
Ingo Molnar62932df2006-01-16 16:34:20 +01001104 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 return 0;
1106}
1107
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001108static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001110 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 unsigned short oval, nval;
1112 int change;
1113
1114 snd_ice1712_save_gpio_status(ice);
1115 oval = wm_get(ice, WM_ADC_MUX);
1116 nval = oval & ~0x77;
Takashi Iwai66820252006-03-20 18:31:57 +01001117 nval |= ucontrol->value.enumerated.item[0] & 7;
1118 nval |= (ucontrol->value.enumerated.item[1] & 7) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 change = (oval != nval);
1120 if (change)
1121 wm_put(ice, WM_ADC_MUX, nval);
1122 snd_ice1712_restore_gpio_status(ice);
Takashi Iwai63786d02005-11-04 13:58:11 +01001123 return change;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124}
1125
1126/*
1127 * CS8415 Input mux
1128 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001129static int aureon_cs8415_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001131 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai32b47da2007-01-29 15:26:36 +01001132 static const char * const aureon_texts[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 "CD", //RXP0
1134 "Optical" //RXP1
1135 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01001136 static const char * const prodigy_texts[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 "CD",
1138 "Coax"
1139 };
1140 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1141 uinfo->count = 1;
1142 uinfo->value.enumerated.items = 2;
1143 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1144 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1145 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71)
1146 strcpy(uinfo->value.enumerated.name, prodigy_texts[uinfo->value.enumerated.item]);
1147 else
1148 strcpy(uinfo->value.enumerated.name, aureon_texts[uinfo->value.enumerated.item]);
1149 return 0;
1150}
1151
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001152static int aureon_cs8415_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001154 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155
1156 //snd_ice1712_save_gpio_status(ice);
1157 //val = aureon_cs8415_get(ice, CS8415_CTRL2);
Takashi Iwai66820252006-03-20 18:31:57 +01001158 ucontrol->value.enumerated.item[0] = ice->spec.aureon.cs8415_mux;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 //snd_ice1712_restore_gpio_status(ice);
1160 return 0;
1161}
1162
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001163static int aureon_cs8415_mux_put(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 unsigned short oval, nval;
1167 int change;
1168
1169 snd_ice1712_save_gpio_status(ice);
1170 oval = aureon_cs8415_get(ice, CS8415_CTRL2);
1171 nval = oval & ~0x07;
Takashi Iwai66820252006-03-20 18:31:57 +01001172 nval |= ucontrol->value.enumerated.item[0] & 7;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 change = (oval != nval);
1174 if (change)
1175 aureon_cs8415_put(ice, CS8415_CTRL2, nval);
1176 snd_ice1712_restore_gpio_status(ice);
Takashi Iwai66820252006-03-20 18:31:57 +01001177 ice->spec.aureon.cs8415_mux = ucontrol->value.enumerated.item[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 return change;
1179}
1180
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001181static int aureon_cs8415_rate_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182{
1183 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1184 uinfo->count = 1;
1185 uinfo->value.integer.min = 0;
1186 uinfo->value.integer.max = 192000;
1187 return 0;
1188}
1189
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001190static int aureon_cs8415_rate_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001192 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 unsigned char ratio;
1194 ratio = aureon_cs8415_get(ice, CS8415_RATIO);
1195 ucontrol->value.integer.value[0] = (int)((unsigned int)ratio * 750);
1196 return 0;
1197}
1198
1199/*
1200 * CS8415A Mute
1201 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001202#define aureon_cs8415_mute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001204static int aureon_cs8415_mute_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001206 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 snd_ice1712_save_gpio_status(ice);
1208 ucontrol->value.integer.value[0] = (aureon_cs8415_get(ice, CS8415_CTRL1) & 0x20) ? 0 : 1;
1209 snd_ice1712_restore_gpio_status(ice);
1210 return 0;
1211}
1212
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001213static int aureon_cs8415_mute_put (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001215 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 unsigned char oval, nval;
1217 int change;
1218 snd_ice1712_save_gpio_status(ice);
1219 oval = aureon_cs8415_get(ice, CS8415_CTRL1);
1220 if (ucontrol->value.integer.value[0])
1221 nval = oval & ~0x20;
1222 else
1223 nval = oval | 0x20;
1224 if ((change = (oval != nval)))
1225 aureon_cs8415_put(ice, CS8415_CTRL1, nval);
1226 snd_ice1712_restore_gpio_status(ice);
1227 return change;
1228}
1229
1230/*
1231 * CS8415A Q-Sub info
1232 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001233static int aureon_cs8415_qsub_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
1235 uinfo->count = 10;
1236 return 0;
1237}
1238
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001239static int aureon_cs8415_qsub_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
1240 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241
1242 snd_ice1712_save_gpio_status(ice);
1243 aureon_cs8415_read(ice, CS8415_QSUB, ucontrol->value.bytes.data, 10);
1244 snd_ice1712_restore_gpio_status(ice);
1245
1246 return 0;
1247}
1248
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001249static int aureon_cs8415_spdif_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_IEC958;
1251 uinfo->count = 1;
1252 return 0;
1253}
1254
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001255static int aureon_cs8415_mask_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 memset(ucontrol->value.iec958.status, 0xFF, 24);
1257 return 0;
1258}
1259
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001260static int aureon_cs8415_spdif_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) {
1261 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262
1263 snd_ice1712_save_gpio_status(ice);
1264 aureon_cs8415_read(ice, CS8415_C_BUFFER, ucontrol->value.iec958.status, 24);
1265 snd_ice1712_restore_gpio_status(ice);
1266 return 0;
1267}
1268
1269/*
1270 * Headphone Amplifier
1271 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001272static int aureon_set_headphone_amp(struct snd_ice1712 *ice, int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273{
1274 unsigned int tmp, tmp2;
1275
1276 tmp2 = tmp = snd_ice1712_gpio_read(ice);
1277 if (enable)
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001278 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1279 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT)
Takashi Iwaic5130272006-05-23 15:46:10 +02001280 tmp |= AUREON_HP_SEL;
1281 else
1282 tmp |= PRODIGY_HP_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 else
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001284 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1285 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT)
Takashi Iwaic5130272006-05-23 15:46:10 +02001286 tmp &= ~ AUREON_HP_SEL;
1287 else
1288 tmp &= ~ PRODIGY_HP_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 if (tmp != tmp2) {
1290 snd_ice1712_gpio_write(ice, tmp);
1291 return 1;
1292 }
1293 return 0;
1294}
1295
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001296static int aureon_get_headphone_amp(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297{
1298 unsigned int tmp = snd_ice1712_gpio_read(ice);
1299
1300 return ( tmp & AUREON_HP_SEL )!= 0;
1301}
1302
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001303#define aureon_hpamp_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001305static int aureon_hpamp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001307 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308
1309 ucontrol->value.integer.value[0] = aureon_get_headphone_amp(ice);
1310 return 0;
1311}
1312
1313
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001314static int aureon_hpamp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001316 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317
1318 return aureon_set_headphone_amp(ice,ucontrol->value.integer.value[0]);
1319}
1320
1321/*
1322 * Deemphasis
1323 */
1324
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001325#define aureon_deemp_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001327static int aureon_deemp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001329 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 0xf;
1331 return 0;
1332}
1333
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001334static int aureon_deemp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001336 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 int temp, temp2;
1338 temp2 = temp = wm_get(ice, WM_DAC_CTRL2);
1339 if (ucontrol->value.integer.value[0])
1340 temp |= 0xf;
1341 else
1342 temp &= ~0xf;
1343 if (temp != temp2) {
1344 wm_put(ice, WM_DAC_CTRL2, temp);
1345 return 1;
1346 }
1347 return 0;
1348}
1349
1350/*
1351 * ADC Oversampling
1352 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001353static int aureon_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354{
Takashi Iwai32b47da2007-01-29 15:26:36 +01001355 static const char * const texts[2] = { "128x", "64x" };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356
1357 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1358 uinfo->count = 1;
1359 uinfo->value.enumerated.items = 2;
1360
1361 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1362 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1363 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1364
1365 return 0;
1366}
1367
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001368static int aureon_oversampling_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001370 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 0x8;
1372 return 0;
1373}
1374
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001375static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376{
1377 int temp, temp2;
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001378 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379
1380 temp2 = temp = wm_get(ice, WM_MASTER);
1381
1382 if (ucontrol->value.enumerated.item[0])
1383 temp |= 0x8;
1384 else
1385 temp &= ~0x8;
1386
1387 if (temp != temp2) {
1388 wm_put(ice, WM_MASTER, temp);
1389 return 1;
1390 }
1391 return 0;
1392}
1393
1394/*
1395 * mixers
1396 */
1397
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01001398static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 {
1400 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1401 .name = "Master Playback Switch",
1402 .info = wm_master_mute_info,
1403 .get = wm_master_mute_get,
1404 .put = wm_master_mute_put
1405 },
1406 {
1407 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001408 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1409 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 .name = "Master Playback Volume",
1411 .info = wm_master_vol_info,
1412 .get = wm_master_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +02001413 .put = wm_master_vol_put,
1414 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 },
1416 {
1417 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1418 .name = "Front Playback Switch",
1419 .info = wm_mute_info,
1420 .get = wm_mute_get,
1421 .put = wm_mute_put,
1422 .private_value = (2 << 8) | 0
1423 },
1424 {
1425 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001426 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1427 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 .name = "Front Playback Volume",
1429 .info = wm_vol_info,
1430 .get = wm_vol_get,
1431 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001432 .private_value = (2 << 8) | 0,
1433 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 },
1435 {
1436 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1437 .name = "Rear Playback Switch",
1438 .info = wm_mute_info,
1439 .get = wm_mute_get,
1440 .put = wm_mute_put,
1441 .private_value = (2 << 8) | 2
1442 },
1443 {
1444 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001445 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1446 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 .name = "Rear Playback Volume",
1448 .info = wm_vol_info,
1449 .get = wm_vol_get,
1450 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001451 .private_value = (2 << 8) | 2,
1452 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 },
1454 {
1455 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1456 .name = "Center Playback Switch",
1457 .info = wm_mute_info,
1458 .get = wm_mute_get,
1459 .put = wm_mute_put,
1460 .private_value = (1 << 8) | 4
1461 },
1462 {
1463 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001464 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1465 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 .name = "Center Playback Volume",
1467 .info = wm_vol_info,
1468 .get = wm_vol_get,
1469 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001470 .private_value = (1 << 8) | 4,
1471 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 },
1473 {
1474 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1475 .name = "LFE Playback Switch",
1476 .info = wm_mute_info,
1477 .get = wm_mute_get,
1478 .put = wm_mute_put,
1479 .private_value = (1 << 8) | 5
1480 },
1481 {
1482 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001483 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1484 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 .name = "LFE Playback Volume",
1486 .info = wm_vol_info,
1487 .get = wm_vol_get,
1488 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001489 .private_value = (1 << 8) | 5,
1490 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 },
1492 {
1493 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1494 .name = "Side Playback Switch",
1495 .info = wm_mute_info,
1496 .get = wm_mute_get,
1497 .put = wm_mute_put,
1498 .private_value = (2 << 8) | 6
1499 },
1500 {
1501 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001502 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1503 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 .name = "Side Playback Volume",
1505 .info = wm_vol_info,
1506 .get = wm_vol_get,
1507 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001508 .private_value = (2 << 8) | 6,
1509 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 }
1511};
1512
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01001513static struct snd_kcontrol_new wm_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 {
1515 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1516 .name = "PCM Playback Switch",
1517 .info = wm_pcm_mute_info,
1518 .get = wm_pcm_mute_get,
1519 .put = wm_pcm_mute_put
1520 },
1521 {
1522 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001523 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1524 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 .name = "PCM Playback Volume",
1526 .info = wm_pcm_vol_info,
1527 .get = wm_pcm_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +02001528 .put = wm_pcm_vol_put,
1529 .tlv = { .p = db_scale_wm_pcm }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 },
1531 {
1532 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1533 .name = "Capture Switch",
1534 .info = wm_adc_mute_info,
1535 .get = wm_adc_mute_get,
1536 .put = wm_adc_mute_put,
1537 },
1538 {
1539 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001540 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1541 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 .name = "Capture Volume",
1543 .info = wm_adc_vol_info,
1544 .get = wm_adc_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +02001545 .put = wm_adc_vol_put,
1546 .tlv = { .p = db_scale_wm_adc }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 },
1548 {
1549 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1550 .name = "Capture Source",
1551 .info = wm_adc_mux_info,
1552 .get = wm_adc_mux_get,
1553 .put = wm_adc_mux_put,
1554 .private_value = 5
1555 },
1556 {
1557 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1558 .name = "External Amplifier",
1559 .info = aureon_hpamp_info,
1560 .get = aureon_hpamp_get,
1561 .put = aureon_hpamp_put
1562 },
1563 {
1564 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1565 .name = "DAC Deemphasis Switch",
1566 .info = aureon_deemp_info,
1567 .get = aureon_deemp_get,
1568 .put = aureon_deemp_put
1569 },
1570 {
1571 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1572 .name = "ADC Oversampling",
1573 .info = aureon_oversampling_info,
1574 .get = aureon_oversampling_get,
1575 .put = aureon_oversampling_put
1576 }
1577};
1578
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01001579static struct snd_kcontrol_new ac97_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 {
1581 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1582 .name = "AC97 Playback Switch",
1583 .info = aureon_ac97_mmute_info,
1584 .get = aureon_ac97_mmute_get,
1585 .put = aureon_ac97_mmute_put,
1586 .private_value = AC97_MASTER
1587 },
1588 {
1589 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001590 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1591 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 .name = "AC97 Playback Volume",
1593 .info = aureon_ac97_vol_info,
1594 .get = aureon_ac97_vol_get,
1595 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001596 .private_value = AC97_MASTER|AUREON_AC97_STEREO,
1597 .tlv = { .p = db_scale_ac97_master }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 },
1599 {
1600 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1601 .name = "CD Playback Switch",
1602 .info = aureon_ac97_mute_info,
1603 .get = aureon_ac97_mute_get,
1604 .put = aureon_ac97_mute_put,
1605 .private_value = AC97_CD
1606 },
1607 {
1608 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001609 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1610 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 .name = "CD Playback Volume",
1612 .info = aureon_ac97_vol_info,
1613 .get = aureon_ac97_vol_get,
1614 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001615 .private_value = AC97_CD|AUREON_AC97_STEREO,
1616 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 },
1618 {
1619 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1620 .name = "Aux Playback Switch",
1621 .info = aureon_ac97_mute_info,
1622 .get = aureon_ac97_mute_get,
1623 .put = aureon_ac97_mute_put,
1624 .private_value = AC97_AUX,
1625 },
1626 {
1627 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001628 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1629 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 .name = "Aux Playback Volume",
1631 .info = aureon_ac97_vol_info,
1632 .get = aureon_ac97_vol_get,
1633 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001634 .private_value = AC97_AUX|AUREON_AC97_STEREO,
1635 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 },
1637 {
1638 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1639 .name = "Line Playback Switch",
1640 .info = aureon_ac97_mute_info,
1641 .get = aureon_ac97_mute_get,
1642 .put = aureon_ac97_mute_put,
1643 .private_value = AC97_LINE
1644 },
1645 {
1646 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001647 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1648 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 .name = "Line Playback Volume",
1650 .info = aureon_ac97_vol_info,
1651 .get = aureon_ac97_vol_get,
1652 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001653 .private_value = AC97_LINE|AUREON_AC97_STEREO,
1654 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 },
1656 {
1657 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1658 .name = "Mic Playback Switch",
1659 .info = aureon_ac97_mute_info,
1660 .get = aureon_ac97_mute_get,
1661 .put = aureon_ac97_mute_put,
1662 .private_value = AC97_MIC
1663 },
1664 {
1665 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001666 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1667 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 .name = "Mic Playback Volume",
1669 .info = aureon_ac97_vol_info,
1670 .get = aureon_ac97_vol_get,
1671 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001672 .private_value = AC97_MIC,
1673 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 },
1675 {
1676 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1677 .name = "Mic Boost (+20dB)",
1678 .info = aureon_ac97_micboost_info,
1679 .get = aureon_ac97_micboost_get,
1680 .put = aureon_ac97_micboost_put
1681 }
1682};
1683
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01001684static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 {
1686 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1687 .name = "AC97 Playback Switch",
1688 .info = aureon_ac97_mmute_info,
1689 .get = aureon_ac97_mmute_get,
1690 .put = aureon_ac97_mmute_put,
1691 .private_value = AC97_MASTER
1692 },
1693 {
1694 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001695 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1696 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 .name = "AC97 Playback Volume",
1698 .info = aureon_ac97_vol_info,
1699 .get = aureon_ac97_vol_get,
1700 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001701 .private_value = AC97_MASTER|AUREON_AC97_STEREO,
1702 .tlv = { .p = db_scale_ac97_master }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 },
1704 {
1705 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1706 .name = "CD Playback Switch",
1707 .info = aureon_ac97_mute_info,
1708 .get = aureon_ac97_mute_get,
1709 .put = aureon_ac97_mute_put,
1710 .private_value = AC97_AUX
1711 },
1712 {
1713 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001714 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1715 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 .name = "CD Playback Volume",
1717 .info = aureon_ac97_vol_info,
1718 .get = aureon_ac97_vol_get,
1719 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001720 .private_value = AC97_AUX|AUREON_AC97_STEREO,
1721 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 },
1723 {
1724 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1725 .name = "Phono Playback Switch",
1726 .info = aureon_ac97_mute_info,
1727 .get = aureon_ac97_mute_get,
1728 .put = aureon_ac97_mute_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001729 .private_value = AC97_CD
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 },
1731 {
1732 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001733 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1734 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 .name = "Phono Playback Volume",
1736 .info = aureon_ac97_vol_info,
1737 .get = aureon_ac97_vol_get,
1738 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001739 .private_value = AC97_CD|AUREON_AC97_STEREO,
1740 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 },
1742 {
1743 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1744 .name = "Line Playback Switch",
1745 .info = aureon_ac97_mute_info,
1746 .get = aureon_ac97_mute_get,
1747 .put = aureon_ac97_mute_put,
1748 .private_value = AC97_LINE
1749 },
1750 {
1751 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001752 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1753 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 .name = "Line Playback Volume",
1755 .info = aureon_ac97_vol_info,
1756 .get = aureon_ac97_vol_get,
1757 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001758 .private_value = AC97_LINE|AUREON_AC97_STEREO,
1759 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 },
1761 {
1762 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1763 .name = "Mic Playback Switch",
1764 .info = aureon_ac97_mute_info,
1765 .get = aureon_ac97_mute_get,
1766 .put = aureon_ac97_mute_put,
1767 .private_value = AC97_MIC
1768 },
1769 {
1770 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001771 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1772 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 .name = "Mic Playback Volume",
1774 .info = aureon_ac97_vol_info,
1775 .get = aureon_ac97_vol_get,
1776 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001777 .private_value = AC97_MIC,
1778 .tlv = { .p = db_scale_ac97_gain }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 },
1780 {
1781 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1782 .name = "Mic Boost (+20dB)",
1783 .info = aureon_ac97_micboost_info,
1784 .get = aureon_ac97_micboost_get,
1785 .put = aureon_ac97_micboost_put
1786 },
1787 {
1788 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1789 .name = "Aux Playback Switch",
1790 .info = aureon_ac97_mute_info,
1791 .get = aureon_ac97_mute_get,
1792 .put = aureon_ac97_mute_put,
1793 .private_value = AC97_VIDEO,
1794 },
1795 {
1796 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001797 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1798 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 .name = "Aux Playback Volume",
1800 .info = aureon_ac97_vol_info,
1801 .get = aureon_ac97_vol_get,
1802 .put = aureon_ac97_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001803 .private_value = AC97_VIDEO|AUREON_AC97_STEREO,
1804 .tlv = { .p = db_scale_ac97_gain }
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +02001805 },
1806 {
1807 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1808 .name = "Aux Source",
1809 .info = aureon_universe_inmux_info,
1810 .get = aureon_universe_inmux_get,
1811 .put = aureon_universe_inmux_put
1812 }
1813
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814};
1815
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01001816static struct snd_kcontrol_new cs8415_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 {
1818 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1819 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH),
1820 .info = aureon_cs8415_mute_info,
1821 .get = aureon_cs8415_mute_get,
1822 .put = aureon_cs8415_mute_put
1823 },
1824 {
1825 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1826 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Source",
1827 .info = aureon_cs8415_mux_info,
1828 .get = aureon_cs8415_mux_get,
1829 .put = aureon_cs8415_mux_put,
1830 },
1831 {
1832 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1833 .name = SNDRV_CTL_NAME_IEC958("Q-subcode ",CAPTURE,DEFAULT),
1834 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1835 .info = aureon_cs8415_qsub_info,
1836 .get = aureon_cs8415_qsub_get,
1837 },
1838 {
1839 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1840 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,MASK),
1841 .access = SNDRV_CTL_ELEM_ACCESS_READ,
1842 .info = aureon_cs8415_spdif_info,
1843 .get = aureon_cs8415_mask_get
1844 },
1845 {
1846 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1847 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT),
1848 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1849 .info = aureon_cs8415_spdif_info,
1850 .get = aureon_cs8415_spdif_get
1851 },
1852 {
1853 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1854 .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Rate",
1855 .access =SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1856 .info = aureon_cs8415_rate_info,
1857 .get = aureon_cs8415_rate_get
1858 }
1859};
1860
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001861static int __devinit aureon_add_controls(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862{
1863 unsigned int i, counts;
1864 int err;
1865
1866 counts = ARRAY_SIZE(aureon_dac_controls);
1867 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY)
1868 counts -= 2; /* no side */
1869 for (i = 0; i < counts; i++) {
1870 err = snd_ctl_add(ice->card, snd_ctl_new1(&aureon_dac_controls[i], ice));
1871 if (err < 0)
1872 return err;
1873 }
1874
1875 for (i = 0; i < ARRAY_SIZE(wm_controls); i++) {
1876 err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice));
1877 if (err < 0)
1878 return err;
1879 }
1880
1881 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) {
1882 for (i = 0; i < ARRAY_SIZE(universe_ac97_controls); i++) {
1883 err = snd_ctl_add(ice->card, snd_ctl_new1(&universe_ac97_controls[i], ice));
1884 if (err < 0)
1885 return err;
1886 }
1887 }
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001888 else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1889 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 for (i = 0; i < ARRAY_SIZE(ac97_controls); i++) {
1891 err = snd_ctl_add(ice->card, snd_ctl_new1(&ac97_controls[i], ice));
1892 if (err < 0)
1893 return err;
1894 }
1895 }
1896
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001897 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1898 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 unsigned char id;
1900 snd_ice1712_save_gpio_status(ice);
1901 id = aureon_cs8415_get(ice, CS8415_ID);
1902 if (id != 0x41)
Takashi Iwai99b359b2005-10-20 18:26:44 +02001903 snd_printk(KERN_INFO "No CS8415 chip. Skipping CS8415 controls.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 else if ((id & 0x0F) != 0x01)
Takashi Iwai99b359b2005-10-20 18:26:44 +02001905 snd_printk(KERN_INFO "Detected unsupported CS8415 rev. (%c)\n", (char)((id & 0x0F) + 'A' - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 else {
1907 for (i = 0; i< ARRAY_SIZE(cs8415_controls); i++) {
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001908 struct snd_kcontrol *kctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 err = snd_ctl_add(ice->card, (kctl = snd_ctl_new1(&cs8415_controls[i], ice)));
1910 if (err < 0)
1911 return err;
1912 if (i > 1)
1913 kctl->id.device = ice->pcm->device;
1914 }
1915 }
1916 snd_ice1712_restore_gpio_status(ice);
1917 }
1918
1919 return 0;
1920}
1921
1922
1923/*
1924 * initialize the chip
1925 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001926static int __devinit aureon_init(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927{
Takashi Iwai32b47da2007-01-29 15:26:36 +01001928 static const unsigned short wm_inits_aureon[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 /* These come first to reduce init pop noise */
1930 0x1b, 0x044, /* ADC Mux (AC'97 source) */
1931 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
1932 0x1d, 0x009, /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */
1933
1934 0x18, 0x000, /* All power-up */
1935
1936 0x16, 0x122, /* I2S, normal polarity, 24bit */
1937 0x17, 0x022, /* 256fs, slave mode */
1938 0x00, 0, /* DAC1 analog mute */
1939 0x01, 0, /* DAC2 analog mute */
1940 0x02, 0, /* DAC3 analog mute */
1941 0x03, 0, /* DAC4 analog mute */
1942 0x04, 0, /* DAC5 analog mute */
1943 0x05, 0, /* DAC6 analog mute */
1944 0x06, 0, /* DAC7 analog mute */
1945 0x07, 0, /* DAC8 analog mute */
1946 0x08, 0x100, /* master analog mute */
1947 0x09, 0xff, /* DAC1 digital full */
1948 0x0a, 0xff, /* DAC2 digital full */
1949 0x0b, 0xff, /* DAC3 digital full */
1950 0x0c, 0xff, /* DAC4 digital full */
1951 0x0d, 0xff, /* DAC5 digital full */
1952 0x0e, 0xff, /* DAC6 digital full */
1953 0x0f, 0xff, /* DAC7 digital full */
1954 0x10, 0xff, /* DAC8 digital full */
1955 0x11, 0x1ff, /* master digital full */
1956 0x12, 0x000, /* phase normal */
1957 0x13, 0x090, /* unmute DAC L/R */
1958 0x14, 0x000, /* all unmute */
1959 0x15, 0x000, /* no deemphasis, no ZFLG */
1960 0x19, 0x000, /* -12dB ADC/L */
1961 0x1a, 0x000, /* -12dB ADC/R */
1962 (unsigned short)-1
1963 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01001964 static const unsigned short wm_inits_prodigy[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965
1966 /* These come first to reduce init pop noise */
1967 0x1b, 0x000, /* ADC Mux */
1968 0x1c, 0x009, /* Out Mux1 */
1969 0x1d, 0x009, /* Out Mux2 */
1970
1971 0x18, 0x000, /* All power-up */
1972
1973 0x16, 0x022, /* I2S, normal polarity, 24bit, high-pass on */
1974 0x17, 0x006, /* 128fs, slave mode */
1975
1976 0x00, 0, /* DAC1 analog mute */
1977 0x01, 0, /* DAC2 analog mute */
1978 0x02, 0, /* DAC3 analog mute */
1979 0x03, 0, /* DAC4 analog mute */
1980 0x04, 0, /* DAC5 analog mute */
1981 0x05, 0, /* DAC6 analog mute */
1982 0x06, 0, /* DAC7 analog mute */
1983 0x07, 0, /* DAC8 analog mute */
1984 0x08, 0x100, /* master analog mute */
1985
1986 0x09, 0x7f, /* DAC1 digital full */
1987 0x0a, 0x7f, /* DAC2 digital full */
1988 0x0b, 0x7f, /* DAC3 digital full */
1989 0x0c, 0x7f, /* DAC4 digital full */
1990 0x0d, 0x7f, /* DAC5 digital full */
1991 0x0e, 0x7f, /* DAC6 digital full */
1992 0x0f, 0x7f, /* DAC7 digital full */
1993 0x10, 0x7f, /* DAC8 digital full */
1994 0x11, 0x1FF, /* master digital full */
1995
1996 0x12, 0x000, /* phase normal */
1997 0x13, 0x090, /* unmute DAC L/R */
1998 0x14, 0x000, /* all unmute */
1999 0x15, 0x000, /* no deemphasis, no ZFLG */
2000
2001 0x19, 0x000, /* -12dB ADC/L */
2002 0x1a, 0x000, /* -12dB ADC/R */
2003 (unsigned short)-1
2004
2005 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01002006 static const unsigned short cs_inits[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 0x0441, /* RUN */
2008 0x0180, /* no mute, OMCK output on RMCK pin */
2009 0x0201, /* S/PDIF source on RXP1 */
2010 0x0605, /* slave, 24bit, MSB on second OSCLK, SDOUT for right channel when OLRCK is high */
2011 (unsigned short)-1
2012 };
2013 unsigned int tmp;
Takashi Iwai32b47da2007-01-29 15:26:36 +01002014 const unsigned short *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 int err, i;
2016
2017 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) {
2018 ice->num_total_dacs = 6;
2019 ice->num_total_adcs = 2;
2020 } else {
2021 /* aureon 7.1 and prodigy 7.1 */
2022 ice->num_total_dacs = 8;
2023 ice->num_total_adcs = 2;
2024 }
2025
2026 /* to remeber the register values of CS8415 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01002027 ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 if (! ice->akm)
2029 return -ENOMEM;
2030 ice->akm_codecs = 1;
2031
2032 if ((err = aureon_ac97_init(ice)) != 0)
2033 return err;
2034
2035 snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for the time being */
2036
2037 /* reset the wm codec as the SPI mode */
2038 snd_ice1712_save_gpio_status(ice);
2039 snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RESET|AUREON_WM_CS|AUREON_CS8415_CS|AUREON_HP_SEL));
2040
2041 tmp = snd_ice1712_gpio_read(ice);
2042 tmp &= ~AUREON_WM_RESET;
2043 snd_ice1712_gpio_write(ice, tmp);
2044 udelay(1);
2045 tmp |= AUREON_WM_CS | AUREON_CS8415_CS;
2046 snd_ice1712_gpio_write(ice, tmp);
2047 udelay(1);
2048 tmp |= AUREON_WM_RESET;
2049 snd_ice1712_gpio_write(ice, tmp);
2050 udelay(1);
2051
2052 /* initialize WM8770 codec */
Takashi Iwai45fe7222006-01-13 13:50:16 +01002053 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71 ||
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01002054 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
2055 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 p = wm_inits_prodigy;
2057 else
2058 p = wm_inits_aureon;
2059 for (; *p != (unsigned short)-1; p += 2)
2060 wm_put(ice, p[0], p[1]);
2061
2062 /* initialize CS8415A codec */
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01002063 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
2064 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
Takashi Iwai45fe7222006-01-13 13:50:16 +01002065 for (p = cs_inits; *p != (unsigned short)-1; p++)
2066 aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24);
2067 ice->spec.aureon.cs8415_mux = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068
Takashi Iwai45fe7222006-01-13 13:50:16 +01002069 aureon_set_headphone_amp(ice, 1);
2070 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071
2072 snd_ice1712_restore_gpio_status(ice);
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +02002073
2074 /* initialize PCA9554 pin directions & set default input*/
2075 aureon_pca9554_write(ice, PCA9554_DIR, 0x00);
2076 aureon_pca9554_write(ice, PCA9554_OUT, 0x00); /* internal AUX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077
2078 ice->spec.aureon.master[0] = WM_VOL_MUTE;
2079 ice->spec.aureon.master[1] = WM_VOL_MUTE;
2080 for (i = 0; i < ice->num_total_dacs; i++) {
2081 ice->spec.aureon.vol[i] = WM_VOL_MUTE;
2082 wm_set_vol(ice, i, ice->spec.aureon.vol[i], ice->spec.aureon.master[i % 2]);
2083 }
2084
2085 return 0;
2086}
2087
2088
2089/*
2090 * Aureon boards don't provide the EEPROM data except for the vendor IDs.
2091 * hence the driver needs to sets up it properly.
2092 */
2093
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01002094static unsigned char aureon51_eeprom[] __devinitdata = {
Takashi Iwai189bc172007-01-29 15:25:40 +01002095 [ICE_EEP2_SYSCONF] = 0x0a, /* clock 512, spdif-in/ADC, 3DACs */
2096 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
2097 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
2098 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
2099 [ICE_EEP2_GPIO_DIR] = 0xff,
2100 [ICE_EEP2_GPIO_DIR1] = 0xff,
2101 [ICE_EEP2_GPIO_DIR2] = 0x5f,
2102 [ICE_EEP2_GPIO_MASK] = 0x00,
2103 [ICE_EEP2_GPIO_MASK1] = 0x00,
2104 [ICE_EEP2_GPIO_MASK2] = 0x00,
2105 [ICE_EEP2_GPIO_STATE] = 0x00,
2106 [ICE_EEP2_GPIO_STATE1] = 0x00,
2107 [ICE_EEP2_GPIO_STATE2] = 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108};
2109
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01002110static unsigned char aureon71_eeprom[] __devinitdata = {
Takashi Iwai189bc172007-01-29 15:25:40 +01002111 [ICE_EEP2_SYSCONF] = 0x0b, /* clock 512, spdif-in/ADC, 4DACs */
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};
Takashi Iwai189bc172007-01-29 15:25:40 +01002125#define prodigy71_eeprom aureon71_eeprom
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01002127static unsigned char prodigy71lt_eeprom[] __devinitdata = {
Takashi Iwai189bc172007-01-29 15:25:40 +01002128 [ICE_EEP2_SYSCONF] = 0x4b, /* clock 384, spdif-in/ADC, 4DACs */
2129 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
2130 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
2131 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
2132 [ICE_EEP2_GPIO_DIR] = 0xff,
2133 [ICE_EEP2_GPIO_DIR1] = 0xff,
2134 [ICE_EEP2_GPIO_DIR2] = 0x5f,
2135 [ICE_EEP2_GPIO_MASK] = 0x00,
2136 [ICE_EEP2_GPIO_MASK1] = 0x00,
2137 [ICE_EEP2_GPIO_MASK2] = 0x00,
2138 [ICE_EEP2_GPIO_STATE] = 0x00,
2139 [ICE_EEP2_GPIO_STATE1] = 0x00,
2140 [ICE_EEP2_GPIO_STATE2] = 0x00,
Takashi Iwai45fe7222006-01-13 13:50:16 +01002141};
Takashi Iwai189bc172007-01-29 15:25:40 +01002142#define prodigy71xt_eeprom prodigy71lt_eeprom
Takashi Iwai45fe7222006-01-13 13:50:16 +01002143
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144/* entry point */
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01002145struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 {
2147 .subvendor = VT1724_SUBDEVICE_AUREON51_SKY,
2148 .name = "Terratec Aureon 5.1-Sky",
2149 .model = "aureon51",
2150 .chip_init = aureon_init,
2151 .build_controls = aureon_add_controls,
2152 .eeprom_size = sizeof(aureon51_eeprom),
2153 .eeprom_data = aureon51_eeprom,
2154 .driver = "Aureon51",
2155 },
2156 {
2157 .subvendor = VT1724_SUBDEVICE_AUREON71_SPACE,
2158 .name = "Terratec Aureon 7.1-Space",
2159 .model = "aureon71",
2160 .chip_init = aureon_init,
2161 .build_controls = aureon_add_controls,
2162 .eeprom_size = sizeof(aureon71_eeprom),
2163 .eeprom_data = aureon71_eeprom,
2164 .driver = "Aureon71",
2165 },
2166 {
2167 .subvendor = VT1724_SUBDEVICE_AUREON71_UNIVERSE,
2168 .name = "Terratec Aureon 7.1-Universe",
2169 .model = "universe",
2170 .chip_init = aureon_init,
2171 .build_controls = aureon_add_controls,
2172 .eeprom_size = sizeof(aureon71_eeprom),
2173 .eeprom_data = aureon71_eeprom,
Takashi Iwai9f37c5b2006-06-29 16:40:21 +02002174 .driver = "Aureon71Univ", /* keep in 15 letters */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 },
2176 {
2177 .subvendor = VT1724_SUBDEVICE_PRODIGY71,
2178 .name = "Audiotrak Prodigy 7.1",
2179 .model = "prodigy71",
2180 .chip_init = aureon_init,
2181 .build_controls = aureon_add_controls,
2182 .eeprom_size = sizeof(prodigy71_eeprom),
2183 .eeprom_data = prodigy71_eeprom,
2184 .driver = "Prodigy71", /* should be identical with Aureon71 */
2185 },
Takashi Iwai45fe7222006-01-13 13:50:16 +01002186 {
2187 .subvendor = VT1724_SUBDEVICE_PRODIGY71LT,
2188 .name = "Audiotrak Prodigy 7.1 LT",
2189 .model = "prodigy71lt",
2190 .chip_init = aureon_init,
2191 .build_controls = aureon_add_controls,
2192 .eeprom_size = sizeof(prodigy71lt_eeprom),
2193 .eeprom_data = prodigy71lt_eeprom,
2194 .driver = "Prodigy71LT",
2195 },
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01002196 {
2197 .subvendor = VT1724_SUBDEVICE_PRODIGY71XT,
2198 .name = "Audiotrak Prodigy 7.1 XT",
2199 .model = "prodigy71xt",
2200 .chip_init = aureon_init,
2201 .build_controls = aureon_add_controls,
2202 .eeprom_size = sizeof(prodigy71xt_eeprom),
2203 .eeprom_data = prodigy71xt_eeprom,
2204 .driver = "Prodigy71LT",
2205 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206 { } /* terminator */
2207};