diff options
| author | Clemens Ladisch <clemens@ladisch.de> | 2009-09-28 05:20:47 -0400 |
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2009-09-28 05:54:52 -0400 |
| commit | 973dca93a3d46cca7e4743300f8a510b779906af (patch) | |
| tree | 35ecad5f3d2f5453aff442471d5b1b88e1b0aa98 | |
| parent | 76ffe1e3fb2f65e98d7ed001c5a2b6f334655364 (diff) | |
sound: virtuoso: add PCM1796 oversampling control
Add a control to increase the oversampling factor to 128x on cards with
PCM1796 or PCM1792A DACs.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
| -rw-r--r-- | sound/pci/oxygen/xonar_pcm179x.c | 182 |
1 files changed, 157 insertions, 25 deletions
diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index 35b3fb4071fb..7f153fb1848d 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c | |||
| @@ -173,8 +173,11 @@ struct xonar_pcm179x { | |||
| 173 | struct xonar_generic generic; | 173 | struct xonar_generic generic; |
| 174 | unsigned int dacs; | 174 | unsigned int dacs; |
| 175 | u8 pcm1796_regs[4][5]; | 175 | u8 pcm1796_regs[4][5]; |
| 176 | unsigned int current_rate; | ||
| 177 | bool os_128; | ||
| 176 | bool hp_active; | 178 | bool hp_active; |
| 177 | s8 hp_gain_offset; | 179 | s8 hp_gain_offset; |
| 180 | bool has_cs2000; | ||
| 178 | u8 cs2000_fun_cfg_1; | 181 | u8 cs2000_fun_cfg_1; |
| 179 | }; | 182 | }; |
| 180 | 183 | ||
| @@ -277,6 +280,7 @@ static void pcm1796_init(struct oxygen *chip) | |||
| 277 | PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD; | 280 | PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD; |
| 278 | data->pcm1796_regs[0][20 - PCM1796_REG_BASE] = PCM1796_OS_64; | 281 | data->pcm1796_regs[0][20 - PCM1796_REG_BASE] = PCM1796_OS_64; |
| 279 | pcm1796_registers_init(chip); | 282 | pcm1796_registers_init(chip); |
| 283 | data->current_rate = 48000; | ||
| 280 | } | 284 | } |
| 281 | 285 | ||
| 282 | static void xonar_d2_init(struct oxygen *chip) | 286 | static void xonar_d2_init(struct oxygen *chip) |
| @@ -401,6 +405,7 @@ static void xonar_st_init(struct oxygen *chip) | |||
| 401 | { | 405 | { |
| 402 | struct xonar_pcm179x *data = chip->model_data; | 406 | struct xonar_pcm179x *data = chip->model_data; |
| 403 | 407 | ||
| 408 | data->has_cs2000 = 1; | ||
| 404 | data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1; | 409 | data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1; |
| 405 | 410 | ||
| 406 | oxygen_write16(chip, OXYGEN_I2S_A_FORMAT, | 411 | oxygen_write16(chip, OXYGEN_I2S_A_FORMAT, |
| @@ -486,18 +491,57 @@ static void xonar_st_resume(struct oxygen *chip) | |||
| 486 | xonar_stx_resume(chip); | 491 | xonar_stx_resume(chip); |
| 487 | } | 492 | } |
| 488 | 493 | ||
| 489 | static void set_pcm1796_params(struct oxygen *chip, | 494 | static unsigned int mclk_from_rate(struct oxygen *chip, unsigned int rate) |
| 490 | struct snd_pcm_hw_params *params) | 495 | { |
| 496 | struct xonar_pcm179x *data = chip->model_data; | ||
| 497 | |||
| 498 | if (rate <= 32000) | ||
| 499 | return OXYGEN_I2S_MCLK_512; | ||
| 500 | else if (rate <= 48000 && data->os_128) | ||
| 501 | return OXYGEN_I2S_MCLK_512; | ||
| 502 | else if (rate <= 96000) | ||
| 503 | return OXYGEN_I2S_MCLK_256; | ||
| 504 | else | ||
| 505 | return OXYGEN_I2S_MCLK_128; | ||
| 506 | } | ||
| 507 | |||
| 508 | static unsigned int get_pcm1796_i2s_mclk(struct oxygen *chip, | ||
| 509 | unsigned int channel, | ||
| 510 | struct snd_pcm_hw_params *params) | ||
| 511 | { | ||
| 512 | if (channel == PCM_MULTICH) | ||
| 513 | return mclk_from_rate(chip, params_rate(params)); | ||
| 514 | else | ||
| 515 | return oxygen_default_i2s_mclk(chip, channel, params); | ||
| 516 | } | ||
| 517 | |||
| 518 | static void update_pcm1796_oversampling(struct oxygen *chip) | ||
| 491 | { | 519 | { |
| 492 | struct xonar_pcm179x *data = chip->model_data; | 520 | struct xonar_pcm179x *data = chip->model_data; |
| 493 | unsigned int i; | 521 | unsigned int i; |
| 494 | u8 reg; | 522 | u8 reg; |
| 495 | 523 | ||
| 496 | reg = params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64; | 524 | if (data->current_rate <= 32000) |
| 525 | reg = PCM1796_OS_128; | ||
| 526 | else if (data->current_rate <= 48000 && data->os_128) | ||
| 527 | reg = PCM1796_OS_128; | ||
| 528 | else if (data->current_rate <= 96000 || data->os_128) | ||
| 529 | reg = PCM1796_OS_64; | ||
| 530 | else | ||
| 531 | reg = PCM1796_OS_32; | ||
| 497 | for (i = 0; i < data->dacs; ++i) | 532 | for (i = 0; i < data->dacs; ++i) |
| 498 | pcm1796_write_cached(chip, i, 20, reg); | 533 | pcm1796_write_cached(chip, i, 20, reg); |
| 499 | } | 534 | } |
| 500 | 535 | ||
| 536 | static void set_pcm1796_params(struct oxygen *chip, | ||
| 537 | struct snd_pcm_hw_params *params) | ||
| 538 | { | ||
| 539 | struct xonar_pcm179x *data = chip->model_data; | ||
| 540 | |||
| 541 | data->current_rate = params_rate(params); | ||
| 542 | update_pcm1796_oversampling(chip); | ||
| 543 | } | ||
| 544 | |||
| 501 | static void update_pcm1796_volume(struct oxygen *chip) | 545 | static void update_pcm1796_volume(struct oxygen *chip) |
| 502 | { | 546 | { |
| 503 | struct xonar_pcm179x *data = chip->model_data; | 547 | struct xonar_pcm179x *data = chip->model_data; |
| @@ -526,26 +570,44 @@ static void update_pcm1796_mute(struct oxygen *chip) | |||
| 526 | pcm1796_write_cached(chip, i, 18, value); | 570 | pcm1796_write_cached(chip, i, 18, value); |
| 527 | } | 571 | } |
| 528 | 572 | ||
| 529 | static void set_cs2000_params(struct oxygen *chip, | 573 | static void update_cs2000_rate(struct oxygen *chip, unsigned int rate) |
| 530 | struct snd_pcm_hw_params *params) | ||
| 531 | { | 574 | { |
| 532 | /* XXX Why is the I2S A MCLK half the actual I2S multich MCLK? */ | 575 | struct xonar_pcm179x *data = chip->model_data; |
| 533 | static const u8 rate_mclks[] = { | ||
| 534 | [OXYGEN_RATE_32000] = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_128, | ||
| 535 | [OXYGEN_RATE_44100] = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_128, | ||
| 536 | [OXYGEN_RATE_48000] = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_128, | ||
| 537 | [OXYGEN_RATE_64000] = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256, | ||
| 538 | [OXYGEN_RATE_88200] = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256, | ||
| 539 | [OXYGEN_RATE_96000] = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256, | ||
| 540 | [OXYGEN_RATE_176400] = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256, | ||
| 541 | [OXYGEN_RATE_192000] = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256, | ||
| 542 | }; | ||
| 543 | unsigned int rate_index; | ||
| 544 | u8 rate_mclk, reg; | 576 | u8 rate_mclk, reg; |
| 545 | 577 | ||
| 546 | rate_index = oxygen_read16(chip, OXYGEN_I2S_MULTICH_FORMAT) | 578 | switch (rate) { |
| 547 | & OXYGEN_I2S_RATE_MASK; | 579 | /* XXX Why is the I2S A MCLK half the actual I2S MCLK? */ |
| 548 | rate_mclk = rate_mclks[rate_index]; | 580 | case 32000: |
| 581 | rate_mclk = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256; | ||
| 582 | break; | ||
| 583 | case 44100: | ||
| 584 | if (data->os_128) | ||
| 585 | rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256; | ||
| 586 | else | ||
| 587 | rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_128; | ||
| 588 | break; | ||
| 589 | default: /* 48000 */ | ||
| 590 | if (data->os_128) | ||
| 591 | rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256; | ||
| 592 | else | ||
| 593 | rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_128; | ||
| 594 | break; | ||
| 595 | case 64000: | ||
| 596 | rate_mclk = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256; | ||
| 597 | break; | ||
| 598 | case 88200: | ||
| 599 | rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256; | ||
| 600 | break; | ||
| 601 | case 96000: | ||
| 602 | rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256; | ||
| 603 | break; | ||
| 604 | case 176400: | ||
| 605 | rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256; | ||
| 606 | break; | ||
| 607 | case 192000: | ||
| 608 | rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256; | ||
| 609 | break; | ||
| 610 | } | ||
| 549 | oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, rate_mclk, | 611 | oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, rate_mclk, |
| 550 | OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_MCLK_MASK); | 612 | OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_MCLK_MASK); |
| 551 | if ((rate_mclk & OXYGEN_I2S_MCLK_MASK) <= OXYGEN_I2S_MCLK_128) | 613 | if ((rate_mclk & OXYGEN_I2S_MCLK_MASK) <= OXYGEN_I2S_MCLK_128) |
| @@ -558,7 +620,7 @@ static void set_cs2000_params(struct oxygen *chip, | |||
| 558 | static void set_st_params(struct oxygen *chip, | 620 | static void set_st_params(struct oxygen *chip, |
| 559 | struct snd_pcm_hw_params *params) | 621 | struct snd_pcm_hw_params *params) |
| 560 | { | 622 | { |
| 561 | set_cs2000_params(chip, params); | 623 | update_cs2000_rate(chip, params_rate(params)); |
| 562 | set_pcm1796_params(chip, params); | 624 | set_pcm1796_params(chip, params); |
| 563 | } | 625 | } |
| 564 | 626 | ||
| @@ -580,6 +642,59 @@ static const struct snd_kcontrol_new alt_switch = { | |||
| 580 | .private_value = GPIO_D2_ALT, | 642 | .private_value = GPIO_D2_ALT, |
| 581 | }; | 643 | }; |
| 582 | 644 | ||
| 645 | static int os_128_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) | ||
| 646 | { | ||
| 647 | static const char *const names[2] = { "64x", "128x" }; | ||
| 648 | |||
| 649 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
| 650 | info->count = 1; | ||
| 651 | info->value.enumerated.items = 2; | ||
| 652 | if (info->value.enumerated.item >= 2) | ||
| 653 | info->value.enumerated.item = 1; | ||
| 654 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
| 655 | return 0; | ||
| 656 | } | ||
| 657 | |||
| 658 | static int os_128_get(struct snd_kcontrol *ctl, | ||
| 659 | struct snd_ctl_elem_value *value) | ||
| 660 | { | ||
| 661 | struct oxygen *chip = ctl->private_data; | ||
| 662 | struct xonar_pcm179x *data = chip->model_data; | ||
| 663 | |||
| 664 | value->value.enumerated.item[0] = data->os_128; | ||
| 665 | return 0; | ||
| 666 | } | ||
| 667 | |||
| 668 | static int os_128_put(struct snd_kcontrol *ctl, | ||
| 669 | struct snd_ctl_elem_value *value) | ||
| 670 | { | ||
| 671 | struct oxygen *chip = ctl->private_data; | ||
| 672 | struct xonar_pcm179x *data = chip->model_data; | ||
| 673 | int changed; | ||
| 674 | |||
| 675 | mutex_lock(&chip->mutex); | ||
| 676 | changed = value->value.enumerated.item[0] != data->os_128; | ||
| 677 | if (changed) { | ||
| 678 | data->os_128 = value->value.enumerated.item[0]; | ||
| 679 | if (data->has_cs2000) | ||
| 680 | update_cs2000_rate(chip, data->current_rate); | ||
| 681 | oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT, | ||
| 682 | mclk_from_rate(chip, data->current_rate), | ||
| 683 | OXYGEN_I2S_MCLK_MASK); | ||
| 684 | update_pcm1796_oversampling(chip); | ||
| 685 | } | ||
| 686 | mutex_unlock(&chip->mutex); | ||
| 687 | return changed; | ||
| 688 | } | ||
| 689 | |||
| 690 | static const struct snd_kcontrol_new os_128_control = { | ||
| 691 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 692 | .name = "DAC Oversampling Playback Enum", | ||
| 693 | .info = os_128_info, | ||
| 694 | .get = os_128_get, | ||
| 695 | .put = os_128_put, | ||
| 696 | }; | ||
| 697 | |||
| 583 | static int st_output_switch_info(struct snd_kcontrol *ctl, | 698 | static int st_output_switch_info(struct snd_kcontrol *ctl, |
| 584 | struct snd_ctl_elem_info *info) | 699 | struct snd_ctl_elem_info *info) |
| 585 | { | 700 | { |
| @@ -745,7 +860,20 @@ static int xonar_st_control_filter(struct snd_kcontrol_new *template) | |||
| 745 | 860 | ||
| 746 | static int xonar_d2_mixer_init(struct oxygen *chip) | 861 | static int xonar_d2_mixer_init(struct oxygen *chip) |
| 747 | { | 862 | { |
| 748 | return snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip)); | 863 | int err; |
| 864 | |||
| 865 | err = snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip)); | ||
| 866 | if (err < 0) | ||
| 867 | return err; | ||
| 868 | err = snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip)); | ||
| 869 | if (err < 0) | ||
| 870 | return err; | ||
| 871 | return 0; | ||
| 872 | } | ||
| 873 | |||
| 874 | static int xonar_hdav_mixer_init(struct oxygen *chip) | ||
| 875 | { | ||
| 876 | return snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip)); | ||
| 749 | } | 877 | } |
| 750 | 878 | ||
| 751 | static int xonar_st_mixer_init(struct oxygen *chip) | 879 | static int xonar_st_mixer_init(struct oxygen *chip) |
| @@ -759,6 +887,9 @@ static int xonar_st_mixer_init(struct oxygen *chip) | |||
| 759 | if (err < 0) | 887 | if (err < 0) |
| 760 | return err; | 888 | return err; |
| 761 | } | 889 | } |
| 890 | err = snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip)); | ||
| 891 | if (err < 0) | ||
| 892 | return err; | ||
| 762 | return 0; | 893 | return 0; |
| 763 | } | 894 | } |
| 764 | 895 | ||
| @@ -771,7 +902,7 @@ static const struct oxygen_model model_xonar_d2 = { | |||
| 771 | .cleanup = xonar_d2_cleanup, | 902 | .cleanup = xonar_d2_cleanup, |
| 772 | .suspend = xonar_d2_suspend, | 903 | .suspend = xonar_d2_suspend, |
| 773 | .resume = xonar_d2_resume, | 904 | .resume = xonar_d2_resume, |
| 774 | .get_i2s_mclk = oxygen_default_i2s_mclk, | 905 | .get_i2s_mclk = get_pcm1796_i2s_mclk, |
| 775 | .set_dac_params = set_pcm1796_params, | 906 | .set_dac_params = set_pcm1796_params, |
| 776 | .set_adc_params = xonar_set_cs53x1_params, | 907 | .set_adc_params = xonar_set_cs53x1_params, |
| 777 | .update_dac_volume = update_pcm1796_volume, | 908 | .update_dac_volume = update_pcm1796_volume, |
| @@ -798,11 +929,12 @@ static const struct oxygen_model model_xonar_hdav = { | |||
| 798 | .longname = "Asus Virtuoso 200", | 929 | .longname = "Asus Virtuoso 200", |
| 799 | .chip = "AV200", | 930 | .chip = "AV200", |
| 800 | .init = xonar_hdav_init, | 931 | .init = xonar_hdav_init, |
| 932 | .mixer_init = xonar_hdav_mixer_init, | ||
| 801 | .cleanup = xonar_hdav_cleanup, | 933 | .cleanup = xonar_hdav_cleanup, |
| 802 | .suspend = xonar_hdav_suspend, | 934 | .suspend = xonar_hdav_suspend, |
| 803 | .resume = xonar_hdav_resume, | 935 | .resume = xonar_hdav_resume, |
| 804 | .pcm_hardware_filter = xonar_hdmi_pcm_hardware_filter, | 936 | .pcm_hardware_filter = xonar_hdmi_pcm_hardware_filter, |
| 805 | .get_i2s_mclk = oxygen_default_i2s_mclk, | 937 | .get_i2s_mclk = get_pcm1796_i2s_mclk, |
| 806 | .set_dac_params = set_hdav_params, | 938 | .set_dac_params = set_hdav_params, |
| 807 | .set_adc_params = xonar_set_cs53x1_params, | 939 | .set_adc_params = xonar_set_cs53x1_params, |
| 808 | .update_dac_volume = update_pcm1796_volume, | 940 | .update_dac_volume = update_pcm1796_volume, |
| @@ -833,7 +965,7 @@ static const struct oxygen_model model_xonar_st = { | |||
| 833 | .cleanup = xonar_st_cleanup, | 965 | .cleanup = xonar_st_cleanup, |
| 834 | .suspend = xonar_st_suspend, | 966 | .suspend = xonar_st_suspend, |
| 835 | .resume = xonar_st_resume, | 967 | .resume = xonar_st_resume, |
| 836 | .get_i2s_mclk = oxygen_default_i2s_mclk, | 968 | .get_i2s_mclk = get_pcm1796_i2s_mclk, |
| 837 | .set_dac_params = set_st_params, | 969 | .set_dac_params = set_st_params, |
| 838 | .set_adc_params = xonar_set_cs53x1_params, | 970 | .set_adc_params = xonar_set_cs53x1_params, |
| 839 | .update_dac_volume = update_pcm1796_volume, | 971 | .update_dac_volume = update_pcm1796_volume, |
