xref: /openbmc/linux/sound/pci/oxygen/xonar_dg.c (revision ddd624c3)
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 static void cs4245_write(struct oxygen *chip, unsigned int reg, u8 value)
68 {
69 	struct dg *data = chip->model_data;
70 
71 	oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
72 			 OXYGEN_SPI_DATA_LENGTH_3 |
73 			 OXYGEN_SPI_CLOCK_1280 |
74 			 (0 << OXYGEN_SPI_CODEC_SHIFT) |
75 			 OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
76 			 CS4245_SPI_ADDRESS |
77 			 CS4245_SPI_WRITE |
78 			 (reg << 8) | value);
79 	data->cs4245_regs[reg] = value;
80 }
81 
82 static void cs4245_write_cached(struct oxygen *chip, unsigned int reg, u8 value)
83 {
84 	struct dg *data = chip->model_data;
85 
86 	if (value != data->cs4245_regs[reg])
87 		cs4245_write(chip, reg, value);
88 }
89 
90 static void cs4245_registers_init(struct oxygen *chip)
91 {
92 	struct dg *data = chip->model_data;
93 
94 	cs4245_write(chip, CS4245_POWER_CTRL, CS4245_PDN);
95 	cs4245_write(chip, CS4245_DAC_CTRL_1,
96 		     data->cs4245_regs[CS4245_DAC_CTRL_1]);
97 	cs4245_write(chip, CS4245_ADC_CTRL,
98 		     data->cs4245_regs[CS4245_ADC_CTRL]);
99 	cs4245_write(chip, CS4245_SIGNAL_SEL,
100 		     data->cs4245_regs[CS4245_SIGNAL_SEL]);
101 	cs4245_write(chip, CS4245_PGA_B_CTRL,
102 		     data->cs4245_regs[CS4245_PGA_B_CTRL]);
103 	cs4245_write(chip, CS4245_PGA_A_CTRL,
104 		     data->cs4245_regs[CS4245_PGA_A_CTRL]);
105 	cs4245_write(chip, CS4245_ANALOG_IN,
106 		     data->cs4245_regs[CS4245_ANALOG_IN]);
107 	cs4245_write(chip, CS4245_DAC_A_CTRL,
108 		     data->cs4245_regs[CS4245_DAC_A_CTRL]);
109 	cs4245_write(chip, CS4245_DAC_B_CTRL,
110 		     data->cs4245_regs[CS4245_DAC_B_CTRL]);
111 	cs4245_write(chip, CS4245_DAC_CTRL_2,
112 		     CS4245_DAC_SOFT | CS4245_DAC_ZERO | CS4245_INVERT_DAC);
113 	cs4245_write(chip, CS4245_INT_MASK, 0);
114 	cs4245_write(chip, CS4245_POWER_CTRL, 0);
115 }
116 
117 static void cs4245_init(struct oxygen *chip)
118 {
119 	struct dg *data = chip->model_data;
120 
121 	data->cs4245_regs[CS4245_DAC_CTRL_1] =
122 		CS4245_DAC_FM_SINGLE | CS4245_DAC_DIF_LJUST;
123 	data->cs4245_regs[CS4245_ADC_CTRL] =
124 		CS4245_ADC_FM_SINGLE | CS4245_ADC_DIF_LJUST;
125 	data->cs4245_regs[CS4245_SIGNAL_SEL] =
126 		CS4245_A_OUT_SEL_HIZ | CS4245_ASYNCH;
127 	data->cs4245_regs[CS4245_PGA_B_CTRL] = 0;
128 	data->cs4245_regs[CS4245_PGA_A_CTRL] = 0;
129 	data->cs4245_regs[CS4245_ANALOG_IN] =
130 		CS4245_PGA_SOFT | CS4245_PGA_ZERO | CS4245_SEL_INPUT_4;
131 	data->cs4245_regs[CS4245_DAC_A_CTRL] = 0;
132 	data->cs4245_regs[CS4245_DAC_B_CTRL] = 0;
133 	cs4245_registers_init(chip);
134 	snd_component_add(chip->card, "CS4245");
135 }
136 
137 static void dg_output_enable(struct oxygen *chip)
138 {
139 	msleep(2500);
140 	oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
141 }
142 
143 static void dg_init(struct oxygen *chip)
144 {
145 	struct dg *data = chip->model_data;
146 
147 	data->output_sel = 0;
148 	data->input_sel = 3;
149 	data->hp_vol_att = 2 * 16;
150 
151 	cs4245_init(chip);
152 
153 	oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
154 			    GPIO_MAGIC | GPIO_HP_DETECT);
155 	oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
156 			  GPIO_INPUT_ROUTE | GPIO_HP_REAR | GPIO_OUTPUT_ENABLE);
157 	oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
158 			    GPIO_INPUT_ROUTE | GPIO_HP_REAR);
159 	dg_output_enable(chip);
160 }
161 
162 static void dg_cleanup(struct oxygen *chip)
163 {
164 	oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
165 }
166 
167 static void dg_suspend(struct oxygen *chip)
168 {
169 	dg_cleanup(chip);
170 }
171 
172 static void dg_resume(struct oxygen *chip)
173 {
174 	cs4245_registers_init(chip);
175 	dg_output_enable(chip);
176 }
177 
178 static void set_cs4245_dac_params(struct oxygen *chip,
179 				  struct snd_pcm_hw_params *params)
180 {
181 	struct dg *data = chip->model_data;
182 	u8 value;
183 
184 	value = data->cs4245_regs[CS4245_DAC_CTRL_1] & ~CS4245_DAC_FM_MASK;
185 	if (params_rate(params) <= 50000)
186 		value |= CS4245_DAC_FM_SINGLE;
187 	else if (params_rate(params) <= 100000)
188 		value |= CS4245_DAC_FM_DOUBLE;
189 	else
190 		value |= CS4245_DAC_FM_QUAD;
191 	cs4245_write_cached(chip, CS4245_DAC_CTRL_1, value);
192 }
193 
194 static void set_cs4245_adc_params(struct oxygen *chip,
195 				  struct snd_pcm_hw_params *params)
196 {
197 	struct dg *data = chip->model_data;
198 	u8 value;
199 
200 	value = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_ADC_FM_MASK;
201 	if (params_rate(params) <= 50000)
202 		value |= CS4245_ADC_FM_SINGLE;
203 	else if (params_rate(params) <= 100000)
204 		value |= CS4245_ADC_FM_DOUBLE;
205 	else
206 		value |= CS4245_ADC_FM_QUAD;
207 	cs4245_write_cached(chip, CS4245_ADC_CTRL, value);
208 }
209 
210 static inline unsigned int shift_bits(unsigned int value,
211 				      unsigned int shift_from,
212 				      unsigned int shift_to,
213 				      unsigned int mask)
214 {
215 	if (shift_from < shift_to)
216 		return (value << (shift_to - shift_from)) & mask;
217 	else
218 		return (value >> (shift_from - shift_to)) & mask;
219 }
220 
221 static unsigned int adjust_dg_dac_routing(struct oxygen *chip,
222 					  unsigned int play_routing)
223 {
224 	return (play_routing & OXYGEN_PLAY_DAC0_SOURCE_MASK) |
225 	       shift_bits(play_routing,
226 			  OXYGEN_PLAY_DAC2_SOURCE_SHIFT,
227 			  OXYGEN_PLAY_DAC1_SOURCE_SHIFT,
228 			  OXYGEN_PLAY_DAC1_SOURCE_MASK) |
229 	       shift_bits(play_routing,
230 			  OXYGEN_PLAY_DAC1_SOURCE_SHIFT,
231 			  OXYGEN_PLAY_DAC2_SOURCE_SHIFT,
232 			  OXYGEN_PLAY_DAC2_SOURCE_MASK) |
233 	       shift_bits(play_routing,
234 			  OXYGEN_PLAY_DAC0_SOURCE_SHIFT,
235 			  OXYGEN_PLAY_DAC3_SOURCE_SHIFT,
236 			  OXYGEN_PLAY_DAC3_SOURCE_MASK);
237 }
238 
239 static int output_switch_info(struct snd_kcontrol *ctl,
240 			      struct snd_ctl_elem_info *info)
241 {
242 	static const char *const names[3] = {
243 		"Speakers", "Headphones", "FP Headphones"
244 	};
245 
246 	return snd_ctl_enum_info(info, 1, 3, names);
247 }
248 
249 static int output_switch_get(struct snd_kcontrol *ctl,
250 			     struct snd_ctl_elem_value *value)
251 {
252 	struct oxygen *chip = ctl->private_data;
253 	struct dg *data = chip->model_data;
254 
255 	mutex_lock(&chip->mutex);
256 	value->value.enumerated.item[0] = data->output_sel;
257 	mutex_unlock(&chip->mutex);
258 	return 0;
259 }
260 
261 static int output_switch_put(struct snd_kcontrol *ctl,
262 			     struct snd_ctl_elem_value *value)
263 {
264 	struct oxygen *chip = ctl->private_data;
265 	struct dg *data = chip->model_data;
266 	u8 reg;
267 	int changed;
268 
269 	if (value->value.enumerated.item[0] > 2)
270 		return -EINVAL;
271 
272 	mutex_lock(&chip->mutex);
273 	changed = value->value.enumerated.item[0] != data->output_sel;
274 	if (changed) {
275 		data->output_sel = value->value.enumerated.item[0];
276 
277 		reg = data->cs4245_regs[CS4245_SIGNAL_SEL] &
278 						~CS4245_A_OUT_SEL_MASK;
279 		reg |= data->output_sel == 2 ?
280 				CS4245_A_OUT_SEL_DAC : CS4245_A_OUT_SEL_HIZ;
281 		cs4245_write_cached(chip, CS4245_SIGNAL_SEL, reg);
282 
283 		cs4245_write_cached(chip, CS4245_DAC_A_CTRL,
284 				    data->output_sel ? data->hp_vol_att : 0);
285 		cs4245_write_cached(chip, CS4245_DAC_B_CTRL,
286 				    data->output_sel ? data->hp_vol_att : 0);
287 
288 		oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
289 				      data->output_sel == 1 ? GPIO_HP_REAR : 0,
290 				      GPIO_HP_REAR);
291 	}
292 	mutex_unlock(&chip->mutex);
293 	return changed;
294 }
295 
296 static int hp_volume_offset_info(struct snd_kcontrol *ctl,
297 				 struct snd_ctl_elem_info *info)
298 {
299 	static const char *const names[3] = {
300 		"< 64 ohms", "64-150 ohms", "150-300 ohms"
301 	};
302 
303 	return snd_ctl_enum_info(info, 1, 3, names);
304 }
305 
306 static int hp_volume_offset_get(struct snd_kcontrol *ctl,
307 				struct snd_ctl_elem_value *value)
308 {
309 	struct oxygen *chip = ctl->private_data;
310 	struct dg *data = chip->model_data;
311 
312 	mutex_lock(&chip->mutex);
313 	if (data->hp_vol_att > 2 * 7)
314 		value->value.enumerated.item[0] = 0;
315 	else if (data->hp_vol_att > 0)
316 		value->value.enumerated.item[0] = 1;
317 	else
318 		value->value.enumerated.item[0] = 2;
319 	mutex_unlock(&chip->mutex);
320 	return 0;
321 }
322 
323 static int hp_volume_offset_put(struct snd_kcontrol *ctl,
324 				struct snd_ctl_elem_value *value)
325 {
326 	static const s8 atts[3] = { 2 * 16, 2 * 7, 0 };
327 	struct oxygen *chip = ctl->private_data;
328 	struct dg *data = chip->model_data;
329 	s8 att;
330 	int changed;
331 
332 	if (value->value.enumerated.item[0] > 2)
333 		return -EINVAL;
334 	att = atts[value->value.enumerated.item[0]];
335 	mutex_lock(&chip->mutex);
336 	changed = att != data->hp_vol_att;
337 	if (changed) {
338 		data->hp_vol_att = att;
339 		if (data->output_sel) {
340 			cs4245_write_cached(chip, CS4245_DAC_A_CTRL, att);
341 			cs4245_write_cached(chip, CS4245_DAC_B_CTRL, att);
342 		}
343 	}
344 	mutex_unlock(&chip->mutex);
345 	return changed;
346 }
347 
348 static int input_vol_info(struct snd_kcontrol *ctl,
349 			  struct snd_ctl_elem_info *info)
350 {
351 	info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
352 	info->count = 2;
353 	info->value.integer.min = 2 * -12;
354 	info->value.integer.max = 2 * 12;
355 	return 0;
356 }
357 
358 static int input_vol_get(struct snd_kcontrol *ctl,
359 			 struct snd_ctl_elem_value *value)
360 {
361 	struct oxygen *chip = ctl->private_data;
362 	struct dg *data = chip->model_data;
363 	unsigned int idx = ctl->private_value;
364 
365 	mutex_lock(&chip->mutex);
366 	value->value.integer.value[0] = data->input_vol[idx][0];
367 	value->value.integer.value[1] = data->input_vol[idx][1];
368 	mutex_unlock(&chip->mutex);
369 	return 0;
370 }
371 
372 static int input_vol_put(struct snd_kcontrol *ctl,
373 			 struct snd_ctl_elem_value *value)
374 {
375 	struct oxygen *chip = ctl->private_data;
376 	struct dg *data = chip->model_data;
377 	unsigned int idx = ctl->private_value;
378 	int changed = 0;
379 
380 	if (value->value.integer.value[0] < 2 * -12 ||
381 	    value->value.integer.value[0] > 2 * 12 ||
382 	    value->value.integer.value[1] < 2 * -12 ||
383 	    value->value.integer.value[1] > 2 * 12)
384 		return -EINVAL;
385 	mutex_lock(&chip->mutex);
386 	changed = data->input_vol[idx][0] != value->value.integer.value[0] ||
387 		  data->input_vol[idx][1] != value->value.integer.value[1];
388 	if (changed) {
389 		data->input_vol[idx][0] = value->value.integer.value[0];
390 		data->input_vol[idx][1] = value->value.integer.value[1];
391 		if (idx == data->input_sel) {
392 			cs4245_write_cached(chip, CS4245_PGA_A_CTRL,
393 					    data->input_vol[idx][0]);
394 			cs4245_write_cached(chip, CS4245_PGA_B_CTRL,
395 					    data->input_vol[idx][1]);
396 		}
397 	}
398 	mutex_unlock(&chip->mutex);
399 	return changed;
400 }
401 
402 static DECLARE_TLV_DB_SCALE(cs4245_pga_db_scale, -1200, 50, 0);
403 
404 static int input_sel_info(struct snd_kcontrol *ctl,
405 			  struct snd_ctl_elem_info *info)
406 {
407 	static const char *const names[4] = {
408 		"Mic", "Aux", "Front Mic", "Line"
409 	};
410 
411 	return snd_ctl_enum_info(info, 1, 4, names);
412 }
413 
414 static int input_sel_get(struct snd_kcontrol *ctl,
415 			 struct snd_ctl_elem_value *value)
416 {
417 	struct oxygen *chip = ctl->private_data;
418 	struct dg *data = chip->model_data;
419 
420 	mutex_lock(&chip->mutex);
421 	value->value.enumerated.item[0] = data->input_sel;
422 	mutex_unlock(&chip->mutex);
423 	return 0;
424 }
425 
426 static int input_sel_put(struct snd_kcontrol *ctl,
427 			 struct snd_ctl_elem_value *value)
428 {
429 	static const u8 sel_values[4] = {
430 		CS4245_SEL_MIC,
431 		CS4245_SEL_INPUT_1,
432 		CS4245_SEL_INPUT_2,
433 		CS4245_SEL_INPUT_4
434 	};
435 	struct oxygen *chip = ctl->private_data;
436 	struct dg *data = chip->model_data;
437 	int changed;
438 
439 	if (value->value.enumerated.item[0] > 3)
440 		return -EINVAL;
441 
442 	mutex_lock(&chip->mutex);
443 	changed = value->value.enumerated.item[0] != data->input_sel;
444 	if (changed) {
445 		data->input_sel = value->value.enumerated.item[0];
446 
447 		cs4245_write(chip, CS4245_ANALOG_IN,
448 			     (data->cs4245_regs[CS4245_ANALOG_IN] &
449 							~CS4245_SEL_MASK) |
450 			     sel_values[data->input_sel]);
451 
452 		cs4245_write_cached(chip, CS4245_PGA_A_CTRL,
453 				    data->input_vol[data->input_sel][0]);
454 		cs4245_write_cached(chip, CS4245_PGA_B_CTRL,
455 				    data->input_vol[data->input_sel][1]);
456 
457 		oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
458 				      data->input_sel ? 0 : GPIO_INPUT_ROUTE,
459 				      GPIO_INPUT_ROUTE);
460 	}
461 	mutex_unlock(&chip->mutex);
462 	return changed;
463 }
464 
465 static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
466 {
467 	static const char *const names[2] = { "Active", "Frozen" };
468 
469 	return snd_ctl_enum_info(info, 1, 2, names);
470 }
471 
472 static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
473 {
474 	struct oxygen *chip = ctl->private_data;
475 	struct dg *data = chip->model_data;
476 
477 	value->value.enumerated.item[0] =
478 		!!(data->cs4245_regs[CS4245_ADC_CTRL] & CS4245_HPF_FREEZE);
479 	return 0;
480 }
481 
482 static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
483 {
484 	struct oxygen *chip = ctl->private_data;
485 	struct dg *data = chip->model_data;
486 	u8 reg;
487 	int changed;
488 
489 	mutex_lock(&chip->mutex);
490 	reg = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE;
491 	if (value->value.enumerated.item[0])
492 		reg |= CS4245_HPF_FREEZE;
493 	changed = reg != data->cs4245_regs[CS4245_ADC_CTRL];
494 	if (changed)
495 		cs4245_write(chip, CS4245_ADC_CTRL, reg);
496 	mutex_unlock(&chip->mutex);
497 	return changed;
498 }
499 
500 #define INPUT_VOLUME(xname, index) { \
501 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
502 	.name = xname, \
503 	.info = input_vol_info, \
504 	.get = input_vol_get, \
505 	.put = input_vol_put, \
506 	.tlv = { .p = cs4245_pga_db_scale }, \
507 	.private_value = index, \
508 }
509 static const struct snd_kcontrol_new dg_controls[] = {
510 	{
511 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
512 		.name = "Analog Output Playback Enum",
513 		.info = output_switch_info,
514 		.get = output_switch_get,
515 		.put = output_switch_put,
516 	},
517 	{
518 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
519 		.name = "Headphones Impedance Playback Enum",
520 		.info = hp_volume_offset_info,
521 		.get = hp_volume_offset_get,
522 		.put = hp_volume_offset_put,
523 	},
524 	INPUT_VOLUME("Mic Capture Volume", 0),
525 	INPUT_VOLUME("Aux Capture Volume", 1),
526 	INPUT_VOLUME("Front Mic Capture Volume", 2),
527 	INPUT_VOLUME("Line Capture Volume", 3),
528 	{
529 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
530 		.name = "Capture Source",
531 		.info = input_sel_info,
532 		.get = input_sel_get,
533 		.put = input_sel_put,
534 	},
535 	{
536 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
537 		.name = "ADC High-pass Filter Capture Enum",
538 		.info = hpf_info,
539 		.get = hpf_get,
540 		.put = hpf_put,
541 	},
542 };
543 
544 static int dg_control_filter(struct snd_kcontrol_new *template)
545 {
546 	if (!strncmp(template->name, "Master Playback ", 16))
547 		return 1;
548 	return 0;
549 }
550 
551 static int dg_mixer_init(struct oxygen *chip)
552 {
553 	unsigned int i;
554 	int err;
555 
556 	for (i = 0; i < ARRAY_SIZE(dg_controls); ++i) {
557 		err = snd_ctl_add(chip->card,
558 				  snd_ctl_new1(&dg_controls[i], chip));
559 		if (err < 0)
560 			return err;
561 	}
562 	return 0;
563 }
564 
565 static void dump_cs4245_registers(struct oxygen *chip,
566 				  struct snd_info_buffer *buffer)
567 {
568 	struct dg *data = chip->model_data;
569 	unsigned int i;
570 
571 	snd_iprintf(buffer, "\nCS4245:");
572 	for (i = 1; i <= 0x10; ++i)
573 		snd_iprintf(buffer, " %02x", data->cs4245_regs[i]);
574 	snd_iprintf(buffer, "\n");
575 }
576 
577 struct oxygen_model model_xonar_dg = {
578 	.longname = "C-Media Oxygen HD Audio",
579 	.chip = "CMI8786",
580 	.init = dg_init,
581 	.control_filter = dg_control_filter,
582 	.mixer_init = dg_mixer_init,
583 	.cleanup = dg_cleanup,
584 	.suspend = dg_suspend,
585 	.resume = dg_resume,
586 	.set_dac_params = set_cs4245_dac_params,
587 	.set_adc_params = set_cs4245_adc_params,
588 	.adjust_dac_routing = adjust_dg_dac_routing,
589 	.dump_registers = dump_cs4245_registers,
590 	.model_data_size = sizeof(struct dg),
591 	.device_config = PLAYBACK_0_TO_I2S |
592 			 PLAYBACK_1_TO_SPDIF |
593 			 CAPTURE_0_FROM_I2S_2 |
594 			 CAPTURE_1_FROM_SPDIF,
595 	.dac_channels_pcm = 6,
596 	.dac_channels_mixer = 0,
597 	.function_flags = OXYGEN_FUNCTION_SPI,
598 	.dac_mclks = OXYGEN_MCLKS(256, 128, 128),
599 	.adc_mclks = OXYGEN_MCLKS(256, 128, 128),
600 	.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
601 	.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
602 };
603