aboutsummaryrefslogtreecommitdiff
path: root/sound/pci/oxygen/oxygen_lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/oxygen/oxygen_lib.c')
-rw-r--r--sound/pci/oxygen/oxygen_lib.c193
1 files changed, 125 insertions, 68 deletions
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c
index 9c5e6450eeb..b67e3060247 100644
--- a/sound/pci/oxygen/oxygen_lib.c
+++ b/sound/pci/oxygen/oxygen_lib.c
@@ -21,6 +21,8 @@
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/module.h>
#include <sound/ac97_codec.h>
#include <sound/asoundef.h>
#include <sound/core.h>
@@ -201,7 +203,13 @@ static void oxygen_proc_read(struct snd_info_entry *entry,
struct oxygen *chip = entry->private_data;
int i, j;
- snd_iprintf(buffer, "CMI8788\n\n");
+ switch (oxygen_read8(chip, OXYGEN_REVISION) & OXYGEN_PACKAGE_ID_MASK) {
+ case OXYGEN_PACKAGE_ID_8786: i = '6'; break;
+ case OXYGEN_PACKAGE_ID_8787: i = '7'; break;
+ case OXYGEN_PACKAGE_ID_8788: i = '8'; break;
+ default: i = '?'; break;
+ }
+ snd_iprintf(buffer, "CMI878%c:\n", i);
for (i = 0; i < OXYGEN_IO_SIZE; i += 0x10) {
snd_iprintf(buffer, "%02x:", i);
for (j = 0; j < 0x10; ++j)
@@ -211,7 +219,7 @@ static void oxygen_proc_read(struct snd_info_entry *entry,
if (mutex_lock_interruptible(&chip->mutex) < 0)
return;
if (chip->has_ac97_0) {
- snd_iprintf(buffer, "\nAC97\n");
+ snd_iprintf(buffer, "\nAC97:\n");
for (i = 0; i < 0x80; i += 0x10) {
snd_iprintf(buffer, "%02x:", i);
for (j = 0; j < 0x10; j += 2)
@@ -221,7 +229,7 @@ static void oxygen_proc_read(struct snd_info_entry *entry,
}
}
if (chip->has_ac97_1) {
- snd_iprintf(buffer, "\nAC97 2\n");
+ snd_iprintf(buffer, "\nAC97 2:\n");
for (i = 0; i < 0x80; i += 0x10) {
snd_iprintf(buffer, "%02x:", i);
for (j = 0; j < 0x10; j += 2)
@@ -231,13 +239,15 @@ static void oxygen_proc_read(struct snd_info_entry *entry,
}
}
mutex_unlock(&chip->mutex);
+ if (chip->model.dump_registers)
+ chip->model.dump_registers(chip, buffer);
}
static void oxygen_proc_init(struct oxygen *chip)
{
struct snd_info_entry *entry;
- if (!snd_card_proc_new(chip->card, "cmi8788", &entry))
+ if (!snd_card_proc_new(chip->card, "oxygen", &entry))
snd_info_set_text_ops(entry, chip, oxygen_proc_read);
}
#else
@@ -261,7 +271,7 @@ oxygen_search_pci_id(struct oxygen *chip, const struct pci_device_id ids[])
*/
subdevice = oxygen_read_eeprom(chip, 2);
/* use default ID if EEPROM is missing */
- if (subdevice == 0xffff)
+ if (subdevice == 0xffff && oxygen_read_eeprom(chip, 1) == 0xffff)
subdevice = 0x8788;
/*
* We use only the subsystem device ID for searching because it is
@@ -303,29 +313,50 @@ static void oxygen_restore_eeprom(struct oxygen *chip,
oxygen_clear_bits8(chip, OXYGEN_MISC,
OXYGEN_MISC_WRITE_PCI_SUBID);
- snd_printk(KERN_INFO "EEPROM ID restored\n");
+ dev_info(chip->card->dev, "EEPROM ID restored\n");
}
}
-static void pci_bridge_magic(void)
+static void configure_pcie_bridge(struct pci_dev *pci)
{
- struct pci_dev *pci = NULL;
+ enum { PEX811X, PI7C9X110 };
+ static const struct pci_device_id bridge_ids[] = {
+ { PCI_VDEVICE(PLX, 0x8111), .driver_data = PEX811X },
+ { PCI_VDEVICE(PLX, 0x8112), .driver_data = PEX811X },
+ { PCI_DEVICE(0x12d8, 0xe110), .driver_data = PI7C9X110 },
+ { }
+ };
+ struct pci_dev *bridge;
+ const struct pci_device_id *id;
u32 tmp;
- for (;;) {
- /* If there is any Pericom PI7C9X110 PCI-E/PCI bridge ... */
- pci = pci_get_device(0x12d8, 0xe110, pci);
- if (!pci)
- break;
- /*
- * ... configure its secondary internal arbiter to park to
- * the secondary port, instead of to the last master.
- */
- if (!pci_read_config_dword(pci, 0x40, &tmp)) {
- tmp |= 1;
- pci_write_config_dword(pci, 0x40, tmp);
- }
- /* Why? Try asking C-Media. */
+ if (!pci->bus || !pci->bus->self)
+ return;
+ bridge = pci->bus->self;
+
+ id = pci_match_id(bridge_ids, bridge);
+ if (!id)
+ return;
+
+ switch (id->driver_data) {
+ case PEX811X: /* PLX PEX8111/PEX8112 PCIe/PCI bridge */
+ pci_read_config_dword(bridge, 0x48, &tmp);
+ tmp |= 1; /* enable blind prefetching */
+ tmp |= 1 << 11; /* enable beacon generation */
+ pci_write_config_dword(bridge, 0x48, tmp);
+
+ pci_write_config_dword(bridge, 0x84, 0x0c);
+ pci_read_config_dword(bridge, 0x88, &tmp);
+ tmp &= ~(7 << 27);
+ tmp |= 2 << 27; /* set prefetch size to 128 bytes */
+ pci_write_config_dword(bridge, 0x88, tmp);
+ break;
+
+ case PI7C9X110: /* Pericom PI7C9X110 PCIe/PCI bridge */
+ pci_read_config_dword(bridge, 0x40, &tmp);
+ tmp |= 1; /* park the PCI arbiter to the sound chip */
+ pci_write_config_dword(bridge, 0x40, tmp);
+ break;
}
}
@@ -342,12 +373,7 @@ static void oxygen_init(struct oxygen *chip)
(IEC958_AES1_CON_PCM_CODER << OXYGEN_SPDIF_CATEGORY_SHIFT);
chip->spdif_pcm_bits = chip->spdif_bits;
- if (oxygen_read8(chip, OXYGEN_REVISION) & OXYGEN_REVISION_2)
- chip->revision = 2;
- else
- chip->revision = 1;
-
- if (chip->revision == 1)
+ if (!(oxygen_read8(chip, OXYGEN_REVISION) & OXYGEN_REVISION_2))
oxygen_set_bits8(chip, OXYGEN_MISC,
OXYGEN_MISC_PCI_MEM_W_1_CLOCK);
@@ -384,28 +410,40 @@ static void oxygen_init(struct oxygen *chip)
(OXYGEN_FORMAT_16 << OXYGEN_MULTICH_FORMAT_SHIFT));
oxygen_write8(chip, OXYGEN_REC_CHANNELS, OXYGEN_REC_CHANNELS_2_2_2);
oxygen_write16(chip, OXYGEN_I2S_MULTICH_FORMAT,
- OXYGEN_RATE_48000 | chip->model.dac_i2s_format |
- OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 |
- OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
+ OXYGEN_RATE_48000 |
+ chip->model.dac_i2s_format |
+ OXYGEN_I2S_MCLK(chip->model.dac_mclks) |
+ OXYGEN_I2S_BITS_16 |
+ OXYGEN_I2S_MASTER |
+ OXYGEN_I2S_BCLK_64);
if (chip->model.device_config & CAPTURE_0_FROM_I2S_1)
oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
- OXYGEN_RATE_48000 | chip->model.adc_i2s_format |
- OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 |
- OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
+ OXYGEN_RATE_48000 |
+ chip->model.adc_i2s_format |
+ OXYGEN_I2S_MCLK(chip->model.adc_mclks) |
+ OXYGEN_I2S_BITS_16 |
+ OXYGEN_I2S_MASTER |
+ OXYGEN_I2S_BCLK_64);
else
oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
- OXYGEN_I2S_MASTER | OXYGEN_I2S_MUTE_MCLK);
+ OXYGEN_I2S_MASTER |
+ OXYGEN_I2S_MUTE_MCLK);
if (chip->model.device_config & (CAPTURE_0_FROM_I2S_2 |
CAPTURE_2_FROM_I2S_2))
oxygen_write16(chip, OXYGEN_I2S_B_FORMAT,
- OXYGEN_RATE_48000 | chip->model.adc_i2s_format |
- OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 |
- OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
+ OXYGEN_RATE_48000 |
+ chip->model.adc_i2s_format |
+ OXYGEN_I2S_MCLK(chip->model.adc_mclks) |
+ OXYGEN_I2S_BITS_16 |
+ OXYGEN_I2S_MASTER |
+ OXYGEN_I2S_BCLK_64);
else
oxygen_write16(chip, OXYGEN_I2S_B_FORMAT,
- OXYGEN_I2S_MASTER | OXYGEN_I2S_MUTE_MCLK);
+ OXYGEN_I2S_MASTER |
+ OXYGEN_I2S_MUTE_MCLK);
oxygen_write16(chip, OXYGEN_I2S_C_FORMAT,
- OXYGEN_I2S_MASTER | OXYGEN_I2S_MUTE_MCLK);
+ OXYGEN_I2S_MASTER |
+ OXYGEN_I2S_MUTE_MCLK);
oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL,
OXYGEN_SPDIF_OUT_ENABLE |
OXYGEN_SPDIF_LOOPBACK);
@@ -518,19 +556,25 @@ static void oxygen_init(struct oxygen *chip)
}
}
-static void oxygen_card_free(struct snd_card *card)
+static void oxygen_shutdown(struct oxygen *chip)
{
- struct oxygen *chip = card->private_data;
-
spin_lock_irq(&chip->reg_lock);
chip->interrupt_mask = 0;
chip->pcm_running = 0;
oxygen_write16(chip, OXYGEN_DMA_STATUS, 0);
oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0);
spin_unlock_irq(&chip->reg_lock);
+}
+
+static void oxygen_card_free(struct snd_card *card)
+{
+ struct oxygen *chip = card->private_data;
+
+ oxygen_shutdown(chip);
if (chip->irq >= 0)
free_irq(chip->irq, chip);
- flush_scheduled_work();
+ flush_work(&chip->spdif_input_bits_work);
+ flush_work(&chip->gpio_work);
chip->model.cleanup(chip);
kfree(chip->model_data);
mutex_destroy(&chip->mutex);
@@ -551,7 +595,8 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
const struct pci_device_id *pci_id;
int err;
- err = snd_card_create(index, id, owner, sizeof(*chip), &card);
+ err = snd_card_new(&pci->dev, index, id, owner,
+ sizeof(*chip), &card);
if (err < 0)
return err;
@@ -572,13 +617,13 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
err = pci_request_regions(pci, DRIVER);
if (err < 0) {
- snd_printk(KERN_ERR "cannot reserve PCI resources\n");
+ dev_err(card->dev, "cannot reserve PCI resources\n");
goto err_pci_enable;
}
if (!(pci_resource_flags(pci, 0) & IORESOURCE_IO) ||
pci_resource_len(pci, 0) < OXYGEN_IO_SIZE) {
- snd_printk(KERN_ERR "invalid PCI I/O range\n");
+ dev_err(card->dev, "invalid PCI I/O range\n");
err = -ENXIO;
goto err_pci_regions;
}
@@ -604,25 +649,24 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
}
pci_set_master(pci);
- snd_card_set_dev(card, &pci->dev);
card->private_free = oxygen_card_free;
- pci_bridge_magic();
+ configure_pcie_bridge(pci);
oxygen_init(chip);
chip->model.init(chip);
err = request_irq(pci->irq, oxygen_interrupt, IRQF_SHARED,
- DRIVER, chip);
+ KBUILD_MODNAME, chip);
if (err < 0) {
- snd_printk(KERN_ERR "cannot grab interrupt %d\n", pci->irq);
+ dev_err(card->dev, "cannot grab interrupt %d\n", pci->irq);
goto err_card;
}
chip->irq = pci->irq;
strcpy(card->driver, chip->model.chip);
strcpy(card->shortname, chip->model.shortname);
- sprintf(card->longname, "%s (rev %u) at %#lx, irq %i",
- chip->model.longname, chip->revision, chip->addr, chip->irq);
+ sprintf(card->longname, "%s at %#lx, irq %i",
+ chip->model.longname, chip->addr, chip->irq);
strcpy(card->mixername, chip->model.chip);
snd_component_add(card, chip->model.chip);
@@ -635,15 +679,15 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
goto err_card;
if (chip->model.device_config & (MIDI_OUTPUT | MIDI_INPUT)) {
- unsigned int info_flags = MPU401_INFO_INTEGRATED;
+ unsigned int info_flags =
+ MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK;
if (chip->model.device_config & MIDI_OUTPUT)
info_flags |= MPU401_INFO_OUTPUT;
if (chip->model.device_config & MIDI_INPUT)
info_flags |= MPU401_INFO_INPUT;
err = snd_mpu401_uart_new(card, 0, MPU401_HW_CMIPCI,
chip->addr + OXYGEN_MPU401,
- info_flags, 0, 0,
- &chip->midi);
+ info_flags, -1, &chip->midi);
if (err < 0)
goto err_card;
}
@@ -678,14 +722,14 @@ EXPORT_SYMBOL(oxygen_pci_probe);
void oxygen_pci_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
EXPORT_SYMBOL(oxygen_pci_remove);
-#ifdef CONFIG_PM
-int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int oxygen_pci_suspend(struct device *dev)
{
- struct snd_card *card = pci_get_drvdata(pci);
+ struct pci_dev *pci = to_pci_dev(dev);
+ struct snd_card *card = dev_get_drvdata(dev);
struct oxygen *chip = card->private_data;
unsigned int i, saved_interrupt_mask;
@@ -706,15 +750,15 @@ int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state)
spin_unlock_irq(&chip->reg_lock);
synchronize_irq(chip->irq);
- flush_scheduled_work();
+ flush_work(&chip->spdif_input_bits_work);
+ flush_work(&chip->gpio_work);
chip->interrupt_mask = saved_interrupt_mask;
pci_disable_device(pci);
pci_save_state(pci);
- pci_set_power_state(pci, pci_choose_state(pci, state));
+ pci_set_power_state(pci, PCI_D3hot);
return 0;
}
-EXPORT_SYMBOL(oxygen_pci_suspend);
static const u32 registers_to_restore[OXYGEN_IO_SIZE / 32] = {
0xffffffff, 0x00ff077f, 0x00011d08, 0x007f00ff,
@@ -742,16 +786,17 @@ static void oxygen_restore_ac97(struct oxygen *chip, unsigned int codec)
chip->saved_ac97_registers[codec][i]);
}
-int oxygen_pci_resume(struct pci_dev *pci)
+static int oxygen_pci_resume(struct device *dev)
{
- struct snd_card *card = pci_get_drvdata(pci);
+ struct pci_dev *pci = to_pci_dev(dev);
+ struct snd_card *card = dev_get_drvdata(dev);
struct oxygen *chip = card->private_data;
unsigned int i;
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- snd_printk(KERN_ERR "cannot reenable device");
+ dev_err(dev, "cannot reenable device");
snd_card_disconnect(card);
return -EIO;
}
@@ -775,5 +820,17 @@ int oxygen_pci_resume(struct pci_dev *pci)
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
return 0;
}
-EXPORT_SYMBOL(oxygen_pci_resume);
-#endif /* CONFIG_PM */
+
+SIMPLE_DEV_PM_OPS(oxygen_pci_pm, oxygen_pci_suspend, oxygen_pci_resume);
+EXPORT_SYMBOL(oxygen_pci_pm);
+#endif /* CONFIG_PM_SLEEP */
+
+void oxygen_pci_shutdown(struct pci_dev *pci)
+{
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct oxygen *chip = card->private_data;
+
+ oxygen_shutdown(chip);
+ chip->model.cleanup(chip);
+}
+EXPORT_SYMBOL(oxygen_pci_shutdown);