Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux...
[linux-2.6-microblaze.git] / sound / soc / amd / raven / pci-acp3x.c
1 // SPDX-License-Identifier: GPL-2.0+
2 //
3 // AMD ACP PCI Driver
4 //
5 //Copyright 2016 Advanced Micro Devices, Inc.
6
7 #include <linux/pci.h>
8 #include <linux/module.h>
9 #include <linux/io.h>
10 #include <linux/platform_device.h>
11 #include <linux/interrupt.h>
12 #include <linux/pm_runtime.h>
13 #include <linux/delay.h>
14
15 #include "acp3x.h"
16
17 struct acp3x_dev_data {
18         void __iomem *acp3x_base;
19         bool acp3x_audio_mode;
20         struct resource *res;
21         struct platform_device *pdev[ACP3x_DEVS];
22 };
23
24 static int acp3x_power_on(void __iomem *acp3x_base)
25 {
26         u32 val;
27         int timeout;
28
29         val = rv_readl(acp3x_base + mmACP_PGFSM_STATUS);
30
31         if (val == 0)
32                 return val;
33
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);
38         timeout = 0;
39         while (++timeout < 500) {
40                 val = rv_readl(acp3x_base + mmACP_PGFSM_STATUS);
41                 if (!val) {
42                         /* Set PME_EN as after ACP power On,
43                          * PME_EN gets cleared
44                          */
45                         rv_writel(0x1, acp3x_base + mmACP_PME_EN);
46                         return 0;
47                 }
48                 udelay(1);
49         }
50         return -ETIMEDOUT;
51 }
52
53 static int acp3x_reset(void __iomem *acp3x_base)
54 {
55         u32 val;
56         int timeout;
57
58         rv_writel(1, acp3x_base + mmACP_SOFT_RESET);
59         timeout = 0;
60         while (++timeout < 500) {
61                 val = rv_readl(acp3x_base + mmACP_SOFT_RESET);
62                 if (val & ACP3x_SOFT_RESET__SoftResetAudDone_MASK)
63                         break;
64                 cpu_relax();
65         }
66         rv_writel(0, acp3x_base + mmACP_SOFT_RESET);
67         timeout = 0;
68         while (++timeout < 500) {
69                 val = rv_readl(acp3x_base + mmACP_SOFT_RESET);
70                 if (!val)
71                         return 0;
72                 cpu_relax();
73         }
74         return -ETIMEDOUT;
75 }
76
77 static int acp3x_init(void __iomem *acp3x_base)
78 {
79         int ret;
80
81         /* power on */
82         ret = acp3x_power_on(acp3x_base);
83         if (ret) {
84                 pr_err("ACP3x power on failed\n");
85                 return ret;
86         }
87         /* Reset */
88         ret = acp3x_reset(acp3x_base);
89         if (ret) {
90                 pr_err("ACP3x reset failed\n");
91                 return ret;
92         }
93         return 0;
94 }
95
96 static int acp3x_deinit(void __iomem *acp3x_base)
97 {
98         int ret;
99
100         /* Reset */
101         ret = acp3x_reset(acp3x_base);
102         if (ret) {
103                 pr_err("ACP3x reset failed\n");
104                 return ret;
105         }
106         return 0;
107 }
108
109 static int snd_acp3x_probe(struct pci_dev *pci,
110                            const struct pci_device_id *pci_id)
111 {
112         struct acp3x_dev_data *adata;
113         struct platform_device_info pdevinfo[ACP3x_DEVS];
114         unsigned int irqflags;
115         int ret, i;
116         u32 addr, val;
117
118         if (pci_enable_device(pci)) {
119                 dev_err(&pci->dev, "pci_enable_device failed\n");
120                 return -ENODEV;
121         }
122
123         ret = pci_request_regions(pci, "AMD ACP3x audio");
124         if (ret < 0) {
125                 dev_err(&pci->dev, "pci_request_regions failed\n");
126                 goto disable_pci;
127         }
128
129         adata = devm_kzalloc(&pci->dev, sizeof(struct acp3x_dev_data),
130                              GFP_KERNEL);
131         if (!adata) {
132                 ret = -ENOMEM;
133                 goto release_regions;
134         }
135
136         /* check for msi interrupt support */
137         ret = pci_enable_msi(pci);
138         if (ret)
139                 /* msi is not enabled */
140                 irqflags = IRQF_SHARED;
141         else
142                 /* msi is enabled */
143                 irqflags = 0;
144
145         addr = pci_resource_start(pci, 0);
146         adata->acp3x_base = devm_ioremap(&pci->dev, addr,
147                                         pci_resource_len(pci, 0));
148         if (!adata->acp3x_base) {
149                 ret = -ENOMEM;
150                 goto disable_msi;
151         }
152         pci_set_master(pci);
153         pci_set_drvdata(pci, adata);
154         ret = acp3x_init(adata->acp3x_base);
155         if (ret)
156                 goto disable_msi;
157
158         val = rv_readl(adata->acp3x_base + mmACP_I2S_PIN_CONFIG);
159         switch (val) {
160         case I2S_MODE:
161                 adata->res = devm_kzalloc(&pci->dev,
162                                           sizeof(struct resource) * 4,
163                                           GFP_KERNEL);
164                 if (!adata->res) {
165                         ret = -ENOMEM;
166                         goto de_init;
167                 }
168
169                 adata->res[0].name = "acp3x_i2s_iomem";
170                 adata->res[0].flags = IORESOURCE_MEM;
171                 adata->res[0].start = addr;
172                 adata->res[0].end = addr + (ACP3x_REG_END - ACP3x_REG_START);
173
174                 adata->res[1].name = "acp3x_i2s_sp";
175                 adata->res[1].flags = IORESOURCE_MEM;
176                 adata->res[1].start = addr + ACP3x_I2STDM_REG_START;
177                 adata->res[1].end = addr + ACP3x_I2STDM_REG_END;
178
179                 adata->res[2].name = "acp3x_i2s_bt";
180                 adata->res[2].flags = IORESOURCE_MEM;
181                 adata->res[2].start = addr + ACP3x_BT_TDM_REG_START;
182                 adata->res[2].end = addr + ACP3x_BT_TDM_REG_END;
183
184                 adata->res[3].name = "acp3x_i2s_irq";
185                 adata->res[3].flags = IORESOURCE_IRQ;
186                 adata->res[3].start = pci->irq;
187                 adata->res[3].end = adata->res[3].start;
188
189                 adata->acp3x_audio_mode = ACP3x_I2S_MODE;
190
191                 memset(&pdevinfo, 0, sizeof(pdevinfo));
192                 pdevinfo[0].name = "acp3x_rv_i2s_dma";
193                 pdevinfo[0].id = 0;
194                 pdevinfo[0].parent = &pci->dev;
195                 pdevinfo[0].num_res = 4;
196                 pdevinfo[0].res = &adata->res[0];
197                 pdevinfo[0].data = &irqflags;
198                 pdevinfo[0].size_data = sizeof(irqflags);
199
200                 pdevinfo[1].name = "acp3x_i2s_playcap";
201                 pdevinfo[1].id = 0;
202                 pdevinfo[1].parent = &pci->dev;
203                 pdevinfo[1].num_res = 1;
204                 pdevinfo[1].res = &adata->res[1];
205
206                 pdevinfo[2].name = "acp3x_i2s_playcap";
207                 pdevinfo[2].id = 1;
208                 pdevinfo[2].parent = &pci->dev;
209                 pdevinfo[2].num_res = 1;
210                 pdevinfo[2].res = &adata->res[1];
211
212                 pdevinfo[3].name = "acp3x_i2s_playcap";
213                 pdevinfo[3].id = 2;
214                 pdevinfo[3].parent = &pci->dev;
215                 pdevinfo[3].num_res = 1;
216                 pdevinfo[3].res = &adata->res[2];
217                 for (i = 0; i < ACP3x_DEVS; i++) {
218                         adata->pdev[i] =
219                                 platform_device_register_full(&pdevinfo[i]);
220                         if (IS_ERR(adata->pdev[i])) {
221                                 dev_err(&pci->dev, "cannot register %s device\n",
222                                         pdevinfo[i].name);
223                                 ret = PTR_ERR(adata->pdev[i]);
224                                 goto unregister_devs;
225                         }
226                 }
227                 break;
228         default:
229                 dev_err(&pci->dev, "Invalid ACP audio mode : %d\n", val);
230                 ret = -ENODEV;
231                 goto disable_msi;
232         }
233         pm_runtime_set_autosuspend_delay(&pci->dev, 2000);
234         pm_runtime_use_autosuspend(&pci->dev);
235         pm_runtime_put_noidle(&pci->dev);
236         pm_runtime_allow(&pci->dev);
237         return 0;
238
239 unregister_devs:
240         if (val == I2S_MODE)
241                 for (i = 0; i < ACP3x_DEVS; i++)
242                         platform_device_unregister(adata->pdev[i]);
243 de_init:
244         if (acp3x_deinit(adata->acp3x_base))
245                 dev_err(&pci->dev, "ACP de-init failed\n");
246 disable_msi:
247         pci_disable_msi(pci);
248 release_regions:
249         pci_release_regions(pci);
250 disable_pci:
251         pci_disable_device(pci);
252
253         return ret;
254 }
255
256 static int snd_acp3x_suspend(struct device *dev)
257 {
258         int ret;
259         struct acp3x_dev_data *adata;
260
261         adata = dev_get_drvdata(dev);
262         ret = acp3x_deinit(adata->acp3x_base);
263         if (ret)
264                 dev_err(dev, "ACP de-init failed\n");
265         else
266                 dev_dbg(dev, "ACP de-initialized\n");
267
268         return 0;
269 }
270
271 static int snd_acp3x_resume(struct device *dev)
272 {
273         int ret;
274         struct acp3x_dev_data *adata;
275
276         adata = dev_get_drvdata(dev);
277         ret = acp3x_init(adata->acp3x_base);
278         if (ret) {
279                 dev_err(dev, "ACP init failed\n");
280                 return ret;
281         }
282         return 0;
283 }
284
285 static const struct dev_pm_ops acp3x_pm = {
286         .runtime_suspend = snd_acp3x_suspend,
287         .runtime_resume =  snd_acp3x_resume,
288         .resume =       snd_acp3x_resume,
289 };
290
291 static void snd_acp3x_remove(struct pci_dev *pci)
292 {
293         struct acp3x_dev_data *adata;
294         int i, ret;
295
296         adata = pci_get_drvdata(pci);
297         if (adata->acp3x_audio_mode == ACP3x_I2S_MODE) {
298                 for (i = 0; i < ACP3x_DEVS; i++)
299                         platform_device_unregister(adata->pdev[i]);
300         }
301         ret = acp3x_deinit(adata->acp3x_base);
302         if (ret)
303                 dev_err(&pci->dev, "ACP de-init failed\n");
304         pm_runtime_forbid(&pci->dev);
305         pm_runtime_get_noresume(&pci->dev);
306         pci_disable_msi(pci);
307         pci_release_regions(pci);
308         pci_disable_device(pci);
309 }
310
311 static const struct pci_device_id snd_acp3x_ids[] = {
312         { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x15e2),
313         .class = PCI_CLASS_MULTIMEDIA_OTHER << 8,
314         .class_mask = 0xffffff },
315         { 0, },
316 };
317 MODULE_DEVICE_TABLE(pci, snd_acp3x_ids);
318
319 static struct pci_driver acp3x_driver  = {
320         .name = KBUILD_MODNAME,
321         .id_table = snd_acp3x_ids,
322         .probe = snd_acp3x_probe,
323         .remove = snd_acp3x_remove,
324         .driver = {
325                 .pm = &acp3x_pm,
326         }
327 };
328
329 module_pci_driver(acp3x_driver);
330
331 MODULE_AUTHOR("Vishnuvardhanrao.Ravulapati@amd.com");
332 MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com");
333 MODULE_DESCRIPTION("AMD ACP3x PCI driver");
334 MODULE_LICENSE("GPL v2");