[ALSA] Remove sound/driver.h
[pandora-kernel.git] / sound / pci / hda / hda_intel.c
index 92bc8b3..3ae4b4c 100644 (file)
@@ -1,6 +1,7 @@
 /*
  *
- *  hda_intel.c - Implementation of primary alsa driver code base for Intel HD Audio.
+ *  hda_intel.c - Implementation of primary alsa driver code base
+ *                for Intel HD Audio.
  *
  *  Copyright(c) 2004 Intel Corporation. All rights reserved.
  *
@@ -33,7 +34,6 @@
  * 
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include "hda_codec.h"
 
 
-static int index = SNDRV_DEFAULT_IDX1;
-static char *id = SNDRV_DEFAULT_STR1;
-static char *model;
-static int position_fix;
-static int probe_mask = -1;
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+static char *model[SNDRV_CARDS];
+static int position_fix[SNDRV_CARDS];
+static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
 static int single_cmd;
 static int enable_msi;
 
-module_param(index, int, 0444);
+module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
-module_param(id, charp, 0444);
+module_param_array(id, charp, NULL, 0444);
 MODULE_PARM_DESC(id, "ID string for Intel HD audio interface.");
-module_param(model, charp, 0444);
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable Intel HD audio interface.");
+module_param_array(model, charp, NULL, 0444);
 MODULE_PARM_DESC(model, "Use the given board model.");
-module_param(position_fix, int, 0444);
-MODULE_PARM_DESC(position_fix, "Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size).");
-module_param(probe_mask, int, 0444);
+module_param_array(position_fix, int, NULL, 0444);
+MODULE_PARM_DESC(position_fix, "Fix DMA pointer "
+                "(0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size).");
+module_param_array(probe_mask, int, NULL, 0444);
 MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1).");
 module_param(single_cmd, bool, 0444);
-MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs (for debugging only).");
-module_param(enable_msi, int, 0);
+MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs "
+                "(for debugging only).");
+module_param(enable_msi, int, 0444);
 MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)");
 
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+/* power_save option is defined in hda_codec.c */
 
-/* just for backward compatibility */
-static int enable;
-module_param(enable, bool, 0444);
+/* reset the HD-audio controller in power save mode.
+ * this may give more power-saving, but will take longer time to
+ * wake up.
+ */
+static int power_save_controller = 1;
+module_param(power_save_controller, bool, 0644);
+MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode.");
+#endif
 
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
@@ -90,6 +102,12 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
                         "{ATI, RS690},"
                         "{ATI, RS780},"
                         "{ATI, R600},"
+                        "{ATI, RV630},"
+                        "{ATI, RV610},"
+                        "{ATI, RV670},"
+                        "{ATI, RV635},"
+                        "{ATI, RV620},"
+                        "{ATI, RV770},"
                         "{VIA, VT8251},"
                         "{VIA, VT8237A},"
                         "{SiS, SIS966},"
@@ -98,6 +116,7 @@ MODULE_DESCRIPTION("Intel HDA driver");
 
 #define SFX    "hda-intel: "
 
+
 /*
  * registers
  */
@@ -213,15 +232,16 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
 #define SD_INT_DESC_ERR                0x10    /* descriptor error interrupt */
 #define SD_INT_FIFO_ERR                0x08    /* FIFO error interrupt */
 #define SD_INT_COMPLETE                0x04    /* completion interrupt */
-#define SD_INT_MASK            (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|SD_INT_COMPLETE)
+#define SD_INT_MASK            (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\
+                                SD_INT_COMPLETE)
 
 /* SD_STS */
 #define SD_STS_FIFO_READY      0x20    /* FIFO ready */
 
 /* INTCTL and INTSTS */
-#define ICH6_INT_ALL_STREAM    0xff            /* all stream interrupts */
-#define ICH6_INT_CTRL_EN       0x40000000      /* controller interrupt enable bit */
-#define ICH6_INT_GLOBAL_EN     0x80000000      /* global interrupt enable bit */
+#define ICH6_INT_ALL_STREAM    0xff       /* all stream interrupts */
+#define ICH6_INT_CTRL_EN       0x40000000 /* controller interrupt enable bit */
+#define ICH6_INT_GLOBAL_EN     0x80000000 /* global interrupt enable bit */
 
 /* GCTL unsolicited response enable bit */
 #define ICH6_GCTL_UREN         (1<<8)
