]> git.karo-electronics.de Git - karo-tx-linux.git/blob - sound/pci/oxygen/xonar_dg.c
ALSA: oxygen: modify adjust_dg_dac_routing function
[karo-tx-linux.git] / sound / pci / oxygen / xonar_dg.c
1 /*
2  * card driver for the Xonar DG/DGX
3  *
4  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
5  * Copyright (c) Roman Volkov <v1ron@mail.ru>
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 DG/DGX
21  * ------------
22  *
23  * CS4245 and CS4361 both will mute all outputs if any clock ratio
24  * is invalid.
25  *
26  * CMI8788:
27  *
28  *   SPI 0 -> CS4245
29  *
30  *   Playback:
31  *   I²S 1 -> CS4245
32  *   I²S 2 -> CS4361 (center/LFE)
33  *   I²S 3 -> CS4361 (surround)
34  *   I²S 4 -> CS4361 (front)
35  *   Capture:
36  *   I²S ADC 1 <- CS4245
37  *
38  *   GPIO 3 <- ?
39  *   GPIO 4 <- headphone detect
40  *   GPIO 5 -> enable ADC analog circuit for the left channel
41  *   GPIO 6 -> enable ADC analog circuit for the right channel
42  *   GPIO 7 -> switch green rear output jack between CS4245 and and the first
43  *             channel of CS4361 (mechanical relay)
44  *   GPIO 8 -> enable output to speakers
45  *
46  * CS4245:
47  *
48  *   input 0 <- mic
49  *   input 1 <- aux
50  *   input 2 <- front mic
51  *   input 4 <- line
52  *   DAC out -> headphones
53  *   aux out -> front panel headphones
54  */
55
56 #include <linux/pci.h>
57 #include <linux/delay.h>
58 #include <sound/control.h>
59 #include <sound/core.h>
60 #include <sound/info.h>
61 #include <sound/pcm.h>
62 #include <sound/tlv.h>
63 #include "oxygen.h"
64 #include "xonar_dg.h"
65 #include "cs4245.h"
66
67 int cs4245_write_spi(struct oxygen *chip, u8 reg)
68 {
69         struct dg *data = chip->model_data;
70         unsigned int packet;
71
72         packet = reg << 8;
73         packet |= (CS4245_SPI_ADDRESS | CS4245_SPI_WRITE) << 16;
74         packet |= data->cs4245_shadow[reg];
75
76         return oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
77                                 OXYGEN_SPI_DATA_LENGTH_3 |
78                                 OXYGEN_SPI_CLOCK_1280 |
79                                 (0 << OXYGEN_SPI_CODEC_SHIFT) |
80                                 OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
81                                 packet);
82 }
83
84 int cs4245_read_spi(struct oxygen *chip, u8 addr)
85 {
86         struct dg *data = chip->model_data;
87         int ret;
88
89         ret = oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
90                 OXYGEN_SPI_DATA_LENGTH_2 |
91                 OXYGEN_SPI_CEN_LATCH_CLOCK_HI |
92                 OXYGEN_SPI_CLOCK_1280 | (0 << OXYGEN_SPI_CODEC_SHIFT),
93                 ((CS4245_SPI_ADDRESS | CS4245_SPI_WRITE) << 8) | addr);
94         if (ret < 0)
95                 return ret;
96
97         ret = oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
98                 OXYGEN_SPI_DATA_LENGTH_2 |
99                 OXYGEN_SPI_CEN_LATCH_CLOCK_HI |
100                 OXYGEN_SPI_CLOCK_1280 | (0 << OXYGEN_SPI_CODEC_SHIFT),
101                 (CS4245_SPI_ADDRESS | CS4245_SPI_READ) << 8);
102         if (ret < 0)
103                 return ret;
104
105         data->cs4245_shadow[addr] = oxygen_read8(chip, OXYGEN_SPI_DATA1);
106
107         return 0;
108 }
109
110 int cs4245_shadow_control(struct oxygen *chip, enum cs4245_shadow_operation op)
111 {
112         struct dg *data = chip->model_data;
113         unsigned char addr;
114         int ret;
115
116         for (addr = 1; addr < ARRAY_SIZE(data->cs4245_shadow); addr++) {
117                 ret = (op == CS4245_SAVE_TO_SHADOW ?
118                         cs4245_read_spi(chip, addr) :
119                         cs4245_write_spi(chip, addr));
120                 if (ret < 0)
121                         return ret;
122         }
123         return 0;
124 }
125
126 static void cs4245_write(struct oxygen *chip, unsigned int reg, u8 value)
127 {
128         struct dg *data = chip->model_data;
129
130         oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
131                          OXYGEN_SPI_DATA_LENGTH_3 |
132                          OXYGEN_SPI_CLOCK_1280 |
133                          (0 << OXYGEN_SPI_CODEC_SHIFT) |
134                          OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
135                          CS4245_SPI_ADDRESS_S |
136                          CS4245_SPI_WRITE_S |
137                          (reg << 8) | value);
138         data->cs4245_shadow[reg] = value;
139 }
140
141 static void cs4245_write_cached(struct oxygen *chip, unsigned int reg, u8 value)
142 {
143         struct dg *data = chip->model_data;
144
145         if (value != data->cs4245_shadow[reg])
146                 cs4245_write(chip, reg, value);
147 }
148
149 static void cs4245_init(struct oxygen *chip)
150 {
151         struct dg *data = chip->model_data;
152
153         /* save the initial state: codec version, registers */
154         cs4245_shadow_control(chip, CS4245_SAVE_TO_SHADOW);
155
156         /*
157          * Power up the CODEC internals, enable soft ramp & zero cross, work in
158          * async. mode, enable aux output from DAC. Invert DAC output as in the
159          * Windows driver.
160          */
161         data->cs4245_shadow[CS4245_POWER_CTRL] = 0;
162         data->cs4245_shadow[CS4245_SIGNAL_SEL] =
163                 CS4245_A_OUT_SEL_DAC | CS4245_ASYNCH;
164         data->cs4245_shadow[CS4245_DAC_CTRL_1] =
165                 CS4245_DAC_FM_SINGLE | CS4245_DAC_DIF_LJUST;
166         data->cs4245_shadow[CS4245_DAC_CTRL_2] =
167                 CS4245_DAC_SOFT | CS4245_DAC_ZERO | CS4245_INVERT_DAC;
168         data->cs4245_shadow[CS4245_ADC_CTRL] =
169                 CS4245_ADC_FM_SINGLE | CS4245_ADC_DIF_LJUST;
170         data->cs4245_shadow[CS4245_ANALOG_IN] =
171                 CS4245_PGA_SOFT | CS4245_PGA_ZERO;
172         data->cs4245_shadow[CS4245_PGA_B_CTRL] = 0;
173         data->cs4245_shadow[CS4245_PGA_A_CTRL] = 0;
174         data->cs4245_shadow[CS4245_DAC_A_CTRL] = 4;
175         data->cs4245_shadow[CS4245_DAC_B_CTRL] = 4;
176
177         cs4245_shadow_control(chip, CS4245_LOAD_FROM_SHADOW);
178         snd_component_add(chip->card, "CS4245");
179 }
180
181 static void dg_init(struct oxygen *chip)
182 {
183         struct dg *data = chip->model_data;
184
185         data->output_sel = 0;
186         data->input_sel = 3;
187         data->hp_vol_att = 2 * 16;
188
189         cs4245_init(chip);
190         oxygen_write16(chip, OXYGEN_GPIO_CONTROL,
191                        GPIO_OUTPUT_ENABLE | GPIO_HP_REAR | GPIO_INPUT_ROUTE);
192         oxygen_write16(chip, OXYGEN_GPIO_DATA, GPIO_INPUT_ROUTE);
193         msleep(2500); /* anti-pop delay */
194         oxygen_write16(chip, OXYGEN_GPIO_DATA,
195                        GPIO_OUTPUT_ENABLE | GPIO_INPUT_ROUTE);
196 }
197
198 static void dg_cleanup(struct oxygen *chip)
199 {
200         oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
201 }
202
203 static void dg_suspend(struct oxygen *chip)
204 {
205         dg_cleanup(chip);
206 }
207
208 static void dg_resume(struct oxygen *chip)
209 {
210         cs4245_shadow_control(chip, CS4245_LOAD_FROM_SHADOW);
211         msleep(2500);
212         oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
213 }
214
215 static void set_cs4245_dac_params(struct oxygen *chip,
216                                   struct snd_pcm_hw_params *params)
217 {
218         struct dg *data = chip->model_data;
219         unsigned char dac_ctrl;
220         unsigned char mclk_freq;
221
222         dac_ctrl = data->cs4245_shadow[CS4245_DAC_CTRL_1] & ~CS4245_DAC_FM_MASK;
223         mclk_freq = data->cs4245_shadow[CS4245_MCLK_FREQ] & ~CS4245_MCLK1_MASK;
224         if (params_rate(params) <= 50000) {
225                 dac_ctrl |= CS4245_DAC_FM_SINGLE;
226                 mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK1_SHIFT;
227         } else if (params_rate(params) <= 100000) {
228                 dac_ctrl |= CS4245_DAC_FM_DOUBLE;
229                 mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK1_SHIFT;
230         } else {
231                 dac_ctrl |= CS4245_DAC_FM_QUAD;
232                 mclk_freq |= CS4245_MCLK_2 << CS4245_MCLK1_SHIFT;
233         }
234         data->cs4245_shadow[CS4245_DAC_CTRL_1] = dac_ctrl;
235         data->cs4245_shadow[CS4245_MCLK_FREQ] = mclk_freq;
236         cs4245_write_spi(chip, CS4245_DAC_CTRL_1);
237         cs4245_write_spi(chip, CS4245_MCLK_FREQ);
238 }
239
240 static void set_cs4245_adc_params(struct oxygen *chip,
241                                   struct snd_pcm_hw_params *params)
242 {
243         struct dg *data = chip->model_data;
244         unsigned char adc_ctrl;
245         unsigned char mclk_freq;
246
247         adc_ctrl = data->cs4245_shadow[CS4245_ADC_CTRL] & ~CS4245_ADC_FM_MASK;
248         mclk_freq = data->cs4245_shadow[CS4245_MCLK_FREQ] & ~CS4245_MCLK2_MASK;
249         if (params_rate(params) <= 50000) {
250                 adc_ctrl |= CS4245_ADC_FM_SINGLE;
251                 mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK2_SHIFT;
252         } else if (params_rate(params) <= 100000) {
253                 adc_ctrl |= CS4245_ADC_FM_DOUBLE;
254                 mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK2_SHIFT;
255         } else {
256                 adc_ctrl |= CS4245_ADC_FM_QUAD;
257                 mclk_freq |= CS4245_MCLK_2 << CS4245_MCLK2_SHIFT;
258         }
259         data->cs4245_shadow[CS4245_ADC_CTRL] = adc_ctrl;
260         data->cs4245_shadow[CS4245_MCLK_FREQ] = mclk_freq;
261         cs4245_write_spi(chip, CS4245_ADC_CTRL);
262         cs4245_write_spi(chip, CS4245_MCLK_FREQ);
263 }
264
265 static unsigned int adjust_dg_dac_routing(struct oxygen *chip,
266                                           unsigned int play_routing)
267 {
268         struct dg *data = chip->model_data;
269         unsigned int routing = 0;
270
271         switch (data->pcm_output) {
272         case PLAYBACK_DST_HP:
273         case PLAYBACK_DST_HP_FP:
274                 oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING,
275                         OXYGEN_PLAY_MUTE23 | OXYGEN_PLAY_MUTE45 |
276                         OXYGEN_PLAY_MUTE67, OXYGEN_PLAY_MUTE_MASK);
277                 break;
278         case PLAYBACK_DST_MULTICH:
279                 routing = (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
280                           (2 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
281                           (1 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
282                           (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT);
283                 oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING,
284                         OXYGEN_PLAY_MUTE01, OXYGEN_PLAY_MUTE_MASK);
285                 break;
286         }
287         return routing;
288 }
289
290 static int output_switch_info(struct snd_kcontrol *ctl,
291                               struct snd_ctl_elem_info *info)
292 {
293         static const char *const names[3] = {
294                 "Speakers", "Headphones", "FP Headphones"
295         };
296
297         return snd_ctl_enum_info(info, 1, 3, names);
298 }
299
300 static int output_switch_get(struct snd_kcontrol *ctl,
301                              struct snd_ctl_elem_value *value)
302 {
303         struct oxygen *chip = ctl->private_data;
304         struct dg *data = chip->model_data;
305
306         mutex_lock(&chip->mutex);
307         value->value.enumerated.item[0] = data->output_sel;
308         mutex_unlock(&chip->mutex);
309         return 0;
310 }
311
312 static int output_switch_put(struct snd_kcontrol *ctl,
313                              struct snd_ctl_elem_value *value)
314 {
315         struct oxygen *chip = ctl->private_data;
316         struct dg *data = chip->model_data;
317         u8 reg;
318         int changed;
319
320         if (value->value.enumerated.item[0] > 2)
321                 return -EINVAL;
322
323         mutex_lock(&chip->mutex);
324         changed = value->value.enumerated.item[0] != data->output_sel;
325         if (changed) {
326                 data->output_sel = value->value.enumerated.item[0];
327
328                 reg = data->cs4245_shadow[CS4245_SIGNAL_SEL] &
329                                                 ~CS4245_A_OUT_SEL_MASK;
330                 reg |= data->output_sel == 2 ?
331                                 CS4245_A_OUT_SEL_DAC : CS4245_A_OUT_SEL_HIZ;
332                 cs4245_write_cached(chip, CS4245_SIGNAL_SEL, reg);
333
334                 cs4245_write_cached(chip, CS4245_DAC_A_CTRL,
335                                     data->output_sel ? data->hp_vol_att : 0);
336                 cs4245_write_cached(chip, CS4245_DAC_B_CTRL,
337                                     data->output_sel ? data->hp_vol_att : 0);
338
339                 oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
340                                       data->output_sel == 1 ? GPIO_HP_REAR : 0,
341                                       GPIO_HP_REAR);
342         }
343         mutex_unlock(&chip->mutex);
344         return changed;
345 }
346
347 static int hp_volume_offset_info(struct snd_kcontrol *ctl,
348                                  struct snd_ctl_elem_info *info)
349 {
350         static const char *const names[3] = {
351                 "< 64 ohms", "64-150 ohms", "150-300 ohms"
352         };
353
354         return snd_ctl_enum_info(info, 1, 3, names);
355 }
356
357 static int hp_volume_offset_get(struct snd_kcontrol *ctl,
358                                 struct snd_ctl_elem_value *value)
359 {
360         struct oxygen *chip = ctl->private_data;
361         struct dg *data = chip->model_data;
362
363         mutex_lock(&chip->mutex);
364         if (data->hp_vol_att > 2 * 7)
365                 value->value.enumerated.item[0] = 0;
366         else if (data->hp_vol_att > 0)
367                 value->value.enumerated.item[0] = 1;
368         else
369                 value->value.enumerated.item[0] = 2;
370         mutex_unlock(&chip->mutex);
371         return 0;
372 }
373
374 static int hp_volume_offset_put(struct snd_kcontrol *ctl,
375                                 struct snd_ctl_elem_value *value)
376 {
377         static const s8 atts[3] = { 2 * 16, 2 * 7, 0 };
378         struct oxygen *chip = ctl->private_data;
379         struct dg *data = chip->model_data;
380         s8 att;
381         int changed;
382
383         if (value->value.enumerated.item[0] > 2)
384                 return -EINVAL;
385         att = atts[value->value.enumerated.item[0]];
386         mutex_lock(&chip->mutex);
387         changed = att != data->hp_vol_att;
388         if (changed) {
389                 data->hp_vol_att = att;
390                 if (data->output_sel) {
391                         cs4245_write_cached(chip, CS4245_DAC_A_CTRL, att);
392                         cs4245_write_cached(chip, CS4245_DAC_B_CTRL, att);
393                 }
394         }
395         mutex_unlock(&chip->mutex);
396         return changed;
397 }
398
399 static int input_vol_info(struct snd_kcontrol *ctl,
400                           struct snd_ctl_elem_info *info)
401 {
402         info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
403         info->count = 2;
404         info->value.integer.min = 2 * -12;
405         info->value.integer.max = 2 * 12;
406         return 0;
407 }
408
409 static int input_vol_get(struct snd_kcontrol *ctl,
410                          struct snd_ctl_elem_value *value)
411 {
412         struct oxygen *chip = ctl->private_data;
413         struct dg *data = chip->model_data;
414         unsigned int idx = ctl->private_value;
415
416         mutex_lock(&chip->mutex);
417         value->value.integer.value[0] = data->input_vol[idx][0];
418         value->value.integer.value[1] = data->input_vol[idx][1];
419         mutex_unlock(&chip->mutex);
420         return 0;
421 }
422
423 static int input_vol_put(struct snd_kcontrol *ctl,
424                          struct snd_ctl_elem_value *value)
425 {
426         struct oxygen *chip = ctl->private_data;
427         struct dg *data = chip->model_data;
428         unsigned int idx = ctl->private_value;
429         int changed = 0;
430
431         if (value->value.integer.value[0] < 2 * -12 ||
432             value->value.integer.value[0] > 2 * 12 ||
433             value->value.integer.value[1] < 2 * -12 ||
434             value->value.integer.value[1] > 2 * 12)
435                 return -EINVAL;
436         mutex_lock(&chip->mutex);
437         changed = data->input_vol[idx][0] != value->value.integer.value[0] ||
438                   data->input_vol[idx][1] != value->value.integer.value[1];
439         if (changed) {
440                 data->input_vol[idx][0] = value->value.integer.value[0];
441                 data->input_vol[idx][1] = value->value.integer.value[1];
442                 if (idx == data->input_sel) {
443                         cs4245_write_cached(chip, CS4245_PGA_A_CTRL,
444                                             data->input_vol[idx][0]);
445                         cs4245_write_cached(chip, CS4245_PGA_B_CTRL,
446                                             data->input_vol[idx][1]);
447                 }
448         }
449         mutex_unlock(&chip->mutex);
450         return changed;
451 }
452
453 static DECLARE_TLV_DB_SCALE(cs4245_pga_db_scale, -1200, 50, 0);
454
455 static int input_sel_info(struct snd_kcontrol *ctl,
456                           struct snd_ctl_elem_info *info)
457 {
458         static const char *const names[4] = {
459                 "Mic", "Aux", "Front Mic", "Line"
460         };
461
462         return snd_ctl_enum_info(info, 1, 4, names);
463 }
464
465 static int input_sel_get(struct snd_kcontrol *ctl,
466                          struct snd_ctl_elem_value *value)
467 {
468         struct oxygen *chip = ctl->private_data;
469         struct dg *data = chip->model_data;
470
471         mutex_lock(&chip->mutex);
472         value->value.enumerated.item[0] = data->input_sel;
473         mutex_unlock(&chip->mutex);
474         return 0;
475 }
476
477 static int input_sel_put(struct snd_kcontrol *ctl,
478                          struct snd_ctl_elem_value *value)
479 {
480         static const u8 sel_values[4] = {
481                 CS4245_SEL_MIC,
482                 CS4245_SEL_INPUT_1,
483                 CS4245_SEL_INPUT_2,
484                 CS4245_SEL_INPUT_4
485         };
486         struct oxygen *chip = ctl->private_data;
487         struct dg *data = chip->model_data;
488         int changed;
489
490         if (value->value.enumerated.item[0] > 3)
491                 return -EINVAL;
492
493         mutex_lock(&chip->mutex);
494         changed = value->value.enumerated.item[0] != data->input_sel;
495         if (changed) {
496                 data->input_sel = value->value.enumerated.item[0];
497
498                 cs4245_write(chip, CS4245_ANALOG_IN,
499                              (data->cs4245_shadow[CS4245_ANALOG_IN] &
500                                                         ~CS4245_SEL_MASK) |
501                              sel_values[data->input_sel]);
502
503                 cs4245_write_cached(chip, CS4245_PGA_A_CTRL,
504                                     data->input_vol[data->input_sel][0]);
505                 cs4245_write_cached(chip, CS4245_PGA_B_CTRL,
506                                     data->input_vol[data->input_sel][1]);
507
508                 oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
509                                       data->input_sel ? 0 : GPIO_INPUT_ROUTE,
510                                       GPIO_INPUT_ROUTE);
511         }
512         mutex_unlock(&chip->mutex);
513         return changed;
514 }
515
516 static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
517 {
518         static const char *const names[2] = { "Active", "Frozen" };
519
520         return snd_ctl_enum_info(info, 1, 2, names);
521 }
522
523 static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
524 {
525         struct oxygen *chip = ctl->private_data;
526         struct dg *data = chip->model_data;
527
528         value->value.enumerated.item[0] =
529                 !!(data->cs4245_shadow[CS4245_ADC_CTRL] & CS4245_HPF_FREEZE);
530         return 0;
531 }
532
533 static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
534 {
535         struct oxygen *chip = ctl->private_data;
536         struct dg *data = chip->model_data;
537         u8 reg;
538         int changed;
539
540         mutex_lock(&chip->mutex);
541         reg = data->cs4245_shadow[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE;
542         if (value->value.enumerated.item[0])
543                 reg |= CS4245_HPF_FREEZE;
544         changed = reg != data->cs4245_shadow[CS4245_ADC_CTRL];
545         if (changed)
546                 cs4245_write(chip, CS4245_ADC_CTRL, reg);
547         mutex_unlock(&chip->mutex);
548         return changed;
549 }
550
551 #define INPUT_VOLUME(xname, index) { \
552         .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
553         .name = xname, \
554         .info = input_vol_info, \
555         .get = input_vol_get, \
556         .put = input_vol_put, \
557         .tlv = { .p = cs4245_pga_db_scale }, \
558         .private_value = index, \
559 }
560 static const struct snd_kcontrol_new dg_controls[] = {
561         {
562                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
563                 .name = "Analog Output Playback Enum",
564                 .info = output_switch_info,
565                 .get = output_switch_get,
566                 .put = output_switch_put,
567         },
568         {
569                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
570                 .name = "Headphones Impedance Playback Enum",
571                 .info = hp_volume_offset_info,
572                 .get = hp_volume_offset_get,
573                 .put = hp_volume_offset_put,
574         },
575         INPUT_VOLUME("Mic Capture Volume", 0),
576         INPUT_VOLUME("Aux Capture Volume", 1),
577         INPUT_VOLUME("Front Mic Capture Volume", 2),
578         INPUT_VOLUME("Line Capture Volume", 3),
579         {
580                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
581                 .name = "Capture Source",
582                 .info = input_sel_info,
583                 .get = input_sel_get,
584                 .put = input_sel_put,
585         },
586         {
587                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
588                 .name = "ADC High-pass Filter Capture Enum",
589                 .info = hpf_info,
590                 .get = hpf_get,
591                 .put = hpf_put,
592         },
593 };
594
595 static int dg_control_filter(struct snd_kcontrol_new *template)
596 {
597         if (!strncmp(template->name, "Master Playback ", 16))
598                 return 1;
599         return 0;
600 }
601
602 static int dg_mixer_init(struct oxygen *chip)
603 {
604         unsigned int i;
605         int err;
606
607         for (i = 0; i < ARRAY_SIZE(dg_controls); ++i) {
608                 err = snd_ctl_add(chip->card,
609                                   snd_ctl_new1(&dg_controls[i], chip));
610                 if (err < 0)
611                         return err;
612         }
613         return 0;
614 }
615
616 static void dump_cs4245_registers(struct oxygen *chip,
617                                   struct snd_info_buffer *buffer)
618 {
619         struct dg *data = chip->model_data;
620         unsigned int i;
621
622         snd_iprintf(buffer, "\nCS4245:");
623         for (i = 1; i <= 0x10; ++i)
624                 snd_iprintf(buffer, " %02x", data->cs4245_shadow[i]);
625         snd_iprintf(buffer, "\n");
626 }
627
628 struct oxygen_model model_xonar_dg = {
629         .longname = "C-Media Oxygen HD Audio",
630         .chip = "CMI8786",
631         .init = dg_init,
632         .control_filter = dg_control_filter,
633         .mixer_init = dg_mixer_init,
634         .cleanup = dg_cleanup,
635         .suspend = dg_suspend,
636         .resume = dg_resume,
637         .set_dac_params = set_cs4245_dac_params,
638         .set_adc_params = set_cs4245_adc_params,
639         .adjust_dac_routing = adjust_dg_dac_routing,
640         .dump_registers = dump_cs4245_registers,
641         .model_data_size = sizeof(struct dg),
642         .device_config = PLAYBACK_0_TO_I2S |
643                          PLAYBACK_1_TO_SPDIF |
644                          CAPTURE_0_FROM_I2S_2 |
645                          CAPTURE_1_FROM_SPDIF,
646         .dac_channels_pcm = 6,
647         .dac_channels_mixer = 0,
648         .function_flags = OXYGEN_FUNCTION_SPI,
649         .dac_mclks = OXYGEN_MCLKS(256, 128, 128),
650         .adc_mclks = OXYGEN_MCLKS(256, 128, 128),
651         .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
652         .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
653 };