1 // SPDX-License-Identifier: GPL-2.0+
5 //Copyright 2016 Advanced Micro Devices, Inc.
8 #include <linux/module.h>
10 #include <linux/platform_device.h>
11 #include <linux/interrupt.h>
12 #include <linux/pm_runtime.h>
13 #include <linux/delay.h>
17 struct acp3x_dev_data
{
18 void __iomem
*acp3x_base
;
19 bool acp3x_audio_mode
;
21 struct platform_device
*pdev
[ACP3x_DEVS
];
25 static int acp3x_power_on(struct acp3x_dev_data
*adata
)
27 void __iomem
*acp3x_base
= adata
->acp3x_base
;
31 val
= rv_readl(acp3x_base
+ mmACP_PGFSM_STATUS
);
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
);
41 while (++timeout
< 500) {
42 val
= rv_readl(acp3x_base
+ mmACP_PGFSM_STATUS
);
44 /* ACP power On clears PME_EN.
45 * Restore the value to its prior state
47 rv_writel(adata
->pme_en
, acp3x_base
+ mmACP_PME_EN
);
55 static int acp3x_reset(void __iomem
*acp3x_base
)
60 rv_writel(1, acp3x_base
+ mmACP_SOFT_RESET
);
62 while (++timeout
< 500) {
63 val
= rv_readl(acp3x_base
+ mmACP_SOFT_RESET
);
64 if (val
& ACP3x_SOFT_RESET__SoftResetAudDone_MASK
)
68 rv_writel(0, acp3x_base
+ mmACP_SOFT_RESET
);
70 while (++timeout
< 500) {
71 val
= rv_readl(acp3x_base
+ mmACP_SOFT_RESET
);
79 static int acp3x_init(struct acp3x_dev_data
*adata
)
81 void __iomem
*acp3x_base
= adata
->acp3x_base
;
85 ret
= acp3x_power_on(adata
);
87 pr_err("ACP3x power on failed\n");
91 ret
= acp3x_reset(acp3x_base
);
93 pr_err("ACP3x reset failed\n");
99 static int acp3x_deinit(void __iomem
*acp3x_base
)
104 ret
= acp3x_reset(acp3x_base
);
106 pr_err("ACP3x reset failed\n");
112 static int snd_acp3x_probe(struct pci_dev
*pci
,
113 const struct pci_device_id
*pci_id
)
115 struct acp3x_dev_data
*adata
;
116 struct platform_device_info pdevinfo
[ACP3x_DEVS
];
117 unsigned int irqflags
;
121 /* Raven device detection */
122 if (pci
->revision
!= 0x00)
125 if (pci_enable_device(pci
)) {
126 dev_err(&pci
->dev
, "pci_enable_device failed\n");
130 ret
= pci_request_regions(pci
, "AMD ACP3x audio");
132 dev_err(&pci
->dev
, "pci_request_regions failed\n");
136 adata
= devm_kzalloc(&pci
->dev
, sizeof(struct acp3x_dev_data
),
140 goto release_regions
;
143 /* check for msi interrupt support */
144 ret
= pci_enable_msi(pci
);
146 /* msi is not enabled */
147 irqflags
= IRQF_SHARED
;
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
) {
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
);
167 val
= rv_readl(adata
->acp3x_base
+ mmACP_I2S_PIN_CONFIG
);
170 adata
->res
= devm_kzalloc(&pci
->dev
,
171 sizeof(struct resource
) * 4,
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
);
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
;
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
;
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
;
198 adata
->acp3x_audio_mode
= ACP3x_I2S_MODE
;
200 memset(&pdevinfo
, 0, sizeof(pdevinfo
));
201 pdevinfo
[0].name
= "acp3x_rv_i2s_dma";
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
);
209 pdevinfo
[1].name
= "acp3x_i2s_playcap";
211 pdevinfo
[1].parent
= &pci
->dev
;
212 pdevinfo
[1].num_res
= 1;
213 pdevinfo
[1].res
= &adata
->res
[1];
215 pdevinfo
[2].name
= "acp3x_i2s_playcap";
217 pdevinfo
[2].parent
= &pci
->dev
;
218 pdevinfo
[2].num_res
= 1;
219 pdevinfo
[2].res
= &adata
->res
[1];
221 pdevinfo
[3].name
= "acp3x_i2s_playcap";
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
++) {
228 platform_device_register_full(&pdevinfo
[i
]);
229 if (IS_ERR(adata
->pdev
[i
])) {
230 dev_err(&pci
->dev
, "cannot register %s device\n",
232 ret
= PTR_ERR(adata
->pdev
[i
]);
233 goto unregister_devs
;
238 dev_info(&pci
->dev
, "ACP audio mode : %d\n", val
);
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
);
249 for (i
= 0; i
< ACP3x_DEVS
; i
++)
250 platform_device_unregister(adata
->pdev
[i
]);
252 if (acp3x_deinit(adata
->acp3x_base
))
253 dev_err(&pci
->dev
, "ACP de-init failed\n");
255 pci_disable_msi(pci
);
257 pci_release_regions(pci
);
259 pci_disable_device(pci
);
264 static int snd_acp3x_suspend(struct device
*dev
)
267 struct acp3x_dev_data
*adata
;
269 adata
= dev_get_drvdata(dev
);
270 ret
= acp3x_deinit(adata
->acp3x_base
);
272 dev_err(dev
, "ACP de-init failed\n");
274 dev_dbg(dev
, "ACP de-initialized\n");
279 static int snd_acp3x_resume(struct device
*dev
)
282 struct acp3x_dev_data
*adata
;
284 adata
= dev_get_drvdata(dev
);
285 ret
= acp3x_init(adata
);
287 dev_err(dev
, "ACP init failed\n");
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
,
299 static void snd_acp3x_remove(struct pci_dev
*pci
)
301 struct acp3x_dev_data
*adata
;
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
]);
309 ret
= acp3x_deinit(adata
->acp3x_base
);
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
);
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 },
325 MODULE_DEVICE_TABLE(pci
, snd_acp3x_ids
);
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
,
337 module_pci_driver(acp3x_driver
);
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");