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