ALSA: HDA: Don't power up hda codec from resume
[linux-2.6.git] / sound / pci / hda / hda_intel.c
index 5f6f903..2407913 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/pci.h>
 #include <linux/mutex.h>
 #include <linux/reboot.h>
+#include <linux/clk.h>
 #include <sound/core.h>
 #include <sound/initval.h>
 #include "hda_codec.h"
@@ -78,8 +79,8 @@ 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_array(position_fix, int, NULL, 0444);
-MODULE_PARM_DESC(position_fix, "Fix DMA pointer "
-                "(0 = auto, 1 = none, 2 = POSBUF).");
+MODULE_PARM_DESC(position_fix, "DMA pointer read method."
+                "(0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO).");
 module_param_array(bdl_pos_adj, int, NULL, 0644);
 MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");
 module_param_array(probe_mask, int, NULL, 0444);
@@ -126,6 +127,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
                         "{Intel, ICH10},"
                         "{Intel, PCH},"
                         "{Intel, CPT},"
+                        "{Intel, PPT},"
                         "{Intel, PBG},"
                         "{Intel, SCH},"
                         "{ATI, SB450},"
@@ -176,7 +178,8 @@ MODULE_DESCRIPTION("Intel HDA driver");
 #define ICH6_REG_INTCTL                        0x20
 #define ICH6_REG_INTSTS                        0x24
 #define ICH6_REG_WALLCLK               0x30    /* 24Mhz source */
-#define ICH6_REG_SYNC                  0x34    
+#define ICH6_REG_OLD_SSYNC             0x34    /* SSYNC for old ICH */
+#define ICH6_REG_SSYNC                 0x38
 #define ICH6_REG_CORBLBASE             0x40
 #define ICH6_REG_CORBUBASE             0x44
 #define ICH6_REG_CORBWP                        0x48
@@ -305,6 +308,7 @@ enum {
        POS_FIX_AUTO,
        POS_FIX_LPIB,
        POS_FIX_POSBUF,
+       POS_FIX_VIACOMBO,
 };
 
 /* Defines for ATI HD Audio support in SB450 south bridge */
