blob: aceaaa036da6a07ec30074a7f8a4329f9f6d7b49 [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
Clemens Ladisch2dbf0ea2010-09-09 12:24:35 +0200380static void update_wm8766_center_lfe_mix(struct oxygen *chip, bool mixed)
381{
382 struct xonar_wm87x6 *data = chip->model_data;
383 unsigned int reg;
384
385 /*
386 * The WM8766 can mix left and right channels, but this setting
387 * applies to all three stereo pairs.
388 */
389 reg = data->wm8766_regs[WM8766_DAC_CTRL] &
390 ~(WM8766_PL_LEFT_MASK | WM8766_PL_RIGHT_MASK);
391 if (mixed)
392 reg |= WM8766_PL_LEFT_LRMIX | WM8766_PL_RIGHT_LRMIX;
393 else
394 reg |= WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT;
395 wm8766_write_cached(chip, WM8766_DAC_CTRL, reg);
396}
397
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100398static void xonar_ds_gpio_changed(struct oxygen *chip)
399{
Clemens Ladisch84cf83a2010-09-09 12:23:06 +0200400 xonar_ds_handle_hp_jack(chip);
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100401}
402
403static int wm8776_bit_switch_get(struct snd_kcontrol *ctl,
404 struct snd_ctl_elem_value *value)
405{
406 struct oxygen *chip = ctl->private_data;
407 struct xonar_wm87x6 *data = chip->model_data;
408 u16 bit = ctl->private_value & 0xffff;
409 unsigned int reg_index = (ctl->private_value >> 16) & 0xff;
410 bool invert = (ctl->private_value >> 24) & 1;
411
412 value->value.integer.value[0] =
413 ((data->wm8776_regs[reg_index] & bit) != 0) ^ invert;
414 return 0;
415}
416
417static int wm8776_bit_switch_put(struct snd_kcontrol *ctl,
418 struct snd_ctl_elem_value *value)
419{
420 struct oxygen *chip = ctl->private_data;
421 struct xonar_wm87x6 *data = chip->model_data;
422 u16 bit = ctl->private_value & 0xffff;
423 u16 reg_value;
424 unsigned int reg_index = (ctl->private_value >> 16) & 0xff;
425 bool invert = (ctl->private_value >> 24) & 1;
426 int changed;
427
428 mutex_lock(&chip->mutex);
429 reg_value = data->wm8776_regs[reg_index] & ~bit;
430 if (value->value.integer.value[0] ^ invert)
431 reg_value |= bit;
432 changed = reg_value != data->wm8776_regs[reg_index];
433 if (changed)
434 wm8776_write(chip, reg_index, reg_value);
435 mutex_unlock(&chip->mutex);
436 return changed;
437}
438
439static int wm8776_field_enum_info(struct snd_kcontrol *ctl,
440 struct snd_ctl_elem_info *info)
441{
442 static const char *const hld[16] = {
443 "0 ms", "2.67 ms", "5.33 ms", "10.6 ms",
444 "21.3 ms", "42.7 ms", "85.3 ms", "171 ms",
445 "341 ms", "683 ms", "1.37 s", "2.73 s",
446 "5.46 s", "10.9 s", "21.8 s", "43.7 s",
447 };
448 static const char *const atk_lim[11] = {
449 "0.25 ms", "0.5 ms", "1 ms", "2 ms",
450 "4 ms", "8 ms", "16 ms", "32 ms",
451 "64 ms", "128 ms", "256 ms",
452 };
453 static const char *const atk_alc[11] = {
454 "8.40 ms", "16.8 ms", "33.6 ms", "67.2 ms",
455 "134 ms", "269 ms", "538 ms", "1.08 s",
456 "2.15 s", "4.3 s", "8.6 s",
457 };
458 static const char *const dcy_lim[11] = {
459 "1.2 ms", "2.4 ms", "4.8 ms", "9.6 ms",
460 "19.2 ms", "38.4 ms", "76.8 ms", "154 ms",
461 "307 ms", "614 ms", "1.23 s",
462 };
463 static const char *const dcy_alc[11] = {
464 "33.5 ms", "67.0 ms", "134 ms", "268 ms",
465 "536 ms", "1.07 s", "2.14 s", "4.29 s",
466 "8.58 s", "17.2 s", "34.3 s",
467 };
468 static const char *const tranwin[8] = {
469 "0 us", "62.5 us", "125 us", "250 us",
470 "500 us", "1 ms", "2 ms", "4 ms",
471 };
472 u8 max;
473 const char *const *names;
474
475 max = (ctl->private_value >> 12) & 0xf;
476 info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
477 info->count = 1;
478 info->value.enumerated.items = max + 1;
479 if (info->value.enumerated.item > max)
480 info->value.enumerated.item = max;
481 switch ((ctl->private_value >> 24) & 0x1f) {
482 case WM8776_ALCCTRL2:
483 names = hld;
484 break;
485 case WM8776_ALCCTRL3:
486 if (((ctl->private_value >> 20) & 0xf) == 0) {
487 if (ctl->private_value & LC_CONTROL_LIMITER)
488 names = atk_lim;
489 else
490 names = atk_alc;
491 } else {
492 if (ctl->private_value & LC_CONTROL_LIMITER)
493 names = dcy_lim;
494 else
495 names = dcy_alc;
496 }
497 break;
498 case WM8776_LIMITER:
499 names = tranwin;
500 break;
501 default:
502 return -ENXIO;
503 }
504 strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
505 return 0;
506}
507
508static int wm8776_field_volume_info(struct snd_kcontrol *ctl,
509 struct snd_ctl_elem_info *info)
510{
511 info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
512 info->count = 1;
513 info->value.integer.min = (ctl->private_value >> 8) & 0xf;
514 info->value.integer.max = (ctl->private_value >> 12) & 0xf;
515 return 0;
516}
517
518static void wm8776_field_set_from_ctl(struct snd_kcontrol *ctl)
519{
520 struct oxygen *chip = ctl->private_data;
521 struct xonar_wm87x6 *data = chip->model_data;
522 unsigned int value, reg_index, mode;
523 u8 min, max, shift;
524 u16 mask, reg_value;
525 bool invert;
526
527 if ((data->wm8776_regs[WM8776_ALCCTRL1] & WM8776_LCSEL_MASK) ==
528 WM8776_LCSEL_LIMITER)
529 mode = LC_CONTROL_LIMITER;
530 else
531 mode = LC_CONTROL_ALC;
532 if (!(ctl->private_value & mode))
533 return;
534
535 value = ctl->private_value & 0xf;
536 min = (ctl->private_value >> 8) & 0xf;
537 max = (ctl->private_value >> 12) & 0xf;
538 mask = (ctl->private_value >> 16) & 0xf;
539 shift = (ctl->private_value >> 20) & 0xf;
540 reg_index = (ctl->private_value >> 24) & 0x1f;
541 invert = (ctl->private_value >> 29) & 0x1;
542
543 if (invert)
544 value = max - (value - min);
545 reg_value = data->wm8776_regs[reg_index];
546 reg_value &= ~(mask << shift);
547 reg_value |= value << shift;
548 wm8776_write_cached(chip, reg_index, reg_value);
549}
550
551static int wm8776_field_set(struct snd_kcontrol *ctl, unsigned int value)
552{
553 struct oxygen *chip = ctl->private_data;
554 u8 min, max;
555 int changed;
556
557 min = (ctl->private_value >> 8) & 0xf;
558 max = (ctl->private_value >> 12) & 0xf;
559 if (value < min || value > max)
560 return -EINVAL;
561 mutex_lock(&chip->mutex);
562 changed = value != (ctl->private_value & 0xf);
563 if (changed) {
564 ctl->private_value = (ctl->private_value & ~0xf) | value;
565 wm8776_field_set_from_ctl(ctl);
566 }
567 mutex_unlock(&chip->mutex);
568 return changed;
569}
570
571static int wm8776_field_enum_get(struct snd_kcontrol *ctl,
572 struct snd_ctl_elem_value *value)
573{
574 value->value.enumerated.item[0] = ctl->private_value & 0xf;
575 return 0;
576}
577
578static int wm8776_field_volume_get(struct snd_kcontrol *ctl,
579 struct snd_ctl_elem_value *value)
580{
581 value->value.integer.value[0] = ctl->private_value & 0xf;
582 return 0;
583}
584
585static int wm8776_field_enum_put(struct snd_kcontrol *ctl,
586 struct snd_ctl_elem_value *value)
587{
588 return wm8776_field_set(ctl, value->value.enumerated.item[0]);
589}
590
591static int wm8776_field_volume_put(struct snd_kcontrol *ctl,
592 struct snd_ctl_elem_value *value)
593{
594 return wm8776_field_set(ctl, value->value.integer.value[0]);
595}
596
597static int wm8776_hp_vol_info(struct snd_kcontrol *ctl,
598 struct snd_ctl_elem_info *info)
599{
600 info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
601 info->count = 2;
602 info->value.integer.min = 0x79 - 60;
603 info->value.integer.max = 0x7f;
604 return 0;
605}
606
607static int wm8776_hp_vol_get(struct snd_kcontrol *ctl,
608 struct snd_ctl_elem_value *value)
609{
610 struct oxygen *chip = ctl->private_data;
611 struct xonar_wm87x6 *data = chip->model_data;
612
613 mutex_lock(&chip->mutex);
614 value->value.integer.value[0] =
615 data->wm8776_regs[WM8776_HPLVOL] & WM8776_HPATT_MASK;
616 value->value.integer.value[1] =
617 data->wm8776_regs[WM8776_HPRVOL] & WM8776_HPATT_MASK;
618 mutex_unlock(&chip->mutex);
619 return 0;
620}
621
622static int wm8776_hp_vol_put(struct snd_kcontrol *ctl,
623 struct snd_ctl_elem_value *value)
624{
625 struct oxygen *chip = ctl->private_data;
626 struct xonar_wm87x6 *data = chip->model_data;
627 u8 to_update;
628
629 mutex_lock(&chip->mutex);
630 to_update = (value->value.integer.value[0] !=
631 (data->wm8776_regs[WM8776_HPLVOL] & WM8776_HPATT_MASK))
632 << 0;
633 to_update |= (value->value.integer.value[1] !=
634 (data->wm8776_regs[WM8776_HPRVOL] & WM8776_HPATT_MASK))
635 << 1;
636 if (value->value.integer.value[0] == value->value.integer.value[1]) {
637 if (to_update) {
638 wm8776_write(chip, WM8776_HPMASTER,
639 value->value.integer.value[0] |
640 WM8776_HPZCEN | WM8776_UPDATE);
641 data->wm8776_regs[WM8776_HPLVOL] =
642 value->value.integer.value[0] | WM8776_HPZCEN;
643 data->wm8776_regs[WM8776_HPRVOL] =
644 value->value.integer.value[0] | WM8776_HPZCEN;
645 }
646 } else {
647 if (to_update & 1)
648 wm8776_write(chip, WM8776_HPLVOL,
649 value->value.integer.value[0] |
650 WM8776_HPZCEN |
651 ((to_update & 2) ? 0 : WM8776_UPDATE));
652 if (to_update & 2)
653 wm8776_write(chip, WM8776_HPRVOL,
654 value->value.integer.value[1] |
655 WM8776_HPZCEN | WM8776_UPDATE);
656 }
657 mutex_unlock(&chip->mutex);
658 return to_update != 0;
659}
660
661static int wm8776_input_mux_get(struct snd_kcontrol *ctl,
662 struct snd_ctl_elem_value *value)
663{
664 struct oxygen *chip = ctl->private_data;
665 struct xonar_wm87x6 *data = chip->model_data;
666 unsigned int mux_bit = ctl->private_value;
667
668 value->value.integer.value[0] =
669 !!(data->wm8776_regs[WM8776_ADCMUX] & mux_bit);
670 return 0;
671}
672
673static int wm8776_input_mux_put(struct snd_kcontrol *ctl,
674 struct snd_ctl_elem_value *value)
675{
676 struct oxygen *chip = ctl->private_data;
677 struct xonar_wm87x6 *data = chip->model_data;
Clemens Ladischfe6ce802010-09-07 13:38:49 +0200678 struct snd_kcontrol *other_ctl;
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100679 unsigned int mux_bit = ctl->private_value;
680 u16 reg;
681 int changed;
682
683 mutex_lock(&chip->mutex);
684 reg = data->wm8776_regs[WM8776_ADCMUX];
685 if (value->value.integer.value[0]) {
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100686 reg |= mux_bit;
Clemens Ladischfe6ce802010-09-07 13:38:49 +0200687 /* line-in and mic-in are exclusive */
688 mux_bit ^= 3;
689 if (reg & mux_bit) {
690 reg &= ~mux_bit;
691 if (mux_bit == 1)
692 other_ctl = data->line_adcmux_control;
693 else
694 other_ctl = data->mic_adcmux_control;
695 snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
696 &other_ctl->id);
697 }
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100698 } else
699 reg &= ~mux_bit;
700 changed = reg != data->wm8776_regs[WM8776_ADCMUX];
701 if (changed) {
702 oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
703 reg & 1 ? GPIO_DS_INPUT_ROUTE : 0,
704 GPIO_DS_INPUT_ROUTE);
705 wm8776_write(chip, WM8776_ADCMUX, reg);
706 }
707 mutex_unlock(&chip->mutex);
708 return changed;
709}
710
711static int wm8776_input_vol_info(struct snd_kcontrol *ctl,
712 struct snd_ctl_elem_info *info)
713{
714 info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
715 info->count = 2;
716 info->value.integer.min = 0xa5;
717 info->value.integer.max = 0xff;
718 return 0;
719}
720
721static int wm8776_input_vol_get(struct snd_kcontrol *ctl,
722 struct snd_ctl_elem_value *value)
723{
724 struct oxygen *chip = ctl->private_data;
725 struct xonar_wm87x6 *data = chip->model_data;
726
727 mutex_lock(&chip->mutex);
728 value->value.integer.value[0] =
729 data->wm8776_regs[WM8776_ADCLVOL] & WM8776_AGMASK;
730 value->value.integer.value[1] =
731 data->wm8776_regs[WM8776_ADCRVOL] & WM8776_AGMASK;
732 mutex_unlock(&chip->mutex);
733 return 0;
734}
735
736static int wm8776_input_vol_put(struct snd_kcontrol *ctl,
737 struct snd_ctl_elem_value *value)
738{
739 struct oxygen *chip = ctl->private_data;
740 struct xonar_wm87x6 *data = chip->model_data;
741 int changed = 0;
742
743 mutex_lock(&chip->mutex);
744 changed = (value->value.integer.value[0] !=
745 (data->wm8776_regs[WM8776_ADCLVOL] & WM8776_AGMASK)) ||
746 (value->value.integer.value[1] !=
747 (data->wm8776_regs[WM8776_ADCRVOL] & WM8776_AGMASK));
748 wm8776_write_cached(chip, WM8776_ADCLVOL,
749 value->value.integer.value[0] | WM8776_ZCA);
750 wm8776_write_cached(chip, WM8776_ADCRVOL,
751 value->value.integer.value[1] | WM8776_ZCA);
752 mutex_unlock(&chip->mutex);
753 return changed;
754}
755
756static int wm8776_level_control_info(struct snd_kcontrol *ctl,
757 struct snd_ctl_elem_info *info)
758{
759 static const char *const names[3] = {
760 "None", "Peak Limiter", "Automatic Level Control"
761 };
762 info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
763 info->count = 1;
764 info->value.enumerated.items = 3;
765 if (info->value.enumerated.item >= 3)
766 info->value.enumerated.item = 2;
767 strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
768 return 0;
769}
770
771static int wm8776_level_control_get(struct snd_kcontrol *ctl,
772 struct snd_ctl_elem_value *value)
773{
774 struct oxygen *chip = ctl->private_data;
775 struct xonar_wm87x6 *data = chip->model_data;
776
777 if (!(data->wm8776_regs[WM8776_ALCCTRL2] & WM8776_LCEN))
778 value->value.enumerated.item[0] = 0;
779 else if ((data->wm8776_regs[WM8776_ALCCTRL1] & WM8776_LCSEL_MASK) ==
780 WM8776_LCSEL_LIMITER)
781 value->value.enumerated.item[0] = 1;
782 else
783 value->value.enumerated.item[0] = 2;
784 return 0;
785}
786
787static void activate_control(struct oxygen *chip,
788 struct snd_kcontrol *ctl, unsigned int mode)
789{
790 unsigned int access;
791
792 if (ctl->private_value & mode)
793 access = 0;
794 else
795 access = SNDRV_CTL_ELEM_ACCESS_INACTIVE;
796 if ((ctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_INACTIVE) != access) {
797 ctl->vd[0].access ^= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
798 snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
799 }
800}
801
802static int wm8776_level_control_put(struct snd_kcontrol *ctl,
803 struct snd_ctl_elem_value *value)
804{
805 struct oxygen *chip = ctl->private_data;
806 struct xonar_wm87x6 *data = chip->model_data;
807 unsigned int mode = 0, i;
808 u16 ctrl1, ctrl2;
809 int changed;
810
811 if (value->value.enumerated.item[0] >= 3)
812 return -EINVAL;
813 mutex_lock(&chip->mutex);
814 changed = value->value.enumerated.item[0] != ctl->private_value;
815 if (changed) {
816 ctl->private_value = value->value.enumerated.item[0];
817 ctrl1 = data->wm8776_regs[WM8776_ALCCTRL1];
818 ctrl2 = data->wm8776_regs[WM8776_ALCCTRL2];
819 switch (value->value.enumerated.item[0]) {
820 default:
821 wm8776_write_cached(chip, WM8776_ALCCTRL2,
822 ctrl2 & ~WM8776_LCEN);
823 break;
824 case 1:
825 wm8776_write_cached(chip, WM8776_ALCCTRL1,
826 (ctrl1 & ~WM8776_LCSEL_MASK) |
827 WM8776_LCSEL_LIMITER);
828 wm8776_write_cached(chip, WM8776_ALCCTRL2,
829 ctrl2 | WM8776_LCEN);
830 mode = LC_CONTROL_LIMITER;
831 break;
832 case 2:
833 wm8776_write_cached(chip, WM8776_ALCCTRL1,
834 (ctrl1 & ~WM8776_LCSEL_MASK) |
835 WM8776_LCSEL_ALC_STEREO);
836 wm8776_write_cached(chip, WM8776_ALCCTRL2,
837 ctrl2 | WM8776_LCEN);
838 mode = LC_CONTROL_ALC;
839 break;
840 }
841 for (i = 0; i < ARRAY_SIZE(data->lc_controls); ++i)
842 activate_control(chip, data->lc_controls[i], mode);
843 }
844 mutex_unlock(&chip->mutex);
845 return changed;
846}
847
848static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
849{
850 static const char *const names[2] = {
851 "None", "High-pass Filter"
852 };
853
854 info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
855 info->count = 1;
856 info->value.enumerated.items = 2;
857 if (info->value.enumerated.item >= 2)
858 info->value.enumerated.item = 1;
859 strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
860 return 0;
861}
862
863static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
864{
865 struct oxygen *chip = ctl->private_data;
866 struct xonar_wm87x6 *data = chip->model_data;
867
868 value->value.enumerated.item[0] =
869 !(data->wm8776_regs[WM8776_ADCIFCTRL] & WM8776_ADCHPD);
870 return 0;
871}
872
873static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
874{
875 struct oxygen *chip = ctl->private_data;
876 struct xonar_wm87x6 *data = chip->model_data;
877 unsigned int reg;
878 int changed;
879
880 mutex_lock(&chip->mutex);
881 reg = data->wm8776_regs[WM8776_ADCIFCTRL] & ~WM8776_ADCHPD;
882 if (!value->value.enumerated.item[0])
883 reg |= WM8776_ADCHPD;
884 changed = reg != data->wm8776_regs[WM8776_ADCIFCTRL];
885 if (changed)
886 wm8776_write(chip, WM8776_ADCIFCTRL, reg);
887 mutex_unlock(&chip->mutex);
888 return changed;
889}
890
891#define WM8776_BIT_SWITCH(xname, reg, bit, invert, flags) { \
892 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
893 .name = xname, \
894 .info = snd_ctl_boolean_mono_info, \
895 .get = wm8776_bit_switch_get, \
896 .put = wm8776_bit_switch_put, \
897 .private_value = ((reg) << 16) | (bit) | ((invert) << 24) | (flags), \
898}
899#define _WM8776_FIELD_CTL(xname, reg, shift, initval, min, max, mask, flags) \
900 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
901 .name = xname, \
902 .private_value = (initval) | ((min) << 8) | ((max) << 12) | \
903 ((mask) << 16) | ((shift) << 20) | ((reg) << 24) | (flags)
904#define WM8776_FIELD_CTL_ENUM(xname, reg, shift, init, min, max, mask, flags) {\
905 _WM8776_FIELD_CTL(xname " Capture Enum", \
906 reg, shift, init, min, max, mask, flags), \
907 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
908 SNDRV_CTL_ELEM_ACCESS_INACTIVE, \
909 .info = wm8776_field_enum_info, \
910 .get = wm8776_field_enum_get, \
911 .put = wm8776_field_enum_put, \
912}
913#define WM8776_FIELD_CTL_VOLUME(a, b, c, d, e, f, g, h, tlv_p) { \
914 _WM8776_FIELD_CTL(a " Capture Volume", b, c, d, e, f, g, h), \
915 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
916 SNDRV_CTL_ELEM_ACCESS_INACTIVE | \
917 SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
918 .info = wm8776_field_volume_info, \
919 .get = wm8776_field_volume_get, \
920 .put = wm8776_field_volume_put, \
921 .tlv = { .p = tlv_p }, \
922}
923
924static const DECLARE_TLV_DB_SCALE(wm87x6_dac_db_scale, -6000, 50, 0);
925static const DECLARE_TLV_DB_SCALE(wm8776_adc_db_scale, -2100, 50, 0);
926static const DECLARE_TLV_DB_SCALE(wm8776_hp_db_scale, -6000, 100, 0);
927static const DECLARE_TLV_DB_SCALE(wm8776_lct_db_scale, -1600, 100, 0);
928static const DECLARE_TLV_DB_SCALE(wm8776_maxgain_db_scale, 0, 400, 0);
929static const DECLARE_TLV_DB_SCALE(wm8776_ngth_db_scale, -7800, 600, 0);
930static const DECLARE_TLV_DB_SCALE(wm8776_maxatten_lim_db_scale, -1200, 100, 0);
931static const DECLARE_TLV_DB_SCALE(wm8776_maxatten_alc_db_scale, -2100, 400, 0);
932
933static const struct snd_kcontrol_new ds_controls[] = {
934 {
935 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
936 .name = "Headphone Playback Volume",
937 .info = wm8776_hp_vol_info,
938 .get = wm8776_hp_vol_get,
939 .put = wm8776_hp_vol_put,
940 .tlv = { .p = wm8776_hp_db_scale },
941 },
942 WM8776_BIT_SWITCH("Headphone Playback Switch",
943 WM8776_PWRDOWN, WM8776_HPPD, 1, 0),
944 {
945 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
946 .name = "Input Capture Volume",
947 .info = wm8776_input_vol_info,
948 .get = wm8776_input_vol_get,
949 .put = wm8776_input_vol_put,
950 .tlv = { .p = wm8776_adc_db_scale },
951 },
952 {
953 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
954 .name = "Line Capture Switch",
955 .info = snd_ctl_boolean_mono_info,
956 .get = wm8776_input_mux_get,
957 .put = wm8776_input_mux_put,
958 .private_value = 1 << 0,
959 },
960 {
961 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
962 .name = "Mic Capture Switch",
963 .info = snd_ctl_boolean_mono_info,
964 .get = wm8776_input_mux_get,
965 .put = wm8776_input_mux_put,
966 .private_value = 1 << 1,
967 },
Clemens Ladisch9bac84e2010-09-09 12:19:21 +0200968 WM8776_BIT_SWITCH("Front Mic Capture Switch",
969 WM8776_ADCMUX, 1 << 2, 0, 0),
970 WM8776_BIT_SWITCH("Aux Capture Switch",
971 WM8776_ADCMUX, 1 << 3, 0, 0),
Clemens Ladischd1db38c2010-01-18 15:44:04 +0100972 {
973 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
974 .name = "ADC Filter Capture Enum",
975 .info = hpf_info,
976 .get = hpf_get,
977 .put = hpf_put,
978 },
979 {
980 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
981 .name = "Level Control Capture Enum",
982 .info = wm8776_level_control_info,
983 .get = wm8776_level_control_get,
984 .put = wm8776_level_control_put,
985 .private_value = 0,
986 },
987};
988static const struct snd_kcontrol_new lc_controls[] = {
989 WM8776_FIELD_CTL_VOLUME("Limiter Threshold",
990 WM8776_ALCCTRL1, 0, 11, 0, 15, 0xf,
991 LC_CONTROL_LIMITER, wm8776_lct_db_scale),
992 WM8776_FIELD_CTL_ENUM("Limiter Attack Time",
993 WM8776_ALCCTRL3, 0, 2, 0, 10, 0xf,
994 LC_CONTROL_LIMITER),
995 WM8776_FIELD_CTL_ENUM("Limiter Decay Time",
996 WM8776_ALCCTRL3, 4, 3, 0, 10, 0xf,
997 LC_CONTROL_LIMITER),
998 WM8776_FIELD_CTL_ENUM("Limiter Transient Window",
999 WM8776_LIMITER, 4, 2, 0, 7, 0x7,
1000 LC_CONTROL_LIMITER),
1001 WM8776_FIELD_CTL_VOLUME("Limiter Maximum Attenuation",
1002 WM8776_LIMITER, 0, 6, 3, 12, 0xf,
1003 LC_CONTROL_LIMITER,
1004 wm8776_maxatten_lim_db_scale),
1005 WM8776_FIELD_CTL_VOLUME("ALC Target Level",
1006 WM8776_ALCCTRL1, 0, 11, 0, 15, 0xf,
1007 LC_CONTROL_ALC, wm8776_lct_db_scale),
1008 WM8776_FIELD_CTL_ENUM("ALC Attack Time",
1009 WM8776_ALCCTRL3, 0, 2, 0, 10, 0xf,
1010 LC_CONTROL_ALC),
1011 WM8776_FIELD_CTL_ENUM("ALC Decay Time",
1012 WM8776_ALCCTRL3, 4, 3, 0, 10, 0xf,
1013 LC_CONTROL_ALC),
1014 WM8776_FIELD_CTL_VOLUME("ALC Maximum Gain",
1015 WM8776_ALCCTRL1, 4, 7, 1, 7, 0x7,
1016 LC_CONTROL_ALC, wm8776_maxgain_db_scale),
1017 WM8776_FIELD_CTL_VOLUME("ALC Maximum Attenuation",
1018 WM8776_LIMITER, 0, 10, 10, 15, 0xf,
1019 LC_CONTROL_ALC, wm8776_maxatten_alc_db_scale),
1020 WM8776_FIELD_CTL_ENUM("ALC Hold Time",
1021 WM8776_ALCCTRL2, 0, 0, 0, 15, 0xf,
1022 LC_CONTROL_ALC),
1023 WM8776_BIT_SWITCH("Noise Gate Capture Switch",
1024 WM8776_NOISEGATE, WM8776_NGAT, 0,
1025 LC_CONTROL_ALC),
1026 WM8776_FIELD_CTL_VOLUME("Noise Gate Threshold",
1027 WM8776_NOISEGATE, 2, 0, 0, 7, 0x7,
1028 LC_CONTROL_ALC, wm8776_ngth_db_scale),
1029};
1030
1031static int xonar_ds_control_filter(struct snd_kcontrol_new *template)
1032{
1033 if (!strncmp(template->name, "CD Capture ", 11))
1034 return 1; /* no CD input */
1035 return 0;
1036}
1037
1038static int xonar_ds_mixer_init(struct oxygen *chip)
1039{
1040 struct xonar_wm87x6 *data = chip->model_data;
1041 unsigned int i;
1042 struct snd_kcontrol *ctl;
1043 int err;
1044
1045 for (i = 0; i < ARRAY_SIZE(ds_controls); ++i) {
1046 ctl = snd_ctl_new1(&ds_controls[i], chip);
1047 if (!ctl)
1048 return -ENOMEM;
1049 err = snd_ctl_add(chip->card, ctl);
1050 if (err < 0)
1051 return err;
Clemens Ladischfe6ce802010-09-07 13:38:49 +02001052 if (!strcmp(ctl->id.name, "Line Capture Switch"))
1053 data->line_adcmux_control = ctl;
1054 else if (!strcmp(ctl->id.name, "Mic Capture Switch"))
1055 data->mic_adcmux_control = ctl;
Clemens Ladischd1db38c2010-01-18 15:44:04 +01001056 }
Clemens Ladischfe6ce802010-09-07 13:38:49 +02001057 if (!data->line_adcmux_control || !data->mic_adcmux_control)
1058 return -ENXIO;
Clemens Ladischd1db38c2010-01-18 15:44:04 +01001059 BUILD_BUG_ON(ARRAY_SIZE(lc_controls) != ARRAY_SIZE(data->lc_controls));
1060 for (i = 0; i < ARRAY_SIZE(lc_controls); ++i) {
1061 ctl = snd_ctl_new1(&lc_controls[i], chip);
1062 if (!ctl)
1063 return -ENOMEM;
1064 err = snd_ctl_add(chip->card, ctl);
1065 if (err < 0)
1066 return err;
1067 data->lc_controls[i] = ctl;
1068 }
1069 return 0;
1070}
1071
1072static const struct oxygen_model model_xonar_ds = {
1073 .shortname = "Xonar DS",
1074 .longname = "Asus Virtuoso 200",
1075 .chip = "AV200",
1076 .init = xonar_ds_init,
1077 .control_filter = xonar_ds_control_filter,
1078 .mixer_init = xonar_ds_mixer_init,
1079 .cleanup = xonar_ds_cleanup,
1080 .suspend = xonar_ds_suspend,
1081 .resume = xonar_ds_resume,
1082 .pcm_hardware_filter = wm8776_adc_hardware_filter,
1083 .get_i2s_mclk = oxygen_default_i2s_mclk,
1084 .set_dac_params = set_wm87x6_dac_params,
1085 .set_adc_params = set_wm8776_adc_params,
1086 .update_dac_volume = update_wm87x6_volume,
1087 .update_dac_mute = update_wm87x6_mute,
Clemens Ladisch2dbf0ea2010-09-09 12:24:35 +02001088 .update_center_lfe_mix = update_wm8766_center_lfe_mix,
Clemens Ladischd1db38c2010-01-18 15:44:04 +01001089 .gpio_changed = xonar_ds_gpio_changed,
1090 .dac_tlv = wm87x6_dac_db_scale,
1091 .model_data_size = sizeof(struct xonar_wm87x6),
1092 .device_config = PLAYBACK_0_TO_I2S |
1093 PLAYBACK_1_TO_SPDIF |
1094 CAPTURE_0_FROM_I2S_1,
1095 .dac_channels = 8,
1096 .dac_volume_min = 255 - 2*60,
1097 .dac_volume_max = 255,
1098 .function_flags = OXYGEN_FUNCTION_SPI,
1099 .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
1100 .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
1101};
1102
1103int __devinit get_xonar_wm87x6_model(struct oxygen *chip,
1104 const struct pci_device_id *id)
1105{
1106 switch (id->subdevice) {
1107 case 0x838e:
1108 chip->model = model_xonar_ds;
1109 break;
1110 default:
1111 return -EINVAL;
1112 }
1113 return 0;
1114}