From: Maruthi Srinivas Bayyavarapu <Maruthi.Bayyavarapu@xxxxxxx> ACP 3x IP have I2S controller device as one of IP blocks. Create a platform device for it, so that PCM platform driver can be binded to this device. Pass PCI resources like MMIO, irq to the platform device. Signed-off-by: Maruthi Bayyavarapu <maruthi.bayyavarapu at amd.com> Signed-off-by: Alex Deucher <alexander.deucher at amd.com> --- sound/soc/amd/raven/acp3x.h | 3 ++ sound/soc/amd/raven/pci-acp3x.c | 68 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/sound/soc/amd/raven/acp3x.h b/sound/soc/amd/raven/acp3x.h index e9b4df0..1996faf 100644 --- a/sound/soc/amd/raven/acp3x.h +++ b/sound/soc/amd/raven/acp3x.h @@ -1,6 +1,9 @@ #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 static inline u32 rv_readl(void __iomem *base_addr) { diff --git a/sound/soc/amd/raven/pci-acp3x.c b/sound/soc/amd/raven/pci-acp3x.c index 204212b..a182013 100644 --- a/sound/soc/amd/raven/pci-acp3x.c +++ b/sound/soc/amd/raven/pci-acp3x.c @@ -15,19 +15,26 @@ #include <linux/pci.h> #include <linux/module.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"); @@ -47,6 +54,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 == NULL) { @@ -56,8 +72,55 @@ static int snd_acp3x_probe(struct pci_dev *pci, pci_set_drvdata(pci, adata); + val = rv_readl(adata->acp3x_base + mmACP_I2S_PIN_CONFIG); + if (val == 0x4) { + adata->res = devm_kzalloc(&pci->dev, + sizeof(struct resource) * 2, + GFP_KERNEL); + if (adata->res == NULL) { + 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 == NULL) { + dev_err(&pci->dev, "cannot register %s device\n", + pdevinfo.name); + ret = -ENODEV; + goto unmap_mmio; + } + } else { + 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 +133,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); } -- 2.5.5