blob: 765d7bd4c3d4c34e1df1421adc3a5d598760ec81 [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.
Alexander Beregalov1ce211a2008-09-07 01:19:00 +040047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
Alexander Beregalov1ce211a2008-09-07 01:19:00 +040049#include <linux/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <linux/delay.h>
51#include <linux/interrupt.h>
52#include <linux/init.h>
53#include <linux/slab.h>
Ingo Molnar62932df2006-01-16 16:34:20 +010054#include <linux/mutex.h>
55
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#include <sound/core.h>
57
58#include "ice1712.h"
59#include "envy24ht.h"
60#include "aureon.h"
Takashi Iwaif640c322006-08-30 16:57:37 +020061#include <sound/tlv.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
Takashi Iwai7cda8ba2008-01-18 13:36:07 +010063/* AC97 register cache for Aureon */
64struct aureon_spec {
65 unsigned short stac9744[64];
66 unsigned int cs8415_mux;
67 unsigned short master[2];
68 unsigned short vol[8];
69 unsigned char pca9554_out;
70};
71
Linus Torvalds1da177e2005-04-16 15:20:36 -070072/* WM8770 registers */
73#define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */
74#define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */
75#define WM_DAC_DIG_ATTEN 0x09 /* DAC1-8 digital attenuation */
76#define WM_DAC_DIG_MASTER_ATTEN 0x11 /* DAC master digital attenuation */
77#define WM_PHASE_SWAP 0x12 /* DAC phase */
78#define WM_DAC_CTRL1 0x13 /* DAC control bits */
79#define WM_MUTE 0x14 /* mute controls */
80#define WM_DAC_CTRL2 0x15 /* de-emphasis and zefo-flag */
81#define WM_INT_CTRL 0x16 /* interface control */
82#define WM_MASTER 0x17 /* master clock and mode */
83#define WM_POWERDOWN 0x18 /* power-down controls */
84#define WM_ADC_GAIN 0x19 /* ADC gain L(19)/R(1a) */
85#define WM_ADC_MUX 0x1b /* input MUX */
86#define WM_OUT_MUX1 0x1c /* output MUX */
87#define WM_OUT_MUX2 0x1e /* output MUX */
88#define WM_RESET 0x1f /* software reset */
89
90/* CS8415A registers */
91#define CS8415_CTRL1 0x01
92#define CS8415_CTRL2 0x02
93#define CS8415_QSUB 0x14
94#define CS8415_RATIO 0x1E
95#define CS8415_C_BUFFER 0x20
96#define CS8415_ID 0x7F
97
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +020098/* PCA9554 registers */
99#define PCA9554_DEV 0x40 /* I2C device address */
100#define PCA9554_IN 0x00 /* input port */
101#define PCA9554_OUT 0x01 /* output port */
102#define PCA9554_INVERT 0x02 /* input invert */
103#define PCA9554_DIR 0x03 /* port directions */
104
105/*
106 * Aureon Universe additional controls using PCA9554
107 */
108
109/*
110 * Send data to pca9554
111 */
112static void aureon_pca9554_write(struct snd_ice1712 *ice, unsigned char reg,
113 unsigned char data)
114{
115 unsigned int tmp;
116 int i, j;
117 unsigned char dev = PCA9554_DEV; /* ID 0100000, write */
118 unsigned char val = 0;
119
120 tmp = snd_ice1712_gpio_read(ice);
121
122 snd_ice1712_gpio_set_mask(ice, ~(AUREON_SPI_MOSI|AUREON_SPI_CLK|
123 AUREON_WM_RW|AUREON_WM_CS|
124 AUREON_CS8415_CS));
125 tmp |= AUREON_WM_RW;
126 tmp |= AUREON_CS8415_CS | AUREON_WM_CS; /* disable SPI devices */
127
128 tmp &= ~AUREON_SPI_MOSI;
129 tmp &= ~AUREON_SPI_CLK;
130 snd_ice1712_gpio_write(ice, tmp);
131 udelay(50);
132
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400133 /*
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200134 * send i2c stop condition and start condition
135 * to obtain sane state
136 */
137 tmp |= AUREON_SPI_CLK;
138 snd_ice1712_gpio_write(ice, tmp);
139 udelay(50);
140 tmp |= AUREON_SPI_MOSI;
141 snd_ice1712_gpio_write(ice, tmp);
142 udelay(100);
143 tmp &= ~AUREON_SPI_MOSI;
144 snd_ice1712_gpio_write(ice, tmp);
145 udelay(50);
146 tmp &= ~AUREON_SPI_CLK;
147 snd_ice1712_gpio_write(ice, tmp);
148 udelay(100);
149 /*
150 * send device address, command and value,
151 * skipping ack cycles inbetween
152 */
153 for (j = 0; j < 3; j++) {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400154 switch (j) {
155 case 0:
156 val = dev;
157 break;
158 case 1:
159 val = reg;
160 break;
161 case 2:
162 val = data;
163 break;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200164 }
165 for (i = 7; i >= 0; i--) {
166 tmp &= ~AUREON_SPI_CLK;
167 snd_ice1712_gpio_write(ice, tmp);
168 udelay(40);
169 if (val & (1 << i))
170 tmp |= AUREON_SPI_MOSI;
171 else
172 tmp &= ~AUREON_SPI_MOSI;
173 snd_ice1712_gpio_write(ice, tmp);
174 udelay(40);
175 tmp |= AUREON_SPI_CLK;
176 snd_ice1712_gpio_write(ice, tmp);
177 udelay(40);
178 }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400179 tmp &= ~AUREON_SPI_CLK;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200180 snd_ice1712_gpio_write(ice, tmp);
181 udelay(40);
182 tmp |= AUREON_SPI_CLK;
183 snd_ice1712_gpio_write(ice, tmp);
184 udelay(40);
185 tmp &= ~AUREON_SPI_CLK;
186 snd_ice1712_gpio_write(ice, tmp);
187 udelay(40);
188 }
189 tmp &= ~AUREON_SPI_CLK;
190 snd_ice1712_gpio_write(ice, tmp);
191 udelay(40);
192 tmp &= ~AUREON_SPI_MOSI;
193 snd_ice1712_gpio_write(ice, tmp);
194 udelay(40);
195 tmp |= AUREON_SPI_CLK;
196 snd_ice1712_gpio_write(ice, tmp);
197 udelay(50);
198 tmp |= AUREON_SPI_MOSI;
199 snd_ice1712_gpio_write(ice, tmp);
200 udelay(100);
201}
202
203static int aureon_universe_inmux_info(struct snd_kcontrol *kcontrol,
204 struct snd_ctl_elem_info *uinfo)
205{
206 char *texts[3] = {"Internal Aux", "Wavetable", "Rear Line-In"};
207
208 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
209 uinfo->count = 1;
210 uinfo->value.enumerated.items = 3;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400211 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200212 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
213 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
214 return 0;
215}
216
217static int aureon_universe_inmux_get(struct snd_kcontrol *kcontrol,
218 struct snd_ctl_elem_value *ucontrol)
219{
220 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100221 struct aureon_spec *spec = ice->spec;
222 ucontrol->value.enumerated.item[0] = spec->pca9554_out;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200223 return 0;
224}
225
226static int aureon_universe_inmux_put(struct snd_kcontrol *kcontrol,
227 struct snd_ctl_elem_value *ucontrol)
228{
229 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100230 struct aureon_spec *spec = ice->spec;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200231 unsigned char oval, nval;
232 int change;
233
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100234 nval = ucontrol->value.enumerated.item[0];
235 if (nval >= 3)
236 return -EINVAL;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200237 snd_ice1712_save_gpio_status(ice);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100238 oval = spec->pca9554_out;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400239 change = (oval != nval);
240 if (change) {
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200241 aureon_pca9554_write(ice, PCA9554_OUT, nval);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100242 spec->pca9554_out = nval;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200243 }
244 snd_ice1712_restore_gpio_status(ice);
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200245 return change;
246}
247
248
249static void aureon_ac97_write(struct snd_ice1712 *ice, unsigned short reg,
250 unsigned short val)
251{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100252 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 unsigned int tmp;
254
255 /* Send address to XILINX chip */
256 tmp = (snd_ice1712_gpio_read(ice) & ~0xFF) | (reg & 0x7F);
257 snd_ice1712_gpio_write(ice, tmp);
258 udelay(10);
259 tmp |= AUREON_AC97_ADDR;
260 snd_ice1712_gpio_write(ice, tmp);
261 udelay(10);
262 tmp &= ~AUREON_AC97_ADDR;
263 snd_ice1712_gpio_write(ice, tmp);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400264 udelay(10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265
266 /* Send low-order byte to XILINX chip */
267 tmp &= ~AUREON_AC97_DATA_MASK;
268 tmp |= val & AUREON_AC97_DATA_MASK;
269 snd_ice1712_gpio_write(ice, tmp);
270 udelay(10);
271 tmp |= AUREON_AC97_DATA_LOW;
272 snd_ice1712_gpio_write(ice, tmp);
273 udelay(10);
274 tmp &= ~AUREON_AC97_DATA_LOW;
275 snd_ice1712_gpio_write(ice, tmp);
276 udelay(10);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400277
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 /* Send high-order byte to XILINX chip */
279 tmp &= ~AUREON_AC97_DATA_MASK;
280 tmp |= (val >> 8) & AUREON_AC97_DATA_MASK;
281
282 snd_ice1712_gpio_write(ice, tmp);
283 udelay(10);
284 tmp |= AUREON_AC97_DATA_HIGH;
285 snd_ice1712_gpio_write(ice, tmp);
286 udelay(10);
287 tmp &= ~AUREON_AC97_DATA_HIGH;
288 snd_ice1712_gpio_write(ice, tmp);
289 udelay(10);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400290
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 /* Instruct XILINX chip to parse the data to the STAC9744 chip */
292 tmp |= AUREON_AC97_COMMIT;
293 snd_ice1712_gpio_write(ice, tmp);
294 udelay(10);
295 tmp &= ~AUREON_AC97_COMMIT;
296 snd_ice1712_gpio_write(ice, tmp);
297 udelay(10);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400298
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 /* Store the data in out private buffer */
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100300 spec->stac9744[(reg & 0x7F) >> 1] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301}
302
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100303static unsigned short aureon_ac97_read(struct snd_ice1712 *ice, unsigned short reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100305 struct aureon_spec *spec = ice->spec;
306 return spec->stac9744[(reg & 0x7F) >> 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307}
308
309/*
310 * Initialize STAC9744 chip
311 */
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400312static int aureon_ac97_init(struct snd_ice1712 *ice)
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200313{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100314 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 int i;
Takashi Iwai32b47da2007-01-29 15:26:36 +0100316 static const unsigned short ac97_defaults[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 0x00, 0x9640,
318 0x02, 0x8000,
319 0x04, 0x8000,
320 0x06, 0x8000,
321 0x0C, 0x8008,
322 0x0E, 0x8008,
323 0x10, 0x8808,
324 0x12, 0x8808,
325 0x14, 0x8808,
326 0x16, 0x8808,
327 0x18, 0x8808,
328 0x1C, 0x8000,
329 0x26, 0x000F,
330 0x28, 0x0201,
331 0x2C, 0xBB80,
332 0x32, 0xBB80,
333 0x7C, 0x8384,
334 0x7E, 0x7644,
335 (unsigned short)-1
336 };
337 unsigned int tmp;
338
339 /* Cold reset */
340 tmp = (snd_ice1712_gpio_read(ice) | AUREON_AC97_RESET) & ~AUREON_AC97_DATA_MASK;
341 snd_ice1712_gpio_write(ice, tmp);
342 udelay(3);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400343
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 tmp &= ~AUREON_AC97_RESET;
345 snd_ice1712_gpio_write(ice, tmp);
346 udelay(3);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400347
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 tmp |= AUREON_AC97_RESET;
349 snd_ice1712_gpio_write(ice, tmp);
350 udelay(3);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400351
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100352 memset(&spec->stac9744, 0, sizeof(spec->stac9744));
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400353 for (i = 0; ac97_defaults[i] != (unsigned short)-1; i += 2)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100354 spec->stac9744[(ac97_defaults[i]) >> 1] = ac97_defaults[i+1];
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400355
356 /* Unmute AC'97 master volume permanently - muting is done by WM8770 */
357 aureon_ac97_write(ice, AC97_MASTER, 0x0000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
359 return 0;
360}
361
362#define AUREON_AC97_STEREO 0x80
363
364/*
365 * AC'97 volume controls
366 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100367static int aureon_ac97_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368{
369 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
370 uinfo->count = kcontrol->private_value & AUREON_AC97_STEREO ? 2 : 1;
371 uinfo->value.integer.min = 0;
372 uinfo->value.integer.max = 31;
373 return 0;
374}
375
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100376static int aureon_ac97_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100378 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 unsigned short vol;
380
Ingo Molnar62932df2006-01-16 16:34:20 +0100381 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
383 vol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
384 ucontrol->value.integer.value[0] = 0x1F - (vol & 0x1F);
385 if (kcontrol->private_value & AUREON_AC97_STEREO)
386 ucontrol->value.integer.value[1] = 0x1F - ((vol >> 8) & 0x1F);
387
Ingo Molnar62932df2006-01-16 16:34:20 +0100388 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 return 0;
390}
391
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100392static int aureon_ac97_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100394 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 unsigned short ovol, nvol;
396 int change;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400397
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 snd_ice1712_save_gpio_status(ice);
399
400 ovol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
401 nvol = (0x1F - ucontrol->value.integer.value[0]) & 0x001F;
402 if (kcontrol->private_value & AUREON_AC97_STEREO)
403 nvol |= ((0x1F - ucontrol->value.integer.value[1]) << 8) & 0x1F00;
404 nvol |= ovol & ~0x1F1F;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400405
406 change = (ovol != nvol);
407 if (change)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 aureon_ac97_write(ice, kcontrol->private_value & 0x7F, nvol);
409
410 snd_ice1712_restore_gpio_status(ice);
411
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400412 return change;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413}
414
415/*
416 * AC'97 mute controls
417 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200418#define aureon_ac97_mute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100420static int aureon_ac97_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100422 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
Ingo Molnar62932df2006-01-16 16:34:20 +0100424 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400426 ucontrol->value.integer.value[0] = aureon_ac97_read(ice,
427 kcontrol->private_value & 0x7F) & 0x8000 ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428
Ingo Molnar62932df2006-01-16 16:34:20 +0100429 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 return 0;
431}
432
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100433static int aureon_ac97_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100435 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 unsigned short ovol, nvol;
437 int change;
438
439 snd_ice1712_save_gpio_status(ice);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400440
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 ovol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400442 nvol = (ucontrol->value.integer.value[0] ? 0x0000 : 0x8000) | (ovol & ~0x8000);
443
444 change = (ovol != nvol);
445 if (change)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 aureon_ac97_write(ice, kcontrol->private_value & 0x7F, nvol);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400447
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 snd_ice1712_restore_gpio_status(ice);
449
450 return change;
451}
452
453/*
454 * AC'97 mute controls
455 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200456#define aureon_ac97_micboost_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100458static int aureon_ac97_micboost_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100460 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461
Ingo Molnar62932df2006-01-16 16:34:20 +0100462 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
464 ucontrol->value.integer.value[0] = aureon_ac97_read(ice, AC97_MIC) & 0x0020 ? 0 : 1;
465
Ingo Molnar62932df2006-01-16 16:34:20 +0100466 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 return 0;
468}
469
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100470static int aureon_ac97_micboost_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100472 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 unsigned short ovol, nvol;
474 int change;
475
476 snd_ice1712_save_gpio_status(ice);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400477
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 ovol = aureon_ac97_read(ice, AC97_MIC);
479 nvol = (ucontrol->value.integer.value[0] ? 0x0000 : 0x0020) | (ovol & ~0x0020);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400480
481 change = (ovol != nvol);
482 if (change)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 aureon_ac97_write(ice, AC97_MIC, nvol);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400484
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 snd_ice1712_restore_gpio_status(ice);
486
487 return change;
488}
489
490/*
491 * write data in the SPI mode
492 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100493static void aureon_spi_write(struct snd_ice1712 *ice, unsigned int cs, unsigned int data, int bits)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494{
495 unsigned int tmp;
496 int i;
Takashi Iwai45fe7222006-01-13 13:50:16 +0100497 unsigned int mosi, clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
499 tmp = snd_ice1712_gpio_read(ice);
500
Toshimune Konnocdf88ef2006-12-18 13:12:18 +0100501 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
502 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) {
Takashi Iwai45fe7222006-01-13 13:50:16 +0100503 snd_ice1712_gpio_set_mask(ice, ~(PRODIGY_SPI_MOSI|PRODIGY_SPI_CLK|PRODIGY_WM_CS));
504 mosi = PRODIGY_SPI_MOSI;
505 clk = PRODIGY_SPI_CLK;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400506 } else {
Takashi Iwai45fe7222006-01-13 13:50:16 +0100507 snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RW|AUREON_SPI_MOSI|AUREON_SPI_CLK|
508 AUREON_WM_CS|AUREON_CS8415_CS));
509 mosi = AUREON_SPI_MOSI;
510 clk = AUREON_SPI_CLK;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400511
Takashi Iwai45fe7222006-01-13 13:50:16 +0100512 tmp |= AUREON_WM_RW;
513 }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400514
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 tmp &= ~cs;
516 snd_ice1712_gpio_write(ice, tmp);
517 udelay(1);
518
519 for (i = bits - 1; i >= 0; i--) {
Takashi Iwai45fe7222006-01-13 13:50:16 +0100520 tmp &= ~clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 snd_ice1712_gpio_write(ice, tmp);
522 udelay(1);
523 if (data & (1 << i))
Takashi Iwai45fe7222006-01-13 13:50:16 +0100524 tmp |= mosi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 else
Takashi Iwai45fe7222006-01-13 13:50:16 +0100526 tmp &= ~mosi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 snd_ice1712_gpio_write(ice, tmp);
528 udelay(1);
Takashi Iwai45fe7222006-01-13 13:50:16 +0100529 tmp |= clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 snd_ice1712_gpio_write(ice, tmp);
531 udelay(1);
532 }
533
Takashi Iwai45fe7222006-01-13 13:50:16 +0100534 tmp &= ~clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 tmp |= cs;
536 snd_ice1712_gpio_write(ice, tmp);
537 udelay(1);
Takashi Iwai45fe7222006-01-13 13:50:16 +0100538 tmp |= clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 snd_ice1712_gpio_write(ice, tmp);
540 udelay(1);
541}
542
543/*
544 * Read data in SPI mode
545 */
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400546static void aureon_spi_read(struct snd_ice1712 *ice, unsigned int cs,
547 unsigned int data, int bits, unsigned char *buffer, int size)
548{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 int i, j;
550 unsigned int tmp;
551
552 tmp = (snd_ice1712_gpio_read(ice) & ~AUREON_SPI_CLK) | AUREON_CS8415_CS|AUREON_WM_CS;
553 snd_ice1712_gpio_write(ice, tmp);
554 tmp &= ~cs;
555 snd_ice1712_gpio_write(ice, tmp);
556 udelay(1);
557
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400558 for (i = bits-1; i >= 0; i--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 if (data & (1 << i))
560 tmp |= AUREON_SPI_MOSI;
561 else
562 tmp &= ~AUREON_SPI_MOSI;
563 snd_ice1712_gpio_write(ice, tmp);
564 udelay(1);
565
566 tmp |= AUREON_SPI_CLK;
567 snd_ice1712_gpio_write(ice, tmp);
568 udelay(1);
569
570 tmp &= ~AUREON_SPI_CLK;
571 snd_ice1712_gpio_write(ice, tmp);
572 udelay(1);
573 }
574
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400575 for (j = 0; j < size; j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 unsigned char outdata = 0;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400577 for (i = 7; i >= 0; i--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 tmp = snd_ice1712_gpio_read(ice);
579 outdata <<= 1;
580 outdata |= (tmp & AUREON_SPI_MISO) ? 1 : 0;
581 udelay(1);
582
583 tmp |= AUREON_SPI_CLK;
584 snd_ice1712_gpio_write(ice, tmp);
585 udelay(1);
586
587 tmp &= ~AUREON_SPI_CLK;
588 snd_ice1712_gpio_write(ice, tmp);
589 udelay(1);
590 }
591 buffer[j] = outdata;
592 }
593
594 tmp |= cs;
595 snd_ice1712_gpio_write(ice, tmp);
596}
597
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400598static unsigned char aureon_cs8415_get(struct snd_ice1712 *ice, int reg)
599{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 unsigned char val;
601 aureon_spi_write(ice, AUREON_CS8415_CS, 0x2000 | reg, 16);
602 aureon_spi_read(ice, AUREON_CS8415_CS, 0x21, 8, &val, 1);
603 return val;
604}
605
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400606static void aureon_cs8415_read(struct snd_ice1712 *ice, int reg,
607 unsigned char *buffer, int size)
608{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 aureon_spi_write(ice, AUREON_CS8415_CS, 0x2000 | reg, 16);
610 aureon_spi_read(ice, AUREON_CS8415_CS, 0x21, 8, buffer, size);
611}
612
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400613static void aureon_cs8415_put(struct snd_ice1712 *ice, int reg,
614 unsigned char val)
615{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 aureon_spi_write(ice, AUREON_CS8415_CS, 0x200000 | (reg << 8) | val, 24);
617}
618
619/*
620 * get the current register value of WM codec
621 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100622static unsigned short wm_get(struct snd_ice1712 *ice, int reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623{
624 reg <<= 1;
625 return ((unsigned short)ice->akm[0].images[reg] << 8) |
626 ice->akm[0].images[reg + 1];
627}
628
629/*
630 * set the register value of WM codec
631 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100632static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633{
Takashi Iwai45fe7222006-01-13 13:50:16 +0100634 aureon_spi_write(ice,
Toshimune Konnocdf88ef2006-12-18 13:12:18 +0100635 ((ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
636 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) ?
637 PRODIGY_WM_CS : AUREON_WM_CS),
Takashi Iwai45fe7222006-01-13 13:50:16 +0100638 (reg << 9) | (val & 0x1ff), 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639}
640
641/*
642 * set the register value of WM codec and remember it
643 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100644static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645{
646 wm_put_nocache(ice, reg, val);
647 reg <<= 1;
648 ice->akm[0].images[reg] = val >> 8;
649 ice->akm[0].images[reg + 1] = val;
650}
651
652/*
653 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200654#define aureon_mono_bool_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
656/*
657 * AC'97 master playback mute controls (Mute on WM8770 chip)
658 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200659#define aureon_ac97_mmute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100661static int aureon_ac97_mmute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100663 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664
Ingo Molnar62932df2006-01-16 16:34:20 +0100665 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666
667 ucontrol->value.integer.value[0] = (wm_get(ice, WM_OUT_MUX1) >> 1) & 0x01;
668
Ingo Molnar62932df2006-01-16 16:34:20 +0100669 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 return 0;
671}
672
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400673static int aureon_ac97_mmute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
674{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100675 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 unsigned short ovol, nvol;
677 int change;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400678
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 snd_ice1712_save_gpio_status(ice);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400680
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 ovol = wm_get(ice, WM_OUT_MUX1);
682 nvol = (ovol & ~0x02) | (ucontrol->value.integer.value[0] ? 0x02 : 0x00);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400683 change = (ovol != nvol);
684 if (change)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 wm_put(ice, WM_OUT_MUX1, nvol);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400686
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 snd_ice1712_restore_gpio_status(ice);
688
689 return change;
690}
691
Jaroslav Kysela482e46d2009-12-09 12:43:44 +0100692static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -10000, 100, 1);
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100693static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
694static const DECLARE_TLV_DB_SCALE(db_scale_wm_adc, -1200, 100, 0);
695static const DECLARE_TLV_DB_SCALE(db_scale_ac97_master, -4650, 150, 0);
696static const DECLARE_TLV_DB_SCALE(db_scale_ac97_gain, -3450, 150, 0);
Takashi Iwaif640c322006-08-30 16:57:37 +0200697
Jaroslav Kysela482e46d2009-12-09 12:43:44 +0100698#define WM_VOL_MAX 100
699#define WM_VOL_CNT 101 /* 0dB .. -100dB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700#define WM_VOL_MUTE 0x8000
701
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100702static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, unsigned short vol, unsigned short master)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703{
704 unsigned char nvol;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400705
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))
707 nvol = 0;
708 else
Jaroslav Kysela482e46d2009-12-09 12:43:44 +0100709 nvol = ((vol % WM_VOL_CNT) * (master % WM_VOL_CNT)) /
710 WM_VOL_MAX;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400711
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 wm_put(ice, index, nvol);
713 wm_put_nocache(ice, index, 0x180 | nvol);
714}
715
716/*
717 * DAC mute control
718 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200719#define wm_pcm_mute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100721static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100723 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
Ingo Molnar62932df2006-01-16 16:34:20 +0100725 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1;
Ingo Molnar62932df2006-01-16 16:34:20 +0100727 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 return 0;
729}
730
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100731static int wm_pcm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100733 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 unsigned short nval, oval;
735 int change;
736
737 snd_ice1712_save_gpio_status(ice);
738 oval = wm_get(ice, WM_MUTE);
739 nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400740 change = (oval != nval);
741 if (change)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 wm_put(ice, WM_MUTE, nval);
743 snd_ice1712_restore_gpio_status(ice);
744
745 return change;
746}
747
748/*
749 * Master volume attenuation mixer control
750 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100751static int wm_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752{
753 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
754 uinfo->count = 2;
755 uinfo->value.integer.min = 0;
756 uinfo->value.integer.max = WM_VOL_MAX;
757 return 0;
758}
759
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100760static int wm_master_vol_get(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);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100763 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 int i;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400765 for (i = 0; i < 2; i++)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100766 ucontrol->value.integer.value[i] =
767 spec->master[i] & ~WM_VOL_MUTE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 return 0;
769}
770
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100771static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100773 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100774 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 int ch, change = 0;
776
777 snd_ice1712_save_gpio_status(ice);
778 for (ch = 0; ch < 2; ch++) {
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100779 unsigned int vol = ucontrol->value.integer.value[ch];
780 if (vol > WM_VOL_MAX)
781 continue;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100782 vol |= spec->master[ch] & WM_VOL_MUTE;
783 if (vol != spec->master[ch]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 int dac;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100785 spec->master[ch] = vol;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
787 wm_set_vol(ice, WM_DAC_ATTEN + dac + ch,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100788 spec->vol[dac + ch],
789 spec->master[ch]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 change = 1;
791 }
792 }
793 snd_ice1712_restore_gpio_status(ice);
794 return change;
795}
796
797/*
798 * DAC volume attenuation mixer control
799 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100800static int wm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801{
802 int voices = kcontrol->private_value >> 8;
803 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
804 uinfo->count = voices;
805 uinfo->value.integer.min = 0; /* mute (-101dB) */
Jaroslav Kysela482e46d2009-12-09 12:43:44 +0100806 uinfo->value.integer.max = WM_VOL_MAX; /* 0dB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 return 0;
808}
809
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100810static int wm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100812 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100813 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 int i, ofs, voices;
815
816 voices = kcontrol->private_value >> 8;
817 ofs = kcontrol->private_value & 0xff;
818 for (i = 0; i < voices; i++)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100819 ucontrol->value.integer.value[i] =
820 spec->vol[ofs+i] & ~WM_VOL_MUTE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 return 0;
822}
823
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100824static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100826 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100827 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 int i, idx, ofs, voices;
829 int change = 0;
830
831 voices = kcontrol->private_value >> 8;
832 ofs = kcontrol->private_value & 0xff;
833 snd_ice1712_save_gpio_status(ice);
834 for (i = 0; i < voices; i++) {
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100835 unsigned int vol = ucontrol->value.integer.value[i];
Jaroslav Kysela482e46d2009-12-09 12:43:44 +0100836 if (vol > WM_VOL_MAX)
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100837 continue;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100838 vol |= spec->vol[ofs+i];
839 if (vol != spec->vol[ofs+i]) {
840 spec->vol[ofs+i] = vol;
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100841 idx = WM_DAC_ATTEN + ofs + i;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100842 wm_set_vol(ice, idx, spec->vol[ofs + i],
843 spec->master[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 change = 1;
845 }
846 }
847 snd_ice1712_restore_gpio_status(ice);
848 return change;
849}
850
851/*
852 * WM8770 mute control
853 */
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400854static int wm_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
855{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
857 uinfo->count = kcontrol->private_value >> 8;
858 uinfo->value.integer.min = 0;
859 uinfo->value.integer.max = 1;
860 return 0;
861}
862
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100863static int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100865 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100866 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 int voices, ofs, i;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400868
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 voices = kcontrol->private_value >> 8;
870 ofs = kcontrol->private_value & 0xFF;
871
872 for (i = 0; i < voices; i++)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100873 ucontrol->value.integer.value[i] =
874 (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 return 0;
876}
877
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100878static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100880 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100881 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 int change = 0, voices, ofs, i;
883
884 voices = kcontrol->private_value >> 8;
885 ofs = kcontrol->private_value & 0xFF;
886
887 snd_ice1712_save_gpio_status(ice);
888 for (i = 0; i < voices; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100889 int val = (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 if (ucontrol->value.integer.value[i] != val) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100891 spec->vol[ofs + i] &= ~WM_VOL_MUTE;
892 spec->vol[ofs + i] |=
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100894 wm_set_vol(ice, ofs + i, spec->vol[ofs + i],
895 spec->master[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 change = 1;
897 }
898 }
899 snd_ice1712_restore_gpio_status(ice);
900
901 return change;
902}
903
904/*
905 * WM8770 master mute control
906 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200907#define wm_master_mute_info snd_ctl_boolean_stereo_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100909static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100911 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100912 struct aureon_spec *spec = ice->spec;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400913
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100914 ucontrol->value.integer.value[0] =
915 (spec->master[0] & WM_VOL_MUTE) ? 0 : 1;
916 ucontrol->value.integer.value[1] =
917 (spec->master[1] & WM_VOL_MUTE) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 return 0;
919}
920
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100921static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100923 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100924 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 int change = 0, i;
926
927 snd_ice1712_save_gpio_status(ice);
928 for (i = 0; i < 2; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100929 int val = (spec->master[i] & WM_VOL_MUTE) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 if (ucontrol->value.integer.value[i] != val) {
931 int dac;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100932 spec->master[i] &= ~WM_VOL_MUTE;
933 spec->master[i] |=
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
935 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
936 wm_set_vol(ice, WM_DAC_ATTEN + dac + i,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100937 spec->vol[dac + i],
938 spec->master[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 change = 1;
940 }
941 }
942 snd_ice1712_restore_gpio_status(ice);
943
944 return change;
945}
946
947/* digital master volume */
948#define PCM_0dB 0xff
949#define PCM_RES 128 /* -64dB */
950#define PCM_MIN (PCM_0dB - PCM_RES)
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100951static int wm_pcm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952{
953 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
954 uinfo->count = 1;
955 uinfo->value.integer.min = 0; /* mute (-64dB) */
956 uinfo->value.integer.max = PCM_RES; /* 0dB */
957 return 0;
958}
959
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100960static int wm_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100962 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 unsigned short val;
964
Ingo Molnar62932df2006-01-16 16:34:20 +0100965 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
967 val = val > PCM_MIN ? (val - PCM_MIN) : 0;
968 ucontrol->value.integer.value[0] = val;
Ingo Molnar62932df2006-01-16 16:34:20 +0100969 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 return 0;
971}
972
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100973static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100975 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 unsigned short ovol, nvol;
977 int change = 0;
978
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 nvol = ucontrol->value.integer.value[0];
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100980 if (nvol > PCM_RES)
981 return -EINVAL;
982 snd_ice1712_save_gpio_status(ice);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff;
984 ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
985 if (ovol != nvol) {
986 wm_put(ice, WM_DAC_DIG_MASTER_ATTEN, nvol); /* prelatch */
987 wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100); /* update */
988 change = 1;
989 }
990 snd_ice1712_restore_gpio_status(ice);
991 return change;
992}
993
994/*
995 * ADC mute control
996 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200997#define wm_adc_mute_info snd_ctl_boolean_stereo_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100999static int wm_adc_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001001 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 unsigned short val;
1003 int i;
1004
Ingo Molnar62932df2006-01-16 16:34:20 +01001005 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 for (i = 0; i < 2; i++) {
1007 val = wm_get(ice, WM_ADC_GAIN + i);
1008 ucontrol->value.integer.value[i] = ~val>>5 & 0x1;
1009 }
Ingo Molnar62932df2006-01-16 16:34:20 +01001010 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 return 0;
1012}
1013
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001014static int wm_adc_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001016 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 unsigned short new, old;
1018 int i, change = 0;
1019
1020 snd_ice1712_save_gpio_status(ice);
1021 for (i = 0; i < 2; i++) {
1022 old = wm_get(ice, WM_ADC_GAIN + i);
1023 new = (~ucontrol->value.integer.value[i]<<5&0x20) | (old&~0x20);
1024 if (new != old) {
1025 wm_put(ice, WM_ADC_GAIN + i, new);
1026 change = 1;
1027 }
1028 }
1029 snd_ice1712_restore_gpio_status(ice);
1030
1031 return change;
1032}
1033
1034/*
1035 * ADC gain mixer control
1036 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001037static int wm_adc_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038{
1039 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1040 uinfo->count = 2;
1041 uinfo->value.integer.min = 0; /* -12dB */
1042 uinfo->value.integer.max = 0x1f; /* 19dB */
1043 return 0;
1044}
1045
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001046static int wm_adc_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001048 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 int i, idx;
1050 unsigned short vol;
1051
Ingo Molnar62932df2006-01-16 16:34:20 +01001052 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 for (i = 0; i < 2; i++) {
1054 idx = WM_ADC_GAIN + i;
1055 vol = wm_get(ice, idx) & 0x1f;
1056 ucontrol->value.integer.value[i] = vol;
1057 }
Ingo Molnar62932df2006-01-16 16:34:20 +01001058 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 return 0;
1060}
1061
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001062static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001064 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 int i, idx;
1066 unsigned short ovol, nvol;
1067 int change = 0;
1068
1069 snd_ice1712_save_gpio_status(ice);
1070 for (i = 0; i < 2; i++) {
1071 idx = WM_ADC_GAIN + i;
Takashi Iwai9cd17cd2007-11-15 15:56:07 +01001072 nvol = ucontrol->value.integer.value[i] & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 ovol = wm_get(ice, idx);
1074 if ((ovol & 0x1f) != nvol) {
1075 wm_put(ice, idx, nvol | (ovol & ~0x1f));
1076 change = 1;
1077 }
1078 }
1079 snd_ice1712_restore_gpio_status(ice);
1080 return change;
1081}
1082
1083/*
1084 * ADC input mux mixer control
1085 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001086static int wm_adc_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087{
Takashi Iwai32b47da2007-01-29 15:26:36 +01001088 static const char * const texts[] = {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001089 "CD", /* AIN1 */
1090 "Aux", /* AIN2 */
1091 "Line", /* AIN3 */
1092 "Mic", /* AIN4 */
1093 "AC97" /* AIN5 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01001095 static const char * const universe_texts[] = {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001096 "Aux1", /* AIN1 */
1097 "CD", /* AIN2 */
1098 "Phono", /* AIN3 */
1099 "Line", /* AIN4 */
1100 "Aux2", /* AIN5 */
1101 "Mic", /* AIN6 */
1102 "Aux3", /* AIN7 */
1103 "AC97" /* AIN8 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 };
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001105 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106
1107 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1108 uinfo->count = 2;
1109 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) {
1110 uinfo->value.enumerated.items = 8;
1111 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1112 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1113 strcpy(uinfo->value.enumerated.name, universe_texts[uinfo->value.enumerated.item]);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001114 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 uinfo->value.enumerated.items = 5;
1116 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1117 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1118 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1119 }
1120 return 0;
1121}
1122
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001123static int wm_adc_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001125 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 unsigned short val;
1127
Ingo Molnar62932df2006-01-16 16:34:20 +01001128 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 val = wm_get(ice, WM_ADC_MUX);
Takashi Iwai66820252006-03-20 18:31:57 +01001130 ucontrol->value.enumerated.item[0] = val & 7;
1131 ucontrol->value.enumerated.item[1] = (val >> 4) & 7;
Ingo Molnar62932df2006-01-16 16:34:20 +01001132 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 return 0;
1134}
1135
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001136static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001138 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 unsigned short oval, nval;
1140 int change;
1141
1142 snd_ice1712_save_gpio_status(ice);
1143 oval = wm_get(ice, WM_ADC_MUX);
1144 nval = oval & ~0x77;
Takashi Iwai66820252006-03-20 18:31:57 +01001145 nval |= ucontrol->value.enumerated.item[0] & 7;
1146 nval |= (ucontrol->value.enumerated.item[1] & 7) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 change = (oval != nval);
1148 if (change)
1149 wm_put(ice, WM_ADC_MUX, nval);
1150 snd_ice1712_restore_gpio_status(ice);
Takashi Iwai63786d02005-11-04 13:58:11 +01001151 return change;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152}
1153
1154/*
1155 * CS8415 Input mux
1156 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001157static int aureon_cs8415_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001159 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai32b47da2007-01-29 15:26:36 +01001160 static const char * const aureon_texts[] = {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001161 "CD", /* RXP0 */
1162 "Optical" /* RXP1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01001164 static const char * const prodigy_texts[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 "CD",
1166 "Coax"
1167 };
1168 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1169 uinfo->count = 1;
1170 uinfo->value.enumerated.items = 2;
1171 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1172 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1173 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71)
1174 strcpy(uinfo->value.enumerated.name, prodigy_texts[uinfo->value.enumerated.item]);
1175 else
1176 strcpy(uinfo->value.enumerated.name, aureon_texts[uinfo->value.enumerated.item]);
1177 return 0;
1178}
1179
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001180static int aureon_cs8415_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001182 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001183 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001185 /* snd_ice1712_save_gpio_status(ice); */
1186 /* val = aureon_cs8415_get(ice, CS8415_CTRL2); */
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001187 ucontrol->value.enumerated.item[0] = spec->cs8415_mux;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001188 /* snd_ice1712_restore_gpio_status(ice); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 return 0;
1190}
1191
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001192static int aureon_cs8415_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001194 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001195 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 unsigned short oval, nval;
1197 int change;
1198
1199 snd_ice1712_save_gpio_status(ice);
1200 oval = aureon_cs8415_get(ice, CS8415_CTRL2);
1201 nval = oval & ~0x07;
Takashi Iwai66820252006-03-20 18:31:57 +01001202 nval |= ucontrol->value.enumerated.item[0] & 7;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 change = (oval != nval);
1204 if (change)
1205 aureon_cs8415_put(ice, CS8415_CTRL2, nval);
1206 snd_ice1712_restore_gpio_status(ice);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001207 spec->cs8415_mux = ucontrol->value.enumerated.item[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 return change;
1209}
1210
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001211static int aureon_cs8415_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212{
1213 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1214 uinfo->count = 1;
1215 uinfo->value.integer.min = 0;
1216 uinfo->value.integer.max = 192000;
1217 return 0;
1218}
1219
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001220static int aureon_cs8415_rate_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 unsigned char ratio;
1224 ratio = aureon_cs8415_get(ice, CS8415_RATIO);
1225 ucontrol->value.integer.value[0] = (int)((unsigned int)ratio * 750);
1226 return 0;
1227}
1228
1229/*
1230 * CS8415A Mute
1231 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001232#define aureon_cs8415_mute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001234static int aureon_cs8415_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001236 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 snd_ice1712_save_gpio_status(ice);
1238 ucontrol->value.integer.value[0] = (aureon_cs8415_get(ice, CS8415_CTRL1) & 0x20) ? 0 : 1;
1239 snd_ice1712_restore_gpio_status(ice);
1240 return 0;
1241}
1242
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001243static int aureon_cs8415_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001245 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 unsigned char oval, nval;
1247 int change;
1248 snd_ice1712_save_gpio_status(ice);
1249 oval = aureon_cs8415_get(ice, CS8415_CTRL1);
1250 if (ucontrol->value.integer.value[0])
1251 nval = oval & ~0x20;
1252 else
1253 nval = oval | 0x20;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001254 change = (oval != nval);
1255 if (change)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 aureon_cs8415_put(ice, CS8415_CTRL1, nval);
1257 snd_ice1712_restore_gpio_status(ice);
1258 return change;
1259}
1260
1261/*
1262 * CS8415A Q-Sub info
1263 */
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001264static int aureon_cs8415_qsub_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1265{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
1267 uinfo->count = 10;
1268 return 0;
1269}
1270
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001271static int aureon_cs8415_qsub_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1272{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001273 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001274
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 snd_ice1712_save_gpio_status(ice);
1276 aureon_cs8415_read(ice, CS8415_QSUB, ucontrol->value.bytes.data, 10);
1277 snd_ice1712_restore_gpio_status(ice);
1278
1279 return 0;
1280}
1281
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001282static int aureon_cs8415_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1283{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
1285 uinfo->count = 1;
1286 return 0;
1287}
1288
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001289static int aureon_cs8415_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1290{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 memset(ucontrol->value.iec958.status, 0xFF, 24);
1292 return 0;
1293}
1294
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001295static int aureon_cs8415_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1296{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001297 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
1299 snd_ice1712_save_gpio_status(ice);
1300 aureon_cs8415_read(ice, CS8415_C_BUFFER, ucontrol->value.iec958.status, 24);
1301 snd_ice1712_restore_gpio_status(ice);
1302 return 0;
1303}
1304
1305/*
1306 * Headphone Amplifier
1307 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001308static int aureon_set_headphone_amp(struct snd_ice1712 *ice, int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309{
1310 unsigned int tmp, tmp2;
1311
1312 tmp2 = tmp = snd_ice1712_gpio_read(ice);
1313 if (enable)
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001314 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1315 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT)
Takashi Iwaic5130272006-05-23 15:46:10 +02001316 tmp |= AUREON_HP_SEL;
1317 else
1318 tmp |= PRODIGY_HP_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 else
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001320 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1321 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT)
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001322 tmp &= ~AUREON_HP_SEL;
Takashi Iwaic5130272006-05-23 15:46:10 +02001323 else
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001324 tmp &= ~PRODIGY_HP_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 if (tmp != tmp2) {
1326 snd_ice1712_gpio_write(ice, tmp);
1327 return 1;
1328 }
1329 return 0;
1330}
1331
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001332static int aureon_get_headphone_amp(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333{
1334 unsigned int tmp = snd_ice1712_gpio_read(ice);
1335
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001336 return (tmp & AUREON_HP_SEL) != 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337}
1338
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001339#define aureon_hpamp_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001341static int aureon_hpamp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001343 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344
1345 ucontrol->value.integer.value[0] = aureon_get_headphone_amp(ice);
1346 return 0;
1347}
1348
1349
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001350static int aureon_hpamp_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
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001354 return aureon_set_headphone_amp(ice, ucontrol->value.integer.value[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355}
1356
1357/*
1358 * Deemphasis
1359 */
1360
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001361#define aureon_deemp_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001363static int aureon_deemp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001365 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 0xf;
1367 return 0;
1368}
1369
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001370static int aureon_deemp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001372 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 int temp, temp2;
1374 temp2 = temp = wm_get(ice, WM_DAC_CTRL2);
1375 if (ucontrol->value.integer.value[0])
1376 temp |= 0xf;
1377 else
1378 temp &= ~0xf;
1379 if (temp != temp2) {
1380 wm_put(ice, WM_DAC_CTRL2, temp);
1381 return 1;
1382 }
1383 return 0;
1384}
1385
1386/*
1387 * ADC Oversampling
1388 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001389static int aureon_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390{
Takashi Iwai32b47da2007-01-29 15:26:36 +01001391 static const char * const texts[2] = { "128x", "64x" };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392
1393 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1394 uinfo->count = 1;
1395 uinfo->value.enumerated.items = 2;
1396
1397 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1398 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1399 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1400
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001401 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402}
1403
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001404static int aureon_oversampling_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001406 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 0x8;
1408 return 0;
1409}
1410
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001411static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412{
1413 int temp, temp2;
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001414 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415
1416 temp2 = temp = wm_get(ice, WM_MASTER);
1417
1418 if (ucontrol->value.enumerated.item[0])
1419 temp |= 0x8;
1420 else
1421 temp &= ~0x8;
1422
1423 if (temp != temp2) {
1424 wm_put(ice, WM_MASTER, temp);
1425 return 1;
1426 }
1427 return 0;
1428}
1429
1430/*
1431 * mixers
1432 */
1433
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01001434static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 {
1436 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1437 .name = "Master Playback Switch",
1438 .info = wm_master_mute_info,
1439 .get = wm_master_mute_get,
1440 .put = wm_master_mute_put
1441 },
1442 {
1443 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001444 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001445 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 .name = "Master Playback Volume",
1447 .info = wm_master_vol_info,
1448 .get = wm_master_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +02001449 .put = wm_master_vol_put,
1450 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 },
1452 {
1453 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1454 .name = "Front Playback Switch",
1455 .info = wm_mute_info,
1456 .get = wm_mute_get,
1457 .put = wm_mute_put,
1458 .private_value = (2 << 8) | 0
1459 },
1460 {
1461 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001462 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001463 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 .name = "Front Playback Volume",
1465 .info = wm_vol_info,
1466 .get = wm_vol_get,
1467 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001468 .private_value = (2 << 8) | 0,
1469 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 },
1471 {
1472 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1473 .name = "Rear Playback Switch",
1474 .info = wm_mute_info,
1475 .get = wm_mute_get,
1476 .put = wm_mute_put,
1477 .private_value = (2 << 8) | 2
1478 },
1479 {
1480 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001481 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001482 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 .name = "Rear Playback Volume",
1484 .info = wm_vol_info,
1485 .get = wm_vol_get,
1486 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001487 .private_value = (2 << 8) | 2,
1488 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 },
1490 {
1491 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1492 .name = "Center Playback Switch",
1493 .info = wm_mute_info,
1494 .get = wm_mute_get,
1495 .put = wm_mute_put,
1496 .private_value = (1 << 8) | 4
1497 },
1498 {
1499 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001500 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001501 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 .name = "Center Playback Volume",
1503 .info = wm_vol_info,
1504 .get = wm_vol_get,
1505 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001506 .private_value = (1 << 8) | 4,
1507 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 },
1509 {
1510 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1511 .name = "LFE Playback Switch",
1512 .info = wm_mute_info,
1513 .get = wm_mute_get,
1514 .put = wm_mute_put,
1515 .private_value = (1 << 8) | 5
1516 },
1517 {
1518 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001519 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001520 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 .name = "LFE Playback Volume",
1522 .info = wm_vol_info,
1523 .get = wm_vol_get,
1524 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001525 .private_value = (1 << 8) | 5,
1526 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 },
1528 {
1529 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1530 .name = "Side Playback Switch",
1531 .info = wm_mute_info,
1532 .get = wm_mute_get,
1533 .put = wm_mute_put,
1534 .private_value = (2 << 8) | 6
1535 },
1536 {
1537 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001538 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001539 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 .name = "Side Playback Volume",
1541 .info = wm_vol_info,
1542 .get = wm_vol_get,
1543 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001544 .private_value = (2 << 8) | 6,
1545 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 }
1547};
1548
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01001549static struct snd_kcontrol_new wm_controls[] __devinitdata = {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001550 {
1551 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 .name = "PCM Playback Switch",
1553 .info = wm_pcm_mute_info,
1554 .get = wm_pcm_mute_get,
1555 .put = wm_pcm_mute_put
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001556 },
1557 {
1558 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001559 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001560 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 .name = "PCM Playback Volume",
1562 .info = wm_pcm_vol_info,
1563 .get = wm_pcm_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +02001564 .put = wm_pcm_vol_put,
1565 .tlv = { .p = db_scale_wm_pcm }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001566 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 {
1568 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1569 .name = "Capture Switch",
1570 .info = wm_adc_mute_info,
1571 .get = wm_adc_mute_get,
1572 .put = wm_adc_mute_put,
1573 },
1574 {
1575 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001576 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001577 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 .name = "Capture Volume",
1579 .info = wm_adc_vol_info,
1580 .get = wm_adc_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +02001581 .put = wm_adc_vol_put,
1582 .tlv = { .p = db_scale_wm_adc }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 },
1584 {
1585 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1586 .name = "Capture Source",
1587 .info = wm_adc_mux_info,
1588 .get = wm_adc_mux_get,
1589 .put = wm_adc_mux_put,
1590 .private_value = 5
1591 },
1592 {
1593 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1594 .name = "External Amplifier",
1595 .info = aureon_hpamp_info,
1596 .get = aureon_hpamp_get,
1597 .put = aureon_hpamp_put
1598 },
1599 {
1600 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1601 .name = "DAC Deemphasis Switch",
1602 .info = aureon_deemp_info,
1603 .get = aureon_deemp_get,
1604 .put = aureon_deemp_put
1605 },
1606 {
1607 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1608 .name = "ADC Oversampling",
1609 .info = aureon_oversampling_info,
1610 .get = aureon_oversampling_get,
1611 .put = aureon_oversampling_put
1612 }
1613};
1614
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01001615static struct snd_kcontrol_new ac97_controls[] __devinitdata = {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001616 {
1617 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 .name = "AC97 Playback Switch",
1619 .info = aureon_ac97_mmute_info,
1620 .get = aureon_ac97_mmute_get,
1621 .put = aureon_ac97_mmute_put,
1622 .private_value = AC97_MASTER
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001623 },
1624 {
1625 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001626 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001627 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1628 .name = "AC97 Playback Volume",
1629 .info = aureon_ac97_vol_info,
1630 .get = aureon_ac97_vol_get,
1631 .put = aureon_ac97_vol_put,
1632 .private_value = AC97_MASTER|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001633 .tlv = { .p = db_scale_ac97_master }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001634 },
1635 {
1636 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1637 .name = "CD Playback Switch",
1638 .info = aureon_ac97_mute_info,
1639 .get = aureon_ac97_mute_get,
1640 .put = aureon_ac97_mute_put,
1641 .private_value = AC97_CD
1642 },
1643 {
1644 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001645 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001646 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1647 .name = "CD Playback Volume",
1648 .info = aureon_ac97_vol_info,
1649 .get = aureon_ac97_vol_get,
1650 .put = aureon_ac97_vol_put,
1651 .private_value = AC97_CD|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001652 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001653 },
1654 {
1655 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1656 .name = "Aux Playback Switch",
1657 .info = aureon_ac97_mute_info,
1658 .get = aureon_ac97_mute_get,
1659 .put = aureon_ac97_mute_put,
1660 .private_value = AC97_AUX,
1661 },
1662 {
1663 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001664 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001665 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1666 .name = "Aux Playback Volume",
1667 .info = aureon_ac97_vol_info,
1668 .get = aureon_ac97_vol_get,
1669 .put = aureon_ac97_vol_put,
1670 .private_value = AC97_AUX|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001671 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001672 },
1673 {
1674 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1675 .name = "Line Playback Switch",
1676 .info = aureon_ac97_mute_info,
1677 .get = aureon_ac97_mute_get,
1678 .put = aureon_ac97_mute_put,
1679 .private_value = AC97_LINE
1680 },
1681 {
1682 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001683 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001684 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1685 .name = "Line Playback Volume",
1686 .info = aureon_ac97_vol_info,
1687 .get = aureon_ac97_vol_get,
1688 .put = aureon_ac97_vol_put,
1689 .private_value = AC97_LINE|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001690 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001691 },
1692 {
1693 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1694 .name = "Mic Playback Switch",
1695 .info = aureon_ac97_mute_info,
1696 .get = aureon_ac97_mute_get,
1697 .put = aureon_ac97_mute_put,
1698 .private_value = AC97_MIC
1699 },
1700 {
1701 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001702 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001703 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1704 .name = "Mic Playback Volume",
1705 .info = aureon_ac97_vol_info,
1706 .get = aureon_ac97_vol_get,
1707 .put = aureon_ac97_vol_put,
1708 .private_value = AC97_MIC,
Takashi Iwaif640c322006-08-30 16:57:37 +02001709 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001710 },
1711 {
1712 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1713 .name = "Mic Boost (+20dB)",
1714 .info = aureon_ac97_micboost_info,
1715 .get = aureon_ac97_micboost_get,
1716 .put = aureon_ac97_micboost_put
1717 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718};
1719
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01001720static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001721 {
1722 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 .name = "AC97 Playback Switch",
1724 .info = aureon_ac97_mmute_info,
1725 .get = aureon_ac97_mmute_get,
1726 .put = aureon_ac97_mmute_put,
1727 .private_value = AC97_MASTER
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001728 },
1729 {
1730 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001731 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001732 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1733 .name = "AC97 Playback Volume",
1734 .info = aureon_ac97_vol_info,
1735 .get = aureon_ac97_vol_get,
1736 .put = aureon_ac97_vol_put,
1737 .private_value = AC97_MASTER|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001738 .tlv = { .p = db_scale_ac97_master }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001739 },
1740 {
1741 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1742 .name = "CD Playback Switch",
1743 .info = aureon_ac97_mute_info,
1744 .get = aureon_ac97_mute_get,
1745 .put = aureon_ac97_mute_put,
1746 .private_value = AC97_AUX
1747 },
1748 {
1749 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001750 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001751 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1752 .name = "CD Playback Volume",
1753 .info = aureon_ac97_vol_info,
1754 .get = aureon_ac97_vol_get,
1755 .put = aureon_ac97_vol_put,
1756 .private_value = AC97_AUX|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001757 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001758 },
1759 {
1760 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1761 .name = "Phono Playback Switch",
1762 .info = aureon_ac97_mute_info,
1763 .get = aureon_ac97_mute_get,
1764 .put = aureon_ac97_mute_put,
1765 .private_value = AC97_CD
1766 },
1767 {
1768 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001769 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001770 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1771 .name = "Phono Playback Volume",
1772 .info = aureon_ac97_vol_info,
1773 .get = aureon_ac97_vol_get,
1774 .put = aureon_ac97_vol_put,
1775 .private_value = AC97_CD|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001776 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001777 },
1778 {
1779 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1780 .name = "Line Playback Switch",
1781 .info = aureon_ac97_mute_info,
1782 .get = aureon_ac97_mute_get,
1783 .put = aureon_ac97_mute_put,
1784 .private_value = AC97_LINE
1785 },
1786 {
1787 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001788 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001789 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1790 .name = "Line Playback Volume",
1791 .info = aureon_ac97_vol_info,
1792 .get = aureon_ac97_vol_get,
1793 .put = aureon_ac97_vol_put,
1794 .private_value = AC97_LINE|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001795 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001796 },
1797 {
1798 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1799 .name = "Mic Playback Switch",
1800 .info = aureon_ac97_mute_info,
1801 .get = aureon_ac97_mute_get,
1802 .put = aureon_ac97_mute_put,
1803 .private_value = AC97_MIC
1804 },
1805 {
1806 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001807 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001808 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1809 .name = "Mic Playback Volume",
1810 .info = aureon_ac97_vol_info,
1811 .get = aureon_ac97_vol_get,
1812 .put = aureon_ac97_vol_put,
1813 .private_value = AC97_MIC,
Takashi Iwaif640c322006-08-30 16:57:37 +02001814 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001815 },
1816 {
1817 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1818 .name = "Mic Boost (+20dB)",
1819 .info = aureon_ac97_micboost_info,
1820 .get = aureon_ac97_micboost_get,
1821 .put = aureon_ac97_micboost_put
1822 },
1823 {
1824 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1825 .name = "Aux Playback Switch",
1826 .info = aureon_ac97_mute_info,
1827 .get = aureon_ac97_mute_get,
1828 .put = aureon_ac97_mute_put,
1829 .private_value = AC97_VIDEO,
1830 },
1831 {
1832 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001833 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001834 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1835 .name = "Aux Playback Volume",
1836 .info = aureon_ac97_vol_info,
1837 .get = aureon_ac97_vol_get,
1838 .put = aureon_ac97_vol_put,
1839 .private_value = AC97_VIDEO|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001840 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001841 },
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +02001842 {
1843 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1844 .name = "Aux Source",
1845 .info = aureon_universe_inmux_info,
1846 .get = aureon_universe_inmux_get,
1847 .put = aureon_universe_inmux_put
1848 }
1849
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850};
1851
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01001852static struct snd_kcontrol_new cs8415_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 {
1854 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001855 .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, SWITCH),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 .info = aureon_cs8415_mute_info,
1857 .get = aureon_cs8415_mute_get,
1858 .put = aureon_cs8415_mute_put
1859 },
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001860 {
1861 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1862 .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) "Source",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 .info = aureon_cs8415_mux_info,
1864 .get = aureon_cs8415_mux_get,
1865 .put = aureon_cs8415_mux_put,
1866 },
1867 {
1868 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001869 .name = SNDRV_CTL_NAME_IEC958("Q-subcode ", CAPTURE, DEFAULT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1871 .info = aureon_cs8415_qsub_info,
1872 .get = aureon_cs8415_qsub_get,
1873 },
1874 {
1875 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001876 .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 .access = SNDRV_CTL_ELEM_ACCESS_READ,
1878 .info = aureon_cs8415_spdif_info,
1879 .get = aureon_cs8415_mask_get
1880 },
1881 {
1882 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001883 .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1885 .info = aureon_cs8415_spdif_info,
1886 .get = aureon_cs8415_spdif_get
1887 },
1888 {
1889 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001890 .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) "Rate",
1891 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 .info = aureon_cs8415_rate_info,
1893 .get = aureon_cs8415_rate_get
1894 }
1895};
1896
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001897static int __devinit aureon_add_controls(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898{
1899 unsigned int i, counts;
1900 int err;
1901
1902 counts = ARRAY_SIZE(aureon_dac_controls);
1903 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY)
1904 counts -= 2; /* no side */
1905 for (i = 0; i < counts; i++) {
1906 err = snd_ctl_add(ice->card, snd_ctl_new1(&aureon_dac_controls[i], ice));
1907 if (err < 0)
1908 return err;
1909 }
1910
1911 for (i = 0; i < ARRAY_SIZE(wm_controls); i++) {
1912 err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice));
1913 if (err < 0)
1914 return err;
1915 }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001916
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) {
1918 for (i = 0; i < ARRAY_SIZE(universe_ac97_controls); i++) {
1919 err = snd_ctl_add(ice->card, snd_ctl_new1(&universe_ac97_controls[i], ice));
1920 if (err < 0)
1921 return err;
1922 }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001923 } else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001924 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 for (i = 0; i < ARRAY_SIZE(ac97_controls); i++) {
1926 err = snd_ctl_add(ice->card, snd_ctl_new1(&ac97_controls[i], ice));
1927 if (err < 0)
1928 return err;
1929 }
1930 }
1931
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001932 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1933 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 unsigned char id;
1935 snd_ice1712_save_gpio_status(ice);
1936 id = aureon_cs8415_get(ice, CS8415_ID);
1937 if (id != 0x41)
Takashi Iwai99b359b2005-10-20 18:26:44 +02001938 snd_printk(KERN_INFO "No CS8415 chip. Skipping CS8415 controls.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 else if ((id & 0x0F) != 0x01)
Takashi Iwai99b359b2005-10-20 18:26:44 +02001940 snd_printk(KERN_INFO "Detected unsupported CS8415 rev. (%c)\n", (char)((id & 0x0F) + 'A' - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 else {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001942 for (i = 0; i < ARRAY_SIZE(cs8415_controls); i++) {
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001943 struct snd_kcontrol *kctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 err = snd_ctl_add(ice->card, (kctl = snd_ctl_new1(&cs8415_controls[i], ice)));
1945 if (err < 0)
1946 return err;
1947 if (i > 1)
1948 kctl->id.device = ice->pcm->device;
1949 }
1950 }
1951 snd_ice1712_restore_gpio_status(ice);
1952 }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001953
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 return 0;
1955}
1956
1957
1958/*
1959 * initialize the chip
1960 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001961static int __devinit aureon_init(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962{
Takashi Iwai32b47da2007-01-29 15:26:36 +01001963 static const unsigned short wm_inits_aureon[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 /* These come first to reduce init pop noise */
1965 0x1b, 0x044, /* ADC Mux (AC'97 source) */
1966 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
1967 0x1d, 0x009, /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */
1968
1969 0x18, 0x000, /* All power-up */
1970
1971 0x16, 0x122, /* I2S, normal polarity, 24bit */
1972 0x17, 0x022, /* 256fs, slave mode */
1973 0x00, 0, /* DAC1 analog mute */
1974 0x01, 0, /* DAC2 analog mute */
1975 0x02, 0, /* DAC3 analog mute */
1976 0x03, 0, /* DAC4 analog mute */
1977 0x04, 0, /* DAC5 analog mute */
1978 0x05, 0, /* DAC6 analog mute */
1979 0x06, 0, /* DAC7 analog mute */
1980 0x07, 0, /* DAC8 analog mute */
1981 0x08, 0x100, /* master analog mute */
1982 0x09, 0xff, /* DAC1 digital full */
1983 0x0a, 0xff, /* DAC2 digital full */
1984 0x0b, 0xff, /* DAC3 digital full */
1985 0x0c, 0xff, /* DAC4 digital full */
1986 0x0d, 0xff, /* DAC5 digital full */
1987 0x0e, 0xff, /* DAC6 digital full */
1988 0x0f, 0xff, /* DAC7 digital full */
1989 0x10, 0xff, /* DAC8 digital full */
1990 0x11, 0x1ff, /* master digital full */
1991 0x12, 0x000, /* phase normal */
1992 0x13, 0x090, /* unmute DAC L/R */
1993 0x14, 0x000, /* all unmute */
1994 0x15, 0x000, /* no deemphasis, no ZFLG */
1995 0x19, 0x000, /* -12dB ADC/L */
1996 0x1a, 0x000, /* -12dB ADC/R */
1997 (unsigned short)-1
1998 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01001999 static const unsigned short wm_inits_prodigy[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000
2001 /* These come first to reduce init pop noise */
2002 0x1b, 0x000, /* ADC Mux */
2003 0x1c, 0x009, /* Out Mux1 */
2004 0x1d, 0x009, /* Out Mux2 */
2005
2006 0x18, 0x000, /* All power-up */
2007
2008 0x16, 0x022, /* I2S, normal polarity, 24bit, high-pass on */
2009 0x17, 0x006, /* 128fs, slave mode */
2010
2011 0x00, 0, /* DAC1 analog mute */
2012 0x01, 0, /* DAC2 analog mute */
2013 0x02, 0, /* DAC3 analog mute */
2014 0x03, 0, /* DAC4 analog mute */
2015 0x04, 0, /* DAC5 analog mute */
2016 0x05, 0, /* DAC6 analog mute */
2017 0x06, 0, /* DAC7 analog mute */
2018 0x07, 0, /* DAC8 analog mute */
2019 0x08, 0x100, /* master analog mute */
2020
2021 0x09, 0x7f, /* DAC1 digital full */
2022 0x0a, 0x7f, /* DAC2 digital full */
2023 0x0b, 0x7f, /* DAC3 digital full */
2024 0x0c, 0x7f, /* DAC4 digital full */
2025 0x0d, 0x7f, /* DAC5 digital full */
2026 0x0e, 0x7f, /* DAC6 digital full */
2027 0x0f, 0x7f, /* DAC7 digital full */
2028 0x10, 0x7f, /* DAC8 digital full */
2029 0x11, 0x1FF, /* master digital full */
2030
2031 0x12, 0x000, /* phase normal */
2032 0x13, 0x090, /* unmute DAC L/R */
2033 0x14, 0x000, /* all unmute */
2034 0x15, 0x000, /* no deemphasis, no ZFLG */
2035
2036 0x19, 0x000, /* -12dB ADC/L */
2037 0x1a, 0x000, /* -12dB ADC/R */
2038 (unsigned short)-1
2039
2040 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01002041 static const unsigned short cs_inits[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 0x0441, /* RUN */
2043 0x0180, /* no mute, OMCK output on RMCK pin */
2044 0x0201, /* S/PDIF source on RXP1 */
2045 0x0605, /* slave, 24bit, MSB on second OSCLK, SDOUT for right channel when OLRCK is high */
2046 (unsigned short)-1
2047 };
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01002048 struct aureon_spec *spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 unsigned int tmp;
Takashi Iwai32b47da2007-01-29 15:26:36 +01002050 const unsigned short *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051 int err, i;
2052
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01002053 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
2054 if (!spec)
2055 return -ENOMEM;
2056 ice->spec = spec;
2057
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) {
2059 ice->num_total_dacs = 6;
2060 ice->num_total_adcs = 2;
2061 } else {
2062 /* aureon 7.1 and prodigy 7.1 */
2063 ice->num_total_dacs = 8;
2064 ice->num_total_adcs = 2;
2065 }
2066
2067 /* to remeber the register values of CS8415 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01002068 ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04002069 if (!ice->akm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 return -ENOMEM;
2071 ice->akm_codecs = 1;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04002072
2073 err = aureon_ac97_init(ice);
2074 if (err != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 return err;
2076
2077 snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for the time being */
2078
2079 /* reset the wm codec as the SPI mode */
2080 snd_ice1712_save_gpio_status(ice);
2081 snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RESET|AUREON_WM_CS|AUREON_CS8415_CS|AUREON_HP_SEL));
2082
2083 tmp = snd_ice1712_gpio_read(ice);
2084 tmp &= ~AUREON_WM_RESET;
2085 snd_ice1712_gpio_write(ice, tmp);
2086 udelay(1);
2087 tmp |= AUREON_WM_CS | AUREON_CS8415_CS;
2088 snd_ice1712_gpio_write(ice, tmp);
2089 udelay(1);
2090 tmp |= AUREON_WM_RESET;
2091 snd_ice1712_gpio_write(ice, tmp);
2092 udelay(1);
2093
2094 /* initialize WM8770 codec */
Takashi Iwai45fe7222006-01-13 13:50:16 +01002095 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71 ||
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01002096 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04002097 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 p = wm_inits_prodigy;
2099 else
2100 p = wm_inits_aureon;
2101 for (; *p != (unsigned short)-1; p += 2)
2102 wm_put(ice, p[0], p[1]);
2103
2104 /* initialize CS8415A codec */
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01002105 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
2106 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
Takashi Iwai45fe7222006-01-13 13:50:16 +01002107 for (p = cs_inits; *p != (unsigned short)-1; p++)
2108 aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01002109 spec->cs8415_mux = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110
Takashi Iwai45fe7222006-01-13 13:50:16 +01002111 aureon_set_headphone_amp(ice, 1);
2112 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113
2114 snd_ice1712_restore_gpio_status(ice);
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +02002115
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04002116 /* initialize PCA9554 pin directions & set default input */
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +02002117 aureon_pca9554_write(ice, PCA9554_DIR, 0x00);
2118 aureon_pca9554_write(ice, PCA9554_OUT, 0x00); /* internal AUX */
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04002119
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01002120 spec->master[0] = WM_VOL_MUTE;
2121 spec->master[1] = WM_VOL_MUTE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 for (i = 0; i < ice->num_total_dacs; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01002123 spec->vol[i] = WM_VOL_MUTE;
2124 wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 }
2126
2127 return 0;
2128}
2129
2130
2131/*
2132 * Aureon boards don't provide the EEPROM data except for the vendor IDs.
2133 * hence the driver needs to sets up it properly.
2134 */
2135
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01002136static unsigned char aureon51_eeprom[] __devinitdata = {
Takashi Iwai189bc172007-01-29 15:25:40 +01002137 [ICE_EEP2_SYSCONF] = 0x0a, /* clock 512, spdif-in/ADC, 3DACs */
2138 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
2139 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
2140 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
2141 [ICE_EEP2_GPIO_DIR] = 0xff,
2142 [ICE_EEP2_GPIO_DIR1] = 0xff,
2143 [ICE_EEP2_GPIO_DIR2] = 0x5f,
2144 [ICE_EEP2_GPIO_MASK] = 0x00,
2145 [ICE_EEP2_GPIO_MASK1] = 0x00,
2146 [ICE_EEP2_GPIO_MASK2] = 0x00,
2147 [ICE_EEP2_GPIO_STATE] = 0x00,
2148 [ICE_EEP2_GPIO_STATE1] = 0x00,
2149 [ICE_EEP2_GPIO_STATE2] = 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150};
2151
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01002152static unsigned char aureon71_eeprom[] __devinitdata = {
Takashi Iwai189bc172007-01-29 15:25:40 +01002153 [ICE_EEP2_SYSCONF] = 0x0b, /* clock 512, spdif-in/ADC, 4DACs */
2154 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
2155 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
2156 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
2157 [ICE_EEP2_GPIO_DIR] = 0xff,
2158 [ICE_EEP2_GPIO_DIR1] = 0xff,
2159 [ICE_EEP2_GPIO_DIR2] = 0x5f,
2160 [ICE_EEP2_GPIO_MASK] = 0x00,
2161 [ICE_EEP2_GPIO_MASK1] = 0x00,
2162 [ICE_EEP2_GPIO_MASK2] = 0x00,
2163 [ICE_EEP2_GPIO_STATE] = 0x00,
2164 [ICE_EEP2_GPIO_STATE1] = 0x00,
2165 [ICE_EEP2_GPIO_STATE2] = 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166};
Takashi Iwai189bc172007-01-29 15:25:40 +01002167#define prodigy71_eeprom aureon71_eeprom
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168
Maximilian Rehkopfc1805dd2008-08-29 14:11:10 +02002169static unsigned char aureon71_universe_eeprom[] __devinitdata = {
2170 [ICE_EEP2_SYSCONF] = 0x2b, /* clock 512, mpu401, spdif-in/ADC,
2171 * 4DACs
2172 */
2173 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
2174 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
2175 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
2176 [ICE_EEP2_GPIO_DIR] = 0xff,
2177 [ICE_EEP2_GPIO_DIR1] = 0xff,
2178 [ICE_EEP2_GPIO_DIR2] = 0x5f,
2179 [ICE_EEP2_GPIO_MASK] = 0x00,
2180 [ICE_EEP2_GPIO_MASK1] = 0x00,
2181 [ICE_EEP2_GPIO_MASK2] = 0x00,
2182 [ICE_EEP2_GPIO_STATE] = 0x00,
2183 [ICE_EEP2_GPIO_STATE1] = 0x00,
2184 [ICE_EEP2_GPIO_STATE2] = 0x00,
2185};
2186
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01002187static unsigned char prodigy71lt_eeprom[] __devinitdata = {
Takashi Iwai189bc172007-01-29 15:25:40 +01002188 [ICE_EEP2_SYSCONF] = 0x4b, /* clock 384, spdif-in/ADC, 4DACs */
2189 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
2190 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
2191 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
2192 [ICE_EEP2_GPIO_DIR] = 0xff,
2193 [ICE_EEP2_GPIO_DIR1] = 0xff,
2194 [ICE_EEP2_GPIO_DIR2] = 0x5f,
2195 [ICE_EEP2_GPIO_MASK] = 0x00,
2196 [ICE_EEP2_GPIO_MASK1] = 0x00,
2197 [ICE_EEP2_GPIO_MASK2] = 0x00,
2198 [ICE_EEP2_GPIO_STATE] = 0x00,
2199 [ICE_EEP2_GPIO_STATE1] = 0x00,
2200 [ICE_EEP2_GPIO_STATE2] = 0x00,
Takashi Iwai45fe7222006-01-13 13:50:16 +01002201};
Takashi Iwai189bc172007-01-29 15:25:40 +01002202#define prodigy71xt_eeprom prodigy71lt_eeprom
Takashi Iwai45fe7222006-01-13 13:50:16 +01002203
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204/* entry point */
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01002205struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206 {
2207 .subvendor = VT1724_SUBDEVICE_AUREON51_SKY,
2208 .name = "Terratec Aureon 5.1-Sky",
2209 .model = "aureon51",
2210 .chip_init = aureon_init,
2211 .build_controls = aureon_add_controls,
2212 .eeprom_size = sizeof(aureon51_eeprom),
2213 .eeprom_data = aureon51_eeprom,
2214 .driver = "Aureon51",
2215 },
2216 {
2217 .subvendor = VT1724_SUBDEVICE_AUREON71_SPACE,
2218 .name = "Terratec Aureon 7.1-Space",
2219 .model = "aureon71",
2220 .chip_init = aureon_init,
2221 .build_controls = aureon_add_controls,
2222 .eeprom_size = sizeof(aureon71_eeprom),
2223 .eeprom_data = aureon71_eeprom,
2224 .driver = "Aureon71",
2225 },
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04002226 {
2227 .subvendor = VT1724_SUBDEVICE_AUREON71_UNIVERSE,
2228 .name = "Terratec Aureon 7.1-Universe",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 .model = "universe",
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04002230 .chip_init = aureon_init,
2231 .build_controls = aureon_add_controls,
Maximilian Rehkopfc1805dd2008-08-29 14:11:10 +02002232 .eeprom_size = sizeof(aureon71_universe_eeprom),
2233 .eeprom_data = aureon71_universe_eeprom,
Takashi Iwai9f37c5b2006-06-29 16:40:21 +02002234 .driver = "Aureon71Univ", /* keep in 15 letters */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 },
2236 {
2237 .subvendor = VT1724_SUBDEVICE_PRODIGY71,
2238 .name = "Audiotrak Prodigy 7.1",
2239 .model = "prodigy71",
2240 .chip_init = aureon_init,
2241 .build_controls = aureon_add_controls,
2242 .eeprom_size = sizeof(prodigy71_eeprom),
2243 .eeprom_data = prodigy71_eeprom,
2244 .driver = "Prodigy71", /* should be identical with Aureon71 */
2245 },
Takashi Iwai45fe7222006-01-13 13:50:16 +01002246 {
2247 .subvendor = VT1724_SUBDEVICE_PRODIGY71LT,
2248 .name = "Audiotrak Prodigy 7.1 LT",
2249 .model = "prodigy71lt",
2250 .chip_init = aureon_init,
2251 .build_controls = aureon_add_controls,
2252 .eeprom_size = sizeof(prodigy71lt_eeprom),
2253 .eeprom_data = prodigy71lt_eeprom,
2254 .driver = "Prodigy71LT",
2255 },
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01002256 {
2257 .subvendor = VT1724_SUBDEVICE_PRODIGY71XT,
2258 .name = "Audiotrak Prodigy 7.1 XT",
2259 .model = "prodigy71xt",
2260 .chip_init = aureon_init,
2261 .build_controls = aureon_add_controls,
2262 .eeprom_size = sizeof(prodigy71xt_eeprom),
2263 .eeprom_data = prodigy71xt_eeprom,
2264 .driver = "Prodigy71LT",
2265 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 { } /* terminator */
2267};