]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ASoC: amd: acp7x: add helper functions and hw ops
authorVijendar Mukunda <Vijendar.Mukunda@amd.com>
Thu, 7 May 2026 18:11:31 +0000 (23:41 +0530)
committerMark Brown <broonie@kernel.org>
Thu, 21 May 2026 23:15:02 +0000 (00:15 +0100)
Add ACP7.x init/deinit helper routines and wire up PCI hw ops for
ACP7.D/7.E/7.F variants.

Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>
Link: https://patch.msgid.link/20260507181251.20594-4-Vijendar.Mukunda@amd.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/amd/acp7x/acp7x-common.c [new file with mode: 0644]
sound/soc/amd/acp7x/acp7x.h
sound/soc/amd/acp7x/pci-acp7x.c

diff --git a/sound/soc/amd/acp7x/acp7x-common.c b/sound/soc/amd/acp7x/acp7x-common.c
new file mode 100644 (file)
index 0000000..68f9b47
--- /dev/null
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * AMD ACP PCI driver callback routines for ACP7.x
+ * platforms.
+ *
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/types.h>
+
+#include "acp7x.h"
+
+static int acp7x_power_on(void __iomem *acp_base)
+{
+       u32 val = 0;
+
+       val = readl(acp_base + ACP_PGFSM_STATUS);
+       if (!(val & ACP7X_PGFSM_STATUS_MASK))
+               return 0;
+
+       writel(ACP7X_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL);
+       val = readl(acp_base + ACP_PGFSM_CONTROL);
+       return readl_poll_timeout(acp_base + ACP_PGFSM_STATUS, val,
+                                 ((val & ACP7X_PGFSM_STATUS_MASK) == 0), DELAY_US, ACP7X_TIMEOUT);
+}
+
+static int acp7x_reset(void __iomem *acp_base)
+{
+       u32 val;
+       int ret;
+
+       writel(1, acp_base + ACP_SOFT_RESET);
+       ret = readl_poll_timeout(acp_base + ACP_SOFT_RESET, val,
+                                val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK,
+                                DELAY_US, ACP7X_TIMEOUT);
+       if (ret)
+               return ret;
+
+       writel(0, acp_base + ACP_SOFT_RESET);
+       return readl_poll_timeout(acp_base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP7X_TIMEOUT);
+}
+
+static int acp7x_init(void __iomem *acp_base, struct device *dev)
+{
+       int ret;
+
+       ret = acp7x_power_on(acp_base);
+       if (ret) {
+               dev_err(dev, "ACP power on failed\n");
+               return ret;
+       }
+       writel(0x01, acp_base + ACP_CONTROL);
+       ret = acp7x_reset(acp_base);
+       if (ret) {
+               dev_err(dev, "ACP reset failed\n");
+               return ret;
+       }
+       writel(0, acp_base + ACP_ZSC_DSP_CTRL);
+       return 0;
+}
+
+static int acp7x_deinit(void __iomem *acp_base, struct device *dev)
+{
+       int ret;
+
+       ret = acp7x_reset(acp_base);
+       if (ret) {
+               dev_err(dev, "ACP reset failed\n");
+               return ret;
+       }
+       writel(0x01, acp_base + ACP_ZSC_DSP_CTRL);
+       return 0;
+}
+
+void acp7x_hw_init_ops(struct acp_hw_ops *hw_ops)
+{
+       hw_ops->acp_init = acp7x_init;
+       hw_ops->acp_deinit = acp7x_deinit;
+}
index b4586a2afae440b95e6ef62efb407137fb50f402..d3a57705385aff09bc487523c0e87a712971b49f 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef __SOUND_SOC_AMD_ACP7X_H
 #define __SOUND_SOC_AMD_ACP7X_H
 
+#include <linux/device.h>
+#include <linux/errno.h>
 #include <linux/io.h>
 #include <linux/pci.h>
 #include <linux/types.h>
 #define ACP7E_PCI_REV          0x7E
 #define ACP7F_PCI_REV          0x7F
 
-int snd_amd_acp_find_config(struct pci_dev *pci);
+/* Common register helper bits used by acp7x-common.c */
+#define ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK  0x00010001
+
+#define DELAY_US                               5
+#define ACP7X_TIMEOUT                          5000
+
+#define ACP7X_PGFSM_CNTL_POWER_ON_MASK         7
+#define ACP7X_PGFSM_STATUS_MASK                        0x3F
+
+struct acp_hw_ops {
+       int (*acp_init)(void __iomem *acp_base, struct device *dev);
+       int (*acp_deinit)(void __iomem *acp_base, struct device *dev);
+       int (*acp_suspend)(struct device *dev);
+       int (*acp_resume)(struct device *dev);
+       int (*acp_suspend_runtime)(struct device *dev);
+       int (*acp_resume_runtime)(struct device *dev);
+};
 
 struct acp7x_dev_data {
        void __iomem *acp7x_base;
+       struct acp_hw_ops *hw_ops;
+       u32 addr;
+       u32 reg_range;
+       u32 acp_rev;
 };
 
