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 --- sound/soc/amd/raven/acp3x.h | 4 +++ sound/soc/amd/raven/pci-acp3x.c | 70 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 73 insertions(+), 1 deletion(-)
diff --git a/sound/soc/amd/raven/acp3x.h b/sound/soc/amd/raven/acp3x.h index e9b4df0..83b1ed8 100644 --- a/sound/soc/amd/raven/acp3x.h +++ b/sound/soc/amd/raven/acp3x.h @@ -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) { diff --git a/sound/soc/amd/raven/pci-acp3x.c b/sound/soc/amd/raven/pci-acp3x.c index 27588ed..0700162 100644 --- a/sound/soc/amd/raven/pci-acp3x.c +++ b/sound/soc/amd/raven/pci-acp3x.c @@ -16,19 +16,26 @@ #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); }