Skip to content

Commit

Permalink
Merge branch 'topic/oxygen' into for-linus
Browse files Browse the repository at this point in the history
  • Loading branch information
Takashi Iwai committed Mar 23, 2009
2 parents 9fb5430 + 873591d commit b54fc8d
Show file tree
Hide file tree
Showing 8 changed files with 507 additions and 116 deletions.
2 changes: 1 addition & 1 deletion Documentation/sound/alsa/ALSA-Configuration.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
3 changes: 2 additions & 1 deletion sound/pci/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 10 additions & 2 deletions sound/pci/oxygen/hifier.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand All @@ -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)
{
Expand All @@ -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;
Expand Down
114 changes: 88 additions & 26 deletions sound/pci/oxygen/oxygen.c
Original file line number Diff line number Diff line change
@@ -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>
*
Expand All @@ -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>
Expand Down Expand Up @@ -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 = {
Expand All @@ -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);
Expand All @@ -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];
Expand Down Expand Up @@ -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);
Expand All @@ -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)
{
Expand Down Expand Up @@ -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,
Expand All @@ -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)
{
Expand All @@ -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;
Expand Down
22 changes: 18 additions & 4 deletions sound/pci/oxygen/oxygen.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
{
Expand Down
31 changes: 31 additions & 0 deletions sound/pci/oxygen/oxygen_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
Loading

0 comments on commit b54fc8d

Please sign in to comment.