blob: cee07fe3aa3640cb093ec1d1c00d3ec38c169bff [file] [log] [blame]
Clemens Ladischd1db38c2010-01-18 15:44:04 +01001/*
2 * card driver for models with WM8776/WM8766 DACs (Xonar DS)
3 *
4 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
5 *
6 *
7 * This driver is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License, version 2.
9 *
10 * This driver is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this driver; if not, see <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Xonar DS
21 * --------
22 *
23 * CMI8788:
24 *
25 * SPI 0 -> WM8766 (surround, center/LFE, back)
26 * SPI 1 -> WM8776 (front, input)
27 *
Clemens Ladisch435feac2010-09-09 12:20:29 +020028 * GPIO 4 <- headphone detect, 0 = plugged
29 * GPIO 6 -> route input jack to mic-in (0) or line-in (1)
Clemens Ladisch84cf83a2010-09-09 12:23:06 +020030 * GPIO 7 -> enable output to front L/R speaker channels
31 * GPIO 8 -> enable output to other speaker channels and front panel headphone
Clemens Ladisch9bac84e2010-09-09 12:19:21 +020032 *
33 * WM8766:
34 *
35 * input 1 <- line
36 * input 2 <- mic
37 * input 3 <- front mic
38 * input 4 <- aux
Clemens Ladischd1db38c2010-01-18 15:44:04 +010039 */
40
41#include <linux/pci.h>
42#include <linux/delay.h>
43#include <sound/control.h>
44#include <sound/core.h>
Clemens Ladisch435feac2010-09-09 12:20:29 +020045#include <sound/jack.h>
Clemens Ladischd1db38c2010-01-18 15:44:04 +010046#include <sound/pcm.h>
47#include <sound/pcm_params.h>
48#include <sound/tlv.h>
49#include "xonar.h"
50#include "wm8776.h"
51#include "wm8766.h"
52
53#define GPIO_DS_HP_DETECT 0x0010
54#define GPIO_DS_INPUT_ROUTE 0x0040
Clemens Ladisch84cf83a2010-09-09 12:23:06 +020055#define GPIO_DS_OUTPUT_FRONTLR 0x0080
56#define GPIO_DS_OUTPUT_ENABLE 0x0100
Clemens Ladischd1db38c2010-01-18 15:44:04 +010057
58#define LC_CONTROL_LIMITER 0x40000000
59#define LC_CONTROL_ALC 0x20000000
60
61struct xonar_wm87x6 {
62 struct xonar_generic generic;
63 u16 wm8776_regs[0x17];
64 u16 wm8766_regs[0x10];
Clemens Ladischfe6ce802010-09-07 13:38:49 +020065 struct snd_kcontrol *line_adcmux_control;
66 struct snd_kcontrol *mic_adcmux_control;
Clemens Ladischd1db38c2010-01-18 15:44:04 +010067 struct snd_kcontrol *lc_controls[13];
Clemens Ladisch435feac2010-09-09 12:20:29 +020068 struct snd_jack *hp_jack;
Clemens Ladischd1db38c2010-01-18 15:44:04 +010069};
70
71static void wm8776_write(struct oxygen *chip,
72 unsigned int reg, unsigned int value)
73{
74 struct xonar_wm87x6 *data = chip->model_data;
75
76 oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
77 OXYGEN_SPI_DATA_LENGTH_2 |
78 OXYGEN_SPI_CLOCK_160 |
79 (1 << OXYGEN_SPI_CODEC_SHIFT) |
80 OXYGEN_SPI_CEN_LATCH_CLOCK_LO,
81 (reg << 9) | value);
82 if (reg < ARRAY_SIZE(data->wm8776_regs)) {
Clemens Ladischfaf4eb22010-03-03 09:16:18 +010083 if (reg >= WM8776_HPLVOL && reg <= WM8776_DACMASTER)
Clemens Ladischd1db38c2010-01-18 15:44:04 +010084 value &= ~WM8776_UPDATE;
85 data->wm8776_regs[reg] = value;
86 }
87}
88
89static void wm8776_write_cached(struct oxygen *chip,
90 unsigned int reg, unsigned int value)
91{
92 struct xonar_wm87x6 *data = chip->model_data;
93
94 if (reg >= ARRAY_SIZE(data->wm8776_regs) ||
95 value != data->wm8776_regs[reg])
96 wm8776_write(chip, reg, value);
97}
98
99static void wm8766_write(struct oxygen *chip,
100 unsigned int reg, unsigned int value)
101{
102 struct xonar_wm87x6 *data = chip->model_data;
103
104 oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
105 OXYGEN_SPI_DATA_LENGTH_2 |
106 OXYGEN_SPI_CLOCK_160 |
107 (0 << OXYGEN_SPI_CODEC_SHIFT) |
108 OXYGEN_SPI_CEN_LATCH_CLOCK_LO,
109 (reg << 9) | value);
Clemens Ladischda0dab52010-09-09 12:18:35 +0200110 if (reg < ARRAY_SIZE(data->wm8766_regs)) {
111 if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) ||
112 (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA))
113 value &= ~WM8766_UPDATE;
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100114 data->wm8766_regs[reg] = value;
Clemens Ladischda0dab52010-09-09 12:18:35 +0200115 }
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100116}
117
118static void wm8766_write_cached(struct oxygen *chip,
119 unsigned int reg, unsigned int value)
120{
121 struct xonar_wm87x6 *data = chip->model_data;
122
123 if (reg >= ARRAY_SIZE(data->wm8766_regs) ||
Clemens Ladischda0dab52010-09-09 12:18:35 +0200124 value != data->wm8766_regs[reg])
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100125 wm8766_write(chip, reg, value);
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100126}
127
128static void wm8776_registers_init(struct oxygen *chip)
129{
130 struct xonar_wm87x6 *data = chip->model_data;
131
132 wm8776_write(chip, WM8776_RESET, 0);
133 wm8776_write(chip, WM8776_DACCTRL1, WM8776_DZCEN |
134 WM8776_PL_LEFT_LEFT | WM8776_PL_RIGHT_RIGHT);
135 wm8776_write(chip, WM8776_DACMUTE, chip->dac_mute ? WM8776_DMUTE : 0);
136 wm8776_write(chip, WM8776_DACIFCTRL,
137 WM8776_DACFMT_LJUST | WM8776_DACWL_24);
138 wm8776_write(chip, WM8776_ADCIFCTRL,
139 data->wm8776_regs[WM8776_ADCIFCTRL]);
140 wm8776_write(chip, WM8776_MSTRCTRL, data->wm8776_regs[WM8776_MSTRCTRL]);
141 wm8776_write(chip, WM8776_PWRDOWN, data->wm8776_regs[WM8776_PWRDOWN]);
142 wm8776_write(chip, WM8776_HPLVOL, data->wm8776_regs[WM8776_HPLVOL]);
143 wm8776_write(chip, WM8776_HPRVOL, data->wm8776_regs[WM8776_HPRVOL] |
144 WM8776_UPDATE);
145 wm8776_write(chip, WM8776_ADCLVOL, data->wm8776_regs[WM8776_ADCLVOL]);
146 wm8776_write(chip, WM8776_ADCRVOL, data->wm8776_regs[WM8776_ADCRVOL]);
147 wm8776_write(chip, WM8776_ADCMUX, data->wm8776_regs[WM8776_ADCMUX]);
148 wm8776_write(chip, WM8776_DACLVOL, chip->dac_volume[0]);
149 wm8776_write(chip, WM8776_DACRVOL, chip->dac_volume[1] | WM8776_UPDATE);
150}
151
152static void wm8766_registers_init(struct oxygen *chip)
153{
Clemens Ladisch84cf83a2010-09-09 12:23:06 +0200154 struct xonar_wm87x6 *data = chip->model_data;
155
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100156 wm8766_write(chip, WM8766_RESET, 0);
Clemens Ladisch84cf83a2010-09-09 12:23:06 +0200157 wm8766_write(chip, WM8766_DAC_CTRL, data->wm8766_regs[WM8766_DAC_CTRL]);
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100158 wm8766_write(chip, WM8766_INT_CTRL, WM8766_FMT_LJUST | WM8766_IWL_24);
159 wm8766_write(chip, WM8766_DAC_CTRL2,
160 WM8766_ZCD | (chip->dac_mute ? WM8766_DMUTE_MASK : 0));
161 wm8766_write(chip, WM8766_LDA1, chip->dac_volume[2]);
162 wm8766_write(chip, WM8766_RDA1, chip->dac_volume[3]);
163 wm8766_write(chip, WM8766_LDA2, chip->dac_volume[4]);
164 wm8766_write(chip, WM8766_RDA2, chip->dac_volume[5]);
165 wm8766_write(chip, WM8766_LDA3, chip->dac_volume[6]);
166 wm8766_write(chip, WM8766_RDA3, chip->dac_volume[7] | WM8766_UPDATE);
167}
168
169static void wm8776_init(struct oxygen *chip)
170{
171 struct xonar_wm87x6 *data = chip->model_data;
172
173 data->wm8776_regs[WM8776_HPLVOL] = (0x79 - 60) | WM8776_HPZCEN;
174 data->wm8776_regs[WM8776_HPRVOL] = (0x79 - 60) | WM8776_HPZCEN;
175 data->wm8776_regs[WM8776_ADCIFCTRL] =
176 WM8776_ADCFMT_LJUST | WM8776_ADCWL_24 | WM8776_ADCMCLK;
177 data->wm8776_regs[WM8776_MSTRCTRL] =
178 WM8776_ADCRATE_256 | WM8776_DACRATE_256;
179 data->wm8776_regs[WM8776_PWRDOWN] = WM8776_HPPD;
180 data->wm8776_regs[WM8776_ADCLVOL] = 0xa5 | WM8776_ZCA;
181 data->wm8776_regs[WM8776_ADCRVOL] = 0xa5 | WM8776_ZCA;
182 data->wm8776_regs[WM8776_ADCMUX] = 0x001;
183 wm8776_registers_init(chip);
184}
185
Clemens Ladisch84cf83a2010-09-09 12:23:06 +0200186static void wm8766_init(struct oxygen *chip)
Clemens Ladisch435feac2010-09-09 12:20:29 +0200187{
188 struct xonar_wm87x6 *data = chip->model_data;
Clemens Ladisch435feac2010-09-09 12:20:29 +0200189
Clemens Ladisch84cf83a2010-09-09 12:23:06 +0200190 data->wm8766_regs[WM8766_DAC_CTRL] =
191 WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT;
192 wm8766_registers_init(chip);
193}
194
195static void xonar_ds_handle_hp_jack(struct oxygen *chip)
196{
197 struct xonar_wm87x6 *data = chip->model_data;
198 bool hp_plugged;
199 unsigned int reg;
200
201 mutex_lock(&chip->mutex);
202
203 hp_plugged = !(oxygen_read16(chip, OXYGEN_GPIO_DATA) &
204 GPIO_DS_HP_DETECT);
205
206 oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
207 hp_plugged ? 0 : GPIO_DS_OUTPUT_FRONTLR,
208 GPIO_DS_OUTPUT_FRONTLR);
209
210 reg = data->wm8766_regs[WM8766_DAC_CTRL] & ~WM8766_MUTEALL;
211 if (hp_plugged)
212 reg |= WM8766_MUTEALL;
213 wm8766_write_cached(chip, WM8766_DAC_CTRL, reg);
214
215 snd_jack_report(data->hp_jack, hp_plugged ? SND_JACK_HEADPHONE : 0);
216
217 mutex_unlock(&chip->mutex);
Clemens Ladisch435feac2010-09-09 12:20:29 +0200218}
219
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100220static void xonar_ds_init(struct oxygen *chip)
221{
222 struct xonar_wm87x6 *data = chip->model_data;
223
224 data->generic.anti_pop_delay = 300;
225 data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE;
226
227 wm8776_init(chip);
Clemens Ladisch84cf83a2010-09-09 12:23:06 +0200228 wm8766_init(chip);
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100229
Clemens Ladisch84cf83a2010-09-09 12:23:06 +0200230 oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
231 GPIO_DS_INPUT_ROUTE | GPIO_DS_OUTPUT_FRONTLR);
232 oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
233 GPIO_DS_HP_DETECT);
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100234 oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DS_INPUT_ROUTE);
235 oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, GPIO_DS_HP_DETECT);
236 chip->interrupt_mask |= OXYGEN_INT_GPIO;
237
238 xonar_enable_output(chip);
239
Clemens Ladisch435feac2010-09-09 12:20:29 +0200240 snd_jack_new(chip->card, "Headphone",
241 SND_JACK_HEADPHONE, &data->hp_jack);
Clemens Ladisch84cf83a2010-09-09 12:23:06 +0200242 xonar_ds_handle_hp_jack(chip);
Clemens Ladisch435feac2010-09-09 12:20:29 +0200243
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100244 snd_component_add(chip->card, "WM8776");
245 snd_component_add(chip->card, "WM8766");
246}
247
248static void xonar_ds_cleanup(struct oxygen *chip)
249{
250 xonar_disable_output(chip);
Clemens Ladisch4c25b932010-09-07 13:37:10 +0200251 wm8776_write(chip, WM8776_RESET, 0);
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100252}
253
254static void xonar_ds_suspend(struct oxygen *chip)
255{
256 xonar_ds_cleanup(chip);
257}
258
259static void xonar_ds_resume(struct oxygen *chip)
260{
261 wm8776_registers_init(chip);
262 wm8766_registers_init(chip);
263 xonar_enable_output(chip);
Clemens Ladisch84cf83a2010-09-09 12:23:06 +0200264 xonar_ds_handle_hp_jack(chip);
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100265}
266
267static void wm8776_adc_hardware_filter(unsigned int channel,
268 struct snd_pcm_hardware *hardware)
269{
270 if (channel == PCM_A) {
271 hardware->rates = SNDRV_PCM_RATE_32000 |
272 SNDRV_PCM_RATE_44100 |
273 SNDRV_PCM_RATE_48000 |
274 SNDRV_PCM_RATE_64000 |
275 SNDRV_PCM_RATE_88200 |
276 SNDRV_PCM_RATE_96000;
277 hardware->rate_max = 96000;
278 }
279}
280
281static void set_wm87x6_dac_params(struct oxygen *chip,
282 struct snd_pcm_hw_params *params)
283{
284}
285
286static void set_wm8776_adc_params(struct oxygen *chip,
287 struct snd_pcm_hw_params *params)
288{
289 u16 reg;
290
291 reg = WM8776_ADCRATE_256 | WM8776_DACRATE_256;
292 if (params_rate(params) > 48000)
293 reg |= WM8776_ADCOSR;
294 wm8776_write_cached(chip, WM8776_MSTRCTRL, reg);
295}
296
297static void update_wm8776_volume(struct oxygen *chip)
298{
299 struct xonar_wm87x6 *data = chip->model_data;
300 u8 to_change;
301
302 if (chip->dac_volume[0] == chip->dac_volume[1]) {
303 if (chip->dac_volume[0] != data->wm8776_regs[WM8776_DACLVOL] ||
304 chip->dac_volume[1] != data->wm8776_regs[WM8776_DACRVOL]) {
305 wm8776_write(chip, WM8776_DACMASTER,
306 chip->dac_volume[0] | WM8776_UPDATE);
307 data->wm8776_regs[WM8776_DACLVOL] = chip->dac_volume[0];
308 data->wm8776_regs[WM8776_DACRVOL] = chip->dac_volume[0];
309 }
310 } else {
311 to_change = (chip->dac_volume[0] !=
312 data->wm8776_regs[WM8776_DACLVOL]) << 0;
313 to_change |= (chip->dac_volume[1] !=
314 data->wm8776_regs[WM8776_DACLVOL]) << 1;
315 if (to_change & 1)
316 wm8776_write(chip, WM8776_DACLVOL, chip->dac_volume[0] |
317 ((to_change & 2) ? 0 : WM8776_UPDATE));
318 if (to_change & 2)
319 wm8776_write(chip, WM8776_DACRVOL,
320 chip->dac_volume[1] | WM8776_UPDATE);
321 }
322}
323
324static void update_wm87x6_volume(struct oxygen *chip)
325{
326 static const u8 wm8766_regs[6] = {
327 WM8766_LDA1, WM8766_RDA1,
328 WM8766_LDA2, WM8766_RDA2,
329 WM8766_LDA3, WM8766_RDA3,
330 };
331 struct xonar_wm87x6 *data = chip->model_data;
332 unsigned int i;
333 u8 to_change;
334
335 update_wm8776_volume(chip);
336 if (chip->dac_volume[2] == chip->dac_volume[3] &&
337 chip->dac_volume[2] == chip->dac_volume[4] &&
338 chip->dac_volume[2] == chip->dac_volume[5] &&
339 chip->dac_volume[2] == chip->dac_volume[6] &&
340 chip->dac_volume[2] == chip->dac_volume[7]) {
341 to_change = 0;
342 for (i = 0; i < 6; ++i)
343 if (chip->dac_volume[2] !=
344 data->wm8766_regs[wm8766_regs[i]])
345 to_change = 1;
346 if (to_change) {
347 wm8766_write(chip, WM8766_MASTDA,
348 chip->dac_volume[2] | WM8766_UPDATE);
349 for (i = 0; i < 6; ++i)
350 data->wm8766_regs[wm8766_regs[i]] =
351 chip->dac_volume[2];
352 }
353 } else {
354 to_change = 0;
355 for (i = 0; i < 6; ++i)
356 to_change |= (chip->dac_volume[2 + i] !=
357 data->wm8766_regs[wm8766_regs[i]]) << i;
358 for (i = 0; i < 6; ++i)
359 if (to_change & (1 << i))
360 wm8766_write(chip, wm8766_regs[i],
361 chip->dac_volume[2 + i] |
362 ((to_change & (0x3e << i))
363 ? 0 : WM8766_UPDATE));
364 }
365}
366
367static void update_wm8776_mute(struct oxygen *chip)
368{
369 wm8776_write_cached(chip, WM8776_DACMUTE,
370 chip->dac_mute ? WM8776_DMUTE : 0);
371}
372
373static void update_wm87x6_mute(struct oxygen *chip)
374{
375 update_wm8776_mute(chip);
376 wm8766_write_cached(chip, WM8766_DAC_CTRL2, WM8766_ZCD |
377 (chip->dac_mute ? WM8766_DMUTE_MASK : 0));
378}
379
380static void xonar_ds_gpio_changed(struct oxygen *chip)
381{
Clemens Ladisch84cf83a2010-09-09 12:23:06 +0200382 xonar_ds_handle_hp_jack(chip);
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100383}
384
385static int wm8776_bit_switch_get(struct snd_kcontrol *ctl,
386 struct snd_ctl_elem_value *value)
387{
388 struct oxygen *chip = ctl->private_data;
389 struct xonar_wm87x6 *data = chip->model_data;
390 u16 bit = ctl->private_value & 0xffff;
391 unsigned int reg_index = (ctl->private_value >> 16) & 0xff;
392 bool invert = (ctl->private_value >> 24) & 1;
393
394 value->value.integer.value[0] =
395 ((data->wm8776_regs[reg_index] & bit) != 0) ^ invert;
396 return 0;
397}
398
399static int wm8776_bit_switch_put(struct snd_kcontrol *ctl,
400 struct snd_ctl_elem_value *value)
401{
402 struct oxygen *chip = ctl->private_data;
403 struct xonar_wm87x6 *data = chip->model_data;
404 u16 bit = ctl->private_value & 0xffff;
405 u16 reg_value;
406 unsigned int reg_index = (ctl->private_value >> 16) & 0xff;
407 bool invert = (ctl->private_value >> 24) & 1;
408 int changed;
409
410 mutex_lock(&chip->mutex);
411 reg_value = data->wm8776_regs[reg_index] & ~bit;
412 if (value->value.integer.value[0] ^ invert)
413 reg_value |= bit;
414 changed = reg_value != data->wm8776_regs[reg_index];
415 if (changed)
416 wm8776_write(chip, reg_index, reg_value);
417 mutex_unlock(&chip->mutex);
418 return changed;
419}
420
421static int wm8776_field_enum_info(struct snd_kcontrol *ctl,
422 struct snd_ctl_elem_info *info)
423{
424 static const char *const hld[16] = {
425 "0 ms", "2.67 ms", "5.33 ms", "10.6 ms",
426 "21.3 ms", "42.7 ms", "85.3 ms", "171 ms",
427 "341 ms", "683 ms", "1.37 s", "2.73 s",
428 "5.46 s", "10.9 s", "21.8 s", "43.7 s",
429 };
430 static const char *const atk_lim[11] = {
431 "0.25 ms", "0.5 ms", "1 ms", "2 ms",
432 "4 ms", "8 ms", "16 ms", "32 ms",
433 "64 ms", "128 ms", "256 ms",
434 };
435 static const char *const atk_alc[11] = {
436 "8.40 ms", "16.8 ms", "33.6 ms", "67.2 ms",
437 "134 ms", "269 ms", "538 ms", "1.08 s",
438 "2.15 s", "4.3 s", "8.6 s",
439 };
440 static const char *const dcy_lim[11] = {
441 "1.2 ms", "2.4 ms", "4.8 ms", "9.6 ms",
442 "19.2 ms", "38.4 ms", "76.8 ms", "154 ms",
443 "307 ms", "614 ms", "1.23 s",
444 };
445 static const char *const dcy_alc[11] = {
446 "33.5 ms", "67.0 ms", "134 ms", "268 ms",
447 "536 ms", "1.07 s", "2.14 s", "4.29 s",
448 "8.58 s", "17.2 s", "34.3 s",
449 };
450 static const char *const tranwin[8] = {
451 "0 us", "62.5 us", "125 us", "250 us",
452 "500 us", "1 ms", "2 ms", "4 ms",
453 };
454 u8 max;
455 const char *const *names;
456
457 max = (ctl->private_value >> 12) & 0xf;
458 info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
459 info->count = 1;
460 info->value.enumerated.items = max + 1;
461 if (info->value.enumerated.item > max)
462 info->value.enumerated.item = max;
463 switch ((ctl->private_value >> 24) & 0x1f) {
464 case WM8776_ALCCTRL2:
465 names = hld;
466 break;
467 case WM8776_ALCCTRL3:
468 if (((ctl->private_value >> 20) & 0xf) == 0) {
469 if (ctl->private_value & LC_CONTROL_LIMITER)
470 names = atk_lim;
471 else
472 names = atk_alc;
473 } else {
474 if (ctl->private_value & LC_CONTROL_LIMITER)
475 names = dcy_lim;
476 else
477 names = dcy_alc;
478 }
479 break;
480 case WM8776_LIMITER:
481 names = tranwin;
482 break;
483 default:
484 return -ENXIO;
485 }
486 strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
487 return 0;
488}
489
490static int wm8776_field_volume_info(struct snd_kcontrol *ctl,
491 struct snd_ctl_elem_info *info)
492{
493 info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
494 info->count = 1;
495 info->value.integer.min = (ctl->private_value >> 8) & 0xf;
496 info->value.integer.max = (ctl->private_value >> 12) & 0xf;
497 return 0;
498}
499
500static void wm8776_field_set_from_ctl(struct snd_kcontrol *ctl)
501{
502 struct oxygen *chip = ctl->private_data;
503 struct xonar_wm87x6 *data = chip->model_data;
504 unsigned int value, reg_index, mode;
505 u8 min, max, shift;
506 u16 mask, reg_value;
507 bool invert;
508
509 if ((data->wm8776_regs[WM8776_ALCCTRL1] & WM8776_LCSEL_MASK) ==
510 WM8776_LCSEL_LIMITER)
511 mode = LC_CONTROL_LIMITER;
512 else
513 mode = LC_CONTROL_ALC;
514 if (!(ctl->private_value & mode))
515 return;
516
517 value = ctl->private_value & 0xf;
518 min = (ctl->private_value >> 8) & 0xf;
519 max = (ctl->private_value >> 12) & 0xf;
520 mask = (ctl->private_value >> 16) & 0xf;
521 shift = (ctl->private_value >> 20) & 0xf;
522 reg_index = (ctl->private_value >> 24) & 0x1f;
523 invert = (ctl->private_value >> 29) & 0x1;
524
525 if (invert)
526 value = max - (value - min);
527 reg_value = data->wm8776_regs[reg_index];
528 reg_value &= ~(mask << shift);
529 reg_value |= value << shift;
530 wm8776_write_cached(chip, reg_index, reg_value);
531}
532
533static int wm8776_field_set(struct snd_kcontrol *ctl, unsigned int value)
534{
535 struct oxygen *chip = ctl->private_data;
536 u8 min, max;
537 int changed;
538
539 min = (ctl->private_value >> 8) & 0xf;
540 max = (ctl->private_value >> 12) & 0xf;
541 if (value < min || value > max)
542 return -EINVAL;
543 mutex_lock(&chip->mutex);
544 changed = value != (ctl->private_value & 0xf);
545 if (changed) {
546 ctl->private_value = (ctl->private_value & ~0xf) | value;
547 wm8776_field_set_from_ctl(ctl);
548 }
549 mutex_unlock(&chip->mutex);
550 return changed;
551}
552
553static int wm8776_field_enum_get(struct snd_kcontrol *ctl,
554 struct snd_ctl_elem_value *value)
555{
556 value->value.enumerated.item[0] = ctl->private_value & 0xf;
557 return 0;
558}
559
560static int wm8776_field_volume_get(struct snd_kcontrol *ctl,
561 struct snd_ctl_elem_value *value)
562{
563 value->value.integer.value[0] = ctl->private_value & 0xf;
564 return 0;
565}
566
567static int wm8776_field_enum_put(struct snd_kcontrol *ctl,
568 struct snd_ctl_elem_value *value)
569{
570 return wm8776_field_set(ctl, value->value.enumerated.item[0]);
571}
572
573static int wm8776_field_volume_put(struct snd_kcontrol *ctl,
574 struct snd_ctl_elem_value *value)
575{
576 return wm8776_field_set(ctl, value->value.integer.value[0]);
577}
578
579static int wm8776_hp_vol_info(struct snd_kcontrol *ctl,
580 struct snd_ctl_elem_info *info)
581{
582 info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
583 info->count = 2;
584 info->value.integer.min = 0x79 - 60;
585 info->value.integer.max = 0x7f;
586 return 0;
587}
588
589static int wm8776_hp_vol_get(struct snd_kcontrol *ctl,
590 struct snd_ctl_elem_value *value)
591{
592 struct oxygen *chip = ctl->private_data;
593 struct xonar_wm87x6 *data = chip->model_data;
594
595 mutex_lock(&chip->mutex);
596 value->value.integer.value[0] =
597 data->wm8776_regs[WM8776_HPLVOL] & WM8776_HPATT_MASK;
598 value->value.integer.value[1] =
599 data->wm8776_regs[WM8776_HPRVOL] & WM8776_HPATT_MASK;
600 mutex_unlock(&chip->mutex);
601 return 0;
602}
603
604static int wm8776_hp_vol_put(struct snd_kcontrol *ctl,
605 struct snd_ctl_elem_value *value)
606{
607 struct oxygen *chip = ctl->private_data;
608 struct xonar_wm87x6 *data = chip->model_data;
609 u8 to_update;
610
611 mutex_lock(&chip->mutex);
612 to_update = (value->value.integer.value[0] !=
613 (data->wm8776_regs[WM8776_HPLVOL] & WM8776_HPATT_MASK))
614 << 0;
615 to_update |= (value->value.integer.value[1] !=
616 (data->wm8776_regs[WM8776_HPRVOL] & WM8776_HPATT_MASK))
617 << 1;
618 if (value->value.integer.value[0] == value->value.integer.value[1]) {
619 if (to_update) {
620 wm8776_write(chip, WM8776_HPMASTER,
621 value->value.integer.value[0] |
622 WM8776_HPZCEN | WM8776_UPDATE);
623 data->wm8776_regs[WM8776_HPLVOL] =
624 value->value.integer.value[0] | WM8776_HPZCEN;
625 data->wm8776_regs[WM8776_HPRVOL] =
626 value->value.integer.value[0] | WM8776_HPZCEN;
627 }
628 } else {
629 if (to_update & 1)
630 wm8776_write(chip, WM8776_HPLVOL,
631 value->value.integer.value[0] |
632 WM8776_HPZCEN |
633 ((to_update & 2) ? 0 : WM8776_UPDATE));
634 if (to_update & 2)
635 wm8776_write(chip, WM8776_HPRVOL,
636 value->value.integer.value[1] |
637 WM8776_HPZCEN | WM8776_UPDATE);
638 }
639 mutex_unlock(&chip->mutex);
640 return to_update != 0;
641}
642
643static int wm8776_input_mux_get(struct snd_kcontrol *ctl,
644 struct snd_ctl_elem_value *value)
645{
646 struct oxygen *chip = ctl->private_data;
647 struct xonar_wm87x6 *data = chip->model_data;
648 unsigned int mux_bit = ctl->private_value;
649
650 value->value.integer.value[0] =
651 !!(data->wm8776_regs[WM8776_ADCMUX] & mux_bit);
652 return 0;
653}
654
655static int wm8776_input_mux_put(struct snd_kcontrol *ctl,
656 struct snd_ctl_elem_value *value)
657{
658 struct oxygen *chip = ctl->private_data;
659 struct xonar_wm87x6 *data = chip->model_data;
Clemens Ladischfe6ce802010-09-07 13:38:49 +0200660 struct snd_kcontrol *other_ctl;
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100661 unsigned int mux_bit = ctl->private_value;
662 u16 reg;
663 int changed;
664
665 mutex_lock(&chip->mutex);
666 reg = data->wm8776_regs[WM8776_ADCMUX];
667 if (value->value.integer.value[0]) {
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100668 reg |= mux_bit;
Clemens Ladischfe6ce802010-09-07 13:38:49 +0200669 /* line-in and mic-in are exclusive */
670 mux_bit ^= 3;
671 if (reg & mux_bit) {
672 reg &= ~mux_bit;
673 if (mux_bit == 1)
674 other_ctl = data->line_adcmux_control;
675 else
676 other_ctl = data->mic_adcmux_control;
677 snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
678 &other_ctl->id);
679 }
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100680 } else
681 reg &= ~mux_bit;
682 changed = reg != data->wm8776_regs[WM8776_ADCMUX];
683 if (changed) {
684 oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
685 reg & 1 ? GPIO_DS_INPUT_ROUTE : 0,
686 GPIO_DS_INPUT_ROUTE);
687 wm8776_write(chip, WM8776_ADCMUX, reg);
688 }
689 mutex_unlock(&chip->mutex);
690 return changed;
691}
692
693static int wm8776_input_vol_info(struct snd_kcontrol *ctl,
694 struct snd_ctl_elem_info *info)
695{
696 info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
697 info->count = 2;
698 info->value.integer.min = 0xa5;
699 info->value.integer.max = 0xff;
700 return 0;
701}
702
703static int wm8776_input_vol_get(struct snd_kcontrol *ctl,
704 struct snd_ctl_elem_value *value)
705{
706 struct oxygen *chip = ctl->private_data;
707 struct xonar_wm87x6 *data = chip->model_data;
708
709 mutex_lock(&chip->mutex);
710 value->value.integer.value[0] =
711 data->wm8776_regs[WM8776_ADCLVOL] & WM8776_AGMASK;
712 value->value.integer.value[1] =
713 data->wm8776_regs[WM8776_ADCRVOL] & WM8776_AGMASK;
714 mutex_unlock(&chip->mutex);
715 return 0;
716}
717
718static int wm8776_input_vol_put(struct snd_kcontrol *ctl,
719 struct snd_ctl_elem_value *value)
720{
721 struct oxygen *chip = ctl->private_data;
722 struct xonar_wm87x6 *data = chip->model_data;
723 int changed = 0;
724
725 mutex_lock(&chip->mutex);
726 changed = (value->value.integer.value[0] !=
727 (data->wm8776_regs[WM8776_ADCLVOL] & WM8776_AGMASK)) ||
728 (value->value.integer.value[1] !=
729 (data->wm8776_regs[WM8776_ADCRVOL] & WM8776_AGMASK));
730 wm8776_write_cached(chip, WM8776_ADCLVOL,
731 value->value.integer.value[0] | WM8776_ZCA);
732 wm8776_write_cached(chip, WM8776_ADCRVOL,
733 value->value.integer.value[1] | WM8776_ZCA);
734 mutex_unlock(&chip->mutex);
735 return changed;
736}
737
738static int wm8776_level_control_info(struct snd_kcontrol *ctl,
739 struct snd_ctl_elem_info *info)
740{
741 static const char *const names[3] = {
742 "None", "Peak Limiter", "Automatic Level Control"
743 };
744 info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
745 info->count = 1;
746 info->value.enumerated.items = 3;
747 if (info->value.enumerated.item >= 3)
748 info->value.enumerated.item = 2;
749 strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
750 return 0;
751}
752
753static int wm8776_level_control_get(struct snd_kcontrol *ctl,
754 struct snd_ctl_elem_value *value)
755{
756 struct oxygen *chip = ctl->private_data;
757 struct xonar_wm87x6 *data = chip->model_data;
758
759 if (!(data->wm8776_regs[WM8776_ALCCTRL2] & WM8776_LCEN))
760 value->value.enumerated.item[0] = 0;
761 else if ((data->wm8776_regs[WM8776_ALCCTRL1] & WM8776_LCSEL_MASK) ==
762 WM8776_LCSEL_LIMITER)
763 value->value.enumerated.item[0] = 1;
764 else
765 value->value.enumerated.item[0] = 2;
766 return 0;
767}
768
769static void activate_control(struct oxygen *chip,
770 struct snd_kcontrol *ctl, unsigned int mode)
771{
772 unsigned int access;
773
774 if (ctl->private_value & mode)
775 access = 0;
776 else
777 access = SNDRV_CTL_ELEM_ACCESS_INACTIVE;
778 if ((ctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_INACTIVE) != access) {
779 ctl->vd[0].access ^= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
780 snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
781 }
782}
783
784static int wm8776_level_control_put(struct snd_kcontrol *ctl,
785 struct snd_ctl_elem_value *value)
786{
787 struct oxygen *chip = ctl->private_data;
788 struct xonar_wm87x6 *data = chip->model_data;
789 unsigned int mode = 0, i;
790 u16 ctrl1, ctrl2;
791 int changed;
792
793 if (value->value.enumerated.item[0] >= 3)
794 return -EINVAL;
795 mutex_lock(&chip->mutex);
796 changed = value->value.enumerated.item[0] != ctl->private_value;
797 if (changed) {
798 ctl->private_value = value->value.enumerated.item[0];
799 ctrl1 = data->wm8776_regs[WM8776_ALCCTRL1];
800 ctrl2 = data->wm8776_regs[WM8776_ALCCTRL2];
801 switch (value->value.enumerated.item[0]) {
802 default:
803 wm8776_write_cached(chip, WM8776_ALCCTRL2,
804 ctrl2 & ~WM8776_LCEN);
805 break;
806 case 1:
807 wm8776_write_cached(chip, WM8776_ALCCTRL1,
808 (ctrl1 & ~WM8776_LCSEL_MASK) |
809 WM8776_LCSEL_LIMITER);
810 wm8776_write_cached(chip, WM8776_ALCCTRL2,
811 ctrl2 | WM8776_LCEN);
812 mode = LC_CONTROL_LIMITER;
813 break;
814 case 2:
815 wm8776_write_cached(chip, WM8776_ALCCTRL1,
816 (ctrl1 & ~WM8776_LCSEL_MASK) |
817 WM8776_LCSEL_ALC_STEREO);
818 wm8776_write_cached(chip, WM8776_ALCCTRL2,
819 ctrl2 | WM8776_LCEN);
820 mode = LC_CONTROL_ALC;
821 break;
822 }
823 for (i = 0; i < ARRAY_SIZE(data->lc_controls); ++i)
824 activate_control(chip, data->lc_controls[i], mode);
825 }
826 mutex_unlock(&chip->mutex);
827 return changed;
828}
829
830static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
831{
832 static const char *const names[2] = {
833 "None", "High-pass Filter"
834 };
835
836 info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
837 info->count = 1;
838 info->value.enumerated.items = 2;
839 if (info->value.enumerated.item >= 2)
840 info->value.enumerated.item = 1;
841 strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
842 return 0;
843}
844
845static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
846{
847 struct oxygen *chip = ctl->private_data;
848 struct xonar_wm87x6 *data = chip->model_data;
849
850 value->value.enumerated.item[0] =
851 !(data->wm8776_regs[WM8776_ADCIFCTRL] & WM8776_ADCHPD);
852 return 0;
853}
854
855static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
856{
857 struct oxygen *chip = ctl->private_data;
858 struct xonar_wm87x6 *data = chip->model_data;
859 unsigned int reg;
860 int changed;
861
862 mutex_lock(&chip->mutex);
863 reg = data->wm8776_regs[WM8776_ADCIFCTRL] & ~WM8776_ADCHPD;
864 if (!value->value.enumerated.item[0])
865 reg |= WM8776_ADCHPD;
866 changed = reg != data->wm8776_regs[WM8776_ADCIFCTRL];
867 if (changed)
868 wm8776_write(chip, WM8776_ADCIFCTRL, reg);
869 mutex_unlock(&chip->mutex);
870 return changed;
871}
872
873#define WM8776_BIT_SWITCH(xname, reg, bit, invert, flags) { \
874 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
875 .name = xname, \
876 .info = snd_ctl_boolean_mono_info, \
877 .get = wm8776_bit_switch_get, \
878 .put = wm8776_bit_switch_put, \
879 .private_value = ((reg) << 16) | (bit) | ((invert) << 24) | (flags), \
880}
881#define _WM8776_FIELD_CTL(xname, reg, shift, initval, min, max, mask, flags) \
882 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
883 .name = xname, \
884 .private_value = (initval) | ((min) << 8) | ((max) << 12) | \
885 ((mask) << 16) | ((shift) << 20) | ((reg) << 24) | (flags)
886#define WM8776_FIELD_CTL_ENUM(xname, reg, shift, init, min, max, mask, flags) {\
887 _WM8776_FIELD_CTL(xname " Capture Enum", \
888 reg, shift, init, min, max, mask, flags), \
889 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
890 SNDRV_CTL_ELEM_ACCESS_INACTIVE, \
891 .info = wm8776_field_enum_info, \
892 .get = wm8776_field_enum_get, \
893 .put = wm8776_field_enum_put, \
894}
895#define WM8776_FIELD_CTL_VOLUME(a, b, c, d, e, f, g, h, tlv_p) { \
896 _WM8776_FIELD_CTL(a " Capture Volume", b, c, d, e, f, g, h), \
897 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
898 SNDRV_CTL_ELEM_ACCESS_INACTIVE | \
899 SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
900 .info = wm8776_field_volume_info, \
901 .get = wm8776_field_volume_get, \
902 .put = wm8776_field_volume_put, \
903 .tlv = { .p = tlv_p }, \
904}
905
906static const DECLARE_TLV_DB_SCALE(wm87x6_dac_db_scale, -6000, 50, 0);
907static const DECLARE_TLV_DB_SCALE(wm8776_adc_db_scale, -2100, 50, 0);
908static const DECLARE_TLV_DB_SCALE(wm8776_hp_db_scale, -6000, 100, 0);
909static const DECLARE_TLV_DB_SCALE(wm8776_lct_db_scale, -1600, 100, 0);
910static const DECLARE_TLV_DB_SCALE(wm8776_maxgain_db_scale, 0, 400, 0);
911static const DECLARE_TLV_DB_SCALE(wm8776_ngth_db_scale, -7800, 600, 0);
912static const DECLARE_TLV_DB_SCALE(wm8776_maxatten_lim_db_scale, -1200, 100, 0);
913static const DECLARE_TLV_DB_SCALE(wm8776_maxatten_alc_db_scale, -2100, 400, 0);
914
915static const struct snd_kcontrol_new ds_controls[] = {
916 {
917 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
918 .name = "Headphone Playback Volume",
919 .info = wm8776_hp_vol_info,
920 .get = wm8776_hp_vol_get,
921 .put = wm8776_hp_vol_put,
922 .tlv = { .p = wm8776_hp_db_scale },
923 },
924 WM8776_BIT_SWITCH("Headphone Playback Switch",
925 WM8776_PWRDOWN, WM8776_HPPD, 1, 0),
926 {
927 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
928 .name = "Input Capture Volume",
929 .info = wm8776_input_vol_info,
930 .get = wm8776_input_vol_get,
931 .put = wm8776_input_vol_put,
932 .tlv = { .p = wm8776_adc_db_scale },
933 },
934 {
935 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
936 .name = "Line Capture Switch",
937 .info = snd_ctl_boolean_mono_info,
938 .get = wm8776_input_mux_get,
939 .put = wm8776_input_mux_put,
940 .private_value = 1 << 0,
941 },
942 {
943 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
944 .name = "Mic Capture Switch",
945 .info = snd_ctl_boolean_mono_info,
946 .get = wm8776_input_mux_get,
947 .put = wm8776_input_mux_put,
948 .private_value = 1 << 1,
949 },
Clemens Ladisch9bac84e2010-09-09 12:19:21 +0200950 WM8776_BIT_SWITCH("Front Mic Capture Switch",
951 WM8776_ADCMUX, 1 << 2, 0, 0),
952 WM8776_BIT_SWITCH("Aux Capture Switch",
953 WM8776_ADCMUX, 1 << 3, 0, 0),
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100954 {
955 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
956 .name = "ADC Filter Capture Enum",
957 .info = hpf_info,
958 .get = hpf_get,
959 .put = hpf_put,
960 },
961 {
962 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
963 .name = "Level Control Capture Enum",
964 .info = wm8776_level_control_info,
965 .get = wm8776_level_control_get,
966 .put = wm8776_level_control_put,
967 .private_value = 0,
968 },
969};
970static const struct snd_kcontrol_new lc_controls[] = {
971 WM8776_FIELD_CTL_VOLUME("Limiter Threshold",
972 WM8776_ALCCTRL1, 0, 11, 0, 15, 0xf,
973 LC_CONTROL_LIMITER, wm8776_lct_db_scale),
974 WM8776_FIELD_CTL_ENUM("Limiter Attack Time",
975 WM8776_ALCCTRL3, 0, 2, 0, 10, 0xf,
976 LC_CONTROL_LIMITER),
977 WM8776_FIELD_CTL_ENUM("Limiter Decay Time",
978 WM8776_ALCCTRL3, 4, 3, 0, 10, 0xf,
979 LC_CONTROL_LIMITER),
980 WM8776_FIELD_CTL_ENUM("Limiter Transient Window",
981 WM8776_LIMITER, 4, 2, 0, 7, 0x7,
982 LC_CONTROL_LIMITER),
983 WM8776_FIELD_CTL_VOLUME("Limiter Maximum Attenuation",
984 WM8776_LIMITER, 0, 6, 3, 12, 0xf,
985 LC_CONTROL_LIMITER,
986 wm8776_maxatten_lim_db_scale),
987 WM8776_FIELD_CTL_VOLUME("ALC Target Level",
988 WM8776_ALCCTRL1, 0, 11, 0, 15, 0xf,
989 LC_CONTROL_ALC, wm8776_lct_db_scale),
990 WM8776_FIELD_CTL_ENUM("ALC Attack Time",
991 WM8776_ALCCTRL3, 0, 2, 0, 10, 0xf,
992 LC_CONTROL_ALC),
993 WM8776_FIELD_CTL_ENUM("ALC Decay Time",
994 WM8776_ALCCTRL3, 4, 3, 0, 10, 0xf,
995 LC_CONTROL_ALC),
996 WM8776_FIELD_CTL_VOLUME("ALC Maximum Gain",
997 WM8776_ALCCTRL1, 4, 7, 1, 7, 0x7,
998 LC_CONTROL_ALC, wm8776_maxgain_db_scale),
999 WM8776_FIELD_CTL_VOLUME("ALC Maximum Attenuation",
1000 WM8776_LIMITER, 0, 10, 10, 15, 0xf,
1001 LC_CONTROL_ALC, wm8776_maxatten_alc_db_scale),
1002 WM8776_FIELD_CTL_ENUM("ALC Hold Time",
1003 WM8776_ALCCTRL2, 0, 0, 0, 15, 0xf,
1004 LC_CONTROL_ALC),
1005 WM8776_BIT_SWITCH("Noise Gate Capture Switch",
1006 WM8776_NOISEGATE, WM8776_NGAT, 0,
1007 LC_CONTROL_ALC),
1008 WM8776_FIELD_CTL_VOLUME("Noise Gate Threshold",
1009 WM8776_NOISEGATE, 2, 0, 0, 7, 0x7,
1010 LC_CONTROL_ALC, wm8776_ngth_db_scale),
1011};
1012
1013static int xonar_ds_control_filter(struct snd_kcontrol_new *template)
1014{
1015 if (!strncmp(template->name, "CD Capture ", 11))
1016 return 1; /* no CD input */
1017 return 0;
1018}
1019
1020static int xonar_ds_mixer_init(struct oxygen *chip)
1021{
1022 struct xonar_wm87x6 *data = chip->model_data;
1023 unsigned int i;
1024 struct snd_kcontrol *ctl;
1025 int err;
1026
1027 for (i = 0; i < ARRAY_SIZE(ds_controls); ++i) {
1028 ctl = snd_ctl_new1(&ds_controls[i], chip);
1029 if (!ctl)
1030 return -ENOMEM;
1031 err = snd_ctl_add(chip->card, ctl);
1032 if (err < 0)
1033 return err;
Clemens Ladischfe6ce802010-09-07 13:38:49 +02001034 if (!strcmp(ctl->id.name, "Line Capture Switch"))
1035 data->line_adcmux_control = ctl;
1036 else if (!strcmp(ctl->id.name, "Mic Capture Switch"))
1037 data->mic_adcmux_control = ctl;
Clemens Ladischd1db38c2010-01-18 15:44:04 +01001038 }
Clemens Ladischfe6ce802010-09-07 13:38:49 +02001039 if (!data->line_adcmux_control || !data->mic_adcmux_control)
1040 return -ENXIO;
Clemens Ladischd1db38c2010-01-18 15:44:04 +01001041 BUILD_BUG_ON(ARRAY_SIZE(lc_controls) != ARRAY_SIZE(data->lc_controls));
1042 for (i = 0; i < ARRAY_SIZE(lc_controls); ++i) {
1043 ctl = snd_ctl_new1(&lc_controls[i], chip);
1044 if (!ctl)
1045 return -ENOMEM;
1046 err = snd_ctl_add(chip->card, ctl);
1047 if (err < 0)
1048 return err;
1049 data->lc_controls[i] = ctl;
1050 }
1051 return 0;
1052}
1053
1054static const struct oxygen_model model_xonar_ds = {
1055 .shortname = "Xonar DS",
1056 .longname = "Asus Virtuoso 200",
1057 .chip = "AV200",
1058 .init = xonar_ds_init,
1059 .control_filter = xonar_ds_control_filter,
1060 .mixer_init = xonar_ds_mixer_init,
1061 .cleanup = xonar_ds_cleanup,
1062 .suspend = xonar_ds_suspend,
1063 .resume = xonar_ds_resume,
1064 .pcm_hardware_filter = wm8776_adc_hardware_filter,
1065 .get_i2s_mclk = oxygen_default_i2s_mclk,
1066 .set_dac_params = set_wm87x6_dac_params,
1067 .set_adc_params = set_wm8776_adc_params,
1068 .update_dac_volume = update_wm87x6_volume,
1069 .update_dac_mute = update_wm87x6_mute,
1070 .gpio_changed = xonar_ds_gpio_changed,
1071 .dac_tlv = wm87x6_dac_db_scale,
1072 .model_data_size = sizeof(struct xonar_wm87x6),
1073 .device_config = PLAYBACK_0_TO_I2S |
1074 PLAYBACK_1_TO_SPDIF |
1075 CAPTURE_0_FROM_I2S_1,
1076 .dac_channels = 8,
1077 .dac_volume_min = 255 - 2*60,
1078 .dac_volume_max = 255,
1079 .function_flags = OXYGEN_FUNCTION_SPI,
1080 .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
1081 .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
1082};
1083
1084int __devinit get_xonar_wm87x6_model(struct oxygen *chip,
1085 const struct pci_device_id *id)
1086{
1087 switch (id->subdevice) {
1088 case 0x838e:
1089 chip->model = model_xonar_ds;
1090 break;
1091 default:
1092 return -EINVAL;
1093 }
1094 return 0;
1095}