diff mbox series

[V2,15/23] ASoC: amd: acp70: add acp driver pm ops support

Message ID 20250120100130.3710412-16-Vijendar.Mukunda@amd.com (mailing list archive)
State New
Headers show
Series ASoC: amd: acp70: add soundwire and acp pdm support | expand

Commit Message

Mukunda,Vijendar Jan. 20, 2025, 10:01 a.m. UTC
Add pm ops support for ACP7.0 PCI driver.

Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
---
 sound/soc/amd/acp70/acp70.h     |  2 +
 sound/soc/amd/acp70/pci-acp70.c | 81 +++++++++++++++++++++++++++++++++
 2 files changed, 83 insertions(+)
diff mbox series

Patch

diff --git a/sound/soc/amd/acp70/acp70.h b/sound/soc/amd/acp70/acp70.h
index 1d8e670264fc..c3b3b6c38902 100644
--- a/sound/soc/amd/acp70/acp70.h
+++ b/sound/soc/amd/acp70/acp70.h
@@ -247,6 +247,7 @@  struct sdw_dma_dev_data {
  * @is_pdm_dev: flag set to true when ACP PDM controller exists
  * @is_pdm_config: flat set to true when PDM configuration is selected from BIOS
  * @is_sdw_config: flag set to true when SDW configuration is selected from BIOS
+ * @sdw_en_stat: flag set to true when any one of the SoundWire manager instance is enabled
  */
 
 struct acp70_dev_data {
@@ -268,6 +269,7 @@  struct acp70_dev_data {
 	bool is_pdm_dev;
 	bool is_pdm_config;
 	bool is_sdw_config;
+	bool sdw_en_stat;
 };
 
 int snd_amd_acp_find_config(struct pci_dev *pci);
diff --git a/sound/soc/amd/acp70/pci-acp70.c b/sound/soc/amd/acp70/pci-acp70.c
index e732a680c092..9b298ddb097c 100644
--- a/sound/soc/amd/acp70/pci-acp70.c
+++ b/sound/soc/amd/acp70/pci-acp70.c
@@ -15,6 +15,7 @@ 
 #include <linux/pci.h>
 #include <linux/platform_device.h>
 #include <sound/pcm_params.h>
+#include <linux/pm_runtime.h>
 #include "../mach-config.h"
 
 #include "acp70.h"
@@ -554,6 +555,10 @@  static int snd_acp70_probe(struct pci_dev *pci,
 		goto de_init;
 	}
 skip_pdev_creation:
+	pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS);
+	pm_runtime_use_autosuspend(&pci->dev);
+	pm_runtime_put_noidle(&pci->dev);
+	pm_runtime_allow(&pci->dev);
 	return 0;
 de_init:
 	if (acp70_deinit(adata->acp70_base, &pci->dev))
@@ -566,6 +571,77 @@  static int snd_acp70_probe(struct pci_dev *pci,
 	return ret;
 }
 
+static bool check_acp_sdw_enable_status(struct acp70_dev_data *adata)
+{
+	u32 sdw0_en, sdw1_en;
+
+	sdw0_en = readl(adata->acp70_base + ACP_SW0_EN);
+	sdw1_en = readl(adata->acp70_base + ACP_SW1_EN);
+	return (sdw0_en || sdw1_en);
+}
+
+static int __maybe_unused snd_acp70_suspend(struct device *dev)
+{
+	struct acp70_dev_data *adata;
+	int ret;
+
+	adata = dev_get_drvdata(dev);
+	if (adata->is_sdw_dev) {
+		adata->sdw_en_stat = check_acp_sdw_enable_status(adata);
+		if (adata->sdw_en_stat)
+			return 0;
+	}
+	ret = acp70_deinit(adata->acp70_base, dev);
+	if (ret)
+		dev_err(dev, "ACP de-init failed\n");
+
+	return ret;
+}
+
+static int __maybe_unused snd_acp70_runtime_resume(struct device *dev)
+{
+	struct acp70_dev_data *adata;
+	int ret;
+
+	adata = dev_get_drvdata(dev);
+
+	if (adata->sdw_en_stat) {
+		writel(0x1, adata->acp70_base + ACP_PME_EN);
+		return 0;
+	}
+
+	ret = acp70_init(adata->acp70_base, dev);
+	if (ret) {
+		dev_err(dev, "ACP init failed\n");
+		return ret;
+	}
+	return 0;
+}
+
+static int __maybe_unused snd_acp70_resume(struct device *dev)
+{
+	struct acp70_dev_data *adata;
+	int ret;
+
+	adata = dev_get_drvdata(dev);
+
+	if (adata->sdw_en_stat) {
+		writel(0x1, adata->acp70_base + ACP_PME_EN);
+		return 0;
+	}
+
+	ret = acp70_init(adata->acp70_base, dev);
+	if (ret)
+		dev_err(dev, "ACP init failed\n");
+
+	return ret;
+}
+
+static const struct dev_pm_ops acp70_pm_ops = {
+	SET_RUNTIME_PM_OPS(snd_acp70_suspend, snd_acp70_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(snd_acp70_suspend, snd_acp70_resume)
+};
+
 static void snd_acp70_remove(struct pci_dev *pci)
 {
 	struct acp70_dev_data *adata;
@@ -583,6 +659,8 @@  static void snd_acp70_remove(struct pci_dev *pci)
 	ret = acp70_deinit(adata->acp70_base, &pci->dev);
 	if (ret)
 		dev_err(&pci->dev, "ACP de-init failed\n");
+	pm_runtime_forbid(&pci->dev);
+	pm_runtime_get_noresume(&pci->dev);
 	pci_release_regions(pci);
 	pci_disable_device(pci);
 }
@@ -600,6 +678,9 @@  static struct pci_driver ps_acp70_driver  = {
 	.id_table = snd_acp70_ids,
 	.probe = snd_acp70_probe,
 	.remove = snd_acp70_remove,
+	.driver = {
+		.pm = &acp70_pm_ops,
+	}
 };
 
 module_pci_driver(ps_acp70_driver);