@@ -318,6 +322,32 @@ enum {
 #define NVIDIA_HDA_OSTRM_COH          0x4c
 #define NVIDIA_HDA_ENABLE_COHBIT      0x01
 
+#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA
+/* Defines for Nvidia Tegra HDA support */
+#define NVIDIA_TEGRA_HDA_BAR0_OFFSET           0x8000
+
+#define NVIDIA_TEGRA_HDA_CFG_CMD_OFFSET        0x1004
+#define NVIDIA_TEGRA_HDA_CFG_BAR0_OFFSET       0x1010
+
+#define NVIDIA_TEGRA_HDA_ENABLE_IO_SPACE       (1 << 0)
+#define NVIDIA_TEGRA_HDA_ENABLE_MEM_SPACE      (1 << 1)
+#define NVIDIA_TEGRA_HDA_ENABLE_BUS_MASTER     (1 << 2)
+#define NVIDIA_TEGRA_HDA_ENABLE_SERR           (1 << 8)
+#define NVIDIA_TEGRA_HDA_DISABLE_INTR          (1 << 10)
+#define NVIDIA_TEGRA_HDA_BAR0_INIT_PROGRAM     0xFFFFFFFF
+#define NVIDIA_TEGRA_HDA_BAR0_FINAL_PROGRAM    (1 << 14)
+
+/* IPFS */
+#define NVIDIA_TEGRA_HDA_IPFS_CONFIG           0x180
+#define NVIDIA_TEGRA_HDA_IPFS_EN_FPCI          0x1
+
+#define NVIDIA_TEGRA_HDA_IPFS_FPCI_BAR0        0x80
+#define NVIDIA_TEGRA_HDA_FPCI_BAR0_START       0x40
+
+#define NVIDIA_TEGRA_HDA_IPFS_INTR_MASK        0x188
+#define NVIDIA_TEGRA_HDA_IPFS_EN_INTR          (1 << 16)
+#endif /* CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA */
+
 /* Defines for Intel SCH HDA snoop control */
 #define INTEL_SCH_HDA_DEVC      0x78
 #define INTEL_SCH_HDA_DEVC_NOSNOOP       (0x1<<11)
@@ -385,10 +415,14 @@ struct azx_rb {
 struct azx {
        struct snd_card *card;
        struct pci_dev *pci;
+       struct platform_device *pdev;
+       struct device *dev;
+       int irq_id;
        int dev_index;
 
        /* chip type specific */
        int driver_type;
+       unsigned int driver_caps;
        int playback_streams;
        int playback_index_offset;
        int capture_streams;
@@ -398,8 +432,18 @@ struct azx {
        /* pci resources */
        unsigned long addr;
        void __iomem *remap_addr;
+#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA
+       void __iomem *remap_config_addr;
+#endif
        int irq;
 
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+       /* platform driver clocks */
+       struct clk **platform_clks;
+       int platform_clk_count;
+       int platform_clk_enable;
+#endif
+
        /* locks */
        spinlock_t reg_lock;
        struct mutex open_mutex;
@@ -433,7 +477,6 @@ struct azx {
        unsigned int polling_mode :1;
        unsigned int msi :1;
        unsigned int irq_pending_warned :1;
-       unsigned int via_dmapos_patch :1; /* enable DMA-position fix for VIA */
        unsigned int probing :1; /* codec probing phase */
 
        /* for debugging */
@@ -457,11 +500,42 @@ enum {
        AZX_DRIVER_SIS,
        AZX_DRIVER_ULI,
        AZX_DRIVER_NVIDIA,
+       AZX_DRIVER_NVIDIA_TEGRA,
        AZX_DRIVER_TERA,
+       AZX_DRIVER_CTX,
        AZX_DRIVER_GENERIC,
        AZX_NUM_DRIVERS, /* keep this as last entry */
 };
 
+/* driver quirks (capabilities) */
+/* bits 0-7 are used for indicating driver type */
+#define AZX_DCAPS_NO_TCSEL     (1 << 8)        /* No Intel TCSEL bit */
+#define AZX_DCAPS_NO_MSI       (1 << 9)        /* No MSI support */
+#define AZX_DCAPS_ATI_SNOOP    (1 << 10)       /* ATI snoop enable */
+#define AZX_DCAPS_NVIDIA_SNOOP (1 << 11)       /* Nvidia snoop enable */
+#define AZX_DCAPS_SCH_SNOOP    (1 << 12)       /* SCH/PCH snoop enable */
+#define AZX_DCAPS_RIRB_DELAY   (1 << 13)       /* Long delay in read loop */
+#define AZX_DCAPS_RIRB_PRE_DELAY (1 << 14)     /* Put a delay before read */
+#define AZX_DCAPS_CTX_WORKAROUND (1 << 15)     /* X-Fi workaround */
+#define AZX_DCAPS_POSFIX_LPIB  (1 << 16)       /* Use LPIB as default */
+#define AZX_DCAPS_POSFIX_VIA   (1 << 17)       /* Use VIACOMBO as default */
+#define AZX_DCAPS_NO_64BIT     (1 << 18)       /* No 64bit address */
+#define AZX_DCAPS_SYNC_WRITE   (1 << 19)       /* sync each cmd write */
+#define AZX_DCAPS_OLD_SSYNC    (1 << 20)       /* Old SSYNC reg for ICH */
+
+/* quirks for ATI SB / AMD Hudson */
+#define AZX_DCAPS_PRESET_ATI_SB \
+       (AZX_DCAPS_ATI_SNOOP | AZX_DCAPS_NO_TCSEL | \
+        AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB)
+
+/* quirks for ATI/AMD HDMI */
+#define AZX_DCAPS_PRESET_ATI_HDMI \
+       (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB)
+
+/* quirks for Nvidia */
+#define AZX_DCAPS_PRESET_NVIDIA \
+       (AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI)
+
 static char *driver_short_names[] __devinitdata = {
        [AZX_DRIVER_ICH] = "HDA Intel",
        [AZX_DRIVER_PCH] = "HDA Intel PCH",
@@ -472,13 +546,57 @@ static char *driver_short_names[] __devinitdata = {
        [AZX_DRIVER_SIS] = "HDA SIS966",
        [AZX_DRIVER_ULI] = "HDA ULI M5461",
        [AZX_DRIVER_NVIDIA] = "HDA NVidia",
+       [AZX_DRIVER_NVIDIA_TEGRA] = "HDA NVIDIA Tegra",
        [AZX_DRIVER_TERA] = "HDA Teradici", 
+       [AZX_DRIVER_CTX] = "HDA Creative", 
        [AZX_DRIVER_GENERIC] = "HD-Audio Generic",
 };
 
 /*
  * macros for easy use
  */
+#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA
+#define MASK_LONG_ALIGN                0x3UL
+#define SHIFT_BYTE             3
+#define SHIFT_BITS(reg)                ((reg & MASK_LONG_ALIGN) << SHIFT_BYTE)
+#define ADDR_ALIGN_L(base, reg)        (base + (reg & ~MASK_LONG_ALIGN))
+#define MASK(bits)             (BIT(bits) - 1)
+#define MASK_REG(reg, bits)    (MASK(bits) << SHIFT_BITS(reg))
+
+#define tegra_write(base, reg, val, bits) \
+       writel((readl(ADDR_ALIGN_L(base, reg)) & ~MASK_REG(reg, bits)) | \
+              ((val) << SHIFT_BITS(reg)), ADDR_ALIGN_L(base, reg))
+
+#define tegra_read(base, reg, bits) \
+       ((readl(ADDR_ALIGN_L(base, reg)) >> SHIFT_BITS(reg)) & MASK(bits))
+
+#define azx_writel(chip, reg, value) \
+       writel(value, (chip)->remap_addr + ICH6_REG_##reg)
+#define azx_readl(chip, reg) \
+       readl((chip)->remap_addr + ICH6_REG_##reg)
+#define azx_writew(chip, reg, value) \
+       tegra_write((chip)->remap_addr, ICH6_REG_##reg, value, 16)
+#define azx_readw(chip, reg) \
+       tegra_read((chip)->remap_addr, ICH6_REG_##reg, 16)
+#define azx_writeb(chip, reg, value) \
+       tegra_write((chip)->remap_addr, ICH6_REG_##reg, value, 8)
+#define azx_readb(chip, reg) \
+       tegra_read((chip)->remap_addr, ICH6_REG_##reg, 8)
+
+#define azx_sd_writel(dev, reg, value) \
+       writel(value, (dev)->sd_addr + ICH6_REG_##reg)
+#define azx_sd_readl(dev, reg) \
+       readl((dev)->sd_addr + ICH6_REG_##reg)
+#define azx_sd_writew(dev, reg, value) \
+       tegra_write((dev)->sd_addr, ICH6_REG_##reg, value, 16)
+#define azx_sd_readw(dev, reg) \
+       tegra_read((dev)->sd_addr, ICH6_REG_##reg, 16)
+#define azx_sd_writeb(dev, reg, value) \
+       tegra_write((dev)->sd_addr, ICH6_REG_##reg, value, 8)
+#define azx_sd_readb(dev, reg) \
+       tegra_read((dev)->sd_addr, ICH6_REG_##reg, 8)
+
+#else /* CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA */
 #define azx_writel(chip,reg,value) \
        writel(value, (chip)->remap_addr + ICH6_REG_##reg)
 #define azx_readl(chip,reg) \
@@ -505,6 +623,8 @@ static char *driver_short_names[] __devinitdata = {
 #define azx_sd_readb(dev,reg) \
        readb((dev)->sd_addr + ICH6_REG_##reg)
 
+#endif /* CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA */
+
 /* for pcm support */
 #define get_azx_dev(substream) (substream->runtime->private_data)
 
@@ -523,7 +643,7 @@ static int azx_alloc_cmd_io(struct azx *chip)
 
        /* 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),
+                                 chip->dev,
                                  PAGE_SIZE, &chip->rb);
        if (err < 0) {
                snd_printk(KERN_ERR SFX "cannot allocate CORB/RIRB\n");
@@ -563,7 +683,10 @@ static void azx_init_cmd_io(struct azx *chip)
        /* reset the rirb hw write pointer */
        azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST);
        /* set N=1, get RIRB response interrupt for new entry */
-       azx_writew(chip, RINTCNT, 1);
+       if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND)
+               azx_writew(chip, RINTCNT, 0xc0);
+       else
+               azx_writew(chip, RINTCNT, 1);
        /* enable rirb dma and response irq */
        azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN);
        spin_unlock_irq(&chip->reg_lock);
@@ -1047,19 +1170,27 @@ 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
+        * codecs.
+        * The PCI register TCSEL is defined in the Intel manuals.
         */
-       update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0);
+       if (!(chip->driver_caps & AZX_DCAPS_NO_TCSEL)) {
+               snd_printdd(SFX "Clearing TCSEL\n");
+               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 */
+       /* For ATI SB450/600/700/800/900 and AMD Hudson azalia HD audio,
+        * we need to enable snoop.
+        */
+       if (chip->driver_caps & AZX_DCAPS_ATI_SNOOP) {
+               snd_printdd(SFX "Enabling ATI snoop\n");
                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 */
+       }
+
+       /* For NVIDIA HDA, enable snoop */
+       if (chip->driver_caps & AZX_DCAPS_NVIDIA_SNOOP) {
+               snd_printdd(SFX "Enabling Nvidia snoop\n");
                update_pci_byte(chip->pci,
                                NVIDIA_HDA_TRANSREG_ADDR,
                                0x0f, NVIDIA_HDA_ENABLE_COHBITS);
@@ -1069,9 +1200,10 @@ static void azx_init_pci(struct azx *chip)
                update_pci_byte(chip->pci,
                                NVIDIA_HDA_OSTRM_COH,
                                0x01, NVIDIA_HDA_ENABLE_COHBIT);
-               break;
-       case AZX_DRIVER_SCH:
-       case AZX_DRIVER_PCH:
+       }
+
+       /* Enable SCH/PCH snoop if needed */
+       if (chip->driver_caps & AZX_DCAPS_SCH_SNOOP) {
                pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop);
                if (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) {
                        pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC,
@@ -1082,11 +1214,86 @@ static void azx_init_pci(struct azx *chip)
                                (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP)
                                ? "Failed" : "OK");
                }
+        }
+}
+
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+/*
+ * initialize the platform specific registers
+ */
+static void reg_update_bits(void __iomem *base, unsigned int reg,
+                           unsigned int mask, unsigned int val)
+{
+       unsigned int data;
+
+       data = readl(base + reg);
+       data &= ~mask;
+       data |= (val & mask);
+       writel(data, base + reg);
+}
+
+static void azx_init_platform(struct azx *chip)
+{
+       switch (chip->driver_type) {
+#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA
+       case AZX_DRIVER_NVIDIA_TEGRA:
+               /*Enable the PCI access */
+               reg_update_bits(chip->remap_config_addr,
+                               NVIDIA_TEGRA_HDA_IPFS_CONFIG,
+                               NVIDIA_TEGRA_HDA_IPFS_EN_FPCI,
+                               NVIDIA_TEGRA_HDA_IPFS_EN_FPCI);
+               /* Enable MEM/IO space and bus master */
+               reg_update_bits(chip->remap_config_addr,
+                               NVIDIA_TEGRA_HDA_CFG_CMD_OFFSET, 0x507,
+                               NVIDIA_TEGRA_HDA_ENABLE_MEM_SPACE |
+                               NVIDIA_TEGRA_HDA_ENABLE_IO_SPACE |
+                               NVIDIA_TEGRA_HDA_ENABLE_BUS_MASTER |
+                               NVIDIA_TEGRA_HDA_ENABLE_SERR);
+               reg_update_bits(chip->remap_config_addr,
+                               NVIDIA_TEGRA_HDA_CFG_BAR0_OFFSET, 0xFFFFFFFF,
+                               NVIDIA_TEGRA_HDA_BAR0_INIT_PROGRAM);
+               reg_update_bits(chip->remap_config_addr,
+                               NVIDIA_TEGRA_HDA_CFG_BAR0_OFFSET, 0xFFFFFFFF,
+                               NVIDIA_TEGRA_HDA_BAR0_FINAL_PROGRAM);
+               reg_update_bits(chip->remap_config_addr,
+                               NVIDIA_TEGRA_HDA_IPFS_FPCI_BAR0, 0xFFFFFFFF,
+                               NVIDIA_TEGRA_HDA_FPCI_BAR0_START);
+               reg_update_bits(chip->remap_config_addr,
+                               NVIDIA_TEGRA_HDA_IPFS_INTR_MASK,
+                               NVIDIA_TEGRA_HDA_IPFS_EN_INTR,
+                               NVIDIA_TEGRA_HDA_IPFS_EN_INTR);
                break;
+#endif
+       default:
+               break;
+       }
 
-        }
+       return;
 }
 
+static void azx_platform_enable_clocks(struct azx *chip)
+{
+       int i;
+
+       for (i = 0; i < chip->platform_clk_count; i++)
+               clk_enable(chip->platform_clks[i]);
+
+       chip->platform_clk_enable++;
+}
+
+static void azx_platform_disable_clocks(struct azx *chip)
+{
+       int i;
+
+       if (!chip->platform_clk_enable)
+               return;
+
+       for (i = 0; i < chip->platform_clk_count; i++)
+               clk_disable(chip->platform_clks[i]);
+
+       chip->platform_clk_enable--;
+}
+#endif /* CONFIG_SND_HDA_PLATFORM_DRIVER */
 
 static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev);
 
@@ -1136,8 +1343,11 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
        /* clear rirb int */
        status = azx_readb(chip, RIRBSTS);
        if (status & RIRB_INT_MASK) {
-               if (status & RIRB_INT_RESPONSE)
+               if (status & RIRB_INT_RESPONSE) {
+                       if (chip->driver_caps & AZX_DCAPS_RIRB_PRE_DELAY)
+                               udelay(80);
                        azx_update_rirb(chip);
+               }
                azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
        }
 
@@ -1227,7 +1437,8 @@ static int azx_setup_periods(struct azx *chip,
                        pos_adj = 0;
                } else {
                        ofs = setup_bdle(substream, azx_dev,
-                                        &bdl, ofs, pos_adj, 1);
+                                        &bdl, ofs, pos_adj,
+                                        !substream->runtime->no_period_wakeup);
                        if (ofs < 0)
                                goto error;
                }
@@ -1239,7 +1450,8 @@ static int azx_setup_periods(struct azx *chip,
                                         period_bytes - pos_adj, 0);
                else
                        ofs = setup_bdle(substream, azx_dev, &bdl, ofs,
-                                        period_bytes, 1);
+                                        period_bytes,
+                                        !substream->runtime->no_period_wakeup);
                if (ofs < 0)
                        goto error;
        }
@@ -1309,11 +1521,8 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
        azx_sd_writel(azx_dev, SD_BDLPU, upper_32_bits(azx_dev->bdl.addr));
 
        /* enable the position buffer */
-       if (chip->position_fix[0] == POS_FIX_POSBUF ||
-           chip->position_fix[0] == POS_FIX_AUTO ||
-           chip->position_fix[1] == POS_FIX_POSBUF ||
-           chip->position_fix[1] == POS_FIX_AUTO ||
-           chip->via_dmapos_patch) {
+       if (chip->position_fix[0] != POS_FIX_LPIB ||
+           chip->position_fix[1] != POS_FIX_LPIB) {
                if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
                        azx_writel(chip, DPLBASE,
                                (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
@@ -1391,6 +1600,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model)
        bus_temp.private_data = chip;
        bus_temp.modelname = model;
        bus_temp.pci = chip->pci;
+       bus_temp.pdev = chip->pdev;
        bus_temp.ops.command = azx_send_cmd;
        bus_temp.ops.get_response = azx_get_response;
        bus_temp.ops.attach_pcm = azx_attach_pcm_stream;
@@ -1404,8 +1614,10 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model)
        if (err < 0)
                return err;
 
-       if (chip->driver_type == AZX_DRIVER_NVIDIA)
+       if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) {
+               snd_printd(SFX "Enable delay in RIRB handling\n");
                chip->bus->needs_damn_long_delay = 1;
+       }
 
        codecs = 0;
        max_slots = azx_max_codecs[chip->driver_type];
@@ -1436,6 +1648,16 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model)
                }
        }
 
+       /* AMD chipsets often cause the communication stalls upon certain
+        * sequence like the pin-detection.  It seems that forcing the synced
+        * access works around the stall.  Grrr...
+        */
+       if (chip->driver_caps & AZX_DCAPS_SYNC_WRITE) {
+               snd_printd(SFX "Enable sync_write for stable communication\n");
+               chip->bus->sync_write = 1;
+               chip->bus->allow_bus_reset = 1;
+       }
+
        /* Then create codec instances */
        for (c = 0; c < max_slots; c++) {
                if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
@@ -1510,7 +1732,8 @@ static struct snd_pcm_hardware azx_pcm_hw = {
                                 /* No full-resume yet implemented */
                                 /* SNDRV_PCM_INFO_RESUME |*/
                                 SNDRV_PCM_INFO_PAUSE |
-                                SNDRV_PCM_INFO_SYNC_START),
+                                SNDRV_PCM_INFO_SYNC_START |
+                                SNDRV_PCM_INFO_NO_PERIOD_WAKEUP),
        .formats =              SNDRV_PCM_FMTBIT_S16_LE,
        .rates =                SNDRV_PCM_RATE_48000,
        .rate_min =             48000,
@@ -1647,15 +1870,18 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
        struct azx_dev *azx_dev = get_azx_dev(substream);
        struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
        struct snd_pcm_runtime *runtime = substream->runtime;
-       unsigned int bufsize, period_bytes, format_val;
+       unsigned int bufsize, period_bytes, format_val, stream_tag;
        int err;
+       struct hda_spdif_out *spdif =
+               snd_hda_spdif_out_of_nid(apcm->codec, hinfo->nid);
+       unsigned short ctls = spdif ? spdif->ctls : 0;
 
        azx_stream_reset(chip, azx_dev);
        format_val = snd_hda_calc_stream_format(runtime->rate,
                                                runtime->channels,
                                                runtime->format,
                                                hinfo->maxbps,
-                                               apcm->codec->spdif_ctls);
+                                               ctls);
        if (!format_val) {
                snd_printk(KERN_ERR SFX
                           "invalid format_val, rate=%d, ch=%d, format=%d\n",
@@ -1689,7 +1915,12 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
        else
                azx_dev->fifo_size = 0;
 
-       return snd_hda_codec_prepare(apcm->codec, hinfo, azx_dev->stream_tag,
+       stream_tag = azx_dev->stream_tag;
+       /* CA-IBG chips need the playback stream starting from 1 */
+       if ((chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) &&
+           stream_tag > chip->capture_streams)
+               stream_tag -= chip->capture_streams;
+       return snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag,
                                     azx_dev->format_val, substream);
 }
 
@@ -1730,7 +1961,11 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        spin_lock(&chip->reg_lock);
        if (nsync > 1) {
                /* first, set SYNC bits of corresponding streams */
-               azx_writel(chip, SYNC, azx_readl(chip, SYNC) | sbits);
+               if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC)
+                       azx_writel(chip, OLD_SSYNC,
+                                  azx_readl(chip, OLD_SSYNC) | sbits);
+               else
+                       azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) | sbits);
        }
        snd_pcm_group_for_each_entry(s, substream) {
                if (s->pcm->card != substream->pcm->card)
@@ -1786,7 +2021,11 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        if (nsync > 1) {
                spin_lock(&chip->reg_lock);
                /* reset SYNC bits */
-               azx_writel(chip, SYNC, azx_readl(chip, SYNC) & ~sbits);
+               if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC)
+                       azx_writel(chip, OLD_SSYNC,
+                                  azx_readl(chip, OLD_SSYNC) & ~sbits);
+               else
+                       azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) & ~sbits);
                spin_unlock(&chip->reg_lock);
        }
        return 0;
@@ -1801,7 +2040,7 @@ static unsigned int azx_via_get_position(struct azx *chip,
        unsigned int fifo_size;
 
        link_pos = azx_sd_readl(azx_dev, SD_LPIB);
-       if (azx_dev->index >= 4) {
+       if (azx_dev->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                /* Playback, no problem using link position */
                return link_pos;
        }
@@ -1849,23 +2088,36 @@ static unsigned int azx_via_get_position(struct azx *chip,
 }
 
 static unsigned int azx_get_position(struct azx *chip,
-                                    struct azx_dev *azx_dev)
+                                    struct azx_dev *azx_dev,
+                                    bool with_check)
 {
        unsigned int pos;
+       int stream = azx_dev->substream->stream;
 
-       if (chip->via_dmapos_patch)
+       switch (chip->position_fix[stream]) {
+       case POS_FIX_LPIB:
+               /* read LPIB */
+               pos = azx_sd_readl(azx_dev, SD_LPIB);
+               break;
+       case POS_FIX_VIACOMBO:
                pos = azx_via_get_position(chip, azx_dev);
-       else {
-               int stream = azx_dev->substream->stream;
-               if (chip->position_fix[stream] == POS_FIX_POSBUF ||
-                   chip->position_fix[stream] == POS_FIX_AUTO) {
-                       /* use the position buffer */
-                       pos = le32_to_cpu(*azx_dev->posbuf);
-               } else {
-                       /* read LPIB */
-                       pos = azx_sd_readl(azx_dev, SD_LPIB);
+               break;
+       default:
+               /* use the position buffer */
+               pos = le32_to_cpu(*azx_dev->posbuf);
+               if (with_check && chip->position_fix[stream] == POS_FIX_AUTO) {
+                       if (!pos || pos == (u32)-1) {
+                               printk(KERN_WARNING
+                                      "hda-intel: Invalid position buffer, "
+                                      "using LPIB read method instead.\n");
+                               chip->position_fix[stream] = POS_FIX_LPIB;
+                               pos = azx_sd_readl(azx_dev, SD_LPIB);
+                       } else
+                               chip->position_fix[stream] = POS_FIX_POSBUF;
                }
+               break;
        }
+
        if (pos >= azx_dev->bufsize)
                pos = 0;
        return pos;
@@ -1877,7 +2129,7 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
        struct azx *chip = apcm->chip;
        struct azx_dev *azx_dev = get_azx_dev(substream);
        return bytes_to_frames(substream->runtime,
-                              azx_get_position(chip, azx_dev));
+                              azx_get_position(chip, azx_dev, false));
 }
 
 /*
@@ -1900,17 +2152,7 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
                return -1;      /* bogus (too early) interrupt */
 
        stream = azx_dev->substream->stream;
-       pos = azx_get_position(chip, azx_dev);
-       if (chip->position_fix[stream] == POS_FIX_AUTO) {
-               if (!pos) {
-                       printk(KERN_WARNING
-                              "hda-intel: Invalid position buffer, "
-                              "using LPIB read method instead.\n");
-                       chip->position_fix[stream] = POS_FIX_LPIB;
-                       pos = azx_get_position(chip, azx_dev);
-               } else
-                       chip->position_fix[stream] = POS_FIX_POSBUF;
-       }
+       pos = azx_get_position(chip, azx_dev, true);
 
        if (WARN_ONCE(!azx_dev->period_bytes,
                      "hda-intel: zero azx_dev->period_bytes"))
@@ -1998,6 +2240,8 @@ static void azx_pcm_free(struct snd_pcm *pcm)
        }
 }
 
+#define MAX_PREALLOC_SIZE      (32 * 1024 * 1024)
+
 static int
 azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
                      struct hda_pcm *cpcm)
@@ -2006,6 +2250,7 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
        struct snd_pcm *pcm;
        struct azx_pcm *apcm;
        int pcm_dev = cpcm->device;
+       unsigned int size;
        int s, err;
 
        if (pcm_dev >= HDA_MAX_PCMS) {
@@ -2041,9 +2286,12 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
                        snd_pcm_set_ops(pcm, s, &azx_pcm_ops);
        }
        /* buffer pre-allocation */
+       size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024;
+       if (size > MAX_PREALLOC_SIZE)
+               size = MAX_PREALLOC_SIZE;
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
-                                             snd_dma_pci_data(chip->pci),
-                                             1024 * 64, 32 * 1024 * 1024);
+                                             chip->dev,
+                                             size, MAX_PREALLOC_SIZE);
        return 0;
 }
 
