ALSA: hda - Fix invalid D3 of headphone DAC on VT202x codecs
[linux-2.6.git] / sound / pci / sis7019.c
index 614ff6e..ff500a8 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/pci.h>
 #include <linux/time.h>
 #include <linux/slab.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <sound/core.h>
@@ -40,7 +40,8 @@ MODULE_SUPPORTED_DEVICE("{{SiS,SiS7019 Audio Accelerator}}");
 
 static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
 static char *id = SNDRV_DEFAULT_STR1;  /* ID for this card */
-static int enable = 1;
+static bool enable = 1;
+static int codecs = 1;
 
 module_param(index, int, 0444);
 MODULE_PARM_DESC(index, "Index value for SiS7019 Audio Accelerator.");
@@ -48,6 +49,8 @@ module_param(id, charp, 0444);
 MODULE_PARM_DESC(id, "ID string for SiS7019 Audio Accelerator.");
 module_param(enable, bool, 0444);
 MODULE_PARM_DESC(enable, "Enable SiS7019 Audio Accelerator.");
+module_param(codecs, int, 0444);
+MODULE_PARM_DESC(codecs, "Set bit to indicate that codec number is expected to be present (default 1)");
 
 static DEFINE_PCI_DEVICE_TABLE(snd_sis7019_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x7019) },
@@ -140,6 +143,9 @@ struct sis7019 {
        dma_addr_t silence_dma_addr;
 };
 
+/* These values are also used by the module param 'codecs' to indicate
+ * which codecs should be present.
+ */
 #define SIS_PRIMARY_CODEC_PRESENT      0x0001
 #define SIS_SECONDARY_CODEC_PRESENT    0x0002
 #define SIS_TERTIARY_CODEC_PRESENT     0x0004
@@ -308,7 +314,7 @@ static irqreturn_t sis_interrupt(int irq, void *dev)
        u32 intr, status;
 
        /* We only use the DMA interrupts, and we don't enable any other
-        * source of interrupts. But, it is possible to see an interupt
+        * source of interrupts. But, it is possible to see an interrupt
         * status that didn't actually interrupt us, so eliminate anything
         * we're not expecting to avoid falsely claiming an IRQ, and an
         * ensuing endless loop.
@@ -773,7 +779,7 @@ static void sis_prepare_timing_voice(struct voice *voice,
                vperiod = 0;
        }
 
-       /* The interrupt handler implements the timing syncronization, so
+       /* The interrupt handler implements the timing synchronization, so
         * setup its state.
         */
        timing->flags |= VOICE_SYNC_TIMING;
