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