[ALSA] HDA-Intel - Add support for Intel SCH
[powerpc.git] / sound / pci / hda / hda_intel.c
index 1672cac..56f8a30 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},"
@@ -84,10 +96,20 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
                         "{Intel, ESB2},"
                         "{Intel, ICH8},"
                         "{Intel, ICH9},"
+                        "{Intel, ICH10},"
+                        "{Intel, SCH},"
                         "{ATI, SB450},"
                         "{ATI, SB600},"
                         "{ATI, RS600},"
                         "{ATI, RS690},"
+                        "{ATI, RS780},"
+                        "{ATI, R600},"
+                        "{ATI, RV630},"
+                        "{ATI, RV610},"
+                        "{ATI, RV670},"
+                        "{ATI, RV635},"
+                        "{ATI, RV620},"
+                        "{ATI, RV770},"
                         "{VIA, VT8251},"
                         "{VIA, VT8237A},"
                         "{SiS, SIS966},"
@@ -96,6 +118,7 @@ MODULE_DESCRIPTION("Intel HDA driver");
 
 #define SFX    "hda-intel: "
 
+
 /*
  * registers
  */
@@ -198,6 +221,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
 #define RIRB_INT_MASK          0x05
 
 /* STATESTS int mask: SD2,SD1,SD0 */
+#define AZX_MAX_CODECS         3
 #define STATESTS_INT_MASK      0x07
 
 /* SD_CTL bits */
@@ -210,15 +234,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)
@@ -254,22 +279,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 */
@@ -334,15 +363,20 @@ struct azx {
 
        /* flags */
        int position_fix;
+       unsigned int running :1;
        unsigned int initialized :1;
        unsigned int single_cmd :1;
        unsigned int polling_mode :1;
        unsigned int msi :1;
+
+       /* for debugging */
+       unsigned int last_cmd;  /* last issued command (to sync) */
 };
 
 /* driver types */
 enum {
        AZX_DRIVER_ICH,
+       AZX_DRIVER_SCH,
        AZX_DRIVER_ATI,
        AZX_DRIVER_ATIHDMI,
        AZX_DRIVER_VIA,
@@ -353,6 +387,7 @@ enum {
 
 static char *driver_short_names[] __devinitdata = {
        [AZX_DRIVER_ICH] = "HDA Intel",
+       [AZX_DRIVER_SCH] = "HDA Intel MID",
        [AZX_DRIVER_ATI] = "HDA ATI SB",
        [AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI",
        [AZX_DRIVER_VIA] = "HDA VIA VT82xx",
@@ -412,7 +447,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");
@@ -463,18 +499,10 @@ static void azx_free_cmd_io(struct azx *chip)
 }
 
 /* send a command */
-static int azx_corb_send_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
-                            unsigned int verb, unsigned int para)
+static int azx_corb_send_cmd(struct hda_codec *codec, u32 val)
 {
        struct azx *chip = codec->bus->private_data;
        unsigned int wp;
-       u32 val;
-
-       val = (u32)(codec->addr & 0x0f) << 28;
-       val |= (u32)direct << 27;
-       val |= (u32)nid << 20;
-       val |= verb << 8;
-       val |= para;
 
        /* add command to corb */
        wp = azx_readb(chip, CORBWP);
@@ -527,20 +555,27 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec)
 
  again:
        timeout = jiffies + msecs_to_jiffies(1000);
-       do {
+       for (;;) {
                if (chip->polling_mode) {
                        spin_lock_irq(&chip->reg_lock);
                        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_interruptible(1);
-       } while (time_after_eq(timeout, jiffies));
+               if (time_after(jiffies, timeout))
+                       break;
+               if (codec->bus->needs_damn_long_delay)
+                       msleep(2); /* temporary workaround */
+               else {
+                       udelay(10);
+                       cond_resched();
+               }
+       }
 
        if (chip->msi) {
                snd_printk(KERN_WARNING "hda_intel: No response from codec, "
-                          "disabling MSI...\n");
+                          "disabling MSI: last cmd=0x%08x\n", chip->last_cmd);
                free_irq(chip->irq, chip);
                chip->irq = -1;
                pci_disable_msi(chip->pci);
@@ -552,13 +587,15 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec)
 
        if (!chip->polling_mode) {
                snd_printk(KERN_WARNING "hda_intel: azx_get_response timeout, "
-                          "switching to polling mode...\n");
+                          "switching to polling mode: last cmd=0x%08x\n",
+                          chip->last_cmd);
                chip->polling_mode = 1;
                goto again;
        }
 
        snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, "
-                  "switching to single_cmd mode...\n");
+                  "switching to single_cmd mode: last cmd=0x%08x\n",
+                  chip->last_cmd);
        chip->rirb.rp = azx_readb(chip, RIRBWP);
        chip->rirb.cmds = 0;
        /* switch to single_cmd mode */
