~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/amd/rpl/rpl-pci-acp6x.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0+
  2 /*
  3  * AMD RPL ACP PCI Driver
  4  *
  5  * Copyright 2022 Advanced Micro Devices, Inc.
  6  */
  7 
  8 #include <linux/pci.h>
  9 #include <linux/module.h>
 10 #include <linux/io.h>
 11 #include <linux/delay.h>
 12 #include <linux/platform_device.h>
 13 #include <linux/pm_runtime.h>
 14 
 15 #include "rpl_acp6x.h"
 16 
 17 struct rpl_dev_data {
 18         void __iomem *acp6x_base;
 19 };
 20 
 21 static int rpl_power_on(void __iomem *acp_base)
 22 {
 23         u32 val;
 24         int timeout;
 25 
 26         val = rpl_acp_readl(acp_base + ACP_PGFSM_STATUS);
 27 
 28         if (!val)
 29                 return val;
 30 
 31         if ((val & ACP_PGFSM_STATUS_MASK) != ACP_POWER_ON_IN_PROGRESS)
 32                 rpl_acp_writel(ACP_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL);
 33         timeout = 0;
 34         while (++timeout < 500) {
 35                 val = rpl_acp_readl(acp_base + ACP_PGFSM_STATUS);
 36                 if (!val)
 37                         return 0;
 38                 udelay(1);
 39         }
 40         return -ETIMEDOUT;
 41 }
 42 
 43 static int rpl_reset(void __iomem *acp_base)
 44 {
 45         u32 val;
 46         int timeout;
 47 
 48         rpl_acp_writel(1, acp_base + ACP_SOFT_RESET);
 49         timeout = 0;
 50         while (++timeout < 500) {
 51                 val = rpl_acp_readl(acp_base + ACP_SOFT_RESET);
 52                 if (val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK)
 53                         break;
 54                 cpu_relax();
 55         }
 56         rpl_acp_writel(0, acp_base + ACP_SOFT_RESET);
 57         timeout = 0;
 58         while (++timeout < 500) {
 59                 val = rpl_acp_readl(acp_base + ACP_SOFT_RESET);
 60                 if (!val)
 61                         return 0;
 62                 cpu_relax();
 63         }
 64         return -ETIMEDOUT;
 65 }
 66 
 67 static int rpl_init(void __iomem *acp_base)
 68 {
 69         int ret;
 70 
 71         /* power on */
 72         ret = rpl_power_on(acp_base);
 73         if (ret) {
 74                 pr_err("ACP power on failed\n");
 75                 return ret;
 76         }
 77         rpl_acp_writel(0x01, acp_base + ACP_CONTROL);
 78         /* Reset */
 79         ret = rpl_reset(acp_base);
 80         if (ret) {
 81                 pr_err("ACP reset failed\n");
 82                 return ret;
 83         }
 84         rpl_acp_writel(0x03, acp_base + ACP_CLKMUX_SEL);
 85         return 0;
 86 }
 87 
 88 static int rpl_deinit(void __iomem *acp_base)
 89 {
 90         int ret;
 91 
 92         /* Reset */
 93         ret = rpl_reset(acp_base);
 94         if (ret) {
 95                 pr_err("ACP reset failed\n");
 96                 return ret;
 97         }
 98         rpl_acp_writel(0x00, acp_base + ACP_CLKMUX_SEL);
 99         rpl_acp_writel(0x00, acp_base + ACP_CONTROL);
100         return 0;
101 }
102 
103 static int snd_rpl_probe(struct pci_dev *pci,
104                          const struct pci_device_id *pci_id)
105 {
106         struct rpl_dev_data *adata;
107         u32 addr;
108         int ret;
109 
110         /* RPL device check */
111         switch (pci->revision) {
112         case 0x62:
113                 break;
114         default:
115                 dev_dbg(&pci->dev, "acp6x pci device not found\n");
116                 return -ENODEV;
117         }
118         if (pci_enable_device(pci)) {
119                 dev_err(&pci->dev, "pci_enable_device failed\n");
120                 return -ENODEV;
121         }
122 
123         ret = pci_request_regions(pci, "AMD ACP6x audio");
124         if (ret < 0) {
125                 dev_err(&pci->dev, "pci_request_regions failed\n");
126                 goto disable_pci;
127         }
128 
129         adata = devm_kzalloc(&pci->dev, sizeof(struct rpl_dev_data),
130                              GFP_KERNEL);
131         if (!adata) {
132                 ret = -ENOMEM;
133                 goto release_regions;
134         }
135 
136         addr = pci_resource_start(pci, 0);
137         adata->acp6x_base = devm_ioremap(&pci->dev, addr,
138                                          pci_resource_len(pci, 0));
139         if (!adata->acp6x_base) {
140                 ret = -ENOMEM;
141                 goto release_regions;
142         }
143         pci_set_master(pci);
144         pci_set_drvdata(pci, adata);
145         ret = rpl_init(adata->acp6x_base);
146         if (ret)
147                 goto release_regions;
148         pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS);
149         pm_runtime_use_autosuspend(&pci->dev);
150         pm_runtime_put_noidle(&pci->dev);
151         pm_runtime_allow(&pci->dev);
152 
153         return 0;
154 release_regions:
155         pci_release_regions(pci);
156 disable_pci:
157         pci_disable_device(pci);
158 
159         return ret;
160 }
161 
162 static int __maybe_unused snd_rpl_suspend(struct device *dev)
163 {
164         struct rpl_dev_data *adata;
165         int ret;
166 
167         adata = dev_get_drvdata(dev);
168         ret = rpl_deinit(adata->acp6x_base);
169         if (ret)
170                 dev_err(dev, "ACP de-init failed\n");
171         return ret;
172 }
173 
174 static int __maybe_unused snd_rpl_resume(struct device *dev)
175 {
176         struct rpl_dev_data *adata;
177         int ret;
178 
179         adata = dev_get_drvdata(dev);
180         ret = rpl_init(adata->acp6x_base);
181         if (ret)
182                 dev_err(dev, "ACP init failed\n");
183         return ret;
184 }
185 
186 static const struct dev_pm_ops rpl_pm = {
187         SET_RUNTIME_PM_OPS(snd_rpl_suspend, snd_rpl_resume, NULL)
188         SET_SYSTEM_SLEEP_PM_OPS(snd_rpl_suspend, snd_rpl_resume)
189 };
190 
191 static void snd_rpl_remove(struct pci_dev *pci)
192 {
193         struct rpl_dev_data *adata;
194         int ret;
195 
196         adata = pci_get_drvdata(pci);
197         ret = rpl_deinit(adata->acp6x_base);
198         if (ret)
199                 dev_err(&pci->dev, "ACP de-init failed\n");
200         pm_runtime_forbid(&pci->dev);
201         pm_runtime_get_noresume(&pci->dev);
202         pci_release_regions(pci);
203         pci_disable_device(pci);
204 }
205 
206 static const struct pci_device_id snd_rpl_ids[] = {
207         { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_DEVICE_ID),
208         .class = PCI_CLASS_MULTIMEDIA_OTHER << 8,
209         .class_mask = 0xffffff },
210         { 0, },
211 };
212 MODULE_DEVICE_TABLE(pci, snd_rpl_ids);
213 
214 static struct pci_driver rpl_acp6x_driver  = {
215         .name = KBUILD_MODNAME,
216         .id_table = snd_rpl_ids,
217         .probe = snd_rpl_probe,
218         .remove = snd_rpl_remove,
219         .driver = {
220                 .pm = &rpl_pm,
221         }
222 };
223 
224 module_pci_driver(rpl_acp6x_driver);
225 
226 MODULE_DESCRIPTION("AMD ACP RPL PCI driver");
227 MODULE_LICENSE("GPL v2");
228 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php