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 302809cb84SRoman Volkov /* analog output select */ 312809cb84SRoman Volkov 322809cb84SRoman Volkov static int output_select_apply(struct oxygen *chip) 332809cb84SRoman Volkov { 342809cb84SRoman Volkov struct dg *data = chip->model_data; 352809cb84SRoman Volkov 362809cb84SRoman Volkov data->cs4245_shadow[CS4245_SIGNAL_SEL] &= ~CS4245_A_OUT_SEL_MASK; 372809cb84SRoman Volkov if (data->output_sel == PLAYBACK_DST_HP) { 382809cb84SRoman Volkov /* mute FP (aux output) amplifier, switch rear jack to CS4245 */ 392809cb84SRoman Volkov oxygen_set_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR); 402809cb84SRoman Volkov } else if (data->output_sel == PLAYBACK_DST_HP_FP) { 412809cb84SRoman Volkov /* 422809cb84SRoman Volkov * Unmute FP amplifier, switch rear jack to CS4361; 432809cb84SRoman Volkov * I2S channels 2,3,4 should be inactive. 442809cb84SRoman Volkov */ 452809cb84SRoman Volkov oxygen_clear_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR); 462809cb84SRoman Volkov data->cs4245_shadow[CS4245_SIGNAL_SEL] |= CS4245_A_OUT_SEL_DAC; 472809cb84SRoman Volkov } else { 482809cb84SRoman Volkov /* 492809cb84SRoman Volkov * 2.0, 4.0, 5.1: switch to CS4361, mute FP amp., 502809cb84SRoman Volkov * and change playback routing. 512809cb84SRoman Volkov */ 522809cb84SRoman Volkov oxygen_clear_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR); 532809cb84SRoman Volkov } 542809cb84SRoman Volkov return cs4245_write_spi(chip, CS4245_SIGNAL_SEL); 552809cb84SRoman Volkov } 562809cb84SRoman Volkov 572809cb84SRoman Volkov static int output_select_info(struct snd_kcontrol *ctl, 58041f26b6SRoman Volkov struct snd_ctl_elem_info *info) 59041f26b6SRoman Volkov { 60041f26b6SRoman Volkov static const char *const names[3] = { 612809cb84SRoman Volkov "Stereo Headphones", 622809cb84SRoman Volkov "Stereo Headphones FP", 632809cb84SRoman Volkov "Multichannel", 64041f26b6SRoman Volkov }; 65041f26b6SRoman Volkov 66041f26b6SRoman Volkov return snd_ctl_enum_info(info, 1, 3, names); 67041f26b6SRoman Volkov } 68041f26b6SRoman Volkov 692809cb84SRoman Volkov static int output_select_get(struct snd_kcontrol *ctl, 70041f26b6SRoman Volkov struct snd_ctl_elem_value *value) 71041f26b6SRoman Volkov { 72041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 73041f26b6SRoman Volkov struct dg *data = chip->model_data; 74041f26b6SRoman Volkov 75041f26b6SRoman Volkov mutex_lock(&chip->mutex); 76041f26b6SRoman Volkov value->value.enumerated.item[0] = data->output_sel; 77041f26b6SRoman Volkov mutex_unlock(&chip->mutex); 78041f26b6SRoman Volkov return 0; 79041f26b6SRoman Volkov } 80041f26b6SRoman Volkov 812809cb84SRoman Volkov static int output_select_put(struct snd_kcontrol *ctl, 82041f26b6SRoman Volkov struct snd_ctl_elem_value *value) 83041f26b6SRoman Volkov { 84041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 85041f26b6SRoman Volkov struct dg *data = chip->model_data; 862809cb84SRoman Volkov unsigned int new = value->value.enumerated.item[0]; 872809cb84SRoman Volkov int changed = 0; 882809cb84SRoman Volkov int ret; 89041f26b6SRoman Volkov 90041f26b6SRoman Volkov mutex_lock(&chip->mutex); 912809cb84SRoman Volkov if (data->output_sel != new) { 922809cb84SRoman Volkov data->output_sel = new; 932809cb84SRoman Volkov ret = output_select_apply(chip); 942809cb84SRoman Volkov changed = ret >= 0 ? 1 : ret; 952809cb84SRoman Volkov oxygen_update_dac_routing(chip); 96041f26b6SRoman Volkov } 97041f26b6SRoman Volkov mutex_unlock(&chip->mutex); 982809cb84SRoman Volkov 99041f26b6SRoman Volkov return changed; 100041f26b6SRoman Volkov } 101041f26b6SRoman Volkov 102*c754639aSRoman Volkov /* CS4245 Headphone Channels A&B Volume Control */ 103*c754639aSRoman Volkov 104*c754639aSRoman Volkov static int hp_stereo_volume_info(struct snd_kcontrol *ctl, 105041f26b6SRoman Volkov struct snd_ctl_elem_info *info) 106041f26b6SRoman Volkov { 107*c754639aSRoman Volkov info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 108*c754639aSRoman Volkov info->count = 2; 109*c754639aSRoman Volkov info->value.integer.min = 0; 110*c754639aSRoman Volkov info->value.integer.max = 255; 111*c754639aSRoman Volkov return 0; 112041f26b6SRoman Volkov } 113041f26b6SRoman Volkov 114*c754639aSRoman Volkov static int hp_stereo_volume_get(struct snd_kcontrol *ctl, 115*c754639aSRoman Volkov struct snd_ctl_elem_value *val) 116041f26b6SRoman Volkov { 117041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 118041f26b6SRoman Volkov struct dg *data = chip->model_data; 119*c754639aSRoman Volkov unsigned int tmp; 120041f26b6SRoman Volkov 121041f26b6SRoman Volkov mutex_lock(&chip->mutex); 122*c754639aSRoman Volkov tmp = (~data->cs4245_shadow[CS4245_DAC_A_CTRL]) & 255; 123*c754639aSRoman Volkov val->value.integer.value[0] = tmp; 124*c754639aSRoman Volkov tmp = (~data->cs4245_shadow[CS4245_DAC_B_CTRL]) & 255; 125*c754639aSRoman Volkov val->value.integer.value[1] = tmp; 126041f26b6SRoman Volkov mutex_unlock(&chip->mutex); 127041f26b6SRoman Volkov return 0; 128041f26b6SRoman Volkov } 129041f26b6SRoman Volkov 130*c754639aSRoman Volkov static int hp_stereo_volume_put(struct snd_kcontrol *ctl, 131*c754639aSRoman Volkov struct snd_ctl_elem_value *val) 132041f26b6SRoman Volkov { 133041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 134041f26b6SRoman Volkov struct dg *data = chip->model_data; 135*c754639aSRoman Volkov int ret; 136*c754639aSRoman Volkov int changed = 0; 137*c754639aSRoman Volkov long new1 = val->value.integer.value[0]; 138*c754639aSRoman Volkov long new2 = val->value.integer.value[1]; 139*c754639aSRoman Volkov 140*c754639aSRoman Volkov if ((new1 > 255) || (new1 < 0) || (new2 > 255) || (new2 < 0)) 141*c754639aSRoman Volkov return -EINVAL; 142*c754639aSRoman Volkov 143*c754639aSRoman Volkov mutex_lock(&chip->mutex); 144*c754639aSRoman Volkov if ((data->cs4245_shadow[CS4245_DAC_A_CTRL] != ~new1) || 145*c754639aSRoman Volkov (data->cs4245_shadow[CS4245_DAC_B_CTRL] != ~new2)) { 146*c754639aSRoman Volkov data->cs4245_shadow[CS4245_DAC_A_CTRL] = ~new1; 147*c754639aSRoman Volkov data->cs4245_shadow[CS4245_DAC_B_CTRL] = ~new2; 148*c754639aSRoman Volkov ret = cs4245_write_spi(chip, CS4245_DAC_A_CTRL); 149*c754639aSRoman Volkov if (ret >= 0) 150*c754639aSRoman Volkov ret = cs4245_write_spi(chip, CS4245_DAC_B_CTRL); 151*c754639aSRoman Volkov changed = ret >= 0 ? 1 : ret; 152*c754639aSRoman Volkov } 153*c754639aSRoman Volkov mutex_unlock(&chip->mutex); 154*c754639aSRoman Volkov 155*c754639aSRoman Volkov return changed; 156*c754639aSRoman Volkov } 157*c754639aSRoman Volkov 158*c754639aSRoman Volkov /* Headphone Mute */ 159*c754639aSRoman Volkov 160*c754639aSRoman Volkov static int hp_mute_get(struct snd_kcontrol *ctl, 161*c754639aSRoman Volkov struct snd_ctl_elem_value *val) 162*c754639aSRoman Volkov { 163*c754639aSRoman Volkov struct oxygen *chip = ctl->private_data; 164*c754639aSRoman Volkov struct dg *data = chip->model_data; 165*c754639aSRoman Volkov 166*c754639aSRoman Volkov mutex_lock(&chip->mutex); 167*c754639aSRoman Volkov val->value.integer.value[0] = 168*c754639aSRoman Volkov !(data->cs4245_shadow[CS4245_DAC_CTRL_1] & CS4245_MUTE_DAC); 169*c754639aSRoman Volkov mutex_unlock(&chip->mutex); 170*c754639aSRoman Volkov return 0; 171*c754639aSRoman Volkov } 172*c754639aSRoman Volkov 173*c754639aSRoman Volkov static int hp_mute_put(struct snd_kcontrol *ctl, 174*c754639aSRoman Volkov struct snd_ctl_elem_value *val) 175*c754639aSRoman Volkov { 176*c754639aSRoman Volkov struct oxygen *chip = ctl->private_data; 177*c754639aSRoman Volkov struct dg *data = chip->model_data; 178*c754639aSRoman Volkov int ret; 179041f26b6SRoman Volkov int changed; 180041f26b6SRoman Volkov 181*c754639aSRoman Volkov if (val->value.integer.value[0] > 1) 182041f26b6SRoman Volkov return -EINVAL; 183041f26b6SRoman Volkov mutex_lock(&chip->mutex); 184*c754639aSRoman Volkov data->cs4245_shadow[CS4245_DAC_CTRL_1] &= ~CS4245_MUTE_DAC; 185*c754639aSRoman Volkov data->cs4245_shadow[CS4245_DAC_CTRL_1] |= 186*c754639aSRoman Volkov (~val->value.integer.value[0] << 2) & CS4245_MUTE_DAC; 187*c754639aSRoman Volkov ret = cs4245_write_spi(chip, CS4245_DAC_CTRL_1); 188*c754639aSRoman Volkov changed = ret >= 0 ? 1 : ret; 189041f26b6SRoman Volkov mutex_unlock(&chip->mutex); 190041f26b6SRoman Volkov return changed; 191041f26b6SRoman Volkov } 192041f26b6SRoman Volkov 193041f26b6SRoman Volkov static int input_vol_info(struct snd_kcontrol *ctl, 194041f26b6SRoman Volkov struct snd_ctl_elem_info *info) 195041f26b6SRoman Volkov { 196041f26b6SRoman Volkov info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 197041f26b6SRoman Volkov info->count = 2; 198041f26b6SRoman Volkov info->value.integer.min = 2 * -12; 199041f26b6SRoman Volkov info->value.integer.max = 2 * 12; 200041f26b6SRoman Volkov return 0; 201041f26b6SRoman Volkov } 202041f26b6SRoman Volkov 203041f26b6SRoman Volkov static int input_vol_get(struct snd_kcontrol *ctl, 204041f26b6SRoman Volkov struct snd_ctl_elem_value *value) 205041f26b6SRoman Volkov { 206041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 207041f26b6SRoman Volkov struct dg *data = chip->model_data; 208041f26b6SRoman Volkov unsigned int idx = ctl->private_value; 209041f26b6SRoman Volkov 210041f26b6SRoman Volkov mutex_lock(&chip->mutex); 211041f26b6SRoman Volkov value->value.integer.value[0] = data->input_vol[idx][0]; 212041f26b6SRoman Volkov value->value.integer.value[1] = data->input_vol[idx][1]; 213041f26b6SRoman Volkov mutex_unlock(&chip->mutex); 214041f26b6SRoman Volkov return 0; 215041f26b6SRoman Volkov } 216041f26b6SRoman Volkov 217041f26b6SRoman Volkov static int input_vol_put(struct snd_kcontrol *ctl, 218041f26b6SRoman Volkov struct snd_ctl_elem_value *value) 219041f26b6SRoman Volkov { 220041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 221041f26b6SRoman Volkov struct dg *data = chip->model_data; 222041f26b6SRoman Volkov unsigned int idx = ctl->private_value; 223041f26b6SRoman Volkov int changed = 0; 224041f26b6SRoman Volkov 225041f26b6SRoman Volkov if (value->value.integer.value[0] < 2 * -12 || 226041f26b6SRoman Volkov value->value.integer.value[0] > 2 * 12 || 227041f26b6SRoman Volkov value->value.integer.value[1] < 2 * -12 || 228041f26b6SRoman Volkov value->value.integer.value[1] > 2 * 12) 229041f26b6SRoman Volkov return -EINVAL; 230041f26b6SRoman Volkov mutex_lock(&chip->mutex); 231041f26b6SRoman Volkov changed = data->input_vol[idx][0] != value->value.integer.value[0] || 232041f26b6SRoman Volkov data->input_vol[idx][1] != value->value.integer.value[1]; 233041f26b6SRoman Volkov if (changed) { 234041f26b6SRoman Volkov data->input_vol[idx][0] = value->value.integer.value[0]; 235041f26b6SRoman Volkov data->input_vol[idx][1] = value->value.integer.value[1]; 236041f26b6SRoman Volkov if (idx == data->input_sel) { 237041f26b6SRoman Volkov cs4245_write_cached(chip, CS4245_PGA_A_CTRL, 238041f26b6SRoman Volkov data->input_vol[idx][0]); 239041f26b6SRoman Volkov cs4245_write_cached(chip, CS4245_PGA_B_CTRL, 240041f26b6SRoman Volkov data->input_vol[idx][1]); 241041f26b6SRoman Volkov } 242041f26b6SRoman Volkov } 243041f26b6SRoman Volkov mutex_unlock(&chip->mutex); 244041f26b6SRoman Volkov return changed; 245041f26b6SRoman Volkov } 246041f26b6SRoman Volkov 247041f26b6SRoman Volkov static DECLARE_TLV_DB_SCALE(cs4245_pga_db_scale, -1200, 50, 0); 248041f26b6SRoman Volkov 249041f26b6SRoman Volkov static int input_sel_info(struct snd_kcontrol *ctl, 250041f26b6SRoman Volkov struct snd_ctl_elem_info *info) 251041f26b6SRoman Volkov { 252041f26b6SRoman Volkov static const char *const names[4] = { 253041f26b6SRoman Volkov "Mic", "Aux", "Front Mic", "Line" 254041f26b6SRoman Volkov }; 255041f26b6SRoman Volkov 256041f26b6SRoman Volkov return snd_ctl_enum_info(info, 1, 4, names); 257041f26b6SRoman Volkov } 258041f26b6SRoman Volkov 259041f26b6SRoman Volkov static int input_sel_get(struct snd_kcontrol *ctl, 260041f26b6SRoman Volkov struct snd_ctl_elem_value *value) 261041f26b6SRoman Volkov { 262041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 263041f26b6SRoman Volkov struct dg *data = chip->model_data; 264041f26b6SRoman Volkov 265041f26b6SRoman Volkov mutex_lock(&chip->mutex); 266041f26b6SRoman Volkov value->value.enumerated.item[0] = data->input_sel; 267041f26b6SRoman Volkov mutex_unlock(&chip->mutex); 268041f26b6SRoman Volkov return 0; 269041f26b6SRoman Volkov } 270041f26b6SRoman Volkov 271041f26b6SRoman Volkov static int input_sel_put(struct snd_kcontrol *ctl, 272041f26b6SRoman Volkov struct snd_ctl_elem_value *value) 273041f26b6SRoman Volkov { 274041f26b6SRoman Volkov static const u8 sel_values[4] = { 275041f26b6SRoman Volkov CS4245_SEL_MIC, 276041f26b6SRoman Volkov CS4245_SEL_INPUT_1, 277041f26b6SRoman Volkov CS4245_SEL_INPUT_2, 278041f26b6SRoman Volkov CS4245_SEL_INPUT_4 279041f26b6SRoman Volkov }; 280041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 281041f26b6SRoman Volkov struct dg *data = chip->model_data; 282041f26b6SRoman Volkov int changed; 283041f26b6SRoman Volkov 284041f26b6SRoman Volkov if (value->value.enumerated.item[0] > 3) 285041f26b6SRoman Volkov return -EINVAL; 286041f26b6SRoman Volkov 287041f26b6SRoman Volkov mutex_lock(&chip->mutex); 288041f26b6SRoman Volkov changed = value->value.enumerated.item[0] != data->input_sel; 289041f26b6SRoman Volkov if (changed) { 290041f26b6SRoman Volkov data->input_sel = value->value.enumerated.item[0]; 291041f26b6SRoman Volkov 292041f26b6SRoman Volkov cs4245_write(chip, CS4245_ANALOG_IN, 293041f26b6SRoman Volkov (data->cs4245_shadow[CS4245_ANALOG_IN] & 294041f26b6SRoman Volkov ~CS4245_SEL_MASK) | 295041f26b6SRoman Volkov sel_values[data->input_sel]); 296041f26b6SRoman Volkov 297041f26b6SRoman Volkov cs4245_write_cached(chip, CS4245_PGA_A_CTRL, 298041f26b6SRoman Volkov data->input_vol[data->input_sel][0]); 299041f26b6SRoman Volkov cs4245_write_cached(chip, CS4245_PGA_B_CTRL, 300041f26b6SRoman Volkov data->input_vol[data->input_sel][1]); 301041f26b6SRoman Volkov 302041f26b6SRoman Volkov oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, 303041f26b6SRoman Volkov data->input_sel ? 0 : GPIO_INPUT_ROUTE, 304041f26b6SRoman Volkov GPIO_INPUT_ROUTE); 305041f26b6SRoman Volkov } 306041f26b6SRoman Volkov mutex_unlock(&chip->mutex); 307041f26b6SRoman Volkov return changed; 308041f26b6SRoman Volkov } 309041f26b6SRoman Volkov 310041f26b6SRoman Volkov static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) 311041f26b6SRoman Volkov { 312041f26b6SRoman Volkov static const char *const names[2] = { "Active", "Frozen" }; 313041f26b6SRoman Volkov 314041f26b6SRoman Volkov return snd_ctl_enum_info(info, 1, 2, names); 315041f26b6SRoman Volkov } 316041f26b6SRoman Volkov 317041f26b6SRoman Volkov static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) 318041f26b6SRoman Volkov { 319041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 320041f26b6SRoman Volkov struct dg *data = chip->model_data; 321041f26b6SRoman Volkov 322041f26b6SRoman Volkov value->value.enumerated.item[0] = 323041f26b6SRoman Volkov !!(data->cs4245_shadow[CS4245_ADC_CTRL] & CS4245_HPF_FREEZE); 324041f26b6SRoman Volkov return 0; 325041f26b6SRoman Volkov } 326041f26b6SRoman Volkov 327041f26b6SRoman Volkov static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) 328041f26b6SRoman Volkov { 329041f26b6SRoman Volkov struct oxygen *chip = ctl->private_data; 330041f26b6SRoman Volkov struct dg *data = chip->model_data; 331041f26b6SRoman Volkov u8 reg; 332041f26b6SRoman Volkov int changed; 333041f26b6SRoman Volkov 334041f26b6SRoman Volkov mutex_lock(&chip->mutex); 335041f26b6SRoman Volkov reg = data->cs4245_shadow[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE; 336041f26b6SRoman Volkov if (value->value.enumerated.item[0]) 337041f26b6SRoman Volkov reg |= CS4245_HPF_FREEZE; 338041f26b6SRoman Volkov changed = reg != data->cs4245_shadow[CS4245_ADC_CTRL]; 339041f26b6SRoman Volkov if (changed) 340041f26b6SRoman Volkov cs4245_write(chip, CS4245_ADC_CTRL, reg); 341041f26b6SRoman Volkov mutex_unlock(&chip->mutex); 342041f26b6SRoman Volkov return changed; 343041f26b6SRoman Volkov } 344041f26b6SRoman Volkov 345041f26b6SRoman Volkov #define INPUT_VOLUME(xname, index) { \ 346041f26b6SRoman Volkov .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 347041f26b6SRoman Volkov .name = xname, \ 348041f26b6SRoman Volkov .info = input_vol_info, \ 349041f26b6SRoman Volkov .get = input_vol_get, \ 350041f26b6SRoman Volkov .put = input_vol_put, \ 351041f26b6SRoman Volkov .tlv = { .p = cs4245_pga_db_scale }, \ 352041f26b6SRoman Volkov .private_value = index, \ 353041f26b6SRoman Volkov } 354*c754639aSRoman Volkov static const DECLARE_TLV_DB_MINMAX(hp_db_scale, -12550, 0); 355041f26b6SRoman Volkov static const struct snd_kcontrol_new dg_controls[] = { 356041f26b6SRoman Volkov { 357041f26b6SRoman Volkov .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 358041f26b6SRoman Volkov .name = "Analog Output Playback Enum", 3592809cb84SRoman Volkov .info = output_select_info, 3602809cb84SRoman Volkov .get = output_select_get, 3612809cb84SRoman Volkov .put = output_select_put, 362041f26b6SRoman Volkov }, 363041f26b6SRoman Volkov { 364041f26b6SRoman Volkov .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 365*c754639aSRoman Volkov .name = "Headphone Playback Volume", 366*c754639aSRoman Volkov .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 367*c754639aSRoman Volkov SNDRV_CTL_ELEM_ACCESS_TLV_READ, 368*c754639aSRoman Volkov .info = hp_stereo_volume_info, 369*c754639aSRoman Volkov .get = hp_stereo_volume_get, 370*c754639aSRoman Volkov .put = hp_stereo_volume_put, 371*c754639aSRoman Volkov .tlv = { .p = hp_db_scale, }, 372*c754639aSRoman Volkov }, 373*c754639aSRoman Volkov { 374*c754639aSRoman Volkov .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 375*c754639aSRoman Volkov .name = "Headphone Playback Switch", 376*c754639aSRoman Volkov .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 377*c754639aSRoman Volkov .info = snd_ctl_boolean_mono_info, 378*c754639aSRoman Volkov .get = hp_mute_get, 379*c754639aSRoman Volkov .put = hp_mute_put, 380041f26b6SRoman Volkov }, 381041f26b6SRoman Volkov INPUT_VOLUME("Mic Capture Volume", 0), 382041f26b6SRoman Volkov INPUT_VOLUME("Aux Capture Volume", 1), 383041f26b6SRoman Volkov INPUT_VOLUME("Front Mic Capture Volume", 2), 384041f26b6SRoman Volkov INPUT_VOLUME("Line Capture Volume", 3), 385041f26b6SRoman Volkov { 386041f26b6SRoman Volkov .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 387041f26b6SRoman Volkov .name = "Capture Source", 388041f26b6SRoman Volkov .info = input_sel_info, 389041f26b6SRoman Volkov .get = input_sel_get, 390041f26b6SRoman Volkov .put = input_sel_put, 391041f26b6SRoman Volkov }, 392041f26b6SRoman Volkov { 393041f26b6SRoman Volkov .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 394041f26b6SRoman Volkov .name = "ADC High-pass Filter Capture Enum", 395041f26b6SRoman Volkov .info = hpf_info, 396041f26b6SRoman Volkov .get = hpf_get, 397041f26b6SRoman Volkov .put = hpf_put, 398041f26b6SRoman Volkov }, 399041f26b6SRoman Volkov }; 400041f26b6SRoman Volkov 401041f26b6SRoman Volkov static int dg_control_filter(struct snd_kcontrol_new *template) 402041f26b6SRoman Volkov { 403041f26b6SRoman Volkov if (!strncmp(template->name, "Master Playback ", 16)) 404041f26b6SRoman Volkov return 1; 405041f26b6SRoman Volkov return 0; 406041f26b6SRoman Volkov } 407041f26b6SRoman Volkov 408041f26b6SRoman Volkov static int dg_mixer_init(struct oxygen *chip) 409041f26b6SRoman Volkov { 410041f26b6SRoman Volkov unsigned int i; 411041f26b6SRoman Volkov int err; 412041f26b6SRoman Volkov 413041f26b6SRoman Volkov for (i = 0; i < ARRAY_SIZE(dg_controls); ++i) { 414041f26b6SRoman Volkov err = snd_ctl_add(chip->card, 415041f26b6SRoman Volkov snd_ctl_new1(&dg_controls[i], chip)); 416041f26b6SRoman Volkov if (err < 0) 417041f26b6SRoman Volkov return err; 418041f26b6SRoman Volkov } 419041f26b6SRoman Volkov return 0; 420041f26b6SRoman Volkov } 421041f26b6SRoman Volkov 422041f26b6SRoman Volkov struct oxygen_model model_xonar_dg = { 423041f26b6SRoman Volkov .longname = "C-Media Oxygen HD Audio", 424041f26b6SRoman Volkov .chip = "CMI8786", 425041f26b6SRoman Volkov .init = dg_init, 426041f26b6SRoman Volkov .control_filter = dg_control_filter, 427041f26b6SRoman Volkov .mixer_init = dg_mixer_init, 428041f26b6SRoman Volkov .cleanup = dg_cleanup, 429041f26b6SRoman Volkov .suspend = dg_suspend, 430041f26b6SRoman Volkov .resume = dg_resume, 431041f26b6SRoman Volkov .set_dac_params = set_cs4245_dac_params, 432041f26b6SRoman Volkov .set_adc_params = set_cs4245_adc_params, 433041f26b6SRoman Volkov .adjust_dac_routing = adjust_dg_dac_routing, 434041f26b6SRoman Volkov .dump_registers = dump_cs4245_registers, 435041f26b6SRoman Volkov .model_data_size = sizeof(struct dg), 436041f26b6SRoman Volkov .device_config = PLAYBACK_0_TO_I2S | 437041f26b6SRoman Volkov PLAYBACK_1_TO_SPDIF | 4383dd77654SRoman Volkov CAPTURE_0_FROM_I2S_1 | 439041f26b6SRoman Volkov CAPTURE_1_FROM_SPDIF, 440041f26b6SRoman Volkov .dac_channels_pcm = 6, 441041f26b6SRoman Volkov .dac_channels_mixer = 0, 442041f26b6SRoman Volkov .function_flags = OXYGEN_FUNCTION_SPI, 443041f26b6SRoman Volkov .dac_mclks = OXYGEN_MCLKS(256, 128, 128), 444041f26b6SRoman Volkov .adc_mclks = OXYGEN_MCLKS(256, 128, 128), 445041f26b6SRoman Volkov .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, 446041f26b6SRoman Volkov .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, 447041f26b6SRoman Volkov }; 448