ASoC: amd: acp7x: add helper functions and hw ops

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>
This commit is contained in:
Vijendar Mukunda 2026-05-07 23:41:31 +05:30 committed by Mark Brown
parent 1da6f798ed
commit b5a2fdc5e7
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
3 changed files with 197 additions and 2 deletions

View File

@ -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;
}

View 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>
@ -22,10 +24,84 @@
#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 */

View File

@ -16,6 +16,26 @@
#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 @@ static int snd_acp7x_probe(struct pci_dev *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);
}