Merge branch 'topic/oxygen' into for-linus

tirimbino
Takashi Iwai 16 years ago
commit b54fc8dd2c
  1. 2
      Documentation/sound/alsa/ALSA-Configuration.txt
  2. 3
      sound/pci/Kconfig
  3. 12
      sound/pci/oxygen/hifier.c
  4. 114
      sound/pci/oxygen/oxygen.c
  5. 22
      sound/pci/oxygen/oxygen.h
  6. 31
      sound/pci/oxygen/oxygen_io.c
  7. 100
      sound/pci/oxygen/oxygen_lib.c
  8. 339
      sound/pci/oxygen/virtuoso.c

@ -1859,7 +1859,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
-------------------
Module for sound cards based on the Asus AV100/AV200 chips,
i.e., Xonar D1, DX, D2, D2X and HDAV1.3 (Deluxe).
i.e., Xonar D1, DX, D2, D2X, HDAV1.3 (Deluxe), and Essence STX.
This module supports autoprobe and multiple cards.

@ -764,7 +764,8 @@ config SND_VIRTUOSO
select SND_OXYGEN_LIB
help
Say Y here to include support for sound cards based on the
Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2 and D2X.
Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, and
Essence STX.
Support for the HDAV1.3 (Deluxe) is very experimental.
To compile this driver as a module, choose M here: the module

@ -45,6 +45,7 @@ MODULE_PARM_DESC(enable, "enable card");
static struct pci_device_id hifier_ids[] __devinitdata = {
{ OXYGEN_PCI_SUBID(0x14c3, 0x1710) },
{ OXYGEN_PCI_SUBID(0x14c3, 0x1711) },
{ OXYGEN_PCI_SUBID_BROKEN_EEPROM },
{ }
};
MODULE_DEVICE_TABLE(pci, hifier_ids);
@ -151,7 +152,6 @@ static const struct oxygen_model model_hifier = {
.shortname = "C-Media CMI8787",
.longname = "C-Media Oxygen HD Audio",
.chip = "CMI8788",
.owner = THIS_MODULE,
.init = hifier_init,
.control_filter = hifier_control_filter,
.cleanup = hifier_cleanup,
@ -173,6 +173,13 @@ static const struct oxygen_model model_hifier = {
.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
};
static int __devinit get_hifier_model(struct oxygen *chip,
const struct pci_device_id *id)
{
chip->model = model_hifier;
return 0;
}
static int __devinit hifier_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
{
@ -185,7 +192,8 @@ static int __devinit hifier_probe(struct pci_dev *pci,
++dev;
return -ENOENT;
}
err = oxygen_pci_probe(pci, index[dev], id[dev], &model_hifier, 0);
err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE,
hifier_ids, get_hifier_model);
if (err >= 0)
++dev;
return err;

@ -1,5 +1,5 @@
/*
* C-Media CMI8788 driver for C-Media's reference design and for the X-Meridian
* C-Media CMI8788 driver for C-Media's reference design and similar models
*
* Copyright (c) Clemens Ladisch <clemens@ladisch.de>
*
@ -26,6 +26,7 @@
*
* GPIO 0 -> DFS0 of AK5385
* GPIO 1 -> DFS1 of AK5385
* GPIO 8 -> enable headphone amplifier on HT-Omega models
*/
#include <linux/delay.h>
@ -61,7 +62,8 @@ MODULE_PARM_DESC(enable, "enable card");
enum {
MODEL_CMEDIA_REF, /* C-Media's reference design */
MODEL_MERIDIAN, /* AuzenTech X-Meridian */
MODEL_HALO, /* HT-Omega Claro halo */
MODEL_CLARO, /* HT-Omega Claro */
MODEL_CLARO_HALO, /* HT-Omega Claro halo */
};
static struct pci_device_id oxygen_ids[] __devinitdata = {
@ -74,8 +76,8 @@ static struct pci_device_id oxygen_ids[] __devinitdata = {
{ OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF },
{ OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF },
{ OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN },
{ OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CMEDIA_REF },
{ OXYGEN_PCI_SUBID(0x7284, 0x9781), .driver_data = MODEL_HALO },
{ OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CLARO },
{ OXYGEN_PCI_SUBID(0x7284, 0x9781), .driver_data = MODEL_CLARO_HALO },
{ }
};
MODULE_DEVICE_TABLE(pci, oxygen_ids);
@ -86,6 +88,8 @@ MODULE_DEVICE_TABLE(pci, oxygen_ids);
#define GPIO_AK5385_DFS_DOUBLE 0x0001
#define GPIO_AK5385_DFS_QUAD 0x0002
#define GPIO_CLARO_HP 0x0100
struct generic_data {
u8 ak4396_ctl2;
u16 saved_wm8785_registers[2];
@ -196,10 +200,46 @@ static void meridian_init(struct oxygen *chip)
ak5385_init(chip);
}
static void claro_enable_hp(struct oxygen *chip)
{
msleep(300);
oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CLARO_HP);
oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_HP);
}
static void claro_init(struct oxygen *chip)
{
ak4396_init(chip);
wm8785_init(chip);
claro_enable_hp(chip);
}
static void claro_halo_init(struct oxygen *chip)
{
ak4396_init(chip);
ak5385_init(chip);
claro_enable_hp(chip);
}
static void generic_cleanup(struct oxygen *chip)
{
}
static void claro_disable_hp(struct oxygen *chip)
{
oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_HP);
}
static void claro_cleanup(struct oxygen *chip)
{
claro_disable_hp(chip);
}
static void claro_suspend(struct oxygen *chip)
{
claro_disable_hp(chip);
}
static void generic_resume(struct oxygen *chip)
{
ak4396_registers_init(chip);
@ -211,6 +251,12 @@ static void meridian_resume(struct oxygen *chip)
ak4396_registers_init(chip);
}
static void claro_resume(struct oxygen *chip)
{
ak4396_registers_init(chip);
claro_enable_hp(chip);
}
static void set_ak4396_params(struct oxygen *chip,
struct snd_pcm_hw_params *params)
{
@ -293,30 +339,10 @@ static void set_ak5385_params(struct oxygen *chip,
static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0);
static int generic_probe(struct oxygen *chip, unsigned long driver_data)
{
if (driver_data == MODEL_MERIDIAN) {
chip->model.init = meridian_init;
chip->model.resume = meridian_resume;
chip->model.set_adc_params = set_ak5385_params;
chip->model.device_config = PLAYBACK_0_TO_I2S |
PLAYBACK_1_TO_SPDIF |
CAPTURE_0_FROM_I2S_2 |
CAPTURE_1_FROM_SPDIF;
}
if (driver_data == MODEL_MERIDIAN || driver_data == MODEL_HALO) {
chip->model.misc_flags = OXYGEN_MISC_MIDI;
chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT;
}
return 0;
}
static const struct oxygen_model model_generic = {
.shortname = "C-Media CMI8788",
.longname = "C-Media Oxygen HD Audio",
.chip = "CMI8788",
.owner = THIS_MODULE,
.probe = generic_probe,
.init = generic_init,
.cleanup = generic_cleanup,
.resume = generic_resume,
@ -341,6 +367,42 @@ static const struct oxygen_model model_generic = {
.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
};
static int __devinit get_oxygen_model(struct oxygen *chip,
const struct pci_device_id *id)
{
chip->model = model_generic;
switch (id->driver_data) {
case MODEL_MERIDIAN:
chip->model.init = meridian_init;
chip->model.resume = meridian_resume;
chip->model.set_adc_params = set_ak5385_params;
chip->model.device_config = PLAYBACK_0_TO_I2S |
PLAYBACK_1_TO_SPDIF |
CAPTURE_0_FROM_I2S_2 |
CAPTURE_1_FROM_SPDIF;
break;
case MODEL_CLARO:
chip->model.init = claro_init;
chip->model.cleanup = claro_cleanup;
chip->model.suspend = claro_suspend;
chip->model.resume = claro_resume;
break;
case MODEL_CLARO_HALO:
chip->model.init = claro_halo_init;
chip->model.cleanup = claro_cleanup;
chip->model.suspend = claro_suspend;
chip->model.resume = claro_resume;
chip->model.set_adc_params = set_ak5385_params;
break;
}
if (id->driver_data == MODEL_MERIDIAN ||
id->driver_data == MODEL_CLARO_HALO) {
chip->model.misc_flags = OXYGEN_MISC_MIDI;
chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT;
}
return 0;
}
static int __devinit generic_oxygen_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
{
@ -353,8 +415,8 @@ static int __devinit generic_oxygen_probe(struct pci_dev *pci,
++dev;
return -ENOENT;
}
err = oxygen_pci_probe(pci, index[dev], id[dev],
&model_generic, pci_id->driver_data);
err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE,
oxygen_ids, get_oxygen_model);
if (err >= 0)
++dev;
return err;

@ -18,6 +18,8 @@
#define OXYGEN_IO_SIZE 0x100
#define OXYGEN_EEPROM_ID 0x434d /* "CM" */
/* model-specific configuration of outputs/inputs */
#define PLAYBACK_0_TO_I2S 0x0001
/* PLAYBACK_0_TO_AC97_0 not implemented */
@ -49,7 +51,13 @@ enum {
.subvendor = sv, \
.subdevice = sd
#define BROKEN_EEPROM_DRIVER_DATA ((unsigned long)-1)
#define OXYGEN_PCI_SUBID_BROKEN_EEPROM \
OXYGEN_PCI_SUBID(PCI_VENDOR_ID_CMEDIA, 0x8788), \
.driver_data = BROKEN_EEPROM_DRIVER_DATA
struct pci_dev;
struct pci_device_id;
struct snd_card;
struct snd_pcm_substream;
struct snd_pcm_hardware;
@ -62,8 +70,6 @@ struct oxygen_model {
const char *shortname;
const char *longname;
const char *chip;
struct module *owner;
int (*probe)(struct oxygen *chip, unsigned long driver_data);
void (*init)(struct oxygen *chip);
int (*control_filter)(struct snd_kcontrol_new *template);
int (*mixer_init)(struct oxygen *chip);
@ -83,6 +89,7 @@ struct oxygen_model {
void (*ac97_switch)(struct oxygen *chip,
unsigned int reg, unsigned int mute);
const unsigned int *dac_tlv;
unsigned long private_data;
size_t model_data_size;
unsigned int device_config;
u8 dac_channels;
@ -134,8 +141,12 @@ struct oxygen {
/* oxygen_lib.c */
int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
const struct oxygen_model *model,
unsigned long driver_data);
struct module *owner,
const struct pci_device_id *ids,
int (*get_model)(struct oxygen *chip,
const struct pci_device_id *id
)
);
void oxygen_pci_remove(struct pci_dev *pci);
#ifdef CONFIG_PM
int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state);
@ -180,6 +191,9 @@ void oxygen_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data);
void oxygen_reset_uart(struct oxygen *chip);
void oxygen_write_uart(struct oxygen *chip, u8 data);
u16 oxygen_read_eeprom(struct oxygen *chip, unsigned int index);
void oxygen_write_eeprom(struct oxygen *chip, unsigned int index, u16 value);
static inline void oxygen_set_bits8(struct oxygen *chip,
unsigned int reg, u8 value)
{

@ -254,3 +254,34 @@ void oxygen_write_uart(struct oxygen *chip, u8 data)
_write_uart(chip, 0, data);
}
EXPORT_SYMBOL(oxygen_write_uart);
u16 oxygen_read_eeprom(struct oxygen *chip, unsigned int index)
{
unsigned int timeout;
oxygen_write8(chip, OXYGEN_EEPROM_CONTROL,
index | OXYGEN_EEPROM_DIR_READ);
for (timeout = 0; timeout < 100; ++timeout) {
udelay(1);
if (!(oxygen_read8(chip, OXYGEN_EEPROM_STATUS)
& OXYGEN_EEPROM_BUSY))
break;
}
return oxygen_read16(chip, OXYGEN_EEPROM_DATA);
}
void oxygen_write_eeprom(struct oxygen *chip, unsigned int index, u16 value)
{
unsigned int timeout;
oxygen_write16(chip, OXYGEN_EEPROM_DATA, value);
oxygen_write8(chip, OXYGEN_EEPROM_CONTROL,
index | OXYGEN_EEPROM_DIR_WRITE);
for (timeout = 0; timeout < 10; ++timeout) {
msleep(1);
if (!(oxygen_read8(chip, OXYGEN_EEPROM_STATUS)
& OXYGEN_EEPROM_BUSY))
return;
}
snd_printk(KERN_ERR "EEPROM write timeout\n");
}

@ -34,6 +34,7 @@ MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
MODULE_DESCRIPTION("C-Media CMI8788 helper library");
MODULE_LICENSE("GPL v2");
#define DRIVER "oxygen"
static inline int oxygen_uart_input_ready(struct oxygen *chip)
{
@ -243,6 +244,62 @@ static void oxygen_proc_init(struct oxygen *chip)
#define oxygen_proc_init(chip)
#endif
static const struct pci_device_id *
oxygen_search_pci_id(struct oxygen *chip, const struct pci_device_id ids[])
{
u16 subdevice;
/*
* Make sure the EEPROM pins are available, i.e., not used for SPI.
* (This function is called before we initialize or use SPI.)
*/
oxygen_clear_bits8(chip, OXYGEN_FUNCTION,
OXYGEN_FUNCTION_ENABLE_SPI_4_5);
/*
* Read the subsystem device ID directly from the EEPROM, because the
* chip didn't if the first EEPROM word was overwritten.
*/
subdevice = oxygen_read_eeprom(chip, 2);
/*
* We use only the subsystem device ID for searching because it is
* unique even without the subsystem vendor ID, which may have been
* overwritten in the EEPROM.
*/
for (; ids->vendor; ++ids)
if (ids->subdevice == subdevice &&
ids->driver_data != BROKEN_EEPROM_DRIVER_DATA)
return ids;
return NULL;
}
static void oxygen_restore_eeprom(struct oxygen *chip,
const struct pci_device_id *id)
{
if (oxygen_read_eeprom(chip, 0) != OXYGEN_EEPROM_ID) {
/*
* This function gets called only when a known card model has
* been detected, i.e., we know there is a valid subsystem
* product ID at index 2 in the EEPROM. Therefore, we have
* been able to deduce the correct subsystem vendor ID, and
* this is enough information to restore the original EEPROM
* contents.
*/
oxygen_write_eeprom(chip, 1, id->subvendor);
oxygen_write_eeprom(chip, 0, OXYGEN_EEPROM_ID);
oxygen_set_bits8(chip, OXYGEN_MISC,
OXYGEN_MISC_WRITE_PCI_SUBID);
pci_write_config_word(chip->pci, PCI_SUBSYSTEM_VENDOR_ID,
id->subvendor);
pci_write_config_word(chip->pci, PCI_SUBSYSTEM_ID,
id->subdevice);
oxygen_clear_bits8(chip, OXYGEN_MISC,
OXYGEN_MISC_WRITE_PCI_SUBID);
snd_printk(KERN_INFO "EEPROM ID restored\n");
}
}
static void oxygen_init(struct oxygen *chip)
{
unsigned int i;
@ -446,21 +503,26 @@ static void oxygen_card_free(struct snd_card *card)
free_irq(chip->irq, chip);
flush_scheduled_work();
chip->model.cleanup(chip);
kfree(chip->model_data);
mutex_destroy(&chip->mutex);
pci_release_regions(chip->pci);
pci_disable_device(chip->pci);
}
int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
const struct oxygen_model *model,
unsigned long driver_data)
struct module *owner,
const struct pci_device_id *ids,
int (*get_model)(struct oxygen *chip,
const struct pci_device_id *id
)
)
{
struct snd_card *card;
struct oxygen *chip;
const struct pci_device_id *pci_id;
int err;
err = snd_card_create(index, id, model->owner,
sizeof(*chip) + model->model_data_size, &card);
err = snd_card_create(index, id, owner, sizeof(*chip), &card);
if (err < 0)
return err;
@ -468,8 +530,6 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
chip->card = card;
chip->pci = pci;
chip->irq = -1;
chip->model = *model;
chip->model_data = chip + 1;
spin_lock_init(&chip->reg_lock);
mutex_init(&chip->mutex);
INIT_WORK(&chip->spdif_input_bits_work,
@ -481,7 +541,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
if (err < 0)
goto err_card;
err = pci_request_regions(pci, model->chip);
err = pci_request_regions(pci, DRIVER);
if (err < 0) {
snd_printk(KERN_ERR "cannot reserve PCI resources\n");
goto err_pci_enable;
@ -495,20 +555,34 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
}
chip->addr = pci_resource_start(pci, 0);
pci_id = oxygen_search_pci_id(chip, ids);
if (!pci_id) {
err = -ENODEV;
goto err_pci_regions;
}
oxygen_restore_eeprom(chip, pci_id);
err = get_model(chip, pci_id);
if (err < 0)
goto err_pci_regions;
if (chip->model.model_data_size) {
chip->model_data = kzalloc(chip->model.model_data_size,
GFP_KERNEL);
if (!chip->model_data) {
err = -ENOMEM;
goto err_pci_regions;
}
}
pci_set_master(pci);
snd_card_set_dev(card, &pci->dev);
card->private_free = oxygen_card_free;
if (chip->model.probe) {
err = chip->model.probe(chip, driver_data);
if (err < 0)
goto err_card;
}
oxygen_init(chip);
chip->model.init(chip);
err = request_irq(pci->irq, oxygen_interrupt, IRQF_SHARED,
chip->model.chip, chip);
DRIVER, chip);
if (err < 0) {
snd_printk(KERN_ERR "cannot grab interrupt %d\n", pci->irq);
goto err_card;

@ -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,8 @@ 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 },
{ }
};
MODULE_DEVICE_TABLE(pci, xonar_ids);
@ -183,12 +214,14 @@ 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 */
struct xonar_data {
unsigned int model;
unsigned int anti_pop_delay;
unsigned int dacs;
u16 output_enable_bit;
@ -334,15 +367,9 @@ static void xonar_d2_init(struct oxygen *chip)
struct xonar_data *data = chip->model_data;
data->anti_pop_delay = 300;
data->dacs = 4;
data->output_enable_bit = GPIO_D2_OUTPUT_ENABLE;
data->pcm1796_oversampling = PCM1796_OS_64;
if (data->model == MODEL_D2X) {
data->ext_power_reg = OXYGEN_GPIO_DATA;
data->ext_power_int_reg = OXYGEN_GPIO_INTERRUPT_MASK;
data->ext_power_bit = GPIO_D2X_EXT_POWER;
oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
GPIO_D2X_EXT_POWER);
}
pcm1796_init(chip);
@ -355,6 +382,18 @@ static void xonar_d2_init(struct oxygen *chip)
snd_component_add(chip->card, "CS5381");
}
static void xonar_d2x_init(struct oxygen *chip)
{
struct xonar_data *data = chip->model_data;
data->ext_power_reg = OXYGEN_GPIO_DATA;
data->ext_power_int_reg = OXYGEN_GPIO_INTERRUPT_MASK;
data->ext_power_bit = GPIO_D2X_EXT_POWER;
oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2X_EXT_POWER);
xonar_d2_init(chip);
}
static void update_cs4362a_volumes(struct oxygen *chip)
{
u8 mute;
@ -422,11 +461,6 @@ static void xonar_d1_init(struct oxygen *chip)
data->cs4398_fm = CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST;
data->cs4362a_fm = CS4362A_FM_SINGLE |
CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L;
if (data->model == MODEL_DX) {
data->ext_power_reg = OXYGEN_GPI_DATA;
data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
data->ext_power_bit = GPI_DX_EXT_POWER;
}
oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
OXYGEN_2WIRE_LENGTH_8 |
@ -447,6 +481,17 @@ static void xonar_d1_init(struct oxygen *chip)
snd_component_add(chip->card, "CS5361");
}
static void xonar_dx_init(struct oxygen *chip)
{
struct xonar_data *data = chip->model_data;
data->ext_power_reg = OXYGEN_GPI_DATA;
data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
data->ext_power_bit = GPI_DX_EXT_POWER;
xonar_d1_init(chip);
}
static void xonar_hdav_init(struct oxygen *chip)
{
struct xonar_data *data = chip->model_data;
@ -458,6 +503,7 @@ static void xonar_hdav_init(struct oxygen *chip)
OXYGEN_2WIRE_SPEED_FAST);
data->anti_pop_delay = 100;
data->dacs = chip->model.private_data == MODEL_HDAV_H6 ? 4 : 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;
@ -484,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;
@ -511,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);
@ -527,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);
@ -554,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)
{
@ -733,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)
{
@ -745,8 +903,8 @@ static void xonar_line_mic_ac97_switch(struct oxygen *chip,
}
}
static const DECLARE_TLV_DB_SCALE(pcm1796_db_scale, -12000, 50, 0);
static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -12700, 100, 0);
static const DECLARE_TLV_DB_SCALE(pcm1796_db_scale, -6000, 50, 0);
static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -6000, 100, 0);
static int xonar_d2_control_filter(struct snd_kcontrol_new *template)
{
@ -763,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));
@ -773,51 +940,14 @@ 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_model_probe(struct oxygen *chip, unsigned long driver_data)
static int xonar_st_mixer_init(struct oxygen *chip)
{
static const char *const names[] = {
[MODEL_D1] = "Xonar D1",
[MODEL_DX] = "Xonar DX",
[MODEL_D2] = "Xonar D2",
[MODEL_D2X] = "Xonar D2X",
[MODEL_HDAV] = "Xonar HDAV1.3",
[MODEL_HDAV_H6] = "Xonar HDAV1.3+H6",
};
static const u8 dacs[] = {
[MODEL_D1] = 2,
[MODEL_DX] = 2,
[MODEL_D2] = 4,
[MODEL_D2X] = 4,
[MODEL_HDAV] = 1,
[MODEL_HDAV_H6] = 4,
};
struct xonar_data *data = chip->model_data;
data->model = driver_data;
if (data->model == MODEL_HDAV) {
oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
GPIO_HDAV_DB_MASK);
switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) &
GPIO_HDAV_DB_MASK) {
case GPIO_HDAV_DB_H6:
data->model = MODEL_HDAV_H6;
break;
case GPIO_HDAV_DB_XX:
snd_printk(KERN_ERR "unknown daughterboard\n");
return -ENODEV;
}
}
data->dacs = dacs[data->model];
chip->model.shortname = names[data->model];
return 0;
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",
.owner = THIS_MODULE,
.probe = xonar_model_probe,
.init = xonar_d2_init,
.control_filter = xonar_d2_control_filter,
.mixer_init = xonar_d2_mixer_init,
@ -837,8 +967,8 @@ static const struct oxygen_model model_xonar_d2 = {
MIDI_OUTPUT |
MIDI_INPUT,
.dac_channels = 8,
.dac_volume_min = 0x0f,
.dac_volume_max = 0xff,
.dac_volume_min = 255 - 2*60,
.dac_volume_max = 255,
.misc_flags = OXYGEN_MISC_MIDI,
.function_flags = OXYGEN_FUNCTION_SPI |
OXYGEN_FUNCTION_ENABLE_SPI_4_5,
@ -849,8 +979,6 @@ static const struct oxygen_model model_xonar_d2 = {
static const struct oxygen_model model_xonar_d1 = {
.longname = "Asus Virtuoso 100",
.chip = "AV200",
.owner = THIS_MODULE,
.probe = xonar_model_probe,
.init = xonar_d1_init,
.control_filter = xonar_d1_control_filter,
.mixer_init = xonar_d1_mixer_init,
@ -868,7 +996,7 @@ static const struct oxygen_model model_xonar_d1 = {
PLAYBACK_1_TO_SPDIF |
CAPTURE_0_FROM_I2S_2,
.dac_channels = 8,
.dac_volume_min = 0,
.dac_volume_min = 127 - 60,
.dac_volume_max = 127,
.function_flags = OXYGEN_FUNCTION_2WIRE,
.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
@ -878,8 +1006,6 @@ static const struct oxygen_model model_xonar_d1 = {
static const struct oxygen_model model_xonar_hdav = {
.longname = "Asus Virtuoso 200",
.chip = "AV200",
.owner = THIS_MODULE,
.probe = xonar_model_probe,
.init = xonar_hdav_init,
.cleanup = xonar_hdav_cleanup,
.suspend = xonar_hdav_suspend,
@ -897,16 +1023,43 @@ static const struct oxygen_model model_xonar_hdav = {
PLAYBACK_1_TO_SPDIF |
CAPTURE_0_FROM_I2S_2,
.dac_channels = 8,
.dac_volume_min = 0x0f,
.dac_volume_max = 0xff,
.dac_volume_min = 255 - 2*60,
.dac_volume_max = 255,
.misc_flags = OXYGEN_MISC_MIDI,
.function_flags = OXYGEN_FUNCTION_2WIRE,
.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
};
static int __devinit xonar_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
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)
{
static const struct oxygen_model *const models[] = {
[MODEL_D1] = &model_xonar_d1,
@ -914,7 +1067,57 @@ static int __devinit xonar_probe(struct pci_dev *pci,
[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",
[MODEL_DX] = "Xonar DX",
[MODEL_D2] = "Xonar D2",
[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;
if (model >= ARRAY_SIZE(models) || !models[model])
return -EINVAL;
chip->model = *models[model];
switch (model) {
case MODEL_D2X:
chip->model.init = xonar_d2x_init;
break;
case MODEL_DX:
chip->model.init = xonar_dx_init;
break;
case MODEL_HDAV:
oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
GPIO_HDAV_DB_MASK);
switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) &
GPIO_HDAV_DB_MASK) {
case GPIO_HDAV_DB_H6:
model = MODEL_HDAV_H6;
break;
case GPIO_HDAV_DB_XX:
snd_printk(KERN_ERR "unknown daughterboard\n");
return -ENODEV;
}
break;
case MODEL_STX:
oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
GPIO_HDAV_DB_MASK);
break;
}
chip->model.shortname = names[model];
chip->model.private_data = model;
return 0;
}
static int __devinit xonar_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
{
static int dev;
int err;
@ -924,10 +1127,8 @@ static int __devinit xonar_probe(struct pci_dev *pci,
++dev;
return -ENOENT;
}
BUG_ON(pci_id->driver_data >= ARRAY_SIZE(models));
err = oxygen_pci_probe(pci, index[dev], id[dev],
models[pci_id->driver_data],
pci_id->driver_data);
err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE,
xonar_ids, get_xonar_model);
if (err >= 0)
++dev;
return err;

Loading…
Cancel
Save