blob: 2d6bf80cb0607a3eafb0f7dcf8978ba011a93a3b [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,
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300151 * skipping ack cycles in between
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200152 */
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{
Takashi Iwaia2af0502012-10-17 09:21:48 +0200206 static const char * const texts[3] =
207 {"Internal Aux", "Wavetable", "Rear Line-In"};
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200208
209 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
210 uinfo->count = 1;
211 uinfo->value.enumerated.items = 3;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400212 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200213 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
214 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
215 return 0;
216}
217
218static int aureon_universe_inmux_get(struct snd_kcontrol *kcontrol,
219 struct snd_ctl_elem_value *ucontrol)
220{
221 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100222 struct aureon_spec *spec = ice->spec;
223 ucontrol->value.enumerated.item[0] = spec->pca9554_out;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200224 return 0;
225}
226
227static int aureon_universe_inmux_put(struct snd_kcontrol *kcontrol,
228 struct snd_ctl_elem_value *ucontrol)
229{
230 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100231 struct aureon_spec *spec = ice->spec;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200232 unsigned char oval, nval;
233 int change;
234
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100235 nval = ucontrol->value.enumerated.item[0];
236 if (nval >= 3)
237 return -EINVAL;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200238 snd_ice1712_save_gpio_status(ice);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100239 oval = spec->pca9554_out;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400240 change = (oval != nval);
241 if (change) {
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200242 aureon_pca9554_write(ice, PCA9554_OUT, nval);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100243 spec->pca9554_out = nval;
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200244 }
245 snd_ice1712_restore_gpio_status(ice);
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200246 return change;
247}
248
249
250static void aureon_ac97_write(struct snd_ice1712 *ice, unsigned short reg,
251 unsigned short val)
252{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100253 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 unsigned int tmp;
255
256 /* Send address to XILINX chip */
257 tmp = (snd_ice1712_gpio_read(ice) & ~0xFF) | (reg & 0x7F);
258 snd_ice1712_gpio_write(ice, tmp);
259 udelay(10);
260 tmp |= AUREON_AC97_ADDR;
261 snd_ice1712_gpio_write(ice, tmp);
262 udelay(10);
263 tmp &= ~AUREON_AC97_ADDR;
264 snd_ice1712_gpio_write(ice, tmp);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400265 udelay(10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
267 /* Send low-order byte to XILINX chip */
268 tmp &= ~AUREON_AC97_DATA_MASK;
269 tmp |= val & AUREON_AC97_DATA_MASK;
270 snd_ice1712_gpio_write(ice, tmp);
271 udelay(10);
272 tmp |= AUREON_AC97_DATA_LOW;
273 snd_ice1712_gpio_write(ice, tmp);
274 udelay(10);
275 tmp &= ~AUREON_AC97_DATA_LOW;
276 snd_ice1712_gpio_write(ice, tmp);
277 udelay(10);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400278
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 /* Send high-order byte to XILINX chip */
280 tmp &= ~AUREON_AC97_DATA_MASK;
281 tmp |= (val >> 8) & AUREON_AC97_DATA_MASK;
282
283 snd_ice1712_gpio_write(ice, tmp);
284 udelay(10);
285 tmp |= AUREON_AC97_DATA_HIGH;
286 snd_ice1712_gpio_write(ice, tmp);
287 udelay(10);
288 tmp &= ~AUREON_AC97_DATA_HIGH;
289 snd_ice1712_gpio_write(ice, tmp);
290 udelay(10);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400291
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 /* Instruct XILINX chip to parse the data to the STAC9744 chip */
293 tmp |= AUREON_AC97_COMMIT;
294 snd_ice1712_gpio_write(ice, tmp);
295 udelay(10);
296 tmp &= ~AUREON_AC97_COMMIT;
297 snd_ice1712_gpio_write(ice, tmp);
298 udelay(10);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400299
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 /* Store the data in out private buffer */
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100301 spec->stac9744[(reg & 0x7F) >> 1] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302}
303
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100304static unsigned short aureon_ac97_read(struct snd_ice1712 *ice, unsigned short reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100306 struct aureon_spec *spec = ice->spec;
307 return spec->stac9744[(reg & 0x7F) >> 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308}
309
310/*
311 * Initialize STAC9744 chip
312 */
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400313static int aureon_ac97_init(struct snd_ice1712 *ice)
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +0200314{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100315 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 int i;
Takashi Iwai32b47da2007-01-29 15:26:36 +0100317 static const unsigned short ac97_defaults[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 0x00, 0x9640,
319 0x02, 0x8000,
320 0x04, 0x8000,
321 0x06, 0x8000,
322 0x0C, 0x8008,
323 0x0E, 0x8008,
324 0x10, 0x8808,
325 0x12, 0x8808,
326 0x14, 0x8808,
327 0x16, 0x8808,
328 0x18, 0x8808,
329 0x1C, 0x8000,
330 0x26, 0x000F,
331 0x28, 0x0201,
332 0x2C, 0xBB80,
333 0x32, 0xBB80,
334 0x7C, 0x8384,
335 0x7E, 0x7644,
336 (unsigned short)-1
337 };
338 unsigned int tmp;
339
340 /* Cold reset */
341 tmp = (snd_ice1712_gpio_read(ice) | AUREON_AC97_RESET) & ~AUREON_AC97_DATA_MASK;
342 snd_ice1712_gpio_write(ice, tmp);
343 udelay(3);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400344
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 tmp &= ~AUREON_AC97_RESET;
346 snd_ice1712_gpio_write(ice, tmp);
347 udelay(3);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400348
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 tmp |= AUREON_AC97_RESET;
350 snd_ice1712_gpio_write(ice, tmp);
351 udelay(3);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400352
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100353 memset(&spec->stac9744, 0, sizeof(spec->stac9744));
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400354 for (i = 0; ac97_defaults[i] != (unsigned short)-1; i += 2)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100355 spec->stac9744[(ac97_defaults[i]) >> 1] = ac97_defaults[i+1];
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400356
357 /* Unmute AC'97 master volume permanently - muting is done by WM8770 */
358 aureon_ac97_write(ice, AC97_MASTER, 0x0000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
360 return 0;
361}
362
363#define AUREON_AC97_STEREO 0x80
364
365/*
366 * AC'97 volume controls
367 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100368static int aureon_ac97_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369{
370 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
371 uinfo->count = kcontrol->private_value & AUREON_AC97_STEREO ? 2 : 1;
372 uinfo->value.integer.min = 0;
373 uinfo->value.integer.max = 31;
374 return 0;
375}
376
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100377static int aureon_ac97_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100379 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 unsigned short vol;
381
Ingo Molnar62932df2006-01-16 16:34:20 +0100382 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
384 vol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
385 ucontrol->value.integer.value[0] = 0x1F - (vol & 0x1F);
386 if (kcontrol->private_value & AUREON_AC97_STEREO)
387 ucontrol->value.integer.value[1] = 0x1F - ((vol >> 8) & 0x1F);
388
Ingo Molnar62932df2006-01-16 16:34:20 +0100389 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 return 0;
391}
392
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100393static int aureon_ac97_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100395 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 unsigned short ovol, nvol;
397 int change;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400398
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 snd_ice1712_save_gpio_status(ice);
400
401 ovol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
402 nvol = (0x1F - ucontrol->value.integer.value[0]) & 0x001F;
403 if (kcontrol->private_value & AUREON_AC97_STEREO)
404 nvol |= ((0x1F - ucontrol->value.integer.value[1]) << 8) & 0x1F00;
405 nvol |= ovol & ~0x1F1F;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400406
407 change = (ovol != nvol);
408 if (change)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 aureon_ac97_write(ice, kcontrol->private_value & 0x7F, nvol);
410
411 snd_ice1712_restore_gpio_status(ice);
412
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400413 return change;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414}
415
416/*
417 * AC'97 mute controls
418 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200419#define aureon_ac97_mute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100421static int aureon_ac97_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100423 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424
Ingo Molnar62932df2006-01-16 16:34:20 +0100425 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400427 ucontrol->value.integer.value[0] = aureon_ac97_read(ice,
428 kcontrol->private_value & 0x7F) & 0x8000 ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429
Ingo Molnar62932df2006-01-16 16:34:20 +0100430 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 return 0;
432}
433
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100434static int aureon_ac97_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100436 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 unsigned short ovol, nvol;
438 int change;
439
440 snd_ice1712_save_gpio_status(ice);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400441
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 ovol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400443 nvol = (ucontrol->value.integer.value[0] ? 0x0000 : 0x8000) | (ovol & ~0x8000);
444
445 change = (ovol != nvol);
446 if (change)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 aureon_ac97_write(ice, kcontrol->private_value & 0x7F, nvol);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400448
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 snd_ice1712_restore_gpio_status(ice);
450
451 return change;
452}
453
454/*
455 * AC'97 mute controls
456 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200457#define aureon_ac97_micboost_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100459static int aureon_ac97_micboost_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100461 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462
Ingo Molnar62932df2006-01-16 16:34:20 +0100463 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464
465 ucontrol->value.integer.value[0] = aureon_ac97_read(ice, AC97_MIC) & 0x0020 ? 0 : 1;
466
Ingo Molnar62932df2006-01-16 16:34:20 +0100467 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 return 0;
469}
470
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100471static int aureon_ac97_micboost_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100473 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 unsigned short ovol, nvol;
475 int change;
476
477 snd_ice1712_save_gpio_status(ice);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400478
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 ovol = aureon_ac97_read(ice, AC97_MIC);
480 nvol = (ucontrol->value.integer.value[0] ? 0x0000 : 0x0020) | (ovol & ~0x0020);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400481
482 change = (ovol != nvol);
483 if (change)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 aureon_ac97_write(ice, AC97_MIC, nvol);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400485
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 snd_ice1712_restore_gpio_status(ice);
487
488 return change;
489}
490
491/*
492 * write data in the SPI mode
493 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100494static void aureon_spi_write(struct snd_ice1712 *ice, unsigned int cs, unsigned int data, int bits)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495{
496 unsigned int tmp;
497 int i;
Takashi Iwai45fe7222006-01-13 13:50:16 +0100498 unsigned int mosi, clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499
500 tmp = snd_ice1712_gpio_read(ice);
501
Toshimune Konnocdf88ef2006-12-18 13:12:18 +0100502 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
503 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) {
Takashi Iwai45fe7222006-01-13 13:50:16 +0100504 snd_ice1712_gpio_set_mask(ice, ~(PRODIGY_SPI_MOSI|PRODIGY_SPI_CLK|PRODIGY_WM_CS));
505 mosi = PRODIGY_SPI_MOSI;
506 clk = PRODIGY_SPI_CLK;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400507 } else {
Takashi Iwai45fe7222006-01-13 13:50:16 +0100508 snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RW|AUREON_SPI_MOSI|AUREON_SPI_CLK|
509 AUREON_WM_CS|AUREON_CS8415_CS));
510 mosi = AUREON_SPI_MOSI;
511 clk = AUREON_SPI_CLK;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400512
Takashi Iwai45fe7222006-01-13 13:50:16 +0100513 tmp |= AUREON_WM_RW;
514 }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400515
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 tmp &= ~cs;
517 snd_ice1712_gpio_write(ice, tmp);
518 udelay(1);
519
520 for (i = bits - 1; i >= 0; i--) {
Takashi Iwai45fe7222006-01-13 13:50:16 +0100521 tmp &= ~clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 snd_ice1712_gpio_write(ice, tmp);
523 udelay(1);
524 if (data & (1 << i))
Takashi Iwai45fe7222006-01-13 13:50:16 +0100525 tmp |= mosi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 else
Takashi Iwai45fe7222006-01-13 13:50:16 +0100527 tmp &= ~mosi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 snd_ice1712_gpio_write(ice, tmp);
529 udelay(1);
Takashi Iwai45fe7222006-01-13 13:50:16 +0100530 tmp |= clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 snd_ice1712_gpio_write(ice, tmp);
532 udelay(1);
533 }
534
Takashi Iwai45fe7222006-01-13 13:50:16 +0100535 tmp &= ~clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 tmp |= cs;
537 snd_ice1712_gpio_write(ice, tmp);
538 udelay(1);
Takashi Iwai45fe7222006-01-13 13:50:16 +0100539 tmp |= clk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 snd_ice1712_gpio_write(ice, tmp);
541 udelay(1);
542}
543
544/*
545 * Read data in SPI mode
546 */
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400547static void aureon_spi_read(struct snd_ice1712 *ice, unsigned int cs,
548 unsigned int data, int bits, unsigned char *buffer, int size)
549{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 int i, j;
551 unsigned int tmp;
552
553 tmp = (snd_ice1712_gpio_read(ice) & ~AUREON_SPI_CLK) | AUREON_CS8415_CS|AUREON_WM_CS;
554 snd_ice1712_gpio_write(ice, tmp);
555 tmp &= ~cs;
556 snd_ice1712_gpio_write(ice, tmp);
557 udelay(1);
558
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400559 for (i = bits-1; i >= 0; i--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 if (data & (1 << i))
561 tmp |= AUREON_SPI_MOSI;
562 else
563 tmp &= ~AUREON_SPI_MOSI;
564 snd_ice1712_gpio_write(ice, tmp);
565 udelay(1);
566
567 tmp |= AUREON_SPI_CLK;
568 snd_ice1712_gpio_write(ice, tmp);
569 udelay(1);
570
571 tmp &= ~AUREON_SPI_CLK;
572 snd_ice1712_gpio_write(ice, tmp);
573 udelay(1);
574 }
575
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400576 for (j = 0; j < size; j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 unsigned char outdata = 0;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400578 for (i = 7; i >= 0; i--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 tmp = snd_ice1712_gpio_read(ice);
580 outdata <<= 1;
581 outdata |= (tmp & AUREON_SPI_MISO) ? 1 : 0;
582 udelay(1);
583
584 tmp |= AUREON_SPI_CLK;
585 snd_ice1712_gpio_write(ice, tmp);
586 udelay(1);
587
588 tmp &= ~AUREON_SPI_CLK;
589 snd_ice1712_gpio_write(ice, tmp);
590 udelay(1);
591 }
592 buffer[j] = outdata;
593 }
594
595 tmp |= cs;
596 snd_ice1712_gpio_write(ice, tmp);
597}
598
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400599static unsigned char aureon_cs8415_get(struct snd_ice1712 *ice, int reg)
600{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 unsigned char val;
602 aureon_spi_write(ice, AUREON_CS8415_CS, 0x2000 | reg, 16);
603 aureon_spi_read(ice, AUREON_CS8415_CS, 0x21, 8, &val, 1);
604 return val;
605}
606
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400607static void aureon_cs8415_read(struct snd_ice1712 *ice, int reg,
608 unsigned char *buffer, int size)
609{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 aureon_spi_write(ice, AUREON_CS8415_CS, 0x2000 | reg, 16);
611 aureon_spi_read(ice, AUREON_CS8415_CS, 0x21, 8, buffer, size);
612}
613
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400614static void aureon_cs8415_put(struct snd_ice1712 *ice, int reg,
615 unsigned char val)
616{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 aureon_spi_write(ice, AUREON_CS8415_CS, 0x200000 | (reg << 8) | val, 24);
618}
619
620/*
621 * get the current register value of WM codec
622 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100623static unsigned short wm_get(struct snd_ice1712 *ice, int reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624{
625 reg <<= 1;
626 return ((unsigned short)ice->akm[0].images[reg] << 8) |
627 ice->akm[0].images[reg + 1];
628}
629
630/*
631 * set the register value of WM codec
632 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100633static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634{
Takashi Iwai45fe7222006-01-13 13:50:16 +0100635 aureon_spi_write(ice,
Toshimune Konnocdf88ef2006-12-18 13:12:18 +0100636 ((ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
637 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) ?
638 PRODIGY_WM_CS : AUREON_WM_CS),
Takashi Iwai45fe7222006-01-13 13:50:16 +0100639 (reg << 9) | (val & 0x1ff), 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640}
641
642/*
643 * set the register value of WM codec and remember it
644 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100645static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646{
647 wm_put_nocache(ice, reg, val);
648 reg <<= 1;
649 ice->akm[0].images[reg] = val >> 8;
650 ice->akm[0].images[reg + 1] = val;
651}
652
653/*
654 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200655#define aureon_mono_bool_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
657/*
658 * AC'97 master playback mute controls (Mute on WM8770 chip)
659 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200660#define aureon_ac97_mmute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100662static int aureon_ac97_mmute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100664 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665
Ingo Molnar62932df2006-01-16 16:34:20 +0100666 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
668 ucontrol->value.integer.value[0] = (wm_get(ice, WM_OUT_MUX1) >> 1) & 0x01;
669
Ingo Molnar62932df2006-01-16 16:34:20 +0100670 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 return 0;
672}
673
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400674static int aureon_ac97_mmute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
675{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100676 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 unsigned short ovol, nvol;
678 int change;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400679
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 snd_ice1712_save_gpio_status(ice);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400681
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 ovol = wm_get(ice, WM_OUT_MUX1);
683 nvol = (ovol & ~0x02) | (ucontrol->value.integer.value[0] ? 0x02 : 0x00);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400684 change = (ovol != nvol);
685 if (change)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 wm_put(ice, WM_OUT_MUX1, nvol);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400687
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 snd_ice1712_restore_gpio_status(ice);
689
690 return change;
691}
692
Jaroslav Kysela482e46d2009-12-09 12:43:44 +0100693static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -10000, 100, 1);
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100694static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
695static const DECLARE_TLV_DB_SCALE(db_scale_wm_adc, -1200, 100, 0);
696static const DECLARE_TLV_DB_SCALE(db_scale_ac97_master, -4650, 150, 0);
697static const DECLARE_TLV_DB_SCALE(db_scale_ac97_gain, -3450, 150, 0);
Takashi Iwaif640c322006-08-30 16:57:37 +0200698
Jaroslav Kysela482e46d2009-12-09 12:43:44 +0100699#define WM_VOL_MAX 100
700#define WM_VOL_CNT 101 /* 0dB .. -100dB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701#define WM_VOL_MUTE 0x8000
702
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100703static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, unsigned short vol, unsigned short master)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704{
705 unsigned char nvol;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400706
Jaroslav Kysela9d4c74642010-02-05 10:19:41 +0100707 if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 nvol = 0;
Jaroslav Kysela9d4c74642010-02-05 10:19:41 +0100709 } else {
Jaroslav Kysela482e46d2009-12-09 12:43:44 +0100710 nvol = ((vol % WM_VOL_CNT) * (master % WM_VOL_CNT)) /
711 WM_VOL_MAX;
Jaroslav Kysela9d4c74642010-02-05 10:19:41 +0100712 nvol += 0x1b;
713 }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400714
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 wm_put(ice, index, nvol);
716 wm_put_nocache(ice, index, 0x180 | nvol);
717}
718
719/*
720 * DAC mute control
721 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200722#define wm_pcm_mute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100724static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100726 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727
Ingo Molnar62932df2006-01-16 16:34:20 +0100728 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1;
Ingo Molnar62932df2006-01-16 16:34:20 +0100730 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 return 0;
732}
733
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100734static int wm_pcm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100736 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 unsigned short nval, oval;
738 int change;
739
740 snd_ice1712_save_gpio_status(ice);
741 oval = wm_get(ice, WM_MUTE);
742 nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400743 change = (oval != nval);
744 if (change)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 wm_put(ice, WM_MUTE, nval);
746 snd_ice1712_restore_gpio_status(ice);
747
748 return change;
749}
750
751/*
752 * Master volume attenuation mixer control
753 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100754static int wm_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755{
756 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
757 uinfo->count = 2;
758 uinfo->value.integer.min = 0;
759 uinfo->value.integer.max = WM_VOL_MAX;
760 return 0;
761}
762
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100763static int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100765 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100766 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 int i;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400768 for (i = 0; i < 2; i++)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100769 ucontrol->value.integer.value[i] =
770 spec->master[i] & ~WM_VOL_MUTE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 return 0;
772}
773
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100774static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100776 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100777 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 int ch, change = 0;
779
780 snd_ice1712_save_gpio_status(ice);
781 for (ch = 0; ch < 2; ch++) {
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100782 unsigned int vol = ucontrol->value.integer.value[ch];
783 if (vol > WM_VOL_MAX)
Jaroslav Kysela9d4c74642010-02-05 10:19:41 +0100784 vol = WM_VOL_MAX;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100785 vol |= spec->master[ch] & WM_VOL_MUTE;
786 if (vol != spec->master[ch]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 int dac;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100788 spec->master[ch] = vol;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
790 wm_set_vol(ice, WM_DAC_ATTEN + dac + ch,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100791 spec->vol[dac + ch],
792 spec->master[ch]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 change = 1;
794 }
795 }
796 snd_ice1712_restore_gpio_status(ice);
797 return change;
798}
799
800/*
801 * DAC volume attenuation mixer control
802 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100803static int wm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804{
805 int voices = kcontrol->private_value >> 8;
806 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
807 uinfo->count = voices;
808 uinfo->value.integer.min = 0; /* mute (-101dB) */
Jaroslav Kysela482e46d2009-12-09 12:43:44 +0100809 uinfo->value.integer.max = WM_VOL_MAX; /* 0dB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 return 0;
811}
812
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100813static int wm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100815 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100816 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 int i, ofs, voices;
818
819 voices = kcontrol->private_value >> 8;
820 ofs = kcontrol->private_value & 0xff;
821 for (i = 0; i < voices; i++)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100822 ucontrol->value.integer.value[i] =
823 spec->vol[ofs+i] & ~WM_VOL_MUTE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 return 0;
825}
826
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100827static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100829 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100830 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 int i, idx, ofs, voices;
832 int change = 0;
833
834 voices = kcontrol->private_value >> 8;
835 ofs = kcontrol->private_value & 0xff;
836 snd_ice1712_save_gpio_status(ice);
837 for (i = 0; i < voices; i++) {
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100838 unsigned int vol = ucontrol->value.integer.value[i];
Jaroslav Kysela482e46d2009-12-09 12:43:44 +0100839 if (vol > WM_VOL_MAX)
Jaroslav Kysela9d4c74642010-02-05 10:19:41 +0100840 vol = WM_VOL_MAX;
841 vol |= spec->vol[ofs+i] & WM_VOL_MUTE;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100842 if (vol != spec->vol[ofs+i]) {
843 spec->vol[ofs+i] = vol;
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100844 idx = WM_DAC_ATTEN + ofs + i;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100845 wm_set_vol(ice, idx, spec->vol[ofs + i],
846 spec->master[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 change = 1;
848 }
849 }
850 snd_ice1712_restore_gpio_status(ice);
851 return change;
852}
853
854/*
855 * WM8770 mute control
856 */
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400857static int wm_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
858{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
860 uinfo->count = kcontrol->private_value >> 8;
861 uinfo->value.integer.min = 0;
862 uinfo->value.integer.max = 1;
863 return 0;
864}
865
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100866static int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100868 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100869 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 int voices, ofs, i;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400871
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 voices = kcontrol->private_value >> 8;
873 ofs = kcontrol->private_value & 0xFF;
874
875 for (i = 0; i < voices; i++)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100876 ucontrol->value.integer.value[i] =
877 (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 return 0;
879}
880
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100881static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100883 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100884 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 int change = 0, voices, ofs, i;
886
887 voices = kcontrol->private_value >> 8;
888 ofs = kcontrol->private_value & 0xFF;
889
890 snd_ice1712_save_gpio_status(ice);
891 for (i = 0; i < voices; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100892 int val = (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 if (ucontrol->value.integer.value[i] != val) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100894 spec->vol[ofs + i] &= ~WM_VOL_MUTE;
895 spec->vol[ofs + i] |=
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100897 wm_set_vol(ice, ofs + i, spec->vol[ofs + i],
898 spec->master[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 change = 1;
900 }
901 }
902 snd_ice1712_restore_gpio_status(ice);
903
904 return change;
905}
906
907/*
908 * WM8770 master mute control
909 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200910#define wm_master_mute_info snd_ctl_boolean_stereo_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100912static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100914 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100915 struct aureon_spec *spec = ice->spec;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +0400916
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100917 ucontrol->value.integer.value[0] =
918 (spec->master[0] & WM_VOL_MUTE) ? 0 : 1;
919 ucontrol->value.integer.value[1] =
920 (spec->master[1] & WM_VOL_MUTE) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 return 0;
922}
923
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100924static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100926 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100927 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 int change = 0, i;
929
930 snd_ice1712_save_gpio_status(ice);
931 for (i = 0; i < 2; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100932 int val = (spec->master[i] & WM_VOL_MUTE) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 if (ucontrol->value.integer.value[i] != val) {
934 int dac;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100935 spec->master[i] &= ~WM_VOL_MUTE;
936 spec->master[i] |=
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
938 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
939 wm_set_vol(ice, WM_DAC_ATTEN + dac + i,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100940 spec->vol[dac + i],
941 spec->master[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 change = 1;
943 }
944 }
945 snd_ice1712_restore_gpio_status(ice);
946
947 return change;
948}
949
950/* digital master volume */
951#define PCM_0dB 0xff
952#define PCM_RES 128 /* -64dB */
953#define PCM_MIN (PCM_0dB - PCM_RES)
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100954static int wm_pcm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955{
956 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
957 uinfo->count = 1;
958 uinfo->value.integer.min = 0; /* mute (-64dB) */
959 uinfo->value.integer.max = PCM_RES; /* 0dB */
960 return 0;
961}
962
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100963static int wm_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100965 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 unsigned short val;
967
Ingo Molnar62932df2006-01-16 16:34:20 +0100968 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
970 val = val > PCM_MIN ? (val - PCM_MIN) : 0;
971 ucontrol->value.integer.value[0] = val;
Ingo Molnar62932df2006-01-16 16:34:20 +0100972 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 return 0;
974}
975
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100976static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100978 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 unsigned short ovol, nvol;
980 int change = 0;
981
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 nvol = ucontrol->value.integer.value[0];
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100983 if (nvol > PCM_RES)
984 return -EINVAL;
985 snd_ice1712_save_gpio_status(ice);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff;
987 ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
988 if (ovol != nvol) {
989 wm_put(ice, WM_DAC_DIG_MASTER_ATTEN, nvol); /* prelatch */
990 wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100); /* update */
991 change = 1;
992 }
993 snd_ice1712_restore_gpio_status(ice);
994 return change;
995}
996
997/*
998 * ADC mute control
999 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001000#define wm_adc_mute_info snd_ctl_boolean_stereo_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001002static int wm_adc_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001004 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 unsigned short val;
1006 int i;
1007
Ingo Molnar62932df2006-01-16 16:34:20 +01001008 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 for (i = 0; i < 2; i++) {
1010 val = wm_get(ice, WM_ADC_GAIN + i);
1011 ucontrol->value.integer.value[i] = ~val>>5 & 0x1;
1012 }
Ingo Molnar62932df2006-01-16 16:34:20 +01001013 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 return 0;
1015}
1016
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001017static int wm_adc_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001019 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 unsigned short new, old;
1021 int i, change = 0;
1022
1023 snd_ice1712_save_gpio_status(ice);
1024 for (i = 0; i < 2; i++) {
1025 old = wm_get(ice, WM_ADC_GAIN + i);
1026 new = (~ucontrol->value.integer.value[i]<<5&0x20) | (old&~0x20);
1027 if (new != old) {
1028 wm_put(ice, WM_ADC_GAIN + i, new);
1029 change = 1;
1030 }
1031 }
1032 snd_ice1712_restore_gpio_status(ice);
1033
1034 return change;
1035}
1036
1037/*
1038 * ADC gain mixer control
1039 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001040static int wm_adc_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041{
1042 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1043 uinfo->count = 2;
1044 uinfo->value.integer.min = 0; /* -12dB */
1045 uinfo->value.integer.max = 0x1f; /* 19dB */
1046 return 0;
1047}
1048
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001049static int wm_adc_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001051 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 int i, idx;
1053 unsigned short vol;
1054
Ingo Molnar62932df2006-01-16 16:34:20 +01001055 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 for (i = 0; i < 2; i++) {
1057 idx = WM_ADC_GAIN + i;
1058 vol = wm_get(ice, idx) & 0x1f;
1059 ucontrol->value.integer.value[i] = vol;
1060 }
Ingo Molnar62932df2006-01-16 16:34:20 +01001061 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 return 0;
1063}
1064
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001065static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001067 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 int i, idx;
1069 unsigned short ovol, nvol;
1070 int change = 0;
1071
1072 snd_ice1712_save_gpio_status(ice);
1073 for (i = 0; i < 2; i++) {
1074 idx = WM_ADC_GAIN + i;
Takashi Iwai9cd17cd2007-11-15 15:56:07 +01001075 nvol = ucontrol->value.integer.value[i] & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 ovol = wm_get(ice, idx);
1077 if ((ovol & 0x1f) != nvol) {
1078 wm_put(ice, idx, nvol | (ovol & ~0x1f));
1079 change = 1;
1080 }
1081 }
1082 snd_ice1712_restore_gpio_status(ice);
1083 return change;
1084}
1085
1086/*
1087 * ADC input mux mixer control
1088 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001089static int wm_adc_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090{
Takashi Iwai32b47da2007-01-29 15:26:36 +01001091 static const char * const texts[] = {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001092 "CD", /* AIN1 */
1093 "Aux", /* AIN2 */
1094 "Line", /* AIN3 */
1095 "Mic", /* AIN4 */
1096 "AC97" /* AIN5 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01001098 static const char * const universe_texts[] = {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001099 "Aux1", /* AIN1 */
1100 "CD", /* AIN2 */
1101 "Phono", /* AIN3 */
1102 "Line", /* AIN4 */
1103 "Aux2", /* AIN5 */
1104 "Mic", /* AIN6 */
1105 "Aux3", /* AIN7 */
1106 "AC97" /* AIN8 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 };
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001108 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109
1110 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1111 uinfo->count = 2;
1112 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) {
1113 uinfo->value.enumerated.items = 8;
1114 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1115 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1116 strcpy(uinfo->value.enumerated.name, universe_texts[uinfo->value.enumerated.item]);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001117 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 uinfo->value.enumerated.items = 5;
1119 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1120 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1121 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1122 }
1123 return 0;
1124}
1125
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001126static int wm_adc_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001128 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 unsigned short val;
1130
Ingo Molnar62932df2006-01-16 16:34:20 +01001131 mutex_lock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 val = wm_get(ice, WM_ADC_MUX);
Takashi Iwai66820252006-03-20 18:31:57 +01001133 ucontrol->value.enumerated.item[0] = val & 7;
1134 ucontrol->value.enumerated.item[1] = (val >> 4) & 7;
Ingo Molnar62932df2006-01-16 16:34:20 +01001135 mutex_unlock(&ice->gpio_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 return 0;
1137}
1138
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001139static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001141 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 unsigned short oval, nval;
1143 int change;
1144
1145 snd_ice1712_save_gpio_status(ice);
1146 oval = wm_get(ice, WM_ADC_MUX);
1147 nval = oval & ~0x77;
Takashi Iwai66820252006-03-20 18:31:57 +01001148 nval |= ucontrol->value.enumerated.item[0] & 7;
1149 nval |= (ucontrol->value.enumerated.item[1] & 7) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 change = (oval != nval);
1151 if (change)
1152 wm_put(ice, WM_ADC_MUX, nval);
1153 snd_ice1712_restore_gpio_status(ice);
Takashi Iwai63786d02005-11-04 13:58:11 +01001154 return change;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155}
1156
1157/*
1158 * CS8415 Input mux
1159 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001160static int aureon_cs8415_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001162 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai32b47da2007-01-29 15:26:36 +01001163 static const char * const aureon_texts[] = {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001164 "CD", /* RXP0 */
1165 "Optical" /* RXP1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01001167 static const char * const prodigy_texts[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 "CD",
1169 "Coax"
1170 };
1171 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1172 uinfo->count = 1;
1173 uinfo->value.enumerated.items = 2;
1174 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1175 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1176 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71)
1177 strcpy(uinfo->value.enumerated.name, prodigy_texts[uinfo->value.enumerated.item]);
1178 else
1179 strcpy(uinfo->value.enumerated.name, aureon_texts[uinfo->value.enumerated.item]);
1180 return 0;
1181}
1182
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001183static int aureon_cs8415_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001185 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001186 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001188 /* snd_ice1712_save_gpio_status(ice); */
1189 /* val = aureon_cs8415_get(ice, CS8415_CTRL2); */
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001190 ucontrol->value.enumerated.item[0] = spec->cs8415_mux;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001191 /* snd_ice1712_restore_gpio_status(ice); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 return 0;
1193}
1194
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001195static int aureon_cs8415_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001197 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001198 struct aureon_spec *spec = ice->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 unsigned short oval, nval;
1200 int change;
1201
1202 snd_ice1712_save_gpio_status(ice);
1203 oval = aureon_cs8415_get(ice, CS8415_CTRL2);
1204 nval = oval & ~0x07;
Takashi Iwai66820252006-03-20 18:31:57 +01001205 nval |= ucontrol->value.enumerated.item[0] & 7;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 change = (oval != nval);
1207 if (change)
1208 aureon_cs8415_put(ice, CS8415_CTRL2, nval);
1209 snd_ice1712_restore_gpio_status(ice);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001210 spec->cs8415_mux = ucontrol->value.enumerated.item[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 return change;
1212}
1213
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001214static int aureon_cs8415_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215{
1216 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1217 uinfo->count = 1;
1218 uinfo->value.integer.min = 0;
1219 uinfo->value.integer.max = 192000;
1220 return 0;
1221}
1222
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001223static int aureon_cs8415_rate_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001225 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 unsigned char ratio;
1227 ratio = aureon_cs8415_get(ice, CS8415_RATIO);
1228 ucontrol->value.integer.value[0] = (int)((unsigned int)ratio * 750);
1229 return 0;
1230}
1231
1232/*
1233 * CS8415A Mute
1234 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001235#define aureon_cs8415_mute_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001237static int aureon_cs8415_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001239 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 snd_ice1712_save_gpio_status(ice);
1241 ucontrol->value.integer.value[0] = (aureon_cs8415_get(ice, CS8415_CTRL1) & 0x20) ? 0 : 1;
1242 snd_ice1712_restore_gpio_status(ice);
1243 return 0;
1244}
1245
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001246static int aureon_cs8415_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001248 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 unsigned char oval, nval;
1250 int change;
1251 snd_ice1712_save_gpio_status(ice);
1252 oval = aureon_cs8415_get(ice, CS8415_CTRL1);
1253 if (ucontrol->value.integer.value[0])
1254 nval = oval & ~0x20;
1255 else
1256 nval = oval | 0x20;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001257 change = (oval != nval);
1258 if (change)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 aureon_cs8415_put(ice, CS8415_CTRL1, nval);
1260 snd_ice1712_restore_gpio_status(ice);
1261 return change;
1262}
1263
1264/*
1265 * CS8415A Q-Sub info
1266 */
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001267static int aureon_cs8415_qsub_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1268{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
1270 uinfo->count = 10;
1271 return 0;
1272}
1273
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001274static int aureon_cs8415_qsub_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1275{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001276 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001277
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 snd_ice1712_save_gpio_status(ice);
1279 aureon_cs8415_read(ice, CS8415_QSUB, ucontrol->value.bytes.data, 10);
1280 snd_ice1712_restore_gpio_status(ice);
1281
1282 return 0;
1283}
1284
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001285static int aureon_cs8415_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1286{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
1288 uinfo->count = 1;
1289 return 0;
1290}
1291
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001292static int aureon_cs8415_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1293{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 memset(ucontrol->value.iec958.status, 0xFF, 24);
1295 return 0;
1296}
1297
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001298static int aureon_cs8415_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1299{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001300 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301
1302 snd_ice1712_save_gpio_status(ice);
1303 aureon_cs8415_read(ice, CS8415_C_BUFFER, ucontrol->value.iec958.status, 24);
1304 snd_ice1712_restore_gpio_status(ice);
1305 return 0;
1306}
1307
1308/*
1309 * Headphone Amplifier
1310 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001311static int aureon_set_headphone_amp(struct snd_ice1712 *ice, int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312{
1313 unsigned int tmp, tmp2;
1314
1315 tmp2 = tmp = snd_ice1712_gpio_read(ice);
1316 if (enable)
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001317 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1318 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT)
Takashi Iwaic5130272006-05-23 15:46:10 +02001319 tmp |= AUREON_HP_SEL;
1320 else
1321 tmp |= PRODIGY_HP_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 else
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001323 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1324 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT)
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001325 tmp &= ~AUREON_HP_SEL;
Takashi Iwaic5130272006-05-23 15:46:10 +02001326 else
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001327 tmp &= ~PRODIGY_HP_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 if (tmp != tmp2) {
1329 snd_ice1712_gpio_write(ice, tmp);
1330 return 1;
1331 }
1332 return 0;
1333}
1334
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001335static int aureon_get_headphone_amp(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336{
1337 unsigned int tmp = snd_ice1712_gpio_read(ice);
1338
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001339 return (tmp & AUREON_HP_SEL) != 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340}
1341
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001342#define aureon_hpamp_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001344static int aureon_hpamp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001346 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347
1348 ucontrol->value.integer.value[0] = aureon_get_headphone_amp(ice);
1349 return 0;
1350}
1351
1352
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001353static int aureon_hpamp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001355 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001357 return aureon_set_headphone_amp(ice, ucontrol->value.integer.value[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358}
1359
1360/*
1361 * Deemphasis
1362 */
1363
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001364#define aureon_deemp_info snd_ctl_boolean_mono_info
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001366static int aureon_deemp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001368 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 0xf;
1370 return 0;
1371}
1372
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001373static int aureon_deemp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001375 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 int temp, temp2;
1377 temp2 = temp = wm_get(ice, WM_DAC_CTRL2);
1378 if (ucontrol->value.integer.value[0])
1379 temp |= 0xf;
1380 else
1381 temp &= ~0xf;
1382 if (temp != temp2) {
1383 wm_put(ice, WM_DAC_CTRL2, temp);
1384 return 1;
1385 }
1386 return 0;
1387}
1388
1389/*
1390 * ADC Oversampling
1391 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001392static int aureon_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393{
Takashi Iwai32b47da2007-01-29 15:26:36 +01001394 static const char * const texts[2] = { "128x", "64x" };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395
1396 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1397 uinfo->count = 1;
1398 uinfo->value.enumerated.items = 2;
1399
1400 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1401 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1402 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1403
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001404 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405}
1406
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001407static int aureon_oversampling_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001409 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 0x8;
1411 return 0;
1412}
1413
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001414static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415{
1416 int temp, temp2;
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001417 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418
1419 temp2 = temp = wm_get(ice, WM_MASTER);
1420
1421 if (ucontrol->value.enumerated.item[0])
1422 temp |= 0x8;
1423 else
1424 temp &= ~0x8;
1425
1426 if (temp != temp2) {
1427 wm_put(ice, WM_MASTER, temp);
1428 return 1;
1429 }
1430 return 0;
1431}
1432
1433/*
1434 * mixers
1435 */
1436
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01001437static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 {
1439 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1440 .name = "Master Playback Switch",
1441 .info = wm_master_mute_info,
1442 .get = wm_master_mute_get,
1443 .put = wm_master_mute_put
1444 },
1445 {
1446 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001447 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001448 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 .name = "Master Playback Volume",
1450 .info = wm_master_vol_info,
1451 .get = wm_master_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +02001452 .put = wm_master_vol_put,
1453 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 },
1455 {
1456 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1457 .name = "Front Playback Switch",
1458 .info = wm_mute_info,
1459 .get = wm_mute_get,
1460 .put = wm_mute_put,
1461 .private_value = (2 << 8) | 0
1462 },
1463 {
1464 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001465 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001466 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 .name = "Front Playback Volume",
1468 .info = wm_vol_info,
1469 .get = wm_vol_get,
1470 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001471 .private_value = (2 << 8) | 0,
1472 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 },
1474 {
1475 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1476 .name = "Rear Playback Switch",
1477 .info = wm_mute_info,
1478 .get = wm_mute_get,
1479 .put = wm_mute_put,
1480 .private_value = (2 << 8) | 2
1481 },
1482 {
1483 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001484 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001485 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 .name = "Rear Playback Volume",
1487 .info = wm_vol_info,
1488 .get = wm_vol_get,
1489 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001490 .private_value = (2 << 8) | 2,
1491 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 },
1493 {
1494 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1495 .name = "Center Playback Switch",
1496 .info = wm_mute_info,
1497 .get = wm_mute_get,
1498 .put = wm_mute_put,
1499 .private_value = (1 << 8) | 4
1500 },
1501 {
1502 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001503 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001504 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 .name = "Center Playback Volume",
1506 .info = wm_vol_info,
1507 .get = wm_vol_get,
1508 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001509 .private_value = (1 << 8) | 4,
1510 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 },
1512 {
1513 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1514 .name = "LFE Playback Switch",
1515 .info = wm_mute_info,
1516 .get = wm_mute_get,
1517 .put = wm_mute_put,
1518 .private_value = (1 << 8) | 5
1519 },
1520 {
1521 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001522 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001523 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 .name = "LFE Playback Volume",
1525 .info = wm_vol_info,
1526 .get = wm_vol_get,
1527 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001528 .private_value = (1 << 8) | 5,
1529 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 },
1531 {
1532 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1533 .name = "Side Playback Switch",
1534 .info = wm_mute_info,
1535 .get = wm_mute_get,
1536 .put = wm_mute_put,
1537 .private_value = (2 << 8) | 6
1538 },
1539 {
1540 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001541 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001542 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 .name = "Side Playback Volume",
1544 .info = wm_vol_info,
1545 .get = wm_vol_get,
1546 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +02001547 .private_value = (2 << 8) | 6,
1548 .tlv = { .p = db_scale_wm_dac }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 }
1550};
1551
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01001552static struct snd_kcontrol_new wm_controls[] __devinitdata = {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001553 {
1554 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 .name = "PCM Playback Switch",
1556 .info = wm_pcm_mute_info,
1557 .get = wm_pcm_mute_get,
1558 .put = wm_pcm_mute_put
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001559 },
1560 {
1561 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001562 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001563 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 .name = "PCM Playback Volume",
1565 .info = wm_pcm_vol_info,
1566 .get = wm_pcm_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +02001567 .put = wm_pcm_vol_put,
1568 .tlv = { .p = db_scale_wm_pcm }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001569 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 {
1571 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1572 .name = "Capture Switch",
1573 .info = wm_adc_mute_info,
1574 .get = wm_adc_mute_get,
1575 .put = wm_adc_mute_put,
1576 },
1577 {
1578 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001579 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001580 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 .name = "Capture Volume",
1582 .info = wm_adc_vol_info,
1583 .get = wm_adc_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +02001584 .put = wm_adc_vol_put,
1585 .tlv = { .p = db_scale_wm_adc }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 },
1587 {
1588 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1589 .name = "Capture Source",
1590 .info = wm_adc_mux_info,
1591 .get = wm_adc_mux_get,
1592 .put = wm_adc_mux_put,
1593 .private_value = 5
1594 },
1595 {
1596 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1597 .name = "External Amplifier",
1598 .info = aureon_hpamp_info,
1599 .get = aureon_hpamp_get,
1600 .put = aureon_hpamp_put
1601 },
1602 {
1603 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1604 .name = "DAC Deemphasis Switch",
1605 .info = aureon_deemp_info,
1606 .get = aureon_deemp_get,
1607 .put = aureon_deemp_put
1608 },
1609 {
1610 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1611 .name = "ADC Oversampling",
1612 .info = aureon_oversampling_info,
1613 .get = aureon_oversampling_get,
1614 .put = aureon_oversampling_put
1615 }
1616};
1617
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01001618static struct snd_kcontrol_new ac97_controls[] __devinitdata = {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001619 {
1620 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 .name = "AC97 Playback Switch",
1622 .info = aureon_ac97_mmute_info,
1623 .get = aureon_ac97_mmute_get,
1624 .put = aureon_ac97_mmute_put,
1625 .private_value = AC97_MASTER
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001626 },
1627 {
1628 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001629 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001630 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1631 .name = "AC97 Playback Volume",
1632 .info = aureon_ac97_vol_info,
1633 .get = aureon_ac97_vol_get,
1634 .put = aureon_ac97_vol_put,
1635 .private_value = AC97_MASTER|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001636 .tlv = { .p = db_scale_ac97_master }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001637 },
1638 {
1639 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1640 .name = "CD Playback Switch",
1641 .info = aureon_ac97_mute_info,
1642 .get = aureon_ac97_mute_get,
1643 .put = aureon_ac97_mute_put,
1644 .private_value = AC97_CD
1645 },
1646 {
1647 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001648 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001649 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1650 .name = "CD Playback Volume",
1651 .info = aureon_ac97_vol_info,
1652 .get = aureon_ac97_vol_get,
1653 .put = aureon_ac97_vol_put,
1654 .private_value = AC97_CD|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001655 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001656 },
1657 {
1658 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1659 .name = "Aux Playback Switch",
1660 .info = aureon_ac97_mute_info,
1661 .get = aureon_ac97_mute_get,
1662 .put = aureon_ac97_mute_put,
1663 .private_value = AC97_AUX,
1664 },
1665 {
1666 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001667 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001668 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1669 .name = "Aux Playback Volume",
1670 .info = aureon_ac97_vol_info,
1671 .get = aureon_ac97_vol_get,
1672 .put = aureon_ac97_vol_put,
1673 .private_value = AC97_AUX|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001674 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001675 },
1676 {
1677 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1678 .name = "Line Playback Switch",
1679 .info = aureon_ac97_mute_info,
1680 .get = aureon_ac97_mute_get,
1681 .put = aureon_ac97_mute_put,
1682 .private_value = AC97_LINE
1683 },
1684 {
1685 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001686 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001687 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1688 .name = "Line Playback Volume",
1689 .info = aureon_ac97_vol_info,
1690 .get = aureon_ac97_vol_get,
1691 .put = aureon_ac97_vol_put,
1692 .private_value = AC97_LINE|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001693 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001694 },
1695 {
1696 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1697 .name = "Mic Playback Switch",
1698 .info = aureon_ac97_mute_info,
1699 .get = aureon_ac97_mute_get,
1700 .put = aureon_ac97_mute_put,
1701 .private_value = AC97_MIC
1702 },
1703 {
1704 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001705 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001706 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1707 .name = "Mic Playback Volume",
1708 .info = aureon_ac97_vol_info,
1709 .get = aureon_ac97_vol_get,
1710 .put = aureon_ac97_vol_put,
1711 .private_value = AC97_MIC,
Takashi Iwaif640c322006-08-30 16:57:37 +02001712 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001713 },
1714 {
1715 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1716 .name = "Mic Boost (+20dB)",
1717 .info = aureon_ac97_micboost_info,
1718 .get = aureon_ac97_micboost_get,
1719 .put = aureon_ac97_micboost_put
1720 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721};
1722
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01001723static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001724 {
1725 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 .name = "AC97 Playback Switch",
1727 .info = aureon_ac97_mmute_info,
1728 .get = aureon_ac97_mmute_get,
1729 .put = aureon_ac97_mmute_put,
1730 .private_value = AC97_MASTER
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001731 },
1732 {
1733 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001734 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001735 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1736 .name = "AC97 Playback Volume",
1737 .info = aureon_ac97_vol_info,
1738 .get = aureon_ac97_vol_get,
1739 .put = aureon_ac97_vol_put,
1740 .private_value = AC97_MASTER|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001741 .tlv = { .p = db_scale_ac97_master }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001742 },
1743 {
1744 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1745 .name = "CD Playback Switch",
1746 .info = aureon_ac97_mute_info,
1747 .get = aureon_ac97_mute_get,
1748 .put = aureon_ac97_mute_put,
1749 .private_value = AC97_AUX
1750 },
1751 {
1752 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001753 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001754 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1755 .name = "CD Playback Volume",
1756 .info = aureon_ac97_vol_info,
1757 .get = aureon_ac97_vol_get,
1758 .put = aureon_ac97_vol_put,
1759 .private_value = AC97_AUX|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001760 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001761 },
1762 {
1763 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1764 .name = "Phono Playback Switch",
1765 .info = aureon_ac97_mute_info,
1766 .get = aureon_ac97_mute_get,
1767 .put = aureon_ac97_mute_put,
1768 .private_value = AC97_CD
1769 },
1770 {
1771 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001772 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001773 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1774 .name = "Phono Playback Volume",
1775 .info = aureon_ac97_vol_info,
1776 .get = aureon_ac97_vol_get,
1777 .put = aureon_ac97_vol_put,
1778 .private_value = AC97_CD|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001779 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001780 },
1781 {
1782 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1783 .name = "Line Playback Switch",
1784 .info = aureon_ac97_mute_info,
1785 .get = aureon_ac97_mute_get,
1786 .put = aureon_ac97_mute_put,
1787 .private_value = AC97_LINE
1788 },
1789 {
1790 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001791 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001792 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1793 .name = "Line Playback Volume",
1794 .info = aureon_ac97_vol_info,
1795 .get = aureon_ac97_vol_get,
1796 .put = aureon_ac97_vol_put,
1797 .private_value = AC97_LINE|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001798 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001799 },
1800 {
1801 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1802 .name = "Mic Playback Switch",
1803 .info = aureon_ac97_mute_info,
1804 .get = aureon_ac97_mute_get,
1805 .put = aureon_ac97_mute_put,
1806 .private_value = AC97_MIC
1807 },
1808 {
1809 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001810 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001811 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1812 .name = "Mic Playback Volume",
1813 .info = aureon_ac97_vol_info,
1814 .get = aureon_ac97_vol_get,
1815 .put = aureon_ac97_vol_put,
1816 .private_value = AC97_MIC,
Takashi Iwaif640c322006-08-30 16:57:37 +02001817 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001818 },
1819 {
1820 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1821 .name = "Mic Boost (+20dB)",
1822 .info = aureon_ac97_micboost_info,
1823 .get = aureon_ac97_micboost_get,
1824 .put = aureon_ac97_micboost_put
1825 },
1826 {
1827 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1828 .name = "Aux Playback Switch",
1829 .info = aureon_ac97_mute_info,
1830 .get = aureon_ac97_mute_get,
1831 .put = aureon_ac97_mute_put,
1832 .private_value = AC97_VIDEO,
1833 },
1834 {
1835 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +02001836 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001837 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
1838 .name = "Aux Playback Volume",
1839 .info = aureon_ac97_vol_info,
1840 .get = aureon_ac97_vol_get,
1841 .put = aureon_ac97_vol_put,
1842 .private_value = AC97_VIDEO|AUREON_AC97_STEREO,
Takashi Iwaif640c322006-08-30 16:57:37 +02001843 .tlv = { .p = db_scale_ac97_gain }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001844 },
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +02001845 {
1846 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1847 .name = "Aux Source",
1848 .info = aureon_universe_inmux_info,
1849 .get = aureon_universe_inmux_get,
1850 .put = aureon_universe_inmux_put
1851 }
1852
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853};
1854
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01001855static struct snd_kcontrol_new cs8415_controls[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 {
1857 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001858 .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, SWITCH),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 .info = aureon_cs8415_mute_info,
1860 .get = aureon_cs8415_mute_get,
1861 .put = aureon_cs8415_mute_put
1862 },
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001863 {
1864 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1865 .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) "Source",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 .info = aureon_cs8415_mux_info,
1867 .get = aureon_cs8415_mux_get,
1868 .put = aureon_cs8415_mux_put,
1869 },
1870 {
1871 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001872 .name = SNDRV_CTL_NAME_IEC958("Q-subcode ", CAPTURE, DEFAULT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1874 .info = aureon_cs8415_qsub_info,
1875 .get = aureon_cs8415_qsub_get,
1876 },
1877 {
1878 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001879 .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 .access = SNDRV_CTL_ELEM_ACCESS_READ,
1881 .info = aureon_cs8415_spdif_info,
1882 .get = aureon_cs8415_mask_get
1883 },
1884 {
1885 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001886 .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1888 .info = aureon_cs8415_spdif_info,
1889 .get = aureon_cs8415_spdif_get
1890 },
1891 {
1892 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001893 .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) "Rate",
1894 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 .info = aureon_cs8415_rate_info,
1896 .get = aureon_cs8415_rate_get
1897 }
1898};
1899
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001900static int __devinit aureon_add_controls(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901{
1902 unsigned int i, counts;
1903 int err;
1904
1905 counts = ARRAY_SIZE(aureon_dac_controls);
1906 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY)
1907 counts -= 2; /* no side */
1908 for (i = 0; i < counts; i++) {
1909 err = snd_ctl_add(ice->card, snd_ctl_new1(&aureon_dac_controls[i], ice));
1910 if (err < 0)
1911 return err;
1912 }
1913
1914 for (i = 0; i < ARRAY_SIZE(wm_controls); i++) {
1915 err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice));
1916 if (err < 0)
1917 return err;
1918 }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001919
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) {
1921 for (i = 0; i < ARRAY_SIZE(universe_ac97_controls); i++) {
1922 err = snd_ctl_add(ice->card, snd_ctl_new1(&universe_ac97_controls[i], ice));
1923 if (err < 0)
1924 return err;
1925 }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001926 } else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001927 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 for (i = 0; i < ARRAY_SIZE(ac97_controls); i++) {
1929 err = snd_ctl_add(ice->card, snd_ctl_new1(&ac97_controls[i], ice));
1930 if (err < 0)
1931 return err;
1932 }
1933 }
1934
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01001935 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
1936 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 unsigned char id;
1938 snd_ice1712_save_gpio_status(ice);
1939 id = aureon_cs8415_get(ice, CS8415_ID);
1940 if (id != 0x41)
Takashi Iwai99b359b2005-10-20 18:26:44 +02001941 snd_printk(KERN_INFO "No CS8415 chip. Skipping CS8415 controls.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 else if ((id & 0x0F) != 0x01)
Takashi Iwai99b359b2005-10-20 18:26:44 +02001943 snd_printk(KERN_INFO "Detected unsupported CS8415 rev. (%c)\n", (char)((id & 0x0F) + 'A' - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 else {
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001945 for (i = 0; i < ARRAY_SIZE(cs8415_controls); i++) {
Takashi Iwaiab0c7d72005-11-17 15:00:18 +01001946 struct snd_kcontrol *kctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 err = snd_ctl_add(ice->card, (kctl = snd_ctl_new1(&cs8415_controls[i], ice)));
1948 if (err < 0)
1949 return err;
1950 if (i > 1)
1951 kctl->id.device = ice->pcm->device;
1952 }
1953 }
1954 snd_ice1712_restore_gpio_status(ice);
1955 }
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04001956
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 return 0;
1958}
1959
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960/*
Bernhard Urbanae761482010-03-23 04:12:38 +01001961 * reset the chip
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 */
Bernhard Urbanae761482010-03-23 04:12:38 +01001963static int aureon_reset(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964{
Takashi Iwai32b47da2007-01-29 15:26:36 +01001965 static const unsigned short wm_inits_aureon[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 /* These come first to reduce init pop noise */
1967 0x1b, 0x044, /* ADC Mux (AC'97 source) */
1968 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
1969 0x1d, 0x009, /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */
1970
1971 0x18, 0x000, /* All power-up */
1972
1973 0x16, 0x122, /* I2S, normal polarity, 24bit */
1974 0x17, 0x022, /* 256fs, slave mode */
1975 0x00, 0, /* DAC1 analog mute */
1976 0x01, 0, /* DAC2 analog mute */
1977 0x02, 0, /* DAC3 analog mute */
1978 0x03, 0, /* DAC4 analog mute */
1979 0x04, 0, /* DAC5 analog mute */
1980 0x05, 0, /* DAC6 analog mute */
1981 0x06, 0, /* DAC7 analog mute */
1982 0x07, 0, /* DAC8 analog mute */
1983 0x08, 0x100, /* master analog mute */
1984 0x09, 0xff, /* DAC1 digital full */
1985 0x0a, 0xff, /* DAC2 digital full */
1986 0x0b, 0xff, /* DAC3 digital full */
1987 0x0c, 0xff, /* DAC4 digital full */
1988 0x0d, 0xff, /* DAC5 digital full */
1989 0x0e, 0xff, /* DAC6 digital full */
1990 0x0f, 0xff, /* DAC7 digital full */
1991 0x10, 0xff, /* DAC8 digital full */
1992 0x11, 0x1ff, /* master digital full */
1993 0x12, 0x000, /* phase normal */
1994 0x13, 0x090, /* unmute DAC L/R */
1995 0x14, 0x000, /* all unmute */
1996 0x15, 0x000, /* no deemphasis, no ZFLG */
1997 0x19, 0x000, /* -12dB ADC/L */
1998 0x1a, 0x000, /* -12dB ADC/R */
1999 (unsigned short)-1
2000 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01002001 static const unsigned short wm_inits_prodigy[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002
2003 /* These come first to reduce init pop noise */
2004 0x1b, 0x000, /* ADC Mux */
2005 0x1c, 0x009, /* Out Mux1 */
2006 0x1d, 0x009, /* Out Mux2 */
2007
2008 0x18, 0x000, /* All power-up */
2009
2010 0x16, 0x022, /* I2S, normal polarity, 24bit, high-pass on */
2011 0x17, 0x006, /* 128fs, slave mode */
2012
2013 0x00, 0, /* DAC1 analog mute */
2014 0x01, 0, /* DAC2 analog mute */
2015 0x02, 0, /* DAC3 analog mute */
2016 0x03, 0, /* DAC4 analog mute */
2017 0x04, 0, /* DAC5 analog mute */
2018 0x05, 0, /* DAC6 analog mute */
2019 0x06, 0, /* DAC7 analog mute */
2020 0x07, 0, /* DAC8 analog mute */
2021 0x08, 0x100, /* master analog mute */
2022
2023 0x09, 0x7f, /* DAC1 digital full */
2024 0x0a, 0x7f, /* DAC2 digital full */
2025 0x0b, 0x7f, /* DAC3 digital full */
2026 0x0c, 0x7f, /* DAC4 digital full */
2027 0x0d, 0x7f, /* DAC5 digital full */
2028 0x0e, 0x7f, /* DAC6 digital full */
2029 0x0f, 0x7f, /* DAC7 digital full */
2030 0x10, 0x7f, /* DAC8 digital full */
2031 0x11, 0x1FF, /* master digital full */
2032
2033 0x12, 0x000, /* phase normal */
2034 0x13, 0x090, /* unmute DAC L/R */
2035 0x14, 0x000, /* all unmute */
2036 0x15, 0x000, /* no deemphasis, no ZFLG */
2037
2038 0x19, 0x000, /* -12dB ADC/L */
2039 0x1a, 0x000, /* -12dB ADC/R */
2040 (unsigned short)-1
2041
2042 };
Takashi Iwai32b47da2007-01-29 15:26:36 +01002043 static const unsigned short cs_inits[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 0x0441, /* RUN */
2045 0x0180, /* no mute, OMCK output on RMCK pin */
2046 0x0201, /* S/PDIF source on RXP1 */
2047 0x0605, /* slave, 24bit, MSB on second OSCLK, SDOUT for right channel when OLRCK is high */
2048 (unsigned short)-1
2049 };
2050 unsigned int tmp;
Takashi Iwai32b47da2007-01-29 15:26:36 +01002051 const unsigned short *p;
Bernhard Urbanae761482010-03-23 04:12:38 +01002052 int err;
2053 struct aureon_spec *spec = ice->spec;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04002054
2055 err = aureon_ac97_init(ice);
2056 if (err != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 return err;
2058
2059 snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for the time being */
2060
2061 /* reset the wm codec as the SPI mode */
2062 snd_ice1712_save_gpio_status(ice);
2063 snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RESET|AUREON_WM_CS|AUREON_CS8415_CS|AUREON_HP_SEL));
2064
2065 tmp = snd_ice1712_gpio_read(ice);
2066 tmp &= ~AUREON_WM_RESET;
2067 snd_ice1712_gpio_write(ice, tmp);
2068 udelay(1);
2069 tmp |= AUREON_WM_CS | AUREON_CS8415_CS;
2070 snd_ice1712_gpio_write(ice, tmp);
2071 udelay(1);
2072 tmp |= AUREON_WM_RESET;
2073 snd_ice1712_gpio_write(ice, tmp);
2074 udelay(1);
2075
2076 /* initialize WM8770 codec */
Takashi Iwai45fe7222006-01-13 13:50:16 +01002077 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71 ||
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01002078 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ||
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04002079 ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 p = wm_inits_prodigy;
2081 else
2082 p = wm_inits_aureon;
2083 for (; *p != (unsigned short)-1; p += 2)
2084 wm_put(ice, p[0], p[1]);
2085
2086 /* initialize CS8415A codec */
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01002087 if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT &&
2088 ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
Takashi Iwai45fe7222006-01-13 13:50:16 +01002089 for (p = cs_inits; *p != (unsigned short)-1; p++)
2090 aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01002091 spec->cs8415_mux = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092
Takashi Iwai45fe7222006-01-13 13:50:16 +01002093 aureon_set_headphone_amp(ice, 1);
2094 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095
2096 snd_ice1712_restore_gpio_status(ice);
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +02002097
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04002098 /* initialize PCA9554 pin directions & set default input */
Maximilian Rehkopfaf9b70a2006-03-31 13:10:35 +02002099 aureon_pca9554_write(ice, PCA9554_DIR, 0x00);
2100 aureon_pca9554_write(ice, PCA9554_OUT, 0x00); /* internal AUX */
Bernhard Urbanae761482010-03-23 04:12:38 +01002101 return 0;
2102}
2103
2104/*
2105 * suspend/resume
2106 */
Takashi Iwaic7561cd2012-08-14 18:12:04 +02002107#ifdef CONFIG_PM_SLEEP
Bernhard Urbanae761482010-03-23 04:12:38 +01002108static int aureon_resume(struct snd_ice1712 *ice)
2109{
2110 struct aureon_spec *spec = ice->spec;
2111 int err, i;
2112
2113 err = aureon_reset(ice);
2114 if (err != 0)
2115 return err;
2116
2117 /* workaround for poking volume with alsamixer after resume:
2118 * just set stored volume again */
2119 for (i = 0; i < ice->num_total_dacs; i++)
2120 wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);
2121 return 0;
2122}
2123#endif
2124
2125/*
2126 * initialize the chip
2127 */
2128static int __devinit aureon_init(struct snd_ice1712 *ice)
2129{
2130 struct aureon_spec *spec;
2131 int i, err;
2132
2133 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
2134 if (!spec)
2135 return -ENOMEM;
2136 ice->spec = spec;
2137
2138 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) {
2139 ice->num_total_dacs = 6;
2140 ice->num_total_adcs = 2;
2141 } else {
2142 /* aureon 7.1 and prodigy 7.1 */
2143 ice->num_total_dacs = 8;
2144 ice->num_total_adcs = 2;
2145 }
2146
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002147 /* to remember the register values of CS8415 */
Bernhard Urbanae761482010-03-23 04:12:38 +01002148 ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
2149 if (!ice->akm)
2150 return -ENOMEM;
2151 ice->akm_codecs = 1;
2152
2153 err = aureon_reset(ice);
2154 if (err != 0)
2155 return err;
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04002156
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01002157 spec->master[0] = WM_VOL_MUTE;
2158 spec->master[1] = WM_VOL_MUTE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 for (i = 0; i < ice->num_total_dacs; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01002160 spec->vol[i] = WM_VOL_MUTE;
2161 wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 }
2163
Takashi Iwaic7561cd2012-08-14 18:12:04 +02002164#ifdef CONFIG_PM_SLEEP
Bernhard Urbanae761482010-03-23 04:12:38 +01002165 ice->pm_resume = aureon_resume;
2166 ice->pm_suspend_enabled = 1;
2167#endif
2168
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169 return 0;
2170}
2171
2172
2173/*
2174 * Aureon boards don't provide the EEPROM data except for the vendor IDs.
2175 * hence the driver needs to sets up it properly.
2176 */
2177
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01002178static unsigned char aureon51_eeprom[] __devinitdata = {
Takashi Iwai189bc172007-01-29 15:25:40 +01002179 [ICE_EEP2_SYSCONF] = 0x0a, /* clock 512, spdif-in/ADC, 3DACs */
2180 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
2181 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
2182 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
2183 [ICE_EEP2_GPIO_DIR] = 0xff,
2184 [ICE_EEP2_GPIO_DIR1] = 0xff,
2185 [ICE_EEP2_GPIO_DIR2] = 0x5f,
2186 [ICE_EEP2_GPIO_MASK] = 0x00,
2187 [ICE_EEP2_GPIO_MASK1] = 0x00,
2188 [ICE_EEP2_GPIO_MASK2] = 0x00,
2189 [ICE_EEP2_GPIO_STATE] = 0x00,
2190 [ICE_EEP2_GPIO_STATE1] = 0x00,
2191 [ICE_EEP2_GPIO_STATE2] = 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192};
2193
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01002194static unsigned char aureon71_eeprom[] __devinitdata = {
Takashi Iwai189bc172007-01-29 15:25:40 +01002195 [ICE_EEP2_SYSCONF] = 0x0b, /* clock 512, spdif-in/ADC, 4DACs */
2196 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
2197 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
2198 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
2199 [ICE_EEP2_GPIO_DIR] = 0xff,
2200 [ICE_EEP2_GPIO_DIR1] = 0xff,
2201 [ICE_EEP2_GPIO_DIR2] = 0x5f,
2202 [ICE_EEP2_GPIO_MASK] = 0x00,
2203 [ICE_EEP2_GPIO_MASK1] = 0x00,
2204 [ICE_EEP2_GPIO_MASK2] = 0x00,
2205 [ICE_EEP2_GPIO_STATE] = 0x00,
2206 [ICE_EEP2_GPIO_STATE1] = 0x00,
2207 [ICE_EEP2_GPIO_STATE2] = 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208};
Takashi Iwai189bc172007-01-29 15:25:40 +01002209#define prodigy71_eeprom aureon71_eeprom
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210
Maximilian Rehkopfc1805dd2008-08-29 14:11:10 +02002211static unsigned char aureon71_universe_eeprom[] __devinitdata = {
2212 [ICE_EEP2_SYSCONF] = 0x2b, /* clock 512, mpu401, spdif-in/ADC,
2213 * 4DACs
2214 */
2215 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
2216 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
2217 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
2218 [ICE_EEP2_GPIO_DIR] = 0xff,
2219 [ICE_EEP2_GPIO_DIR1] = 0xff,
2220 [ICE_EEP2_GPIO_DIR2] = 0x5f,
2221 [ICE_EEP2_GPIO_MASK] = 0x00,
2222 [ICE_EEP2_GPIO_MASK1] = 0x00,
2223 [ICE_EEP2_GPIO_MASK2] = 0x00,
2224 [ICE_EEP2_GPIO_STATE] = 0x00,
2225 [ICE_EEP2_GPIO_STATE1] = 0x00,
2226 [ICE_EEP2_GPIO_STATE2] = 0x00,
2227};
2228
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01002229static unsigned char prodigy71lt_eeprom[] __devinitdata = {
Takashi Iwai189bc172007-01-29 15:25:40 +01002230 [ICE_EEP2_SYSCONF] = 0x4b, /* clock 384, spdif-in/ADC, 4DACs */
2231 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
2232 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
2233 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
2234 [ICE_EEP2_GPIO_DIR] = 0xff,
2235 [ICE_EEP2_GPIO_DIR1] = 0xff,
2236 [ICE_EEP2_GPIO_DIR2] = 0x5f,
2237 [ICE_EEP2_GPIO_MASK] = 0x00,
2238 [ICE_EEP2_GPIO_MASK1] = 0x00,
2239 [ICE_EEP2_GPIO_MASK2] = 0x00,
2240 [ICE_EEP2_GPIO_STATE] = 0x00,
2241 [ICE_EEP2_GPIO_STATE1] = 0x00,
2242 [ICE_EEP2_GPIO_STATE2] = 0x00,
Takashi Iwai45fe7222006-01-13 13:50:16 +01002243};
Takashi Iwai189bc172007-01-29 15:25:40 +01002244#define prodigy71xt_eeprom prodigy71lt_eeprom
Takashi Iwai45fe7222006-01-13 13:50:16 +01002245
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246/* entry point */
Takashi Iwai1b60f6b2007-03-13 22:13:47 +01002247struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 {
2249 .subvendor = VT1724_SUBDEVICE_AUREON51_SKY,
2250 .name = "Terratec Aureon 5.1-Sky",
2251 .model = "aureon51",
2252 .chip_init = aureon_init,
2253 .build_controls = aureon_add_controls,
2254 .eeprom_size = sizeof(aureon51_eeprom),
2255 .eeprom_data = aureon51_eeprom,
2256 .driver = "Aureon51",
2257 },
2258 {
2259 .subvendor = VT1724_SUBDEVICE_AUREON71_SPACE,
2260 .name = "Terratec Aureon 7.1-Space",
2261 .model = "aureon71",
2262 .chip_init = aureon_init,
2263 .build_controls = aureon_add_controls,
2264 .eeprom_size = sizeof(aureon71_eeprom),
2265 .eeprom_data = aureon71_eeprom,
2266 .driver = "Aureon71",
2267 },
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04002268 {
2269 .subvendor = VT1724_SUBDEVICE_AUREON71_UNIVERSE,
2270 .name = "Terratec Aureon 7.1-Universe",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 .model = "universe",
Alexander Beregalov1ce211a2008-09-07 01:19:00 +04002272 .chip_init = aureon_init,
2273 .build_controls = aureon_add_controls,
Maximilian Rehkopfc1805dd2008-08-29 14:11:10 +02002274 .eeprom_size = sizeof(aureon71_universe_eeprom),
2275 .eeprom_data = aureon71_universe_eeprom,
Takashi Iwai9f37c5b2006-06-29 16:40:21 +02002276 .driver = "Aureon71Univ", /* keep in 15 letters */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 },
2278 {
2279 .subvendor = VT1724_SUBDEVICE_PRODIGY71,
2280 .name = "Audiotrak Prodigy 7.1",
2281 .model = "prodigy71",
2282 .chip_init = aureon_init,
2283 .build_controls = aureon_add_controls,
2284 .eeprom_size = sizeof(prodigy71_eeprom),
2285 .eeprom_data = prodigy71_eeprom,
2286 .driver = "Prodigy71", /* should be identical with Aureon71 */
2287 },
Takashi Iwai45fe7222006-01-13 13:50:16 +01002288 {
2289 .subvendor = VT1724_SUBDEVICE_PRODIGY71LT,
2290 .name = "Audiotrak Prodigy 7.1 LT",
2291 .model = "prodigy71lt",
2292 .chip_init = aureon_init,
2293 .build_controls = aureon_add_controls,
2294 .eeprom_size = sizeof(prodigy71lt_eeprom),
2295 .eeprom_data = prodigy71lt_eeprom,
2296 .driver = "Prodigy71LT",
2297 },
Toshimune Konnocdf88ef2006-12-18 13:12:18 +01002298 {
2299 .subvendor = VT1724_SUBDEVICE_PRODIGY71XT,
2300 .name = "Audiotrak Prodigy 7.1 XT",
2301 .model = "prodigy71xt",
2302 .chip_init = aureon_init,
2303 .build_controls = aureon_add_controls,
2304 .eeprom_size = sizeof(prodigy71xt_eeprom),
2305 .eeprom_data = prodigy71xt_eeprom,
2306 .driver = "Prodigy71LT",
2307 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 { } /* terminator */
2309};