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
];
24 static int acp3x_power_on(void __iomem
*acp3x_base
)
29 val
= rv_readl(acp3x_base
+ mmACP_PGFSM_STATUS
);
34 if (!((val
& ACP_PGFSM_STATUS_MASK
) ==
35 ACP_POWER_ON_IN_PROGRESS
))
36 rv_writel(ACP_PGFSM_CNTL_POWER_ON_MASK
,
37 acp3x_base
+ mmACP_PGFSM_CONTROL
);
39 while (++timeout
< 500) {
40 val
= rv_readl(acp3x_base
+ mmACP_PGFSM_STATUS
);
48 static int acp3x_power_off(void __iomem
*acp3x_base
)
53 rv_writel(ACP_PGFSM_CNTL_POWER_OFF_MASK
,
54 acp3x_base
+ mmACP_PGFSM_CONTROL
);
56 while (++timeout
< 500) {
57 val
= rv_readl(acp3x_base
+ mmACP_PGFSM_STATUS
);
58 if ((val
& ACP_PGFSM_STATUS_MASK
) == ACP_POWERED_OFF
)
65 static int acp3x_reset(void __iomem
*acp3x_base
)
70 rv_writel(1, acp3x_base
+ mmACP_SOFT_RESET
);
72 while (++timeout
< 500) {
73 val
= rv_readl(acp3x_base
+ mmACP_SOFT_RESET
);
74 if (val
& ACP3x_SOFT_RESET__SoftResetAudDone_MASK
)
78 rv_writel(0, acp3x_base
+ mmACP_SOFT_RESET
);
80 while (++timeout
< 500) {
81 val
= rv_readl(acp3x_base
+ mmACP_SOFT_RESET
);
89 static int acp3x_init(void __iomem
*acp3x_base
)
94 ret
= acp3x_power_on(acp3x_base
);
96 pr_err("ACP3x power on failed\n");
100 ret
= acp3x_reset(acp3x_base
);
102 pr_err("ACP3x reset failed\n");
108 static int acp3x_deinit(void __iomem
*acp3x_base
)
113 ret
= acp3x_reset(acp3x_base
);
115 pr_err("ACP3x reset failed\n");
119 ret
= acp3x_power_off(acp3x_base
);
121 pr_err("ACP3x power off failed\n");
127 static int snd_acp3x_probe(struct pci_dev
*pci
,
128 const struct pci_device_id
*pci_id
)
130 struct acp3x_dev_data
*adata
;
131 struct platform_device_info pdevinfo
[ACP3x_DEVS
];
132 unsigned int irqflags
;
136 if (pci_enable_device(pci
)) {
137 dev_err(&pci
->dev
, "pci_enable_device failed\n");
141 ret
= pci_request_regions(pci
, "AMD ACP3x audio");
143 dev_err(&pci
->dev
, "pci_request_regions failed\n");
147 adata
= devm_kzalloc(&pci
->dev
, sizeof(struct acp3x_dev_data
),
151 goto release_regions
;
154 /* check for msi interrupt support */
155 ret
= pci_enable_msi(pci
);
157 /* msi is not enabled */
158 irqflags
= IRQF_SHARED
;
163 addr
= pci_resource_start(pci
, 0);
164 adata
->acp3x_base
= devm_ioremap(&pci
->dev
, addr
,
165 pci_resource_len(pci
, 0));
166 if (!adata
->acp3x_base
) {
171 pci_set_drvdata(pci
, adata
);
172 ret
= acp3x_init(adata
->acp3x_base
);
176 val
= rv_readl(adata
->acp3x_base
+ mmACP_I2S_PIN_CONFIG
);
179 adata
->res
= devm_kzalloc(&pci
->dev
,
180 sizeof(struct resource
) * 4,
187 adata
->res
[0].name
= "acp3x_i2s_iomem";
188 adata
->res
[0].flags
= IORESOURCE_MEM
;
189 adata
->res
[0].start
= addr
;
190 adata
->res
[0].end
= addr
+ (ACP3x_REG_END
- ACP3x_REG_START
);
192 adata
->res
[1].name
= "acp3x_i2s_sp";
193 adata
->res
[1].flags
= IORESOURCE_MEM
;
194 adata
->res
[1].start
= addr
+ ACP3x_I2STDM_REG_START
;
195 adata
->res
[1].end
= addr
+ ACP3x_I2STDM_REG_END
;
197 adata
->res
[2].name
= "acp3x_i2s_bt";
198 adata
->res
[2].flags
= IORESOURCE_MEM
;
199 adata
->res
[2].start
= addr
+ ACP3x_BT_TDM_REG_START
;
200 adata
->res
[2].end
= addr
+ ACP3x_BT_TDM_REG_END
;
202 adata
->res
[3].name
= "acp3x_i2s_irq";
203 adata
->res
[3].flags
= IORESOURCE_IRQ
;
204 adata
->res
[3].start
= pci
->irq
;
205 adata
->res
[3].end
= adata
->res
[3].start
;
207 adata
->acp3x_audio_mode
= ACP3x_I2S_MODE
;
209 memset(&pdevinfo
, 0, sizeof(pdevinfo
));
210 pdevinfo
[0].name
= "acp3x_rv_i2s_dma";
212 pdevinfo
[0].parent
= &pci
->dev
;
213 pdevinfo
[0].num_res
= 4;
214 pdevinfo
[0].res
= &adata
->res
[0];
215 pdevinfo
[0].data
= &irqflags
;
216 pdevinfo
[0].size_data
= sizeof(irqflags
);
218 pdevinfo
[1].name
= "acp3x_i2s_playcap";
220 pdevinfo
[1].parent
= &pci
->dev
;
221 pdevinfo
[1].num_res
= 1;
222 pdevinfo
[1].res
= &adata
->res
[1];
224 pdevinfo
[2].name
= "acp3x_i2s_playcap";
226 pdevinfo
[2].parent
= &pci
->dev
;
227 pdevinfo
[2].num_res
= 1;
228 pdevinfo
[2].res
= &adata
->res
[1];
230 pdevinfo
[3].name
= "acp3x_i2s_playcap";
232 pdevinfo
[3].parent
= &pci
->dev
;
233 pdevinfo
[3].num_res
= 1;
234 pdevinfo
[3].res
= &adata
->res
[2];
235 for (i
= 0; i
< ACP3x_DEVS
; i
++) {
237 platform_device_register_full(&pdevinfo
[i
]);
238 if (IS_ERR(adata
->pdev
[i
])) {
239 dev_err(&pci
->dev
, "cannot register %s device\n",
241 ret
= PTR_ERR(adata
->pdev
[i
]);
242 goto unregister_devs
;
247 dev_err(&pci
->dev
, "Invalid ACP audio mode : %d\n", val
);
251 pm_runtime_set_autosuspend_delay(&pci
->dev
, 2000);
252 pm_runtime_use_autosuspend(&pci
->dev
);
253 pm_runtime_set_active(&pci
->dev
);
254 pm_runtime_put_noidle(&pci
->dev
);
255 pm_runtime_enable(&pci
->dev
);
256 pm_runtime_allow(&pci
->dev
);
261 for (i
= 0; i
< ACP3x_DEVS
; i
++)
262 platform_device_unregister(adata
->pdev
[i
]);
264 if (acp3x_deinit(adata
->acp3x_base
))
265 dev_err(&pci
->dev
, "ACP de-init failed\n");
267 pci_disable_msi(pci
);
269 pci_release_regions(pci
);
271 pci_disable_device(pci
);
276 static int snd_acp3x_suspend(struct device
*dev
)
279 struct acp3x_dev_data
*adata
;
281 adata
= dev_get_drvdata(dev
);
282 ret
= acp3x_deinit(adata
->acp3x_base
);
284 dev_err(dev
, "ACP de-init failed\n");
286 dev_dbg(dev
, "ACP de-initialized\n");
291 static int snd_acp3x_resume(struct device
*dev
)
294 struct acp3x_dev_data
*adata
;
296 adata
= dev_get_drvdata(dev
);
297 ret
= acp3x_init(adata
->acp3x_base
);
299 dev_err(dev
, "ACP init failed\n");
305 static const struct dev_pm_ops acp3x_pm
= {
306 .runtime_suspend
= snd_acp3x_suspend
,
307 .runtime_resume
= snd_acp3x_resume
,
308 .resume
= snd_acp3x_resume
,
311 static void snd_acp3x_remove(struct pci_dev
*pci
)
313 struct acp3x_dev_data
*adata
;
316 adata
= pci_get_drvdata(pci
);
317 if (adata
->acp3x_audio_mode
== ACP3x_I2S_MODE
) {
318 for (i
= 0; i
< ACP3x_DEVS
; i
++)
319 platform_device_unregister(adata
->pdev
[i
]);
321 ret
= acp3x_deinit(adata
->acp3x_base
);
323 dev_err(&pci
->dev
, "ACP de-init failed\n");
324 pm_runtime_disable(&pci
->dev
);
325 pm_runtime_get_noresume(&pci
->dev
);
326 pci_disable_msi(pci
);
327 pci_release_regions(pci
);
328 pci_disable_device(pci
);
331 static const struct pci_device_id snd_acp3x_ids
[] = {
332 { PCI_DEVICE(PCI_VENDOR_ID_AMD
, 0x15e2),
333 .class = PCI_CLASS_MULTIMEDIA_OTHER
<< 8,
334 .class_mask
= 0xffffff },
337 MODULE_DEVICE_TABLE(pci
, snd_acp3x_ids
);
339 static struct pci_driver acp3x_driver
= {
340 .name
= KBUILD_MODNAME
,
341 .id_table
= snd_acp3x_ids
,
342 .probe
= snd_acp3x_probe
,
343 .remove
= snd_acp3x_remove
,
349 module_pci_driver(acp3x_driver
);
351 MODULE_AUTHOR("Vishnuvardhanrao.Ravulapati@amd.com");
352 MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com");
353 MODULE_DESCRIPTION("AMD ACP3x PCI driver");
354 MODULE_LICENSE("GPL v2");