1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * AMD common ACP PCI driver for ACP7.x variants 4 * which includes ACP7.D/7.E/7.F and future variants 5 * with same register layout. 6 * 7 * Copyright 2026 Advanced Micro Devices, Inc. 8 */ 9 10 #include <linux/errno.h> 11 #include <linux/io.h> 12 #include <linux/module.h> 13 #include <linux/pci.h> 14 #include <linux/pm_runtime.h> 15 #include <linux/slab.h> 16 #include <linux/types.h> 17 18 #include "acp7x.h" 19 20 static int acp_hw_init_ops(struct acp7x_dev_data *adata, struct pci_dev *pci) 21 { 22 adata->hw_ops = devm_kzalloc(&pci->dev, sizeof(struct acp_hw_ops), 23 GFP_KERNEL); 24 if (!adata->hw_ops) 25 return -ENOMEM; 26 27 switch (adata->acp_rev) { 28 case ACP7D_PCI_REV: 29 case ACP7E_PCI_REV: 30 case ACP7F_PCI_REV: 31 acp7x_hw_init_ops(adata->hw_ops); 32 break; 33 default: 34 dev_err(&pci->dev, "ACP device not found\n"); 35 return -ENODEV; 36 } 37 return 0; 38 } 39 40 static int snd_acp7x_probe(struct pci_dev *pci, 41 const struct pci_device_id *pci_id) 42 { 43 struct acp7x_dev_data *adata; 44 u32 addr; 45 u32 flag; 46 int ret; 47 48 flag = snd_amd_acp_find_config(pci); 49 if (flag) 50 return -ENODEV; 51 /* ACP PCI revision id check for ACP7.x platforms */ 52 switch (pci->revision) { 53 case ACP7D_PCI_REV: 54 case ACP7E_PCI_REV: 55 case ACP7F_PCI_REV: 56 break; 57 default: 58 return -ENODEV; 59 } 60 if (pci_enable_device(pci)) { 61 dev_err(&pci->dev, "pci_enable_device failed\n"); 62 return -ENODEV; 63 } 64 65 ret = pci_request_regions(pci, "AMD ACP7.x audio"); 66 if (ret < 0) { 67 dev_err(&pci->dev, "pci_request_regions failed\n"); 68 goto disable_pci; 69 } 70 adata = devm_kzalloc(&pci->dev, sizeof(struct acp7x_dev_data), 71 GFP_KERNEL); 72 if (!adata) { 73 ret = -ENOMEM; 74 goto release_regions; 75 } 76 addr = pci_resource_start(pci, 0); 77 adata->acp7x_base = devm_ioremap(&pci->dev, addr, 78 pci_resource_len(pci, 0)); 79 if (!adata->acp7x_base) { 80 ret = -ENOMEM; 81 goto release_regions; 82 } 83 adata->addr = addr; 84 adata->reg_range = ACP7X_REG_END - ACP7X_REG_START; 85 adata->acp_rev = pci->revision; 86 pci_set_master(pci); 87 pci_set_drvdata(pci, adata); 88 ret = acp_hw_init_ops(adata, pci); 89 if (ret) { 90 dev_err(&pci->dev, "ACP hw ops init failed\n"); 91 goto release_regions; 92 } 93 ret = acp_hw_init(adata, &pci->dev); 94 if (ret) 95 goto release_regions; 96 97 pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS); 98 pm_runtime_use_autosuspend(&pci->dev); 99 pm_runtime_put_noidle(&pci->dev); 100 pm_runtime_allow(&pci->dev); 101 return 0; 102 103 release_regions: 104 pci_release_regions(pci); 105 disable_pci: 106 pci_disable_device(pci); 107 108 return ret; 109 } 110 111 static int __maybe_unused snd_acp_suspend(struct device *dev) 112 { 113 return acp_hw_suspend(dev); 114 } 115 116 static int __maybe_unused snd_acp_runtime_resume(struct device *dev) 117 { 118 return acp_hw_runtime_resume(dev); 119 } 120 121 static int __maybe_unused snd_acp_resume(struct device *dev) 122 { 123 return acp_hw_resume(dev); 124 } 125 126 static const struct dev_pm_ops acp7x_pm_ops = { 127 SET_RUNTIME_PM_OPS(snd_acp_suspend, snd_acp_runtime_resume, NULL) 128 SET_SYSTEM_SLEEP_PM_OPS(snd_acp_suspend, snd_acp_resume) 129 }; 130 131 static void snd_acp7x_remove(struct pci_dev *pci) 132 { 133 struct acp7x_dev_data *adata; 134 int ret; 135 136 adata = pci_get_drvdata(pci); 137 ret = acp_hw_deinit(adata, &pci->dev); 138 if (ret) 139 dev_err(&pci->dev, "ACP de-init failed\n"); 140 pm_runtime_forbid(&pci->dev); 141 pm_runtime_get_noresume(&pci->dev); 142 pci_release_regions(pci); 143 pci_disable_device(pci); 144 } 145 146 static const struct pci_device_id snd_acp7x_ids[] = { 147 { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_DEVICE_ID), 148 .class = PCI_CLASS_MULTIMEDIA_OTHER << 8, 149 .class_mask = 0xffffff }, 150 { 0, }, 151 }; 152 MODULE_DEVICE_TABLE(pci, snd_acp7x_ids); 153 154 static struct pci_driver acp7x_pci_driver = { 155 .name = KBUILD_MODNAME, 156 .id_table = snd_acp7x_ids, 157 .probe = snd_acp7x_probe, 158 .remove = snd_acp7x_remove, 159 .driver = { 160 .pm = &acp7x_pm_ops, 161 } 162 }; 163 164 module_pci_driver(acp7x_pci_driver); 165 166 MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); 167 MODULE_DESCRIPTION("AMD ACP PCI driver for ACP7.X"); 168 MODULE_LICENSE("GPL"); 169