[PATCH 05/21] ASoC: amd: acp70: create platform devices for acp child nodes

Vijendar Mukunda posted 21 patches 12 months ago
There is a newer version of this series
[PATCH 05/21] ASoC: amd: acp70: create platform devices for acp child nodes
Posted by Vijendar Mukunda 12 months ago
Create platform devices for ACP child nodes(ACP PDM controller,
DMIC codec, SoundWire DMA driver, SoundWire manager instances).

Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
---
 sound/soc/amd/acp70/acp70.h     |   8 ++
 sound/soc/amd/acp70/pci-acp70.c | 157 ++++++++++++++++++++++++++++++++
 2 files changed, 165 insertions(+)

diff --git a/sound/soc/amd/acp70/acp70.h b/sound/soc/amd/acp70/acp70.h
index 1b20de75876a..68035fbf23d1 100644
--- a/sound/soc/amd/acp70/acp70.h
+++ b/sound/soc/amd/acp70/acp70.h
@@ -61,6 +61,10 @@ enum acp_config {
 /**
  * struct acp70_dev_data - acp pci driver context
  * @acp70_base: acp mmio base
+ * @res: resource
+ * @pdm_dev: ACP PDM controller platform device
+ * @dmic_codec: platform device for DMIC Codec
+ * sdw_dma_dev: platform device for SoundWire DMA controller
  * @acp_lock: used to protect acp common registers
  * @info: SoundWire AMD information found in ACPI tables
  * @sdw: SoundWire context for all SoundWire manager instances
@@ -75,6 +79,10 @@ enum acp_config {
 
 struct acp70_dev_data {
 	void __iomem *acp70_base;
+	struct resource *res;
+	struct platform_device *pdm_dev;
+	struct platform_device *dmic_codec_dev;
+	struct platform_device *sdw_dma_dev;
 	struct mutex acp_lock; /* protect shared registers */
 	struct sdw_amd_acpi_info info;
 	/* sdw context allocated by SoundWire driver */
diff --git a/sound/soc/amd/acp70/pci-acp70.c b/sound/soc/amd/acp70/pci-acp70.c
index d360dfc396ad..a6812fa269b1 100644
--- a/sound/soc/amd/acp70/pci-acp70.c
+++ b/sound/soc/amd/acp70/pci-acp70.c
@@ -12,6 +12,7 @@
 #include <linux/iopoll.h>
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/platform_device.h>
 #include "../mach-config.h"
 
 #include "acp70.h"
@@ -115,11 +116,54 @@ static int acp_scan_sdw_devices(struct device *dev, u64 addr)
 	acp_data->info.count = AMD_SDW_MAX_MANAGERS;
 	return amd_sdw_scan_controller(&acp_data->info);
 }
+
+static int amd_sdw_probe(struct device *dev)
+{
+	struct acp70_dev_data *acp_data;
+	struct sdw_amd_res sdw_res;
+	int ret;
+
+	acp_data = dev_get_drvdata(dev);
+	memset(&sdw_res, 0, sizeof(sdw_res));
+	sdw_res.addr = acp_data->addr;
+	sdw_res.reg_range = acp_data->reg_range;
+	sdw_res.handle = acp_data->info.handle;
+	sdw_res.parent = dev;
+	sdw_res.dev = dev;
+	sdw_res.acp_lock = &acp_data->acp_lock;
+	sdw_res.count = acp_data->info.count;
+	sdw_res.mmio_base = acp_data->acp70_base;
+	sdw_res.link_mask = acp_data->info.link_mask;
+	sdw_res.acp_rev = acp_data->acp_rev;
+	ret = sdw_amd_probe(&sdw_res, &acp_data->sdw);
+	if (ret)
+		dev_err(dev, "error: SoundWire probe failed\n");
+	return ret;
+}
+
+static int amd_sdw_exit(struct acp70_dev_data *acp_data)
+{
+	if (acp_data->sdw)
+		sdw_amd_exit(acp_data->sdw);
+	acp_data->sdw = NULL;
+
+	return 0;
+}
 #else
 static int acp_scan_sdw_devices(struct device *dev, u64 addr)
 {
 	return 0;
 }
+
+static int amd_sdw_probe(struct device *dev)
+{
+	return 0;
+}
+
+static int amd_sdw_exit(struct acp70_dev_data *acp_data)
+{
+	return 0;
+}
 #endif
 
 static int get_acp70_device_config(struct pci_dev *pci, struct acp70_dev_data *acp_data)
@@ -188,6 +232,102 @@ static int get_acp70_device_config(struct pci_dev *pci, struct acp70_dev_data *a
 	}
 	return 0;
 }