@@ -2084,17 +2332,19 @@ static int __devinit azx_init_stream(struct azx *chip)
 
 static int azx_acquire_irq(struct azx *chip, int do_disconnect)
 {
-       if (request_irq(chip->pci->irq, azx_interrupt,
+       if (request_irq(chip->irq_id, azx_interrupt,
                        chip->msi ? 0 : IRQF_SHARED,
-                       "hda_intel", chip)) {
+                       KBUILD_MODNAME, chip)) {
                printk(KERN_ERR "hda-intel: unable to grab IRQ %d, "
-                      "disabling device\n", chip->pci->irq);
+                      "disabling device\n", chip->irq_id);
                if (do_disconnect)
                        snd_card_disconnect(chip->card);
                return -1;
        }
-       chip->irq = chip->pci->irq;
-       pci_intx(chip->pci, !chip->msi);
+       chip->irq = chip->irq_id;
+       if (chip->pci)
+               pci_intx(chip->pci, !chip->msi);
+
        return 0;
 }
 
@@ -2132,11 +2382,19 @@ static void azx_power_notify(struct hda_bus *bus)
                        break;
                }
        }
-       if (power_on)
+       if (power_on) {
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+               azx_platform_enable_clocks(chip);
+#endif
                azx_init_chip(chip, 1);
+       }
        else if (chip->running && power_save_controller &&
-                !bus->power_keep_link_on)
+                !bus->power_keep_link_on) {
                azx_stop_chip(chip);
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+               azx_platform_disable_clocks(chip);
+#endif
+       }
 }
 #endif /* CONFIG_SND_HDA_POWER_SAVE */
 