@@ -578,32 +615,27 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec)
  */
 
 /* send a command */
-static int azx_single_send_cmd(struct hda_codec *codec, hda_nid_t nid,
-                              int direct, unsigned int verb,
-                              unsigned int para)
+static int azx_single_send_cmd(struct hda_codec *codec, u32 val)
 {
        struct azx *chip = codec->bus->private_data;
-       u32 val;
        int timeout = 50;
 
-       val = (u32)(codec->addr & 0x0f) << 28;
-       val |= (u32)direct << 27;
-       val |= (u32)nid << 20;
-       val |= verb << 8;
-       val |= para;
-
        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);
+       if (printk_ratelimit())
+               snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n",
+                          azx_readw(chip, IRS), val);
        return -EIO;
 }
 
@@ -619,7 +651,9 @@ 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));
+       if (printk_ratelimit())
+               snd_printd(SFX "get_response timeout: IRS=0x%x\n",
+                          azx_readw(chip, IRS));
        return (unsigned int)-1;
 }
 
@@ -636,10 +670,19 @@ static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid,
                        unsigned int para)
 {
        struct azx *chip = codec->bus->private_data;
+       u32 val;
+
+       val = (u32)(codec->addr & 0x0f) << 28;
+       val |= (u32)direct << 27;
+       val |= (u32)nid << 20;
+       val |= verb << 8;
+       val |= para;
+       chip->last_cmd = val;
+
        if (chip->single_cmd)
-               return azx_single_send_cmd(codec, nid, direct, verb, para);
+               return azx_single_send_cmd(codec, val);
        else
-               return azx_corb_send_cmd(codec, nid, direct, verb, para);
+               return azx_corb_send_cmd(codec, val);
 }
 
 /* get a response */
@@ -652,12 +695,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 +826,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 +848,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 +926,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 +980,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 +1002,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 +1022,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,10 +1048,11 @@ 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, err;
+       int c, codecs, audio_codecs, err;
 
        memset(&bus_temp, 0, sizeof(bus_temp));
        bus_temp.private_data = chip;
@@ -986,20 +1060,38 @@ 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 = 0;
-       for (c = 0; c < azx_max_codecs[chip->driver_type]; c++) {
-               if ((chip->codec_mask & (1 << c)) & probe_mask) {
-                       err = snd_hda_codec_new(chip->bus, c, NULL);
+       codecs = audio_codecs = 0;
+       for (c = 0; c < AZX_MAX_CODECS; c++) {
+               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)
                                continue;
                        codecs++;
+                       if (codec->afg)
+                               audio_codecs++;
                }
        }
-       if (! codecs) {
+       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)) & codec_probe_mask) {
+                               err = snd_hda_codec_new(chip->bus, c, NULL);
+                               if (err < 0)
+                                       continue;
+                               codecs++;
+                       }
+               }
+       }
+       if (!codecs) {
                snd_printk(KERN_ERR SFX "no codecs initialized\n");
                return -ENXIO;
        }
@@ -1024,7 +1116,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];
                }
@@ -1038,7 +1130,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 */
@@ -1091,8 +1184,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;
        }
@@ -1121,13 +1217,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)
@@ -1161,13 +1260,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);
@@ -1209,7 +1310,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;
@@ -1227,7 +1329,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");
@@ -1278,7 +1380,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;
@@ -1308,26 +1411,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++;
@@ -1336,16 +1440,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;
@@ -1372,7 +1477,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);
@@ -1409,6 +1515,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
@@ -1422,8 +1568,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);
@@ -1456,7 +1603,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;
@@ -1471,20 +1622,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) {
@@ -1518,8 +1658,9 @@ static int azx_dev_free(struct snd_device *device)
 /*
  * white/black-listing for position_fix
  */
-static const struct snd_pci_quirk position_fix_list[] __devinitdata = {
+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),
        {}
 };
 
