pci-ps.c (d93618da6b6d453c6a9684a3460ffd51b9b4ef2e) | pci-ps.c (4b19211435950a78af032c26ad64a5268e6012be) |
---|---|
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * AMD Pink Sardine ACP PCI Driver 4 * 5 * Copyright 2022 Advanced Micro Devices, Inc. 6 */ 7 8#include <linux/pci.h> 9#include <linux/module.h> 10#include <linux/io.h> 11#include <linux/delay.h> 12#include <linux/platform_device.h> 13#include <linux/acpi.h> 14#include <linux/interrupt.h> 15#include <sound/pcm_params.h> 16#include <linux/pm_runtime.h> 17 | 1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * AMD Pink Sardine ACP PCI Driver 4 * 5 * Copyright 2022 Advanced Micro Devices, Inc. 6 */ 7 8#include <linux/pci.h> 9#include <linux/module.h> 10#include <linux/io.h> 11#include <linux/delay.h> 12#include <linux/platform_device.h> 13#include <linux/acpi.h> 14#include <linux/interrupt.h> 15#include <sound/pcm_params.h> 16#include <linux/pm_runtime.h> 17 |
18#include "acp62.h" | 18#include "acp63.h" |
19 | 19 |
20struct acp62_dev_data { 21 void __iomem *acp62_base; | 20struct acp63_dev_data { 21 void __iomem *acp63_base; |
22 struct resource *res; | 22 struct resource *res; |
23 bool acp62_audio_mode; | 23 bool acp63_audio_mode; |
24 struct platform_device *pdev[ACP6x_DEVS]; 25}; 26 | 24 struct platform_device *pdev[ACP6x_DEVS]; 25}; 26 |
27static int acp62_power_on(void __iomem *acp_base) | 27static int acp63_power_on(void __iomem *acp_base) |
28{ 29 u32 val; 30 int timeout; 31 | 28{ 29 u32 val; 30 int timeout; 31 |
32 val = acp62_readl(acp_base + ACP_PGFSM_STATUS); | 32 val = acp63_readl(acp_base + ACP_PGFSM_STATUS); |
33 34 if (!val) 35 return val; 36 37 if ((val & ACP_PGFSM_STATUS_MASK) != ACP_POWER_ON_IN_PROGRESS) | 33 34 if (!val) 35 return val; 36 37 if ((val & ACP_PGFSM_STATUS_MASK) != ACP_POWER_ON_IN_PROGRESS) |
38 acp62_writel(ACP_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL); | 38 acp63_writel(ACP_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL); |
39 timeout = 0; 40 while (++timeout < 500) { | 39 timeout = 0; 40 while (++timeout < 500) { |
41 val = acp62_readl(acp_base + ACP_PGFSM_STATUS); | 41 val = acp63_readl(acp_base + ACP_PGFSM_STATUS); |
42 if (!val) 43 return 0; 44 udelay(1); 45 } 46 return -ETIMEDOUT; 47} 48 | 42 if (!val) 43 return 0; 44 udelay(1); 45 } 46 return -ETIMEDOUT; 47} 48 |
49static int acp62_reset(void __iomem *acp_base) | 49static int acp63_reset(void __iomem *acp_base) |
50{ 51 u32 val; 52 int timeout; 53 | 50{ 51 u32 val; 52 int timeout; 53 |
54 acp62_writel(1, acp_base + ACP_SOFT_RESET); | 54 acp63_writel(1, acp_base + ACP_SOFT_RESET); |
55 timeout = 0; 56 while (++timeout < 500) { | 55 timeout = 0; 56 while (++timeout < 500) { |
57 val = acp62_readl(acp_base + ACP_SOFT_RESET); | 57 val = acp63_readl(acp_base + ACP_SOFT_RESET); |
58 if (val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK) 59 break; 60 cpu_relax(); 61 } | 58 if (val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK) 59 break; 60 cpu_relax(); 61 } |
62 acp62_writel(0, acp_base + ACP_SOFT_RESET); | 62 acp63_writel(0, acp_base + ACP_SOFT_RESET); |
63 timeout = 0; 64 while (++timeout < 500) { | 63 timeout = 0; 64 while (++timeout < 500) { |
65 val = acp62_readl(acp_base + ACP_SOFT_RESET); | 65 val = acp63_readl(acp_base + ACP_SOFT_RESET); |
66 if (!val) 67 return 0; 68 cpu_relax(); 69 } 70 return -ETIMEDOUT; 71} 72 | 66 if (!val) 67 return 0; 68 cpu_relax(); 69 } 70 return -ETIMEDOUT; 71} 72 |
73static void acp62_enable_interrupts(void __iomem *acp_base) | 73static void acp63_enable_interrupts(void __iomem *acp_base) |
74{ | 74{ |
75 acp62_writel(1, acp_base + ACP_EXTERNAL_INTR_ENB); | 75 acp63_writel(1, acp_base + ACP_EXTERNAL_INTR_ENB); |
76} 77 | 76} 77 |
78static void acp62_disable_interrupts(void __iomem *acp_base) | 78static void acp63_disable_interrupts(void __iomem *acp_base) |
79{ | 79{ |
80 acp62_writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp_base + | 80 acp63_writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp_base + |
81 ACP_EXTERNAL_INTR_STAT); | 81 ACP_EXTERNAL_INTR_STAT); |
82 acp62_writel(0, acp_base + ACP_EXTERNAL_INTR_CNTL); 83 acp62_writel(0, acp_base + ACP_EXTERNAL_INTR_ENB); | 82 acp63_writel(0, acp_base + ACP_EXTERNAL_INTR_CNTL); 83 acp63_writel(0, acp_base + ACP_EXTERNAL_INTR_ENB); |
84} 85 | 84} 85 |
86static int acp62_init(void __iomem *acp_base, struct device *dev) | 86static int acp63_init(void __iomem *acp_base, struct device *dev) |
87{ 88 int ret; 89 | 87{ 88 int ret; 89 |
90 ret = acp62_power_on(acp_base); | 90 ret = acp63_power_on(acp_base); |
91 if (ret) { 92 dev_err(dev, "ACP power on failed\n"); 93 return ret; 94 } | 91 if (ret) { 92 dev_err(dev, "ACP power on failed\n"); 93 return ret; 94 } |
95 acp62_writel(0x01, acp_base + ACP_CONTROL); 96 ret = acp62_reset(acp_base); | 95 acp63_writel(0x01, acp_base + ACP_CONTROL); 96 ret = acp63_reset(acp_base); |
97 if (ret) { 98 dev_err(dev, "ACP reset failed\n"); 99 return ret; 100 } | 97 if (ret) { 98 dev_err(dev, "ACP reset failed\n"); 99 return ret; 100 } |
101 acp62_writel(0x03, acp_base + ACP_CLKMUX_SEL); 102 acp62_enable_interrupts(acp_base); | 101 acp63_writel(0x03, acp_base + ACP_CLKMUX_SEL); 102 acp63_enable_interrupts(acp_base); |
103 return 0; 104} 105 | 103 return 0; 104} 105 |
106static int acp62_deinit(void __iomem *acp_base, struct device *dev) | 106static int acp63_deinit(void __iomem *acp_base, struct device *dev) |
107{ 108 int ret; 109 | 107{ 108 int ret; 109 |
110 acp62_disable_interrupts(acp_base); 111 ret = acp62_reset(acp_base); | 110 acp63_disable_interrupts(acp_base); 111 ret = acp63_reset(acp_base); |
112 if (ret) { 113 dev_err(dev, "ACP reset failed\n"); 114 return ret; 115 } | 112 if (ret) { 113 dev_err(dev, "ACP reset failed\n"); 114 return ret; 115 } |
116 acp62_writel(0, acp_base + ACP_CLKMUX_SEL); 117 acp62_writel(0, acp_base + ACP_CONTROL); | 116 acp63_writel(0, acp_base + ACP_CLKMUX_SEL); 117 acp63_writel(0, acp_base + ACP_CONTROL); |
118 return 0; 119} 120 | 118 return 0; 119} 120 |
121static irqreturn_t acp62_irq_handler(int irq, void *dev_id) | 121static irqreturn_t acp63_irq_handler(int irq, void *dev_id) |
122{ | 122{ |
123 struct acp62_dev_data *adata; | 123 struct acp63_dev_data *adata; |
124 struct pdm_dev_data *ps_pdm_data; 125 u32 val; 126 127 adata = dev_id; 128 if (!adata) 129 return IRQ_NONE; 130 | 124 struct pdm_dev_data *ps_pdm_data; 125 u32 val; 126 127 adata = dev_id; 128 if (!adata) 129 return IRQ_NONE; 130 |
131 val = acp62_readl(adata->acp62_base + ACP_EXTERNAL_INTR_STAT); | 131 val = acp63_readl(adata->acp63_base + ACP_EXTERNAL_INTR_STAT); |
132 if (val & BIT(PDM_DMA_STAT)) { 133 ps_pdm_data = dev_get_drvdata(&adata->pdev[0]->dev); | 132 if (val & BIT(PDM_DMA_STAT)) { 133 ps_pdm_data = dev_get_drvdata(&adata->pdev[0]->dev); |
134 acp62_writel(BIT(PDM_DMA_STAT), adata->acp62_base + ACP_EXTERNAL_INTR_STAT); | 134 acp63_writel(BIT(PDM_DMA_STAT), adata->acp63_base + ACP_EXTERNAL_INTR_STAT); |
135 if (ps_pdm_data->capture_stream) 136 snd_pcm_period_elapsed(ps_pdm_data->capture_stream); 137 return IRQ_HANDLED; 138 } 139 return IRQ_NONE; 140} 141 | 135 if (ps_pdm_data->capture_stream) 136 snd_pcm_period_elapsed(ps_pdm_data->capture_stream); 137 return IRQ_HANDLED; 138 } 139 return IRQ_NONE; 140} 141 |
142static int snd_acp62_probe(struct pci_dev *pci, | 142static int snd_acp63_probe(struct pci_dev *pci, |
143 const struct pci_device_id *pci_id) 144{ | 143 const struct pci_device_id *pci_id) 144{ |
145 struct acp62_dev_data *adata; | 145 struct acp63_dev_data *adata; |
146 struct platform_device_info pdevinfo[ACP6x_DEVS]; 147 int index, ret; 148 int val = 0x00; 149 struct acpi_device *adev; 150 const union acpi_object *obj; 151 u32 addr; 152 unsigned int irqflags; 153 154 irqflags = IRQF_SHARED; 155 /* Pink Sardine device check */ 156 switch (pci->revision) { 157 case 0x63: 158 break; 159 default: | 146 struct platform_device_info pdevinfo[ACP6x_DEVS]; 147 int index, ret; 148 int val = 0x00; 149 struct acpi_device *adev; 150 const union acpi_object *obj; 151 u32 addr; 152 unsigned int irqflags; 153 154 irqflags = IRQF_SHARED; 155 /* Pink Sardine device check */ 156 switch (pci->revision) { 157 case 0x63: 158 break; 159 default: |
160 dev_dbg(&pci->dev, "acp62 pci device not found\n"); | 160 dev_dbg(&pci->dev, "acp63 pci device not found\n"); |
161 return -ENODEV; 162 } 163 if (pci_enable_device(pci)) { 164 dev_err(&pci->dev, "pci_enable_device failed\n"); 165 return -ENODEV; 166 } 167 168 ret = pci_request_regions(pci, "AMD ACP6.2 audio"); 169 if (ret < 0) { 170 dev_err(&pci->dev, "pci_request_regions failed\n"); 171 goto disable_pci; 172 } | 161 return -ENODEV; 162 } 163 if (pci_enable_device(pci)) { 164 dev_err(&pci->dev, "pci_enable_device failed\n"); 165 return -ENODEV; 166 } 167 168 ret = pci_request_regions(pci, "AMD ACP6.2 audio"); 169 if (ret < 0) { 170 dev_err(&pci->dev, "pci_request_regions failed\n"); 171 goto disable_pci; 172 } |
173 adata = devm_kzalloc(&pci->dev, sizeof(struct acp62_dev_data), | 173 adata = devm_kzalloc(&pci->dev, sizeof(struct acp63_dev_data), |
174 GFP_KERNEL); 175 if (!adata) { 176 ret = -ENOMEM; 177 goto release_regions; 178 } 179 180 addr = pci_resource_start(pci, 0); | 174 GFP_KERNEL); 175 if (!adata) { 176 ret = -ENOMEM; 177 goto release_regions; 178 } 179 180 addr = pci_resource_start(pci, 0); |
181 adata->acp62_base = devm_ioremap(&pci->dev, addr, | 181 adata->acp63_base = devm_ioremap(&pci->dev, addr, |
182 pci_resource_len(pci, 0)); | 182 pci_resource_len(pci, 0)); |
183 if (!adata->acp62_base) { | 183 if (!adata->acp63_base) { |
184 ret = -ENOMEM; 185 goto release_regions; 186 } 187 pci_set_master(pci); 188 pci_set_drvdata(pci, adata); | 184 ret = -ENOMEM; 185 goto release_regions; 186 } 187 pci_set_master(pci); 188 pci_set_drvdata(pci, adata); |
189 ret = acp62_init(adata->acp62_base, &pci->dev); | 189 ret = acp63_init(adata->acp63_base, &pci->dev); |
190 if (ret) 191 goto release_regions; | 190 if (ret) 191 goto release_regions; |
192 val = acp62_readl(adata->acp62_base + ACP_PIN_CONFIG); | 192 val = acp63_readl(adata->acp63_base + ACP_PIN_CONFIG); |
193 switch (val) { 194 case ACP_CONFIG_0: 195 case ACP_CONFIG_1: 196 case ACP_CONFIG_2: 197 case ACP_CONFIG_3: 198 case ACP_CONFIG_9: 199 case ACP_CONFIG_15: 200 dev_info(&pci->dev, "Audio Mode %d\n", val); --- 14 unchanged lines hidden (view full) --- 215 ret = -ENOMEM; 216 goto de_init; 217 } 218 219 adata->res->name = "acp_iomem"; 220 adata->res->flags = IORESOURCE_MEM; 221 adata->res->start = addr; 222 adata->res->end = addr + (ACP6x_REG_END - ACP6x_REG_START); | 193 switch (val) { 194 case ACP_CONFIG_0: 195 case ACP_CONFIG_1: 196 case ACP_CONFIG_2: 197 case ACP_CONFIG_3: 198 case ACP_CONFIG_9: 199 case ACP_CONFIG_15: 200 dev_info(&pci->dev, "Audio Mode %d\n", val); --- 14 unchanged lines hidden (view full) --- 215 ret = -ENOMEM; 216 goto de_init; 217 } 218 219 adata->res->name = "acp_iomem"; 220 adata->res->flags = IORESOURCE_MEM; 221 adata->res->start = addr; 222 adata->res->end = addr + (ACP6x_REG_END - ACP6x_REG_START); |
223 adata->acp62_audio_mode = ACP6x_PDM_MODE; | 223 adata->acp63_audio_mode = ACP6x_PDM_MODE; |
224 225 memset(&pdevinfo, 0, sizeof(pdevinfo)); 226 pdevinfo[0].name = "acp_ps_pdm_dma"; 227 pdevinfo[0].id = 0; 228 pdevinfo[0].parent = &pci->dev; 229 pdevinfo[0].num_res = 1; 230 pdevinfo[0].res = adata->res; 231 --- 11 unchanged lines hidden (view full) --- 243 244 if (IS_ERR(adata->pdev[index])) { 245 dev_err(&pci->dev, 246 "cannot register %s device\n", 247 pdevinfo[index].name); 248 ret = PTR_ERR(adata->pdev[index]); 249 goto unregister_devs; 250 } | 224 225 memset(&pdevinfo, 0, sizeof(pdevinfo)); 226 pdevinfo[0].name = "acp_ps_pdm_dma"; 227 pdevinfo[0].id = 0; 228 pdevinfo[0].parent = &pci->dev; 229 pdevinfo[0].num_res = 1; 230 pdevinfo[0].res = adata->res; 231 --- 11 unchanged lines hidden (view full) --- 243 244 if (IS_ERR(adata->pdev[index])) { 245 dev_err(&pci->dev, 246 "cannot register %s device\n", 247 pdevinfo[index].name); 248 ret = PTR_ERR(adata->pdev[index]); 249 goto unregister_devs; 250 } |
251 ret = devm_request_irq(&pci->dev, pci->irq, acp62_irq_handler, | 251 ret = devm_request_irq(&pci->dev, pci->irq, acp63_irq_handler, |
252 irqflags, "ACP_PCI_IRQ", adata); 253 if (ret) { 254 dev_err(&pci->dev, "ACP PCI IRQ request failed\n"); 255 goto unregister_devs; 256 } 257 } 258 } 259 break; 260 } 261 pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS); 262 pm_runtime_use_autosuspend(&pci->dev); 263 pm_runtime_put_noidle(&pci->dev); 264 pm_runtime_allow(&pci->dev); 265 return 0; 266unregister_devs: 267 for (--index; index >= 0; index--) 268 platform_device_unregister(adata->pdev[index]); 269de_init: | 252 irqflags, "ACP_PCI_IRQ", adata); 253 if (ret) { 254 dev_err(&pci->dev, "ACP PCI IRQ request failed\n"); 255 goto unregister_devs; 256 } 257 } 258 } 259 break; 260 } 261 pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS); 262 pm_runtime_use_autosuspend(&pci->dev); 263 pm_runtime_put_noidle(&pci->dev); 264 pm_runtime_allow(&pci->dev); 265 return 0; 266unregister_devs: 267 for (--index; index >= 0; index--) 268 platform_device_unregister(adata->pdev[index]); 269de_init: |
270 if (acp62_deinit(adata->acp62_base, &pci->dev)) | 270 if (acp63_deinit(adata->acp63_base, &pci->dev)) |
271 dev_err(&pci->dev, "ACP de-init failed\n"); 272release_regions: 273 pci_release_regions(pci); 274disable_pci: 275 pci_disable_device(pci); 276 277 return ret; 278} 279 | 271 dev_err(&pci->dev, "ACP de-init failed\n"); 272release_regions: 273 pci_release_regions(pci); 274disable_pci: 275 pci_disable_device(pci); 276 277 return ret; 278} 279 |
280static int __maybe_unused snd_acp62_suspend(struct device *dev) | 280static int __maybe_unused snd_acp63_suspend(struct device *dev) |
281{ | 281{ |
282 struct acp62_dev_data *adata; | 282 struct acp63_dev_data *adata; |
283 int ret; 284 285 adata = dev_get_drvdata(dev); | 283 int ret; 284 285 adata = dev_get_drvdata(dev); |
286 ret = acp62_deinit(adata->acp62_base, dev); | 286 ret = acp63_deinit(adata->acp63_base, dev); |
287 if (ret) 288 dev_err(dev, "ACP de-init failed\n"); 289 return ret; 290} 291 | 287 if (ret) 288 dev_err(dev, "ACP de-init failed\n"); 289 return ret; 290} 291 |
292static int __maybe_unused snd_acp62_resume(struct device *dev) | 292static int __maybe_unused snd_acp63_resume(struct device *dev) |
293{ | 293{ |
294 struct acp62_dev_data *adata; | 294 struct acp63_dev_data *adata; |
295 int ret; 296 297 adata = dev_get_drvdata(dev); | 295 int ret; 296 297 adata = dev_get_drvdata(dev); |
298 ret = acp62_init(adata->acp62_base, dev); | 298 ret = acp63_init(adata->acp63_base, dev); |
299 if (ret) 300 dev_err(dev, "ACP init failed\n"); 301 return ret; 302} 303 | 299 if (ret) 300 dev_err(dev, "ACP init failed\n"); 301 return ret; 302} 303 |
304static const struct dev_pm_ops acp62_pm_ops = { 305 SET_RUNTIME_PM_OPS(snd_acp62_suspend, snd_acp62_resume, NULL) 306 SET_SYSTEM_SLEEP_PM_OPS(snd_acp62_suspend, snd_acp62_resume) | 304static const struct dev_pm_ops acp63_pm_ops = { 305 SET_RUNTIME_PM_OPS(snd_acp63_suspend, snd_acp63_resume, NULL) 306 SET_SYSTEM_SLEEP_PM_OPS(snd_acp63_suspend, snd_acp63_resume) |
307}; 308 | 307}; 308 |
309static void snd_acp62_remove(struct pci_dev *pci) | 309static void snd_acp63_remove(struct pci_dev *pci) |
310{ | 310{ |
311 struct acp62_dev_data *adata; | 311 struct acp63_dev_data *adata; |
312 int ret, index; 313 314 adata = pci_get_drvdata(pci); | 312 int ret, index; 313 314 adata = pci_get_drvdata(pci); |
315 if (adata->acp62_audio_mode == ACP6x_PDM_MODE) { | 315 if (adata->acp63_audio_mode == ACP6x_PDM_MODE) { |
316 for (index = 0; index < ACP6x_DEVS; index++) 317 platform_device_unregister(adata->pdev[index]); 318 } | 316 for (index = 0; index < ACP6x_DEVS; index++) 317 platform_device_unregister(adata->pdev[index]); 318 } |
319 ret = acp62_deinit(adata->acp62_base, &pci->dev); | 319 ret = acp63_deinit(adata->acp63_base, &pci->dev); |
320 if (ret) 321 dev_err(&pci->dev, "ACP de-init failed\n"); 322 pm_runtime_forbid(&pci->dev); 323 pm_runtime_get_noresume(&pci->dev); 324 pci_release_regions(pci); 325 pci_disable_device(pci); 326} 327 | 320 if (ret) 321 dev_err(&pci->dev, "ACP de-init failed\n"); 322 pm_runtime_forbid(&pci->dev); 323 pm_runtime_get_noresume(&pci->dev); 324 pci_release_regions(pci); 325 pci_disable_device(pci); 326} 327 |
328static const struct pci_device_id snd_acp62_ids[] = { | 328static const struct pci_device_id snd_acp63_ids[] = { |
329 { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_DEVICE_ID), 330 .class = PCI_CLASS_MULTIMEDIA_OTHER << 8, 331 .class_mask = 0xffffff }, 332 { 0, }, 333}; | 329 { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_DEVICE_ID), 330 .class = PCI_CLASS_MULTIMEDIA_OTHER << 8, 331 .class_mask = 0xffffff }, 332 { 0, }, 333}; |
334MODULE_DEVICE_TABLE(pci, snd_acp62_ids); | 334MODULE_DEVICE_TABLE(pci, snd_acp63_ids); |
335 | 335 |
336static struct pci_driver ps_acp62_driver = { | 336static struct pci_driver ps_acp63_driver = { |
337 .name = KBUILD_MODNAME, | 337 .name = KBUILD_MODNAME, |
338 .id_table = snd_acp62_ids, 339 .probe = snd_acp62_probe, 340 .remove = snd_acp62_remove, | 338 .id_table = snd_acp63_ids, 339 .probe = snd_acp63_probe, 340 .remove = snd_acp63_remove, |
341 .driver = { | 341 .driver = { |
342 .pm = &acp62_pm_ops, | 342 .pm = &acp63_pm_ops, |
343 } 344}; 345 | 343 } 344}; 345 |
346module_pci_driver(ps_acp62_driver); | 346module_pci_driver(ps_acp63_driver); |
347 348MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); 349MODULE_AUTHOR("Syed.SabaKareem@amd.com"); 350MODULE_DESCRIPTION("AMD ACP Pink Sardine PCI driver"); 351MODULE_LICENSE("GPL v2"); | 347 348MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); 349MODULE_AUTHOR("Syed.SabaKareem@amd.com"); 350MODULE_DESCRIPTION("AMD ACP Pink Sardine PCI driver"); 351MODULE_LICENSE("GPL v2"); |