@@ -2156,12 +2414,17 @@ static int snd_hda_codecs_inuse(struct hda_bus *bus)
        return 0;
 }
 
-static int azx_suspend(struct pci_dev *pci, pm_message_t state)
+static int azx_suspend(struct azx *chip, pm_message_t state)
 {
-       struct snd_card *card = pci_get_drvdata(pci);
-       struct azx *chip = card->private_data;
+       struct snd_card *card = chip->card;
        int i;
 
+#if defined(CONFIG_SND_HDA_PLATFORM_DRIVER) && \
+       defined(CONFIG_SND_HDA_POWER_SAVE)
+       if (chip->pdev)
+               azx_platform_enable_clocks(chip);
+#endif
+
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
        azx_clear_irq_pending(chip);
        for (i = 0; i < HDA_MAX_PCMS; i++)
@@ -2173,42 +2436,111 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state)
                free_irq(chip->irq, chip);
                chip->irq = -1;
        }
-       if (chip->msi)
-               pci_disable_msi(chip->pci);
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, pci_choose_state(pci, state));
+
+       if (chip->pci) {
+               if (chip->msi)
+                       pci_disable_msi(chip->pci);
+               pci_disable_device(chip->pci);
+               pci_save_state(chip->pci);
+               pci_set_power_state(chip->pci,
+                                   pci_choose_state(chip->pci, state));
+       }
+
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+       if (chip->pdev) {
+               /* Disable all clk references */
+               while (chip->platform_clk_enable)
+                       azx_platform_disable_clocks(chip);
+       }
+#endif
+
        return 0;
 }
 
