1*041f26b6SRoman Volkov /* 2*041f26b6SRoman Volkov * Mixer controls for the Xonar DG/DGX 3*041f26b6SRoman Volkov * 4*041f26b6SRoman Volkov * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 5*041f26b6SRoman Volkov * Copyright (c) Roman Volkov <v1ron@mail.ru> 6*041f26b6SRoman Volkov * 7*041f26b6SRoman Volkov * This driver is free software; you can redistribute it and/or modify 8*041f26b6SRoman Volkov * it under the terms of the GNU General Public License, version 2. 9*041f26b6SRoman Volkov * 10*041f26b6SRoman Volkov * This driver is distributed in the hope that it will be useful, 11*041f26b6SRoman Volkov * but WITHOUT ANY WARRANTY; without even the implied warranty of 12*041f26b6SRoman Volkov * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13*041f26b6SRoman Volkov * GNU General Public License for more details. 14*041f26b6SRoman Volkov * 15*041f26b6SRoman Volkov * You should have received a copy of the GNU General Public License 16*041f26b6SRoman Volkov * along with this driver; if not, see <http://www.gnu.org/licenses/>. 17*041f26b6SRoman Volkov */ 18*041f26b6SRoman Volkov 19*041f26b6SRoman Volkov #include <linux/pci.h> 20*041f26b6SRoman Volkov #include <linux/delay.h> 21*041f26b6SRoman Volkov #include <sound/control.h> 22*041f26b6SRoman Volkov #include <sound/core.h> 23*041f26b6SRoman Volkov #include <sound/info.h> 24*041f26b6SRoman Volkov #include <sound/pcm.h> 25*041f26b6SRoman Volkov #include <sound/tlv.h> 26*041f26b6SRoman Volkov #include "oxygen.h" 27*041f26b6SRoman Volkov #include "xonar_dg.h" 28*041f26b6SRoman Volkov #include "cs4245.h" 29*041f26b6SRoman Volkov 30*041f26b6SRoman Volkov static int output_switch_info(struct snd_kcontrol *ctl, 31*041f26b6SRoman Volkov struct snd_ctl_elem_info *info) 32*041f26b6SRoman Volkov { 33*041f26b6SRoman Volkov static const char *const names[3] = { 34*041f26b6SRoman Volkov "Speakers", "Headphones", "FP Headphones" 35*041f26b6SRoman Volkov }; 36*041f26b6SRoman Volkov 37*041f26b6SRoman Volkov return snd_ctl_enum_info(info, 1, 3, names); 38*041f26b6SRoman Volkov } 39*041f26b6SRoman Volkov 40*041f26b6SRoman Volkov static int output_switch_get(struct snd_kcontrol *ctl, 41*041f26b6SRoman Volkov struct snd_ctl_elem_value *value) 42*041f26b6SRoman Volkov { 43*041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 44*041f26b6SRoman Volkov struct dg *data = chip->model_data; 45*041f26b6SRoman Volkov 46*041f26b6SRoman Volkov mutex_lock(&chip->mutex); 47*041f26b6SRoman Volkov value->value.enumerated.item[0] = data->output_sel; 48*041f26b6SRoman Volkov mutex_unlock(&chip->mutex); 49*041f26b6SRoman Volkov return 0; 50*041f26b6SRoman Volkov } 51*041f26b6SRoman Volkov 52*041f26b6SRoman Volkov static int output_switch_put(struct snd_kcontrol *ctl, 53*041f26b6SRoman Volkov struct snd_ctl_elem_value *value) 54*041f26b6SRoman Volkov { 55*041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 56*041f26b6SRoman Volkov struct dg *data = chip->model_data; 57*041f26b6SRoman Volkov u8 reg; 58*041f26b6SRoman Volkov int changed; 59*041f26b6SRoman Volkov 60*041f26b6SRoman Volkov if (value->value.enumerated.item[0] > 2) 61*041f26b6SRoman Volkov return -EINVAL; 62*041f26b6SRoman Volkov 63*041f26b6SRoman Volkov mutex_lock(&chip->mutex); 64*041f26b6SRoman Volkov changed = value->value.enumerated.item[0] != data->output_sel; 65*041f26b6SRoman Volkov if (changed) { 66*041f26b6SRoman Volkov data->output_sel = value->value.enumerated.item[0]; 67*041f26b6SRoman Volkov 68*041f26b6SRoman Volkov reg = data->cs4245_shadow[CS4245_SIGNAL_SEL] & 69*041f26b6SRoman Volkov ~CS4245_A_OUT_SEL_MASK; 70*041f26b6SRoman Volkov reg |= data->output_sel == 2 ? 71*041f26b6SRoman Volkov CS4245_A_OUT_SEL_DAC : CS4245_A_OUT_SEL_HIZ; 72*041f26b6SRoman Volkov cs4245_write_cached(chip, CS4245_SIGNAL_SEL, reg); 73*041f26b6SRoman Volkov 74*041f26b6SRoman Volkov cs4245_write_cached(chip, CS4245_DAC_A_CTRL, 75*041f26b6SRoman Volkov data->output_sel ? data->hp_vol_att : 0); 76*041f26b6SRoman Volkov cs4245_write_cached(chip, CS4245_DAC_B_CTRL, 77*041f26b6SRoman Volkov data->output_sel ? data->hp_vol_att : 0); 78*041f26b6SRoman Volkov 79*041f26b6SRoman Volkov oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, 80*041f26b6SRoman Volkov data->output_sel == 1 ? GPIO_HP_REAR : 0, 81*041f26b6SRoman Volkov GPIO_HP_REAR); 82*041f26b6SRoman Volkov } 83*041f26b6SRoman Volkov mutex_unlock(&chip->mutex); 84*041f26b6SRoman Volkov return changed; 85*041f26b6SRoman Volkov } 86*041f26b6SRoman Volkov 87*041f26b6SRoman Volkov static int hp_volume_offset_info(struct snd_kcontrol *ctl, 88*041f26b6SRoman Volkov struct snd_ctl_elem_info *info) 89*041f26b6SRoman Volkov { 90*041f26b6SRoman Volkov static const char *const names[3] = { 91*041f26b6SRoman Volkov "< 64 ohms", "64-150 ohms", "150-300 ohms" 92*041f26b6SRoman Volkov }; 93*041f26b6SRoman Volkov 94*041f26b6SRoman Volkov return snd_ctl_enum_info(info, 1, 3, names); 95*041f26b6SRoman Volkov } 96*041f26b6SRoman Volkov 97*041f26b6SRoman Volkov static int hp_volume_offset_get(struct snd_kcontrol *ctl, 98*041f26b6SRoman Volkov struct snd_ctl_elem_value *value) 99*041f26b6SRoman Volkov { 100*041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 101*041f26b6SRoman Volkov struct dg *data = chip->model_data; 102*041f26b6SRoman Volkov 103*041f26b6SRoman Volkov mutex_lock(&chip->mutex); 104*041f26b6SRoman Volkov if (data->hp_vol_att > 2 * 7) 105*041f26b6SRoman Volkov value->value.enumerated.item[0] = 0; 106*041f26b6SRoman Volkov else if (data->hp_vol_att > 0) 107*041f26b6SRoman Volkov value->value.enumerated.item[0] = 1; 108*041f26b6SRoman Volkov else 109*041f26b6SRoman Volkov value->value.enumerated.item[0] = 2; 110*041f26b6SRoman Volkov mutex_unlock(&chip->mutex); 111*041f26b6SRoman Volkov return 0; 112*041f26b6SRoman Volkov } 113*041f26b6SRoman Volkov 114*041f26b6SRoman Volkov static int hp_volume_offset_put(struct snd_kcontrol *ctl, 115*041f26b6SRoman Volkov struct snd_ctl_elem_value *value) 116*041f26b6SRoman Volkov { 117*041f26b6SRoman Volkov static const s8 atts[3] = { 2 * 16, 2 * 7, 0 }; 118*041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 119*041f26b6SRoman Volkov struct dg *data = chip->model_data; 120*041f26b6SRoman Volkov s8 att; 121*041f26b6SRoman Volkov int changed; 122*041f26b6SRoman Volkov 123*041f26b6SRoman Volkov if (value->value.enumerated.item[0] > 2) 124*041f26b6SRoman Volkov return -EINVAL; 125*041f26b6SRoman Volkov att = atts[value->value.enumerated.item[0]]; 126*041f26b6SRoman Volkov mutex_lock(&chip->mutex); 127*041f26b6SRoman Volkov changed = att != data->hp_vol_att; 128*041f26b6SRoman Volkov if (changed) { 129*041f26b6SRoman Volkov data->hp_vol_att = att; 130*041f26b6SRoman Volkov if (data->output_sel) { 131*041f26b6SRoman Volkov cs4245_write_cached(chip, CS4245_DAC_A_CTRL, att); 132*041f26b6SRoman Volkov cs4245_write_cached(chip, CS4245_DAC_B_CTRL, att); 133*041f26b6SRoman Volkov } 134*041f26b6SRoman Volkov } 135*041f26b6SRoman Volkov mutex_unlock(&chip->mutex); 136*041f26b6SRoman Volkov return changed; 137*041f26b6SRoman Volkov } 138*041f26b6SRoman Volkov 139*041f26b6SRoman Volkov static int input_vol_info(struct snd_kcontrol *ctl, 140*041f26b6SRoman Volkov struct snd_ctl_elem_info *info) 141*041f26b6SRoman Volkov { 142*041f26b6SRoman Volkov info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 143*041f26b6SRoman Volkov info->count = 2; 144*041f26b6SRoman Volkov info->value.integer.min = 2 * -12; 145*041f26b6SRoman Volkov info->value.integer.max = 2 * 12; 146*041f26b6SRoman Volkov return 0; 147*041f26b6SRoman Volkov } 148*041f26b6SRoman Volkov 149*041f26b6SRoman Volkov static int input_vol_get(struct snd_kcontrol *ctl, 150*041f26b6SRoman Volkov struct snd_ctl_elem_value *value) 151*041f26b6SRoman Volkov { 152*041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 153*041f26b6SRoman Volkov struct dg *data = chip->model_data; 154*041f26b6SRoman Volkov unsigned int idx = ctl->private_value; 155*041f26b6SRoman Volkov 156*041f26b6SRoman Volkov mutex_lock(&chip->mutex); 157*041f26b6SRoman Volkov value->value.integer.value[0] = data->input_vol[idx][0]; 158*041f26b6SRoman Volkov value->value.integer.value[1] = data->input_vol[idx][1]; 159*041f26b6SRoman Volkov mutex_unlock(&chip->mutex); 160*041f26b6SRoman Volkov return 0; 161*041f26b6SRoman Volkov } 162*041f26b6SRoman Volkov 163*041f26b6SRoman Volkov static int input_vol_put(struct snd_kcontrol *ctl, 164*041f26b6SRoman Volkov struct snd_ctl_elem_value *value) 165*041f26b6SRoman Volkov { 166*041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 167*041f26b6SRoman Volkov struct dg *data = chip->model_data; 168*041f26b6SRoman Volkov unsigned int idx = ctl->private_value; 169*041f26b6SRoman Volkov int changed = 0; 170*041f26b6SRoman Volkov 171*041f26b6SRoman Volkov if (value->value.integer.value[0] < 2 * -12 || 172*041f26b6SRoman Volkov value->value.integer.value[0] > 2 * 12 || 173*041f26b6SRoman Volkov value->value.integer.value[1] < 2 * -12 || 174*041f26b6SRoman Volkov value->value.integer.value[1] > 2 * 12) 175*041f26b6SRoman Volkov return -EINVAL; 176*041f26b6SRoman Volkov mutex_lock(&chip->mutex); 177*041f26b6SRoman Volkov changed = data->input_vol[idx][0] != value->value.integer.value[0] || 178*041f26b6SRoman Volkov data->input_vol[idx][1] != value->value.integer.value[1]; 179*041f26b6SRoman Volkov if (changed) { 180*041f26b6SRoman Volkov data->input_vol[idx][0] = value->value.integer.value[0]; 181*041f26b6SRoman Volkov data->input_vol[idx][1] = value->value.integer.value[1]; 182*041f26b6SRoman Volkov if (idx == data->input_sel) { 183*041f26b6SRoman Volkov cs4245_write_cached(chip, CS4245_PGA_A_CTRL, 184*041f26b6SRoman Volkov data->input_vol[idx][0]); 185*041f26b6SRoman Volkov cs4245_write_cached(chip, CS4245_PGA_B_CTRL, 186*041f26b6SRoman Volkov data->input_vol[idx][1]); 187*041f26b6SRoman Volkov } 188*041f26b6SRoman Volkov } 189*041f26b6SRoman Volkov mutex_unlock(&chip->mutex); 190*041f26b6SRoman Volkov return changed; 191*041f26b6SRoman Volkov } 192*041f26b6SRoman Volkov 193*041f26b6SRoman Volkov static DECLARE_TLV_DB_SCALE(cs4245_pga_db_scale, -1200, 50, 0); 194*041f26b6SRoman Volkov 195*041f26b6SRoman Volkov static int input_sel_info(struct snd_kcontrol *ctl, 196*041f26b6SRoman Volkov struct snd_ctl_elem_info *info) 197*041f26b6SRoman Volkov { 198*041f26b6SRoman Volkov static const char *const names[4] = { 199*041f26b6SRoman Volkov "Mic", "Aux", "Front Mic", "Line" 200*041f26b6SRoman Volkov }; 201*041f26b6SRoman Volkov 202*041f26b6SRoman Volkov return snd_ctl_enum_info(info, 1, 4, names); 203*041f26b6SRoman Volkov } 204*041f26b6SRoman Volkov 205*041f26b6SRoman Volkov static int input_sel_get(struct snd_kcontrol *ctl, 206*041f26b6SRoman Volkov struct snd_ctl_elem_value *value) 207*041f26b6SRoman Volkov { 208*041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 209*041f26b6SRoman Volkov struct dg *data = chip->model_data; 210*041f26b6SRoman Volkov 211*041f26b6SRoman Volkov mutex_lock(&chip->mutex); 212*041f26b6SRoman Volkov value->value.enumerated.item[0] = data->input_sel; 213*041f26b6SRoman Volkov mutex_unlock(&chip->mutex); 214*041f26b6SRoman Volkov return 0; 215*041f26b6SRoman Volkov } 216*041f26b6SRoman Volkov 217*041f26b6SRoman Volkov static int input_sel_put(struct snd_kcontrol *ctl, 218*041f26b6SRoman Volkov struct snd_ctl_elem_value *value) 219*041f26b6SRoman Volkov { 220*041f26b6SRoman Volkov static const u8 sel_values[4] = { 221*041f26b6SRoman Volkov CS4245_SEL_MIC, 222*041f26b6SRoman Volkov CS4245_SEL_INPUT_1, 223*041f26b6SRoman Volkov CS4245_SEL_INPUT_2, 224*041f26b6SRoman Volkov CS4245_SEL_INPUT_4 225*041f26b6SRoman Volkov }; 226*041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 227*041f26b6SRoman Volkov struct dg *data = chip->model_data; 228*041f26b6SRoman Volkov int changed; 229*041f26b6SRoman Volkov 230*041f26b6SRoman Volkov if (value->value.enumerated.item[0] > 3) 231*041f26b6SRoman Volkov return -EINVAL; 232*041f26b6SRoman Volkov 233*041f26b6SRoman Volkov mutex_lock(&chip->mutex); 234*041f26b6SRoman Volkov changed = value->value.enumerated.item[0] != data->input_sel; 235*041f26b6SRoman Volkov if (changed) { 236*041f26b6SRoman Volkov data->input_sel = value->value.enumerated.item[0]; 237*041f26b6SRoman Volkov 238*041f26b6SRoman Volkov cs4245_write(chip, CS4245_ANALOG_IN, 239*041f26b6SRoman Volkov (data->cs4245_shadow[CS4245_ANALOG_IN] & 240*041f26b6SRoman Volkov ~CS4245_SEL_MASK) | 241*041f26b6SRoman Volkov sel_values[data->input_sel]); 242*041f26b6SRoman Volkov 243*041f26b6SRoman Volkov cs4245_write_cached(chip, CS4245_PGA_A_CTRL, 244*041f26b6SRoman Volkov data->input_vol[data->input_sel][0]); 245*041f26b6SRoman Volkov cs4245_write_cached(chip, CS4245_PGA_B_CTRL, 246*041f26b6SRoman Volkov data->input_vol[data->input_sel][1]); 247*041f26b6SRoman Volkov 248*041f26b6SRoman Volkov oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, 249*041f26b6SRoman Volkov data->input_sel ? 0 : GPIO_INPUT_ROUTE, 250*041f26b6SRoman Volkov GPIO_INPUT_ROUTE); 251*041f26b6SRoman Volkov } 252*041f26b6SRoman Volkov mutex_unlock(&chip->mutex); 253*041f26b6SRoman Volkov return changed; 254*041f26b6SRoman Volkov } 255*041f26b6SRoman Volkov 256*041f26b6SRoman Volkov static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) 257*041f26b6SRoman Volkov { 258*041f26b6SRoman Volkov static const char *const names[2] = { "Active", "Frozen" }; 259*041f26b6SRoman Volkov 260*041f26b6SRoman Volkov return snd_ctl_enum_info(info, 1, 2, names); 261*041f26b6SRoman Volkov } 262*041f26b6SRoman Volkov 263*041f26b6SRoman Volkov static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) 264*041f26b6SRoman Volkov { 265*041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 266*041f26b6SRoman Volkov struct dg *data = chip->model_data; 267*041f26b6SRoman Volkov 268*041f26b6SRoman Volkov value->value.enumerated.item[0] = 269*041f26b6SRoman Volkov !!(data->cs4245_shadow[CS4245_ADC_CTRL] & CS4245_HPF_FREEZE); 270*041f26b6SRoman Volkov return 0; 271*041f26b6SRoman Volkov } 272*041f26b6SRoman Volkov 273*041f26b6SRoman Volkov static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) 274*041f26b6SRoman Volkov { 275*041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 276*041f26b6SRoman Volkov struct dg *data = chip->model_data; 277*041f26b6SRoman Volkov u8 reg; 278*041f26b6SRoman Volkov int changed; 279*041f26b6SRoman Volkov 280*041f26b6SRoman Volkov mutex_lock(&chip->mutex); 281*041f26b6SRoman Volkov reg = data->cs4245_shadow[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE; 282*041f26b6SRoman Volkov if (value->value.enumerated.item[0]) 283*041f26b6SRoman Volkov reg |= CS4245_HPF_FREEZE; 284*041f26b6SRoman Volkov changed = reg != data->cs4245_shadow[CS4245_ADC_CTRL]; 285*041f26b6SRoman Volkov if (changed) 286*041f26b6SRoman Volkov cs4245_write(chip, CS4245_ADC_CTRL, reg); 287*041f26b6SRoman Volkov mutex_unlock(&chip->mutex); 288*041f26b6SRoman Volkov return changed; 289*041f26b6SRoman Volkov } 290*041f26b6SRoman Volkov 291*041f26b6SRoman Volkov #define INPUT_VOLUME(xname, index) { \ 292*041f26b6SRoman Volkov .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 293*041f26b6SRoman Volkov .name = xname, \ 294*041f26b6SRoman Volkov .info = input_vol_info, \ 295*041f26b6SRoman Volkov .get = input_vol_get, \ 296*041f26b6SRoman Volkov .put = input_vol_put, \ 297*041f26b6SRoman Volkov .tlv = { .p = cs4245_pga_db_scale }, \ 298*041f26b6SRoman Volkov .private_value = index, \ 299*041f26b6SRoman Volkov } 300*041f26b6SRoman Volkov static const struct snd_kcontrol_new dg_controls[] = { 301*041f26b6SRoman Volkov { 302*041f26b6SRoman Volkov .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 303*041f26b6SRoman Volkov .name = "Analog Output Playback Enum", 304*041f26b6SRoman Volkov .info = output_switch_info, 305*041f26b6SRoman Volkov .get = output_switch_get, 306*041f26b6SRoman Volkov .put = output_switch_put, 307*041f26b6SRoman Volkov }, 308*041f26b6SRoman Volkov { 309*041f26b6SRoman Volkov .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 310*041f26b6SRoman Volkov .name = "Headphones Impedance Playback Enum", 311*041f26b6SRoman Volkov .info = hp_volume_offset_info, 312*041f26b6SRoman Volkov .get = hp_volume_offset_get, 313*041f26b6SRoman Volkov .put = hp_volume_offset_put, 314*041f26b6SRoman Volkov }, 315*041f26b6SRoman Volkov INPUT_VOLUME("Mic Capture Volume", 0), 316*041f26b6SRoman Volkov INPUT_VOLUME("Aux Capture Volume", 1), 317*041f26b6SRoman Volkov INPUT_VOLUME("Front Mic Capture Volume", 2), 318*041f26b6SRoman Volkov INPUT_VOLUME("Line Capture Volume", 3), 319*041f26b6SRoman Volkov { 320*041f26b6SRoman Volkov .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 321*041f26b6SRoman Volkov .name = "Capture Source", 322*041f26b6SRoman Volkov .info = input_sel_info, 323*041f26b6SRoman Volkov .get = input_sel_get, 324*041f26b6SRoman Volkov .put = input_sel_put, 325*041f26b6SRoman Volkov }, 326*041f26b6SRoman Volkov { 327*041f26b6SRoman Volkov .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 328*041f26b6SRoman Volkov .name = "ADC High-pass Filter Capture Enum", 329*041f26b6SRoman Volkov .info = hpf_info, 330*041f26b6SRoman Volkov .get = hpf_get, 331*041f26b6SRoman Volkov .put = hpf_put, 332*041f26b6SRoman Volkov }, 333*041f26b6SRoman Volkov }; 334*041f26b6SRoman Volkov 335*041f26b6SRoman Volkov static int dg_control_filter(struct snd_kcontrol_new *template) 336*041f26b6SRoman Volkov { 337*041f26b6SRoman Volkov if (!strncmp(template->name, "Master Playback ", 16)) 338*041f26b6SRoman Volkov return 1; 339*041f26b6SRoman Volkov return 0; 340*041f26b6SRoman Volkov } 341*041f26b6SRoman Volkov 342*041f26b6SRoman Volkov static int dg_mixer_init(struct oxygen *chip) 343*041f26b6SRoman Volkov { 344*041f26b6SRoman Volkov unsigned int i; 345*041f26b6SRoman Volkov int err; 346*041f26b6SRoman Volkov 347*041f26b6SRoman Volkov for (i = 0; i < ARRAY_SIZE(dg_controls); ++i) { 348*041f26b6SRoman Volkov err = snd_ctl_add(chip->card, 349*041f26b6SRoman Volkov snd_ctl_new1(&dg_controls[i], chip)); 350*041f26b6SRoman Volkov if (err < 0) 351*041f26b6SRoman Volkov return err; 352*041f26b6SRoman Volkov } 353*041f26b6SRoman Volkov return 0; 354*041f26b6SRoman Volkov } 355*041f26b6SRoman Volkov 356*041f26b6SRoman Volkov struct oxygen_model model_xonar_dg = { 357*041f26b6SRoman Volkov .longname = "C-Media Oxygen HD Audio", 358*041f26b6SRoman Volkov .chip = "CMI8786", 359*041f26b6SRoman Volkov .init = dg_init, 360*041f26b6SRoman Volkov .control_filter = dg_control_filter, 361*041f26b6SRoman Volkov .mixer_init = dg_mixer_init, 362*041f26b6SRoman Volkov .cleanup = dg_cleanup, 363*041f26b6SRoman Volkov .suspend = dg_suspend, 364*041f26b6SRoman Volkov .resume = dg_resume, 365*041f26b6SRoman Volkov .set_dac_params = set_cs4245_dac_params, 366*041f26b6SRoman Volkov .set_adc_params = set_cs4245_adc_params, 367*041f26b6SRoman Volkov .adjust_dac_routing = adjust_dg_dac_routing, 368*041f26b6SRoman Volkov .dump_registers = dump_cs4245_registers, 369*041f26b6SRoman Volkov .model_data_size = sizeof(struct dg), 370*041f26b6SRoman Volkov .device_config = PLAYBACK_0_TO_I2S | 371*041f26b6SRoman Volkov PLAYBACK_1_TO_SPDIF | 372*041f26b6SRoman Volkov CAPTURE_0_FROM_I2S_2 | 373*041f26b6SRoman Volkov CAPTURE_1_FROM_SPDIF, 374*041f26b6SRoman Volkov .dac_channels_pcm = 6, 375*041f26b6SRoman Volkov .dac_channels_mixer = 0, 376*041f26b6SRoman Volkov .function_flags = OXYGEN_FUNCTION_SPI, 377*041f26b6SRoman Volkov .dac_mclks = OXYGEN_MCLKS(256, 128, 128), 378*041f26b6SRoman Volkov .adc_mclks = OXYGEN_MCLKS(256, 128, 128), 379*041f26b6SRoman Volkov .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, 380*041f26b6SRoman Volkov .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, 381*041f26b6SRoman Volkov }; 382