11eb2852eSVijendar Mukunda // SPDX-License-Identifier: GPL-2.0+
21eb2852eSVijendar Mukunda //
31eb2852eSVijendar Mukunda // AMD Renoir ACP PCI Driver
41eb2852eSVijendar Mukunda //
51eb2852eSVijendar Mukunda //Copyright 2020 Advanced Micro Devices, Inc.
61eb2852eSVijendar Mukunda
71eb2852eSVijendar Mukunda #include <linux/pci.h>
89e0d21e1SVijendar Mukunda #include <linux/acpi.h>
9718c406eSJaroslav Kysela #include <linux/dmi.h>
101eb2852eSVijendar Mukunda #include <linux/module.h>
111eb2852eSVijendar Mukunda #include <linux/io.h>
1285ded495SVijendar Mukunda #include <linux/delay.h>
1366c4f558SVijendar Mukunda #include <linux/platform_device.h>
1466c4f558SVijendar Mukunda #include <linux/interrupt.h>
15c346e768SVijendar Mukunda #include <linux/pm_runtime.h>
161eb2852eSVijendar Mukunda
171eb2852eSVijendar Mukunda #include "rn_acp3x.h"
181eb2852eSVijendar Mukunda
1985ded495SVijendar Mukunda static int acp_power_gating;
2085ded495SVijendar Mukunda module_param(acp_power_gating, int, 0644);
2185ded495SVijendar Mukunda MODULE_PARM_DESC(acp_power_gating, "Enable acp power gating");
2285ded495SVijendar Mukunda
237655e326SPierre-Louis Bossart /*
24718c406eSJaroslav Kysela * dmic_acpi_check = -1 - Use ACPI/DMI method to detect the DMIC hardware presence at runtime
25718c406eSJaroslav Kysela * = 0 - Skip the DMIC device creation and return probe failure
26718c406eSJaroslav Kysela * = 1 - Force DMIC support
279e0d21e1SVijendar Mukunda */
289e0d21e1SVijendar Mukunda static int dmic_acpi_check = ACP_DMIC_AUTO;
299e0d21e1SVijendar Mukunda module_param(dmic_acpi_check, bint, 0644);
30718c406eSJaroslav Kysela MODULE_PARM_DESC(dmic_acpi_check, "Digital microphone presence (-1=auto, 0=none, 1=force)");
319e0d21e1SVijendar Mukunda
321eb2852eSVijendar Mukunda struct acp_dev_data {
331eb2852eSVijendar Mukunda void __iomem *acp_base;
3466c4f558SVijendar Mukunda struct resource *res;
35b208c3bcSVijendar Mukunda struct platform_device *pdev[ACP_DEVS];
361eb2852eSVijendar Mukunda };
371eb2852eSVijendar Mukunda
rn_acp_power_on(void __iomem * acp_base)3885ded495SVijendar Mukunda static int rn_acp_power_on(void __iomem *acp_base)
3985ded495SVijendar Mukunda {
4085ded495SVijendar Mukunda u32 val;
4185ded495SVijendar Mukunda int timeout;
4285ded495SVijendar Mukunda
4385ded495SVijendar Mukunda val = rn_readl(acp_base + ACP_PGFSM_STATUS);
4485ded495SVijendar Mukunda
4585ded495SVijendar Mukunda if (val == 0)
4685ded495SVijendar Mukunda return val;
4785ded495SVijendar Mukunda
4885ded495SVijendar Mukunda if ((val & ACP_PGFSM_STATUS_MASK) !=
4985ded495SVijendar Mukunda ACP_POWER_ON_IN_PROGRESS)
5085ded495SVijendar Mukunda rn_writel(ACP_PGFSM_CNTL_POWER_ON_MASK,
5185ded495SVijendar Mukunda acp_base + ACP_PGFSM_CONTROL);
5285ded495SVijendar Mukunda timeout = 0;
5385ded495SVijendar Mukunda while (++timeout < 500) {
5485ded495SVijendar Mukunda val = rn_readl(acp_base + ACP_PGFSM_STATUS);
5585ded495SVijendar Mukunda if (!val)
5685ded495SVijendar Mukunda return 0;
5785ded495SVijendar Mukunda udelay(1);
5885ded495SVijendar Mukunda }
5985ded495SVijendar Mukunda return -ETIMEDOUT;
6085ded495SVijendar Mukunda }
6185ded495SVijendar Mukunda
rn_acp_power_off(void __iomem * acp_base)6285ded495SVijendar Mukunda static int rn_acp_power_off(void __iomem *acp_base)
6385ded495SVijendar Mukunda {
6485ded495SVijendar Mukunda u32 val;
6585ded495SVijendar Mukunda int timeout;
6685ded495SVijendar Mukunda
6785ded495SVijendar Mukunda rn_writel(ACP_PGFSM_CNTL_POWER_OFF_MASK,
6885ded495SVijendar Mukunda acp_base + ACP_PGFSM_CONTROL);
6985ded495SVijendar Mukunda timeout = 0;
7085ded495SVijendar Mukunda while (++timeout < 500) {
7185ded495SVijendar Mukunda val = rn_readl(acp_base + ACP_PGFSM_STATUS);
7285ded495SVijendar Mukunda if ((val & ACP_PGFSM_STATUS_MASK) == ACP_POWERED_OFF)
7385ded495SVijendar Mukunda return 0;
7485ded495SVijendar Mukunda udelay(1);
7585ded495SVijendar Mukunda }
7685ded495SVijendar Mukunda return -ETIMEDOUT;
7785ded495SVijendar Mukunda }
7885ded495SVijendar Mukunda
rn_acp_reset(void __iomem * acp_base)7985ded495SVijendar Mukunda static int rn_acp_reset(void __iomem *acp_base)
8085ded495SVijendar Mukunda {
8185ded495SVijendar Mukunda u32 val;
8285ded495SVijendar Mukunda int timeout;
8385ded495SVijendar Mukunda
8485ded495SVijendar Mukunda rn_writel(1, acp_base + ACP_SOFT_RESET);
8585ded495SVijendar Mukunda timeout = 0;
8685ded495SVijendar Mukunda while (++timeout < 500) {
8785ded495SVijendar Mukunda val = rn_readl(acp_base + ACP_SOFT_RESET);
8885ded495SVijendar Mukunda if (val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK)
8985ded495SVijendar Mukunda break;
9085ded495SVijendar Mukunda cpu_relax();
9185ded495SVijendar Mukunda }
9285ded495SVijendar Mukunda rn_writel(0, acp_base + ACP_SOFT_RESET);
9385ded495SVijendar Mukunda timeout = 0;
9485ded495SVijendar Mukunda while (++timeout < 500) {
9585ded495SVijendar Mukunda val = rn_readl(acp_base + ACP_SOFT_RESET);
9685ded495SVijendar Mukunda if (!val)
9785ded495SVijendar Mukunda return 0;
9885ded495SVijendar Mukunda cpu_relax();
9985ded495SVijendar Mukunda }
10085ded495SVijendar Mukunda return -ETIMEDOUT;
10185ded495SVijendar Mukunda }
10285ded495SVijendar Mukunda
rn_acp_enable_interrupts(void __iomem * acp_base)10385ded495SVijendar Mukunda static void rn_acp_enable_interrupts(void __iomem *acp_base)
10485ded495SVijendar Mukunda {
10585ded495SVijendar Mukunda u32 ext_intr_ctrl;
10685ded495SVijendar Mukunda
10785ded495SVijendar Mukunda rn_writel(0x01, acp_base + ACP_EXTERNAL_INTR_ENB);
10885ded495SVijendar Mukunda ext_intr_ctrl = rn_readl(acp_base + ACP_EXTERNAL_INTR_CNTL);
10985ded495SVijendar Mukunda ext_intr_ctrl |= ACP_ERROR_MASK;
11085ded495SVijendar Mukunda rn_writel(ext_intr_ctrl, acp_base + ACP_EXTERNAL_INTR_CNTL);
11185ded495SVijendar Mukunda }
11285ded495SVijendar Mukunda
rn_acp_disable_interrupts(void __iomem * acp_base)11385ded495SVijendar Mukunda static void rn_acp_disable_interrupts(void __iomem *acp_base)
11485ded495SVijendar Mukunda {
11585ded495SVijendar Mukunda rn_writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp_base +
11685ded495SVijendar Mukunda ACP_EXTERNAL_INTR_STAT);
11785ded495SVijendar Mukunda rn_writel(0x00, acp_base + ACP_EXTERNAL_INTR_ENB);
11885ded495SVijendar Mukunda }
11985ded495SVijendar Mukunda
rn_acp_init(void __iomem * acp_base)12085ded495SVijendar Mukunda static int rn_acp_init(void __iomem *acp_base)
12185ded495SVijendar Mukunda {
12285ded495SVijendar Mukunda int ret;
12385ded495SVijendar Mukunda
12485ded495SVijendar Mukunda /* power on */
12585ded495SVijendar Mukunda ret = rn_acp_power_on(acp_base);
12685ded495SVijendar Mukunda if (ret) {
12785ded495SVijendar Mukunda pr_err("ACP power on failed\n");
12885ded495SVijendar Mukunda return ret;
12985ded495SVijendar Mukunda }
13085ded495SVijendar Mukunda rn_writel(0x01, acp_base + ACP_CONTROL);
13185ded495SVijendar Mukunda /* Reset */
13285ded495SVijendar Mukunda ret = rn_acp_reset(acp_base);
13385ded495SVijendar Mukunda if (ret) {
13485ded495SVijendar Mukunda pr_err("ACP reset failed\n");
13585ded495SVijendar Mukunda return ret;
13685ded495SVijendar Mukunda }
13785ded495SVijendar Mukunda rn_writel(0x03, acp_base + ACP_CLKMUX_SEL);
13885ded495SVijendar Mukunda rn_acp_enable_interrupts(acp_base);
13985ded495SVijendar Mukunda return 0;
14085ded495SVijendar Mukunda }
14185ded495SVijendar Mukunda
rn_acp_deinit(void __iomem * acp_base)14285ded495SVijendar Mukunda static int rn_acp_deinit(void __iomem *acp_base)
14385ded495SVijendar Mukunda {
14485ded495SVijendar Mukunda int ret;
14585ded495SVijendar Mukunda
14685ded495SVijendar Mukunda rn_acp_disable_interrupts(acp_base);
14785ded495SVijendar Mukunda /* Reset */
14885ded495SVijendar Mukunda ret = rn_acp_reset(acp_base);
14985ded495SVijendar Mukunda if (ret) {
15085ded495SVijendar Mukunda pr_err("ACP reset failed\n");
15185ded495SVijendar Mukunda return ret;
15285ded495SVijendar Mukunda }
15385ded495SVijendar Mukunda rn_writel(0x00, acp_base + ACP_CLKMUX_SEL);
15485ded495SVijendar Mukunda rn_writel(0x00, acp_base + ACP_CONTROL);
15585ded495SVijendar Mukunda /* power off */
15685ded495SVijendar Mukunda if (acp_power_gating) {
15785ded495SVijendar Mukunda ret = rn_acp_power_off(acp_base);
15885ded495SVijendar Mukunda if (ret) {
15985ded495SVijendar Mukunda pr_err("ACP power off failed\n");
16085ded495SVijendar Mukunda return ret;
16185ded495SVijendar Mukunda }
16285ded495SVijendar Mukunda }
16385ded495SVijendar Mukunda return 0;
16485ded495SVijendar Mukunda }
16585ded495SVijendar Mukunda
166718c406eSJaroslav Kysela static const struct dmi_system_id rn_acp_quirk_table[] = {
167718c406eSJaroslav Kysela {
16840caffd6SJaroslav Kysela /* Lenovo IdeaPad S340-14API */
169718c406eSJaroslav Kysela .matches = {
170718c406eSJaroslav Kysela DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
17140caffd6SJaroslav Kysela DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "81NB"),
17240caffd6SJaroslav Kysela }
17340caffd6SJaroslav Kysela },
17440caffd6SJaroslav Kysela {
17540caffd6SJaroslav Kysela /* Lenovo IdeaPad Flex 5 14ARE05 */
17640caffd6SJaroslav Kysela .matches = {
17740caffd6SJaroslav Kysela DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
17840caffd6SJaroslav Kysela DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "81X2"),
17940caffd6SJaroslav Kysela }
18040caffd6SJaroslav Kysela },
18140caffd6SJaroslav Kysela {
18240caffd6SJaroslav Kysela /* Lenovo IdeaPad 5 15ARE05 */
18340caffd6SJaroslav Kysela .matches = {
18440caffd6SJaroslav Kysela DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
18540caffd6SJaroslav Kysela DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "81YQ"),
186718c406eSJaroslav Kysela }
187718c406eSJaroslav Kysela },
18827556599SJaroslav Kysela {
18927556599SJaroslav Kysela /* Lenovo ThinkPad E14 Gen 2 */
19027556599SJaroslav Kysela .matches = {
19127556599SJaroslav Kysela DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
19227556599SJaroslav Kysela DMI_EXACT_MATCH(DMI_BOARD_NAME, "20T6CTO1WW"),
19327556599SJaroslav Kysela }
19427556599SJaroslav Kysela },
1951f092d1cSJaroslav Kysela {
1961f092d1cSJaroslav Kysela /* Lenovo ThinkPad X395 */
1971f092d1cSJaroslav Kysela .matches = {
1981f092d1cSJaroslav Kysela DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
1991f092d1cSJaroslav Kysela DMI_EXACT_MATCH(DMI_BOARD_NAME, "20NLCTO1WW"),
2001f092d1cSJaroslav Kysela }
2011f092d1cSJaroslav Kysela },
202718c406eSJaroslav Kysela {}
203718c406eSJaroslav Kysela };
204718c406eSJaroslav Kysela
snd_rn_acp_probe(struct pci_dev * pci,const struct pci_device_id * pci_id)2051eb2852eSVijendar Mukunda static int snd_rn_acp_probe(struct pci_dev *pci,
2061eb2852eSVijendar Mukunda const struct pci_device_id *pci_id)
2071eb2852eSVijendar Mukunda {
2081eb2852eSVijendar Mukunda struct acp_dev_data *adata;
209b208c3bcSVijendar Mukunda struct platform_device_info pdevinfo[ACP_DEVS];
210ee3d1339SVijendar Mukunda #if defined(CONFIG_ACPI)
2119e0d21e1SVijendar Mukunda acpi_handle handle;
2129e0d21e1SVijendar Mukunda acpi_integer dmic_status;
213ee3d1339SVijendar Mukunda #endif
214718c406eSJaroslav Kysela const struct dmi_system_id *dmi_id;
215*2d7d9f36SAjit Kumar Pandey unsigned int irqflags, flag;
216b208c3bcSVijendar Mukunda int ret, index;
2171eb2852eSVijendar Mukunda u32 addr;
2181eb2852eSVijendar Mukunda
219*2d7d9f36SAjit Kumar Pandey /* Return if acp config flag is defined */
220*2d7d9f36SAjit Kumar Pandey flag = snd_amd_acp_find_config(pci);
221*2d7d9f36SAjit Kumar Pandey if (flag)
222*2d7d9f36SAjit Kumar Pandey return -ENODEV;
223*2d7d9f36SAjit Kumar Pandey
22455d8e6a8SJaroslav Kysela /* Renoir device check */
22555d8e6a8SJaroslav Kysela if (pci->revision != 0x01)
22655d8e6a8SJaroslav Kysela return -ENODEV;
22755d8e6a8SJaroslav Kysela
2281eb2852eSVijendar Mukunda if (pci_enable_device(pci)) {
2291eb2852eSVijendar Mukunda dev_err(&pci->dev, "pci_enable_device failed\n");
2301eb2852eSVijendar Mukunda return -ENODEV;
2311eb2852eSVijendar Mukunda }
2321eb2852eSVijendar Mukunda
2331eb2852eSVijendar Mukunda ret = pci_request_regions(pci, "AMD ACP3x audio");
2341eb2852eSVijendar Mukunda if (ret < 0) {
2351eb2852eSVijendar Mukunda dev_err(&pci->dev, "pci_request_regions failed\n");
2361eb2852eSVijendar Mukunda goto disable_pci;
2371eb2852eSVijendar Mukunda }
2381eb2852eSVijendar Mukunda
2391eb2852eSVijendar Mukunda adata = devm_kzalloc(&pci->dev, sizeof(struct acp_dev_data),
2401eb2852eSVijendar Mukunda GFP_KERNEL);
2411eb2852eSVijendar Mukunda if (!adata) {
2421eb2852eSVijendar Mukunda ret = -ENOMEM;
2431eb2852eSVijendar Mukunda goto release_regions;
2441eb2852eSVijendar Mukunda }
2451eb2852eSVijendar Mukunda
24666c4f558SVijendar Mukunda /* check for msi interrupt support */
24766c4f558SVijendar Mukunda ret = pci_enable_msi(pci);
24866c4f558SVijendar Mukunda if (ret)
24966c4f558SVijendar Mukunda /* msi is not enabled */
25066c4f558SVijendar Mukunda irqflags = IRQF_SHARED;
25166c4f558SVijendar Mukunda else
25266c4f558SVijendar Mukunda /* msi is enabled */
25366c4f558SVijendar Mukunda irqflags = 0;
25466c4f558SVijendar Mukunda
2551eb2852eSVijendar Mukunda addr = pci_resource_start(pci, 0);
2561eb2852eSVijendar Mukunda adata->acp_base = devm_ioremap(&pci->dev, addr,
2571eb2852eSVijendar Mukunda pci_resource_len(pci, 0));
2581eb2852eSVijendar Mukunda if (!adata->acp_base) {
2591eb2852eSVijendar Mukunda ret = -ENOMEM;
26066c4f558SVijendar Mukunda goto disable_msi;
2611eb2852eSVijendar Mukunda }
2621eb2852eSVijendar Mukunda pci_set_master(pci);
2631eb2852eSVijendar Mukunda pci_set_drvdata(pci, adata);
26485ded495SVijendar Mukunda ret = rn_acp_init(adata->acp_base);
26585ded495SVijendar Mukunda if (ret)
26666c4f558SVijendar Mukunda goto disable_msi;
26766c4f558SVijendar Mukunda
2689e0d21e1SVijendar Mukunda if (!dmic_acpi_check) {
2699e0d21e1SVijendar Mukunda ret = -ENODEV;
2709e0d21e1SVijendar Mukunda goto de_init;
2719e0d21e1SVijendar Mukunda } else if (dmic_acpi_check == ACP_DMIC_AUTO) {
27268d1abe1SVijendar Mukunda #if defined(CONFIG_ACPI)
2739e0d21e1SVijendar Mukunda handle = ACPI_HANDLE(&pci->dev);
2749e0d21e1SVijendar Mukunda ret = acpi_evaluate_integer(handle, "_WOV", NULL, &dmic_status);
2759e0d21e1SVijendar Mukunda if (ACPI_FAILURE(ret)) {
276ab5893fdSTakashi Iwai ret = -ENODEV;
2779e0d21e1SVijendar Mukunda goto de_init;
2789e0d21e1SVijendar Mukunda }
2799e0d21e1SVijendar Mukunda if (!dmic_status) {
2809e0d21e1SVijendar Mukunda ret = -ENODEV;
2819e0d21e1SVijendar Mukunda goto de_init;
2829e0d21e1SVijendar Mukunda }
28368d1abe1SVijendar Mukunda #endif
284718c406eSJaroslav Kysela dmi_id = dmi_first_match(rn_acp_quirk_table);
285718c406eSJaroslav Kysela if (dmi_id && !dmi_id->driver_data) {
286718c406eSJaroslav Kysela dev_info(&pci->dev, "ACPI settings override using DMI (ACP mic is not present)");
287718c406eSJaroslav Kysela ret = -ENODEV;
288718c406eSJaroslav Kysela goto de_init;
289718c406eSJaroslav Kysela }
2909e0d21e1SVijendar Mukunda }
2919e0d21e1SVijendar Mukunda
29266c4f558SVijendar Mukunda adata->res = devm_kzalloc(&pci->dev,
29366c4f558SVijendar Mukunda sizeof(struct resource) * 2,
29466c4f558SVijendar Mukunda GFP_KERNEL);
29566c4f558SVijendar Mukunda if (!adata->res) {
29666c4f558SVijendar Mukunda ret = -ENOMEM;
29766c4f558SVijendar Mukunda goto de_init;
29866c4f558SVijendar Mukunda }
29966c4f558SVijendar Mukunda
30066c4f558SVijendar Mukunda adata->res[0].name = "acp_pdm_iomem";
30166c4f558SVijendar Mukunda adata->res[0].flags = IORESOURCE_MEM;
30266c4f558SVijendar Mukunda adata->res[0].start = addr;
30366c4f558SVijendar Mukunda adata->res[0].end = addr + (ACP_REG_END - ACP_REG_START);
30466c4f558SVijendar Mukunda adata->res[1].name = "acp_pdm_irq";
30566c4f558SVijendar Mukunda adata->res[1].flags = IORESOURCE_IRQ;
30666c4f558SVijendar Mukunda adata->res[1].start = pci->irq;
30766c4f558SVijendar Mukunda adata->res[1].end = pci->irq;
30866c4f558SVijendar Mukunda
30966c4f558SVijendar Mukunda memset(&pdevinfo, 0, sizeof(pdevinfo));
310b208c3bcSVijendar Mukunda pdevinfo[0].name = "acp_rn_pdm_dma";
311b208c3bcSVijendar Mukunda pdevinfo[0].id = 0;
312b208c3bcSVijendar Mukunda pdevinfo[0].parent = &pci->dev;
313b208c3bcSVijendar Mukunda pdevinfo[0].num_res = 2;
314b208c3bcSVijendar Mukunda pdevinfo[0].res = adata->res;
315b208c3bcSVijendar Mukunda pdevinfo[0].data = &irqflags;
316b208c3bcSVijendar Mukunda pdevinfo[0].size_data = sizeof(irqflags);
31766c4f558SVijendar Mukunda
318b208c3bcSVijendar Mukunda pdevinfo[1].name = "dmic-codec";
319b208c3bcSVijendar Mukunda pdevinfo[1].id = 0;
320b208c3bcSVijendar Mukunda pdevinfo[1].parent = &pci->dev;
321b208c3bcSVijendar Mukunda pdevinfo[2].name = "acp_pdm_mach";
322b208c3bcSVijendar Mukunda pdevinfo[2].id = 0;
323b208c3bcSVijendar Mukunda pdevinfo[2].parent = &pci->dev;
324b208c3bcSVijendar Mukunda for (index = 0; index < ACP_DEVS; index++) {
325b208c3bcSVijendar Mukunda adata->pdev[index] =
326b208c3bcSVijendar Mukunda platform_device_register_full(&pdevinfo[index]);
327b208c3bcSVijendar Mukunda if (IS_ERR(adata->pdev[index])) {
32866c4f558SVijendar Mukunda dev_err(&pci->dev, "cannot register %s device\n",
329b208c3bcSVijendar Mukunda pdevinfo[index].name);
330b208c3bcSVijendar Mukunda ret = PTR_ERR(adata->pdev[index]);
33166c4f558SVijendar Mukunda goto unregister_devs;
33266c4f558SVijendar Mukunda }
333b208c3bcSVijendar Mukunda }
334c346e768SVijendar Mukunda pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS);
335c346e768SVijendar Mukunda pm_runtime_use_autosuspend(&pci->dev);
336c346e768SVijendar Mukunda pm_runtime_put_noidle(&pci->dev);
337c346e768SVijendar Mukunda pm_runtime_allow(&pci->dev);
3381eb2852eSVijendar Mukunda return 0;
3391eb2852eSVijendar Mukunda
34066c4f558SVijendar Mukunda unregister_devs:
341b208c3bcSVijendar Mukunda for (index = 0; index < ACP_DEVS; index++)
342b208c3bcSVijendar Mukunda platform_device_unregister(adata->pdev[index]);
34366c4f558SVijendar Mukunda de_init:
34466c4f558SVijendar Mukunda if (rn_acp_deinit(adata->acp_base))
34566c4f558SVijendar Mukunda dev_err(&pci->dev, "ACP de-init failed\n");
34666c4f558SVijendar Mukunda disable_msi:
34766c4f558SVijendar Mukunda pci_disable_msi(pci);
3481eb2852eSVijendar Mukunda release_regions:
3491eb2852eSVijendar Mukunda pci_release_regions(pci);
3501eb2852eSVijendar Mukunda disable_pci:
3511eb2852eSVijendar Mukunda pci_disable_device(pci);
3521eb2852eSVijendar Mukunda
3531eb2852eSVijendar Mukunda return ret;
3541eb2852eSVijendar Mukunda }
3551eb2852eSVijendar Mukunda
snd_rn_acp_suspend(struct device * dev)356c346e768SVijendar Mukunda static int snd_rn_acp_suspend(struct device *dev)
357c346e768SVijendar Mukunda {
358c346e768SVijendar Mukunda int ret;
359c346e768SVijendar Mukunda struct acp_dev_data *adata;
360c346e768SVijendar Mukunda
361c346e768SVijendar Mukunda adata = dev_get_drvdata(dev);
362c346e768SVijendar Mukunda ret = rn_acp_deinit(adata->acp_base);
363c346e768SVijendar Mukunda if (ret)
364c346e768SVijendar Mukunda dev_err(dev, "ACP de-init failed\n");
365c346e768SVijendar Mukunda else
366c346e768SVijendar Mukunda dev_dbg(dev, "ACP de-initialized\n");
367c346e768SVijendar Mukunda
368ce595586SVijendar Mukunda return ret;
369c346e768SVijendar Mukunda }
370c346e768SVijendar Mukunda
snd_rn_acp_resume(struct device * dev)371c346e768SVijendar Mukunda static int snd_rn_acp_resume(struct device *dev)
372c346e768SVijendar Mukunda {
373c346e768SVijendar Mukunda int ret;
374c346e768SVijendar Mukunda struct acp_dev_data *adata;
375c346e768SVijendar Mukunda
376c346e768SVijendar Mukunda adata = dev_get_drvdata(dev);
377c346e768SVijendar Mukunda ret = rn_acp_init(adata->acp_base);
378c346e768SVijendar Mukunda if (ret) {
379c346e768SVijendar Mukunda dev_err(dev, "ACP init failed\n");
380c346e768SVijendar Mukunda return ret;
381c346e768SVijendar Mukunda }
382c346e768SVijendar Mukunda return 0;
383c346e768SVijendar Mukunda }
384c346e768SVijendar Mukunda
385c346e768SVijendar Mukunda static const struct dev_pm_ops rn_acp_pm = {
386c346e768SVijendar Mukunda .runtime_suspend = snd_rn_acp_suspend,
387c346e768SVijendar Mukunda .runtime_resume = snd_rn_acp_resume,
388c346e768SVijendar Mukunda .suspend = snd_rn_acp_suspend,
389c346e768SVijendar Mukunda .resume = snd_rn_acp_resume,
390d00f541aSMario Limonciello .restore = snd_rn_acp_resume,
391d00f541aSMario Limonciello .poweroff = snd_rn_acp_suspend,
392c346e768SVijendar Mukunda };
393c346e768SVijendar Mukunda
snd_rn_acp_remove(struct pci_dev * pci)3941eb2852eSVijendar Mukunda static void snd_rn_acp_remove(struct pci_dev *pci)
3951eb2852eSVijendar Mukunda {
39685ded495SVijendar Mukunda struct acp_dev_data *adata;
397b208c3bcSVijendar Mukunda int ret, index;
39885ded495SVijendar Mukunda
39985ded495SVijendar Mukunda adata = pci_get_drvdata(pci);
400b208c3bcSVijendar Mukunda for (index = 0; index < ACP_DEVS; index++)
401b208c3bcSVijendar Mukunda platform_device_unregister(adata->pdev[index]);
40285ded495SVijendar Mukunda ret = rn_acp_deinit(adata->acp_base);
40385ded495SVijendar Mukunda if (ret)
40485ded495SVijendar Mukunda dev_err(&pci->dev, "ACP de-init failed\n");
405c346e768SVijendar Mukunda pm_runtime_forbid(&pci->dev);
406c346e768SVijendar Mukunda pm_runtime_get_noresume(&pci->dev);
4071eb2852eSVijendar Mukunda pci_disable_msi(pci);
4081eb2852eSVijendar Mukunda pci_release_regions(pci);
4091eb2852eSVijendar Mukunda pci_disable_device(pci);
4101eb2852eSVijendar Mukunda }
4111eb2852eSVijendar Mukunda
4121eb2852eSVijendar Mukunda static const struct pci_device_id snd_rn_acp_ids[] = {
4131eb2852eSVijendar Mukunda { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_DEVICE_ID),
4141eb2852eSVijendar Mukunda .class = PCI_CLASS_MULTIMEDIA_OTHER << 8,
4151eb2852eSVijendar Mukunda .class_mask = 0xffffff },
4161eb2852eSVijendar Mukunda { 0, },
4171eb2852eSVijendar Mukunda };
4181eb2852eSVijendar Mukunda MODULE_DEVICE_TABLE(pci, snd_rn_acp_ids);
4191eb2852eSVijendar Mukunda
4201eb2852eSVijendar Mukunda static struct pci_driver rn_acp_driver = {
4211eb2852eSVijendar Mukunda .name = KBUILD_MODNAME,
4221eb2852eSVijendar Mukunda .id_table = snd_rn_acp_ids,
4231eb2852eSVijendar Mukunda .probe = snd_rn_acp_probe,
4241eb2852eSVijendar Mukunda .remove = snd_rn_acp_remove,
425c346e768SVijendar Mukunda .driver = {
426c346e768SVijendar Mukunda .pm = &rn_acp_pm,
427c346e768SVijendar Mukunda }
4281eb2852eSVijendar Mukunda };
4291eb2852eSVijendar Mukunda
4301eb2852eSVijendar Mukunda module_pci_driver(rn_acp_driver);
4311eb2852eSVijendar Mukunda
4321eb2852eSVijendar Mukunda MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
4331eb2852eSVijendar Mukunda MODULE_DESCRIPTION("AMD ACP Renoir PCI driver");
4341eb2852eSVijendar Mukunda MODULE_LICENSE("GPL v2");
435