diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2009-02-26 09:27:20 +0100 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-02-26 09:39:08 +0100 |
commit | 930738de602d2ceb0d1c1b368fe2a8d2a974ab72 (patch) | |
tree | dcf30656424e965026567b6e122a82b56af97989 /sound/pci/oxygen | |
parent | eacbb9dba6b4c982a0217ea2c7d15db88d4fda37 (diff) | |
download | lwn-930738de602d2ceb0d1c1b368fe2a8d2a974ab72.tar.gz lwn-930738de602d2ceb0d1c1b368fe2a8d2a974ab72.zip |
sound: virtuoso: add Xonar Essence STX support
Add support for the Asus Xonar Essence STX sound card.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/oxygen')
-rw-r--r-- | sound/pci/oxygen/virtuoso.c | 192 |
1 files changed, 192 insertions, 0 deletions
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 @@ * CS4362A: AD0 <- 0 */ +/* + * Xonar Essence STX + * ----------------- + * + * CMI8788: + * + * I²C <-> PCM1792A + * + * GPI 0 <- external power present + * + * GPIO 0 -> enable output to speakers + * GPIO 1 -> route HP to front panel (0) or rear jack (1) + * GPIO 2 -> M0 of CS5381 + * GPIO 3 -> M1 of CS5381 + * GPIO 7 -> route output to speaker jacks (0) or HP (1) + * GPIO 8 -> route input jack to line-in (0) or mic-in (1) + * + * PCM1792A: + * + * AD0 <- 0 + * + * H6 daughterboard + * ---------------- + * + * GPIO 4 <- 0 + * GPIO 5 <- 0 + */ + #include <linux/pci.h> #include <linux/delay.h> #include <linux/mutex.h> @@ -152,6 +180,7 @@ enum { MODEL_DX, MODEL_HDAV, /* without daughterboard */ MODEL_HDAV_H6, /* with H6 daughterboard */ + MODEL_STX, }; static struct pci_device_id xonar_ids[] __devinitdata = { @@ -160,6 +189,7 @@ static struct pci_device_id xonar_ids[] __devinitdata = { { OXYGEN_PCI_SUBID(0x1043, 0x82b7), .driver_data = MODEL_D2X }, { OXYGEN_PCI_SUBID(0x1043, 0x8314), .driver_data = MODEL_HDAV }, { OXYGEN_PCI_SUBID(0x1043, 0x834f), .driver_data = MODEL_D1 }, + { OXYGEN_PCI_SUBID(0x1043, 0x835c), .driver_data = MODEL_STX }, { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, { } }; @@ -184,6 +214,9 @@ MODULE_DEVICE_TABLE(pci, xonar_ids); #define GPIO_HDAV_DB_H6 0x0000 #define GPIO_HDAV_DB_XX 0x0020 +#define GPIO_ST_HP_REAR 0x0002 +#define GPIO_ST_HP 0x0080 + #define I2C_DEVICE_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ADx=i, /W=0 */ #define I2C_DEVICE_CS4398 0x9e /* 10011, AD1=1, AD0=1, /W=0 */ #define I2C_DEVICE_CS4362A 0x30 /* 001100, AD0=0, /W=0 */ @@ -497,6 +530,36 @@ static void xonar_hdav_init(struct oxygen *chip) snd_component_add(chip->card, "CS5381"); } +static void xonar_stx_init(struct oxygen *chip) +{ + struct xonar_data *data = chip->model_data; + + oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, + OXYGEN_2WIRE_LENGTH_8 | + OXYGEN_2WIRE_INTERRUPT_MASK | + OXYGEN_2WIRE_SPEED_FAST); + + data->anti_pop_delay = 100; + data->dacs = 1; + data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE; + data->ext_power_reg = OXYGEN_GPI_DATA; + data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; + data->ext_power_bit = GPI_DX_EXT_POWER; + data->pcm1796_oversampling = PCM1796_OS_64; + + pcm1796_init(chip); + + oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, + GPIO_DX_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP); + oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, + GPIO_DX_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP); + + xonar_common_init(chip); + + snd_component_add(chip->card, "PCM1792A"); + snd_component_add(chip->card, "CS5381"); +} + static void xonar_disable_output(struct oxygen *chip) { struct xonar_data *data = chip->model_data; @@ -524,6 +587,11 @@ static void xonar_hdav_cleanup(struct oxygen *chip) xonar_disable_output(chip); } +static void xonar_st_cleanup(struct oxygen *chip) +{ + xonar_disable_output(chip); +} + static void xonar_d2_suspend(struct oxygen *chip) { xonar_d2_cleanup(chip); @@ -540,6 +608,11 @@ static void xonar_hdav_suspend(struct oxygen *chip) msleep(2); } +static void xonar_st_suspend(struct oxygen *chip) +{ + xonar_st_cleanup(chip); +} + static void xonar_d2_resume(struct oxygen *chip) { pcm1796_init(chip); @@ -567,6 +640,12 @@ static void xonar_hdav_resume(struct oxygen *chip) xonar_enable_output(chip); } +static void xonar_st_resume(struct oxygen *chip) +{ + pcm1796_init(chip); + xonar_enable_output(chip); +} + static void xonar_hdav_pcm_hardware_filter(unsigned int channel, struct snd_pcm_hardware *hardware) { @@ -746,6 +825,72 @@ static const struct snd_kcontrol_new front_panel_switch = { .private_value = GPIO_DX_FRONT_PANEL, }; +static int st_output_switch_info(struct snd_kcontrol *ctl, + struct snd_ctl_elem_info *info) +{ + static const char *const names[3] = { + "Speakers", "Headphones", "FP Headphones" + }; + + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + info->count = 1; + info->value.enumerated.items = 3; + if (info->value.enumerated.item >= 3) + info->value.enumerated.item = 2; + strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); + return 0; +} + +static int st_output_switch_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + u16 gpio; + + gpio = oxygen_read16(chip, OXYGEN_GPIO_DATA); + if (!(gpio & GPIO_ST_HP)) + value->value.enumerated.item[0] = 0; + else if (gpio & GPIO_ST_HP_REAR) + value->value.enumerated.item[0] = 1; + else + value->value.enumerated.item[0] = 2; + return 0; +} + + +static int st_output_switch_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + u16 gpio_old, gpio; + + mutex_lock(&chip->mutex); + gpio_old = oxygen_read16(chip, OXYGEN_GPIO_DATA); + gpio = gpio_old; + switch (value->value.enumerated.item[0]) { + case 0: + gpio &= ~(GPIO_ST_HP | GPIO_ST_HP_REAR); + break; + case 1: + gpio |= GPIO_ST_HP | GPIO_ST_HP_REAR; + break; + case 2: + gpio = (gpio | GPIO_ST_HP) & ~GPIO_ST_HP_REAR; + break; + } + oxygen_write16(chip, OXYGEN_GPIO_DATA, gpio); + mutex_unlock(&chip->mutex); + return gpio != gpio_old; +} + +static const struct snd_kcontrol_new st_output_switch = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog Output", + .info = st_output_switch_info, + .get = st_output_switch_get, + .put = st_output_switch_put, +}; + static void xonar_line_mic_ac97_switch(struct oxygen *chip, unsigned int reg, unsigned int mute) { @@ -776,6 +921,15 @@ static int xonar_d1_control_filter(struct snd_kcontrol_new *template) return 0; } +static int xonar_st_control_filter(struct snd_kcontrol_new *template) +{ + if (!strncmp(template->name, "CD Capture ", 11)) + return 1; /* no CD input */ + if (!strcmp(template->name, "Stereo Upmixing")) + return 1; /* stereo only - we don't need upmixing */ + return 0; +} + static int xonar_d2_mixer_init(struct oxygen *chip) { 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) return snd_ctl_add(chip->card, snd_ctl_new1(&front_panel_switch, chip)); } +static int xonar_st_mixer_init(struct oxygen *chip) +{ + return snd_ctl_add(chip->card, snd_ctl_new1(&st_output_switch, chip)); +} + static const struct oxygen_model model_xonar_d2 = { .longname = "Asus Virtuoso 200", .chip = "AV200", @@ -872,6 +1031,33 @@ static const struct oxygen_model model_xonar_hdav = { .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, }; +static const struct oxygen_model model_xonar_st = { + .longname = "Asus Virtuoso 100", + .chip = "AV200", + .init = xonar_stx_init, + .control_filter = xonar_st_control_filter, + .mixer_init = xonar_st_mixer_init, + .cleanup = xonar_st_cleanup, + .suspend = xonar_st_suspend, + .resume = xonar_st_resume, + .set_dac_params = set_pcm1796_params, + .set_adc_params = set_cs53x1_params, + .update_dac_volume = update_pcm1796_volume, + .update_dac_mute = update_pcm1796_mute, + .ac97_switch = xonar_line_mic_ac97_switch, + .dac_tlv = pcm1796_db_scale, + .model_data_size = sizeof(struct xonar_data), + .device_config = PLAYBACK_0_TO_I2S | + PLAYBACK_1_TO_SPDIF | + CAPTURE_0_FROM_I2S_2, + .dac_channels = 2, + .dac_volume_min = 255 - 2*60, + .dac_volume_max = 255, + .function_flags = OXYGEN_FUNCTION_2WIRE, + .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, + .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, +}; + static int __devinit get_xonar_model(struct oxygen *chip, const struct pci_device_id *id) { @@ -881,6 +1067,7 @@ static int __devinit get_xonar_model(struct oxygen *chip, [MODEL_D2] = &model_xonar_d2, [MODEL_D2X] = &model_xonar_d2, [MODEL_HDAV] = &model_xonar_hdav, + [MODEL_STX] = &model_xonar_st, }; static const char *const names[] = { [MODEL_D1] = "Xonar D1", @@ -889,6 +1076,7 @@ static int __devinit get_xonar_model(struct oxygen *chip, [MODEL_D2X] = "Xonar D2X", [MODEL_HDAV] = "Xonar HDAV1.3", [MODEL_HDAV_H6] = "Xonar HDAV1.3+H6", + [MODEL_STX] = "Xonar Essence STX", }; unsigned int model = id->driver_data; @@ -916,6 +1104,10 @@ static int __devinit get_xonar_model(struct oxygen *chip, return -ENODEV; } break; + case MODEL_STX: + oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, + GPIO_HDAV_DB_MASK); + break; } chip->model.shortname = names[model]; |