+
+static void acp70_fill_platform_dev_info(struct platform_device_info *pdevinfo,
+					 struct device *parent,
+					 struct fwnode_handle *fw_node,
+					 char *name, unsigned int id,
+					 const struct resource *res,
+					 unsigned int num_res,
+					 const void *data,
+					 size_t size_data)
+{
+	pdevinfo->name = name;
+	pdevinfo->id = id;
+	pdevinfo->parent = parent;
+	pdevinfo->num_res = num_res;
+	pdevinfo->res = res;
+	pdevinfo->data = data;
+	pdevinfo->size_data = size_data;
+	pdevinfo->fwnode = fw_node;
+}
+
+static int create_acp70_platform_devs(struct pci_dev *pci, struct acp70_dev_data *adata, u32 addr)
+{
+	struct platform_device_info pdevinfo;
+	struct device *parent;
+	int ret;
+
+	parent = &pci->dev;
+
+	if (adata->is_sdw_dev || adata->is_pdm_dev) {
+		adata->res = devm_kzalloc(&pci->dev, sizeof(struct resource), GFP_KERNEL);
+		if (!adata->res) {
+			ret = -ENOMEM;
+			goto de_init;
+		}
+		adata->res->flags = IORESOURCE_MEM;
+		adata->res->start = addr;
+		adata->res->end = addr + (ACP70_REG_END - ACP70_REG_START);
+		memset(&pdevinfo, 0, sizeof(pdevinfo));
+	}
+
+	if (adata->is_pdm_dev && adata->is_pdm_config) {
+		acp70_fill_platform_dev_info(&pdevinfo, parent, NULL, "acp70_pdm_dma",
+					     0, adata->res, 1, NULL, 0);
+
+		adata->pdm_dev = platform_device_register_full(&pdevinfo);
+		if (IS_ERR(adata->pdm_dev)) {
+			dev_err(&pci->dev,
+				"cannot register %s device\n", pdevinfo.name);
+			ret = PTR_ERR(adata->pdm_dev);
+			goto de_init;
+		}
+		memset(&pdevinfo, 0, sizeof(pdevinfo));
+		acp70_fill_platform_dev_info(&pdevinfo, parent, NULL, "dmic-codec",
+					     0, NULL, 0, NULL, 0);
+		adata->dmic_codec_dev = platform_device_register_full(&pdevinfo);
+		if (IS_ERR(adata->dmic_codec_dev)) {
+			dev_err(&pci->dev,
+				"cannot register %s device\n", pdevinfo.name);
+			ret = PTR_ERR(adata->dmic_codec_dev);
+			goto unregister_pdm_dev;
+		}
+	}
+	if (adata->is_sdw_dev && adata->is_sdw_config) {
+		ret = amd_sdw_probe(&pci->dev);
+		if (ret) {
+			if (adata->is_pdm_dev)
+				goto unregister_dmic_codec_dev;
+			else
+				goto de_init;
+		}
+		memset(&pdevinfo, 0, sizeof(pdevinfo));
+		acp70_fill_platform_dev_info(&pdevinfo, parent, NULL, "amd_acp70_sdw_dma",
+					     0, adata->res, 1, NULL, 0);
+
+		adata->sdw_dma_dev = platform_device_register_full(&pdevinfo);
+		if (IS_ERR(adata->sdw_dma_dev)) {
+			dev_err(&pci->dev,
+				"cannot register %s device\n", pdevinfo.name);
+			ret = PTR_ERR(adata->sdw_dma_dev);
+			if (adata->is_pdm_dev)
+				goto unregister_dmic_codec_dev;
+			else
+				goto de_init;
+		}
+	}
+	return 0;
+unregister_dmic_codec_dev:
+		platform_device_unregister(adata->dmic_codec_dev);
+unregister_pdm_dev:
+		platform_device_unregister(adata->pdm_dev);
+de_init:
+	if (acp70_deinit(adata->acp70_base, &pci->dev))
+		dev_err(&pci->dev, "ACP de-init failed\n");
+	return ret;
+}
+
 static int snd_acp70_probe(struct pci_dev *pci,
 			   const struct pci_device_id *pci_id)
 {
@@ -249,8 +389,16 @@ static int snd_acp70_probe(struct pci_dev *pci,
 		dev_dbg(&pci->dev, "get acp device config failed:%d\n", ret);
 		goto skip_pdev_creation;
 	}
+	ret = create_acp70_platform_devs(pci, adata, addr);
+	if (ret < 0) {
+		dev_err(&pci->dev, "ACP platform devices creation failed\n");
+		goto de_init;
+	}
 skip_pdev_creation:
 	return 0;
+de_init:
+	if (acp70_deinit(adata->acp70_base, &pci->dev))
+		dev_err(&pci->dev, "ACP de-init failed\n");
 release_regions:
 	pci_release_regions(pci);
 disable_pci:
@@ -265,6 +413,14 @@ static void snd_acp70_remove(struct pci_dev *pci)
 	int ret;
 
 	adata = pci_get_drvdata(pci);
+	if (adata->sdw) {
+		amd_sdw_exit(adata);
+		platform_device_unregister(adata->sdw_dma_dev);
+	}
+	if (adata->is_pdm_dev) {
+		platform_device_unregister(adata->pdm_dev);
+		platform_device_unregister(adata->dmic_codec_dev);
+	}
 	ret = acp70_deinit(adata->acp70_base, &pci->dev);
 	if (ret)
 		dev_err(&pci->dev, "ACP de-init failed\n");
@@ -291,5 +447,6 @@ module_pci_driver(ps_acp70_driver);
 
 MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
 MODULE_DESCRIPTION("AMD ACP7.0 PCI driver");
+MODULE_IMPORT_NS("SOUNDWIRE_AMD_INIT");
 MODULE_IMPORT_NS("SND_AMD_SOUNDWIRE_ACPI");
 MODULE_LICENSE("GPL");
-- 
2.34.1