1 // SPDX-License-Identifier: GPL-2.0+ 2 // 3 // AMD ACP PCI Driver 4 // 5 //Copyright 2016 Advanced Micro Devices, Inc. 6 7 #include <linux/pci.h> 8 #include <linux/module.h> 9 #include <linux/io.h> 10 #include <linux/platform_device.h> 11 #include <linux/interrupt.h> 12 #include <linux/pm_runtime.h> 13 #include <linux/delay.h> 14 15 #include "acp3x.h" 16 17 struct acp3x_dev_data { 18 void __iomem *acp3x_base; 19 bool acp3x_audio_mode; 20 struct resource *res; 21 struct platform_device *pdev[ACP3x_DEVS]; 22 u32 pme_en; 23 }; 24 25 static int acp3x_power_on(struct acp3x_dev_data *adata) 26 { 27 void __iomem *acp3x_base = adata->acp3x_base; 28 u32 val; 29 int timeout; 30 31 val = rv_readl(acp3x_base + mmACP_PGFSM_STATUS); 32 33 if (val == 0) 34 return val; 35 36 if (!((val & ACP_PGFSM_STATUS_MASK) == 37 ACP_POWER_ON_IN_PROGRESS)) 38 rv_writel(ACP_PGFSM_CNTL_POWER_ON_MASK, 39 acp3x_base + mmACP_PGFSM_CONTROL); 40 timeout = 0; 41 while (++timeout < 500) { 42 val = rv_readl(acp3x_base + mmACP_PGFSM_STATUS); 43 if (!val) { 44 /* ACP power On clears PME_EN. 45 * Restore the value to its prior state 46 */ 47 rv_writel(adata->pme_en, acp3x_base + mmACP_PME_EN); 48 return 0; 49 } 50 udelay(1); 51 } 52 return -ETIMEDOUT; 53 } 54 55 static int acp3x_reset(void __iomem *acp3x_base) 56 { 57 u32 val; 58 int timeout; 59 60 rv_writel(1, acp3x_base + mmACP_SOFT_RESET); 61 timeout = 0; 62 while (++timeout < 500) { 63 val = rv_readl(acp3x_base + mmACP_SOFT_RESET); 64 if (val & ACP3x_SOFT_RESET__SoftResetAudDone_MASK) 65 break; 66 cpu_relax(); 67 } 68 rv_writel(0, acp3x_base + mmACP_SOFT_RESET); 69 timeout = 0; 70 while (++timeout < 500) { 71 val = rv_readl(acp3x_base + mmACP_SOFT_RESET); 72 if (!val) 73 return 0; 74 cpu_relax(); 75 } 76 return -ETIMEDOUT; 77 } 78 79 static int acp3x_init(struct acp3x_dev_data *adata) 80 { 81 void __iomem *acp3x_base = adata->acp3x_base; 82 int ret; 83 84 /* power on */ 85 ret = acp3x_power_on(adata); 86 if (ret) { 87 pr_err("ACP3x power on failed\n"); 88 return ret; 89 } 90 /* Reset */ 91 ret = acp3x_reset(acp3x_base); 92 if (ret) { 93 pr_err("ACP3x reset failed\n"); 94 return ret; 95 } 96 return 0; 97 } 98 99 static int acp3x_deinit(void __iomem *acp3x_base) 100 { 101 int ret; 102 103 /* Reset */ 104 ret = acp3x_reset(acp3x_base); 105 if (ret) { 106 pr_err("ACP3x reset failed\n"); 107 return ret; 108 } 109 return 0; 110 } 111 112 static int snd_acp3x_probe(struct pci_dev *pci, 113 const struct pci_device_id *pci_id) 114 { 115 struct acp3x_dev_data *adata; 116 struct platform_device_info pdevinfo[ACP3x_DEVS]; 117 unsigned int irqflags; 118 int ret, i; 119 u32 addr, val; 120 121 /* Raven device detection */ 122 if (pci->revision != 0x00) 123 return -ENODEV; 124 125 if (pci_enable_device(pci)) { 126 dev_err(&pci->dev, "pci_enable_device failed\n"); 127 return -ENODEV; 128 } 129 130 ret = pci_request_regions(pci, "AMD ACP3x audio"); 131 if (ret < 0) { 132 dev_err(&pci->dev, "pci_request_regions failed\n"); 133 goto disable_pci; 134 } 135 136 adata = devm_kzalloc(&pci->dev, sizeof(struct acp3x_dev_data), 137 GFP_KERNEL); 138 if (!adata) { 139 ret = -ENOMEM; 140 goto release_regions; 141 } 142 143 /* check for msi interrupt support */ 144 ret = pci_enable_msi(pci); 145 if (ret) 146 /* msi is not enabled */ 147 irqflags = IRQF_SHARED; 148 else 149 /* msi is enabled */ 150 irqflags = 0; 151 152 addr = pci_resource_start(pci, 0); 153 adata->acp3x_base = devm_ioremap(&pci->dev, addr, 154 pci_resource_len(pci, 0)); 155 if (!adata->acp3x_base) { 156 ret = -ENOMEM; 157 goto disable_msi; 158 } 159 pci_set_master(pci); 160 pci_set_drvdata(pci, adata); 161 /* Save ACP_PME_EN state */ 162 adata->pme_en = rv_readl(adata->acp3x_base + mmACP_PME_EN); 163 ret = acp3x_init(adata); 164 if (ret) 165 goto disable_msi; 166 167 val = rv_readl(adata->acp3x_base + mmACP_I2S_PIN_CONFIG); 168 switch (val) { 169 case I2S_MODE: 170 adata->res = devm_kzalloc(&pci->dev, 171 sizeof(struct resource) * 4, 172 GFP_KERNEL); 173 if (!adata->res) { 174 ret = -ENOMEM; 175 goto de_init; 176 } 177 178 adata->res[0].name = "acp3x_i2s_iomem"; 179 adata->res[0].flags = IORESOURCE_MEM; 180 adata->res[0].start = addr; 181 adata->res[0].end = addr + (ACP3x_REG_END - ACP3x_REG_START); 182 183 adata->res[1].name = "acp3x_i2s_sp"; 184 adata->res[1].flags = IORESOURCE_MEM; 185 adata->res[1].start = addr + ACP3x_I2STDM_REG_START; 186 adata->res[1].end = addr + ACP3x_I2STDM_REG_END; 187 188 adata->res[2].name = "acp3x_i2s_bt"; 189 adata->res[2].flags = IORESOURCE_MEM; 190 adata->res[2].start = addr + ACP3x_BT_TDM_REG_START; 191 adata->res[2].end = addr + ACP3x_BT_TDM_REG_END; 192 193 adata->res[3].name = "acp3x_i2s_irq"; 194 adata->res[3].flags = IORESOURCE_IRQ; 195 adata->res[3].start = pci->irq; 196 adata->res[3].end = adata->res[3].start; 197 198 adata->acp3x_audio_mode = ACP3x_I2S_MODE; 199 200 memset(&pdevinfo, 0, sizeof(pdevinfo)); 201 pdevinfo[0].name = "acp3x_rv_i2s_dma"; 202 pdevinfo[0].id = 0; 203 pdevinfo[0].parent = &pci->dev; 204 pdevinfo[0].num_res = 4; 205 pdevinfo[0].res = &adata->res[0]; 206 pdevinfo[0].data = &irqflags; 207 pdevinfo[0].size_data = sizeof(irqflags); 208 209 pdevinfo[1].name = "acp3x_i2s_playcap"; 210 pdevinfo[1].id = 0; 211 pdevinfo[1].parent = &pci->dev; 212 pdevinfo[1].num_res = 1; 213 pdevinfo[1].res = &adata->res[1]; 214 215 pdevinfo[2].name = "acp3x_i2s_playcap"; 216 pdevinfo[2].id = 1; 217 pdevinfo[2].parent = &pci->dev; 218 pdevinfo[2].num_res = 1; 219 pdevinfo[2].res = &adata->res[1]; 220 221 pdevinfo[3].name = "acp3x_i2s_playcap"; 222 pdevinfo[3].id = 2; 223 pdevinfo[3].parent = &pci->dev; 224 pdevinfo[3].num_res = 1; 225 pdevinfo[3].res = &adata->res[2]; 226 for (i = 0; i < ACP3x_DEVS; i++) { 227 adata->pdev[i] = 228 platform_device_register_full(&pdevinfo[i]); 229 if (IS_ERR(adata->pdev[i])) { 230 dev_err(&pci->dev, "cannot register %s device\n", 231 pdevinfo[i].name); 232 ret = PTR_ERR(adata->pdev[i]); 233 goto unregister_devs; 234 } 235 } 236 break; 237 default: 238 dev_info(&pci->dev, "ACP audio mode : %d\n", val); 239 break; 240 } 241 pm_runtime_set_autosuspend_delay(&pci->dev, 2000); 242 pm_runtime_use_autosuspend(&pci->dev); 243 pm_runtime_put_noidle(&pci->dev); 244 pm_runtime_allow(&pci->dev); 245 return 0; 246 247 unregister_devs: 248 if (val == I2S_MODE) 249 for (i = 0; i < ACP3x_DEVS; i++) 250 platform_device_unregister(adata->pdev[i]); 251 de_init: 252 if (acp3x_deinit(adata->acp3x_base)) 253 dev_err(&pci->dev, "ACP de-init failed\n"); 254 disable_msi: 255 pci_disable_msi(pci); 256 release_regions: 257 pci_release_regions(pci); 258 disable_pci: 259 pci_disable_device(pci); 260 261 return ret; 262 } 263 264 static int snd_acp3x_suspend(struct device *dev) 265 { 266 int ret; 267 struct acp3x_dev_data *adata; 268 269 adata = dev_get_drvdata(dev); 270 ret = acp3x_deinit(adata->acp3x_base); 271 if (ret) 272 dev_err(dev, "ACP de-init failed\n"); 273 else 274 dev_dbg(dev, "ACP de-initialized\n"); 275 276 return 0; 277 } 278 279 static int snd_acp3x_resume(struct device *dev) 280 { 281 int ret; 282 struct acp3x_dev_data *adata; 283 284 adata = dev_get_drvdata(dev); 285 ret = acp3x_init(adata); 286 if (ret) { 287 dev_err(dev, "ACP init failed\n"); 288 return ret; 289 } 290 return 0; 291 } 292 293 static const struct dev_pm_ops acp3x_pm = { 294 .runtime_suspend = snd_acp3x_suspend, 295 .runtime_resume = snd_acp3x_resume, 296 .resume = snd_acp3x_resume, 297 }; 298 299 static void snd_acp3x_remove(struct pci_dev *pci) 300 { 301 struct acp3x_dev_data *adata; 302 int i, ret; 303 304 adata = pci_get_drvdata(pci); 305 if (adata->acp3x_audio_mode == ACP3x_I2S_MODE) { 306 for (i = 0; i < ACP3x_DEVS; i++) 307 platform_device_unregister(adata->pdev[i]); 308 } 309 ret = acp3x_deinit(adata->acp3x_base); 310 if (ret) 311 dev_err(&pci->dev, "ACP de-init failed\n"); 312 pm_runtime_forbid(&pci->dev); 313 pm_runtime_get_noresume(&pci->dev); 314 pci_disable_msi(pci); 315 pci_release_regions(pci); 316 pci_disable_device(pci); 317 } 318 319 static const struct pci_device_id snd_acp3x_ids[] = { 320 { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x15e2), 321 .class = PCI_CLASS_MULTIMEDIA_OTHER << 8, 322 .class_mask = 0xffffff }, 323 { 0, }, 324 }; 325 MODULE_DEVICE_TABLE(pci, snd_acp3x_ids); 326 327 static struct pci_driver acp3x_driver = { 328 .name = KBUILD_MODNAME, 329 .id_table = snd_acp3x_ids, 330 .probe = snd_acp3x_probe, 331 .remove = snd_acp3x_remove, 332 .driver = { 333 .pm = &acp3x_pm, 334 } 335 }; 336 337 module_pci_driver(acp3x_driver); 338 339 MODULE_AUTHOR("Vishnuvardhanrao.Ravulapati@amd.com"); 340 MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com"); 341 MODULE_DESCRIPTION("AMD ACP3x PCI driver"); 342 MODULE_LICENSE("GPL v2"); 343