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 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 3 snd-virtuoso-objs := virtuoso.o xonar_lib.o \ 4 xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o 5
··· 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_mixer.o xonar_dg.o 3 snd-virtuoso-objs := virtuoso.o xonar_lib.o \ 4 xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o 5
+10 -363
sound/pci/oxygen/xonar_dg.c
··· 123 return 0; 124 } 125 126 - static void cs4245_write(struct oxygen *chip, unsigned int reg, u8 value) 127 { 128 struct dg *data = chip->model_data; 129 ··· 138 data->cs4245_shadow[reg] = value; 139 } 140 141 - static void cs4245_write_cached(struct oxygen *chip, unsigned int reg, u8 value) 142 { 143 struct dg *data = chip->model_data; 144 ··· 178 snd_component_add(chip->card, "CS4245"); 179 } 180 181 - static void dg_init(struct oxygen *chip) 182 { 183 struct dg *data = chip->model_data; 184 ··· 195 GPIO_OUTPUT_ENABLE | GPIO_INPUT_ROUTE); 196 } 197 198 - static void dg_cleanup(struct oxygen *chip) 199 { 200 oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE); 201 } 202 203 - static void dg_suspend(struct oxygen *chip) 204 { 205 dg_cleanup(chip); 206 } 207 208 - static void dg_resume(struct oxygen *chip) 209 { 210 cs4245_shadow_control(chip, CS4245_LOAD_FROM_SHADOW); 211 msleep(2500); 212 oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE); 213 } 214 215 - static void set_cs4245_dac_params(struct oxygen *chip, 216 struct snd_pcm_hw_params *params) 217 { 218 struct dg *data = chip->model_data; ··· 237 cs4245_write_spi(chip, CS4245_MCLK_FREQ); 238 } 239 240 - static void set_cs4245_adc_params(struct oxygen *chip, 241 struct snd_pcm_hw_params *params) 242 { 243 struct dg *data = chip->model_data; ··· 262 cs4245_write_spi(chip, CS4245_MCLK_FREQ); 263 } 264 265 - static unsigned int adjust_dg_dac_routing(struct oxygen *chip, 266 unsigned int play_routing) 267 { 268 struct dg *data = chip->model_data; ··· 287 return routing; 288 } 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, 617 struct snd_info_buffer *buffer) 618 { 619 struct dg *data = chip->model_data; ··· 299 snd_iprintf(buffer, " %02x", data->cs4245_shadow[addr]); 300 snd_iprintf(buffer, "\n"); 301 } 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 - };
··· 123 return 0; 124 } 125 126 + void cs4245_write(struct oxygen *chip, unsigned int reg, u8 value) 127 { 128 struct dg *data = chip->model_data; 129 ··· 138 data->cs4245_shadow[reg] = value; 139 } 140 141 + void cs4245_write_cached(struct oxygen *chip, unsigned int reg, u8 value) 142 { 143 struct dg *data = chip->model_data; 144 ··· 178 snd_component_add(chip->card, "CS4245"); 179 } 180 181 + void dg_init(struct oxygen *chip) 182 { 183 struct dg *data = chip->model_data; 184 ··· 195 GPIO_OUTPUT_ENABLE | GPIO_INPUT_ROUTE); 196 } 197 198 + void dg_cleanup(struct oxygen *chip) 199 { 200 oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE); 201 } 202 203 + void dg_suspend(struct oxygen *chip) 204 { 205 dg_cleanup(chip); 206 } 207 208 + void dg_resume(struct oxygen *chip) 209 { 210 cs4245_shadow_control(chip, CS4245_LOAD_FROM_SHADOW); 211 msleep(2500); 212 oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE); 213 } 214 215 + void set_cs4245_dac_params(struct oxygen *chip, 216 struct snd_pcm_hw_params *params) 217 { 218 struct dg *data = chip->model_data; ··· 237 cs4245_write_spi(chip, CS4245_MCLK_FREQ); 238 } 239 240 + void set_cs4245_adc_params(struct oxygen *chip, 241 struct snd_pcm_hw_params *params) 242 { 243 struct dg *data = chip->model_data; ··· 262 cs4245_write_spi(chip, CS4245_MCLK_FREQ); 263 } 264 265 + unsigned int adjust_dg_dac_routing(struct oxygen *chip, 266 unsigned int play_routing) 267 { 268 struct dg *data = chip->model_data; ··· 287 return routing; 288 } 289 290 + void dump_cs4245_registers(struct oxygen *chip, 291 struct snd_info_buffer *buffer) 292 { 293 struct dg *data = chip->model_data; ··· 625 snd_iprintf(buffer, " %02x", data->cs4245_shadow[addr]); 626 snd_iprintf(buffer, "\n"); 627 }
+19
sound/pci/oxygen/xonar_dg.h
··· 34 u8 hp_vol_att; 35 }; 36 37 extern struct oxygen_model model_xonar_dg; 38 39 #endif
··· 34 u8 hp_vol_att; 35 }; 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 + 56 extern struct oxygen_model model_xonar_dg; 57 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 + };