diff options
| -rw-r--r-- | Documentation/sound/alsa/ALSA-Configuration.txt | 2 | ||||
| -rw-r--r-- | sound/pci/Kconfig | 3 | ||||
| -rw-r--r-- | sound/pci/oxygen/virtuoso.c | 192 |
3 files changed, 195 insertions, 2 deletions
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 841a9365d5fd..1356d2a6772b 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt | |||
| @@ -1824,7 +1824,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
| 1824 | ------------------- | 1824 | ------------------- |
| 1825 | 1825 | ||
| 1826 | Module for sound cards based on the Asus AV100/AV200 chips, | 1826 | Module for sound cards based on the Asus AV100/AV200 chips, |
| 1827 | i.e., Xonar D1, DX, D2, D2X and HDAV1.3 (Deluxe). | 1827 | i.e., Xonar D1, DX, D2, D2X, HDAV1.3 (Deluxe), and Essence STX. |
| 1828 | 1828 | ||
| 1829 | This module supports autoprobe and multiple cards. | 1829 | This module supports autoprobe and multiple cards. |
| 1830 | 1830 | ||
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 82b9bddcdcd6..21d117ada84b 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig | |||
| @@ -744,7 +744,8 @@ config SND_VIRTUOSO | |||
| 744 | select SND_OXYGEN_LIB | 744 | select SND_OXYGEN_LIB |
| 745 | help | 745 | help |
| 746 | Say Y here to include support for sound cards based on the | 746 | Say Y here to include support for sound cards based on the |
| 747 | Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2 and D2X. | 747 | Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, and |
| 748 | Essence STX. | ||
| 748 | Support for the HDAV1.3 (Deluxe) is very experimental. | 749 | Support for the HDAV1.3 (Deluxe) is very experimental. |
| 749 | 750 | ||
| 750 | To compile this driver as a module, choose M here: the module | 751 | To compile this driver as a module, choose M here: the module |
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 00dc97806f1b..bc5ce11c8b14 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c | |||
| @@ -112,6 +112,34 @@ | |||
| 112 | * CS4362A: AD0 <- 0 | 112 | * CS4362A: AD0 <- 0 |
| 113 | */ | 113 | */ |
| 114 | 114 | ||
| 115 | /* | ||
| 116 | * Xonar Essence STX | ||
| 117 | * ----------------- | ||
| 118 | * | ||
| 119 | * CMI8788: | ||
| 120 | * | ||
| 121 | * I²C <-> PCM1792A | ||
| 122 | * | ||
| 123 | * GPI 0 <- external power present | ||
| 124 | * | ||
| 125 | * GPIO 0 -> enable output to speakers | ||
| 126 | * GPIO 1 -> route HP to front panel (0) or rear jack (1) | ||
| 127 | * GPIO 2 -> M0 of CS5381 | ||
| 128 | * GPIO 3 -> M1 of CS5381 | ||
| 129 | * GPIO 7 -> route output to speaker jacks (0) or HP (1) | ||
| 130 | * GPIO 8 -> route input jack to line-in (0) or mic-in (1) | ||
| 131 | * | ||
| 132 | * PCM1792A: | ||
| 133 | * | ||
| 134 | * AD0 <- 0 | ||
| 135 | * | ||
| 136 | * H6 daughterboard | ||
| 137 | * ---------------- | ||
| 138 | * | ||
| 139 | * GPIO 4 <- 0 | ||
| 140 | * GPIO 5 <- 0 | ||
| 141 | */ | ||
| 142 | |||
| 115 | #include <linux/pci.h> | 143 | #include <linux/pci.h> |
| 116 | #include <linux/delay.h> | 144 | #include <linux/delay.h> |
| 117 | #include <linux/mutex.h> | 145 | #include <linux/mutex.h> |
| @@ -152,6 +180,7 @@ enum { | |||
| 152 | MODEL_DX, | 180 | MODEL_DX, |
| 153 | MODEL_HDAV, /* without daughterboard */ | 181 | MODEL_HDAV, /* without daughterboard */ |
| 154 | MODEL_HDAV_H6, /* with H6 daughterboard */ | 182 | MODEL_HDAV_H6, /* with H6 daughterboard */ |
| 183 | MODEL_STX, | ||
| 155 | }; | 184 | }; |
| 156 | 185 | ||
| 157 | static struct pci_device_id xonar_ids[] __devinitdata = { | 186 | static struct pci_device_id xonar_ids[] __devinitdata = { |
| @@ -160,6 +189,7 @@ static struct pci_device_id xonar_ids[] __devinitdata = { | |||
| 160 | { OXYGEN_PCI_SUBID(0x1043, 0x82b7), .driver_data = MODEL_D2X }, | 189 | { OXYGEN_PCI_SUBID(0x1043, 0x82b7), .driver_data = MODEL_D2X }, |
| 161 | { OXYGEN_PCI_SUBID(0x1043, 0x8314), .driver_data = MODEL_HDAV }, | 190 | { OXYGEN_PCI_SUBID(0x1043, 0x8314), .driver_data = MODEL_HDAV }, |
| 162 | { OXYGEN_PCI_SUBID(0x1043, 0x834f), .driver_data = MODEL_D1 }, | 191 | { OXYGEN_PCI_SUBID(0x1043, 0x834f), .driver_data = MODEL_D1 }, |
| 192 | { OXYGEN_PCI_SUBID(0x1043, 0x835c), .driver_data = MODEL_STX }, | ||
| 163 | { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, | 193 | { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, |
| 164 | { } | 194 | { } |
| 165 | }; | 195 | }; |
| @@ -184,6 +214,9 @@ MODULE_DEVICE_TABLE(pci, xonar_ids); | |||
| 184 | #define GPIO_HDAV_DB_H6 0x0000 | 214 | #define GPIO_HDAV_DB_H6 0x0000 |
| 185 | #define GPIO_HDAV_DB_XX 0x0020 | 215 | #define GPIO_HDAV_DB_XX 0x0020 |
| 186 | 216 | ||
| 217 | #define GPIO_ST_HP_REAR 0x0002 | ||
| 218 | #define GPIO_ST_HP 0x0080 | ||
| 219 | |||
| 187 | #define I2C_DEVICE_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ADx=i, /W=0 */ | 220 | #define I2C_DEVICE_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ADx=i, /W=0 */ |
| 188 | #define I2C_DEVICE_CS4398 0x9e /* 10011, AD1=1, AD0=1, /W=0 */ | 221 | #define I2C_DEVICE_CS4398 0x9e /* 10011, AD1=1, AD0=1, /W=0 */ |
| 189 | #define I2C_DEVICE_CS4362A 0x30 /* 001100, AD0=0, /W=0 */ | 222 | #define I2C_DEVICE_CS4362A 0x30 /* 001100, AD0=0, /W=0 */ |
| @@ -497,6 +530,36 @@ static void xonar_hdav_init(struct oxygen *chip) | |||
| 497 | snd_component_add(chip->card, "CS5381"); | 530 | snd_component_add(chip->card, "CS5381"); |
| 498 | } | 531 | } |
| 499 | 532 | ||
| 533 | static void xonar_stx_init(struct oxygen *chip) | ||
| 534 | { | ||
| 535 | struct xonar_data *data = chip->model_data; | ||
| 536 | |||
| 537 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, | ||
| 538 | OXYGEN_2WIRE_LENGTH_8 | | ||
| 539 | OXYGEN_2WIRE_INTERRUPT_MASK | | ||
| 540 | OXYGEN_2WIRE_SPEED_FAST); | ||
| 541 | |||
| 542 | data->anti_pop_delay = 100; | ||
| 543 | data->dacs = 1; | ||
| 544 | data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE; | ||
| 545 | data->ext_power_reg = OXYGEN_GPI_DATA; | ||
| 546 | data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; | ||
| 547 | data->ext_power_bit = GPI_DX_EXT_POWER; | ||
| 548 | data->pcm1796_oversampling = PCM1796_OS_64; | ||
| 549 | |||
| 550 | pcm1796_init(chip); | ||
| 551 | |||
| 552 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, | ||
| 553 | GPIO_DX_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP); | ||
| 554 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, | ||
| 555 | GPIO_DX_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP); | ||
| 556 | |||
| 557 | xonar_common_init(chip); | ||
| 558 | |||
| 559 | snd_component_add(chip->card, "PCM1792A"); | ||
| 560 | snd_component_add(chip->card, "CS5381"); | ||
| 561 | } | ||
| 562 | |||
| 500 | static void xonar_disable_output(struct oxygen *chip) | 563 | static void xonar_disable_output(struct oxygen *chip) |
| 501 | { | 564 | { |
| 502 | struct xonar_data *data = chip->model_data; | 565 | struct xonar_data *data = chip->model_data; |
| @@ -524,6 +587,11 @@ static void xonar_hdav_cleanup(struct oxygen *chip) | |||
| 524 | xonar_disable_output(chip); | 587 | xonar_disable_output(chip); |
| 525 | } | 588 | } |
| 526 | 589 | ||
| 590 | static void xonar_st_cleanup(struct oxygen *chip) | ||
| 591 | { | ||
| 592 | xonar_disable_output(chip); | ||
| 593 | } | ||
| 594 | |||
| 527 | static void xonar_d2_suspend(struct oxygen *chip) | 595 | static void xonar_d2_suspend(struct oxygen *chip) |
| 528 | { | 596 | { |
| 529 | xonar_d2_cleanup(chip); | 597 | xonar_d2_cleanup(chip); |
| @@ -540,6 +608,11 @@ static void xonar_hdav_suspend(struct oxygen *chip) | |||
| 540 | msleep(2); | 608 | msleep(2); |
| 541 | } | 609 | } |
| 542 | 610 | ||
| 611 | static void xonar_st_suspend(struct oxygen *chip) | ||
| 612 | { | ||
| 613 | xonar_st_cleanup(chip); | ||
| 614 | } | ||
| 615 | |||
| 543 | static void xonar_d2_resume(struct oxygen *chip) | 616 | static void xonar_d2_resume(struct oxygen *chip) |
| 544 | { | 617 | { |
| 545 | pcm1796_init(chip); | 618 | pcm1796_init(chip); |
| @@ -567,6 +640,12 @@ static void xonar_hdav_resume(struct oxygen *chip) | |||
| 567 | xonar_enable_output(chip); | 640 | xonar_enable_output(chip); |
| 568 | } | 641 | } |
| 569 | 642 | ||
| 643 | static void xonar_st_resume(struct oxygen *chip) | ||
| 644 | { | ||
| 645 | pcm1796_init(chip); | ||
| 646 | xonar_enable_output(chip); | ||
| 647 | } | ||
| 648 | |||
| 570 | static void xonar_hdav_pcm_hardware_filter(unsigned int channel, | 649 | static void xonar_hdav_pcm_hardware_filter(unsigned int channel, |
| 571 | struct snd_pcm_hardware *hardware) | 650 | struct snd_pcm_hardware *hardware) |
| 572 | { | 651 | { |
| @@ -746,6 +825,72 @@ static const struct snd_kcontrol_new front_panel_switch = { | |||
| 746 | .private_value = GPIO_DX_FRONT_PANEL, | 825 | .private_value = GPIO_DX_FRONT_PANEL, |
| 747 | }; | 826 | }; |
| 748 | 827 | ||
| 828 | static int st_output_switch_info(struct snd_kcontrol *ctl, | ||
| 829 | struct snd_ctl_elem_info *info) | ||
| 830 | { | ||
| 831 | static const char *const names[3] = { | ||
| 832 | "Speakers", "Headphones", "FP Headphones" | ||
| 833 | }; | ||
| 834 | |||
| 835 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
| 836 | info->count = 1; | ||
| 837 | info->value.enumerated.items = 3; | ||
| 838 | if (info->value.enumerated.item >= 3) | ||
| 839 | info->value.enumerated.item = 2; | ||
| 840 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
| 841 | return 0; | ||
| 842 | } | ||
| 843 | |||
| 844 | static int st_output_switch_get(struct snd_kcontrol *ctl, | ||
| 845 | struct snd_ctl_elem_value *value) | ||
| 846 | { | ||
| 847 | struct oxygen *chip = ctl->private_data; | ||
| 848 | u16 gpio; | ||
| 849 | |||
| 850 | gpio = oxygen_read16(chip, OXYGEN_GPIO_DATA); | ||
| 851 | if (!(gpio & GPIO_ST_HP)) | ||
| 852 | value->value.enumerated.item[0] = 0; | ||
| 853 | else if (gpio & GPIO_ST_HP_REAR) | ||
| 854 | value->value.enumerated.item[0] = 1; | ||
| 855 | else | ||
| 856 | value->value.enumerated.item[0] = 2; | ||
| 857 | return 0; | ||
| 858 | } | ||
| 859 | |||
| 860 | |||
| 861 | static int st_output_switch_put(struct snd_kcontrol *ctl, | ||
| 862 | struct snd_ctl_elem_value *value) | ||
| 863 | { | ||
| 864 | struct oxygen *chip = ctl->private_data; | ||
| 865 | u16 gpio_old, gpio; | ||
| 866 | |||
| 867 | mutex_lock(&chip->mutex); | ||
| 868 | gpio_old = oxygen_read16(chip, OXYGEN_GPIO_DATA); | ||
| 869 | gpio = gpio_old; | ||
| 870 | switch (value->value.enumerated.item[0]) { | ||
| 871 | case 0: | ||
| 872 | gpio &= ~(GPIO_ST_HP | GPIO_ST_HP_REAR); | ||
| 873 | break; | ||
| 874 | case 1: | ||
| 875 | gpio |= GPIO_ST_HP | GPIO_ST_HP_REAR; | ||
| 876 | break; | ||
| 877 | case 2: | ||
| 878 | gpio = (gpio | GPIO_ST_HP) & ~GPIO_ST_HP_REAR; | ||
| 879 | break; | ||
| 880 | } | ||
| 881 | oxygen_write16(chip, OXYGEN_GPIO_DATA, gpio); | ||
| 882 | mutex_unlock(&chip->mutex); | ||
| 883 | return gpio != gpio_old; | ||
| 884 | } | ||
| 885 | |||
| 886 | static const struct snd_kcontrol_new st_output_switch = { | ||
| 887 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 888 | .name = "Analog Output", | ||
| 889 | .info = st_output_switch_info, | ||
| 890 | .get = st_output_switch_get, | ||
| 891 | .put = st_output_switch_put, | ||
| 892 | }; | ||
| 893 | |||
| 749 | static void xonar_line_mic_ac97_switch(struct oxygen *chip, | 894 | static void xonar_line_mic_ac97_switch(struct oxygen *chip, |
| 750 | unsigned int reg, unsigned int mute) | 895 | unsigned int reg, unsigned int mute) |
| 751 | { | 896 | { |
| @@ -776,6 +921,15 @@ static int xonar_d1_control_filter(struct snd_kcontrol_new *template) | |||
| 776 | return 0; | 921 | return 0; |
| 777 | } | 922 | } |
| 778 | 923 | ||
| 924 | static int xonar_st_control_filter(struct snd_kcontrol_new *template) | ||
| 925 | { | ||
| 926 | if (!strncmp(template->name, "CD Capture ", 11)) | ||
| 927 | return 1; /* no CD input */ | ||
| 928 | if (!strcmp(template->name, "Stereo Upmixing")) | ||
| 929 | return 1; /* stereo only - we don't need upmixing */ | ||
| 930 | return 0; | ||
| 931 | } | ||
| 932 | |||
| 779 | static int xonar_d2_mixer_init(struct oxygen *chip) | 933 | static int xonar_d2_mixer_init(struct oxygen *chip) |
| 780 | { | 934 | { |
| 781 | return snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip)); | 935 | return snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip)); |
| @@ -786,6 +940,11 @@ static int xonar_d1_mixer_init(struct oxygen *chip) | |||
| 786 | return snd_ctl_add(chip->card, snd_ctl_new1(&front_panel_switch, chip)); | 940 | return snd_ctl_add(chip->card, snd_ctl_new1(&front_panel_switch, chip)); |
| 787 | } | 941 | } |
| 788 | 942 | ||
| 943 | static int xonar_st_mixer_init(struct oxygen *chip) | ||
| 944 | { | ||
| 945 | return snd_ctl_add(chip->card, snd_ctl_new1(&st_output_switch, chip)); | ||
| 946 | } | ||
| 947 | |||
| 789 | static const struct oxygen_model model_xonar_d2 = { | 948 | static const struct oxygen_model model_xonar_d2 = { |
| 790 | .longname = "Asus Virtuoso 200", | 949 | .longname = "Asus Virtuoso 200", |
| 791 | .chip = "AV200", | 950 | .chip = "AV200", |
| @@ -872,6 +1031,33 @@ static const struct oxygen_model model_xonar_hdav = { | |||
| 872 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | 1031 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, |
| 873 | }; | 1032 | }; |
| 874 | 1033 | ||
| 1034 | static const struct oxygen_model model_xonar_st = { | ||
| 1035 | .longname = "Asus Virtuoso 100", | ||
| 1036 | .chip = "AV200", | ||
| 1037 | .init = xonar_stx_init, | ||
| 1038 | .control_filter = xonar_st_control_filter, | ||
| 1039 | .mixer_init = xonar_st_mixer_init, | ||
| 1040 | .cleanup = xonar_st_cleanup, | ||
| 1041 | .suspend = xonar_st_suspend, | ||
| 1042 | .resume = xonar_st_resume, | ||
| 1043 | .set_dac_params = set_pcm1796_params, | ||
| 1044 | .set_adc_params = set_cs53x1_params, | ||
| 1045 | .update_dac_volume = update_pcm1796_volume, | ||
| 1046 | .update_dac_mute = update_pcm1796_mute, | ||
| 1047 | .ac97_switch = xonar_line_mic_ac97_switch, | ||
| 1048 | .dac_tlv = pcm1796_db_scale, | ||
| 1049 | .model_data_size = sizeof(struct xonar_data), | ||
| 1050 | .device_config = PLAYBACK_0_TO_I2S | | ||
| 1051 | PLAYBACK_1_TO_SPDIF | | ||
| 1052 | CAPTURE_0_FROM_I2S_2, | ||
| 1053 | .dac_channels = 2, | ||
| 1054 | .dac_volume_min = 255 - 2*60, | ||
| 1055 | .dac_volume_max = 255, | ||
| 1056 | .function_flags = OXYGEN_FUNCTION_2WIRE, | ||
| 1057 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
| 1058 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
| 1059 | }; | ||
| 1060 | |||
| 875 | static int __devinit get_xonar_model(struct oxygen *chip, | 1061 | static int __devinit get_xonar_model(struct oxygen *chip, |
| 876 | const struct pci_device_id *id) | 1062 | const struct pci_device_id *id) |
| 877 | { | 1063 | { |
| @@ -881,6 +1067,7 @@ static int __devinit get_xonar_model(struct oxygen *chip, | |||
| 881 | [MODEL_D2] = &model_xonar_d2, | 1067 | [MODEL_D2] = &model_xonar_d2, |
| 882 | [MODEL_D2X] = &model_xonar_d2, | 1068 | [MODEL_D2X] = &model_xonar_d2, |
| 883 | [MODEL_HDAV] = &model_xonar_hdav, | 1069 | [MODEL_HDAV] = &model_xonar_hdav, |
| 1070 | [MODEL_STX] = &model_xonar_st, | ||
| 884 | }; | 1071 | }; |
| 885 | static const char *const names[] = { | 1072 | static const char *const names[] = { |
| 886 | [MODEL_D1] = "Xonar D1", | 1073 | [MODEL_D1] = "Xonar D1", |
| @@ -889,6 +1076,7 @@ static int __devinit get_xonar_model(struct oxygen *chip, | |||
| 889 | [MODEL_D2X] = "Xonar D2X", | 1076 | [MODEL_D2X] = "Xonar D2X", |
| 890 | [MODEL_HDAV] = "Xonar HDAV1.3", | 1077 | [MODEL_HDAV] = "Xonar HDAV1.3", |
| 891 | [MODEL_HDAV_H6] = "Xonar HDAV1.3+H6", | 1078 | [MODEL_HDAV_H6] = "Xonar HDAV1.3+H6", |
| 1079 | [MODEL_STX] = "Xonar Essence STX", | ||
| 892 | }; | 1080 | }; |
| 893 | unsigned int model = id->driver_data; | 1081 | unsigned int model = id->driver_data; |
| 894 | 1082 | ||
| @@ -916,6 +1104,10 @@ static int __devinit get_xonar_model(struct oxygen *chip, | |||
| 916 | return -ENODEV; | 1104 | return -ENODEV; |
| 917 | } | 1105 | } |
| 918 | break; | 1106 | break; |
| 1107 | case MODEL_STX: | ||
| 1108 | oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, | ||
| 1109 | GPIO_HDAV_DB_MASK); | ||
| 1110 | break; | ||
| 919 | } | 1111 | } |
| 920 | 1112 | ||
| 921 | chip->model.shortname = names[model]; | 1113 | chip->model.shortname = names[model]; |
