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>
This commit is contained in:
Clemens Ladisch
2009-02-26 09:27:20 +01:00
committed by Takashi Iwai
parent eacbb9dba6
commit 930738de60
3 changed files with 195 additions and 2 deletions

View File

@@ -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];