@@ -1530,7 +1671,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);
@@ -1540,21 +1681,52 @@ 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;
        int err;
+       unsigned short gcap;
        static struct snd_device_ops ops = {
                .dev_free = azx_dev_free,
        };
 
        *rchip = NULL;
-       
+
        err = pci_enable_device(pci);
        if (err < 0)
                return err;
@@ -1574,7 +1746,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;
 
@@ -1615,58 +1788,79 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        pci_set_master(pci);
        synchronize_irq(chip->irq);
 
-       switch (chip->driver_type) {
-       case AZX_DRIVER_ULI:
-               chip->playback_streams = ULI_NUM_PLAYBACK;
-               chip->capture_streams = ULI_NUM_CAPTURE;
-               chip->playback_index_offset = ULI_PLAYBACK_INDEX;
-               chip->capture_index_offset = ULI_CAPTURE_INDEX;
-               break;
-       case AZX_DRIVER_ATIHDMI:
-               chip->playback_streams = ATIHDMI_NUM_PLAYBACK;
-               chip->capture_streams = ATIHDMI_NUM_CAPTURE;
-               chip->playback_index_offset = ATIHDMI_PLAYBACK_INDEX;
-               chip->capture_index_offset = ATIHDMI_CAPTURE_INDEX;
-               break;
-       default:
-               chip->playback_streams = ICH6_NUM_PLAYBACK;
-               chip->capture_streams = ICH6_NUM_CAPTURE;
-               chip->playback_index_offset = ICH6_PLAYBACK_INDEX;
-               chip->capture_index_offset = ICH6_CAPTURE_INDEX;
-               break;
+       gcap = azx_readw(chip, GCAP);
+       snd_printdd("chipset global capabilities = 0x%x\n", gcap);
+
+       if (gcap) {
+               /* read number of streams from GCAP register instead of using
+                * hardcoded value
+                */
+               chip->playback_streams = (gcap & (0xF << 12)) >> 12;
+               chip->capture_streams = (gcap & (0xF << 8)) >> 8;
+               chip->playback_index_offset = (gcap & (0xF << 12)) >> 12;
+               chip->capture_index_offset = 0;
+       } else {
+               /* gcap didn't give any info, switching to old method */
+
+               switch (chip->driver_type) {
+               case AZX_DRIVER_ULI:
+                       chip->playback_streams = ULI_NUM_PLAYBACK;
+                       chip->capture_streams = ULI_NUM_CAPTURE;
+                       chip->playback_index_offset = ULI_PLAYBACK_INDEX;
+                       chip->capture_index_offset = ULI_CAPTURE_INDEX;
+                       break;
+               case AZX_DRIVER_ATIHDMI:
+                       chip->playback_streams = ATIHDMI_NUM_PLAYBACK;
+                       chip->capture_streams = ATIHDMI_NUM_CAPTURE;
+                       chip->playback_index_offset = ATIHDMI_PLAYBACK_INDEX;
+                       chip->capture_index_offset = ATIHDMI_CAPTURE_INDEX;
+                       break;
+               default:
+                       chip->playback_streams = ICH6_NUM_PLAYBACK;
+                       chip->capture_streams = ICH6_NUM_CAPTURE;
+                       chip->playback_index_offset = ICH6_PLAYBACK_INDEX;
+                       chip->capture_index_offset = ICH6_CAPTURE_INDEX;
+                       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");
@@ -1674,14 +1868,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;
@@ -1691,19 +1887,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;
@@ -1711,32 +1929,39 @@ 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);
 
+       dev++;
        return err;
 }
 
@@ -1754,10 +1979,21 @@ static struct pci_device_id azx_ids[] = {
        { 0x8086, 0x284b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH8 */
        { 0x8086, 0x293e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */
        { 0x8086, 0x293f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */
+       { 0x8086, 0x3a3e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH10 */
+       { 0x8086, 0x3a6e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH10 */
+       { 0x8086, 0x811b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SCH }, /* SCH*/
        { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */
        { 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, 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 */
@@ -1769,6 +2005,16 @@ static struct pci_device_id azx_ids[] = {
        { 0x10de, 0x044b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP65 */
        { 0x10de, 0x055c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP67 */
        { 0x10de, 0x055d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP67 */
+       { 0x10de, 0x07fc, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP73 */
+       { 0x10de, 0x07fd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP73 */
+       { 0x10de, 0x0774, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
+       { 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);