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