-static int azx_resume(struct pci_dev *pci)
+static int azx_resume(struct azx *chip)
 {
-       struct snd_card *card = pci_get_drvdata(pci);
-       struct azx *chip = card->private_data;
+       struct snd_card *card = chip->card;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "hda-intel: pci_enable_device failed, "
-                      "disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+       if (chip->pdev)
+               azx_platform_enable_clocks(chip);
+#endif
+
+       if (chip->pci) {
+               pci_set_power_state(chip->pci, PCI_D0);
+               pci_restore_state(chip->pci);
+               if (pci_enable_device(chip->pci) < 0) {
+                       printk(KERN_ERR "hda-intel: pci_enable_device failed, "
+                              "disabling device\n");
+                       snd_card_disconnect(card);
+                       return -EIO;
+               }
+               pci_set_master(chip->pci);
+               if (chip->msi)
+                       if (pci_enable_msi(chip->pci) < 0)
+                               chip->msi = 0;
        }
-       pci_set_master(pci);
-       if (chip->msi)
-               if (pci_enable_msi(pci) < 0)
-                       chip->msi = 0;
+
        if (azx_acquire_irq(chip, 1) < 0)
                return -EIO;
-       azx_init_pci(chip);
+
+       if (chip->pci)
+               azx_init_pci(chip);
+
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+       if (chip->pdev)
+               azx_init_platform(chip);
+#endif
 
        if (snd_hda_codecs_inuse(chip->bus))
                azx_init_chip(chip, 1);
 
        snd_hda_resume(chip->bus);
        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+
+#if defined(CONFIG_SND_HDA_PLATFORM_DRIVER) && \
+       defined(CONFIG_SND_HDA_POWER_SAVE)
+       if (chip->pdev)
+               azx_platform_disable_clocks(chip);
+#endif
+
        return 0;
 }
+
+static int azx_suspend_pci(struct pci_dev *pci, pm_message_t state)
+{
+       struct snd_card *card = pci_get_drvdata(pci);
+       struct azx *chip = card->private_data;
+
+       return azx_suspend(chip, state);
+}
+
+static int azx_resume_pci(struct pci_dev *pci)
+{
+       struct snd_card *card = pci_get_drvdata(pci);
+       struct azx *chip = card->private_data;
+
+       return azx_resume(chip);
+}
+
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+static int azx_suspend_platform(struct platform_device *pdev,
+                               pm_message_t state)
+{
+       struct snd_card *card = dev_get_drvdata(&pdev->dev);
+       struct azx *chip = card->private_data;
+
+       return azx_suspend(chip, state);
+}
+
+static int azx_resume_platform(struct platform_device *pdev)
+{
+       struct snd_card *card = dev_get_drvdata(&pdev->dev);
+       struct azx *chip = card->private_data;
+
+       return azx_resume(chip);
+}
+#endif /* CONFIG_SND_HDA_PLATFORM_DRIVER */
 #endif /* CONFIG_PM */
 
 
@@ -2218,8 +2550,22 @@ static int azx_resume(struct pci_dev *pci)
 static int azx_halt(struct notifier_block *nb, unsigned long event, void *buf)
 {
        struct azx *chip = container_of(nb, struct azx, reboot_notifier);
+
+#if defined(CONFIG_SND_HDA_PLATFORM_DRIVER) && \
+       defined(CONFIG_SND_HDA_POWER_SAVE)
+       if (chip->pdev)
+               azx_platform_enable_clocks(chip);
+#endif
+
        snd_hda_bus_reboot_notify(chip->bus);
        azx_stop_chip(chip);
+
+#if defined(CONFIG_SND_HDA_PLATFORM_DRIVER) && \
+       defined(CONFIG_SND_HDA_POWER_SAVE)
+       if (chip->pdev)
+               azx_platform_disable_clocks(chip);
+#endif
+
        return NOTIFY_OK;
 }
 
@@ -2251,9 +2597,15 @@ static int azx_free(struct azx *chip)
                azx_stop_chip(chip);
        }
 
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+       azx_platform_disable_clocks(chip);
+       for (i = 0; i < chip->platform_clk_count; i++)
+               clk_put(chip->platform_clks[i]);
+#endif
+
        if (chip->irq >= 0)
                free_irq(chip->irq, (void*)chip);
-       if (chip->msi)
+       if (chip->pci && chip->msi)
                pci_disable_msi(chip->pci);
        if (chip->remap_addr)
                iounmap(chip->remap_addr);
@@ -2267,8 +2619,10 @@ static int azx_free(struct azx *chip)
                snd_dma_free_pages(&chip->rb);
        if (chip->posbuf.area)
                snd_dma_free_pages(&chip->posbuf);
-       pci_release_regions(chip->pci);
-       pci_disable_device(chip->pci);
+       if (chip->pci) {
+               pci_release_regions(chip->pci);
+               pci_disable_device(chip->pci);
+       }
        kfree(chip->azx_dev);
        kfree(chip);
 
