1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Mixer controls for the Xonar DG/DGX 4 * 5 * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 6 * Copyright (c) Roman Volkov <v1ron@mail.ru> 7 */ 8 9 #include <linux/pci.h> 10 #include <linux/delay.h> 11 #include <sound/control.h> 12 #include <sound/core.h> 13 #include <sound/info.h> 14 #include <sound/pcm.h> 15 #include <sound/tlv.h> 16 #include "oxygen.h" 17 #include "xonar_dg.h" 18 #include "cs4245.h" 19 20 /* analog output select */ 21 22 static int output_select_apply(struct oxygen *chip) 23 { 24 struct dg *data = chip->model_data; 25 26 data->cs4245_shadow[CS4245_SIGNAL_SEL] &= ~CS4245_A_OUT_SEL_MASK; 27 if (data->output_sel == PLAYBACK_DST_HP) { 28 /* mute FP (aux output) amplifier, switch rear jack to CS4245 */ 29 oxygen_set_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR); 30 } else if (data->output_sel == PLAYBACK_DST_HP_FP) { 31 /* 32 * Unmute FP amplifier, switch rear jack to CS4361; 33 * I2S channels 2,3,4 should be inactive. 34 */ 35 oxygen_clear_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR); 36 data->cs4245_shadow[CS4245_SIGNAL_SEL] |= CS4245_A_OUT_SEL_DAC; 37 } else { 38 /* 39 * 2.0, 4.0, 5.1: switch to CS4361, mute FP amp., 40 * and change playback routing. 41 */ 42 oxygen_clear_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR); 43 } 44 return cs4245_write_spi(chip, CS4245_SIGNAL_SEL); 45 } 46 47 static int output_select_info(struct snd_kcontrol *ctl, 48 struct snd_ctl_elem_info *info) 49 { 50 static const char *const names[3] = { 51 "Stereo Headphones", 52 "Stereo Headphones FP", 53 "Multichannel", 54 }; 55 56 return snd_ctl_enum_info(info, 1, 3, names); 57 } 58 59 static int output_select_get(struct snd_kcontrol *ctl, 60 struct snd_ctl_elem_value *value) 61 { 62 struct oxygen *chip = ctl->private_data; 63 struct dg *data = chip->model_data; 64 65 guard(mutex)(&chip->mutex); 66 value->value.enumerated.item[0] = data->output_sel; 67 return 0; 68 } 69 70 static int output_select_put(struct snd_kcontrol *ctl, 71 struct snd_ctl_elem_value *value) 72 { 73 struct oxygen *chip = ctl->private_data; 74 struct dg *data = chip->model_data; 75 unsigned int new = value->value.enumerated.item[0]; 76 int changed = 0; 77 int ret; 78 79 guard(mutex)(&chip->mutex); 80 if (data->output_sel != new) { 81 data->output_sel = new; 82 ret = output_select_apply(chip); 83 changed = ret >= 0 ? 1 : ret; 84 oxygen_update_dac_routing(chip); 85 } 86 87 return changed; 88 } 89 90 /* CS4245 Headphone Channels A&B Volume Control */ 91 92 static int hp_stereo_volume_info(struct snd_kcontrol *ctl, 93 struct snd_ctl_elem_info *info) 94 { 95 info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 96 info->count = 2; 97 info->value.integer.min = 0; 98 info->value.integer.max = 255; 99 return 0; 100 } 101 102 static int hp_stereo_volume_get(struct snd_kcontrol *ctl, 103 struct snd_ctl_elem_value *val) 104 { 105 struct oxygen *chip = ctl->private_data; 106 struct dg *data = chip->model_data; 107 unsigned int tmp; 108 109 guard(mutex)(&chip->mutex); 110 tmp = (~data->cs4245_shadow[CS4245_DAC_A_CTRL]) & 255; 111 val->value.integer.value[0] = tmp; 112 tmp = (~data->cs4245_shadow[CS4245_DAC_B_CTRL]) & 255; 113 val->value.integer.value[1] = tmp; 114 return 0; 115 } 116 117 static int hp_stereo_volume_put(struct snd_kcontrol *ctl, 118 struct snd_ctl_elem_value *val) 119 { 120 struct oxygen *chip = ctl->private_data; 121 struct dg *data = chip->model_data; 122 int ret; 123 int changed = 0; 124 long new1 = val->value.integer.value[0]; 125 long new2 = val->value.integer.value[1]; 126 127 if ((new1 > 255) || (new1 < 0) || (new2 > 255) || (new2 < 0)) 128 return -EINVAL; 129 130 guard(mutex)(&chip->mutex); 131 if ((data->cs4245_shadow[CS4245_DAC_A_CTRL] != ~new1) || 132 (data->cs4245_shadow[CS4245_DAC_B_CTRL] != ~new2)) { 133 data->cs4245_shadow[CS4245_DAC_A_CTRL] = ~new1; 134 data->cs4245_shadow[CS4245_DAC_B_CTRL] = ~new2; 135 ret = cs4245_write_spi(chip, CS4245_DAC_A_CTRL); 136 if (ret >= 0) 137 ret = cs4245_write_spi(chip, CS4245_DAC_B_CTRL); 138 changed = ret >= 0 ? 1 : ret; 139 } 140 141 return changed; 142 } 143 144 /* Headphone Mute */ 145 146 static int hp_mute_get(struct snd_kcontrol *ctl, 147 struct snd_ctl_elem_value *val) 148 { 149 struct oxygen *chip = ctl->private_data; 150 struct dg *data = chip->model_data; 151 152 guard(mutex)(&chip->mutex); 153 val->value.integer.value[0] = 154 !(data->cs4245_shadow[CS4245_DAC_CTRL_1] & CS4245_MUTE_DAC); 155 return 0; 156 } 157 158 static int hp_mute_put(struct snd_kcontrol *ctl, 159 struct snd_ctl_elem_value *val) 160 { 161 struct oxygen *chip = ctl->private_data; 162 struct dg *data = chip->model_data; 163 int ret; 164 int changed; 165 166 if (val->value.integer.value[0] > 1) 167 return -EINVAL; 168 guard(mutex)(&chip->mutex); 169 data->cs4245_shadow[CS4245_DAC_CTRL_1] &= ~CS4245_MUTE_DAC; 170 data->cs4245_shadow[CS4245_DAC_CTRL_1] |= 171 (~val->value.integer.value[0] << 2) & CS4245_MUTE_DAC; 172 ret = cs4245_write_spi(chip, CS4245_DAC_CTRL_1); 173 changed = ret >= 0 ? 1 : ret; 174 return changed; 175 } 176 177 /* capture volume for all sources */ 178 179 static int input_volume_apply(struct oxygen *chip, char left, char right) 180 { 181 struct dg *data = chip->model_data; 182 int ret; 183 184 data->cs4245_shadow[CS4245_PGA_A_CTRL] = left; 185 data->cs4245_shadow[CS4245_PGA_B_CTRL] = right; 186 ret = cs4245_write_spi(chip, CS4245_PGA_A_CTRL); 187 if (ret < 0) 188 return ret; 189 return cs4245_write_spi(chip, CS4245_PGA_B_CTRL); 190 } 191 192 static int input_vol_info(struct snd_kcontrol *ctl, 193 struct snd_ctl_elem_info *info) 194 { 195 info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 196 info->count = 2; 197 info->value.integer.min = 2 * -12; 198 info->value.integer.max = 2 * 12; 199 return 0; 200 } 201 202 static int input_vol_get(struct snd_kcontrol *ctl, 203 struct snd_ctl_elem_value *value) 204 { 205 struct oxygen *chip = ctl->private_data; 206 struct dg *data = chip->model_data; 207 unsigned int idx = ctl->private_value; 208 209 guard(mutex)(&chip->mutex); 210 value->value.integer.value[0] = data->input_vol[idx][0]; 211 value->value.integer.value[1] = data->input_vol[idx][1]; 212 return 0; 213 } 214 215 static int input_vol_put(struct snd_kcontrol *ctl, 216 struct snd_ctl_elem_value *value) 217 { 218 struct oxygen *chip = ctl->private_data; 219 struct dg *data = chip->model_data; 220 unsigned int idx = ctl->private_value; 221 int changed = 0; 222 int ret = 0; 223 224 if (value->value.integer.value[0] < 2 * -12 || 225 value->value.integer.value[0] > 2 * 12 || 226 value->value.integer.value[1] < 2 * -12 || 227 value->value.integer.value[1] > 2 * 12) 228 return -EINVAL; 229 guard(mutex)(&chip->mutex); 230 changed = data->input_vol[idx][0] != value->value.integer.value[0] || 231 data->input_vol[idx][1] != value->value.integer.value[1]; 232 if (changed) { 233 data->input_vol[idx][0] = value->value.integer.value[0]; 234 data->input_vol[idx][1] = value->value.integer.value[1]; 235 if (idx == data->input_sel) { 236 ret = input_volume_apply(chip, 237 data->input_vol[idx][0], 238 data->input_vol[idx][1]); 239 } 240 changed = ret >= 0 ? 1 : ret; 241 } 242 return changed; 243 } 244 245 /* Capture Source */ 246 247 static int input_source_apply(struct oxygen *chip) 248 { 249 struct dg *data = chip->model_data; 250 251 data->cs4245_shadow[CS4245_ANALOG_IN] &= ~CS4245_SEL_MASK; 252 if (data->input_sel == CAPTURE_SRC_FP_MIC) 253 data->cs4245_shadow[CS4245_ANALOG_IN] |= CS4245_SEL_INPUT_2; 254 else if (data->input_sel == CAPTURE_SRC_LINE) 255 data->cs4245_shadow[CS4245_ANALOG_IN] |= CS4245_SEL_INPUT_4; 256 else if (data->input_sel != CAPTURE_SRC_MIC) 257 data->cs4245_shadow[CS4245_ANALOG_IN] |= CS4245_SEL_INPUT_1; 258 return cs4245_write_spi(chip, CS4245_ANALOG_IN); 259 } 260 261 static int input_sel_info(struct snd_kcontrol *ctl, 262 struct snd_ctl_elem_info *info) 263 { 264 static const char *const names[4] = { 265 "Mic", "Front Mic", "Line", "Aux" 266 }; 267 268 return snd_ctl_enum_info(info, 1, 4, names); 269 } 270 271 static int input_sel_get(struct snd_kcontrol *ctl, 272 struct snd_ctl_elem_value *value) 273 { 274 struct oxygen *chip = ctl->private_data; 275 struct dg *data = chip->model_data; 276 277 guard(mutex)(&chip->mutex); 278 value->value.enumerated.item[0] = data->input_sel; 279 return 0; 280 } 281 282 static int input_sel_put(struct snd_kcontrol *ctl, 283 struct snd_ctl_elem_value *value) 284 { 285 struct oxygen *chip = ctl->private_data; 286 struct dg *data = chip->model_data; 287 int changed; 288 int ret; 289 290 if (value->value.enumerated.item[0] > 3) 291 return -EINVAL; 292 293 guard(mutex)(&chip->mutex); 294 changed = value->value.enumerated.item[0] != data->input_sel; 295 if (changed) { 296 data->input_sel = value->value.enumerated.item[0]; 297 298 ret = input_source_apply(chip); 299 if (ret >= 0) 300 ret = input_volume_apply(chip, 301 data->input_vol[data->input_sel][0], 302 data->input_vol[data->input_sel][1]); 303 changed = ret >= 0 ? 1 : ret; 304 } 305 return changed; 306 } 307 308 /* ADC high-pass filter */ 309 310 static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) 311 { 312 static const char *const names[2] = { "Active", "Frozen" }; 313 314 return snd_ctl_enum_info(info, 1, 2, names); 315 } 316 317 static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) 318 { 319 struct oxygen *chip = ctl->private_data; 320 struct dg *data = chip->model_data; 321 322 value->value.enumerated.item[0] = 323 !!(data->cs4245_shadow[CS4245_ADC_CTRL] & CS4245_HPF_FREEZE); 324 return 0; 325 } 326 327 static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) 328 { 329 struct oxygen *chip = ctl->private_data; 330 struct dg *data = chip->model_data; 331 u8 reg; 332 int changed; 333 334 guard(mutex)(&chip->mutex); 335 reg = data->cs4245_shadow[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE; 336 if (value->value.enumerated.item[0]) 337 reg |= CS4245_HPF_FREEZE; 338 changed = reg != data->cs4245_shadow[CS4245_ADC_CTRL]; 339 if (changed) { 340 data->cs4245_shadow[CS4245_ADC_CTRL] = reg; 341 cs4245_write_spi(chip, CS4245_ADC_CTRL); 342 } 343 return changed; 344 } 345 346 #define INPUT_VOLUME(xname, index) { \ 347 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 348 .name = xname, \ 349 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ 350 SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ 351 .info = input_vol_info, \ 352 .get = input_vol_get, \ 353 .put = input_vol_put, \ 354 .tlv = { .p = pga_db_scale }, \ 355 .private_value = index, \ 356 } 357 static const DECLARE_TLV_DB_MINMAX(hp_db_scale, -12550, 0); 358 static const DECLARE_TLV_DB_MINMAX(pga_db_scale, -1200, 1200); 359 static const struct snd_kcontrol_new dg_controls[] = { 360 { 361 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 362 .name = "Analog Output Playback Enum", 363 .info = output_select_info, 364 .get = output_select_get, 365 .put = output_select_put, 366 }, 367 { 368 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 369 .name = "Headphone Playback Volume", 370 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 371 SNDRV_CTL_ELEM_ACCESS_TLV_READ, 372 .info = hp_stereo_volume_info, 373 .get = hp_stereo_volume_get, 374 .put = hp_stereo_volume_put, 375 .tlv = { .p = hp_db_scale, }, 376 }, 377 { 378 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 379 .name = "Headphone Playback Switch", 380 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 381 .info = snd_ctl_boolean_mono_info, 382 .get = hp_mute_get, 383 .put = hp_mute_put, 384 }, 385 INPUT_VOLUME("Mic Capture Volume", CAPTURE_SRC_MIC), 386 INPUT_VOLUME("Front Mic Capture Volume", CAPTURE_SRC_FP_MIC), 387 INPUT_VOLUME("Line Capture Volume", CAPTURE_SRC_LINE), 388 INPUT_VOLUME("Aux Capture Volume", CAPTURE_SRC_AUX), 389 { 390 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 391 .name = "Capture Source", 392 .info = input_sel_info, 393 .get = input_sel_get, 394 .put = input_sel_put, 395 }, 396 { 397 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 398 .name = "ADC High-pass Filter Capture Enum", 399 .info = hpf_info, 400 .get = hpf_get, 401 .put = hpf_put, 402 }, 403 }; 404 405 static int dg_control_filter(struct snd_kcontrol_new *template) 406 { 407 if (!strncmp(template->name, "Master Playback ", 16)) 408 return 1; 409 return 0; 410 } 411 412 static int dg_mixer_init(struct oxygen *chip) 413 { 414 unsigned int i; 415 int err; 416 417 output_select_apply(chip); 418 input_source_apply(chip); 419 oxygen_update_dac_routing(chip); 420 421 for (i = 0; i < ARRAY_SIZE(dg_controls); ++i) { 422 err = snd_ctl_add(chip->card, 423 snd_ctl_new1(&dg_controls[i], chip)); 424 if (err < 0) 425 return err; 426 } 427 428 return 0; 429 } 430 431 const struct oxygen_model model_xonar_dg = { 432 .longname = "C-Media Oxygen HD Audio", 433 .chip = "CMI8786", 434 .init = dg_init, 435 .control_filter = dg_control_filter, 436 .mixer_init = dg_mixer_init, 437 .cleanup = dg_cleanup, 438 .suspend = dg_suspend, 439 .resume = dg_resume, 440 .set_dac_params = set_cs4245_dac_params, 441 .set_adc_params = set_cs4245_adc_params, 442 .adjust_dac_routing = adjust_dg_dac_routing, 443 .dump_registers = dump_cs4245_registers, 444 .model_data_size = sizeof(struct dg), 445 .device_config = PLAYBACK_0_TO_I2S | 446 PLAYBACK_1_TO_SPDIF | 447 CAPTURE_0_FROM_I2S_1 | 448 CAPTURE_1_FROM_SPDIF, 449 .dac_channels_pcm = 6, 450 .dac_channels_mixer = 0, 451 .function_flags = OXYGEN_FUNCTION_SPI, 452 .dac_mclks = OXYGEN_MCLKS(256, 128, 128), 453 .adc_mclks = OXYGEN_MCLKS(256, 128, 128), 454 .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, 455 .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, 456 }; 457