@@ -257,22 +277,26 @@ enum {
  */
 
 struct azx_dev {
-       u32 *bdl;                       /* virtual address of the BDL */
-       dma_addr_t bdl_addr;            /* physical address of the BDL */
-       u32 *posbuf;                    /* position buffer pointer */
+       u32 *bdl;               /* virtual address of the BDL */
+       dma_addr_t bdl_addr;    /* physical address of the BDL */
+       u32 *posbuf;            /* position buffer pointer */
 
-       unsigned int bufsize;           /* size of the play buffer in bytes */
-       unsigned int fragsize;          /* size of each period in bytes */
-       unsigned int frags;             /* number for period in the play buffer */
-       unsigned int fifo_size;         /* FIFO size */
+       unsigned int bufsize;   /* size of the play buffer in bytes */
+       unsigned int fragsize;  /* size of each period in bytes */
+       unsigned int frags;     /* number for period in the play buffer */
+       unsigned int fifo_size; /* FIFO size */
 
-       void __iomem *sd_addr;          /* stream descriptor pointer */
+       void __iomem *sd_addr;  /* stream descriptor pointer */
 
-       u32 sd_int_sta_mask;            /* stream int status mask */
+       u32 sd_int_sta_mask;    /* stream int status mask */
 
        /* pcm support */
-       struct snd_pcm_substream *substream;    /* assigned substream, set in PCM open */
-       unsigned int format_val;        /* format value to be set in the controller and the codec */
+       struct snd_pcm_substream *substream;    /* assigned substream,
+                                                * set in PCM open
+                                                */
+       unsigned int format_val;        /* format value to be set in the
+                                        * controller and the codec
+                                        */
        unsigned char stream_tag;       /* assigned stream */
        unsigned char index;            /* stream index */
        /* for sanity check of position buffer */
@@ -337,6 +361,7 @@ struct azx {
 
        /* flags */
        int position_fix;
+       unsigned int running :1;
        unsigned int initialized :1;
        unsigned int single_cmd :1;
        unsigned int polling_mode :1;
@@ -418,7 +443,8 @@ static int azx_alloc_cmd_io(struct azx *chip)
        int err;
 
        /* single page (at least 4096 bytes) must suffice for both ringbuffes */
-       err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
+       err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
+                                 snd_dma_pci_data(chip->pci),
                                  PAGE_SIZE, &chip->rb);
        if (err < 0) {
                snd_printk(KERN_ERR SFX "cannot allocate CORB/RIRB\n");
@@ -531,9 +557,10 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec)
                        azx_update_rirb(chip);
                        spin_unlock_irq(&chip->reg_lock);
                }
-               if (! chip->rirb.cmds)
+               if (!chip->rirb.cmds)
                        return chip->rirb.res; /* the last value */
-               schedule_timeout(1);
+               udelay(10);
+               cond_resched();
        } while (time_after_eq(timeout, jiffies));
 
        if (chip->msi) {
@@ -585,16 +612,19 @@ static int azx_single_send_cmd(struct hda_codec *codec, u32 val)
 
        while (timeout--) {
                /* check ICB busy bit */
-               if (! (azx_readw(chip, IRS) & ICH6_IRS_BUSY)) {
+               if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) {
                        /* Clear IRV valid bit */
-                       azx_writew(chip, IRS, azx_readw(chip, IRS) | ICH6_IRS_VALID);
+                       azx_writew(chip, IRS, azx_readw(chip, IRS) |
+                                  ICH6_IRS_VALID);
                        azx_writel(chip, IC, val);
-                       azx_writew(chip, IRS, azx_readw(chip, IRS) | ICH6_IRS_BUSY);
+                       azx_writew(chip, IRS, azx_readw(chip, IRS) |
+                                  ICH6_IRS_BUSY);
                        return 0;
                }
                udelay(1);
        }
-       snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n", azx_readw(chip, IRS), val);
+       snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n",
+                  azx_readw(chip, IRS), val);
        return -EIO;
 }
 
@@ -610,7 +640,8 @@ static unsigned int azx_single_get_response(struct hda_codec *codec)
                        return azx_readl(chip, IR);
                udelay(1);
        }