@@ -2284,25 +2638,22 @@ static int azx_dev_free(struct snd_device *device)
  * white/black-listing for position_fix
  */
 static struct snd_pci_quirk position_fix_list[] __devinitdata = {
-       SND_PCI_QUIRK(0x1025, 0x009f, "Acer Aspire 5110", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB),
-       SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB),
+       SND_PCI_QUIRK(0x1028, 0x02c6, "Dell Inspiron 1010", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS M2V", POS_FIX_LPIB),
+       SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS 1101HA", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB),
-       SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba A100-259", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1297, 0x3166, "Shuttle", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1458, 0xa022, "ga-ma770-ud3", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB),
-       SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1565, 0x8218, "Biostar Microtech", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1849, 0x0888, "775Dual-VSTA", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x8086, 0x2503, "DG965OT AAD63733-203", POS_FIX_LPIB),
-       SND_PCI_QUIRK(0x8086, 0xd601, "eMachines T5212", POS_FIX_LPIB),
        {}
 };
 
@@ -2313,26 +2664,29 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
        switch (fix) {
        case POS_FIX_LPIB:
        case POS_FIX_POSBUF:
+       case POS_FIX_VIACOMBO:
                return fix;
        }
 
-       /* Check VIA/ATI HD Audio Controller exist */
-       switch (chip->driver_type) {
-       case AZX_DRIVER_VIA:
-       case AZX_DRIVER_ATI:
-               chip->via_dmapos_patch = 1;
-               /* Use link position directly, avoid any transfer problem. */
-               return POS_FIX_LPIB;
+       if (chip->pci) {
+               q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
+               if (q) {
+                       printk(KERN_INFO
+                              "hda_intel: position_fix set to %d "
+                              "for device %04x:%04x\n",
+                              q->value, q->subvendor, q->subdevice);
+                       return q->value;
+               }
        }
-       chip->via_dmapos_patch = 0;
 
-       q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
-       if (q) {
-               printk(KERN_INFO
-                      "hda_intel: position_fix set to %d "
-                      "for device %04x:%04x\n",
-                      q->value, q->subvendor, q->subdevice);
-               return q->value;
+       /* Check VIA/ATI HD Audio Controller exist */
+       if (chip->driver_caps & AZX_DCAPS_POSFIX_VIA) {
+               snd_printd(SFX "Using VIACOMBO position fix\n");
+               return POS_FIX_VIACOMBO;
+       }
+       if (chip->driver_caps & AZX_DCAPS_POSFIX_LPIB) {
+               snd_printd(SFX "Using LPIB position fix\n");
+               return POS_FIX_LPIB;
        }
        return POS_FIX_AUTO;
 }
@@ -2364,7 +2718,7 @@ static void __devinit check_probe_mask(struct azx *chip, int dev)
        const struct snd_pci_quirk *q;
 
        chip->codec_probe_mask = probe_mask[dev];
-       if (chip->codec_probe_mask == -1) {
+       if (chip->pci && (chip->codec_probe_mask == -1)) {
                q = snd_pci_quirk_lookup(chip->pci, probe_mask_list);
                if (q) {
                        printk(KERN_INFO
@@ -2400,6 +2754,12 @@ static void __devinit check_msi(struct azx *chip)
 {
        const struct snd_pci_quirk *q;
 
+       /* Disable MSI if chip is not a pci device */
+       if (!chip->pci) {
+               chip->msi = 0;
+               return;
+       }
+
        if (enable_msi >= 0) {
                chip->msi = !!enable_msi;
                return;
@@ -2415,22 +2775,31 @@ static void __devinit check_msi(struct azx *chip)
        }
 
        /* NVidia chipsets seem to cause troubles with MSI */
-       if (chip->driver_type == AZX_DRIVER_NVIDIA) {
-               printk(KERN_INFO "hda_intel: Disable MSI for Nvidia chipset\n");
+       if (chip->driver_caps & AZX_DCAPS_NO_MSI) {
+               printk(KERN_INFO "hda_intel: Disabling MSI\n");
                chip->msi = 0;
        }
 }
 
+#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA
+static const char *tegra_clk_names[] __devinitdata = {
+       "hda",
+       "hda2codec",
+       "hda2hdmi",
+};
+static struct clk *tegra_clks[ARRAY_SIZE(tegra_clk_names)];
+#endif
 
 /*
  * constructor
  */
 static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
-                               int dev, int driver_type,
+                               struct platform_device *pdev,
+                               int dev, unsigned int driver_caps,
                                struct azx **rchip)
 {
        struct azx *chip;
-       int i, err;
+       int i, err = 0;
        unsigned short gcap;
        static struct snd_device_ops ops = {
                .dev_free = azx_dev_free,
@@ -2438,14 +2807,17 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
 
        *rchip = NULL;
 
-       err = pci_enable_device(pci);
-       if (err < 0)
-               return err;
+       if (pci) {
+               err = pci_enable_device(pci);
+               if (err < 0)
+                       return err;
+       }
 
        chip = kzalloc(sizeof(*chip), GFP_KERNEL);
        if (!chip) {
                snd_printk(KERN_ERR SFX "cannot allocate chip\n");
-               pci_disable_device(pci);
+               if (pci)
+                       pci_disable_device(pci);
                return -ENOMEM;
        }
 
@@ -2453,8 +2825,12 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        mutex_init(&chip->open_mutex);
        chip->card = card;
        chip->pci = pci;
+       chip->pdev = pdev;
+       chip->dev = pci ? snd_dma_pci_data(pci) : &pdev->dev;
+       chip->irq_id = pci ? pci->irq : platform_get_irq(pdev, 0);
        chip->irq = -1;
-       chip->driver_type = driver_type;
+       chip->driver_caps = driver_caps;
+       chip->driver_type = driver_caps & 0xff;
        check_msi(chip);
        chip->dev_index = dev;
        INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work);
@@ -2487,39 +2863,105 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        }
 #endif
 
-       err = pci_request_regions(pci, "ICH HD audio");
-       if (err < 0) {
-               kfree(chip);
-               pci_disable_device(pci);
-               return err;
-       }
+       if (chip->pci) {
+               err = pci_request_regions(pci, "ICH HD audio");
+               if (err < 0) {
+                       kfree(chip);
+                       pci_disable_device(pci);
+                       return err;
+               }
 
-       chip->addr = pci_resource_start(pci, 0);
-       chip->remap_addr = pci_ioremap_bar(pci, 0);
-       if (chip->remap_addr == NULL) {
-               snd_printk(KERN_ERR SFX "ioremap error\n");
-               err = -ENXIO;
-               goto errout;
+               chip->addr = pci_resource_start(pci, 0);
+               chip->remap_addr = pci_ioremap_bar(pci, 0);
+               if (chip->remap_addr == NULL) {
+                       snd_printk(KERN_ERR SFX "ioremap error\n");
+                       err = -ENXIO;
+                       goto errout;
+               }
+
+               if (chip->msi)
+                       if (pci_enable_msi(pci) < 0)
+                               chip->msi = 0;
        }
 
-       if (chip->msi)
-               if (pci_enable_msi(pci) < 0)
-                       chip->msi = 0;
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+       if (chip->pdev) {
+               struct resource *res, *region;
+
+               /* Do platform specific initialization */
+               switch (chip->driver_type) {
+#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA
+               case AZX_DRIVER_NVIDIA_TEGRA:
+                       chip->platform_clk_count = ARRAY_SIZE(tegra_clk_names);
+                       for (i = 0; i < chip->platform_clk_count; i++) {
+                               tegra_clks[i] = clk_get(&pdev->dev,
+                                                       tegra_clk_names[i]);
+                               if (IS_ERR_OR_NULL(tegra_clks[i])) {
+                                       err = PTR_ERR(tegra_clks[i]);
+                                       goto errout;
+                               }
+                       }
+                       chip->platform_clks = tegra_clks;
+                       break;
+#endif
+               default:
+                       break;
+               }
+
+               azx_platform_enable_clocks(chip);
+
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+               if (res == NULL) {
+                       err = EINVAL;
+                       goto errout;
+               }
+
+               region = devm_request_mem_region(chip->dev, res->start,
+                                                resource_size(res),
+                                                pdev->name);
+               if (!region) {
+                       snd_printk(KERN_ERR SFX "Mem region already claimed\n");
+                       err = -EINVAL;
+                       goto errout;
+               }
+
+               chip->addr = res->start;
+               chip->remap_addr = devm_ioremap(chip->dev,
+                                               res->start,
+                                               resource_size(res));
+               if (chip->remap_addr == NULL) {
+                       snd_printk(KERN_ERR SFX "ioremap error\n");
+                       err = -ENXIO;
+                       goto errout;
+               }
+
+#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA
+               if (chip->driver_type == AZX_DRIVER_NVIDIA_TEGRA) {
+                       chip->remap_config_addr = chip->remap_addr;
+                       chip->remap_addr += NVIDIA_TEGRA_HDA_BAR0_OFFSET;
+                       chip->addr += NVIDIA_TEGRA_HDA_BAR0_OFFSET;
+               }
+#endif
+
+               azx_init_platform(chip);
+       }
+#endif /* CONFIG_SND_HDA_PLATFORM_DRIVER */
 
        if (azx_acquire_irq(chip, 0) < 0) {
                err = -EBUSY;
                goto errout;
        }
 
-       pci_set_master(pci);
+       if (chip->pci)
+               pci_set_master(pci);
+
        synchronize_irq(chip->irq);
 
        gcap = azx_readw(chip, GCAP);
        snd_printdd(SFX "chipset global capabilities = 0x%x\n", gcap);
 
        /* disable SB600 64bit support for safety */
-       if ((chip->driver_type == AZX_DRIVER_ATI) ||
-           (chip->driver_type == AZX_DRIVER_ATIHDMI)) {
+       if (chip->pci && chip->pci->vendor == PCI_VENDOR_ID_ATI) {
                struct pci_dev *p_smbus;
                p_smbus = pci_get_device(PCI_VENDOR_ID_ATI,
                                         PCI_DEVICE_ID_ATI_SBX00_SMBUS,
@@ -2531,17 +2973,21 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
                }
        }
 
-       /* disable 64bit DMA address for Teradici */
-       /* it does not work with device 6549:1200 subsys e4a2:040b */
-       if (chip->driver_type == AZX_DRIVER_TERA)
+       /* disable 64bit DMA address on some devices */
+       if (chip->driver_caps & AZX_DCAPS_NO_64BIT) {
+               snd_printd(SFX "Disabling 64bit DMA\n");
                gcap &= ~ICH6_GCAP_64OK;
+       }
 
-       /* allow 64bit DMA address if supported by H/W */
-       if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
-               pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64));
-       else {
-               pci_set_dma_mask(pci, DMA_BIT_MASK(32));
-               pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32));
+       if (chip->pci) {
+               /* allow 64bit DMA address if supported by H/W */
+               if ((gcap & ICH6_GCAP_64OK) &&
+                   !pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
+                       pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64));
+               else {
+                       pci_set_dma_mask(pci, DMA_BIT_MASK(32));
+                       pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32));
+               }
        }
 
        /* read number of streams from GCAP register instead of using
@@ -2581,7 +3027,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        for (i = 0; i < chip->num_streams; i++) {
                /* allocate memory for the BDL for each stream */
                err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
-                                         snd_dma_pci_data(chip->pci),
+                                         chip->dev,
                                          BDL_SIZE, &chip->azx_dev[i].bdl);
                if (err < 0) {
                        snd_printk(KERN_ERR SFX "cannot allocate BDL\n");
@@ -2590,7 +3036,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        }
        /* allocate memory for the position buffer */
        err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
