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