ASoC: amd: create ACP3x PCM platform device
authorVijendar Mukunda <Vijendar.Mukunda@amd.com>
Mon, 12 Nov 2018 05:34:54 +0000 (11:04 +0530)
committerMark Brown <broonie@kernel.org>
Tue, 13 Nov 2018 19:44:04 +0000 (11:44 -0800)
ACP 3x IP has I2S controller device as one of IP blocks.
Create a platform device for it, so that the PCM platform driver
can be bound to this device. Pass PCI resources like MMIO, irq
to the platform device.

Signed-off-by: Maruthi Bayyavarapu <maruthi.bayyavarapu@amd.com>
Tested-by: Ravulapati Vishnu vardhan Rao <vishnuvardhanrao.ravulapati@amd.com>
Signed-off-by: Vijendar Mukunda <vijendar.mukunda@amd.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/amd/raven/acp3x.h
sound/soc/amd/raven/pci-acp3x.c

index e9b4df0c67265bf7438240e5d7ec291fb5436364..83b1ed8f60603d7a06fb5be7d28b6ed2e07ca056 100644 (file)
@@ -1,6 +1,10 @@
 #include "chip_offset_byte.h"
 
 #define ACP3x_PHY_BASE_ADDRESS 0x1240000
+#define        ACP3x_I2S_MODE  0
+#define        ACP3x_REG_START 0x1240000
+#define        ACP3x_REG_END   0x1250200
+#define I2S_MODE       0x04
 
 static inline u32 rv_readl(void __iomem *base_addr)
 {
index 27588ed066c9d6efefeb3503d9a9941d00bfa73f..0700162b0ed191860ab3496b5977f816e78a8501 100644 (file)
 #include <linux/pci.h>
 #include <linux/module.h>
 #include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
 
 #include "acp3x.h"
 
 struct acp3x_dev_data {
        void __iomem *acp3x_base;
+       bool acp3x_audio_mode;
+       struct resource *res;
+       struct platform_device *pdev;
 };
 
 static int snd_acp3x_probe(struct pci_dev *pci,
                           const struct pci_device_id *pci_id)
 {
        int ret;
-       u32 addr;
+       u32 addr, val;
        struct acp3x_dev_data *adata;
+       struct platform_device_info pdevinfo;
+       unsigned int irqflags;
 
        if (pci_enable_device(pci)) {
                dev_err(&pci->dev, "pci_enable_device failed\n");
@@ -48,6 +55,15 @@ static int snd_acp3x_probe(struct pci_dev *pci,
                goto release_regions;
        }
 
+       /* check for msi interrupt support */
+       ret = pci_enable_msi(pci);
+       if (ret)
+               /* msi is not enabled */
+               irqflags = IRQF_SHARED;
+       else
+               /* msi is enabled */
+               irqflags = 0;
+
        addr = pci_resource_start(pci, 0);
        adata->acp3x_base = ioremap(addr, pci_resource_len(pci, 0));
        if (!adata->acp3x_base) {
@@ -56,8 +72,57 @@ static int snd_acp3x_probe(struct pci_dev *pci,
        }
        pci_set_master(pci);
        pci_set_drvdata(pci, adata);
+
+       val = rv_readl(adata->acp3x_base + mmACP_I2S_PIN_CONFIG);
+       switch (val) {
+       case I2S_MODE:
+               adata->res = devm_kzalloc(&pci->dev,
+                                         sizeof(struct resource) * 2,
+                                         GFP_KERNEL);
+               if (!adata->res) {
+                       ret = -ENOMEM;
+                       goto unmap_mmio;
+               }
+
+               adata->res[0].name = "acp3x_i2s_iomem";
+               adata->res[0].flags = IORESOURCE_MEM;
+               adata->res[0].start = addr;
+               adata->res[0].end = addr + (ACP3x_REG_END - ACP3x_REG_START);
+
+               adata->res[1].name = "acp3x_i2s_irq";
+               adata->res[1].flags = IORESOURCE_IRQ;
+               adata->res[1].start = pci->irq;
+               adata->res[1].end = pci->irq;
+
+               adata->acp3x_audio_mode = ACP3x_I2S_MODE;
+
+               memset(&pdevinfo, 0, sizeof(pdevinfo));
+               pdevinfo.name = "acp3x_rv_i2s";
+               pdevinfo.id = 0;
+               pdevinfo.parent = &pci->dev;
+               pdevinfo.num_res = 2;
+               pdevinfo.res = adata->res;
+               pdevinfo.data = &irqflags;
+               pdevinfo.size_data = sizeof(irqflags);
+
+               adata->pdev = platform_device_register_full(&pdevinfo);
+               if (!adata->pdev) {
+                       dev_err(&pci->dev, "cannot register %s device\n",
+                               pdevinfo.name);
+                       ret = -ENODEV;
+                       goto unmap_mmio;
+               }
+               break;
+       default:
+               dev_err(&pci->dev, "Inavlid ACP audio mode : %d\n", val);
+               ret = -ENODEV;
+               goto unmap_mmio;
+       }
        return 0;
 
+unmap_mmio:
+       pci_disable_msi(pci);
+       iounmap(adata->acp3x_base);
 release_regions:
        pci_release_regions(pci);
 disable_pci:
@@ -70,7 +135,10 @@ static void snd_acp3x_remove(struct pci_dev *pci)
 {
        struct acp3x_dev_data *adata = pci_get_drvdata(pci);
 
+       platform_device_unregister(adata->pdev);
        iounmap(adata->acp3x_base);
+
+       pci_disable_msi(pci);
        pci_release_regions(pci);
        pci_disable_device(pci);
 }