@@ -977,7 +983,7 @@ timeout:
        mutex_unlock(&sis->ac97_mutex);
 
        if (!count) {
-               printk(KERN_ERR "sis7019: ac97 codec %d timeout cmd 0x%08x\n",
+               dev_err(&sis->pci->dev, "ac97 codec %d timeout cmd 0x%08x\n",
                                        codec, cmd);
        }
 
@@ -1049,7 +1055,7 @@ static int sis_chip_free(struct sis7019 *sis)
        /* Reset the chip, and disable all interrputs.
         */
        outl(SIS_GCR_SOFTWARE_RESET, sis->ioport + SIS_GCR);
-       udelay(10);
+       udelay(25);
        outl(0, sis->ioport + SIS_GCR);
        outl(0, sis->ioport + SIS_GIER);
 
@@ -1078,6 +1084,7 @@ static int sis_chip_init(struct sis7019 *sis)
 {
        unsigned long io = sis->ioport;
        void __iomem *ioaddr = sis->ioaddr;
+       unsigned long timeout;
        u16 status;
        int count;
        int i;
@@ -1085,7 +1092,7 @@ static int sis_chip_init(struct sis7019 *sis)
        /* Reset the audio controller
         */
        outl(SIS_GCR_SOFTWARE_RESET, io + SIS_GCR);
-       udelay(10);
+       udelay(25);
        outl(0, io + SIS_GCR);
 
        /* Get the AC-link semaphore, and reset the codecs
@@ -1098,27 +1105,51 @@ static int sis_chip_init(struct sis7019 *sis)
                return -EIO;
 
        outl(SIS_AC97_CMD_CODEC_COLD_RESET, io + SIS_AC97_CMD);
-       udelay(10);
+       udelay(250);
 
        count = 0xffff;
        while ((inw(io + SIS_AC97_STATUS) & SIS_AC97_STATUS_BUSY) && --count)
                udelay(1);
 
+       /* Command complete, we can let go of the semaphore now.
+        */
+       outl(SIS_AC97_SEMA_RELEASE, io + SIS_AC97_SEMA);
+       if (!count)
+               return -EIO;
+
        /* Now that we've finished the reset, find out what's attached.
+        * There are some codec/board combinations that take an extremely
+        * long time to come up. 350+ ms has been observed in the field,
+        * so we'll give them up to 500ms.
         */
-       status = inl(io + SIS_AC97_STATUS);
-       if (status & SIS_AC97_STATUS_CODEC_READY)
-               sis->codecs_present |= SIS_PRIMARY_CODEC_PRESENT;
-       if (status & SIS_AC97_STATUS_CODEC2_READY)
-               sis->codecs_present |= SIS_SECONDARY_CODEC_PRESENT;
-       if (status & SIS_AC97_STATUS_CODEC3_READY)
-               sis->codecs_present |= SIS_TERTIARY_CODEC_PRESENT;
-
-       /* All done, let go of the semaphore, and check for errors
+       sis->codecs_present = 0;
+       timeout = msecs_to_jiffies(500) + jiffies;
+       while (time_before_eq(jiffies, timeout)) {
+               status = inl(io + SIS_AC97_STATUS);
+               if (status & SIS_AC97_STATUS_CODEC_READY)
+                       sis->codecs_present |= SIS_PRIMARY_CODEC_PRESENT;
+               if (status & SIS_AC97_STATUS_CODEC2_READY)
+                       sis->codecs_present |= SIS_SECONDARY_CODEC_PRESENT;
+               if (status & SIS_AC97_STATUS_CODEC3_READY)
+                       sis->codecs_present |= SIS_TERTIARY_CODEC_PRESENT;
+
+               if (sis->codecs_present == codecs)
+                       break;
+
+               msleep(1);
+       }
+
+       /* All done, check for errors.
         */
-       outl(SIS_AC97_SEMA_RELEASE, io + SIS_AC97_SEMA);
-       if (!sis->codecs_present || !count)
+       if (!sis->codecs_present) {
+               dev_err(&sis->pci->dev, "could not find any codecs\n");
                return -EIO;
+       }
+
+       if (sis->codecs_present != codecs) {
+               dev_warn(&sis->pci->dev, "missing codecs, found %0x, expected %0x\n",
+                                        sis->codecs_present, codecs);
+       }
 
        /* Let the hardware know that the audio driver is alive,
         * and enable PCM slots on the AC-link for L/R playback (3 & 4) and
@@ -1139,7 +1170,7 @@ static int sis_chip_init(struct sis7019 *sis)
         */
        outl(SIS_DMA_CSR_PCI_SETTINGS, io + SIS_DMA_CSR);
 
-       /* Reset the syncronization groups for all of the channels
+       /* Reset the synchronization groups for all of the channels
         * to be asyncronous. If we start doing SPDIF or 5.1 sound, etc.
         * we'll need to change how we handle these. Until then, we just
         * assign sub-mixer 0 to all playback channels, and avoid any
@@ -1225,18 +1256,18 @@ static int sis_resume(struct pci_dev *pci)
        pci_restore_state(pci);
 
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "sis7019: unable to re-enable device\n");
+               dev_err(&pci->dev, "unable to re-enable device\n");
                goto error;
        }
 
        if (sis_chip_init(sis)) {
-               printk(KERN_ERR "sis7019: unable to re-init controller\n");
+               dev_err(&pci->dev, "unable to re-init controller\n");
                goto error;
        }
 
-       if (request_irq(pci->irq, sis_interrupt, IRQF_DISABLED|IRQF_SHARED,
-                               card->shortname, sis)) {
-               printk(KERN_ERR "sis7019: unable to regain IRQ %d\n", pci->irq);
+       if (request_irq(pci->irq, sis_interrupt, IRQF_SHARED,
+                       KBUILD_MODNAME, sis)) {
+               dev_err(&pci->dev, "unable to regain IRQ %d\n", pci->irq);
                goto error;
        }
 
@@ -1304,8 +1335,7 @@ static int __devinit sis_chip_create(struct snd_card *card,
                goto error_out;
 
        if (pci_set_dma_mask(pci, DMA_BIT_MASK(30)) < 0) {
-               printk(KERN_ERR "sis7019: architecture does not support "
-                                       "30-bit PCI busmaster DMA");
+               dev_err(&pci->dev, "architecture does not support 30-bit PCI busmaster DMA");
                goto error_out_enabled;
        }
 
@@ -1319,20 +1349,20 @@ static int __devinit sis_chip_create(struct snd_card *card,
 
        rc = pci_request_regions(pci, "SiS7019");
        if (rc) {
-               printk(KERN_ERR "sis7019: unable request regions\n");
+               dev_err(&pci->dev, "unable request regions\n");
                goto error_out_enabled;
        }
 
        rc = -EIO;
        sis->ioaddr = ioremap_nocache(pci_resource_start(pci, 1), 0x4000);
        if (!sis->ioaddr) {
-               printk(KERN_ERR "sis7019: unable to remap MMIO, aborting\n");
+               dev_err(&pci->dev, "unable to remap MMIO, aborting\n");
                goto error_out_cleanup;
        }
 
        rc = sis_alloc_suspend(sis);
        if (rc < 0) {
-               printk(KERN_ERR "sis7019: unable to allocate state storage\n");
+               dev_err(&pci->dev, "unable to allocate state storage\n");
                goto error_out_cleanup;
        }
 
@@ -1340,9 +1370,9 @@ static int __devinit sis_chip_create(struct snd_card *card,
        if (rc)
                goto error_out_cleanup;
 
-       if (request_irq(pci->irq, sis_interrupt, IRQF_DISABLED|IRQF_SHARED,
-                               card->shortname, sis)) {
-               printk(KERN_ERR "unable to allocate irq %d\n", sis->irq);
+       if (request_irq(pci->irq, sis_interrupt, IRQF_SHARED, KBUILD_MODNAME,
+                       sis)) {
+               dev_err(&pci->dev, "unable to allocate irq %d\n", sis->irq);
                goto error_out_cleanup;
        }
 
@@ -1390,6 +1420,17 @@ static int __devinit snd_sis7019_probe(struct pci_dev *pci,
        if (!enable)
                goto error_out;
 
+       /* The user can specify which codecs should be present so that we
+        * can wait for them to show up if they are slow to recover from
+        * the AC97 cold reset. We default to a single codec, the primary.
+        *
+        * We assume that SIS_PRIMARY_*_PRESENT matches bits 0-2.
+        */
+       codecs &= SIS_PRIMARY_CODEC_PRESENT | SIS_SECONDARY_CODEC_PRESENT |
+                 SIS_TERTIARY_CODEC_PRESENT;
+       if (!codecs)
+               codecs = SIS_PRIMARY_CODEC_PRESENT;
+
        rc = snd_card_create(index, id, THIS_MODULE, sizeof(*sis), &card);
        if (rc < 0)
                goto error_out;
@@ -1436,7 +1477,7 @@ static void __devexit snd_sis7019_remove(struct pci_dev *pci)
 }
 
 static struct pci_driver sis7019_driver = {
-       .name = "SiS7019",
+       .name = KBUILD_MODNAME,
        .id_table = snd_sis7019_ids,
        .probe = snd_sis7019_probe,
        .remove = __devexit_p(snd_sis7019_remove),