xref: /linux/sound/soc/amd/acp7x/pci-acp7x.c (revision 0eaed89c18aeedf0898baf2dbf5ff027c6795152)
11da6f798SVijendar Mukunda // SPDX-License-Identifier: GPL-2.0-only
21da6f798SVijendar Mukunda /*
31da6f798SVijendar Mukunda  * AMD common ACP PCI driver for ACP7.x variants
41da6f798SVijendar Mukunda  * which includes ACP7.D/7.E/7.F and future variants
51da6f798SVijendar Mukunda  * with same register layout.
61da6f798SVijendar Mukunda  *
71da6f798SVijendar Mukunda  * Copyright 2026 Advanced Micro Devices, Inc.
81da6f798SVijendar Mukunda  */
91da6f798SVijendar Mukunda 
101da6f798SVijendar Mukunda #include <linux/errno.h>
111da6f798SVijendar Mukunda #include <linux/io.h>
121da6f798SVijendar Mukunda #include <linux/module.h>
131da6f798SVijendar Mukunda #include <linux/pci.h>
14*07d56a83SVijendar Mukunda #include <linux/pm_runtime.h>
151da6f798SVijendar Mukunda #include <linux/slab.h>
161da6f798SVijendar Mukunda #include <linux/types.h>
171da6f798SVijendar Mukunda 
181da6f798SVijendar Mukunda #include "acp7x.h"
191da6f798SVijendar Mukunda 
20b5a2fdc5SVijendar Mukunda static int acp_hw_init_ops(struct acp7x_dev_data *adata, struct pci_dev *pci)
21b5a2fdc5SVijendar Mukunda {
22b5a2fdc5SVijendar Mukunda 	adata->hw_ops = devm_kzalloc(&pci->dev, sizeof(struct acp_hw_ops),
23b5a2fdc5SVijendar Mukunda 				     GFP_KERNEL);
24b5a2fdc5SVijendar Mukunda 	if (!adata->hw_ops)
25b5a2fdc5SVijendar Mukunda 		return -ENOMEM;
26b5a2fdc5SVijendar Mukunda 
27b5a2fdc5SVijendar Mukunda 	switch (adata->acp_rev) {
28b5a2fdc5SVijendar Mukunda 	case ACP7D_PCI_REV:
29b5a2fdc5SVijendar Mukunda 	case ACP7E_PCI_REV:
30b5a2fdc5SVijendar Mukunda 	case ACP7F_PCI_REV:
31b5a2fdc5SVijendar Mukunda 		acp7x_hw_init_ops(adata->hw_ops);
32b5a2fdc5SVijendar Mukunda 		break;
33b5a2fdc5SVijendar Mukunda 	default:
34b5a2fdc5SVijendar Mukunda 		dev_err(&pci->dev, "ACP device not found\n");
35b5a2fdc5SVijendar Mukunda 		return -ENODEV;
36b5a2fdc5SVijendar Mukunda 	}
37b5a2fdc5SVijendar Mukunda 	return 0;
38b5a2fdc5SVijendar Mukunda }
39b5a2fdc5SVijendar Mukunda 
401da6f798SVijendar Mukunda static int snd_acp7x_probe(struct pci_dev *pci,
411da6f798SVijendar Mukunda 			   const struct pci_device_id *pci_id)
421da6f798SVijendar Mukunda {
431da6f798SVijendar Mukunda 	struct acp7x_dev_data *adata;
441da6f798SVijendar Mukunda 	u32 addr;
451da6f798SVijendar Mukunda 	u32 flag;
461da6f798SVijendar Mukunda 	int ret;
471da6f798SVijendar Mukunda 
481da6f798SVijendar Mukunda 	flag = snd_amd_acp_find_config(pci);
491da6f798SVijendar Mukunda 	if (flag)
501da6f798SVijendar Mukunda 		return -ENODEV;
511da6f798SVijendar Mukunda 	/* ACP PCI revision id check for ACP7.x platforms */
521da6f798SVijendar Mukunda 	switch (pci->revision) {
531da6f798SVijendar Mukunda 	case ACP7D_PCI_REV:
541da6f798SVijendar Mukunda 	case ACP7E_PCI_REV:
551da6f798SVijendar Mukunda 	case ACP7F_PCI_REV:
561da6f798SVijendar Mukunda 		break;
571da6f798SVijendar Mukunda 	default:
581da6f798SVijendar Mukunda 		return -ENODEV;
591da6f798SVijendar Mukunda 	}
601da6f798SVijendar Mukunda 	if (pci_enable_device(pci)) {
611da6f798SVijendar Mukunda 		dev_err(&pci->dev, "pci_enable_device failed\n");
621da6f798SVijendar Mukunda 		return -ENODEV;
631da6f798SVijendar Mukunda 	}
641da6f798SVijendar Mukunda 
651da6f798SVijendar Mukunda 	ret = pci_request_regions(pci, "AMD ACP7.x audio");
661da6f798SVijendar Mukunda 	if (ret < 0) {
671da6f798SVijendar Mukunda 		dev_err(&pci->dev, "pci_request_regions failed\n");
681da6f798SVijendar Mukunda 		goto disable_pci;
691da6f798SVijendar Mukunda 	}
701da6f798SVijendar Mukunda 	adata = devm_kzalloc(&pci->dev, sizeof(struct acp7x_dev_data),
711da6f798SVijendar Mukunda 			     GFP_KERNEL);
721da6f798SVijendar Mukunda 	if (!adata) {
731da6f798SVijendar Mukunda 		ret = -ENOMEM;
741da6f798SVijendar Mukunda 		goto release_regions;
751da6f798SVijendar Mukunda 	}
761da6f798SVijendar Mukunda 	addr = pci_resource_start(pci, 0);
771da6f798SVijendar Mukunda 	adata->acp7x_base = devm_ioremap(&pci->dev, addr,
781da6f798SVijendar Mukunda 					 pci_resource_len(pci, 0));
791da6f798SVijendar Mukunda 	if (!adata->acp7x_base) {
801da6f798SVijendar Mukunda 		ret = -ENOMEM;
811da6f798SVijendar Mukunda 		goto release_regions;
821da6f798SVijendar Mukunda 	}
83b5a2fdc5SVijendar Mukunda 	adata->addr = addr;
84b5a2fdc5SVijendar Mukunda 	adata->reg_range = ACP7X_REG_END - ACP7X_REG_START;
85b5a2fdc5SVijendar Mukunda 	adata->acp_rev = pci->revision;
861da6f798SVijendar Mukunda 	pci_set_master(pci);
871da6f798SVijendar Mukunda 	pci_set_drvdata(pci, adata);
88b5a2fdc5SVijendar Mukunda 	ret = acp_hw_init_ops(adata, pci);
89b5a2fdc5SVijendar Mukunda 	if (ret) {
90b5a2fdc5SVijendar Mukunda 		dev_err(&pci->dev, "ACP hw ops init failed\n");
91b5a2fdc5SVijendar Mukunda 		goto release_regions;
92b5a2fdc5SVijendar Mukunda 	}
93b5a2fdc5SVijendar Mukunda 	ret = acp_hw_init(adata, &pci->dev);
94b5a2fdc5SVijendar Mukunda 	if (ret)
95b5a2fdc5SVijendar Mukunda 		goto release_regions;
96*07d56a83SVijendar Mukunda 
97*07d56a83SVijendar Mukunda 	pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS);
98*07d56a83SVijendar Mukunda 	pm_runtime_use_autosuspend(&pci->dev);
99*07d56a83SVijendar Mukunda 	pm_runtime_put_noidle(&pci->dev);
100*07d56a83SVijendar Mukunda 	pm_runtime_allow(&pci->dev);
1011da6f798SVijendar Mukunda 	return 0;
1021da6f798SVijendar Mukunda 
1031da6f798SVijendar Mukunda release_regions:
1041da6f798SVijendar Mukunda 	pci_release_regions(pci);
1051da6f798SVijendar Mukunda disable_pci:
1061da6f798SVijendar Mukunda 	pci_disable_device(pci);
1071da6f798SVijendar Mukunda 
1081da6f798SVijendar Mukunda 	return ret;
1091da6f798SVijendar Mukunda }
1101da6f798SVijendar Mukunda 
111*07d56a83SVijendar Mukunda static int __maybe_unused snd_acp_suspend(struct device *dev)
112*07d56a83SVijendar Mukunda {
113*07d56a83SVijendar Mukunda 	return acp_hw_suspend(dev);
114*07d56a83SVijendar Mukunda }
115*07d56a83SVijendar Mukunda 
116*07d56a83SVijendar Mukunda static int __maybe_unused snd_acp_runtime_resume(struct device *dev)
117*07d56a83SVijendar Mukunda {
118*07d56a83SVijendar Mukunda 	return acp_hw_runtime_resume(dev);
119*07d56a83SVijendar Mukunda }
120*07d56a83SVijendar Mukunda 
121*07d56a83SVijendar Mukunda static int __maybe_unused snd_acp_resume(struct device *dev)
122*07d56a83SVijendar Mukunda {
123*07d56a83SVijendar Mukunda 	return acp_hw_resume(dev);
124*07d56a83SVijendar Mukunda }
125*07d56a83SVijendar Mukunda 
126*07d56a83SVijendar Mukunda static const struct dev_pm_ops acp7x_pm_ops = {
127*07d56a83SVijendar Mukunda 	SET_RUNTIME_PM_OPS(snd_acp_suspend, snd_acp_runtime_resume, NULL)
128*07d56a83SVijendar Mukunda 	SET_SYSTEM_SLEEP_PM_OPS(snd_acp_suspend, snd_acp_resume)
129*07d56a83SVijendar Mukunda };
130*07d56a83SVijendar Mukunda 
1311da6f798SVijendar Mukunda static void snd_acp7x_remove(struct pci_dev *pci)
1321da6f798SVijendar Mukunda {
133b5a2fdc5SVijendar Mukunda 	struct acp7x_dev_data *adata;
134b5a2fdc5SVijendar Mukunda 	int ret;
135b5a2fdc5SVijendar Mukunda 
136b5a2fdc5SVijendar Mukunda 	adata = pci_get_drvdata(pci);
137b5a2fdc5SVijendar Mukunda 	ret = acp_hw_deinit(adata, &pci->dev);
138b5a2fdc5SVijendar Mukunda 	if (ret)
139b5a2fdc5SVijendar Mukunda 		dev_err(&pci->dev, "ACP de-init failed\n");
140*07d56a83SVijendar Mukunda 	pm_runtime_forbid(&pci->dev);
141*07d56a83SVijendar Mukunda 	pm_runtime_get_noresume(&pci->dev);
1421da6f798SVijendar Mukunda 	pci_release_regions(pci);
1431da6f798SVijendar Mukunda 	pci_disable_device(pci);
1441da6f798SVijendar Mukunda }
1451da6f798SVijendar Mukunda 
1461da6f798SVijendar Mukunda static const struct pci_device_id snd_acp7x_ids[] = {
1471da6f798SVijendar Mukunda 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_DEVICE_ID),
1481da6f798SVijendar Mukunda 	.class = PCI_CLASS_MULTIMEDIA_OTHER << 8,
1491da6f798SVijendar Mukunda 	.class_mask = 0xffffff },
1501da6f798SVijendar Mukunda 	{ 0, },
1511da6f798SVijendar Mukunda };
1521da6f798SVijendar Mukunda MODULE_DEVICE_TABLE(pci, snd_acp7x_ids);
1531da6f798SVijendar Mukunda 
1541da6f798SVijendar Mukunda static struct pci_driver acp7x_pci_driver  = {
1551da6f798SVijendar Mukunda 	.name = KBUILD_MODNAME,
1561da6f798SVijendar Mukunda 	.id_table = snd_acp7x_ids,
1571da6f798SVijendar Mukunda 	.probe = snd_acp7x_probe,
1581da6f798SVijendar Mukunda 	.remove = snd_acp7x_remove,
159*07d56a83SVijendar Mukunda 	.driver = {
160*07d56a83SVijendar Mukunda 		.pm = &acp7x_pm_ops,
161*07d56a83SVijendar Mukunda 	}
1621da6f798SVijendar Mukunda };
1631da6f798SVijendar Mukunda 
1641da6f798SVijendar Mukunda module_pci_driver(acp7x_pci_driver);
1651da6f798SVijendar Mukunda 
1661da6f798SVijendar Mukunda MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
1671da6f798SVijendar Mukunda MODULE_DESCRIPTION("AMD ACP PCI driver for ACP7.X");
1681da6f798SVijendar Mukunda MODULE_LICENSE("GPL");
169