1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * AMD ACP PCI driver callback routines for ACP7.x 4 * platforms. 5 * 6 * Copyright 2026 Advanced Micro Devices, Inc. 7 */ 8 9 #include <linux/device.h> 10 #include <linux/io.h> 11 #include <linux/iopoll.h> 12 #include <linux/types.h> 13 14 #include "acp7x.h" 15 16 static int acp7x_power_on(void __iomem *acp_base) 17 { 18 u32 val = 0; 19 20 val = readl(acp_base + ACP_PGFSM_STATUS); 21 if (!(val & ACP7X_PGFSM_STATUS_MASK)) 22 return 0; 23 24 writel(ACP7X_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL); 25 val = readl(acp_base + ACP_PGFSM_CONTROL); 26 return readl_poll_timeout(acp_base + ACP_PGFSM_STATUS, val, 27 ((val & ACP7X_PGFSM_STATUS_MASK) == 0), DELAY_US, ACP7X_TIMEOUT); 28 } 29 30 static int acp7x_reset(void __iomem *acp_base) 31 { 32 u32 val; 33 int ret; 34 35 writel(1, acp_base + ACP_SOFT_RESET); 36 ret = readl_poll_timeout(acp_base + ACP_SOFT_RESET, val, 37 val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK, 38 DELAY_US, ACP7X_TIMEOUT); 39 if (ret) 40 return ret; 41 42 writel(0, acp_base + ACP_SOFT_RESET); 43 return readl_poll_timeout(acp_base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP7X_TIMEOUT); 44 } 45 46 static int acp7x_init(void __iomem *acp_base, struct device *dev) 47 { 48 int ret; 49 50 ret = acp7x_power_on(acp_base); 51 if (ret) { 52 dev_err(dev, "ACP power on failed\n"); 53 return ret; 54 } 55 writel(0x01, acp_base + ACP_CONTROL); 56 ret = acp7x_reset(acp_base); 57 if (ret) { 58 dev_err(dev, "ACP reset failed\n"); 59 return ret; 60 } 61 writel(0, acp_base + ACP_ZSC_DSP_CTRL); 62 return 0; 63 } 64 65 static int acp7x_deinit(void __iomem *acp_base, struct device *dev) 66 { 67 int ret; 68 69 ret = acp7x_reset(acp_base); 70 if (ret) { 71 dev_err(dev, "ACP reset failed\n"); 72 return ret; 73 } 74 writel(0x01, acp_base + ACP_ZSC_DSP_CTRL); 75 return 0; 76 } 77 78 static int __maybe_unused snd_acp7x_suspend(struct device *dev) 79 { 80 struct acp7x_dev_data *adata; 81 int ret; 82 83 adata = dev_get_drvdata(dev); 84 ret = acp_hw_deinit(adata, dev); 85 if (ret) 86 dev_err(dev, "ACP de-init failed\n"); 87 return ret; 88 } 89 90 static int __maybe_unused snd_acp7x_runtime_resume(struct device *dev) 91 { 92 struct acp7x_dev_data *adata; 93 int ret; 94 95 adata = dev_get_drvdata(dev); 96 ret = acp_hw_init(adata, dev); 97 if (ret) { 98 dev_err(dev, "ACP init failed\n"); 99 return ret; 100 } 101 return 0; 102 } 103 104 static int __maybe_unused snd_acp7x_resume(struct device *dev) 105 { 106 struct acp7x_dev_data *adata; 107 int ret; 108 109 adata = dev_get_drvdata(dev); 110 ret = acp_hw_init(adata, dev); 111 if (ret) 112 dev_err(dev, "ACP init failed\n"); 113 114 return ret; 115 } 116 117 void acp7x_hw_init_ops(struct acp_hw_ops *hw_ops) 118 { 119 hw_ops->acp_init = acp7x_init; 120 hw_ops->acp_deinit = acp7x_deinit; 121 hw_ops->acp_suspend = snd_acp7x_suspend; 122 hw_ops->acp_resume = snd_acp7x_resume; 123 hw_ops->acp_suspend_runtime = snd_acp7x_suspend; 124 hw_ops->acp_resume_runtime = snd_acp7x_runtime_resume; 125 } 126