-       snd_printd(SFX "get_response timeout: IRS=0x%x\n", azx_readw(chip, IRS));
+       snd_printd(SFX "get_response timeout: IRS=0x%x\n",
+                  azx_readw(chip, IRS));
        return (unsigned int)-1;
 }
 
@@ -652,12 +683,18 @@ static unsigned int azx_get_response(struct hda_codec *codec)
                return azx_rirb_get_response(codec);
 }
 
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static void azx_power_notify(struct hda_codec *codec);
+#endif
 
 /* reset codec link */
 static int azx_reset(struct azx *chip)
 {
        int count;
 
+       /* clear STATESTS */
+       azx_writeb(chip, STATESTS, STATESTS_INT_MASK);
+
        /* reset controller */
        azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_RESET);
 
@@ -777,18 +814,12 @@ static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev)
 
 
 /*
- * initialize the chip
+ * reset and start the controller registers
  */
 static void azx_init_chip(struct azx *chip)
 {
-       unsigned char reg;
-
-       /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44)
-        * TCSEL == Traffic Class Select Register, which sets PCI express QOS
-        * Ensuring these bits are 0 clears playback static on some HD Audio codecs
-        */
-       pci_read_config_byte (chip->pci, ICH6_PCIREG_TCSEL, &reg);
-       pci_write_config_byte(chip->pci, ICH6_PCIREG_TCSEL, reg & 0xf8);
+       if (chip->initialized)
+               return;
 
        /* reset controller */
        azx_reset(chip);
@@ -805,19 +836,45 @@ static void azx_init_chip(struct azx *chip)
        azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr);
        azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr));
 
+       chip->initialized = 1;
+}
+
+/*
+ * initialize the PCI registers
+ */
+/* update bits in a PCI register byte */
+static void update_pci_byte(struct pci_dev *pci, unsigned int reg,
+                           unsigned char mask, unsigned char val)
+{
+       unsigned char data;
+
+       pci_read_config_byte(pci, reg, &data);
+       data &= ~mask;
+       data |= (val & mask);
+       pci_write_config_byte(pci, reg, data);
+}
+
+static void azx_init_pci(struct azx *chip)
+{
+       /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44)
+        * TCSEL == Traffic Class Select Register, which sets PCI express QOS
+        * Ensuring these bits are 0 clears playback static on some HD Audio
+        * codecs
+        */
+       update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0);
+
        switch (chip->driver_type) {
        case AZX_DRIVER_ATI:
                /* For ATI SB450 azalia HD audio, we need to enable snoop */
-               pci_read_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, 
-                                    &reg);
-               pci_write_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, 
-                                     (reg & 0xf8) | ATI_SB450_HDAUDIO_ENABLE_SNOOP);
+               update_pci_byte(chip->pci,
+                               ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, 
+                               0x07, ATI_SB450_HDAUDIO_ENABLE_SNOOP);
                break;
        case AZX_DRIVER_NVIDIA:
                /* For NVIDIA HDA, enable snoop */
-               pci_read_config_byte(chip->pci,NVIDIA_HDA_TRANSREG_ADDR, &reg);
-               pci_write_config_byte(chip->pci,NVIDIA_HDA_TRANSREG_ADDR,
-                                     (reg & 0xf0) | NVIDIA_HDA_ENABLE_COHBITS);
+               update_pci_byte(chip->pci,
+                               NVIDIA_HDA_TRANSREG_ADDR,
+                               0x0f, NVIDIA_HDA_ENABLE_COHBITS);
                break;
         }
 }
@@ -857,7 +914,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
        /* clear rirb int */
        status = azx_readb(chip, RIRBSTS);
        if (status & RIRB_INT_MASK) {
-               if (! chip->single_cmd && (status & RIRB_INT_RESPONSE))
+               if (!chip->single_cmd && (status & RIRB_INT_RESPONSE))
                        azx_update_rirb(chip);
                azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
        }
@@ -911,9 +968,11 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
        int timeout;
 
        /* make sure the run bit is zero for SD */
-       azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) & ~SD_CTL_DMA_START);
+       azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) &
+                     ~SD_CTL_DMA_START);
        /* reset stream */
