pci-acp5x.c (4a7151c9688cc166ff6bf5a1a00e3cee429a2f11) pci-acp5x.c (5d9ee88a10e854c5c43e0ae6b1bb0ff454cd45d1)
1// SPDX-License-Identifier: GPL-2.0+
2//
3// AMD Vangogh ACP PCI Driver
4//
5// Copyright (C) 2021 Advanced Micro Devices, Inc. All rights reserved.
6
7#include <linux/pci.h>
8#include <linux/module.h>
9#include <linux/io.h>
1// SPDX-License-Identifier: GPL-2.0+
2//
3// AMD Vangogh ACP PCI Driver
4//
5// Copyright (C) 2021 Advanced Micro Devices, Inc. All rights reserved.
6
7#include <linux/pci.h>
8#include <linux/module.h>
9#include <linux/io.h>
10#include <linux/delay.h>
10
11#include "acp5x.h"
12
13struct acp5x_dev_data {
14 void __iomem *acp5x_base;
15};
16
11
12#include "acp5x.h"
13
14struct acp5x_dev_data {
15 void __iomem *acp5x_base;
16};
17
18static int acp5x_power_on(void __iomem *acp5x_base)
19{
20 u32 val;
21 int timeout;
22
23 val = acp_readl(acp5x_base + ACP_PGFSM_STATUS);
24
25 if (val == 0)
26 return val;
27
28 if ((val & ACP_PGFSM_STATUS_MASK) !=
29 ACP_POWER_ON_IN_PROGRESS)
30 acp_writel(ACP_PGFSM_CNTL_POWER_ON_MASK,
31 acp5x_base + ACP_PGFSM_CONTROL);
32 timeout = 0;
33 while (++timeout < 500) {
34 val = acp_readl(acp5x_base + ACP_PGFSM_STATUS);
35 if ((val & ACP_PGFSM_STATUS_MASK) == ACP_POWERED_ON)
36 return 0;
37 udelay(1);
38 }
39 return -ETIMEDOUT;
40}
41
42static int acp5x_reset(void __iomem *acp5x_base)
43{
44 u32 val;
45 int timeout;
46
47 acp_writel(1, acp5x_base + ACP_SOFT_RESET);
48 timeout = 0;
49 while (++timeout < 500) {
50 val = acp_readl(acp5x_base + ACP_SOFT_RESET);
51 if (val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK)
52 break;
53 cpu_relax();
54 }
55 acp_writel(0, acp5x_base + ACP_SOFT_RESET);
56 timeout = 0;
57 while (++timeout < 500) {
58 val = acp_readl(acp5x_base + ACP_SOFT_RESET);
59 if (!val)
60 return 0;
61 cpu_relax();
62 }
63 return -ETIMEDOUT;
64}
65
66static void acp5x_enable_interrupts(void __iomem *acp5x_base)
67{
68 acp_writel(0x01, acp5x_base + ACP_EXTERNAL_INTR_ENB);
69}
70
71static void acp5x_disable_interrupts(void __iomem *acp5x_base)
72{
73 acp_writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp5x_base +
74 ACP_EXTERNAL_INTR_STAT);
75 acp_writel(0x00, acp5x_base + ACP_EXTERNAL_INTR_CNTL);
76 acp_writel(0x00, acp5x_base + ACP_EXTERNAL_INTR_ENB);
77}
78
79static int acp5x_init(void __iomem *acp5x_base)
80{
81 int ret;
82
83 /* power on */
84 ret = acp5x_power_on(acp5x_base);
85 if (ret) {
86 pr_err("ACP5x power on failed\n");
87 return ret;
88 }
89 /* Reset */
90 ret = acp5x_reset(acp5x_base);
91 if (ret) {
92 pr_err("ACP5x reset failed\n");
93 return ret;
94 }
95 acp5x_enable_interrupts(acp5x_base);
96 return 0;
97}
98
99static int acp5x_deinit(void __iomem *acp5x_base)
100{
101 int ret;
102
103 acp5x_disable_interrupts(acp5x_base);
104 /* Reset */
105 ret = acp5x_reset(acp5x_base);
106 if (ret) {
107 pr_err("ACP5x reset failed\n");
108 return ret;
109 }
110 return 0;
111}
112
17static int snd_acp5x_probe(struct pci_dev *pci,
18 const struct pci_device_id *pci_id)
19{
20 struct acp5x_dev_data *adata;
21 int ret;
22 u32 addr;
23
24 if (pci->revision != 0x50)

--- 20 unchanged lines hidden (view full) ---

45 adata->acp5x_base = devm_ioremap(&pci->dev, addr,
46 pci_resource_len(pci, 0));
47 if (!adata->acp5x_base) {
48 ret = -ENOMEM;
49 goto release_regions;
50 }
51 pci_set_master(pci);
52 pci_set_drvdata(pci, adata);
113static int snd_acp5x_probe(struct pci_dev *pci,
114 const struct pci_device_id *pci_id)
115{
116 struct acp5x_dev_data *adata;
117 int ret;
118 u32 addr;
119
120 if (pci->revision != 0x50)

--- 20 unchanged lines hidden (view full) ---

141 adata->acp5x_base = devm_ioremap(&pci->dev, addr,
142 pci_resource_len(pci, 0));
143 if (!adata->acp5x_base) {
144 ret = -ENOMEM;
145 goto release_regions;
146 }
147 pci_set_master(pci);
148 pci_set_drvdata(pci, adata);
149 ret = acp5x_init(adata->acp5x_base);
150 if (ret)
151 goto release_regions;
53
54release_regions:
55 pci_release_regions(pci);
56disable_pci:
57 pci_disable_device(pci);
58
59 return ret;
60}
61
62static void snd_acp5x_remove(struct pci_dev *pci)
63{
152
153release_regions:
154 pci_release_regions(pci);
155disable_pci:
156 pci_disable_device(pci);
157
158 return ret;
159}
160
161static void snd_acp5x_remove(struct pci_dev *pci)
162{
163 struct acp5x_dev_data *adata;
164 int ret;
165
166 adata = pci_get_drvdata(pci);
167 ret = acp5x_deinit(adata->acp5x_base);
168 if (ret)
169 dev_err(&pci->dev, "ACP de-init failed\n");
64 pci_release_regions(pci);
65 pci_disable_device(pci);
66}
67
68static const struct pci_device_id snd_acp5x_ids[] = {
69 { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_DEVICE_ID),
70 .class = PCI_CLASS_MULTIMEDIA_OTHER << 8,
71 .class_mask = 0xffffff },

--- 16 unchanged lines hidden ---
170 pci_release_regions(pci);
171 pci_disable_device(pci);
172}
173
174static const struct pci_device_id snd_acp5x_ids[] = {
175 { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_DEVICE_ID),
176 .class = PCI_CLASS_MULTIMEDIA_OTHER << 8,
177 .class_mask = 0xffffff },

--- 16 unchanged lines hidden ---