ALSA: oxygen: Xonar DG(X): move the mixer code into another file

Moving the mixer code away makes things easier. The mixer
will control the driver, so the functions of the
driver need to be non-static.

Signed-off-by: Roman Volkov <v1ron@mail.ru>
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>

authored by Roman Volkov and committed by Clemens Ladisch 041f26b6 06f70d0d

+411 -364
+1 -1
sound/pci/oxygen/Makefile
··· 1 1 snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o 2 - snd-oxygen-objs := oxygen.o xonar_dg.o 2 + snd-oxygen-objs := oxygen.o xonar_dg_mixer.o xonar_dg.o 3 3 snd-virtuoso-objs := virtuoso.o xonar_lib.o \ 4 4 xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o 5 5
+10 -363
sound/pci/oxygen/xonar_dg.c
··· 123 123 return 0; 124 124 } 125 125 126 - static void cs4245_write(struct oxygen *chip, unsigned int reg, u8 value) 126 + void cs4245_write(struct oxygen *chip, unsigned int reg, u8 value) 127 127 { 128 128 struct dg *data = chip->model_data; 129 129 ··· 138 138 data->cs4245_shadow[reg] = value; 139 139 } 140 140 141 - static void cs4245_write_cached(struct oxygen *chip, unsigned int reg, u8 value) 141 + void cs4245_write_cached(struct oxygen *chip, unsigned int reg, u8 value) 142 142 { 143 143 struct dg *data = chip->model_data; 144 144 ··· 178 178 snd_component_add(chip->card, "CS4245"); 179 179 } 180 180 181 - static void dg_init(struct oxygen *chip) 181 + void dg_init(struct oxygen *chip) 182 182 { 183 183 struct dg *data = chip->model_data; 184 184 ··· 195 195 GPIO_OUTPUT_ENABLE | GPIO_INPUT_ROUTE); 196 196 } 197 197 198 - static void dg_cleanup(struct oxygen *chip) 198 + void dg_cleanup(struct oxygen *chip) 199 199 { 200 200 oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE); 201 201 } 202 202 203 - static void dg_suspend(struct oxygen *chip) 203 + void dg_suspend(struct oxygen *chip) 204 204 { 205 205 dg_cleanup(chip); 206 206 } 207 207 208 - static void dg_resume(struct oxygen *chip) 208 + void dg_resume(struct oxygen *chip) 209 209 { 210 210 cs4245_shadow_control(chip, CS4245_LOAD_FROM_SHADOW); 211 211 msleep(2500); 212 212 oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE); 213 213 } 214 214 215 - static void set_cs4245_dac_params(struct oxygen *chip, 215 + void set_cs4245_dac_params(struct oxygen *chip, 216 216 struct snd_pcm_hw_params *params) 217 217 { 218 218 struct dg *data = chip->model_data; ··· 237 237 cs4245_write_spi(chip, CS4245_MCLK_FREQ); 238 238 } 239 239 240 - static void set_cs4245_adc_params(struct oxygen *chip, 240 + void set_cs4245_adc_params(struct oxygen *chip, 241 241 struct snd_pcm_hw_params *params) 242 242 { 243 243 struct dg *data = chip->model_data; ··· 262 262 cs4245_write_spi(chip, CS4245_MCLK_FREQ); 263 263 } 264 264 265 - static unsigned int adjust_dg_dac_routing(struct oxygen *chip, 265 + unsigned int adjust_dg_dac_routing(struct oxygen *chip, 266 266 unsigned int play_routing) 267 267 { 268 268 struct dg *data = chip->model_data; ··· 287 287 return routing; 288 288 } 289 289 290 - static int output_switch_info(struct snd_kcontrol *ctl, 291 - struct snd_ctl_elem_info *info) 292 - { 293 - static const char *const names[3] = { 294 - "Speakers", "Headphones", "FP Headphones" 295 - }; 296 - 297 - return snd_ctl_enum_info(info, 1, 3, names); 298 - } 299 - 300 - static int output_switch_get(struct snd_kcontrol *ctl, 301 - struct snd_ctl_elem_value *value) 302 - { 303 - struct oxygen *chip = ctl->private_data; 304 - struct dg *data = chip->model_data; 305 - 306 - mutex_lock(&chip->mutex); 307 - value->value.enumerated.item[0] = data->output_sel; 308 - mutex_unlock(&chip->mutex); 309 - return 0; 310 - } 311 - 312 - static int output_switch_put(struct snd_kcontrol *ctl, 313 - struct snd_ctl_elem_value *value) 314 - { 315 - struct oxygen *chip = ctl->private_data; 316 - struct dg *data = chip->model_data; 317 - u8 reg; 318 - int changed; 319 - 320 - if (value->value.enumerated.item[0] > 2) 321 - return -EINVAL; 322 - 323 - mutex_lock(&chip->mutex); 324 - changed = value->value.enumerated.item[0] != data->output_sel; 325 - if (changed) { 326 - data->output_sel = value->value.enumerated.item[0]; 327 - 328 - reg = data->cs4245_shadow[CS4245_SIGNAL_SEL] & 329 - ~CS4245_A_OUT_SEL_MASK; 330 - reg |= data->output_sel == 2 ? 331 - CS4245_A_OUT_SEL_DAC : CS4245_A_OUT_SEL_HIZ; 332 - cs4245_write_cached(chip, CS4245_SIGNAL_SEL, reg); 333 - 334 - cs4245_write_cached(chip, CS4245_DAC_A_CTRL, 335 - data->output_sel ? data->hp_vol_att : 0); 336 - cs4245_write_cached(chip, CS4245_DAC_B_CTRL, 337 - data->output_sel ? data->hp_vol_att : 0); 338 - 339 - oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, 340 - data->output_sel == 1 ? GPIO_HP_REAR : 0, 341 - GPIO_HP_REAR); 342 - } 343 - mutex_unlock(&chip->mutex); 344 - return changed; 345 - } 346 - 347 - static int hp_volume_offset_info(struct snd_kcontrol *ctl, 348 - struct snd_ctl_elem_info *info) 349 - { 350 - static const char *const names[3] = { 351 - "< 64 ohms", "64-150 ohms", "150-300 ohms" 352 - }; 353 - 354 - return snd_ctl_enum_info(info, 1, 3, names); 355 - } 356 - 357 - static int hp_volume_offset_get(struct snd_kcontrol *ctl, 358 - struct snd_ctl_elem_value *value) 359 - { 360 - struct oxygen *chip = ctl->private_data; 361 - struct dg *data = chip->model_data; 362 - 363 - mutex_lock(&chip->mutex); 364 - if (data->hp_vol_att > 2 * 7) 365 - value->value.enumerated.item[0] = 0; 366 - else if (data->hp_vol_att > 0) 367 - value->value.enumerated.item[0] = 1; 368 - else 369 - value->value.enumerated.item[0] = 2; 370 - mutex_unlock(&chip->mutex); 371 - return 0; 372 - } 373 - 374 - static int hp_volume_offset_put(struct snd_kcontrol *ctl, 375 - struct snd_ctl_elem_value *value) 376 - { 377 - static const s8 atts[3] = { 2 * 16, 2 * 7, 0 }; 378 - struct oxygen *chip = ctl->private_data; 379 - struct dg *data = chip->model_data; 380 - s8 att; 381 - int changed; 382 - 383 - if (value->value.enumerated.item[0] > 2) 384 - return -EINVAL; 385 - att = atts[value->value.enumerated.item[0]]; 386 - mutex_lock(&chip->mutex); 387 - changed = att != data->hp_vol_att; 388 - if (changed) { 389 - data->hp_vol_att = att; 390 - if (data->output_sel) { 391 - cs4245_write_cached(chip, CS4245_DAC_A_CTRL, att); 392 - cs4245_write_cached(chip, CS4245_DAC_B_CTRL, att); 393 - } 394 - } 395 - mutex_unlock(&chip->mutex); 396 - return changed; 397 - } 398 - 399 - static int input_vol_info(struct snd_kcontrol *ctl, 400 - struct snd_ctl_elem_info *info) 401 - { 402 - info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 403 - info->count = 2; 404 - info->value.integer.min = 2 * -12; 405 - info->value.integer.max = 2 * 12; 406 - return 0; 407 - } 408 - 409 - static int input_vol_get(struct snd_kcontrol *ctl, 410 - struct snd_ctl_elem_value *value) 411 - { 412 - struct oxygen *chip = ctl->private_data; 413 - struct dg *data = chip->model_data; 414 - unsigned int idx = ctl->private_value; 415 - 416 - mutex_lock(&chip->mutex); 417 - value->value.integer.value[0] = data->input_vol[idx][0]; 418 - value->value.integer.value[1] = data->input_vol[idx][1]; 419 - mutex_unlock(&chip->mutex); 420 - return 0; 421 - } 422 - 423 - static int input_vol_put(struct snd_kcontrol *ctl, 424 - struct snd_ctl_elem_value *value) 425 - { 426 - struct oxygen *chip = ctl->private_data; 427 - struct dg *data = chip->model_data; 428 - unsigned int idx = ctl->private_value; 429 - int changed = 0; 430 - 431 - if (value->value.integer.value[0] < 2 * -12 || 432 - value->value.integer.value[0] > 2 * 12 || 433 - value->value.integer.value[1] < 2 * -12 || 434 - value->value.integer.value[1] > 2 * 12) 435 - return -EINVAL; 436 - mutex_lock(&chip->mutex); 437 - changed = data->input_vol[idx][0] != value->value.integer.value[0] || 438 - data->input_vol[idx][1] != value->value.integer.value[1]; 439 - if (changed) { 440 - data->input_vol[idx][0] = value->value.integer.value[0]; 441 - data->input_vol[idx][1] = value->value.integer.value[1]; 442 - if (idx == data->input_sel) { 443 - cs4245_write_cached(chip, CS4245_PGA_A_CTRL, 444 - data->input_vol[idx][0]); 445 - cs4245_write_cached(chip, CS4245_PGA_B_CTRL, 446 - data->input_vol[idx][1]); 447 - } 448 - } 449 - mutex_unlock(&chip->mutex); 450 - return changed; 451 - } 452 - 453 - static DECLARE_TLV_DB_SCALE(cs4245_pga_db_scale, -1200, 50, 0); 454 - 455 - static int input_sel_info(struct snd_kcontrol *ctl, 456 - struct snd_ctl_elem_info *info) 457 - { 458 - static const char *const names[4] = { 459 - "Mic", "Aux", "Front Mic", "Line" 460 - }; 461 - 462 - return snd_ctl_enum_info(info, 1, 4, names); 463 - } 464 - 465 - static int input_sel_get(struct snd_kcontrol *ctl, 466 - struct snd_ctl_elem_value *value) 467 - { 468 - struct oxygen *chip = ctl->private_data; 469 - struct dg *data = chip->model_data; 470 - 471 - mutex_lock(&chip->mutex); 472 - value->value.enumerated.item[0] = data->input_sel; 473 - mutex_unlock(&chip->mutex); 474 - return 0; 475 - } 476 - 477 - static int input_sel_put(struct snd_kcontrol *ctl, 478 - struct snd_ctl_elem_value *value) 479 - { 480 - static const u8 sel_values[4] = { 481 - CS4245_SEL_MIC, 482 - CS4245_SEL_INPUT_1, 483 - CS4245_SEL_INPUT_2, 484 - CS4245_SEL_INPUT_4 485 - }; 486 - struct oxygen *chip = ctl->private_data; 487 - struct dg *data = chip->model_data; 488 - int changed; 489 - 490 - if (value->value.enumerated.item[0] > 3) 491 - return -EINVAL; 492 - 493 - mutex_lock(&chip->mutex); 494 - changed = value->value.enumerated.item[0] != data->input_sel; 495 - if (changed) { 496 - data->input_sel = value->value.enumerated.item[0]; 497 - 498 - cs4245_write(chip, CS4245_ANALOG_IN, 499 - (data->cs4245_shadow[CS4245_ANALOG_IN] & 500 - ~CS4245_SEL_MASK) | 501 - sel_values[data->input_sel]); 502 - 503 - cs4245_write_cached(chip, CS4245_PGA_A_CTRL, 504 - data->input_vol[data->input_sel][0]); 505 - cs4245_write_cached(chip, CS4245_PGA_B_CTRL, 506 - data->input_vol[data->input_sel][1]); 507 - 508 - oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, 509 - data->input_sel ? 0 : GPIO_INPUT_ROUTE, 510 - GPIO_INPUT_ROUTE); 511 - } 512 - mutex_unlock(&chip->mutex); 513 - return changed; 514 - } 515 - 516 - static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) 517 - { 518 - static const char *const names[2] = { "Active", "Frozen" }; 519 - 520 - return snd_ctl_enum_info(info, 1, 2, names); 521 - } 522 - 523 - static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) 524 - { 525 - struct oxygen *chip = ctl->private_data; 526 - struct dg *data = chip->model_data; 527 - 528 - value->value.enumerated.item[0] = 529 - !!(data->cs4245_shadow[CS4245_ADC_CTRL] & CS4245_HPF_FREEZE); 530 - return 0; 531 - } 532 - 533 - static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) 534 - { 535 - struct oxygen *chip = ctl->private_data; 536 - struct dg *data = chip->model_data; 537 - u8 reg; 538 - int changed; 539 - 540 - mutex_lock(&chip->mutex); 541 - reg = data->cs4245_shadow[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE; 542 - if (value->value.enumerated.item[0]) 543 - reg |= CS4245_HPF_FREEZE; 544 - changed = reg != data->cs4245_shadow[CS4245_ADC_CTRL]; 545 - if (changed) 546 - cs4245_write(chip, CS4245_ADC_CTRL, reg); 547 - mutex_unlock(&chip->mutex); 548 - return changed; 549 - } 550 - 551 - #define INPUT_VOLUME(xname, index) { \ 552 - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 553 - .name = xname, \ 554 - .info = input_vol_info, \ 555 - .get = input_vol_get, \ 556 - .put = input_vol_put, \ 557 - .tlv = { .p = cs4245_pga_db_scale }, \ 558 - .private_value = index, \ 559 - } 560 - static const struct snd_kcontrol_new dg_controls[] = { 561 - { 562 - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 563 - .name = "Analog Output Playback Enum", 564 - .info = output_switch_info, 565 - .get = output_switch_get, 566 - .put = output_switch_put, 567 - }, 568 - { 569 - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 570 - .name = "Headphones Impedance Playback Enum", 571 - .info = hp_volume_offset_info, 572 - .get = hp_volume_offset_get, 573 - .put = hp_volume_offset_put, 574 - }, 575 - INPUT_VOLUME("Mic Capture Volume", 0), 576 - INPUT_VOLUME("Aux Capture Volume", 1), 577 - INPUT_VOLUME("Front Mic Capture Volume", 2), 578 - INPUT_VOLUME("Line Capture Volume", 3), 579 - { 580 - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 581 - .name = "Capture Source", 582 - .info = input_sel_info, 583 - .get = input_sel_get, 584 - .put = input_sel_put, 585 - }, 586 - { 587 - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 588 - .name = "ADC High-pass Filter Capture Enum", 589 - .info = hpf_info, 590 - .get = hpf_get, 591 - .put = hpf_put, 592 - }, 593 - }; 594 - 595 - static int dg_control_filter(struct snd_kcontrol_new *template) 596 - { 597 - if (!strncmp(template->name, "Master Playback ", 16)) 598 - return 1; 599 - return 0; 600 - } 601 - 602 - static int dg_mixer_init(struct oxygen *chip) 603 - { 604 - unsigned int i; 605 - int err; 606 - 607 - for (i = 0; i < ARRAY_SIZE(dg_controls); ++i) { 608 - err = snd_ctl_add(chip->card, 609 - snd_ctl_new1(&dg_controls[i], chip)); 610 - if (err < 0) 611 - return err; 612 - } 613 - return 0; 614 - } 615 - 616 - static void dump_cs4245_registers(struct oxygen *chip, 290 + void dump_cs4245_registers(struct oxygen *chip, 617 291 struct snd_info_buffer *buffer) 618 292 { 619 293 struct dg *data = chip->model_data; ··· 299 625 snd_iprintf(buffer, " %02x", data->cs4245_shadow[addr]); 300 626 snd_iprintf(buffer, "\n"); 301 627 } 302 - 303 - struct oxygen_model model_xonar_dg = { 304 - .longname = "C-Media Oxygen HD Audio", 305 - .chip = "CMI8786", 306 - .init = dg_init, 307 - .control_filter = dg_control_filter, 308 - .mixer_init = dg_mixer_init, 309 - .cleanup = dg_cleanup, 310 - .suspend = dg_suspend, 311 - .resume = dg_resume, 312 - .set_dac_params = set_cs4245_dac_params, 313 - .set_adc_params = set_cs4245_adc_params, 314 - .adjust_dac_routing = adjust_dg_dac_routing, 315 - .dump_registers = dump_cs4245_registers, 316 - .model_data_size = sizeof(struct dg), 317 - .device_config = PLAYBACK_0_TO_I2S | 318 - PLAYBACK_1_TO_SPDIF | 319 - CAPTURE_0_FROM_I2S_2 | 320 - CAPTURE_1_FROM_SPDIF, 321 - .dac_channels_pcm = 6, 322 - .dac_channels_mixer = 0, 323 - .function_flags = OXYGEN_FUNCTION_SPI, 324 - .dac_mclks = OXYGEN_MCLKS(256, 128, 128), 325 - .adc_mclks = OXYGEN_MCLKS(256, 128, 128), 326 - .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, 327 - .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, 328 - };
+19
sound/pci/oxygen/xonar_dg.h
··· 34 34 u8 hp_vol_att; 35 35 }; 36 36 37 + /* Xonar DG control routines */ 38 + int cs4245_write_spi(struct oxygen *chip, u8 reg); 39 + int cs4245_read_spi(struct oxygen *chip, u8 reg); 40 + int cs4245_shadow_control(struct oxygen *chip, enum cs4245_shadow_operation op); 41 + void dg_init(struct oxygen *chip); 42 + void set_cs4245_dac_params(struct oxygen *chip, 43 + struct snd_pcm_hw_params *params); 44 + void set_cs4245_adc_params(struct oxygen *chip, 45 + struct snd_pcm_hw_params *params); 46 + unsigned int adjust_dg_dac_routing(struct oxygen *chip, 47 + unsigned int play_routing); 48 + void dump_cs4245_registers(struct oxygen *chip, 49 + struct snd_info_buffer *buffer); 50 + void dg_suspend(struct oxygen *chip); 51 + void dg_resume(struct oxygen *chip); 52 + void dg_cleanup(struct oxygen *chip); 53 + void cs4245_write(struct oxygen *chip, unsigned int reg, u8 value); 54 + void cs4245_write_cached(struct oxygen *chip, unsigned int reg, u8 value); 55 + 37 56 extern struct oxygen_model model_xonar_dg; 38 57 39 58 #endif
+381
sound/pci/oxygen/xonar_dg_mixer.c
··· 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 + static int output_switch_info(struct snd_kcontrol *ctl, 31 + struct snd_ctl_elem_info *info) 32 + { 33 + static const char *const names[3] = { 34 + "Speakers", "Headphones", "FP Headphones" 35 + }; 36 + 37 + return snd_ctl_enum_info(info, 1, 3, names); 38 + } 39 + 40 + static int output_switch_get(struct snd_kcontrol *ctl, 41 + struct snd_ctl_elem_value *value) 42 + { 43 + struct oxygen *chip = ctl->private_data; 44 + struct dg *data = chip->model_data; 45 + 46 + mutex_lock(&chip->mutex); 47 + value->value.enumerated.item[0] = data->output_sel; 48 + mutex_unlock(&chip->mutex); 49 + return 0; 50 + } 51 + 52 + static int output_switch_put(struct snd_kcontrol *ctl, 53 + struct snd_ctl_elem_value *value) 54 + { 55 + struct oxygen *chip = ctl->private_data; 56 + struct dg *data = chip->model_data; 57 + u8 reg; 58 + int changed; 59 + 60 + if (value->value.enumerated.item[0] > 2) 61 + return -EINVAL; 62 + 63 + mutex_lock(&chip->mutex); 64 + changed = value->value.enumerated.item[0] != data->output_sel; 65 + if (changed) { 66 + data->output_sel = value->value.enumerated.item[0]; 67 + 68 + reg = data->cs4245_shadow[CS4245_SIGNAL_SEL] & 69 + ~CS4245_A_OUT_SEL_MASK; 70 + reg |= data->output_sel == 2 ? 71 + CS4245_A_OUT_SEL_DAC : CS4245_A_OUT_SEL_HIZ; 72 + cs4245_write_cached(chip, CS4245_SIGNAL_SEL, reg); 73 + 74 + cs4245_write_cached(chip, CS4245_DAC_A_CTRL, 75 + data->output_sel ? data->hp_vol_att : 0); 76 + cs4245_write_cached(chip, CS4245_DAC_B_CTRL, 77 + data->output_sel ? data->hp_vol_att : 0); 78 + 79 + oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, 80 + data->output_sel == 1 ? GPIO_HP_REAR : 0, 81 + GPIO_HP_REAR); 82 + } 83 + mutex_unlock(&chip->mutex); 84 + return changed; 85 + } 86 + 87 + static int hp_volume_offset_info(struct snd_kcontrol *ctl, 88 + struct snd_ctl_elem_info *info) 89 + { 90 + static const char *const names[3] = { 91 + "< 64 ohms", "64-150 ohms", "150-300 ohms" 92 + }; 93 + 94 + return snd_ctl_enum_info(info, 1, 3, names); 95 + } 96 + 97 + static int hp_volume_offset_get(struct snd_kcontrol *ctl, 98 + struct snd_ctl_elem_value *value) 99 + { 100 + struct oxygen *chip = ctl->private_data; 101 + struct dg *data = chip->model_data; 102 + 103 + mutex_lock(&chip->mutex); 104 + if (data->hp_vol_att > 2 * 7) 105 + value->value.enumerated.item[0] = 0; 106 + else if (data->hp_vol_att > 0) 107 + value->value.enumerated.item[0] = 1; 108 + else 109 + value->value.enumerated.item[0] = 2; 110 + mutex_unlock(&chip->mutex); 111 + return 0; 112 + } 113 + 114 + static int hp_volume_offset_put(struct snd_kcontrol *ctl, 115 + struct snd_ctl_elem_value *value) 116 + { 117 + static const s8 atts[3] = { 2 * 16, 2 * 7, 0 }; 118 + struct oxygen *chip = ctl->private_data; 119 + struct dg *data = chip->model_data; 120 + s8 att; 121 + int changed; 122 + 123 + if (value->value.enumerated.item[0] > 2) 124 + return -EINVAL; 125 + att = atts[value->value.enumerated.item[0]]; 126 + mutex_lock(&chip->mutex); 127 + changed = att != data->hp_vol_att; 128 + if (changed) { 129 + data->hp_vol_att = att; 130 + if (data->output_sel) { 131 + cs4245_write_cached(chip, CS4245_DAC_A_CTRL, att); 132 + cs4245_write_cached(chip, CS4245_DAC_B_CTRL, att); 133 + } 134 + } 135 + mutex_unlock(&chip->mutex); 136 + return changed; 137 + } 138 + 139 + static int input_vol_info(struct snd_kcontrol *ctl, 140 + struct snd_ctl_elem_info *info) 141 + { 142 + info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 143 + info->count = 2; 144 + info->value.integer.min = 2 * -12; 145 + info->value.integer.max = 2 * 12; 146 + return 0; 147 + } 148 + 149 + static int input_vol_get(struct snd_kcontrol *ctl, 150 + struct snd_ctl_elem_value *value) 151 + { 152 + struct oxygen *chip = ctl->private_data; 153 + struct dg *data = chip->model_data; 154 + unsigned int idx = ctl->private_value; 155 + 156 + mutex_lock(&chip->mutex); 157 + value->value.integer.value[0] = data->input_vol[idx][0]; 158 + value->value.integer.value[1] = data->input_vol[idx][1]; 159 + mutex_unlock(&chip->mutex); 160 + return 0; 161 + } 162 + 163 + static int input_vol_put(struct snd_kcontrol *ctl, 164 + struct snd_ctl_elem_value *value) 165 + { 166 + struct oxygen *chip = ctl->private_data; 167 + struct dg *data = chip->model_data; 168 + unsigned int idx = ctl->private_value; 169 + int changed = 0; 170 + 171 + if (value->value.integer.value[0] < 2 * -12 || 172 + value->value.integer.value[0] > 2 * 12 || 173 + value->value.integer.value[1] < 2 * -12 || 174 + value->value.integer.value[1] > 2 * 12) 175 + return -EINVAL; 176 + mutex_lock(&chip->mutex); 177 + changed = data->input_vol[idx][0] != value->value.integer.value[0] || 178 + data->input_vol[idx][1] != value->value.integer.value[1]; 179 + if (changed) { 180 + data->input_vol[idx][0] = value->value.integer.value[0]; 181 + data->input_vol[idx][1] = value->value.integer.value[1]; 182 + if (idx == data->input_sel) { 183 + cs4245_write_cached(chip, CS4245_PGA_A_CTRL, 184 + data->input_vol[idx][0]); 185 + cs4245_write_cached(chip, CS4245_PGA_B_CTRL, 186 + data->input_vol[idx][1]); 187 + } 188 + } 189 + mutex_unlock(&chip->mutex); 190 + return changed; 191 + } 192 + 193 + static DECLARE_TLV_DB_SCALE(cs4245_pga_db_scale, -1200, 50, 0); 194 + 195 + static int input_sel_info(struct snd_kcontrol *ctl, 196 + struct snd_ctl_elem_info *info) 197 + { 198 + static const char *const names[4] = { 199 + "Mic", "Aux", "Front Mic", "Line" 200 + }; 201 + 202 + return snd_ctl_enum_info(info, 1, 4, names); 203 + } 204 + 205 + static int input_sel_get(struct snd_kcontrol *ctl, 206 + struct snd_ctl_elem_value *value) 207 + { 208 + struct oxygen *chip = ctl->private_data; 209 + struct dg *data = chip->model_data; 210 + 211 + mutex_lock(&chip->mutex); 212 + value->value.enumerated.item[0] = data->input_sel; 213 + mutex_unlock(&chip->mutex); 214 + return 0; 215 + } 216 + 217 + static int input_sel_put(struct snd_kcontrol *ctl, 218 + struct snd_ctl_elem_value *value) 219 + { 220 + static const u8 sel_values[4] = { 221 + CS4245_SEL_MIC, 222 + CS4245_SEL_INPUT_1, 223 + CS4245_SEL_INPUT_2, 224 + CS4245_SEL_INPUT_4 225 + }; 226 + struct oxygen *chip = ctl->private_data; 227 + struct dg *data = chip->model_data; 228 + int changed; 229 + 230 + if (value->value.enumerated.item[0] > 3) 231 + return -EINVAL; 232 + 233 + mutex_lock(&chip->mutex); 234 + changed = value->value.enumerated.item[0] != data->input_sel; 235 + if (changed) { 236 + data->input_sel = value->value.enumerated.item[0]; 237 + 238 + cs4245_write(chip, CS4245_ANALOG_IN, 239 + (data->cs4245_shadow[CS4245_ANALOG_IN] & 240 + ~CS4245_SEL_MASK) | 241 + sel_values[data->input_sel]); 242 + 243 + cs4245_write_cached(chip, CS4245_PGA_A_CTRL, 244 + data->input_vol[data->input_sel][0]); 245 + cs4245_write_cached(chip, CS4245_PGA_B_CTRL, 246 + data->input_vol[data->input_sel][1]); 247 + 248 + oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, 249 + data->input_sel ? 0 : GPIO_INPUT_ROUTE, 250 + GPIO_INPUT_ROUTE); 251 + } 252 + mutex_unlock(&chip->mutex); 253 + return changed; 254 + } 255 + 256 + static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) 257 + { 258 + static const char *const names[2] = { "Active", "Frozen" }; 259 + 260 + return snd_ctl_enum_info(info, 1, 2, names); 261 + } 262 + 263 + static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) 264 + { 265 + struct oxygen *chip = ctl->private_data; 266 + struct dg *data = chip->model_data; 267 + 268 + value->value.enumerated.item[0] = 269 + !!(data->cs4245_shadow[CS4245_ADC_CTRL] & CS4245_HPF_FREEZE); 270 + return 0; 271 + } 272 + 273 + static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) 274 + { 275 + struct oxygen *chip = ctl->private_data; 276 + struct dg *data = chip->model_data; 277 + u8 reg; 278 + int changed; 279 + 280 + mutex_lock(&chip->mutex); 281 + reg = data->cs4245_shadow[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE; 282 + if (value->value.enumerated.item[0]) 283 + reg |= CS4245_HPF_FREEZE; 284 + changed = reg != data->cs4245_shadow[CS4245_ADC_CTRL]; 285 + if (changed) 286 + cs4245_write(chip, CS4245_ADC_CTRL, reg); 287 + mutex_unlock(&chip->mutex); 288 + return changed; 289 + } 290 + 291 + #define INPUT_VOLUME(xname, index) { \ 292 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 293 + .name = xname, \ 294 + .info = input_vol_info, \ 295 + .get = input_vol_get, \ 296 + .put = input_vol_put, \ 297 + .tlv = { .p = cs4245_pga_db_scale }, \ 298 + .private_value = index, \ 299 + } 300 + static const struct snd_kcontrol_new dg_controls[] = { 301 + { 302 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 303 + .name = "Analog Output Playback Enum", 304 + .info = output_switch_info, 305 + .get = output_switch_get, 306 + .put = output_switch_put, 307 + }, 308 + { 309 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 310 + .name = "Headphones Impedance Playback Enum", 311 + .info = hp_volume_offset_info, 312 + .get = hp_volume_offset_get, 313 + .put = hp_volume_offset_put, 314 + }, 315 + INPUT_VOLUME("Mic Capture Volume", 0), 316 + INPUT_VOLUME("Aux Capture Volume", 1), 317 + INPUT_VOLUME("Front Mic Capture Volume", 2), 318 + INPUT_VOLUME("Line Capture Volume", 3), 319 + { 320 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 321 + .name = "Capture Source", 322 + .info = input_sel_info, 323 + .get = input_sel_get, 324 + .put = input_sel_put, 325 + }, 326 + { 327 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 328 + .name = "ADC High-pass Filter Capture Enum", 329 + .info = hpf_info, 330 + .get = hpf_get, 331 + .put = hpf_put, 332 + }, 333 + }; 334 + 335 + static int dg_control_filter(struct snd_kcontrol_new *template) 336 + { 337 + if (!strncmp(template->name, "Master Playback ", 16)) 338 + return 1; 339 + return 0; 340 + } 341 + 342 + static int dg_mixer_init(struct oxygen *chip) 343 + { 344 + unsigned int i; 345 + int err; 346 + 347 + for (i = 0; i < ARRAY_SIZE(dg_controls); ++i) { 348 + err = snd_ctl_add(chip->card, 349 + snd_ctl_new1(&dg_controls[i], chip)); 350 + if (err < 0) 351 + return err; 352 + } 353 + return 0; 354 + } 355 + 356 + struct oxygen_model model_xonar_dg = { 357 + .longname = "C-Media Oxygen HD Audio", 358 + .chip = "CMI8786", 359 + .init = dg_init, 360 + .control_filter = dg_control_filter, 361 + .mixer_init = dg_mixer_init, 362 + .cleanup = dg_cleanup, 363 + .suspend = dg_suspend, 364 + .resume = dg_resume, 365 + .set_dac_params = set_cs4245_dac_params, 366 + .set_adc_params = set_cs4245_adc_params, 367 + .adjust_dac_routing = adjust_dg_dac_routing, 368 + .dump_registers = dump_cs4245_registers, 369 + .model_data_size = sizeof(struct dg), 370 + .device_config = PLAYBACK_0_TO_I2S | 371 + PLAYBACK_1_TO_SPDIF | 372 + CAPTURE_0_FROM_I2S_2 | 373 + CAPTURE_1_FROM_SPDIF, 374 + .dac_channels_pcm = 6, 375 + .dac_channels_mixer = 0, 376 + .function_flags = OXYGEN_FUNCTION_SPI, 377 + .dac_mclks = OXYGEN_MCLKS(256, 128, 128), 378 + .adc_mclks = OXYGEN_MCLKS(256, 128, 128), 379 + .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, 380 + .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, 381 + };