-                                 snd_dma_pci_data(chip->pci),
+                                 chip->dev,
                                  chip->num_streams * 8, &chip->posbuf);
        if (err < 0) {
                snd_printk(KERN_ERR SFX "cannot allocate posbuf\n");
@@ -2605,7 +3051,8 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        azx_init_stream(chip);
 
        /* initialize chip */
-       azx_init_pci(chip);
+       if (chip->pci)
+               azx_init_pci(chip);
        azx_init_chip(chip, (probe_only[dev] & 2) == 0);
 
        /* codec detection */
@@ -2650,11 +3097,13 @@ static void power_down_all_codecs(struct azx *chip)
 }
 
 static int __devinit azx_probe(struct pci_dev *pci,
-                              const struct pci_device_id *pci_id)
+                              struct platform_device *pdev,
+                              int driver_data)
 {
        static int dev;
        struct snd_card *card;
        struct azx *chip;
+       struct device *azx_dev = pci ? &pci->dev : &pdev->dev;
        int err;
 
        if (dev >= SNDRV_CARDS)
@@ -2671,9 +3120,9 @@ static int __devinit azx_probe(struct pci_dev *pci,
        }
 
        /* set this here since it's referred in snd_hda_load_patch() */
-       snd_card_set_dev(card, &pci->dev);
+       snd_card_set_dev(card, azx_dev);
 
-       err = azx_create(card, pci, dev, pci_id->driver_data, &chip);
+       err = azx_create(card, pci, pdev, dev, driver_data, &chip);
        if (err < 0)
                goto out_free;
        card->private_data = chip;
@@ -2687,7 +3136,7 @@ static int __devinit azx_probe(struct pci_dev *pci,
        if (err < 0)
                goto out_free;
 #ifdef CONFIG_SND_HDA_PATCH_LOADER
-       if (patch[dev]) {
+       if (patch[dev] && *patch[dev]) {
                snd_printk(KERN_ERR SFX "Applying patch firmware '%s'\n",
                           patch[dev]);
                err = snd_hda_load_patch(chip->bus, patch[dev]);
@@ -2715,7 +3164,11 @@ static int __devinit azx_probe(struct pci_dev *pci,
        if (err < 0)
                goto out_free;
 
-       pci_set_drvdata(pci, card);
+       if (pci)
+               pci_set_drvdata(pci, card);
+       else
+               dev_set_drvdata(&pdev->dev, card);
+
        chip->running = 1;
        power_down_all_codecs(chip);
        azx_notifier_register(chip);
@@ -2727,45 +3180,93 @@ out_free:
        return err;
 }
 
-static void __devexit azx_remove(struct pci_dev *pci)
+static int __devinit azx_probe_pci(struct pci_dev *pci,
+                                  const struct pci_device_id *pci_id)
+{
+       return azx_probe(pci, NULL, pci_id->driver_data);
+}
+
+static void __devexit azx_remove_pci(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
        pci_set_drvdata(pci, NULL);
 }
 
 /* PCI IDs */
-static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
+static DEFINE_PCI_DEVICE_TABLE(azx_pci_ids) = {
        /* CPT */
-       { PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH },
+       { PCI_DEVICE(0x8086, 0x1c20),
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP },
        /* PBG */
-       { PCI_DEVICE(0x8086, 0x1d20), .driver_data = AZX_DRIVER_PCH },
+       { PCI_DEVICE(0x8086, 0x1d20),
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP },
+       /* Panther Point */
+       { PCI_DEVICE(0x8086, 0x1e20),
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP },
        /* SCH */
-       { PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH },
+       { PCI_DEVICE(0x8086, 0x811b),
+         .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP },
+       { PCI_DEVICE(0x8086, 0x2668),
+         .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC },  /* ICH6 */
+       { PCI_DEVICE(0x8086, 0x27d8),
+         .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC },  /* ICH7 */
+       { PCI_DEVICE(0x8086, 0x269a),
+         .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC },  /* ESB2 */
+       { PCI_DEVICE(0x8086, 0x284b),
+         .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC },  /* ICH8 */
+       { PCI_DEVICE(0x8086, 0x293e),
+         .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC },  /* ICH9 */
+       { PCI_DEVICE(0x8086, 0x293f),
+         .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC },  /* ICH9 */
+       { PCI_DEVICE(0x8086, 0x3a3e),
+         .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC },  /* ICH10 */
+       { PCI_DEVICE(0x8086, 0x3a6e),
+         .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC },  /* ICH10 */
        /* Generic Intel */
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID),
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
          .class_mask = 0xffffff,
          .driver_data = AZX_DRIVER_ICH },
-       /* ATI SB 450/600 */
-       { PCI_DEVICE(0x1002, 0x437b), .driver_data = AZX_DRIVER_ATI },
-       { PCI_DEVICE(0x1002, 0x4383), .driver_data = AZX_DRIVER_ATI },
+       /* ATI SB 450/600/700/800/900 */
+       { PCI_DEVICE(0x1002, 0x437b),
+         .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB },
+       { PCI_DEVICE(0x1002, 0x4383),
+         .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB },
+       /* AMD Hudson */
+       { PCI_DEVICE(0x1022, 0x780d),
+         .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB },
        /* ATI HDMI */
-       { PCI_DEVICE(0x1002, 0x793b), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0x7919), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0x960f), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0x970f), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa00), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa08), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa10), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa18), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa20), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa28), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa30), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa38), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa40), .driver_data = AZX_DRIVER_ATIHDMI },
-       { PCI_DEVICE(0x1002, 0xaa48), .driver_data = AZX_DRIVER_ATIHDMI },
+       { PCI_DEVICE(0x1002, 0x793b),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0x7919),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0x960f),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0x970f),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa00),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa08),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa10),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa18),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa20),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa28),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa30),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa38),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa40),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaa48),
+         .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
        /* VIA VT8251/VT8237A */