+void acp7x_hw_init_ops(struct acp_hw_ops *hw_ops);
+
+static inline int acp_hw_init(struct acp7x_dev_data *adata, struct device *dev)
+{
+       if (adata && adata->hw_ops && adata->hw_ops->acp_init)
+               return adata->hw_ops->acp_init(adata->acp7x_base, dev);
+       return -EOPNOTSUPP;
+}
+
+static inline int acp_hw_deinit(struct acp7x_dev_data *adata, struct device *dev)
+{
+       if (adata && adata->hw_ops && adata->hw_ops->acp_deinit)
+               return adata->hw_ops->acp_deinit(adata->acp7x_base, dev);
+       return -EOPNOTSUPP;
+}
+
+static inline int acp_hw_suspend(struct device *dev)
+{
+       struct acp7x_dev_data *adata = dev_get_drvdata(dev);
+
+       if (adata && adata->hw_ops && adata->hw_ops->acp_suspend)
+               return adata->hw_ops->acp_suspend(dev);
+       return -EOPNOTSUPP;
+}
+
+static inline int acp_hw_resume(struct device *dev)
+{
+       struct acp7x_dev_data *adata = dev_get_drvdata(dev);
+
+       if (adata && adata->hw_ops && adata->hw_ops->acp_resume)
+               return adata->hw_ops->acp_resume(dev);
+       return -EOPNOTSUPP;
+}
+
+static inline int acp_hw_suspend_runtime(struct device *dev)
+{
+       struct acp7x_dev_data *adata = dev_get_drvdata(dev);
+
+       if (adata && adata->hw_ops && adata->hw_ops->acp_suspend_runtime)
+               return adata->hw_ops->acp_suspend_runtime(dev);
+       return -EOPNOTSUPP;
+}
+
+static inline int acp_hw_runtime_resume(struct device *dev)
+{
+       struct acp7x_dev_data *adata = dev_get_drvdata(dev);
+
+       if (adata && adata->hw_ops && adata->hw_ops->acp_resume_runtime)
+               return adata->hw_ops->acp_resume_runtime(dev);
+       return -EOPNOTSUPP;
+}
+
+int snd_amd_acp_find_config(struct pci_dev *pci);
+
 #endif /* __SOUND_SOC_AMD_ACP7X_H */
index 476b3ae526349113ee94b1ed3b9d00748db74368..237eb06e3cadcd9b1a66f905e07d22595da8e904 100644 (file)
 
 #include "acp7x.h"
 
+static int acp_hw_init_ops(struct acp7x_dev_data *adata, struct pci_dev *pci)
+{
+       adata->hw_ops = devm_kzalloc(&pci->dev, sizeof(struct acp_hw_ops),
+                                    GFP_KERNEL);
+       if (!adata->hw_ops)
+               return -ENOMEM;
+
+       switch (adata->acp_rev) {
+       case ACP7D_PCI_REV:
+       case ACP7E_PCI_REV:
+       case ACP7F_PCI_REV:
+               acp7x_hw_init_ops(adata->hw_ops);
+               break;
+       default:
+               dev_err(&pci->dev, "ACP device not found\n");
+               return -ENODEV;
+       }
+       return 0;
+}
+
 static int snd_acp7x_probe(struct pci_dev *pci,
                           const struct pci_device_id *pci_id)
 {
@@ -27,7 +47,6 @@ static int snd_acp7x_probe(struct pci_dev *pci,
        flag = snd_amd_acp_find_config(pci);
        if (flag)
                return -ENODEV;
-
        /* ACP PCI revision id check for ACP7.x platforms */
        switch (pci->revision) {
        case ACP7D_PCI_REV:
@@ -60,8 +79,19 @@ static int snd_acp7x_probe(struct pci_dev *pci,
                ret = -ENOMEM;
                goto release_regions;
        }
+       adata->addr = addr;
+       adata->reg_range = ACP7X_REG_END - ACP7X_REG_START;
+       adata->acp_rev = pci->revision;
        pci_set_master(pci);
        pci_set_drvdata(pci, adata);
+       ret = acp_hw_init_ops(adata, pci);
+       if (ret) {
+               dev_err(&pci->dev, "ACP hw ops init failed\n");
+               goto release_regions;
+       }
+       ret = acp_hw_init(adata, &pci->dev);
+       if (ret)
+               goto release_regions;
        return 0;
 
 release_regions:
@@ -74,6 +104,13 @@ disable_pci:
 
 static void snd_acp7x_remove(struct pci_dev *pci)
 {
+       struct acp7x_dev_data *adata;
+       int ret;
+
+       adata = pci_get_drvdata(pci);
+       ret = acp_hw_deinit(adata, &pci->dev);
+       if (ret)
+               dev_err(&pci->dev, "ACP de-init failed\n");
        pci_release_regions(pci);
        pci_disable_device(pci);
 }