1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
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.
6 // Copyright(c) 2022 Advanced Micro Devices, Inc. All rights reserved.
8 // Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
11 * Generic PCI interface for ACP device
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>
22 #include "../mach-config.h"
24 #define DRV_NAME "acp_pci"
26 #define ACP3x_REG_START 0x1240000
27 #define ACP3x_REG_END 0x125C000
29 static struct platform_device
*dmic_dev
;
30 static struct platform_device
*pdev
;
32 static const struct resource acp_res
[] = {
35 .end
= ACP3x_REG_END
- ACP3x_REG_START
,
37 .flags
= IORESOURCE_MEM
,
42 .name
= "acp_dai_irq",
43 .flags
= IORESOURCE_IRQ
,
47 static int acp_pci_probe(struct pci_dev
*pci
, const struct pci_device_id
*pci_id
)
49 struct platform_device_info pdevinfo
;
50 struct device
*dev
= &pci
->dev
;
51 const struct resource
*res_acp
;
52 struct acp_chip_info
*chip
;
54 unsigned int flag
, addr
, num_res
, i
;
57 flag
= snd_amd_acp_find_config(pci
);
58 if (flag
!= FLAG_AMD_LEGACY
&& flag
!= FLAG_AMD_LEGACY_ONLY_DMIC
)
61 chip
= devm_kzalloc(&pci
->dev
, sizeof(*chip
), GFP_KERNEL
);
65 if (pci_enable_device(pci
))
66 return dev_err_probe(&pci
->dev
, -ENODEV
,
67 "pci_enable_device failed\n");
69 ret
= pci_request_regions(pci
, "AMD ACP3x audio");
71 dev_err(&pci
->dev
, "pci_request_regions failed\n");
79 num_res
= ARRAY_SIZE(acp_res
);
80 chip
->acp_rev
= pci
->revision
;
81 switch (pci
->revision
) {
83 chip
->name
= "acp_asoc_renoir";
86 chip
->name
= "acp_asoc_rembrandt";
89 chip
->name
= "acp_asoc_acp63";
92 chip
->name
= "acp_asoc_acp70";
95 chip
->name
= "acp_asoc_acp70";
98 dev_err(dev
, "Unsupported device revision:0x%x\n", pci
->revision
);
100 goto release_regions
;
103 dmic_dev
= platform_device_register_data(dev
, "dmic-codec", PLATFORM_DEVID_NONE
, NULL
, 0);
104 if (IS_ERR(dmic_dev
)) {
105 dev_err(dev
, "failed to create DMIC device\n");
106 ret
= PTR_ERR(dmic_dev
);
107 goto release_regions
;
110 addr
= pci_resource_start(pci
, 0);
111 chip
->base
= devm_ioremap(&pci
->dev
, addr
, pci_resource_len(pci
, 0));
114 goto unregister_dmic_dev
;
117 ret
= acp_init(chip
);
119 goto unregister_dmic_dev
;
121 check_acp_config(pci
, chip
);
122 if (!chip
->is_pdm_dev
&& !chip
->is_i2s_config
)
123 goto skip_pdev_creation
;
125 res
= devm_kcalloc(&pci
->dev
, num_res
, sizeof(struct resource
), GFP_KERNEL
);
128 goto unregister_dmic_dev
;
131 for (i
= 0; i
< num_res
; i
++, res_acp
++) {
132 res
[i
].name
= res_acp
->name
;
133 res
[i
].flags
= res_acp
->flags
;
134 res
[i
].start
= addr
+ res_acp
->start
;
135 res
[i
].end
= addr
+ res_acp
->end
;
136 if (res_acp
->flags
== IORESOURCE_IRQ
) {
137 res
[i
].start
= pci
->irq
;
138 res
[i
].end
= res
[i
].start
;
142 memset(&pdevinfo
, 0, sizeof(pdevinfo
));
144 pdevinfo
.name
= chip
->name
;
146 pdevinfo
.parent
= &pci
->dev
;
147 pdevinfo
.num_res
= num_res
;
148 pdevinfo
.res
= &res
[0];
149 pdevinfo
.data
= chip
;
150 pdevinfo
.size_data
= sizeof(*chip
);
152 pdev
= platform_device_register_full(&pdevinfo
);
154 dev_err(&pci
->dev
, "cannot register %s device\n", pdevinfo
.name
);
156 goto unregister_dmic_dev
;
160 chip
->chip_pdev
= pdev
;
161 dev_set_drvdata(&pci
->dev
, chip
);
162 pm_runtime_set_autosuspend_delay(&pci
->dev
, 2000);
163 pm_runtime_use_autosuspend(&pci
->dev
);
164 pm_runtime_put_noidle(&pci
->dev
);
165 pm_runtime_allow(&pci
->dev
);
169 platform_device_unregister(dmic_dev
);
171 pci_release_regions(pci
);
173 pci_disable_device(pci
);
178 static int __maybe_unused
snd_acp_suspend(struct device
*dev
)
180 struct acp_chip_info
*chip
;
183 chip
= dev_get_drvdata(dev
);
184 ret
= acp_deinit(chip
);
186 dev_err(dev
, "ACP de-init failed\n");
190 static int __maybe_unused
snd_acp_resume(struct device
*dev
)
192 struct acp_chip_info
*chip
;
193 struct acp_dev_data
*adata
;
197 chip
= dev_get_drvdata(dev
);
198 ret
= acp_init(chip
);
200 dev_err(dev
, "ACP init failed\n");
201 if (chip
->chip_pdev
) {
202 child
= chip
->chip_pdev
->dev
;
203 adata
= dev_get_drvdata(&child
);
205 acp_enable_interrupts(adata
);
210 static const struct dev_pm_ops acp_pm_ops
= {
211 SET_RUNTIME_PM_OPS(snd_acp_suspend
, snd_acp_resume
, NULL
)
212 SET_SYSTEM_SLEEP_PM_OPS(snd_acp_suspend
, snd_acp_resume
)
215 static void acp_pci_remove(struct pci_dev
*pci
)
217 struct acp_chip_info
*chip
;
220 chip
= pci_get_drvdata(pci
);
221 pm_runtime_forbid(&pci
->dev
);
222 pm_runtime_get_noresume(&pci
->dev
);
224 platform_device_unregister(dmic_dev
);
226 platform_device_unregister(pdev
);
227 ret
= acp_deinit(chip
);
229 dev_err(&pci
->dev
, "ACP de-init failed\n");
233 static const struct pci_device_id acp_pci_ids
[] = {
234 { PCI_DEVICE(PCI_VENDOR_ID_AMD
, ACP_PCI_DEV_ID
)},
237 MODULE_DEVICE_TABLE(pci
, acp_pci_ids
);
239 /* pci_driver definition */
240 static struct pci_driver snd_amd_acp_pci_driver
= {
241 .name
= KBUILD_MODNAME
,
242 .id_table
= acp_pci_ids
,
243 .probe
= acp_pci_probe
,
244 .remove
= acp_pci_remove
,
249 module_pci_driver(snd_amd_acp_pci_driver
);
251 MODULE_DESCRIPTION("AMD ACP common PCI support");
252 MODULE_LICENSE("Dual BSD/GPL");
253 MODULE_IMPORT_NS("SND_SOC_ACP_COMMON");
254 MODULE_ALIAS(DRV_NAME
);