-       { PCI_DEVICE(0x1106, 0x3288), .driver_data = AZX_DRIVER_VIA },
+       { PCI_DEVICE(0x1106, 0x3288),
+         .driver_data = AZX_DRIVER_VIA | AZX_DCAPS_POSFIX_VIA },
        /* SIS966 */
        { PCI_DEVICE(0x1039, 0x7502), .driver_data = AZX_DRIVER_SIS },
        /* ULI M5461 */
@@ -2774,9 +3275,10 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID),
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
          .class_mask = 0xffffff,
-         .driver_data = AZX_DRIVER_NVIDIA },
+         .driver_data = AZX_DRIVER_NVIDIA | AZX_DCAPS_PRESET_NVIDIA },
        /* Teradici */
-       { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA },
+       { PCI_DEVICE(0x6549, 0x1200),
+         .driver_data = AZX_DRIVER_TERA | AZX_DCAPS_NO_64BIT },
        /* Creative X-Fi (CA0110-IBG) */
 #if !defined(CONFIG_SND_CTXFI) && !defined(CONFIG_SND_CTXFI_MODULE)
        /* the following entry conflicts with snd-ctxfi driver,
@@ -2786,43 +3288,108 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_ANY_ID),
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
          .class_mask = 0xffffff,
-         .driver_data = AZX_DRIVER_GENERIC },
+         .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
+         AZX_DCAPS_RIRB_PRE_DELAY | AZX_DCAPS_POSFIX_LPIB },
 #else
        /* this entry seems still valid -- i.e. without emu20kx chip */
-       { PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_GENERIC },
+       { PCI_DEVICE(0x1102, 0x0009),
+         .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
+         AZX_DCAPS_RIRB_PRE_DELAY | AZX_DCAPS_POSFIX_LPIB },
 #endif
+       /* Vortex86MX */
+       { PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
+       /* VMware HDAudio */
+       { PCI_DEVICE(0x15ad, 0x1977), .driver_data = AZX_DRIVER_GENERIC },
        /* AMD/ATI Generic, PCI class code and Vendor ID for HD Audio */
        { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID),
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
          .class_mask = 0xffffff,
-         .driver_data = AZX_DRIVER_GENERIC },
+         .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_HDMI },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_ANY_ID),
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
          .class_mask = 0xffffff,
-         .driver_data = AZX_DRIVER_GENERIC },
+         .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_HDMI },
        { 0, }
 };
-MODULE_DEVICE_TABLE(pci, azx_ids);
+MODULE_DEVICE_TABLE(pci, azx_pci_ids);
 
 /* pci_driver definition */
 static struct pci_driver driver = {
-       .name = "HDA Intel",
-       .id_table = azx_ids,
-       .probe = azx_probe,
-       .remove = __devexit_p(azx_remove),
+       .name = KBUILD_MODNAME,
+       .id_table = azx_pci_ids,
+       .probe = azx_probe_pci,
+       .remove = __devexit_p(azx_remove_pci),
+#ifdef CONFIG_PM
+       .suspend = azx_suspend_pci,
+       .resume = azx_resume_pci,
+#endif
+};
+
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+static int __devinit azx_probe_platform(struct platform_device *pdev)
+{
+       const struct platform_device_id *pdev_id = platform_get_device_id(pdev);
+
+       return azx_probe(NULL, pdev, pdev_id->driver_data);
+}
+
+static int __devexit azx_remove_platform(struct platform_device *pdev)
+{
+       return snd_card_free(dev_get_drvdata(&pdev->dev));
+}
+
+static const struct platform_device_id azx_platform_ids[] = {
+#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA
+       { "tegra30-hda",
+         .driver_data = AZX_DRIVER_NVIDIA_TEGRA | AZX_DCAPS_RIRB_DELAY },
+#endif
+       { },
+};
+MODULE_DEVICE_TABLE(platform, azx_platform_ids);
+
+/* platform_driver definition */
+static struct platform_driver hda_platform_driver = {
+       .driver = {
+               .name = "hda-platform"
+       },
+       .probe = azx_probe_platform,
+       .remove = __devexit_p(azx_remove_platform),
+       .id_table = azx_platform_ids,
 #ifdef CONFIG_PM
-       .suspend = azx_suspend,
-       .resume = azx_resume,
+       .suspend = azx_suspend_platform,
+       .resume = azx_resume_platform,
 #endif
 };
+#endif /* CONFIG_SND_HDA_PLATFORM_DRIVER */
 
 static int __init alsa_card_azx_init(void)
 {
-       return pci_register_driver(&driver);
+       int err = 0;
+
+       err = pci_register_driver(&driver);
+       if (err < 0) {
+               snd_printk(KERN_ERR SFX "Failed to register pci driver\n");
+               return err;
+       }
+
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+       err = platform_driver_register(&hda_platform_driver);
+       if (err < 0) {
+               snd_printk(KERN_ERR SFX "Failed to register platform driver\n");
+               pci_unregister_driver(&driver);
+               return err;
+       }
+#endif
+
+       return 0;
 }
 
 static void __exit alsa_card_azx_exit(void)
 {
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+       platform_driver_unregister(&hda_platform_driver);
+#endif
+
        pci_unregister_driver(&driver);
 }