ALSA: hda: Add hda platform driver support
Sumit Bhattacharya [Tue, 8 Nov 2011 15:35:52 +0000 (20:35 +0530)]
It is possible that some chips have a HD-audio controller which is not
installed on a PCI bus. Nvidia Tegra has Azalia HD-audio controller
but it uses proprietery interface to communicate with the controller.

This commit adds a platform driver interface support to HDA driver
which can be used by non-PCI bus based HDA controller.

Bug 872652

Signed-off-by: Sumit Bhattacharya <sumitb@nvidia.com>

Change-Id: I73fb55858387f511738a09de3f52e7d326353ebf
Reviewed-on: http://git-master/r/59504
Tested-by: Sumit Bhattacharya <sumitb@nvidia.com>
Reviewed-by: Scott Peterson <speterson@nvidia.com>
Reviewed-by: Stephen Warren <swarren@nvidia.com>

Rebase-Id: R51a3866f0cb9889d947d6c7045ad7e8976cb3e69

sound/pci/hda/Kconfig
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_intel.c

index bb7e102..083731d 100644 (file)
@@ -84,6 +84,13 @@ config SND_HDA_PATCH_LOADER
 
          This option turns on hwdep and reconfig features automatically.
 
+config SND_HDA_PLATFORM_DRIVER
+       bool "Build platform driver interface for HD-audio driver"
+       help
+         Say Y here to build a platform driver interface for HD-audio driver.
+         This interface can be used by platforms which have an Azalia
+         controller not installed on a PCI bus.
+
 config SND_HDA_CODEC_REALTEK
        bool "Build Realtek HD-audio codec support"
        default y
index 755f2b0..8f801ae 100644 (file)
@@ -21,6 +21,8 @@
 #ifndef __SOUND_HDA_CODEC_H
 #define __SOUND_HDA_CODEC_H
 
+#include <linux/platform_device.h>
+
 #include <sound/info.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
@@ -617,6 +619,7 @@ struct hda_bus_ops {
 struct hda_bus_template {
        void *private_data;
        struct pci_dev *pci;
+       struct platform_device *pdev;
        const char *modelname;
        int *power_save;
        struct hda_bus_ops ops;
index f665975..d1cfd80 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"
@@ -388,6 +389,9 @@ 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 */
@@ -404,6 +408,12 @@ struct azx {
        void __iomem *remap_addr;
        int irq;
 
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+       /* platform driver clocks */
+       struct clk **platform_clks;
+       int platform_clk_count;
+#endif
+
        /* locks */
        spinlock_t reg_lock;
        struct mutex open_mutex;
@@ -557,7 +567,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");
@@ -1131,6 +1141,28 @@ static void azx_init_pci(struct azx *chip)
         }
 }
 
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+/* Platform driver specific initiallization */
+static void azx_init_platform(struct azx *chip)
+{
+}
+
+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]);
+}
+
+static void azx_platform_disable_clocks(struct azx *chip)
+{
+       int i;
+
+       for (i = 0; i < chip->platform_clk_count; i++)
+               clk_disable(chip->platform_clks[i]);
+}
+#endif /* CONFIG_SND_HDA_PLATFORM_DRIVER */
 
 static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev);
 
@@ -1437,6 +1469,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;
@@ -2126,7 +2159,7 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
        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),
+                                             chip->dev,
                                              size, MAX_PREALLOC_SIZE);
        return 0;
 }
@@ -2168,17 +2201,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,
                        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;
 }
 
@@ -2240,10 +2275,9 @@ 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;
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
@@ -2257,34 +2291,58 @@ 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)
+               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);
@@ -2293,6 +2351,41 @@ static int azx_resume(struct pci_dev *pci)
        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
        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 */
 
 
@@ -2335,9 +2428,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);
@@ -2351,8 +2450,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);
 
@@ -2397,13 +2498,15 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
                return fix;
        }
 
-       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;
+       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;
+               }
        }
 
        /* Check VIA/ATI HD Audio Controller exist */
@@ -2445,7 +2548,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
@@ -2481,6 +2584,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;
@@ -2507,6 +2616,7 @@ static void __devinit check_msi(struct azx *chip)
  * constructor
  */
 static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
+                               struct platform_device *pdev,
                                int dev, unsigned int driver_caps,
                                struct azx **rchip)
 {
@@ -2519,14 +2629,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;
        }
 
@@ -2534,6 +2647,9 @@ 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_caps = driver_caps;
        chip->driver_type = driver_caps & 0xff;
@@ -2569,38 +2685,76 @@ 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;
+
+               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;
+               }
+
+               azx_init_platform(chip);
+       }
+#endif
 
        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->pci->vendor == PCI_VENDOR_ID_ATI) {
+       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,
@@ -2618,12 +2772,15 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
                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
@@ -2663,7 +2820,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");
@@ -2672,7 +2829,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");
@@ -2687,7 +2844,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 */
@@ -2732,11 +2890,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)
@@ -2753,9 +2913,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;
@@ -2797,7 +2957,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);
@@ -2809,14 +2973,20 @@ 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 | AZX_DCAPS_SCH_SNOOP },
@@ -2934,27 +3104,81 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
          .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 = KBUILD_MODNAME,
-       .id_table = azx_ids,
-       .probe = azx_probe,
-       .remove = __devexit_p(azx_remove),
+       .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[] = {
+       { },
+};
+MODULE_DEVICE_TABLE(platform, azx_platform_ids);
+
+/* platform_driver definition */
+static struct platform_driver driver_platform = {
+       .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(&driver_platform);
+       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(&driver_platform);
+#endif
+
        pci_unregister_driver(&driver);
 }