Commit 603f2ded authored by Vijendar Mukunda's avatar Vijendar Mukunda Committed by Mark Brown

ASoC: amd: create acp5x platform devices

ACP5.x IP has multiple I2S controllers and DMA controller.
Create platform devices for I2S HS controller instance, I2S SP controller
instance and DMA controller.
Pass PCI resources like MMIO, irq to these platform devices.
Reviewed-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: default avatarVijendar Mukunda <Vijendar.Mukunda@amd.com>
Link: https://lore.kernel.org/r/20210721180430.11571-5-Vijendar.Mukunda@amd.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 5d9ee88a
...@@ -22,6 +22,17 @@ ...@@ -22,6 +22,17 @@
#define ACP_ERR_INTR_MASK 0x20000000 #define ACP_ERR_INTR_MASK 0x20000000
#define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF #define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF
#define ACP5x_DEVS 3
#define ACP5x_REG_START 0x1240000
#define ACP5x_REG_END 0x1250200
#define ACP5x_I2STDM_REG_START 0x1242400
#define ACP5x_I2STDM_REG_END 0x1242410
#define ACP5x_HS_TDM_REG_START 0x1242814
#define ACP5x_HS_TDM_REG_END 0x1242824
#define I2S_MODE 0
#define ACP5x_I2S_MODE 1
#define ACP5x_RES 4
/* common header file uses exact offset rather than relative /* common header file uses exact offset rather than relative
* offset which requires subtraction logic from base_addr * offset which requires subtraction logic from base_addr
* for accessing ACP5x MMIO space registers * for accessing ACP5x MMIO space registers
......
...@@ -8,11 +8,16 @@ ...@@ -8,11 +8,16 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include "acp5x.h" #include "acp5x.h"
struct acp5x_dev_data { struct acp5x_dev_data {
void __iomem *acp5x_base; void __iomem *acp5x_base;
bool acp5x_audio_mode;
struct resource *res;
struct platform_device *pdev[ACP5x_DEVS];
}; };
static int acp5x_power_on(void __iomem *acp5x_base) static int acp5x_power_on(void __iomem *acp5x_base)
...@@ -114,9 +119,12 @@ static int snd_acp5x_probe(struct pci_dev *pci, ...@@ -114,9 +119,12 @@ static int snd_acp5x_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id) const struct pci_device_id *pci_id)
{ {
struct acp5x_dev_data *adata; struct acp5x_dev_data *adata;
int ret; struct platform_device_info pdevinfo[ACP5x_DEVS];
u32 addr; unsigned int irqflags;
int ret, i;
u32 addr, val;
irqflags = IRQF_SHARED;
if (pci->revision != 0x50) if (pci->revision != 0x50)
return -ENODEV; return -ENODEV;
...@@ -150,6 +158,82 @@ static int snd_acp5x_probe(struct pci_dev *pci, ...@@ -150,6 +158,82 @@ static int snd_acp5x_probe(struct pci_dev *pci,
if (ret) if (ret)
goto release_regions; goto release_regions;
val = acp_readl(adata->acp5x_base + ACP_PIN_CONFIG);
switch (val) {
case I2S_MODE:
adata->res = devm_kzalloc(&pci->dev,
sizeof(struct resource) * ACP5x_RES,
GFP_KERNEL);
if (!adata->res) {
ret = -ENOMEM;
goto de_init;
}
adata->res[0].name = "acp5x_i2s_iomem";
adata->res[0].flags = IORESOURCE_MEM;
adata->res[0].start = addr;
adata->res[0].end = addr + (ACP5x_REG_END - ACP5x_REG_START);
adata->res[1].name = "acp5x_i2s_sp";
adata->res[1].flags = IORESOURCE_MEM;
adata->res[1].start = addr + ACP5x_I2STDM_REG_START;
adata->res[1].end = addr + ACP5x_I2STDM_REG_END;
adata->res[2].name = "acp5x_i2s_hs";
adata->res[2].flags = IORESOURCE_MEM;
adata->res[2].start = addr + ACP5x_HS_TDM_REG_START;
adata->res[2].end = addr + ACP5x_HS_TDM_REG_END;
adata->res[3].name = "acp5x_i2s_irq";
adata->res[3].flags = IORESOURCE_IRQ;
adata->res[3].start = pci->irq;
adata->res[3].end = adata->res[3].start;
adata->acp5x_audio_mode = ACP5x_I2S_MODE;
memset(&pdevinfo, 0, sizeof(pdevinfo));
pdevinfo[0].name = "acp5x_i2s_dma";
pdevinfo[0].id = 0;
pdevinfo[0].parent = &pci->dev;
pdevinfo[0].num_res = 4;
pdevinfo[0].res = &adata->res[0];
pdevinfo[0].data = &irqflags;
pdevinfo[0].size_data = sizeof(irqflags);
pdevinfo[1].name = "acp5x_i2s_playcap";
pdevinfo[1].id = 0;
pdevinfo[1].parent = &pci->dev;
pdevinfo[1].num_res = 1;
pdevinfo[1].res = &adata->res[1];
pdevinfo[2].name = "acp5x_i2s_playcap";
pdevinfo[2].id = 1;
pdevinfo[2].parent = &pci->dev;
pdevinfo[2].num_res = 1;
pdevinfo[2].res = &adata->res[2];
for (i = 0; i < ACP5x_DEVS; i++) {
adata->pdev[i] =
platform_device_register_full(&pdevinfo[i]);
if (IS_ERR(adata->pdev[i])) {
dev_err(&pci->dev, "cannot register %s device\n",
pdevinfo[i].name);
ret = PTR_ERR(adata->pdev[i]);
goto unregister_devs;
}
}
break;
default:
dev_info(&pci->dev, "ACP audio mode : %d\n", val);
}
return 0;
unregister_devs:
for (--i; i >= 0; i--)
platform_device_unregister(adata->pdev[i]);
de_init:
if (acp5x_deinit(adata->acp5x_base))
dev_err(&pci->dev, "ACP de-init failed\n");
release_regions: release_regions:
pci_release_regions(pci); pci_release_regions(pci);
disable_pci: disable_pci:
...@@ -161,9 +245,13 @@ static int snd_acp5x_probe(struct pci_dev *pci, ...@@ -161,9 +245,13 @@ static int snd_acp5x_probe(struct pci_dev *pci,
static void snd_acp5x_remove(struct pci_dev *pci) static void snd_acp5x_remove(struct pci_dev *pci)
{ {
struct acp5x_dev_data *adata; struct acp5x_dev_data *adata;
int ret; int i, ret;
adata = pci_get_drvdata(pci); adata = pci_get_drvdata(pci);
if (adata->acp5x_audio_mode == ACP5x_I2S_MODE) {
for (i = 0; i < ACP5x_DEVS; i++)
platform_device_unregister(adata->pdev[i]);
}
ret = acp5x_deinit(adata->acp5x_base); ret = acp5x_deinit(adata->acp5x_base);
if (ret) if (ret)
dev_err(&pci->dev, "ACP de-init failed\n"); dev_err(&pci->dev, "ACP de-init failed\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment