1041f26b6SRoman Volkov /* 2041f26b6SRoman Volkov * Mixer controls for the Xonar DG/DGX 3041f26b6SRoman Volkov * 4041f26b6SRoman Volkov * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 5041f26b6SRoman Volkov * Copyright (c) Roman Volkov <v1ron@mail.ru> 6041f26b6SRoman Volkov * 7041f26b6SRoman Volkov * This driver is free software; you can redistribute it and/or modify 8041f26b6SRoman Volkov * it under the terms of the GNU General Public License, version 2. 9041f26b6SRoman Volkov * 10041f26b6SRoman Volkov * This driver is distributed in the hope that it will be useful, 11041f26b6SRoman Volkov * but WITHOUT ANY WARRANTY; without even the implied warranty of 12041f26b6SRoman Volkov * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13041f26b6SRoman Volkov * GNU General Public License for more details. 14041f26b6SRoman Volkov * 15041f26b6SRoman Volkov * You should have received a copy of the GNU General Public License 16041f26b6SRoman Volkov * along with this driver; if not, see <http://www.gnu.org/licenses/>. 17041f26b6SRoman Volkov */ 18041f26b6SRoman Volkov 19041f26b6SRoman Volkov #include <linux/pci.h> 20041f26b6SRoman Volkov #include <linux/delay.h> 21041f26b6SRoman Volkov #include <sound/control.h> 22041f26b6SRoman Volkov #include <sound/core.h> 23041f26b6SRoman Volkov #include <sound/info.h> 24041f26b6SRoman Volkov #include <sound/pcm.h> 25041f26b6SRoman Volkov #include <sound/tlv.h> 26041f26b6SRoman Volkov #include "oxygen.h" 27041f26b6SRoman Volkov #include "xonar_dg.h" 28041f26b6SRoman Volkov #include "cs4245.h" 29041f26b6SRoman Volkov 30041f26b6SRoman Volkov static int output_switch_info(struct snd_kcontrol *ctl, 31041f26b6SRoman Volkov struct snd_ctl_elem_info *info) 32041f26b6SRoman Volkov { 33041f26b6SRoman Volkov static const char *const names[3] = { 34041f26b6SRoman Volkov "Speakers", "Headphones", "FP Headphones" 35041f26b6SRoman Volkov }; 36041f26b6SRoman Volkov 37041f26b6SRoman Volkov return snd_ctl_enum_info(info, 1, 3, names); 38041f26b6SRoman Volkov } 39041f26b6SRoman Volkov 40041f26b6SRoman Volkov static int output_switch_get(struct snd_kcontrol *ctl, 41041f26b6SRoman Volkov struct snd_ctl_elem_value *value) 42041f26b6SRoman Volkov { 43041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 44041f26b6SRoman Volkov struct dg *data = chip->model_data; 45041f26b6SRoman Volkov 46041f26b6SRoman Volkov mutex_lock(&chip->mutex); 47041f26b6SRoman Volkov value->value.enumerated.item[0] = data->output_sel; 48041f26b6SRoman Volkov mutex_unlock(&chip->mutex); 49041f26b6SRoman Volkov return 0; 50041f26b6SRoman Volkov } 51041f26b6SRoman Volkov 52041f26b6SRoman Volkov static int output_switch_put(struct snd_kcontrol *ctl, 53041f26b6SRoman Volkov struct snd_ctl_elem_value *value) 54041f26b6SRoman Volkov { 55041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 56041f26b6SRoman Volkov struct dg *data = chip->model_data; 57041f26b6SRoman Volkov u8 reg; 58041f26b6SRoman Volkov int changed; 59041f26b6SRoman Volkov 60041f26b6SRoman Volkov if (value->value.enumerated.item[0] > 2) 61041f26b6SRoman Volkov return -EINVAL; 62041f26b6SRoman Volkov 63041f26b6SRoman Volkov mutex_lock(&chip->mutex); 64041f26b6SRoman Volkov changed = value->value.enumerated.item[0] != data->output_sel; 65041f26b6SRoman Volkov if (changed) { 66041f26b6SRoman Volkov data->output_sel = value->value.enumerated.item[0]; 67041f26b6SRoman Volkov 68041f26b6SRoman Volkov reg = data->cs4245_shadow[CS4245_SIGNAL_SEL] & 69041f26b6SRoman Volkov ~CS4245_A_OUT_SEL_MASK; 70041f26b6SRoman Volkov reg |= data->output_sel == 2 ? 71041f26b6SRoman Volkov CS4245_A_OUT_SEL_DAC : CS4245_A_OUT_SEL_HIZ; 72041f26b6SRoman Volkov cs4245_write_cached(chip, CS4245_SIGNAL_SEL, reg); 73041f26b6SRoman Volkov 74041f26b6SRoman Volkov cs4245_write_cached(chip, CS4245_DAC_A_CTRL, 75041f26b6SRoman Volkov data->output_sel ? data->hp_vol_att : 0); 76041f26b6SRoman Volkov cs4245_write_cached(chip, CS4245_DAC_B_CTRL, 77041f26b6SRoman Volkov data->output_sel ? data->hp_vol_att : 0); 78041f26b6SRoman Volkov 79041f26b6SRoman Volkov oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, 80041f26b6SRoman Volkov data->output_sel == 1 ? GPIO_HP_REAR : 0, 81041f26b6SRoman Volkov GPIO_HP_REAR); 82041f26b6SRoman Volkov } 83041f26b6SRoman Volkov mutex_unlock(&chip->mutex); 84041f26b6SRoman Volkov return changed; 85041f26b6SRoman Volkov } 86041f26b6SRoman Volkov 87041f26b6SRoman Volkov static int hp_volume_offset_info(struct snd_kcontrol *ctl, 88041f26b6SRoman Volkov struct snd_ctl_elem_info *info) 89041f26b6SRoman Volkov { 90041f26b6SRoman Volkov static const char *const names[3] = { 91041f26b6SRoman Volkov "< 64 ohms", "64-150 ohms", "150-300 ohms" 92041f26b6SRoman Volkov }; 93041f26b6SRoman Volkov 94041f26b6SRoman Volkov return snd_ctl_enum_info(info, 1, 3, names); 95041f26b6SRoman Volkov } 96041f26b6SRoman Volkov 97041f26b6SRoman Volkov static int hp_volume_offset_get(struct snd_kcontrol *ctl, 98041f26b6SRoman Volkov struct snd_ctl_elem_value *value) 99041f26b6SRoman Volkov { 100041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 101041f26b6SRoman Volkov struct dg *data = chip->model_data; 102041f26b6SRoman Volkov 103041f26b6SRoman Volkov mutex_lock(&chip->mutex); 104041f26b6SRoman Volkov if (data->hp_vol_att > 2 * 7) 105041f26b6SRoman Volkov value->value.enumerated.item[0] = 0; 106041f26b6SRoman Volkov else if (data->hp_vol_att > 0) 107041f26b6SRoman Volkov value->value.enumerated.item[0] = 1; 108041f26b6SRoman Volkov else 109041f26b6SRoman Volkov value->value.enumerated.item[0] = 2; 110041f26b6SRoman Volkov mutex_unlock(&chip->mutex); 111041f26b6SRoman Volkov return 0; 112041f26b6SRoman Volkov } 113041f26b6SRoman Volkov 114041f26b6SRoman Volkov static int hp_volume_offset_put(struct snd_kcontrol *ctl, 115041f26b6SRoman Volkov struct snd_ctl_elem_value *value) 116041f26b6SRoman Volkov { 117041f26b6SRoman Volkov static const s8 atts[3] = { 2 * 16, 2 * 7, 0 }; 118041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 119041f26b6SRoman Volkov struct dg *data = chip->model_data; 120041f26b6SRoman Volkov s8 att; 121041f26b6SRoman Volkov int changed; 122041f26b6SRoman Volkov 123041f26b6SRoman Volkov if (value->value.enumerated.item[0] > 2) 124041f26b6SRoman Volkov return -EINVAL; 125041f26b6SRoman Volkov att = atts[value->value.enumerated.item[0]]; 126041f26b6SRoman Volkov mutex_lock(&chip->mutex); 127041f26b6SRoman Volkov changed = att != data->hp_vol_att; 128041f26b6SRoman Volkov if (changed) { 129041f26b6SRoman Volkov data->hp_vol_att = att; 130041f26b6SRoman Volkov if (data->output_sel) { 131041f26b6SRoman Volkov cs4245_write_cached(chip, CS4245_DAC_A_CTRL, att); 132041f26b6SRoman Volkov cs4245_write_cached(chip, CS4245_DAC_B_CTRL, att); 133041f26b6SRoman Volkov } 134041f26b6SRoman Volkov } 135041f26b6SRoman Volkov mutex_unlock(&chip->mutex); 136041f26b6SRoman Volkov return changed; 137041f26b6SRoman Volkov } 138041f26b6SRoman Volkov 139041f26b6SRoman Volkov static int input_vol_info(struct snd_kcontrol *ctl, 140041f26b6SRoman Volkov struct snd_ctl_elem_info *info) 141041f26b6SRoman Volkov { 142041f26b6SRoman Volkov info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 143041f26b6SRoman Volkov info->count = 2; 144041f26b6SRoman Volkov info->value.integer.min = 2 * -12; 145041f26b6SRoman Volkov info->value.integer.max = 2 * 12; 146041f26b6SRoman Volkov return 0; 147041f26b6SRoman Volkov } 148041f26b6SRoman Volkov 149041f26b6SRoman Volkov static int input_vol_get(struct snd_kcontrol *ctl, 150041f26b6SRoman Volkov struct snd_ctl_elem_value *value) 151041f26b6SRoman Volkov { 152041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 153041f26b6SRoman Volkov struct dg *data = chip->model_data; 154041f26b6SRoman Volkov unsigned int idx = ctl->private_value; 155041f26b6SRoman Volkov 156041f26b6SRoman Volkov mutex_lock(&chip->mutex); 157041f26b6SRoman Volkov value->value.integer.value[0] = data->input_vol[idx][0]; 158041f26b6SRoman Volkov value->value.integer.value[1] = data->input_vol[idx][1]; 159041f26b6SRoman Volkov mutex_unlock(&chip->mutex); 160041f26b6SRoman Volkov return 0; 161041f26b6SRoman Volkov } 162041f26b6SRoman Volkov 163041f26b6SRoman Volkov static int input_vol_put(struct snd_kcontrol *ctl, 164041f26b6SRoman Volkov struct snd_ctl_elem_value *value) 165041f26b6SRoman Volkov { 166041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 167041f26b6SRoman Volkov struct dg *data = chip->model_data; 168041f26b6SRoman Volkov unsigned int idx = ctl->private_value; 169041f26b6SRoman Volkov int changed = 0; 170041f26b6SRoman Volkov 171041f26b6SRoman Volkov if (value->value.integer.value[0] < 2 * -12 || 172041f26b6SRoman Volkov value->value.integer.value[0] > 2 * 12 || 173041f26b6SRoman Volkov value->value.integer.value[1] < 2 * -12 || 174041f26b6SRoman Volkov value->value.integer.value[1] > 2 * 12) 175041f26b6SRoman Volkov return -EINVAL; 176041f26b6SRoman Volkov mutex_lock(&chip->mutex); 177041f26b6SRoman Volkov changed = data->input_vol[idx][0] != value->value.integer.value[0] || 178041f26b6SRoman Volkov data->input_vol[idx][1] != value->value.integer.value[1]; 179041f26b6SRoman Volkov if (changed) { 180041f26b6SRoman Volkov data->input_vol[idx][0] = value->value.integer.value[0]; 181041f26b6SRoman Volkov data->input_vol[idx][1] = value->value.integer.value[1]; 182041f26b6SRoman Volkov if (idx == data->input_sel) { 183041f26b6SRoman Volkov cs4245_write_cached(chip, CS4245_PGA_A_CTRL, 184041f26b6SRoman Volkov data->input_vol[idx][0]); 185041f26b6SRoman Volkov cs4245_write_cached(chip, CS4245_PGA_B_CTRL, 186041f26b6SRoman Volkov data->input_vol[idx][1]); 187041f26b6SRoman Volkov } 188041f26b6SRoman Volkov } 189041f26b6SRoman Volkov mutex_unlock(&chip->mutex); 190041f26b6SRoman Volkov return changed; 191041f26b6SRoman Volkov } 192041f26b6SRoman Volkov 193041f26b6SRoman Volkov static DECLARE_TLV_DB_SCALE(cs4245_pga_db_scale, -1200, 50, 0); 194041f26b6SRoman Volkov 195041f26b6SRoman Volkov static int input_sel_info(struct snd_kcontrol *ctl, 196041f26b6SRoman Volkov struct snd_ctl_elem_info *info) 197041f26b6SRoman Volkov { 198041f26b6SRoman Volkov static const char *const names[4] = { 199041f26b6SRoman Volkov "Mic", "Aux", "Front Mic", "Line" 200041f26b6SRoman Volkov }; 201041f26b6SRoman Volkov 202041f26b6SRoman Volkov return snd_ctl_enum_info(info, 1, 4, names); 203041f26b6SRoman Volkov } 204041f26b6SRoman Volkov 205041f26b6SRoman Volkov static int input_sel_get(struct snd_kcontrol *ctl, 206041f26b6SRoman Volkov struct snd_ctl_elem_value *value) 207041f26b6SRoman Volkov { 208041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 209041f26b6SRoman Volkov struct dg *data = chip->model_data; 210041f26b6SRoman Volkov 211041f26b6SRoman Volkov mutex_lock(&chip->mutex); 212041f26b6SRoman Volkov value->value.enumerated.item[0] = data->input_sel; 213041f26b6SRoman Volkov mutex_unlock(&chip->mutex); 214041f26b6SRoman Volkov return 0; 215041f26b6SRoman Volkov } 216041f26b6SRoman Volkov 217041f26b6SRoman Volkov static int input_sel_put(struct snd_kcontrol *ctl, 218041f26b6SRoman Volkov struct snd_ctl_elem_value *value) 219041f26b6SRoman Volkov { 220041f26b6SRoman Volkov static const u8 sel_values[4] = { 221041f26b6SRoman Volkov CS4245_SEL_MIC, 222041f26b6SRoman Volkov CS4245_SEL_INPUT_1, 223041f26b6SRoman Volkov CS4245_SEL_INPUT_2, 224041f26b6SRoman Volkov CS4245_SEL_INPUT_4 225041f26b6SRoman Volkov }; 226041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 227041f26b6SRoman Volkov struct dg *data = chip->model_data; 228041f26b6SRoman Volkov int changed; 229041f26b6SRoman Volkov 230041f26b6SRoman Volkov if (value->value.enumerated.item[0] > 3) 231041f26b6SRoman Volkov return -EINVAL; 232041f26b6SRoman Volkov 233041f26b6SRoman Volkov mutex_lock(&chip->mutex); 234041f26b6SRoman Volkov changed = value->value.enumerated.item[0] != data->input_sel; 235041f26b6SRoman Volkov if (changed) { 236041f26b6SRoman Volkov data->input_sel = value->value.enumerated.item[0]; 237041f26b6SRoman Volkov 238041f26b6SRoman Volkov cs4245_write(chip, CS4245_ANALOG_IN, 239041f26b6SRoman Volkov (data->cs4245_shadow[CS4245_ANALOG_IN] & 240041f26b6SRoman Volkov ~CS4245_SEL_MASK) | 241041f26b6SRoman Volkov sel_values[data->input_sel]); 242041f26b6SRoman Volkov 243041f26b6SRoman Volkov cs4245_write_cached(chip, CS4245_PGA_A_CTRL, 244041f26b6SRoman Volkov data->input_vol[data->input_sel][0]); 245041f26b6SRoman Volkov cs4245_write_cached(chip, CS4245_PGA_B_CTRL, 246041f26b6SRoman Volkov data->input_vol[data->input_sel][1]); 247041f26b6SRoman Volkov 248041f26b6SRoman Volkov oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, 249041f26b6SRoman Volkov data->input_sel ? 0 : GPIO_INPUT_ROUTE, 250041f26b6SRoman Volkov GPIO_INPUT_ROUTE); 251041f26b6SRoman Volkov } 252041f26b6SRoman Volkov mutex_unlock(&chip->mutex); 253041f26b6SRoman Volkov return changed; 254041f26b6SRoman Volkov } 255041f26b6SRoman Volkov 256041f26b6SRoman Volkov static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) 257041f26b6SRoman Volkov { 258041f26b6SRoman Volkov static const char *const names[2] = { "Active", "Frozen" }; 259041f26b6SRoman Volkov 260041f26b6SRoman Volkov return snd_ctl_enum_info(info, 1, 2, names); 261041f26b6SRoman Volkov } 262041f26b6SRoman Volkov 263041f26b6SRoman Volkov static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) 264041f26b6SRoman Volkov { 265041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 266041f26b6SRoman Volkov struct dg *data = chip->model_data; 267041f26b6SRoman Volkov 268041f26b6SRoman Volkov value->value.enumerated.item[0] = 269041f26b6SRoman Volkov !!(data->cs4245_shadow[CS4245_ADC_CTRL] & CS4245_HPF_FREEZE); 270041f26b6SRoman Volkov return 0; 271041f26b6SRoman Volkov } 272041f26b6SRoman Volkov 273041f26b6SRoman Volkov static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) 274041f26b6SRoman Volkov { 275041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 276041f26b6SRoman Volkov struct dg *data = chip->model_data; 277041f26b6SRoman Volkov u8 reg; 278041f26b6SRoman Volkov int changed; 279041f26b6SRoman Volkov 280041f26b6SRoman Volkov mutex_lock(&chip->mutex); 281041f26b6SRoman Volkov reg = data->cs4245_shadow[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE; 282041f26b6SRoman Volkov if (value->value.enumerated.item[0]) 283041f26b6SRoman Volkov reg |= CS4245_HPF_FREEZE; 284041f26b6SRoman Volkov changed = reg != data->cs4245_shadow[CS4245_ADC_CTRL]; 285041f26b6SRoman Volkov if (changed) 286041f26b6SRoman Volkov cs4245_write(chip, CS4245_ADC_CTRL, reg); 287041f26b6SRoman Volkov mutex_unlock(&chip->mutex); 288041f26b6SRoman Volkov return changed; 289041f26b6SRoman Volkov } 290041f26b6SRoman Volkov 291041f26b6SRoman Volkov #define INPUT_VOLUME(xname, index) { \ 292041f26b6SRoman Volkov .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 293041f26b6SRoman Volkov .name = xname, \ 294041f26b6SRoman Volkov .info = input_vol_info, \ 295041f26b6SRoman Volkov .get = input_vol_get, \ 296041f26b6SRoman Volkov .put = input_vol_put, \ 297041f26b6SRoman Volkov .tlv = { .p = cs4245_pga_db_scale }, \ 298041f26b6SRoman Volkov .private_value = index, \ 299041f26b6SRoman Volkov } 300041f26b6SRoman Volkov static const struct snd_kcontrol_new dg_controls[] = { 301041f26b6SRoman Volkov { 302041f26b6SRoman Volkov .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 303041f26b6SRoman Volkov .name = "Analog Output Playback Enum", 304041f26b6SRoman Volkov .info = output_switch_info, 305041f26b6SRoman Volkov .get = output_switch_get, 306041f26b6SRoman Volkov .put = output_switch_put, 307041f26b6SRoman Volkov }, 308041f26b6SRoman Volkov { 309041f26b6SRoman Volkov .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 310041f26b6SRoman Volkov .name = "Headphones Impedance Playback Enum", 311041f26b6SRoman Volkov .info = hp_volume_offset_info, 312041f26b6SRoman Volkov .get = hp_volume_offset_get, 313041f26b6SRoman Volkov .put = hp_volume_offset_put, 314041f26b6SRoman Volkov }, 315041f26b6SRoman Volkov INPUT_VOLUME("Mic Capture Volume", 0), 316041f26b6SRoman Volkov INPUT_VOLUME("Aux Capture Volume", 1), 317041f26b6SRoman Volkov INPUT_VOLUME("Front Mic Capture Volume", 2), 318041f26b6SRoman Volkov INPUT_VOLUME("Line Capture Volume", 3), 319041f26b6SRoman Volkov { 320041f26b6SRoman Volkov .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 321041f26b6SRoman Volkov .name = "Capture Source", 322041f26b6SRoman Volkov .info = input_sel_info, 323041f26b6SRoman Volkov .get = input_sel_get, 324041f26b6SRoman Volkov .put = input_sel_put, 325041f26b6SRoman Volkov }, 326041f26b6SRoman Volkov { 327041f26b6SRoman Volkov .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 328041f26b6SRoman Volkov .name = "ADC High-pass Filter Capture Enum", 329041f26b6SRoman Volkov .info = hpf_info, 330041f26b6SRoman Volkov .get = hpf_get, 331041f26b6SRoman Volkov .put = hpf_put, 332041f26b6SRoman Volkov }, 333041f26b6SRoman Volkov }; 334041f26b6SRoman Volkov 335041f26b6SRoman Volkov static int dg_control_filter(struct snd_kcontrol_new *template) 336041f26b6SRoman Volkov { 337041f26b6SRoman Volkov if (!strncmp(template->name, "Master Playback ", 16)) 338041f26b6SRoman Volkov return 1; 339041f26b6SRoman Volkov return 0; 340041f26b6SRoman Volkov } 341041f26b6SRoman Volkov 342041f26b6SRoman Volkov static int dg_mixer_init(struct oxygen *chip) 343041f26b6SRoman Volkov { 344041f26b6SRoman Volkov unsigned int i; 345041f26b6SRoman Volkov int err; 346041f26b6SRoman Volkov 347041f26b6SRoman Volkov for (i = 0; i < ARRAY_SIZE(dg_controls); ++i) { 348041f26b6SRoman Volkov err = snd_ctl_add(chip->card, 349041f26b6SRoman Volkov snd_ctl_new1(&dg_controls[i], chip)); 350041f26b6SRoman Volkov if (err < 0) 351041f26b6SRoman Volkov return err; 352041f26b6SRoman Volkov } 353041f26b6SRoman Volkov return 0; 354041f26b6SRoman Volkov } 355041f26b6SRoman Volkov 356041f26b6SRoman Volkov struct oxygen_model model_xonar_dg = { 357041f26b6SRoman Volkov .longname = "C-Media Oxygen HD Audio", 358041f26b6SRoman Volkov .chip = "CMI8786", 359041f26b6SRoman Volkov .init = dg_init, 360041f26b6SRoman Volkov .control_filter = dg_control_filter, 361041f26b6SRoman Volkov .mixer_init = dg_mixer_init, 362041f26b6SRoman Volkov .cleanup = dg_cleanup, 363041f26b6SRoman Volkov .suspend = dg_suspend, 364041f26b6SRoman Volkov .resume = dg_resume, 365041f26b6SRoman Volkov .set_dac_params = set_cs4245_dac_params, 366041f26b6SRoman Volkov .set_adc_params = set_cs4245_adc_params, 367041f26b6SRoman Volkov .adjust_dac_routing = adjust_dg_dac_routing, 368041f26b6SRoman Volkov .dump_registers = dump_cs4245_registers, 369041f26b6SRoman Volkov .model_data_size = sizeof(struct dg), 370041f26b6SRoman Volkov .device_config = PLAYBACK_0_TO_I2S | 371041f26b6SRoman Volkov PLAYBACK_1_TO_SPDIF | 372*3dd77654SRoman Volkov CAPTURE_0_FROM_I2S_1 | 373041f26b6SRoman Volkov CAPTURE_1_FROM_SPDIF, 374041f26b6SRoman Volkov .dac_channels_pcm = 6, 375041f26b6SRoman Volkov .dac_channels_mixer = 0, 376041f26b6SRoman Volkov .function_flags = OXYGEN_FUNCTION_SPI, 377041f26b6SRoman Volkov .dac_mclks = OXYGEN_MCLKS(256, 128, 128), 378041f26b6SRoman Volkov .adc_mclks = OXYGEN_MCLKS(256, 128, 128), 379041f26b6SRoman Volkov .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, 380041f26b6SRoman Volkov .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, 381041f26b6SRoman Volkov }; 382