-       azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) | SD_CTL_STREAM_RESET);
+       azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) |
+                     SD_CTL_STREAM_RESET);
        udelay(3);
        timeout = 300;
        while (!((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) &&
@@ -931,7 +990,7 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
 
        /* program the stream_tag */
        azx_sd_writel(azx_dev, SD_CTL,
-                     (azx_sd_readl(azx_dev, SD_CTL) & ~SD_CTL_STREAM_TAG_MASK) |
+                     (azx_sd_readl(azx_dev, SD_CTL) & ~SD_CTL_STREAM_TAG_MASK)|
                      (azx_dev->stream_tag << SD_CTL_STREAM_TAG_SHIFT));
 
        /* program the length of samples in cyclic buffer */
@@ -951,11 +1010,13 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
        azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl_addr));
 
        /* enable the position buffer */
-       if (! (azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
-               azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
+       if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
+               azx_writel(chip, DPLBASE,
+                          (u32)chip->posbuf.addr |ICH6_DPLBASE_ENABLE);
 
        /* set the interrupt enable bits in the descriptor control register */
-       azx_sd_writel(azx_dev, SD_CTL, azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK);
+       azx_sd_writel(azx_dev, SD_CTL,
+                     azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK);
 
        return 0;
 }
@@ -975,7 +1036,8 @@ static unsigned int azx_max_codecs[] __devinitdata = {
        [AZX_DRIVER_NVIDIA] = 3,        /* FIXME: correct? */
 };
 
-static int __devinit azx_codec_create(struct azx *chip, const char *model)
+static int __devinit azx_codec_create(struct azx *chip, const char *model,
+                                     unsigned int codec_probe_mask)
 {
        struct hda_bus_template bus_temp;
        int c, codecs, audio_codecs, err;
@@ -986,13 +1048,17 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model)
        bus_temp.pci = chip->pci;
        bus_temp.ops.command = azx_send_cmd;
        bus_temp.ops.get_response = azx_get_response;
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+       bus_temp.ops.pm_notify = azx_power_notify;
+#endif
 
-       if ((err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus)) < 0)
+       err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus);
+       if (err < 0)
                return err;
 
        codecs = audio_codecs = 0;
        for (c = 0; c < AZX_MAX_CODECS; c++) {
-               if ((chip->codec_mask & (1 << c)) & probe_mask) {
+               if ((chip->codec_mask & (1 << c)) & codec_probe_mask) {
                        struct hda_codec *codec;
                        err = snd_hda_codec_new(chip->bus, c, &codec);
                        if (err < 0)
@@ -1005,7 +1071,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model)
        if (!audio_codecs) {
                /* probe additional slots if no codec is found */
                for (; c < azx_max_codecs[chip->driver_type]; c++) {
-                       if ((chip->codec_mask & (1 << c)) & probe_mask) {
+                       if ((chip->codec_mask & (1 << c)) & codec_probe_mask) {
                                err = snd_hda_codec_new(chip->bus, c, NULL);
                                if (err < 0)
                                        continue;
@@ -1038,7 +1104,7 @@ static inline struct azx_dev *azx_assign_device(struct azx *chip, int stream)
                nums = chip->capture_streams;
        }
        for (i = 0; i < nums; i++, dev++)
-               if (! chip->azx_dev[dev].opened) {
+               if (!chip->azx_dev[dev].opened) {
                        chip->azx_dev[dev].opened = 1;
                        return &chip->azx_dev[dev];
                }
@@ -1052,7 +1118,8 @@ static inline void azx_release_device(struct azx_dev *azx_dev)
 }
 
 static struct snd_pcm_hardware azx_pcm_hw = {
-       .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+       .info =                 (SNDRV_PCM_INFO_MMAP |
+                                SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                 SNDRV_PCM_INFO_MMAP_VALID |
                                 /* No full-resume yet implemented */
@@ -1105,8 +1172,11 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
                                   128);
        snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
                                   128);
-       if ((err = hinfo->ops.open(hinfo, apcm->codec, substream)) < 0) {
+       snd_hda_power_up(apcm->codec);
+       err = hinfo->ops.open(hinfo, apcm->codec, substream);
+       if (err < 0) {
                azx_release_device(azx_dev);
+               snd_hda_power_down(apcm->codec);
                mutex_unlock(&chip->open_mutex);
                return err;
        }
@@ -1135,13 +1205,16 @@ static int azx_pcm_close(struct snd_pcm_substream *substream)
        spin_unlock_irqrestore(&chip->reg_lock, flags);
        azx_release_device(azx_dev);
        hinfo->ops.close(hinfo, apcm->codec, substream);
+       snd_hda_power_down(apcm->codec);
        mutex_unlock(&chip->open_mutex);
        return 0;
 }
 
-static int azx_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params)
+static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
+                            struct snd_pcm_hw_params *hw_params)
 {
-       return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+       return snd_pcm_lib_malloc_pages(substream,
+                                       params_buffer_bytes(hw_params));
 }
 
 static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
@@ -1175,13 +1248,15 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
                                                         runtime->channels,
                                                         runtime->format,
                                                         hinfo->maxbps);
-       if (! azx_dev->format_val) {
-               snd_printk(KERN_ERR SFX "invalid format_val, rate=%d, ch=%d, format=%d\n",
+       if (!azx_dev->format_val) {
+               snd_printk(KERN_ERR SFX
+                          "invalid format_val, rate=%d, ch=%d, format=%d\n",
                           runtime->rate, runtime->channels, runtime->format);
                return -EINVAL;
        }
 
-       snd_printdd("azx_pcm_prepare: bufsize=0x%x, fragsize=0x%x, format=0x%x\n",
+       snd_printdd("azx_pcm_prepare: bufsize=0x%x, fragsize=0x%x, "
+                   "format=0x%x\n",
                    azx_dev->bufsize, azx_dev->fragsize, azx_dev->format_val);
        azx_setup_periods(azx_dev);
        azx_setup_controller(chip, azx_dev);
@@ -1223,7 +1298,8 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
            cmd == SNDRV_PCM_TRIGGER_SUSPEND ||
            cmd == SNDRV_PCM_TRIGGER_STOP) {
                int timeout = 5000;
-               while (azx_sd_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START && --timeout)
+               while ((azx_sd_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START) &&
+                      --timeout)
                        ;
        }
        return err;
@@ -1241,7 +1317,7 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
                /* use the position buffer */
                pos = le32_to_cpu(*azx_dev->posbuf);
                if (chip->position_fix == POS_FIX_AUTO &&
-                   azx_dev->period_intr == 1 && ! pos) {
+                   azx_dev->period_intr == 1 && !pos) {
                        printk(KERN_WARNING
                               "hda-intel: Invalid position buffer, "
                               "using LPIB read method instead.\n");
@@ -1292,7 +1368,8 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec,
        snd_assert(cpcm->name, return -EINVAL);
 
        err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,
-                         cpcm->stream[0].substreams, cpcm->stream[1].substreams,
+                         cpcm->stream[0].substreams,
+                         cpcm->stream[1].substreams,
                          &pcm);
        if (err < 0)
                return err;
@@ -1322,26 +1399,27 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec,
 
 static int __devinit azx_pcm_create(struct azx *chip)
 {
-       struct list_head *p;
        struct hda_codec *codec;
        int c, err;
        int pcm_dev;
 
-       if ((err = snd_hda_build_pcms(chip->bus)) < 0)
+       err = snd_hda_build_pcms(chip->bus);
+       if (err < 0)
                return err;
 
        /* create audio PCMs */
        pcm_dev = 0;
-       list_for_each(p, &chip->bus->codec_list) {
-               codec = list_entry(p, struct hda_codec, list);
+       list_for_each_entry(codec, &chip->bus->codec_list, list) {
                for (c = 0; c < codec->num_pcms; c++) {
                        if (codec->pcm_info[c].is_modem)
                                continue; /* create later */
                        if (pcm_dev >= AZX_MAX_AUDIO_PCMS) {
-                               snd_printk(KERN_ERR SFX "Too many audio PCMs\n");
+                               snd_printk(KERN_ERR SFX
+                                          "Too many audio PCMs\n");
                                return -EINVAL;
                        }
-                       err = create_codec_pcm(chip, codec, &codec->pcm_info[c], pcm_dev);
+                       err = create_codec_pcm(chip, codec,
+                                              &codec->pcm_info[c], pcm_dev);
                        if (err < 0)
                                return err;
                        pcm_dev++;
@@ -1350,16 +1428,17 @@ static int __devinit azx_pcm_create(struct azx *chip)
 
        /* create modem PCMs */
        pcm_dev = AZX_MAX_AUDIO_PCMS;
-       list_for_each(p, &chip->bus->codec_list) {
-               codec = list_entry(p, struct hda_codec, list);
+       list_for_each_entry(codec, &chip->bus->codec_list, list) {
                for (c = 0; c < codec->num_pcms; c++) {
-                       if (! codec->pcm_info[c].is_modem)
+                       if (!codec->pcm_info[c].is_modem)
                                continue; /* already created */
                        if (pcm_dev >= AZX_MAX_PCMS) {
-                               snd_printk(KERN_ERR SFX "Too many modem PCMs\n");
+                               snd_printk(KERN_ERR SFX
+                                          "Too many modem PCMs\n");
                                return -EINVAL;
                        }
-                       err = create_codec_pcm(chip, codec, &codec->pcm_info[c], pcm_dev);
+                       err = create_codec_pcm(chip, codec,
+                                              &codec->pcm_info[c], pcm_dev);
                        if (err < 0)
                                return err;
                        chip->pcm[pcm_dev]->dev_class = SNDRV_PCM_CLASS_MODEM;
@@ -1386,7 +1465,8 @@ static int __devinit azx_init_stream(struct azx *chip)
        int i;
 
        /* initialize each stream (aka device)
-        * assign the starting bdl address to each stream (device) and initialize
+        * assign the starting bdl address to each stream (device)
+        * and initialize
         */
        for (i = 0; i < chip->num_streams; i++) {
                unsigned int off = sizeof(u32) * (i * AZX_MAX_FRAG * 4);
@@ -1423,6 +1503,46 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect)
 }
 
 
+static void azx_stop_chip(struct azx *chip)
+{
+       if (!chip->initialized)
+               return;
+
+       /* disable interrupts */
+       azx_int_disable(chip);
+       azx_int_clear(chip);
+
+       /* disable CORB/RIRB */
+       azx_free_cmd_io(chip);
+
+       /* disable position buffer */
+       azx_writel(chip, DPLBASE, 0);
+       azx_writel(chip, DPUBASE, 0);
+
+       chip->initialized = 0;
+}
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+/* power-up/down the controller */
+static void azx_power_notify(struct hda_codec *codec)
+{
+       struct azx *chip = codec->bus->private_data;
+       struct hda_codec *c;
+       int power_on = 0;
+
+       list_for_each_entry(c, &codec->bus->codec_list, list) {
+               if (c->power_on) {
+                       power_on = 1;
+                       break;
+               }
+       }
+       if (power_on)
+               azx_init_chip(chip);
+       else if (chip->running && power_save_controller)
+               azx_stop_chip(chip);
+}
+#endif /* CONFIG_SND_HDA_POWER_SAVE */
+
 #ifdef CONFIG_PM
 /*
  * power management
@@ -1436,8 +1556,9 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state)
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
        for (i = 0; i < chip->pcm_devs; i++)
                snd_pcm_suspend_all(chip->pcm[i]);
-       snd_hda_suspend(chip->bus, state);
-       azx_free_cmd_io(chip);
+       if (chip->initialized)
+               snd_hda_suspend(chip->bus, state);
+       azx_stop_chip(chip);
        if (chip->irq >= 0) {
                synchronize_irq(chip->irq);
                free_irq(chip->irq, chip);
@@ -1470,7 +1591,11 @@ static int azx_resume(struct pci_dev *pci)
                        chip->msi = 0;
        if (azx_acquire_irq(chip, 1) < 0)
                return -EIO;
-       azx_init_chip(chip);
+       azx_init_pci(chip);
+
+       if (snd_hda_codecs_inuse(chip->bus))
+               azx_init_chip(chip);
+
        snd_hda_resume(chip->bus);
        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
        return 0;
@@ -1485,20 +1610,9 @@ static int azx_free(struct azx *chip)
 {
        if (chip->initialized) {
                int i;
-
                for (i = 0; i < chip->num_streams; i++)
                        azx_stream_stop(chip, &chip->azx_dev[i]);
-
-               /* disable interrupts */
-               azx_int_disable(chip);
-               azx_int_clear(chip);
-
-               /* disable CORB/RIRB */
-               azx_free_cmd_io(chip);
-
-               /* disable position buffer */
-               azx_writel(chip, DPLBASE, 0);
-               azx_writel(chip, DPUBASE, 0);
+               azx_stop_chip(chip);
        }
 
        if (chip->irq >= 0) {
@@ -1534,6 +1648,7 @@ static int azx_dev_free(struct snd_device *device)
  */
 static struct snd_pci_quirk position_fix_list[] __devinitdata = {
        SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_NONE),
+       SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_NONE),
        {}
 };
 
@@ -1544,7 +1659,7 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
        if (fix == POS_FIX_AUTO) {
                q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
                if (q) {
-                       snd_printdd(KERN_INFO
+                       printk(KERN_INFO
                                    "hda_intel: position_fix set to %d "
                                    "for device %04x:%04x\n",
                                    q->value, q->subvendor, q->subdevice);
@@ -1554,11 +1669,41 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
        return fix;
 }
 
+/*
+ * black-lists for probe_mask
+ */
+static struct snd_pci_quirk probe_mask_list[] __devinitdata = {
+       /* Thinkpad often breaks the controller communication when accessing
+        * to the non-working (or non-existing) modem codec slot.
+        */
+       SND_PCI_QUIRK(0x1014, 0x05b7, "Thinkpad Z60", 0x01),
+       SND_PCI_QUIRK(0x17aa, 0x2010, "Thinkpad X/T/R60", 0x01),
+       SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X/T/R61", 0x01),
+       {}
+};
+
+static void __devinit check_probe_mask(struct azx *chip, int dev)
+{
+       const struct snd_pci_quirk *q;
+
+       if (probe_mask[dev] == -1) {
+               q = snd_pci_quirk_lookup(chip->pci, probe_mask_list);
+               if (q) {
+                       printk(KERN_INFO
+                              "hda_intel: probe_mask set to 0x%x "
+                              "for device %04x:%04x\n",
+                              q->value, q->subvendor, q->subdevice);
+                       probe_mask[dev] = q->value;
+               }
+       }
+}
+
+
 /*
  * constructor
  */
 static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
-                               int driver_type,
+                               int dev, int driver_type,
                                struct azx **rchip)
 {
        struct azx *chip;
@@ -1588,7 +1733,8 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        chip->driver_type = driver_type;
        chip->msi = enable_msi;
 
-       chip->position_fix = check_position_fix(chip, position_fix);
+       chip->position_fix = check_position_fix(chip, position_fix[dev]);
+       check_probe_mask(chip, dev);
 
        chip->single_cmd = single_cmd;
 
@@ -1650,37 +1796,43 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
                break;
        }
        chip->num_streams = chip->playback_streams + chip->capture_streams;
-       chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), GFP_KERNEL);
+       chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev),
+                               GFP_KERNEL);
        if (!chip->azx_dev) {
                snd_printk(KERN_ERR "cannot malloc azx_dev\n");
                goto errout;
        }
 
        /* allocate memory for the BDL for each stream */
-       if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
-                                      BDL_SIZE, &chip->bdl)) < 0) {
+       err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
+                                 snd_dma_pci_data(chip->pci),
+                                 BDL_SIZE, &chip->bdl);
+       if (err < 0) {
                snd_printk(KERN_ERR SFX "cannot allocate BDL\n");
                goto errout;
        }
        /* allocate memory for the position buffer */
-       if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
-                                      chip->num_streams * 8, &chip->posbuf)) < 0) {
+       err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
+                                 snd_dma_pci_data(chip->pci),
+                                 chip->num_streams * 8, &chip->posbuf);
+       if (err < 0) {
                snd_printk(KERN_ERR SFX "cannot allocate posbuf\n");
                goto errout;
        }
        /* allocate CORB/RIRB */
