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

TOMOYO Linux Cross Reference
Linux/sound/soc/amd/acp/acp-pci.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-only OR BSD-3-Clause)
  2 //
  3 // This file is provided under a dual BSD/GPLv2 license. When using or
  4 // redistributing this file, you may do so under either license.
  5 //
  6 // Copyright(c) 2022 Advanced Micro Devices, Inc. All rights reserved.
  7 //
  8 // Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
  9 
 10 /*
 11  * Generic PCI interface for ACP device
 12  */
 13 
 14 #include <linux/delay.h>
 15 #include <linux/interrupt.h>
 16 #include <linux/pci.h>
 17 #include <linux/platform_device.h>
 18 #include <linux/module.h>
 19 #include <linux/pm_runtime.h>
 20 
 21 #include "amd.h"
 22 #include "../mach-config.h"
 23 
 24 #define DRV_NAME "acp_pci"
 25 
 26 #define ACP3x_REG_START 0x1240000
 27 #define ACP3x_REG_END   0x125C000
 28 
 29 static struct platform_device *dmic_dev;
 30 static struct platform_device *pdev;
 31 
 32 static const struct resource acp_res[] = {
 33         {
 34                 .start = 0,
 35                 .end = ACP3x_REG_END - ACP3x_REG_START,
 36                 .name = "acp_mem",
 37                 .flags = IORESOURCE_MEM,
 38         },
 39         {
 40                 .start = 0,
 41                 .end = 0,
 42                 .name = "acp_dai_irq",
 43                 .flags = IORESOURCE_IRQ,
 44         },
 45 };
 46 
 47 static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
 48 {
 49         struct platform_device_info pdevinfo;
 50         struct device *dev = &pci->dev;
 51         const struct resource *res_acp;
 52         struct acp_chip_info *chip;
 53         struct resource *res;
 54         unsigned int flag, addr, num_res, i;
 55         int ret;
 56 
 57         flag = snd_amd_acp_find_config(pci);
 58         if (flag != FLAG_AMD_LEGACY && flag != FLAG_AMD_LEGACY_ONLY_DMIC)
 59                 return -ENODEV;
 60 
 61         chip = devm_kzalloc(&pci->dev, sizeof(*chip), GFP_KERNEL);
 62         if (!chip)
 63                 return -ENOMEM;
 64 
 65         if (pci_enable_device(pci))
 66                 return dev_err_probe(&pci->dev, -ENODEV,
 67                                      "pci_enable_device failed\n");
 68 
 69         ret = pci_request_regions(pci, "AMD ACP3x audio");
 70         if (ret < 0) {
 71                 dev_err(&pci->dev, "pci_request_regions failed\n");
 72                 ret = -ENOMEM;
 73                 goto disable_pci;
 74         }
 75 
 76         pci_set_master(pci);
 77 
 78         res_acp = acp_res;
 79         num_res = ARRAY_SIZE(acp_res);
 80 
 81         switch (pci->revision) {
 82         case 0x01:
 83                 chip->name = "acp_asoc_renoir";
 84                 chip->acp_rev = ACP3X_DEV;
 85                 break;
 86         case 0x6f:
 87                 chip->name = "acp_asoc_rembrandt";
 88                 chip->acp_rev = ACP6X_DEV;
 89                 break;
 90         case 0x63:
 91                 chip->name = "acp_asoc_acp63";
 92                 chip->acp_rev = ACP63_DEV;
 93                 break;
 94         case 0x70:
 95                 chip->name = "acp_asoc_acp70";
 96                 chip->acp_rev = ACP70_DEV;
 97                 break;
 98         default:
 99                 dev_err(dev, "Unsupported device revision:0x%x\n", pci->revision);
100                 ret = -EINVAL;
101                 goto release_regions;
102         }
103         chip->flag = flag;
104         dmic_dev = platform_device_register_data(dev, "dmic-codec", PLATFORM_DEVID_NONE, NULL, 0);
105         if (IS_ERR(dmic_dev)) {
106                 dev_err(dev, "failed to create DMIC device\n");
107                 ret = PTR_ERR(dmic_dev);
108                 goto release_regions;
109         }
110 
111         addr = pci_resource_start(pci, 0);
112         chip->base = devm_ioremap(&pci->dev, addr, pci_resource_len(pci, 0));
113         if (!chip->base) {
114                 ret = -ENOMEM;
115                 goto unregister_dmic_dev;
116         }
117 
118         ret = acp_init(chip);
119         if (ret)
120                 goto unregister_dmic_dev;
121 
122         check_acp_config(pci, chip);
123         if (!chip->is_pdm_dev && !chip->is_i2s_config)
124                 goto skip_pdev_creation;
125 
126         res = devm_kcalloc(&pci->dev, num_res, sizeof(struct resource), GFP_KERNEL);
127         if (!res) {
128                 ret = -ENOMEM;
129                 goto unregister_dmic_dev;
130         }
131 
132         for (i = 0; i < num_res; i++, res_acp++) {
133                 res[i].name = res_acp->name;
134                 res[i].flags = res_acp->flags;
135                 res[i].start = addr + res_acp->start;
136                 res[i].end = addr + res_acp->end;
137                 if (res_acp->flags == IORESOURCE_IRQ) {
138                         res[i].start = pci->irq;
139                         res[i].end = res[i].start;
140                 }
141         }
142 
143         memset(&pdevinfo, 0, sizeof(pdevinfo));
144 
145         pdevinfo.name = chip->name;
146         pdevinfo.id = 0;
147         pdevinfo.parent = &pci->dev;
148         pdevinfo.num_res = num_res;
149         pdevinfo.res = &res[0];
150         pdevinfo.data = chip;
151         pdevinfo.size_data = sizeof(*chip);
152 
153         pdev = platform_device_register_full(&pdevinfo);
154         if (IS_ERR(pdev)) {
155                 dev_err(&pci->dev, "cannot register %s device\n", pdevinfo.name);
156                 ret = PTR_ERR(pdev);
157                 goto unregister_dmic_dev;
158         }
159 
160 skip_pdev_creation:
161         chip->chip_pdev = pdev;
162         dev_set_drvdata(&pci->dev, chip);
163         pm_runtime_set_autosuspend_delay(&pci->dev, 2000);
164         pm_runtime_use_autosuspend(&pci->dev);
165         pm_runtime_put_noidle(&pci->dev);
166         pm_runtime_allow(&pci->dev);
167         return ret;
168 
169 unregister_dmic_dev:
170         platform_device_unregister(dmic_dev);
171 release_regions:
172         pci_release_regions(pci);
173 disable_pci:
174         pci_disable_device(pci);
175 
176         return ret;
177 };
178 
179 static int __maybe_unused snd_acp_suspend(struct device *dev)
180 {
181         struct acp_chip_info *chip;
182         int ret;
183 
184         chip = dev_get_drvdata(dev);
185         ret = acp_deinit(chip);
186         if (ret)
187                 dev_err(dev, "ACP de-init failed\n");
188         return ret;
189 }
190 
191 static int __maybe_unused snd_acp_resume(struct device *dev)
192 {
193         struct acp_chip_info *chip;
194         struct acp_dev_data *adata;
195         struct device child;
196         int ret;
197 
198         chip = dev_get_drvdata(dev);
199         ret = acp_init(chip);
200         if (ret)
201                 dev_err(dev, "ACP init failed\n");
202         if (chip->chip_pdev) {
203                 child = chip->chip_pdev->dev;
204                 adata = dev_get_drvdata(&child);
205                 if (adata)
206                         acp_enable_interrupts(adata);
207         }
208         return ret;
209 }
210 
211 static const struct dev_pm_ops acp_pm_ops = {
212         SET_RUNTIME_PM_OPS(snd_acp_suspend, snd_acp_resume, NULL)
213         SET_SYSTEM_SLEEP_PM_OPS(snd_acp_suspend, snd_acp_resume)
214 };
215 
216 static void acp_pci_remove(struct pci_dev *pci)
217 {
218         struct acp_chip_info *chip;
219         int ret;
220 
221         chip = pci_get_drvdata(pci);
222         pm_runtime_forbid(&pci->dev);
223         pm_runtime_get_noresume(&pci->dev);
224         if (dmic_dev)
225                 platform_device_unregister(dmic_dev);
226         if (pdev)
227                 platform_device_unregister(pdev);
228         ret = acp_deinit(chip);
229         if (ret)
230                 dev_err(&pci->dev, "ACP de-init failed\n");
231 }
232 
233 /* PCI IDs */
234 static const struct pci_device_id acp_pci_ids[] = {
235         { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_PCI_DEV_ID)},
236         { 0, }
237 };
238 MODULE_DEVICE_TABLE(pci, acp_pci_ids);
239 
240 /* pci_driver definition */
241 static struct pci_driver snd_amd_acp_pci_driver = {
242         .name = KBUILD_MODNAME,
243         .id_table = acp_pci_ids,
244         .probe = acp_pci_probe,
245         .remove = acp_pci_remove,
246         .driver = {
247                 .pm = &acp_pm_ops,
248         },
249 };
250 module_pci_driver(snd_amd_acp_pci_driver);
251 
252 MODULE_DESCRIPTION("AMD ACP common PCI support");
253 MODULE_LICENSE("Dual BSD/GPL");
254 MODULE_IMPORT_NS(SND_SOC_ACP_COMMON);
255 MODULE_ALIAS(DRV_NAME);
256 

~ [ 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