1 // SPDX-License-Identifier: GPL-2.0+
3 // AMD Renoir ACP PCI Driver
5 //Copyright 2020 Advanced Micro Devices, Inc.
8 #include <linux/acpi.h>
10 #include <linux/module.h>
12 #include <linux/delay.h>
13 #include <linux/platform_device.h>
14 #include <linux/interrupt.h>
15 #include <linux/pm_runtime.h>
19 static int acp_power_gating
;
20 module_param(acp_power_gating
, int, 0644);
21 MODULE_PARM_DESC(acp_power_gating
, "Enable acp power gating");
24 * dmic_acpi_check = -1 - Use ACPI/DMI method to detect the DMIC hardware presence at runtime
25 * = 0 - Skip the DMIC device creation and return probe failure
26 * = 1 - Force DMIC support
28 static int dmic_acpi_check
= ACP_DMIC_AUTO
;
29 module_param(dmic_acpi_check
, bint
, 0644);
30 MODULE_PARM_DESC(dmic_acpi_check
, "Digital microphone presence (-1=auto, 0=none, 1=force)");
33 void __iomem
*acp_base
;
35 struct platform_device
*pdev
[ACP_DEVS
];
38 static int rn_acp_power_on(void __iomem
*acp_base
)
43 val
= rn_readl(acp_base
+ ACP_PGFSM_STATUS
);
48 if ((val
& ACP_PGFSM_STATUS_MASK
) !=
49 ACP_POWER_ON_IN_PROGRESS
)
50 rn_writel(ACP_PGFSM_CNTL_POWER_ON_MASK
,
51 acp_base
+ ACP_PGFSM_CONTROL
);
53 while (++timeout
< 500) {
54 val
= rn_readl(acp_base
+ ACP_PGFSM_STATUS
);
62 static int rn_acp_power_off(void __iomem
*acp_base
)
67 rn_writel(ACP_PGFSM_CNTL_POWER_OFF_MASK
,
68 acp_base
+ ACP_PGFSM_CONTROL
);
70 while (++timeout
< 500) {
71 val
= rn_readl(acp_base
+ ACP_PGFSM_STATUS
);
72 if ((val
& ACP_PGFSM_STATUS_MASK
) == ACP_POWERED_OFF
)
79 static int rn_acp_reset(void __iomem
*acp_base
)
84 rn_writel(1, acp_base
+ ACP_SOFT_RESET
);
86 while (++timeout
< 500) {
87 val
= rn_readl(acp_base
+ ACP_SOFT_RESET
);
88 if (val
& ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK
)
92 rn_writel(0, acp_base
+ ACP_SOFT_RESET
);
94 while (++timeout
< 500) {
95 val
= rn_readl(acp_base
+ ACP_SOFT_RESET
);
103 static void rn_acp_enable_interrupts(void __iomem
*acp_base
)
107 rn_writel(0x01, acp_base
+ ACP_EXTERNAL_INTR_ENB
);
108 ext_intr_ctrl
= rn_readl(acp_base
+ ACP_EXTERNAL_INTR_CNTL
);
109 ext_intr_ctrl
|= ACP_ERROR_MASK
;
110 rn_writel(ext_intr_ctrl
, acp_base
+ ACP_EXTERNAL_INTR_CNTL
);
113 static void rn_acp_disable_interrupts(void __iomem
*acp_base
)
115 rn_writel(ACP_EXT_INTR_STAT_CLEAR_MASK
, acp_base
+
116 ACP_EXTERNAL_INTR_STAT
);
117 rn_writel(0x00, acp_base
+ ACP_EXTERNAL_INTR_ENB
);
120 static int rn_acp_init(void __iomem
*acp_base
)
125 ret
= rn_acp_power_on(acp_base
);
127 pr_err("ACP power on failed\n");
130 rn_writel(0x01, acp_base
+ ACP_CONTROL
);
132 ret
= rn_acp_reset(acp_base
);
134 pr_err("ACP reset failed\n");
137 rn_writel(0x03, acp_base
+ ACP_CLKMUX_SEL
);
138 rn_acp_enable_interrupts(acp_base
);
142 static int rn_acp_deinit(void __iomem
*acp_base
)
146 rn_acp_disable_interrupts(acp_base
);
148 ret
= rn_acp_reset(acp_base
);
150 pr_err("ACP reset failed\n");
153 rn_writel(0x00, acp_base
+ ACP_CLKMUX_SEL
);
154 rn_writel(0x00, acp_base
+ ACP_CONTROL
);
156 if (acp_power_gating
) {
157 ret
= rn_acp_power_off(acp_base
);
159 pr_err("ACP power off failed\n");
166 static const struct dmi_system_id rn_acp_quirk_table
[] = {
168 /* Lenovo IdeaPad Flex 5 14ARE05, IdeaPad 5 15ARE05 */
170 DMI_EXACT_MATCH(DMI_BOARD_VENDOR
, "LENOVO"),
171 DMI_EXACT_MATCH(DMI_BOARD_NAME
, "LNVNB161216"),
177 static int snd_rn_acp_probe(struct pci_dev
*pci
,
178 const struct pci_device_id
*pci_id
)
180 struct acp_dev_data
*adata
;
181 struct platform_device_info pdevinfo
[ACP_DEVS
];
182 #if defined(CONFIG_ACPI)
184 acpi_integer dmic_status
;
186 const struct dmi_system_id
*dmi_id
;
187 unsigned int irqflags
;
191 /* Renoir device check */
192 if (pci
->revision
!= 0x01)
195 if (pci_enable_device(pci
)) {
196 dev_err(&pci
->dev
, "pci_enable_device failed\n");
200 ret
= pci_request_regions(pci
, "AMD ACP3x audio");
202 dev_err(&pci
->dev
, "pci_request_regions failed\n");
206 adata
= devm_kzalloc(&pci
->dev
, sizeof(struct acp_dev_data
),
210 goto release_regions
;
213 /* check for msi interrupt support */
214 ret
= pci_enable_msi(pci
);
216 /* msi is not enabled */
217 irqflags
= IRQF_SHARED
;
222 addr
= pci_resource_start(pci
, 0);
223 adata
->acp_base
= devm_ioremap(&pci
->dev
, addr
,
224 pci_resource_len(pci
, 0));
225 if (!adata
->acp_base
) {
230 pci_set_drvdata(pci
, adata
);
231 ret
= rn_acp_init(adata
->acp_base
);
235 if (!dmic_acpi_check
) {
238 } else if (dmic_acpi_check
== ACP_DMIC_AUTO
) {
239 #if defined(CONFIG_ACPI)
240 handle
= ACPI_HANDLE(&pci
->dev
);
241 ret
= acpi_evaluate_integer(handle
, "_WOV", NULL
, &dmic_status
);
242 if (ACPI_FAILURE(ret
)) {
251 dmi_id
= dmi_first_match(rn_acp_quirk_table
);
252 if (dmi_id
&& !dmi_id
->driver_data
) {
253 dev_info(&pci
->dev
, "ACPI settings override using DMI (ACP mic is not present)");
259 adata
->res
= devm_kzalloc(&pci
->dev
,
260 sizeof(struct resource
) * 2,
267 adata
->res
[0].name
= "acp_pdm_iomem";
268 adata
->res
[0].flags
= IORESOURCE_MEM
;
269 adata
->res
[0].start
= addr
;
270 adata
->res
[0].end
= addr
+ (ACP_REG_END
- ACP_REG_START
);
271 adata
->res
[1].name
= "acp_pdm_irq";
272 adata
->res
[1].flags
= IORESOURCE_IRQ
;
273 adata
->res
[1].start
= pci
->irq
;
274 adata
->res
[1].end
= pci
->irq
;
276 memset(&pdevinfo
, 0, sizeof(pdevinfo
));
277 pdevinfo
[0].name
= "acp_rn_pdm_dma";
279 pdevinfo
[0].parent
= &pci
->dev
;
280 pdevinfo
[0].num_res
= 2;
281 pdevinfo
[0].res
= adata
->res
;
282 pdevinfo
[0].data
= &irqflags
;
283 pdevinfo
[0].size_data
= sizeof(irqflags
);
285 pdevinfo
[1].name
= "dmic-codec";
287 pdevinfo
[1].parent
= &pci
->dev
;
288 pdevinfo
[2].name
= "acp_pdm_mach";
290 pdevinfo
[2].parent
= &pci
->dev
;
291 for (index
= 0; index
< ACP_DEVS
; index
++) {
293 platform_device_register_full(&pdevinfo
[index
]);
294 if (IS_ERR(adata
->pdev
[index
])) {
295 dev_err(&pci
->dev
, "cannot register %s device\n",
296 pdevinfo
[index
].name
);
297 ret
= PTR_ERR(adata
->pdev
[index
]);
298 goto unregister_devs
;
301 pm_runtime_set_autosuspend_delay(&pci
->dev
, ACP_SUSPEND_DELAY_MS
);
302 pm_runtime_use_autosuspend(&pci
->dev
);
303 pm_runtime_put_noidle(&pci
->dev
);
304 pm_runtime_allow(&pci
->dev
);
308 for (index
= 0; index
< ACP_DEVS
; index
++)
309 platform_device_unregister(adata
->pdev
[index
]);
311 if (rn_acp_deinit(adata
->acp_base
))
312 dev_err(&pci
->dev
, "ACP de-init failed\n");
314 pci_disable_msi(pci
);
316 pci_release_regions(pci
);
318 pci_disable_device(pci
);
323 static int snd_rn_acp_suspend(struct device
*dev
)
326 struct acp_dev_data
*adata
;
328 adata
= dev_get_drvdata(dev
);
329 ret
= rn_acp_deinit(adata
->acp_base
);
331 dev_err(dev
, "ACP de-init failed\n");
333 dev_dbg(dev
, "ACP de-initialized\n");
338 static int snd_rn_acp_resume(struct device
*dev
)
341 struct acp_dev_data
*adata
;
343 adata
= dev_get_drvdata(dev
);
344 ret
= rn_acp_init(adata
->acp_base
);
346 dev_err(dev
, "ACP init failed\n");
352 static const struct dev_pm_ops rn_acp_pm
= {
353 .runtime_suspend
= snd_rn_acp_suspend
,
354 .runtime_resume
= snd_rn_acp_resume
,
355 .suspend
= snd_rn_acp_suspend
,
356 .resume
= snd_rn_acp_resume
,
359 static void snd_rn_acp_remove(struct pci_dev
*pci
)
361 struct acp_dev_data
*adata
;
364 adata
= pci_get_drvdata(pci
);
365 for (index
= 0; index
< ACP_DEVS
; index
++)
366 platform_device_unregister(adata
->pdev
[index
]);
367 ret
= rn_acp_deinit(adata
->acp_base
);
369 dev_err(&pci
->dev
, "ACP de-init failed\n");
370 pm_runtime_forbid(&pci
->dev
);
371 pm_runtime_get_noresume(&pci
->dev
);
372 pci_disable_msi(pci
);
373 pci_release_regions(pci
);
374 pci_disable_device(pci
);
377 static const struct pci_device_id snd_rn_acp_ids
[] = {
378 { PCI_DEVICE(PCI_VENDOR_ID_AMD
, ACP_DEVICE_ID
),
379 .class = PCI_CLASS_MULTIMEDIA_OTHER
<< 8,
380 .class_mask
= 0xffffff },
383 MODULE_DEVICE_TABLE(pci
, snd_rn_acp_ids
);
385 static struct pci_driver rn_acp_driver
= {
386 .name
= KBUILD_MODNAME
,
387 .id_table
= snd_rn_acp_ids
,
388 .probe
= snd_rn_acp_probe
,
389 .remove
= snd_rn_acp_remove
,
395 module_pci_driver(rn_acp_driver
);
397 MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
398 MODULE_DESCRIPTION("AMD ACP Renoir PCI driver");
399 MODULE_LICENSE("GPL v2");