-       if (! chip->single_cmd)
-               if ((err = azx_alloc_cmd_io(chip)) < 0)
+       if (!chip->single_cmd) {
+               err = azx_alloc_cmd_io(chip);
+               if (err < 0)
                        goto errout;
+       }
 
        /* initialize streams */
        azx_init_stream(chip);
 
        /* initialize chip */
+       azx_init_pci(chip);
        azx_init_chip(chip);
 
-       chip->initialized = 1;
-
        /* codec detection */
        if (!chip->codec_mask) {
                snd_printk(KERN_ERR SFX "no codecs found!\n");
@@ -1688,14 +1840,16 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
                goto errout;
        }
 
-       if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) <0) {
+       err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+       if (err <0) {
                snd_printk(KERN_ERR SFX "Error creating device [card]!\n");
                goto errout;
        }
 
        strcpy(card->driver, "HDA-Intel");
        strcpy(card->shortname, driver_short_names[chip->driver_type]);
-       sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->addr, chip->irq);
+       sprintf(card->longname, "%s at 0x%lx irq %i",
+               card->shortname, chip->addr, chip->irq);
 
        *rchip = chip;
        return 0;
@@ -1705,19 +1859,41 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        return err;
 }
 
-static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
+static void power_down_all_codecs(struct azx *chip)
 {
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+       /* The codecs were powered up in snd_hda_codec_new().
+        * Now all initialization done, so turn them down if possible
+        */
+       struct hda_codec *codec;
+       list_for_each_entry(codec, &chip->bus->codec_list, list) {
+               snd_hda_power_down(codec);
+       }
+#endif
+}
+
+static int __devinit azx_probe(struct pci_dev *pci,
+                              const struct pci_device_id *pci_id)
+{
+       static int dev;
        struct snd_card *card;
        struct azx *chip;
        int err;
 
-       card = snd_card_new(index, id, THIS_MODULE, 0);
+       if (dev >= SNDRV_CARDS)
+               return -ENODEV;
+       if (!enable[dev]) {
+               dev++;
+               return -ENOENT;
+       }
+
+       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
        if (!card) {
                snd_printk(KERN_ERR SFX "Error creating card!\n");
                return -ENOMEM;
        }
 
-       err = azx_create(card, pci, pci_id->driver_data, &chip);
+       err = azx_create(card, pci, dev, pci_id->driver_data, &chip);
        if (err < 0) {
                snd_card_free(card);
                return err;
@@ -1725,31 +1901,37 @@ static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id *
        card->private_data = chip;
 
        /* create codec instances */
-       if ((err = azx_codec_create(chip, model)) < 0) {
+       err = azx_codec_create(chip, model[dev], probe_mask[dev]);
+       if (err < 0) {
                snd_card_free(card);
                return err;
        }
 
        /* create PCM streams */
-       if ((err = azx_pcm_create(chip)) < 0) {
+       err = azx_pcm_create(chip);
+       if (err < 0) {
                snd_card_free(card);
                return err;
        }
 
        /* create mixer controls */
-       if ((err = azx_mixer_create(chip)) < 0) {
+       err = azx_mixer_create(chip);
+       if (err < 0) {
                snd_card_free(card);
                return err;
        }
 
        snd_card_set_dev(card, &pci->dev);
 
-       if ((err = snd_card_register(card)) < 0) {
+       err = snd_card_register(card);
+       if (err < 0) {
                snd_card_free(card);
                return err;
        }
 
        pci_set_drvdata(pci, card);
+       chip->running = 1;
+       power_down_all_codecs(chip);
 
        return err;
 }
@@ -1772,8 +1954,14 @@ static struct pci_device_id azx_ids[] = {
        { 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */
        { 0x1002, 0x793b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS600 HDMI */
        { 0x1002, 0x7919, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS690 HDMI */
-       { 0x1002, 0x960c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS780 HDMI */
+       { 0x1002, 0x960f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS780 HDMI */
        { 0x1002, 0xaa00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI R600 HDMI */
+       { 0x1002, 0xaa08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV630 HDMI */
+       { 0x1002, 0xaa10, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV610 HDMI */
+       { 0x1002, 0xaa18, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV670 HDMI */
+       { 0x1002, 0xaa20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV635 HDMI */
+       { 0x1002, 0xaa28, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV620 HDMI */
+       { 0x1002, 0xaa30, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV770 HDMI */
        { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */
        { 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */
        { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */
@@ -1791,6 +1979,10 @@ static struct pci_device_id azx_ids[] = {
        { 0x10de, 0x0775, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
        { 0x10de, 0x0776, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
        { 0x10de, 0x0777, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
+       { 0x10de, 0x0ac0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP79 */
+       { 0x10de, 0x0ac1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP79 */
+       { 0x10de, 0x0ac2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP79 */
+       { 0x10de, 0x0ac3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP79 */
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, azx_ids);